内核版本: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 <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <unistd.h>
-
#include <linux/input.h>
-
#include <sys/mman.h>
-
-
//jpeg库的标准头文件
-
#include <stdio.h>
-
#include "jpeglib.h"
-
#include <setjmp.h>
-
-
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.