Linux jpeg编程

一、编译移植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文件的压缩图像数据读出,放到jpg_buffer中去等待解压
  • 开始解压,获取必要的图像信息(只是解压头部的必要信息)
  • 根据图像信息分配一块内存bmp_buffr,用来存放jpeg解压后的数据部分
  • 头部信息与数据部分是分开解压
  • 最后在讲bmp_buffer中的数据刷进LCD映射的显存中

二、代码编写

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]#

效果:
在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页