背景:
网上已经有很多关于利用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.csdn.net/detail/subfate/3345143下载,如果没有CSDN的积分,请到
http://www.latelee.org/yetanothertest/tools/下载。
完整的工程及测试用的图片压缩包下载:
http://www.latelee.org/yetanothertest/program/src/jpeg-test-latelee.org.tar.bz2
注:压缩包中的fb_utils.c文件在不断修改,当修改后,恕不更新此处的工程。