Linux jpeg程式設計

巴斯比男孩發表於2020-12-03

一、編譯移植JPEG庫

獲取JPEG庫
官網連結下載jpeg庫

在這裡插入圖片描述
交叉編譯JPEG庫

  • 在linux中,切換到jpeg庫所在的路徑下
  • 在linux中解壓jepg庫,一般地解壓到家目錄下–>因為在家目錄下,擁有一切許可權。
tar xzvf jpegsrc.v9c.tar.gz -C ~

tar:解壓/壓縮的linux命令
處理以.gz結尾的壓縮包
x:解壓 c:壓縮
v:以可見的方式進行解壓,這個引數不是必須的。
f:檔案
-C:指定解壓之後的路徑
~:家目錄
如果有v選項,則會列印解壓的過程。

  • 回到家目錄下,看看有沒有一個新的目錄叫jpeg-9c/,這個目錄就是jpeg庫解壓出來的目錄
  • 在家目錄下建立一個新的目錄,作為安裝之後的目錄,如果沒有寫許可權的話,需要給予許可權
mkidr jpgbuf //建立目錄
chmod 777 jpgbuf //修改目錄許可權

`進入jpeg-9c/目錄,然後ls檢視目錄下的檔案,有一個叫configure的配置檔案

  • 配置
./configure --host=arm-none-linux-gnueabi --prefix=/home/gec/jpgbuf

其中:
./configure --> 執行當前目錄下的configure檔案,會生成一個makefile檔案
–host=arm-none-linux-gnueabi -->指定用arm交叉工具鏈進行編譯,這樣生成的檔案才能在arm平臺使用
–prefix=/home/gec/jpgbuf -->指定安裝路徑

  • 編譯
make //編譯makefile檔案

`如果結果是下面這樣子:

make all-am
make[1]: Entering directory ‘/home/gec/jpeg-9a’
make[1]: Leaving directory ‘/home/gec/jpeg-9a’ --> 則需要清除連結檔案

```c
make clean //清除連結檔案

清除結束後,重新make編譯makefile檔案

  • 安裝
 make install

安裝結束後,切換到~/jpgbuf/目錄下,如果看到有bin include lib share這4個目錄,則編譯移植jpeg庫成功

拷貝庫檔案到開發板即可。

二、程式碼編寫

jpeg.h檔案

#ifndef __JPEG_H__
#define __JPEG_H__

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>



#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdbool.h>
#include <linux/input.h>
#include "jpeglib.h"
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

 struct image_info
 {
	 int width;
	 int height;
	 int pixel_size;
 };

extern void write_lcd( 
 unsigned char *bmp_buffer,
 struct image_info *imageinfo,
 unsigned  char *FB, struct fb_var_screeninfo *vinfo);
 
 extern unsigned long read_image_from_file(
 int fd,
 unsigned char *jpg_buffer,
 unsigned long jpg_size);
 
 extern int Stat(const char *filename, struct stat *file_info);
 
extern   int Open(const char *filename, int mode);

#endif

jpeg.c檔案

#include "jpeg.h"

 // 將 bmp_buffer 中的 24 位的 RGB 資料,寫入 LCD 的 32 位的視訊記憶體中
 void write_lcd( 
 unsigned char *bmp_buffer,
 struct image_info *imageinfo,
 unsigned  char *FB, struct fb_var_screeninfo *vinfo)
 {
		   bzero(FB, vinfo->xres * vinfo->yres * 4);

		 int x, y;
		 for(x=0; x<vinfo->yres && x<imageinfo->height; x++)
		 {
			 for(y=0; y<vinfo->xres && y<imageinfo->width; y++)
			 {
				 unsigned long lcd_offset = (vinfo->xres*x + y) * 4;
				unsigned long bmp_offset = (imageinfo->width*x+y) *
				 imageinfo->pixel_size;

				 memcpy(FB + lcd_offset + vinfo->red.offset/8,
				 bmp_buffer + bmp_offset + 0, 1);
				 memcpy(FB + lcd_offset + vinfo->green.offset/8,
				 bmp_buffer + bmp_offset + 1, 1);
				 memcpy(FB + lcd_offset + vinfo->blue.offset/8,
				 bmp_buffer + bmp_offset + 2, 1);
			 }

		 }
 }

 // 將 jpeg 檔案的壓縮影像資料讀出,放到 jpg_buffer 中去等待解壓
 unsigned long read_image_from_file(
 int fd,
 unsigned char *jpg_buffer,
 unsigned long jpg_size)
 {
	 unsigned long nread = 0;
	 unsigned long total = 0;

	 while(jpg_size > 0)
	 {
		 nread = read(fd, jpg_buffer, jpg_size);

		 jpg_size -= nread;
		 jpg_buffer += nread;
		 total += nread;
	 }
	 close(fd);

	 return total;
}
//獲取圖片檔案的資訊
 int Stat(const char *filename, struct stat *file_info)
 {
	 int ret = stat(filename, file_info);

	 if(ret == -1)
	{
		 fprintf(stderr, "[%d]: stat failed: "
		 "%s\n", __LINE__, strerror(errno));
		 exit(1);
	 }

	 return ret;
 }
//開啟LCD裝置
 int Open(const char *filename, int mode)
 {
	 int fd = open(filename, mode);
	 if(fd == -1)
	 {
		 fprintf(stderr, "[%d]: open failed: ""%s\n", __LINE__, strerror(errno));
		 exit(1);
	 }

	 return fd;
}

main.c檔案

#include "jpeg.h"

 int main(int argc, char **argv)
 {
	 if(argc != 2)
	 {
		 printf("Usage: %s <jpeg image>\n", argv[0]);
		 exit(1);
	 }


 // 讀取圖片檔案屬性資訊
 // 並根據其大小分配記憶體緩衝區 jpg_buffer
 struct stat file_info;
 Stat(argv[1], &file_info);
 int fd = Open(argv[1], O_RDONLY);

 unsigned char *jpg_buffer;
 jpg_buffer = (unsigned char *)calloc(1, file_info.st_size);
 read_image_from_file(fd, jpg_buffer, file_info.st_size);


 // 宣告解壓縮結構體,以及錯誤管理結構體
 struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;

// 使用預設的出錯處理來初始化解壓縮結構體
 cinfo.err = jpeg_std_error(&jerr);
 jpeg_create_decompress(&cinfo);

 // 配置該 cinfo,使其從 jpg_buffer 中讀取 jpg_size 個位元組
 // 這些資料必須是完整的 JPEG 資料
 jpeg_mem_src(&cinfo, jpg_buffer, file_info.st_size);


 int ret = jpeg_read_header(&cinfo, true);
 if(ret != 1)
 {

 fprintf(stderr, "[%d]: jpeg_read_header failed: "
 "%s\n", __LINE__, strerror(errno));
 exit(1);
 }

 // 開始解壓
 jpeg_start_decompress(&cinfo);

 struct image_info imageinfo;
 imageinfo.width = cinfo.output_width;
 imageinfo.height = cinfo.output_height;
 imageinfo.pixel_size = cinfo.output_components;

 int row_stride = imageinfo.width * imageinfo.pixel_size;

 // 根據圖片的尺寸大小,分配一塊相應的記憶體 bmp_buffer
 // 用來存放從 jpg_buffer 解壓出來的影像資料
 unsigned long bmp_size;
 unsigned char *bmp_buffer;
 bmp_size = imageinfo.width *
 imageinfo.height * imageinfo.pixel_size;
 bmp_buffer = (unsigned char *)calloc(1, bmp_size);

 // 迴圈地將圖片的每一行讀出並解壓到 bmp_buffer 中

 while(cinfo.output_scanline < cinfo.output_height)
 {
	 unsigned char *buffer_array[1];
	 buffer_array[0] = bmp_buffer +
	 (cinfo.output_scanline) * row_stride;
	 jpeg_read_scanlines(&cinfo, buffer_array, 1);
 }

 // 解壓完了,將 jpeg 相關的資源釋放掉
 jpeg_finish_decompress(&cinfo);
 jpeg_destroy_decompress(&cinfo);
 free(jpg_buffer);


 // 準備 LCD 螢幕
 int lcd = Open("/dev/fb0", O_RDWR|O_EXCL);

 // 獲取 LCD 裝置的當前引數
 struct fb_var_screeninfo vinfo;

 ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);

 // 根據當前 LCD 裝置引數申請適當大小的 FRAMEBUFFR
 unsigned char *FB;
 unsigned long bpp = vinfo.bits_per_pixel;
 FB = mmap(NULL, vinfo.xres * vinfo.yres * bpp/8,
 PROT_READ|PROT_WRITE, MAP_SHARED, lcd, 0);

 // 將 bmp_buffer 中的 RGB 影像資料,寫入 FRAMEBUFFER 中
 write_lcd(bmp_buffer, &imageinfo, FB, &vinfo);

 return 0;
 }

通用Makefile


CROSS_COMPILE ?=arm-none-linux-gnueabi-
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm

STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump

export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP

CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include

LDFLAGS := -L $(shell pwd)/lib -ljpeg

export CFLAGS LDFLAGS

TOPDIR := $(shell pwd)
export TOPDIR

TARGET := test


obj-y += main.o
obj-y += jpeg.o

all : start_recursive_build $(TARGET)
	@echo $(TARGET) has been built!

start_recursive_build:
	make -C ./ -f $(TOPDIR)/Makefile.build

$(TARGET) : built-in.o
	$(CC) -o $(TARGET) built-in.o $(LDFLAGS)

clean:
	rm -f $(shell find -name "*.o")
	rm -f $(TARGET)

distclean:
	rm -f $(shell find -name "*.o")
	rm -f $(shell find -name "*.d")
	rm -f $(TARGET)
	

三、程式碼框架

在這裡插入圖片描述

實驗效果

執行:

[root@GEC6818 /mnt/jpeg]#./test load.jpg
[root@GEC6818 /mnt/jpeg]#

效果:
在這裡插入圖片描述

相關文章