背景:
网上已经有很多关于利用libjpeg显示图片的文章了,因此本文的技术含量不算高。本文是使用libjpeg的v8版本,在开发板的LCD上显示jpg格式图片,关于libjpeg,可到其官方网站下载源码,源码附有许多文档,包括详细的例子(example.c)。
关于如何使用libjpeg,本文不再说明,因为网上文章已经很多了。本文中的代码有几处是自已经修改过的。
1、将所有操作framebuffer的函数放到单独的文件,名称为fb_utils.c,代码主要是来自一个叫ripple的项目。这个文件也用到其它很多地方。
2、libjpeg指定的图片来源有两种,一是文件,一是内存。后者是新版本支持的,旧版本,例如6b,就没有这个函数。
完整的显示jpg图片函数如下:
* draw_jpeg - Display a jpeg picture from (0, 0) on framebuffer
* @name: picture name(foo.jpg)
*/
int draw_jpeg( char *name)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *infile;
unsigned char *buffer;
int x, y;
unsigned char *tmp_buf;
unsigned long size;
int ret;
if ((infile = fopen(name, "rb")) == NULL) {
fprintf(stderr, "open %s failed\n", name);
return - 1;
}
cinfo .err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
// 获取图片文件大小
fseek(infile, 0L, SEEK_END);
size = ftell(infile);
rewind(infile);
tmp_buf = ( unsigned char *)malloc( sizeof( char) * size);
if (tmp_buf == NULL)
{
printf( "malloc failed.\n");
return - 1;
}
ret = fread(tmp_buf, 1, size, infile);
if (ret != size)
{
printf( "read jpeg file error.\n");
return - 1;
}
// memory
jpeg_mem_src(&cinfo, tmp_buf, size); // 指定图片在内存的地址及大小
//jpeg_stdio_src(&cinfo, infile); // 指定图片文件
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
if ((cinfo .output_width > fb_width) || (cinfo .output_height > fb_height)) {
printf( "too large JPEG file,cannot display\n");
return - 1;
}
buffer = ( unsigned char *) malloc(cinfo .output_width * cinfo .output_components);
//printf("%d %d\n", cinfo.output_width, cinfo.output_components); /*eg, 240 3(rgb888)*/
x = y = 0;
while (cinfo .output_scanline < cinfo .output_height) {
jpeg_read_scanlines(&cinfo, &buffer, 1);
if (fb_depth == 16) {
unsigned short color;
for (x= 0; x < cinfo .output_width; x++) {
// LCD为rgb565格式
color = make16color(buffer[x* 3], buffer[x* 3+ 1], buffer[x* 3+ 2]);
fb_pixel(x, y, color);
}
} else if (fb_depth == 24) {
// not test
memcpy(( unsigned char *) fb_mem + y * fb_width * 3,
buffer, cinfo .output_width * cinfo .output_components);
}
y++; // next scanline
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
free(tmp_buf);
free(buffer);
return 0;
}
几点说明:
1、使用图片文件测试,第一种是用jpeg_stdio_src指定图片来源为文件,第二种是将图片读入内存,再使用jpeg_mem_src来指定图片在内存的位置及大小。
2、本文测试所用的LCD格式为rgb565,即16色,而原来图片为24色,所以需要使用一个函数来转换。当得到适合在LCD显示的颜色值后,就可以调用像素函数在LCD上画点了。
就这么简单。
下面是在LCD上显示的图片,使用fb2png截图。
左图是rgb565格式,因为LCD就是这种格式,显示正常,而右图是rgb888格式,不能正常显示出来。
关于fb2png这个工具,我找了好久,现在已经不记得原代码出处了。可以到
http://download.youkuaiyun.com/detail/subfate/3345143下载,如果没有优快云的积分,请到
http://www.latelee.org/yetanothertest/tools/下载。
完整的工程及测试用的图片压缩包下载:
http://www.latelee.org/yetanothertest/program/src/jpeg-test-latelee.org.tar.bz2
注:压缩包中的fb_utils.c文件在不断修改,当修改后,恕不更新此处的工程。