linux应用编程--显示bmp图片

Posted 小懒虫alex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux应用编程--显示bmp图片相关的知识,希望对你有一定的参考价值。

平台:tiny4412SDK 1161 + HD700

kernel:linux 3.5

bmp:24位深

前言:

  前边设置好了HD700的驱动,能够正常显示像素,现在学习bmp图片格式并显示一张bmp图片。

1、bmp图片格式:

  BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发,BMP位图格式理所当然地被广泛应用。

  常用的图片格式有:JPEG、GIF、PSD、PNG、SWF、SVG……

2、bmp图片的优缺点:

  优点:包含的图像信息较丰富,几乎不进行压缩

  缺点:占用磁盘空间过大

3、bmp图片的应用范围:

  网络上应用较少,目前BMP在单机上比较流行

4、bmp图片数据结构:

  bmp图片文件数据流中前54个字节是bmp格式包含的数据头信息,其余为颜色数据。

  数据头信息如下数据结构:

    //14byte文件头  
    typedef struct    
    {  
        char cfType[2];  //文件类型,"BM"(0x4D42)  
        long cfSize;    //文件大小(字节)    
        long cfReserved;  //保留,值为0    
        long cfoffBits;    //数据区相对于文件头的偏移量(字节)  
    }__attribute__((packed)) BITMAPFILEHEADER;    
    //__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐  
    //40byte信息头  
    typedef struct    
    {  
        char ciSize[4];      //BITMAPFILEHEADER所占的字节数  
        long ciWidth;        //宽度  
        long ciHeight;       //高度    
        char ciPlanes[2];    //目标设备的位平面数,值为1  
        int ciBitCount;      //每个像素的位数    
        char ciCompress[4];  //压缩说明  
        char ciSizeImage[4]; //用字节表示的图像大小,该数据必须是4的倍数  
        char ciXPelsPerMeter[4];//目标设备的水平像素数/米  
        char ciYPelsPerMeter[4];//目标设备的垂直像素数/米  
        char ciClrUsed[4];      //位图使用调色板的颜色数    
        char ciClrImportant[4]; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要  
    }__attribute__((packed)) BITMAPINFOHEADER;    

编程过程当中需要多加关注的成员是文件类型、数据区偏移量、宽度、高度、像素位深。

5、编程思路:

1)、打开linux系统下显示设备。

2)、获取设备的大小信息,得到屏幕宽高,并计算屏幕大小。

3)、根据屏幕大小映射显存区域

4)、显示图片
  a、打开图片文件

  b、获取数据头

  c、判断文件类型

  d、循环读取颜色数据

  e、把数据往显存当中写入

  f、关闭图片文件

5)、解除映射

6)、关闭显示设备

6、注意事项:

  1、从bmp图片文件当中读取像素信息时,需要根据位深度读取不同大小的数据信息,例如例子当中使用的是24位深度,每次读取一个像素数据是3个字节。

  2、bmp图片的像素数据存储的排版是从下到上、从左到右的。

7、待优化:

  1、图片显示需要根据位深度不同而读取颜色数据时做适应性变化。

  2、添加显示初始位置接口

  3、由于映射的显存是一段连续的地址,需要对图片行、列显示做限定处理,确保超出屏幕大小不会显示混乱。

8、代码实现:

#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>  
  
//14byte文件头  
typedef struct	
{  
	char cfType[2];//文件类型,"BM"(0x4D42)  
	long cfSize;//文件大小(字节)	
	long cfReserved;//保留,值为0	
	long cfoffBits;//数据区相对于文件头的偏移量(字节)  
}__attribute__((packed)) BITMAPFILEHEADER;	
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐  
  
//40byte信息头  
typedef struct	
{  
	char ciSize[4];//BITMAPFILEHEADER所占的字节数  
	long ciWidth;//宽度  
	long ciHeight;//高度	
	char ciPlanes[2];//目标设备的位平面数,值为1  
	int ciBitCount;//每个像素的位数	
	char ciCompress[4];//压缩说明  
	char ciSizeImage[4];//用字节表示的图像大小,该数据必须是4的倍数  
	char ciXPelsPerMeter[4];//目标设备的水平像素数/米  
	char ciYPelsPerMeter[4];//目标设备的垂直像素数/米  
	char ciClrUsed[4]; //位图使用调色板的颜色数	
	char ciClrImportant[4]; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要  
}__attribute__((packed)) BITMAPINFOHEADER;	
  
typedef struct	
{  
	unsigned char blue;  
	unsigned char green;  
	unsigned char red;  
//	unsigned char reserved;  
}__attribute__((packed)) PIXEL;//颜色模式RGB  
  
BITMAPFILEHEADER FileHead;	
BITMAPINFOHEADER InfoHead;	
  
static char *fbp = 0;  
static int xres = 0;  
static int yres = 0;  
static int bits_per_pixel = 0;	
  
int show_bmp();  
  
int main ( int argc, char *argv[] )  
{  
	int fbfd = 0;  
	struct fb_var_screeninfo vinfo;  
	struct fb_fix_screeninfo finfo;  
	long int screensize = 0;  
	struct fb_bitfield red;  
	struct fb_bitfield green;  
	struct fb_bitfield blue;  
  
	//打开显示设备  
	fbfd = open("/dev/fb0", O_RDWR);  
	if (!fbfd)	
	{  
		printf("Error: cannot open framebuffer device.
");  
		exit(1);  
	}  
  
	if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))  
	{  
		printf("Error:reading fixed information.
");  
		exit(2);  
	}  
  
	if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))  
	{  
		printf("Error: reading variable information.
");  
		exit(3);  
	}  
	printf("R:%d,G:%d,B:%d 
", vinfo.red.offset, vinfo.green.offset, vinfo.blue.offset ); 
	printf("R:%d,G:%d,B:%d 
", vinfo.red.length, vinfo.green.length, vinfo.blue.length );  
  
	printf("%dx%d, %dbpp
", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );  
	xres = vinfo.xres;	
	yres = vinfo.yres;	
	bits_per_pixel = vinfo.bits_per_pixel;	
  
	//计算屏幕的总大小(字节)	
	screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
	printf("screensize=%d byte
",screensize);	
  
	//对象映射	
	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.
");  
		exit(4);  
	}  
 
	//显示图像	
	show_bmp();  
  
	//删除对象映射  
	munmap(fbp, screensize);  
	close(fbfd);  
	return 0;  
}  
  
int show_bmp()	
{  
	FILE *fp;  
	int rc;  
	int line_x, line_y;  
	long int location = 0, BytesPerLine = 0;  
  
	fp = fopen( "timg.bmp", "rb" );  
	if (fp == NULL)  
	{  
		return(-1);  
	}  
  
	rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );  
	if ( rc != 1)  
	{  
		printf("read header error!
");  
		fclose(fp);  
		return(-2);  
	}  
  
	//检测是否是bmp图像	
	if (memcmp(FileHead.cfType, "BM", 2) != 0)	
	{  
		printf("it‘s not a BMP file
");  
		fclose(fp);  
		return(-3);  
	}  
  
	rc = fread((char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp);  
	if (rc != 1)  
	{  
		printf("read infoheader error!
");  
		fclose(fp);  
		return(-4);  
	}  
  
	//跳转的数据区  
	fseek(fp, FileHead.cfoffBits, SEEK_SET);  
	//每行字节数  
	BytesPerLine = (InfoHead.ciWidth * InfoHead.ciBitCount + 31) / 32 * 4;	
	line_x = line_y = 0;  
	//向framebuffer中写BMP图片  
	while(!feof(fp))  
	{  
		PIXEL pix;	
		rc = fread( (char *)&pix, 1, sizeof(PIXEL), fp);  
		if (rc != sizeof(PIXEL))  
			break;	
		location = line_x * bits_per_pixel / 8 + (InfoHead.ciHeight - line_y - 1) * xres * bits_per_pixel / 8;	
  
		//显示每一个像素  
		*(fbp + location + 0)=pix.blue;  
		*(fbp + location + 1)=pix.green;  
		*(fbp + location + 2)=pix.red;	
		*(fbp + location + 3)=0;  
		line_x++;  
		if (line_x == InfoHead.ciWidth)  
		{  
			line_x = 0;  
			line_y++;  
			if(line_y == InfoHead.ciHeight)  
				break;	
		}  
	}  
	fclose(fp);  
	return(0);  
} 

  

以上是关于linux应用编程--显示bmp图片的主要内容,如果未能解决你的问题,请参考以下文章

Linux应用开发-LCD显示BMP图片

Linux framebuffer显示bmp图片

正点原子I.MX6U-MINI应用篇5嵌入式Linux在LCD上显示BMPJPGPNG图片

提取bmp图片的颜色信息,可直接framebuffer显示

Linux LCD 显示图片

为啥 SDL 程序不显示 BMP 图片?