1. 前言
在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。
libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。
**源码获取地址:**http://www.ijg.org/
2. 安装编译步骤
下面介绍libjpeg库交叉编译器的详细步骤。
① 下载源码包,将源码包拷贝到linux系统下。比如:jpegsrc.v9b.tar.gz
② 解码源码包
[root@xiaolong jpeg-9b]# tar xf jpegsrc.v9b.tar.gz
③ 配置源码
[root@xiaolong jpeg-9b]#
./configure --prefix=/usr/local/lib CC=arm-linux-gcc --host=arm-linux --enable-shared --enable-static
注意:
/usr/local/lib 表示指定源码最终安装的路径。
④ 编译源码
[root@xiaolong jpeg-9b]# make
⑤ 安装源码
[root@xiaolong jpeg-9b]# make install
安装好的目录如下:(/usr/local/lib)
[root@xiaolong lib]# ls
bin include lib share
文件结构:
[root@xiaolong lib]# pwd
/usr/local/lib
[root@xiaolong lib]# tree ./
./
├── bin
│ ├── cjpeg
│ ├── djpeg
│ ├── jpegtran
│ ├── rdjpgcom
│ └── wrjpgcom
├── include
│ ├── jconfig.h
│ ├── jerror.h
│ ├── jmorecfg.h
│ └── jpeglib.h
├── lib
│ ├── libjpeg.a
│ ├── libjpeg.la
│ ├── libjpeg.so -> libjpeg.so.9.2.0
│ ├── libjpeg.so.9 -> libjpeg.so.9.2.0
│ └── libjpeg.so.9.2.0
└── share
└── man
└── man1
├── cjpeg.1
├── djpeg.1
├── jpegtran.1
├── rdjpgcom.1
└── wrjpgcom.1
6 directories, 19 files
3. 使用步骤
1.将以下几个头文件拷贝到需要编译的工程目录下:
jmorecfg.h、jpeglib.h、jerror.h、jconfig.h
2.将以下头文件加到工程中:
#include "jpeglib.h"
3./将usr/local/lib目录下的生成的库文件拷贝到开发板的lib目录下。
4.编译选择--任意一种:
arm-linux-gcc -o app show_jpeg.c -L/usr/local/lib
arm-linux-gcc -o app show_jpeg.c -l:libjpeg.so.9
arm-linux-gcc show_jpeg.c -ljpeg -static -o app
show_jpeg.c是要编译的源文件
app 是生成的目标文件。
-static 表示静态生成
#include <jpeglib.h>头文件定义解压缩使用的数据结构信息。
4. 使用案例
4.1 使用libjpg库编码-RGB数据保存为jpg图片
下面这个是利用libjpeg封装的一个方便函数,用于将传入的rgb数据压缩编码成jpg文件保存,一般用与屏幕截屏、相机拍照等地方。
#include <jpeglib.h>
#define JPEG_QUALITY 100 //图片质量
int savejpg(uchar *pdata, char *jpg_file, int width, int height)
{
//分别为RGB数据,要保存的jpg文件名,图片长宽
int depth = 3;
JSAMPROW row_pointer[1];//指向一行图像数据的指针
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile;
cinfo.err = jpeg_std_error(&jerr);//要首先初始化错误信息
//* Now we can initialize the JPEG compression object.
jpeg_create_compress(&cinfo);
if ((outfile = fopen(jpg_file, "wb")) == NULL)
{
fprintf(stderr, "can't open %s\n", jpg_file);
return -1;
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width; //* image width and height, in pixels
cinfo.image_height = height;
cinfo.input_components = depth; //* # of color components per pixel
cinfo.in_color_space = JCS_RGB; //* colorspace of input image
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE ); //* limit to baseline-JPEG values
jpeg_start_compress(&cinfo, TRUE);
int row_stride = width * 3;
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = (JSAMPROW)(pdata + cinfo.next_scanline * row_stride);//一行一行数据的传,jpeg为大端数据格式
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);//这几个函数都是固定流程
fclose(outfile);
return 0;
}
4.2 LCD显示jpg格式图片
下面代码利用libjpeg库解码传入的jpg文件,得到rgb数据,再绘制到LCD屏上显示。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <jpeglib.h>
#include <jerror.h>
// 24位色和16位色转换宏
// by cheungmine
#define RGB888_TO_RGB565(r,g,b) ((WORD)(((WORD(r)<<8)&0xF800)|((WORD(g)<<3)&0x7E0)|((WORD(b) >> 3))))
#define RGB_TO_RGB565(rgb) ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<11)|((((WORD)((rgb)>>10))&(0x3F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
#define RGB888_TO_RGB555(r,g,b) ((WORD)(((WORD(r)<<7)&0x7C00)|((WORD(g)<<2)&0x3E0)|((WORD(b)>>3))))
#define RGB_TO_RGB555(rgb) ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<10)|((((WORD)((rgb)>>11))&(0x1F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
#define RGB555_TO_RGB(rgb555) ((DWORD)(((BYTE)(((rgb555)>>7)&0xF8)|((WORD)((BYTE)(((rgb555)>>2)&0xF8))<<8))|(((DWORD)(BYTE)(((rgb555)<<3)&0xF8))<<16)))
#define RGB565_TO_RGB(rgb565) ((DWORD)(((BYTE)((((rgb565)&0xF800)>>11)<<3)|((WORD)((BYTE)((((rgb565)&0x07E0)>>5)<<2))<<8))|(((DWORD)(BYTE)(((rgb565)&0x001F)<<3))<<16)))
unsigned short rgb888_to_rgb555(unsigned char red,unsigned char green,unsigned char blue);
unsigned short rgb888_to_rgb565(unsigned char red,unsigned char green,unsigned char blue);
/*--------------------------------------------------------------
JPEG图片显示
---------------------------------------------------------------*/
static unsigned char *fbmem = NULL;
static struct fb_var_screeninfo var;//定义可变参数结构体来接收驱动传过来的可变参数结构体
static struct fb_fix_screeninfo fix;//定义固定参数结构体来接收驱动传过来的固定参
//显示JPEG
int show_jpeg(unsigned char *file)
{
struct jpeg_decompress_struct cinfo; //存放图像的数据
struct jpeg_error_mgr jerr; //存放错误信息
FILE *infile;
unsigned int *dst=fbmem;
unsigned char *buffer;
unsigned int x;
unsigned int y;
/*
* 打开图像文件
*/
if ((infile = fopen(file, "rb")) == NULL) {
fprintf(stderr, "open %s failed\n", file);
exit(-1);
}
/*
* init jpeg压缩对象错误处理程序
*/
cinfo.err = jpeg_std_error(&jerr); //初始化标准错误,用来存放错误信息
jpeg_create_decompress(&cinfo); //创建解压缩结构信息
/*
* 将jpeg压缩对象绑定到infile
*/
jpeg_stdio_src(&cinfo, infile);
/*
* 读jpeg头
*/
jpeg_read_header(&cinfo, TRUE);
/*
*开始解压
*/
jpeg_start_decompress(&cinfo);
printf("JPEG高度: %d\n",cinfo.output_height);
printf("JPEG宽度: %d\n",cinfo.output_width);
printf("JPEG颜色位数(字节单位): %d\n",cinfo.output_components);
//为一条扫描线上的像素点分配存储空间
buffer = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);
y = 0;
//将图片内容显示到framebuffer上
while (cinfo.output_scanline < cinfo.output_height)
{
//读取一行的数据
jpeg_read_scanlines(&cinfo, &buffer, 1);
//判断LCD屏的映射空间像素位数
if (var.bits_per_pixel == 32)
{
unsigned int color;
for (x = 0; x < cinfo.output_width; x++) {
color = buffer[x * 3 + 0] << 16 |
buffer[x * 3 + 1] << 8 |
buffer[x * 3 + 2] << 0;
dst = ((unsigned int *) fbmem + y * var.xres + x);
*dst = color;
}
}
y++; // 显示下一个像素点
}
/*
* 完成解压,摧毁解压对象
*/
jpeg_finish_decompress(&cinfo); //结束解压
jpeg_destroy_decompress(&cinfo); //释放结构体占用的空间
/*
* 释放内存缓冲区
*/
free(buffer);
/*
* 释放内存缓冲区
*/
fclose(infile);
return 0;
}
/*映射LCD显示的内存空间*/
unsigned char * fmem(unsigned char *fbname)
{
int fb;
unsigned char *mem;
fb = open(fbname,2);
if(fb<0)
{
printf("open fbdev is error!!!\n");
return NULL;
}
ioctl(fb,FBIOGET_VSCREENINFO,&var);//获取固定参数结构体放在var结构体中
ioctl(fb,FBIOGET_FSCREENINFO,&fix);//获取固定参数,存放在fix结构体中
mem = (unsigned char *)mmap(NULL,fix.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
if(mem == (unsigned char *)-1)
{
printf("fbmmap is error!!!\n");
munmap(mem,fix.smem_len);
return NULL;
}
return mem;
}
int main (int argc,char** argv) //./a.out /dev/fb0 xxx.bmp
{
int fb ,i=4;
char key;
unsigned char * bmpmem;
if(argc!=3)
{
printf("Usage: ./%s <fbdev> <bmpname> \n",argv[0]);
return -1;
}
fbmem = fmem(argv[1]); //将缓冲设备映射到内存进行写入
memset(fbmem,0x00,fix.smem_len);//清屏函数 往映射的地址填充fix.sem_len大小的0xff颜色进去
show_jpeg(argv[2]); //程序运行时显示主界面
return 0;
}