操作系统:Ubuntu14.04
内核版本:Linux version 4.4.0-130-generic
交叉编译工具:gcc-3.4.5-glibc-2.3.6
libjpeg库版本:jpegsrc.v9c
材料准备:4.3(480*272)寸jpg图像,编译好的生成文件,上传到开发板(可以参考我之前写过的文章)
代码如下(包含BMP和JPGE代码),详情请看代码注释
欢迎大家在评论留言~~~~~~~~~~~~~~~~
#include
#include
#include
#include
#include
#include
#include
//jpeg库的标准头文件
#include
#include "jpeglib.h"
#include
int lcd; //全局变量
short * fb_mem; //这块的数据类型一定要注意,如果使用就要跟一个像素匹配两个字节(一个像素由多少个字节组成有关)
/*jpeg显示所需的结构体*/
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
/*jpeg显示所需的结构体*/
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
int init_lcd()
{
lcd = open("/dev/fb0",O_RDWR); //1.打开LCD设备
if(lcd == -1)
{
perror("open LCD Err");
return -1;
}
printf("request LCD OK!\n");
//映射显存
fb_mem = mmap(NULL, //映射后的地址,NULL系统自动分配
480*272*2, //映射的大小,字节
PROT_READ|PROT_WRITE, //映射的操作
MAP_SHARED, //映射的共享操作 MAP_SHARED MAP_PRIVATE
lcd, //目标设备的文件描述符
0); //映射的数据地址偏移量,默认0
if(fb_mem == MAP_FAILED)
{
perror("LCD mmap");
return -1;
}
}
int uninit_lcd()
{
close(lcd); //6.关闭LCD
/*取消映射*/
munmap(fb_mem, //映射后的操作地址
480*272*2); //映射的大小
}
// 解码 JPEG 图片,并转成 RGB 值
int show_JPEG_file (char * filename)
{
int i,x;
//unsigned int lcdbuf[800];
short lcdbuf[480]; //注意,这里lcdbuf是2个字节的数据类型,因为一个此lcd一个像素用两个字节表示
//JPEG 解码信息结构体
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
/* More stuff */
FILE * infile; /* source file */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
//打开要解码的JPG图片文件
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
//分配并初始化解码结构体信息
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
//判断文件类型并做出错处理
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
//指定解码的源文件关联
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
//获取jpeg文件的头信息,获取文件大小及尺寸
(void) jpeg_read_header(&cinfo, TRUE);
/* Step 4: set parameters for decompression */
//设置必要的解码信息,可省略
/* Step 5: Start decompressor */
//开始解码
(void) jpeg_start_decompress(&cinfo);
/* JSAMPLEs per row in output buffer */
// 设置每行jpg像素数据解码的大小
row_stride = cinfo.output_width * cinfo.output_components;
//加载jpg文件的数据源,并赋值数据地址到buffer
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
//逐行解码
while (cinfo.output_scanline < cinfo.output_height)
{
//读取新的一行的jpeg数据
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
//将解码后的数据进行处理(自定义)
//put_scanline_someplace(buffer[0], row_stride);
//如何将解码后的每行像素的RGB数据(buffer[0]),写入显存
//fb_mem <----- buffer[0](data) row_stride(size)
for(x=0,i=0;x<480;x++,i+=3)
//for(x=0,i=0;x<800;x++,i+=3)
{ //r g b
lcdbuf[x] = ((buffer[0][i])>>3) << 11 | ((buffer[0][i+1])>>2) << 5 | buffer[0][i+2]>>3;
//算法:jpg解码后的24rgb图像转化为16位的rgb图像(此4.3寸LCD,1个像素由2个字节组成)
}
memcpy((fb_mem+(cinfo.output_scanline-1)*480),lcdbuf,sizeof(lcdbuf));
}
/* Step 7: Finish decompression */
//结束解码
(void) jpeg_finish_decompress(&cinfo);
/* Step 8: Release JPEG decompression object */
//释放解码结构的空间内容
jpeg_destroy_decompress(&cinfo);
//uninit_lcd(); //关闭LCD
//释放jpeg文件的资源
fclose(infile);
//结束
return 1;
}
int show_bmp(char *file) //显示一张图片 思路
{
int ret,x,y,i;
//注意:因为此LCD是一个像素包含两个字节,所以要用short,用int类型则会出错
short lcdbuf[480*272*2];
char temp[3] = {0};
char bmpbuf[480*272*3];
int bmp = open(file,O_RDONLY); //2.打开bmp图片
if(bmp == -1)
{
perror("open BMP Err");
return -1;
}
lseek(bmp, 54, SEEK_SET); //偏移54个字节
ret = read(bmp,bmpbuf,480*272*3); //3.读取bmp信息
if(ret ==-1)
{
perror("read BMP Err");
return -1;
}
//4.change 24bit RGB to 16bit 思路:r:g:b = 5:6:5
//取r的高五位,g的高6位,b的高5位,或运算,重新组成一个新的16位
for(y=0,i=0;y<272;y++)
{
for(x=0;x<480;x++,i+=3)
{
// B G R
lcdbuf[(271-y)*480+x] = (bmpbuf[i])>>3 | (bmpbuf[i+1]>>2)<<5 | (bmpbuf[i+2]>>3) <<11;
//将24位转化为16位算法
}
}
memcpy(fb_mem,lcdbuf,480*272*2);
//ret = write(lcd,lcdbuf,480*272*2); //5.往LCD写数据
if(ret ==-1)
{
perror("write LCD Err");
return -1;
}
//close(lcd); //6.关闭lcd,在专门的关闭初始化函数实现
close(bmp); //7.关闭图片
return 0;
}
int main()
{
init_lcd(); //LCD 初始化
printf("my Project!\n");
show_bmp("picture_3.bmp");
sleep(3);
show_JPEG_file("test.jpg");
uninit_lcd(); //关闭LCD
return 0;
}
步骤如下
1.
2.
3.