[完美解决]如何在JZ2440 4.3寸LCD显示屏显示jpg图片

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_25908839/article/details/81211967

操作系统: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 <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.

猜你喜欢

转载自blog.csdn.net/qq_25908839/article/details/81211967