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位图像基本上没有颜色区别。
bmp文件格式中rgb555与rgb888之间的转换,24位与16位位图的转换的更多相关文章
- BMP文件格式分析
前两天要做一个读取bmp文件的小程序,顺便查找了一些关于BMP格式的文章,现在post上来. 简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运 ...
- BMP文件格式及读写
转 http://blog.csdn.net/pkueecser/article/details/5579604 http://blog.csdn.net/pkueecser/article/deta ...
- Windows下bmp文件格式
6.1 BMP文件格式 6.1.1 简介 位图文件(Bitmap-File,BMP)格式是Windows采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式.Window ...
- BMP文件格式详解
BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广 ...
- bmp文件格式详细解析
先区分几个概念:16色和16位色一样吗? 不一样! 颜色位数,即是用多少位字节表示的值,每一位可以表示0和1两值.通常图片的颜色深度,简称色深,就是用位数来表示的,所以,我通常会看到8位色,16位色, ...
- OpenGL学习--05--纹理立方体--BMP文件格式详解(转载)
http://blog.csdn.net/o_sun_o/article/details/8351037 BMP文件格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称 ...
- BMP文件格式实例分析
1. 以下为一个RGB565-16位BMP位图实际的部分数据: 00000000h: 42 4D 46 58 02 00 00 00 00 00 46 00 00 00 28 00 ; BMFX... ...
- 【转】bmp文件格式详解
先区分几个概念:16色和16位色一样吗? 不一样! 颜色位数,即是用多少位字节表示的值,每一位可以表示0和1两值.通常图片的颜色深度,简称色深,就是用位数来表示的,所以,我通常会看到8位色,16位色, ...
- BMP文件格式具体解释
BMP文件格式具体解释(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统 ...
随机推荐
- nohup和&后台运行,查看占用端口进程
1.nohup 用途:不挂断地运行命令. 语法:nohup Command [ Arg - ] [ & ] 无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup ...
- 【最新版】从零开始在 macOS 上配置 Lua 开发环境
脚本语言,你可能更需要的是 Lua 不同的脚本语言有不同的特性,第一接触的脚本语言,可能会影响自己对整个脚本语言的理解和认知.我以前接触最多的脚本语言是 JavaScript.后果就是:我一度以为脚本 ...
- 配置好postfix邮件服务器之后就可以使用它来发送邮件了
下面是一段摘自W3school关于php mail函数的栗子,经过测试发现两个问题. <?php $to = "somebody@example.com, somebodyelse@e ...
- CSS实现父元素半透明,子元素不透明
CSS实现父元素半透明,子元素不透明. 很久以来大家都习惯使用opacity:0.5在新式浏览器里实现半透明,而对IE较旧的版本使用filter:Alpha(opacity=0.5)的滤镜来实现半透明 ...
- [java语言]——InetAddress类的getByName()方法
InetAddress---表示互联网协议(IP)地址 ---InetAddress.getByName("www.163.com")----在给定主机名的情况下确定主机的IP地址 ...
- 前端html 中jQuery实现对文本的搜索并把搜索相关内容显示出来
做项目的时候有这么一个需求,客户信息显示出来后我要搜索查找相关的客户,并把相关的客户信息全部显示出来,因为一个客户全部信息我写在一个div里面 所以显示的时候就是显示整个div.先看看实现的效果: ...
- 《天书夜读:从汇编语言到windows内核编程》十一 用C++编写内核程序
---恢复内容开始--- 1) C++的"高级"特性,是它的优点也是它的缺点,微软对于使用C++写内核程序即不推崇也不排斥,使用C++写驱动需注意: a)New等操作符不能直接使用 ...
- ArrayList迭代过程删除问题
一:首先看下几个ArrayList循环过程删除元素的方法(一下内容均基于jdk7): package list; import java.util.ArrayList; import java.uti ...
- 源码剖析Django REST framework的请求生命周期
学习Django的时候知道,在Django请求的生命周期中,请求经过WSGI和中间件到达路由,不管是FBV还是CBV都会先执行View视图函数中的dispatch方法 REST framework是基 ...
- javascript面向对象编程(OOP)——汇总
目录 一.JS的解析与执行过程 预处理阶段 执行阶段 二.作用域 块作用域 函数作用域 动态作用域 词法作用域 三.闭包 什么是闭包 闭包的好处 四.类与对象 对象 类 原型(prototype) t ...