⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 showimg.c

📁 嵌入式linux下基于framebuffer显示bmp和Jpeg格式的图片。
💻 C
字号:
/*
   showimg.c
   
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <jpeglib.h>
#include <setjmp.h>
int image_height;
int image_width;
JSAMPLE  image_buffer[320][720];
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;

//14byte
typedef struct
{
  char cfType[2];         /* 文件类型, 必须为 "BM" (0x4D42)*/
  char cfSize[4];         /* 文件的大小(字节) */
  char cfReserved[4];     /* 保留, 必须为 0 */
  char cfoffBits[4];      /* 位图阵列相对于文件头的偏移量(字节)*/
}__attribute__((packed)) BITMAPFILEHEADER;       /* 文件头结构 *///__attribute__((packed))作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。


//40byte
typedef struct
{
  char ciSize[4];         /* size of BITMAPINFOHEADER */
  char ciWidth[4];        /* 位图宽度(像素) */
  char ciHeight[4];       /* 位图高度(像素) */
  char ciPlanes[2];       /* 目标设备的位平面数, 必须置为1 */
  char ciBitCount[2];     /* 每个像素的位数, 1,4,8或24 */
  char ciCompress[4];     /* 位图阵列的压缩方法,0=不压缩 */
  char ciSizeImage[4];    /* 图像大小(字节) */
  char ciXPelsPerMeter[4];/* 目标设备水平每米像素个数 */
  char ciYPelsPerMeter[4];/* 目标设备垂直每米像素个数 */
  char ciClrUsed[4];      /* 位图实际使用的颜色表的颜色数 */
  char ciClrImportant[4]; /* 重要颜色索引的个数 */
}__attribute__((packed)) BITMAPINFOHEADER;       /* 位图信息头结构 */


typedef struct
{
  unsigned short blue:5;    //每个颜色均用5位表示,X R R R R R G G G G G B B B B B (X表示不用,可以忽略)高字节,低字节
  unsigned short green:5;
  unsigned short red:5;
  unsigned short rev:1;
}__attribute__((packed)) RGB555;

typedef struct
{
  unsigned short blue:5;    //R R R R R G G G G G G B B B B B
  unsigned short green:6;
  unsigned short red:5;
}__attribute__((packed)) RGB565;

typedef struct
{
  unsigned short blue:8;    //内存中RGB各分量的排列顺序为:BGR BGR 
  unsigned short green:8;
  unsigned short red:8;
}__attribute__((packed)) RGB888;

BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;


char *fbp = 0;
int xres = 0;
int yres = 0;
int bits_per_pixel = 0;

int  show_bmp  ( char *bmpfile );
long chartolong ( char * string, int length );
/******************************************************************************
*
******************************************************************************/
int main ( int argc, char *argv[] )
{
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (!fbfd)
    {
        printf("Error cannot open framebuffer device.\n");
        exit(1);
    }

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
    {
        printf("Error reading fixed information.\n");
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
    {
        printf("Error reading variable information.\n");
        exit(3);
    }

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
    xres = vinfo.xres;
    yres = vinfo.yres;
    bits_per_pixel = vinfo.bits_per_pixel;

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                       fbfd, 0);
    if ((int)fbp == -1)
    {
        printf("Error failed to map framebuffer device to memory.\n");
        exit(4);
    }
printf("sizeof header=%d\n", sizeof(BITMAPFILEHEADER));
printf("into show_bmp fun\n");

      show_img( argv[1] );

    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}

/******************************************************************************
*
******************************************************************************/
int show_img( char *imgfile )
{
        FILE *fp;
        //int RGBflag;
        int rc;
        int ciBitCount, ciWidth, ciHeight;
        int line_x, line_y;
        long int location = 0, BytesPerLine = 0;
        char tmp[1024*10];

        if(is_bmp(imgfile))
        {
        /* 打开位图文件 */
        	fp = fopen( imgfile, "rb" );
       		if (fp == NULL)
        	{
                return( -1 );
        	}
        
        /* 读取位图文件头 */
        	rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );   //读位图文件头到FileHead中
        	if ( rc != 1)
        	{
				printf("read header error!\n");
                fclose( fp );
                return( -2 );
        	}
        
        /* 判断位图的类型 */
       		if (memcmp(FileHead.cfType, "BM", 2) != 0)
        	{
			printf("it's not a BMP file\n");
                fclose( fp );
                return( -3 );
        	}

        /* 读取位图信息头 */
        	rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );//fread(buffer,size,count,fp),size:要读写的字节数;count:要进行读写多少个size字节的数据项;
        	if ( rc != 1)
        	{
				printf("read infoheader error!\n");
                fclose( fp );
                return( -4 );
        	}

       			ciWidth    = (int) chartolong( InfoHead.ciWidth,    4 );    //InfoHead.ciWidth,为一个字符串,得到图像的实际宽度
       			ciHeight   = (int) chartolong( InfoHead.ciHeight,   4 );   //实际的高度
        		ciBitCount = (int) chartolong( InfoHead.ciBitCount, 4 );   //每像素的实际位数

				fseek(fp, (int)chartolong(FileHead.cfoffBits, 4), SEEK_SET);   //读偏移量,取得图像数据的实际位置
				BytesPerLine = (ciWidth * ciBitCount + 31) / 32 * 4;   //因为存储时要按四位对齐,也就是32位,技巧在意若ciWidth * ciBitCount为32的整数倍,则结果为ciWidth * ciBitCount/32,否则为ciWidth * ciBitCount/32+1;
        
				printf("width=%d, height=%d, bitCount=%d, offset=%d\n", ciWidth, ciHeight, ciBitCount, (int)chartolong(FileHead.cfoffBits, 4));
       	 		line_x = line_y = 0;


			while(!feof(fp))  //检测流上的文件结束符,如果遇到文件结束,函数feof(fp)的值为1,否则为0
			{
				unsigned short int tmp;
				unsigned short int red,green,blue;
				if( ciBitCount==16)
				{
					RGB555 pix16;
					//unsigned short RGB555;
					rc = fread( (char *)&pix16, 1,2, fp );  //完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
					if (rc != 2 )
					{ break; }
					tmp=pix16.red<<11 | pix16.green<<6 | pix16.blue;
				}
		
				if( ciBitCount==24)
				{
					RGB888 pix24;
					//unsigned short RGB888;;
					rc = fread((char *)&pix24, 1,3, fp );  //完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
					if (rc != 3) 
					{ break; }
					red=(pix24.red&0xF8)<<8;   
            		green=(pix24.green&0xFA)<<3;   
           			blue=(pix24.blue&0xF8)>>3;   
					tmp=red|green|blue;
				}
		
					location = line_x * bits_per_pixel / 8 + (ciHeight - line_y - 1) * xres * bits_per_pixel / 8;
        
					*((unsigned short int*)(fbp + location)) = tmp;   //bmp的数据是倒序,从左下角开始。给出了两个指针相加的范例。

					line_x++;
					if (line_x == ciWidth )
						{
							line_x = 0;
							line_y++;
			
					if(line_y==ciHeight-1)
						{
							break;
						}
				}
			}
        fclose( fp );
        }
        if(is_jpg(imgfile))
        {
             unsigned short int tmp;
			 unsigned short int red,green,blue;
             read_jpeg_file(imgfile);
             for(line_x=0;line_x< ciWidth;line_x++)
             {
                 for(line_y=0;line_y<ciHeight;line_y++)
                 {
                    red=(image_buffer[line_x][3*line_y]&0xF8)<<8;   
            		green=(image_buffer[line_x][3*line_y+1]&0xFA)<<3;   
           			blue=(image_buffer[line_x][3*line_y+2]&0xF8)>>3;   
					tmp=red|green|blue;
					location = line_y * bits_per_pixel / 8 + line_x * xres * bits_per_pixel / 8;
					*((unsigned short int*)(fbp + location)) = tmp; 
                 }
             }
          
        }
        else printf("can't display format");
        return( 0 );
}

/******************************************************************************
*
******************************************************************************/
long chartolong( char * string, int length )   //将4个字符串类的数据合并成一个long型变量
{
        long number;
        
        if (length <= 4)
        {
                memset( &number, 0x00, sizeof(long) );
                memcpy( &number, string, length );
        }
        
        return( number );
}

/******************************************************************************
*判断一个文件是jpeg格式还是bmp格式
******************************************************************************/
static int is_bmp (char *filename)
{
	int length = strlen (filename);
	if (filename[length-4] != '.')
	{
		return 0;
	}
	if ((filename[length-3] != 'b') && (filename[length-3] != 'B'))
	{
		return 0;
	}
	if ((filename[length-2] != 'm') && (filename[length-2] != 'M'))
	{
		return 0;
	}
	if ((filename[length-1] != 'p') && (filename[length-1] != 'P'))
	{
		return 0;
	}
	return 1;
}

static int is_jpg (char *filename)
{
	int length = strlen (filename);
	if (filename[length-4] != '.')
	{
		return 0;
	}
	if ((filename[length-3] != 'j') && (filename[length-3] != 'J'))
	{
		return 0;
	}
	if ((filename[length-2] != 'p') && (filename[length-2] != 'P'))
	{
		return 0;
	}
	if ((filename[length-1] != 'g') && (filename[length-1] != 'G'))
	{
		return 0;
	}
	return 1;
}
/******************************************************************************
*对jpeg格式代码进行解码
******************************************************************************/
METHODDEF(void)my_error_exit (j_common_ptr cinfo)
{
  my_error_ptr myerr = (my_error_ptr) cinfo->err;
  (*cinfo->err->output_message) (cinfo);
  longjmp(myerr->setjmp_buffer, 1);
}

int  read_jpeg_file(char * filename)
{
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE * infile;          /* source file */
  JSAMPARRAY buffer;      /* Output row buffer */
  int row_stride;		/* physical row width in output buffer */
  int i;
  infile=fopen(filename,"rb");
  if (infile == NULL)
    {
      fprintf (stderr, "can't open %s\n", filename);
      exit(1);
    }
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  if (setjmp(jerr.setjmp_buffer)) {
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return 0;
   }
  jpeg_create_decompress(&cinfo);
  jpeg_stdio_src(&cinfo, infile);
  (void) jpeg_read_header(&cinfo, TRUE);
  (void) jpeg_start_decompress(&cinfo);
  /* row_stride = cinfo.output_width * cinfo.output_components; */
  row_stride=image_width*3;
  buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
  for(i=0;i<image_height;i++) {
    (void) jpeg_read_scanlines(&cinfo,buffer,1);
    memcpy(image_buffer[i],buffer[0],row_stride);
    }
 (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  fclose(infile);
  return 1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -