bmp文件格式中rgb555与rgb888之间的转换,24位与16位位图的转换

今日,有同事问我,rgb555模式下的位图文件的格式问题,于是花了一下午的时间通过猜测与测试,分析出了如下bmp文件在rgb555模式下的文件存储规律:

1:bmp文件的文件信息头中的biBitCount数据应该为16

在rgb555模式下,一个像素占用2字节,rgb分别占用5位,另外有一位是填充位。

2:16位数据的组成如下

第一个字节:g5g4g3b7b6b5b4b3

第二个字节:0r7r6r5r4r3g7g6

其中第二个字节的左边第一位为填充位,我在实验中用0填充。

3:该16位bmp图像无调色板数据

4:该16位bmp图像在显示时,图片浏览软件(如windows画图)会将rgb555自动转换为rgb888显示。具体的方法如下

b7b6b5b4b3->b7b6b5b4b3b7b6b5

r7r6r5r4r3->r7r6r5r4r7r6r5

g7g6g5g4g3->r7r6r5r4g7g6g5

测试图片如下

上面的图像为24位bmp图像,从左往右的色带的像素值BGR分别为

0,0,128

0,128,0

128,0,0

0,0,64

0,64,0

64,0,0

32,0,0

如果将图像转换为rgb55模式的bmp文件格式,则转换后的文件为16位的bmp文件。从左往右的色带中的像素值分别为

第一个字节  第二个字节

00000000    01000000

00000000    00000010

00010000    00000000

00000000    00100000

00000000    00000001

00001000    00000000

00000100    00000000

转换代码如下:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

BYTE *Read24BitBmpFile2Img(const char * filename,int *width,int *height)
{
	FILE * BinFile;
    BITMAPFILEHEADER FileHeader;
    BITMAPINFOHEADER BmpHeader;
	BYTE *img;
	unsigned int size;
	int Suc=1,w,h;

	// Open File
	*width=*height=0;
	if((BinFile=fopen(filename,"rb"))==NULL) return NULL;
	// Read Struct Info
	if (fread((void *)&FileHeader,1,sizeof(FileHeader),BinFile)!=sizeof(FileHeader)) Suc=-1;
	if (fread((void *)&BmpHeader,1,sizeof(BmpHeader),BinFile)!=sizeof(BmpHeader)) Suc=-1;
	if ( (Suc==-1) || (FileHeader.bfOffBits<sizeof(FileHeader)+sizeof(BmpHeader) ))
	{
			   fclose(BinFile);
			   return NULL;
	}
	// Read Image Data
	*width=w=BmpHeader.biWidth;
	*height=h=BmpHeader.biHeight;
	size=(*width)*(*height)*3;
	fseek(BinFile,FileHeader.bfOffBits,SEEK_SET);
	if ( (img=new BYTE[size])!=NULL)
	{
		for(int i=0;i<h;i++)
		{
			if(fread(img+(h-1-i)*w*3,sizeof(BYTE),w*3,BinFile)!=w*3)
			{
				fclose(BinFile);
				delete img;
				img=NULL;
				return NULL;
			}
			fseek(BinFile,(3*w+3)/4*4-3*w,SEEK_CUR);
		}
    }
    fclose(BinFile);
    return img;
}

void BGR8882BGR555(unsigned char *img888, unsigned char * img555,int width,int height)
{
	unsigned char *p = img888;
	unsigned char *q = img555;
	unsigned char r,g,b;
	unsigned char r1,g1,b1;
	int i ,j;
	for(i = 0;i< height;i++)
	{
		for(j = 0; j< width;j++)
		{
			b = *p;
			g = *(p+1);
			r = *(p+2);
			g1 = g>>6;
			r = (r>>3)<<2;
			*(q+1) = r | g1;
			g1 = ((g<<2)>>5)<<5;
			b1 = (b>>3);
			*(q) = g1 | b1;
			p+=3;
			q+=2;
		}
	}
}
bool Write555BitImg2BmpFile(BYTE *pImg,int width,int height,const char * filename)
// 当宽度不是4的倍数时自动添加成4的倍数
{
	FILE *BinFile;
    BITMAPFILEHEADER FileHeader;
    BITMAPINFOHEADER BmpHeader;
    bool Suc=true;
    int i,extend;
	BYTE p[4],*pCur;

    // Open File
    if((BinFile=fopen(filename,"w+b"))==NULL) {  return false; }
	// Fill the FileHeader
	FileHeader.bfType= ((WORD) ('M' << 8) | 'B');
	FileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
	FileHeader.bfSize=FileHeader.bfOffBits+width*height*3L ;
	FileHeader.bfReserved1=0;
	FileHeader.bfReserved2=0;
	if(fwrite((void*)&FileHeader,1,sizeof(BITMAPFILEHEADER),BinFile)!=sizeof(BITMAPFILEHEADER))
	Suc=false;
	// Fill the ImgHeader
	BmpHeader.biSize = 40;
    BmpHeader.biWidth = width;
	BmpHeader.biHeight = height;
	BmpHeader.biPlanes = 1 ;
	BmpHeader.biBitCount = 16 ;
	BmpHeader.biCompression = 0 ;
	BmpHeader.biSizeImage = 0 ;
	BmpHeader.biXPelsPerMeter = 0;
	BmpHeader.biYPelsPerMeter = 0;
	BmpHeader.biClrUsed = 0;
	BmpHeader.biClrImportant = 0;
	if(fwrite((void*)&BmpHeader,1,sizeof(BITMAPINFOHEADER),BinFile)!=sizeof(BITMAPINFOHEADER))
	Suc=false;

	// write image data
	extend=(2*width+2)/4*4-2*width;
	if (extend==0)
	{
		  for(pCur=pImg+(height-1)*2*width;pCur>=pImg;pCur-=2*width)
		  {
		    if (fwrite((void *)pCur,1,width*2,BinFile)!=(unsigned int)(2*width)) Suc=false; // 真实的数据
		  }
	}
	else
	{
	   for(pCur=pImg+(height-1)*2*width;pCur>=pImg;pCur-=2*width)
	   {
		 if (fwrite((void *)pCur,1,width*2,BinFile)!=(unsigned int)(2*width)) Suc=false; // 真实的数据
		 if (fwrite((void *)(pCur+2*(width-1)+0),1,extend,BinFile)!=1) Suc=false; // 扩充的数据
	   }
	}
	// return;
	fclose(BinFile);
	return Suc;
}

void main()
{
	int width,height;

	BYTE *pGryImg=Read24BitBmpFile2Img("test.bmp",&width,&height);
	printf("%d,%d",width,height);
	unsigned char *pImg555 = new unsigned char[width*height*2];

	BGR8882BGR555(pGryImg, pImg555,width,height);
	Write555BitImg2BmpFile(pImg555,width,height,"result.bmp");

	delete pGryImg;
	delete pImg555;
	return;
}

运行后生成文件result.bmp文件及其文件属性如下

用像素提取工具查看windows画图打开的result.bmp中各个色条的rgb值如下:

以最右边色带为例说明为什么rgb显示为0,0,33

在rgb555中最右边色带的像素值为第一个字节00000100    第二个字节00000000

根据第一个字节:g5g4g3b7b6b5b4b3第二个字节:0r7r6r5r4r3g7g6可知

b7b6b5b4b3为00100

r7r6r5r4r3为00000

g7g6g5g4g3为00000

按照rgb555转为rgb888的转换规则:

b7b6b5b4b3->b7b6b5b4b3b7b6b5

r7r6r5r4r3->r7r6r5r4r7r6r5

g7g6g5g4g3->r7r6r5r4g7g6g5

可以算得rgb888中r的8位数据为00000000,g的8位数据为000000,b的数据为00100001

换算为十进制为RGB(0,0,33)

测试一下自然图像:

原图:24位彩色图像 bmp文件格式

转换后的16位图像(RGB555格式)bmp文件及其文件属性如下:

可以看到16位图像与24位图像基本上没有颜色差别。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-02 06:59:09

bmp文件格式中rgb555与rgb888之间的转换,24位与16位位图的转换的相关文章

16位bmp文件中RGB555转RGB565算法

做tft彩屏显示图片的时候,显示16位位图,显示屏的显示模式为RGB565.使用img2lcd转换后的16位bmp,显示出来后,颜色有偏差:转换为565格式的bin文件,显示完全正常,可以确定转换为bmp后,格式为RGB555.网上查找相关资料显示,Windows 图片查看器显示正常的图片,均为RGB555格式,系统自带画图画图工具保存时,不支持将文件保存为16位位图格式. 以下为555转565的程序片段,转换后的结果和使用img2lcd软件保存为565格式的结果完全相同.转换的结果其实就是将原

BMP文件格式及读写

转 http://blog.csdn.net/pkueecser/article/details/5579604 http://blog.csdn.net/pkueecser/article/details/5573395 http://blog.csdn.net/holybin/article/details/25792741 ####################################################################################

C编程中的8位、16位、32位整数的分解与合并

在单片机的编程中对于8位.16位.32位整数的分解与合并用的比较多,今天做了简要学习,后面还需要加以总结. 练习在VC++6.0编程环境中进行,源程序:#include <stdio.h>#include "string.h" int main(int argc, char argv[]){ unsigned int Data_Uint32=0x12345678;unsigned short int Data_Uint16_1,Data_Uint16_2;unsigned

BMP文件格式,RGB之间格式转换 碰到坑,MARK

很多人在转储bmp文件的时候,会出现各种各样的问题,特别是抓屏的时候,经常保存下来的图片 怪怪的,偏差很大!比如下面: 有时候,明明感觉自己是对的,但往往结果很让人抓狂. 这种情况一般是对bmp文件格式理解不对,或者没有透彻导致,当然至少是显示出来,所以大部分是对的,只是某些地方出错! 网上也有很多bmp文件格式,但都说得不够透彻,导致实际总要走些弯路. bmp是常见图片格式,使用非常广泛.近期在处理ui库的时候,了解下bmp格式,也发现其中一些坑,记录下. bmp格式很简单,网上搜索一堆,百科

北亚工程师详细解说BMP文件格式

BMP是一种与硬件设备无关的图像文件格式,使用非常广.它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BblP文件所占用的空间很大.BMP文件的图像深度可选lbit.4bit.8bit及24bit.BMP文件存储数据时,图像的扫描方式是按从左到右.从下到上的顺序. 由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式. 典型的BMP图像文件由三部分组成:位图文件头数据结构,它包含BMP图像文件

bmp文件格式详细解析

先区分几个概念:16色和16位色一样吗? 不一样! 颜色位数,即是用多少位字节表示的值,每一位可以表示0和1两值.通常图片的颜色深度,简称色深,就是用位数来表示的,所以,我通常会看到8位色,16位色,24位色和32位色.而我们在其它地方看到的又是16色,256色,16777216色等等,这些怎么一回事呢? 16色即代表16种颜色,256色即256种颜色,8位色就是用8个位来表示的颜色,即2的8次方,就是256色,16位色2的16次方,就是65536色,24位即16777216色,32位即4294

BMP文件格式

BMP文件由文件头.位图信息头.颜色信息和图像数据4部分组成: 位图文件头结构BITMAPFILEHEADER 位图信息头结构BITMAPINFOHEADER 位图颜色表RGBQUAD 位图像素数据 1.位图文件头 位图文件头结构含有BMP文件的类型.文件大小和位图起始位置等信息.其结构定义如下: typedef struct tagBITMAPFILEHEADER { WORD bfType; //位图文件的类型,必须为BMP DWORD bfSize; //位图文件的大小,以字节为单位 WO

BMP文件格式具体解释

BMP文件格式具体解释(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广泛使用的图像文件格式.由于它能够不作不论什么变换地保存图像像素域的数据.因此成为我们取得RAW数据的重要来源.Windows的图形用户界面(graphical user interfaces)也在它的内建图像子系统GDI中对BMP格式提供了支持. 以下以Notepad++为分析工具,结合Wind

C#中 byte[] Image Bitmap之间的相互转化

/// <summary>         /// 将图片Image转换成Byte[]         /// </summary>         /// <param name="Image">image对象</param> /// <param name="imageFormat">后缀名</param> /// <returns></returns> public