在arm开发板上实现播放内存里所有的jpg和bmp格式图片

之前学习的时候一个作业,趁机会发表一下做个记录,bmp图片较为简单就可以实现了,关于bmp图片的原理可参考这个链接https://blog.csdn.net/u013066730/article/details/82625158,jpg的话是使用了官方的jpg库,可自行去官方下载http://www.ijg.org/

下面是一些代码

main.c 的内容

/*查找整个系统中的bmp和jpg格式图片,并打印出他们的信息,同时在开发板上显示这张图片*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BLACK 0x000000

int read_JPEG_file (char * filename,int *lcd); 	//读取JPG格式图片信息

/*显示.JPG格式的图片*/
void show_jpg(char *photo_path)
{
	//打开需要映射的硬件设备  
 	int lcd_fd = open("/dev/fb0",O_RDWR);
		if(lcd_fd < 0)
		{
			perror("open fail");
			exit(0); 
		}


	//映射文件到虚拟内存空间中    
	int  *lcd_p =  mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
	
	
	//对JPEG  图片解码并显示
	read_JPEG_file(photo_path,lcd_p);
	
	sleep(1);
	int i=0;
	for(i=0;i<800*480;i++)
	{
		*(lcd_p+i) = BLACK;
	}
	
	//关闭映射和打开的文件
	munmap(lcd_p,800*480*4);
	close(lcd_fd);
}

/*显示.BMP格式的图片*/
void show_bmp(char *photo_path)
{
	//打开需要映射的硬件设备
	int lcd_fd = open("/dev/fb0",O_RDWR);
	if(!lcd_fd)
	{
		perror("open");
		exit(1);
	}
	
	//映射文件到虚拟内存空间中
	int *lcd_p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
	
	int bmp_fd = open(photo_path,O_RDWR);
	if(!bmp_fd)
	{
		perror("open");
		exit(2);
	}
	
	//读取图片的头信息
	unsigned char head[54]={0};
	read(bmp_fd,head,54);
	
	//处理头数据
	int chang = *((int *)&head[18]);
	int kuan = *((int *)&head[22]);
	int bit = *((int *)&head[28]);
	
	printf("chang=%d,kuan=%d,bit=%d\n",chang,kuan,bit);

	//根据头数据定义像素数据的缓存地址		
	char color_buf[chang*kuan*(bit/8)];
	int size = read(bmp_fd,color_buf,sizeof(color_buf));
	printf("size=%d\n",size);
	
	//定义一个数据的缓冲区
	int buf24[chang*kuan];
	int i=0;
	for(i=0;i<chang*kuan;i++)
	{
		buf24[i]  =  color_buf[i*3+0] |  color_buf[i*3+1]<< 8  | color_buf[i*3+2]  << 16;
					 //B 0-7  				G 8-15				     R:16 - 23
	}

	//把图像的数据写入到lcd屏幕设备中
	int  x=0,y=0;  
	
	
	for(y=0;y<kuan;y++)
	{	
		for(x=0;x<chang;x++)
		{
			//超出显示屏范围跳出  
			if(x >= 800 || y >= 480)
				break;
			//图片没有超出显示屏范围
			else if(chang <= 800 && kuan <= 480 )
			{
				*(lcd_p + (800*(480-kuan)/2 + (800-chang)/2) + x + y*800) = buf24[x + (kuan-1-y)*chang];
			}
			// 图片长和宽都超出屏幕,显示图片中间800*480部分
			else if(chang > 800 && kuan > 480)
			{
				*(lcd_p + x + y*800)  =  buf24[(chang-800)/2 + x + (kuan - (kuan-480)/2 - 1 - y) * chang];
			}
			// 图片长超出,宽没有,居中显示
			else if(chang > 800 && kuan <= 480)
			{
				*(lcd_p + (800*(480-kuan)/2) + x + y*800) = buf24[(chang-800)/2 + x + (kuan-1-y)*chang];
			}
			// 图片宽超出,长没有,居中显示
			else if(chang <= 800 && kuan > 480)
			{
				*(lcd_p + (800-chang)/2 + x + y*800) = buf24[x + (kuan - (kuan-480)/2 - 1 - y) * chang];
			}
		}
	}
	
	/*图片显示一秒后清屏进入下一张图片*/
	sleep(1);
	for(i=0;i<800*480;i++)
	{
		*(lcd_p+i) = BLACK;
	}
	
	//关闭映射和打开的文件
	munmap(lcd_p,800*480*4);
	close(bmp_fd);
	close(lcd_fd);		
}

/*实现搜索整个系统中的   .bmp  .jpg 文件 */
int find(char *path)
{
	DIR *dir=opendir(path);
	if(dir==NULL)
	{
		/*根目录下一些文件无法打开,为了不影响观看效果,不打印错误结果*/
		//perror("opedndir");
		return -1;
	}

	while(1)
	{
		struct dirent *ep = readdir(dir);

		if(ep==NULL)
		{
			break;
		}
		

		//跳过隐藏文件
		if( ep->d_name[0] == '.' )
		{
			continue;
		}
		
		//目录
		if(ep->d_type==DT_DIR)
		{
			char buf[4096]={0};
			if(strcmp(path,"/")==0)
				sprintf(buf,"%s%s",path,ep->d_name);
			else
				sprintf(buf,"%s/%s",path,ep->d_name);
	//		printf("%s\n",buf);
			
			find(buf);
		}
		
		//文件
		if(ep->d_type==DT_REG)
		{
			/*  *.bmp 文件   */
			if(strstr(ep->d_name,".bmp") != NULL )
			{
				if(strcmp(strstr(ep->d_name,".bmp"),".bmp") == 0)
				{
					if(strcmp(path,"/")==0)
						printf("%s%s",path,ep->d_name);
					else
						printf("%s/%s\n",path,ep->d_name);
					
					char buf1[4096]={0};
					if(strcmp(path,"/")==0)
						sprintf(buf1,"%s%s",path,ep->d_name);
					else
						sprintf(buf1,"%s/%s",path,ep->d_name);

					show_bmp(buf1);
				}
			}
			/*  *.jpg  文件  */
			if(strstr(ep->d_name,".jpg") != NULL)
			{
				if(strcmp(strstr(ep->d_name,".jpg"),".jpg") == 0)
				{
					if(strcmp(path,"/")==0)
						printf("%s%s",path,ep->d_name);
					else
						printf("%s/%s\n",path,ep->d_name);
					
					char buf2[4096]={0};
					if(strcmp(path,"/")==0)
						sprintf(buf2,"%s%s",path,ep->d_name);
					else
						sprintf(buf2,"%s/%s",path,ep->d_name);
					
					show_jpg(buf2);
				}
			}
		}
	}
	
	closedir(dir);
}

int main(int argc,char *argv[])
{
		find("/");
		printf("\nOver!!!");
		printf("\n\n");
}

jpg.c的内容


#include 
#include "jpeglib.h"
#include 

extern JSAMPLE * image_buffer;	/* Points to large array of R,G,B-order data */
extern int image_height;	/* Number of rows in image */
extern int image_width;		/* Number of columns in image */

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;

/*
 * Here's the routine that will replace the standard error_exit method:
 */

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);
}

//功能:读取jpeg 文件中的数据转换成  r g b 值 
int read_JPEG_file (char * filename,int *lcd)
{
  
  //定义一个 jpeg  的解码对象 
  struct jpeg_decompress_struct cinfo;


  //定义一个jpeg  的出错对象 
  struct my_error_mgr jerr;
  /* More stuff */
  FILE * infile;		/*源文件*/
  JSAMPARRAY buffer;		/*输出行缓存*/
  int row_stride;		/*输出行缓存的宽度*/

  
	//打开源文件
  if ((infile = fopen(filename, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    return 0;
  }

  /* Step 1: 初始化JPEG 解码对象*/

  /*初始化出错对象 */
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp(jerr.setjmp_buffer)) {
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return 0;
  }
  
  
  /*初始化解码对象*/
  jpeg_create_decompress(&cinfo);

  /* Step 2: 关联源文件与解码对象*/
  jpeg_stdio_src(&cinfo, infile);

  /* Step 3: 读取jpeg图像的头数据*/
  (void) jpeg_read_header(&cinfo, TRUE);
 

  /* Step 5: 开始解码*/
  (void) jpeg_start_decompress(&cinfo);
 
 
  /* 一行所占用的字节数 */
  row_stride = cinfo.output_width * cinfo.output_components;
  
  /*为输出行缓存分配堆空间*/
  buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

 //cinfo.output_width * cinfo.output_components
 
 
 int buf24[cinfo.output_width*cinfo.output_height];
	//重点!!!!! 循环对每一行数据进行解码!! 
  while (cinfo.output_scanline < cinfo.output_height) 
  {
	//printf("%d\n",cinfo.output_scanline);
	//读取一行数据进行解码 并 写入到 buffer 中
    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
	char *p = buffer[0];  //指向数据的R G B 数据的缓存首地址  
	
	int i=0; 
	for(i=0;i<cinfo.output_width;i++)  //把一行的 R G B 值全部都取出来  
	{	
		char  r = *p++; 
		char  g = *p++;
		char  b = *p++; 	
		buf24[i + (cinfo.output_scanline-1) * cinfo.output_width] = r << 16 | g << 8 | b;   // 处理 jpeg 中的RGB 数据 
	}
  }	
  
  //把图像的数据写入到lcd屏幕设备中
  int x = 0, y = 0;
  
  for(y=0;y<cinfo.output_height;y++)
  {
	  for(x=0;x<cinfo.output_width;x++)
	  {
			//超出显示屏范围跳出  
			if(x >= 800 || y >= 480)
				break;
			//图片没有超出显示屏范围
			else if(cinfo.output_width <= 800 && cinfo.output_height <= 480 )
			{
				*(lcd + (800*(480-cinfo.output_height)/2 + (800-cinfo.output_width)/2) + x + y*800) = buf24[x + y*cinfo.output_width];
			}
			// 图片长和宽都超出屏幕,显示图片中间800*480部分
			else if(cinfo.output_width > 800 && cinfo.output_height > 480)
			{
				*(lcd + x + y*800)  =  buf24[(cinfo.output_width-800)/2 + x + ((cinfo.output_height-480)/2 + y) * cinfo.output_width];
			}
			// 图片长超出,宽没有,居中显示
			else if(cinfo.output_width > 800 && cinfo.output_height <= 480)
			{
				*(lcd + (800*(480-cinfo.output_height)/2) + x + y*800) = buf24[(cinfo.output_width-800)/2 + x + y*cinfo.output_width];
			}
			// 图片宽超出,长没有,居中显示
			else if(cinfo.output_width <= 800 && cinfo.output_height > 480)
			{
				*(lcd + (800-cinfo.output_width)/2 + x + y*800) = buf24[x + ((cinfo.output_height-480)/2 +y) * cinfo.output_width];
			}
	  }
  }
  
			
		//*(lcd + (cinfo.output_scanline - 1)*800 + i)  = color;   //把转换后的颜色数据赋值给   lcd 屏幕 
		//cinfo.output_scanline*800 第几行  
	
  
	//把解码后的数据输出 LCD 屏幕中
   // put_scanline_someplace(buffer[0], row_stride);

  



  /* Step 7: Finish decompression */
  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  fclose(infile);

  return 1;
}

测试用的机器是arm架构、linux系统的粤嵌公司的6818开发板,最终实现效果就是在屏幕上轮流播放内存里面的所有bmp和jpg格式的图片。

你可能感兴趣的:(嵌入式软件工程师)