一、编译移植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]#
效果: