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;
}