24位位图转4位彩色图(BMP)
2013-04-15 14:31
417 查看
24位位图转4位彩色图(BMP)
之前的“24位位图转4位灰度图”中已经说明了,调色板与图象数据格式。
这里对图象数据格式做下补充,并讲解24位位图转4位彩色图的算法
1.图象数据格式
在我完成这个算法的编码时,运行效果有一个非常严重的错误,就是所有的蓝和红色反了。也就是说,应该是蓝色的地方呈现了红色,应该是红色的地方呈现了兰色。
我的分析为:因为一般来说,BMP文件的数据是从上到下、从左到右的(参考:精通Visual C++数字图象处理典型算法及实现,第二版18页).
所以我们在缓存中
R = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
B = pBuffer[dwIndex++];
这样度取RGB,实际上是不对的,这样就把R和B读反了,最先读出来的应该是B然后是G然后是R。
通过实验,我把整个屏幕都弄成蓝色(非纯蓝)的然后截图,然后把按RGB顺序读取截图的数值输入到文件中,之后在WINDOWS 的调色板中,输入参数RGB观察颜色,发现呈现出的颜色是某种暗绿色,而将R与B调换之后,呈现出的颜色正是我屏幕的颜色。这样就更证明了我的假设。当我把所有度曲颜色的R与B调换之后,非常完美,完全呈现了正确的颜色。
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
2.转换算法
首先来确定一下,4位16色,到底有哪16色。
首先R,G,B各三种颜色,再有R,G,B两两组合又有三种颜色。
再就是以上的六种颜色有深浅之分,这就12种颜色
例如(255,0,0)浅红
(128,0,0)深红
然后
(0,0,0)黑色
(64,64,64)深灰
(128,128,128)浅灰
(255,255,255)白色
这是一共16种颜色。
我是这样想的,在颜色中除了灰度的颜色,其他的所有颜色的R,G,B的值只有0,128,255三种。
由这三个值组成的所有组合一共27个,分别如下
0 0 0 0
1 0 0 128
2 0 0 255
3 0 128 0
4 0 128 128
5 0 128 255
6 0 255 0
7 0 255 128
8 0 255 255
9 128 0 0
10 128 0 128
11 128 0 255
12 128 128 0
13 128 128 128
14 128 128 255
15 128 255 0
16 128 255 128
17 128 255 255
18 255 0 0
19 255 0 128
20 255 0 255
21 255 128 0
22 255 128 128
23 255 128 255
24 255 255 0
25 255 255 128
26 255 255 255
按照这个循序排列有一个好处。就是如果我知道(R,G,B )的值就能通过公式计算找到他在数组中的位置。
例如(128,255,255)
第一个数是R=128则这组颜色的标号一定是9-17这一组中,
G=255,那么这个颜色的标号一定是9-17这组中的第7-9个
B=255,那么这个颜色的标号一定是9-17这组中的第7-9个的第3个
另p表示颜色的标号,那么
if(R==0) p = 0;
else if(R==128) p = 9;
else if(R==255) p = 18;
if(G==0) p += 0;
else if(G==128) p += 3;
else if(G==255) p += 6;
if(B==0) p += 0;
else if(B==128) p += 1;
else if(B==255) p += 2;
这样p最后得到的就是颜色的标号.
具体代码如下
int GetR(UCHAR R)
{
if(R==0)
return 0;
if(R==128)
return 9;
if(R==255)
return 18;
}
int GetG(UCHAR G)
{
if(G==0)
return 0;
if(G==128)
return 3;
if(G==255)
return 6;
}
int GetB(UCHAR B)
{
if(B==0)
return 0;
if(B==128)
return 1;
if(B==255)
return 2;
}
int p = GetR(R) + GetG(G) + GetB(B);
为什么要把这27种颜色标号呢??因为这27种颜色中我们只需要12种(黑色,灰色,白色另做处理,标号中保留这三种颜色是为了方便公式计算),我的想法是先将一种颜色转换成这27种颜色中的一种,然后在看看这种颜色和那12种颜色中哪个最接近。
建立如下16色调色板
void SetRGB(RGBQUAD &pa,UCHAR R,UCHAR G,UCHAR B)
{
pa.rgbRed = R;
pa.rgbGreen = G;
pa.rgbBlue = B;
pa.rgbReserved = 0;
}
// 创建调色板
RGBQUAD pa[16];
SetRGB(pa[0],0,0,0);
SetRGB(pa[1],0,0,128);
SetRGB(pa[2],0,0,255);
SetRGB(pa[3],0,128,0);
SetRGB(pa[4],0,128,128);
SetRGB(pa[5],0,255,0);
SetRGB(pa[6],0,255,255);
SetRGB(pa[7],128,0,0);
SetRGB(pa[8],128,0,128);
SetRGB(pa[9],128,128,0);
SetRGB(pa[10],128,128,128);
SetRGB(pa[11],255,255,255);
SetRGB(pa[12],255,0,0);
SetRGB(pa[13],255,0,255);
SetRGB(pa[14],255,255,0);
SetRGB(pa[15],64,64,64);
按照这个顺序排列16色,那么我27色的数组中保存的就是这27种颜色对应这16色的标号
例如27色中的(0,0,0)就对应16色中的(0,0,0)所以这个27色数组中color[0]=0;
而(0,128,255)这种颜色,通过调色板比较,这个颜色近似(0,128,128)这样没有丢失颜色只是颜色更深一些。
通过这种比较得出这27色的数组为
int color[27] = {0,1,2,3,4,4,5,4,6,7,8,8,9,10,10,9,10,6,12,8,13,9,10,13,14,14,11};
现在来总结下如何从一个颜色得到的这27色。
我实验了一下,发现一个颜色的R,G,B三个数的方差小于20(近似数,只是眼睛的观察取得和计算方差得到这个数值,没有数学证明依据,如果哪位数学大牛能用数学证明出一个数更合适,希望可以分享一下)时,这个颜色很接近灰度色。再根据平均值判断下更接近0,64,128,255哪个。
如果不是灰度色,我的原则是突出重要颜色,忽略次要颜色。
例如0 63 240平均值是101,方差是101.597显然它不是灰度色,
而主要颜色是B=240,重要颜色向高进,次要颜色向低舍
这样这个颜色就近似成(0,0,255)在27色数组中p = 0 + 0 + 2 = 2; 在16色中标号color[2] = 2;
再例如(70,140,200)平均数为136近似成(0,255,255)color[p = 0 + 6 + 2] = 6
(100,129,200)平均数为143近似为(0,128,255) color[p = 0 + 3 + 2] = 4(0,128,128)
具体代码如下
UCHAR GetL(UCHAR C)//忽略次要颜色,向低舍
{
if(C>=0&&C<128)
{
return 0;
}
if(C>=128&&C<255)
return 128;
return 255;
}
UCHAR GetH(UCHAR C)//重要颜色,向高进
{
if(C>0&&C<=128)
{
return 128;
}
if(C>128&&C<=255)
return 255;
return 0;
}
/**********
*计算标记*
***********/
int GetR(UCHAR R)
{
if(R==0)
return 0;
if(R==128)
return 9;
if(R==255)
return 18;
}
int GetG(UCHAR G)
{
if(G==0)
return 0;
if(G==128)
return 3;
if(G==255)
return 6;
}
int GetB(UCHAR B)
{
if(B==0)
return 0;
if(B==128)
return 1;
if(B==255)
return 2;
}
/******************************
*获取更接近的灰度,通过平均值*
*******************************/
int GetGray(double ave)
{
int t1,t2;
if(ave>=0&&ave<=64)
{
t1 = ave - 0;
t2 = 128 - ave;
if(t1<t2)
return 0;
return 64;
}
if(ave>64&&ave<=128)
{
t1 = ave - 64;
t2 = 128 - ave;
if(t1<t2)
return 64;
return 128;
}
t1 = ave - 128;
t2 = 255 - ave;
if(t1<t2)
return 128;
return 255;
}
int GetColor(double ave,UCHAR C)//返回一个颜色近似后的值
{
if(C>ave)//突出主要颜色
return GetH(C);
return GetL(C);//忽略次要颜色
}
int GetRGB(UCHAR R,UCHAR G,UCHAR B)//返回调色板中的标号
{
int color[27] = {0,1,2,3,4,4,5,4,6,7,8,8,9,10,10,9,10,6,12,8,13,9,10,13,14,14,11};
//计算平均值
double ave = (R + G + B)/3;
//计算方差
double var = ((R-ave)*(R-ave)+(G-ave)*(G-ave)+(B-ave)*(B-ave))/3.0;
var = sqrt(var);
if(var<=20)//判断是否为灰度色
{
switch(GetGray(ave))
{
case 0: return 0;
case 64: return 15;
case 128: return 10;
case 255: return 11;
}
}
R = GetColor(ave,R);
G = GetColor(ave,G);
B = GetColor(ave,B);
int p = GetR(R) + GetG(G) + GetB(B);
return color[p];
}
3.具体代码
BOOL Convert24To4Cai(LPCTSTR lpszSrcFile, LPCTSTR lpszDestFile)//24->4彩
{
BITMAPFILEHEADER bmHdr; // BMP文件头
BITMAPINFOHEADER bmInfo; // BMP文件信息
HANDLE hFile, hNewFile;
DWORD dwByteWritten = 0;
// 打开源文件句柄
hFile = CreateFile(lpszSrcFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
// 创建新文件
hNewFile = CreateFile(lpszDestFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hNewFile == INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
return FALSE;
}
// 读取源文件BMP头和文件信息
ReadFile(hFile, &bmHdr, sizeof(bmHdr), &dwByteWritten, NULL);
ReadFile(hFile, &bmInfo, sizeof(bmInfo), &dwByteWritten, NULL);
TRACE("biSize: %d , biWidth: %d , biHeight: %d , biBitCount: %d , biSizeImage: %d /n",bmInfo.biSize,bmInfo.biWidth,bmInfo.biHeight,bmInfo.biBitCount,bmInfo.biSizeImage);
TRACE("biX: %d , biY: %d , biClrUsed: %d , biClrImportant: %d /n",bmInfo.biXPelsPerMeter,bmInfo.biYPelsPerMeter,bmInfo.biClrUsed,bmInfo.biClrImportant);
// 只处理24位未压缩的图像
if (bmInfo.biBitCount != 24 || bmInfo.biCompression!=0)
{
CloseHandle(hNewFile);
CloseHandle(hFile);
DeleteFile(lpszDestFile);
return FALSE;
}
// 计算图像数据大小
DWORD dwOldSize = bmInfo.biSizeImage;
if(dwOldSize == 0) // 重新计算
{
dwOldSize = bmHdr.bfSize - sizeof(bmHdr) - sizeof(bmInfo);
}
TRACE("Old Width: %d , Old Height: %d ,Old Size: %d bytes/n",bmInfo.biWidth,bmInfo.biHeight,dwOldSize);
long wid = bmInfo.biWidth % 4;
if(wid>0)
{
wid = 4 - wid;
}
wid += bmInfo.biWidth;
DWORD dwNewSize;
dwNewSize = wid * bmInfo.biHeight / 2; //计算转换后新图象大小
TRACE("New Size: %d bytes/n", dwNewSize);
// 读取原始数据
UCHAR *pBuffer = NULL;
pBuffer = new UCHAR[dwOldSize]; // 申请原始数据空间
if(pBuffer == NULL)
{
CloseHandle(hNewFile);
CloseHandle(hFile);
DeleteFile(lpszDestFile);
return FALSE;
}
// 读取数据
ReadFile(hFile, pBuffer, dwOldSize, &dwByteWritten, NULL);
UCHAR *pNew = new UCHAR[dwNewSize];
DWORD dwIndex = 0, dwOldIndex = 0;
while( dwIndex < dwOldSize )//一字节表示两个像素
{
USHORT R,G,B;
////////////////////////////////////////////////////////////////
// 第一个像素
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
int maxcolor = GetRGB(R,G,B);
//第二个像素
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
int maxcolor2 = GetRGB(R,G,B);
pNew[dwOldIndex++] = ( maxcolor<<4 )| maxcolor2;//合成一个字节表示两个像素
}
// out.Close();
////////////////////////////////////////////////////////////////////////////////
// 完工, 把结果保存到新文件中
// 修改属性
bmHdr.bfSize = sizeof(bmHdr)+sizeof(bmInfo)+sizeof(RGBQUAD)*16+dwNewSize;
bmHdr.bfOffBits = bmHdr.bfSize - dwNewSize;
bmInfo.biBitCount = 4;
bmInfo.biSizeImage = dwNewSize;
// 创建调色板
RGBQUAD pa[16];
SetRGB(pa[0],0,0,0);
SetRGB(pa[1],0,0,128);
SetRGB(pa[2],0,0,255);
SetRGB(pa[3],0,128,0);
SetRGB(pa[4],0,128,128);
SetRGB(pa[5],0,255,0);
SetRGB(pa[6],0,255,255);
SetRGB(pa[7],128,0,0);
SetRGB(pa[8],128,0,128);
SetRGB(pa[9],128,128,0);
SetRGB(pa[10],128,128,128);
SetRGB(pa[11],255,255,255);
SetRGB(pa[12],255,0,0);
SetRGB(pa[13],255,0,255);
SetRGB(pa[14],255,255,0);
SetRGB(pa[15],64,64,64);
// BMP头
WriteFile(hNewFile, &bmHdr, sizeof(bmHdr), &dwByteWritten, NULL);
// 文件信息头
WriteFile(hNewFile, &bmInfo, sizeof(bmInfo), &dwByteWritten, NULL);
// 调色板
WriteFile(hNewFile, pa, sizeof(RGBQUAD)*16, &dwByteWritten, NULL);
// 文件数据
WriteFile(hNewFile, pNew, dwNewSize, &dwByteWritten, NULL);
delete []pBuffer;
delete []pNew;
// 关闭文件句柄
CloseHandle(hNewFile);
CloseHandle(hFile);
return TRUE;
}
之前的“24位位图转4位灰度图”中已经说明了,调色板与图象数据格式。
这里对图象数据格式做下补充,并讲解24位位图转4位彩色图的算法
1.图象数据格式
在我完成这个算法的编码时,运行效果有一个非常严重的错误,就是所有的蓝和红色反了。也就是说,应该是蓝色的地方呈现了红色,应该是红色的地方呈现了兰色。
我的分析为:因为一般来说,BMP文件的数据是从上到下、从左到右的(参考:精通Visual C++数字图象处理典型算法及实现,第二版18页).
所以我们在缓存中
R = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
B = pBuffer[dwIndex++];
这样度取RGB,实际上是不对的,这样就把R和B读反了,最先读出来的应该是B然后是G然后是R。
通过实验,我把整个屏幕都弄成蓝色(非纯蓝)的然后截图,然后把按RGB顺序读取截图的数值输入到文件中,之后在WINDOWS 的调色板中,输入参数RGB观察颜色,发现呈现出的颜色是某种暗绿色,而将R与B调换之后,呈现出的颜色正是我屏幕的颜色。这样就更证明了我的假设。当我把所有度曲颜色的R与B调换之后,非常完美,完全呈现了正确的颜色。
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
2.转换算法
首先来确定一下,4位16色,到底有哪16色。
首先R,G,B各三种颜色,再有R,G,B两两组合又有三种颜色。
再就是以上的六种颜色有深浅之分,这就12种颜色
例如(255,0,0)浅红
(128,0,0)深红
然后
(0,0,0)黑色
(64,64,64)深灰
(128,128,128)浅灰
(255,255,255)白色
这是一共16种颜色。
我是这样想的,在颜色中除了灰度的颜色,其他的所有颜色的R,G,B的值只有0,128,255三种。
由这三个值组成的所有组合一共27个,分别如下
0 0 0 0
1 0 0 128
2 0 0 255
3 0 128 0
4 0 128 128
5 0 128 255
6 0 255 0
7 0 255 128
8 0 255 255
9 128 0 0
10 128 0 128
11 128 0 255
12 128 128 0
13 128 128 128
14 128 128 255
15 128 255 0
16 128 255 128
17 128 255 255
18 255 0 0
19 255 0 128
20 255 0 255
21 255 128 0
22 255 128 128
23 255 128 255
24 255 255 0
25 255 255 128
26 255 255 255
按照这个循序排列有一个好处。就是如果我知道(R,G,B )的值就能通过公式计算找到他在数组中的位置。
例如(128,255,255)
第一个数是R=128则这组颜色的标号一定是9-17这一组中,
G=255,那么这个颜色的标号一定是9-17这组中的第7-9个
B=255,那么这个颜色的标号一定是9-17这组中的第7-9个的第3个
另p表示颜色的标号,那么
if(R==0) p = 0;
else if(R==128) p = 9;
else if(R==255) p = 18;
if(G==0) p += 0;
else if(G==128) p += 3;
else if(G==255) p += 6;
if(B==0) p += 0;
else if(B==128) p += 1;
else if(B==255) p += 2;
这样p最后得到的就是颜色的标号.
具体代码如下
int GetR(UCHAR R)
{
if(R==0)
return 0;
if(R==128)
return 9;
if(R==255)
return 18;
}
int GetG(UCHAR G)
{
if(G==0)
return 0;
if(G==128)
return 3;
if(G==255)
return 6;
}
int GetB(UCHAR B)
{
if(B==0)
return 0;
if(B==128)
return 1;
if(B==255)
return 2;
}
int p = GetR(R) + GetG(G) + GetB(B);
为什么要把这27种颜色标号呢??因为这27种颜色中我们只需要12种(黑色,灰色,白色另做处理,标号中保留这三种颜色是为了方便公式计算),我的想法是先将一种颜色转换成这27种颜色中的一种,然后在看看这种颜色和那12种颜色中哪个最接近。
建立如下16色调色板
void SetRGB(RGBQUAD &pa,UCHAR R,UCHAR G,UCHAR B)
{
pa.rgbRed = R;
pa.rgbGreen = G;
pa.rgbBlue = B;
pa.rgbReserved = 0;
}
// 创建调色板
RGBQUAD pa[16];
SetRGB(pa[0],0,0,0);
SetRGB(pa[1],0,0,128);
SetRGB(pa[2],0,0,255);
SetRGB(pa[3],0,128,0);
SetRGB(pa[4],0,128,128);
SetRGB(pa[5],0,255,0);
SetRGB(pa[6],0,255,255);
SetRGB(pa[7],128,0,0);
SetRGB(pa[8],128,0,128);
SetRGB(pa[9],128,128,0);
SetRGB(pa[10],128,128,128);
SetRGB(pa[11],255,255,255);
SetRGB(pa[12],255,0,0);
SetRGB(pa[13],255,0,255);
SetRGB(pa[14],255,255,0);
SetRGB(pa[15],64,64,64);
按照这个顺序排列16色,那么我27色的数组中保存的就是这27种颜色对应这16色的标号
例如27色中的(0,0,0)就对应16色中的(0,0,0)所以这个27色数组中color[0]=0;
而(0,128,255)这种颜色,通过调色板比较,这个颜色近似(0,128,128)这样没有丢失颜色只是颜色更深一些。
通过这种比较得出这27色的数组为
int color[27] = {0,1,2,3,4,4,5,4,6,7,8,8,9,10,10,9,10,6,12,8,13,9,10,13,14,14,11};
现在来总结下如何从一个颜色得到的这27色。
我实验了一下,发现一个颜色的R,G,B三个数的方差小于20(近似数,只是眼睛的观察取得和计算方差得到这个数值,没有数学证明依据,如果哪位数学大牛能用数学证明出一个数更合适,希望可以分享一下)时,这个颜色很接近灰度色。再根据平均值判断下更接近0,64,128,255哪个。
如果不是灰度色,我的原则是突出重要颜色,忽略次要颜色。
例如0 63 240平均值是101,方差是101.597显然它不是灰度色,
而主要颜色是B=240,重要颜色向高进,次要颜色向低舍
这样这个颜色就近似成(0,0,255)在27色数组中p = 0 + 0 + 2 = 2; 在16色中标号color[2] = 2;
再例如(70,140,200)平均数为136近似成(0,255,255)color[p = 0 + 6 + 2] = 6
(100,129,200)平均数为143近似为(0,128,255) color[p = 0 + 3 + 2] = 4(0,128,128)
具体代码如下
UCHAR GetL(UCHAR C)//忽略次要颜色,向低舍
{
if(C>=0&&C<128)
{
return 0;
}
if(C>=128&&C<255)
return 128;
return 255;
}
UCHAR GetH(UCHAR C)//重要颜色,向高进
{
if(C>0&&C<=128)
{
return 128;
}
if(C>128&&C<=255)
return 255;
return 0;
}
/**********
*计算标记*
***********/
int GetR(UCHAR R)
{
if(R==0)
return 0;
if(R==128)
return 9;
if(R==255)
return 18;
}
int GetG(UCHAR G)
{
if(G==0)
return 0;
if(G==128)
return 3;
if(G==255)
return 6;
}
int GetB(UCHAR B)
{
if(B==0)
return 0;
if(B==128)
return 1;
if(B==255)
return 2;
}
/******************************
*获取更接近的灰度,通过平均值*
*******************************/
int GetGray(double ave)
{
int t1,t2;
if(ave>=0&&ave<=64)
{
t1 = ave - 0;
t2 = 128 - ave;
if(t1<t2)
return 0;
return 64;
}
if(ave>64&&ave<=128)
{
t1 = ave - 64;
t2 = 128 - ave;
if(t1<t2)
return 64;
return 128;
}
t1 = ave - 128;
t2 = 255 - ave;
if(t1<t2)
return 128;
return 255;
}
int GetColor(double ave,UCHAR C)//返回一个颜色近似后的值
{
if(C>ave)//突出主要颜色
return GetH(C);
return GetL(C);//忽略次要颜色
}
int GetRGB(UCHAR R,UCHAR G,UCHAR B)//返回调色板中的标号
{
int color[27] = {0,1,2,3,4,4,5,4,6,7,8,8,9,10,10,9,10,6,12,8,13,9,10,13,14,14,11};
//计算平均值
double ave = (R + G + B)/3;
//计算方差
double var = ((R-ave)*(R-ave)+(G-ave)*(G-ave)+(B-ave)*(B-ave))/3.0;
var = sqrt(var);
if(var<=20)//判断是否为灰度色
{
switch(GetGray(ave))
{
case 0: return 0;
case 64: return 15;
case 128: return 10;
case 255: return 11;
}
}
R = GetColor(ave,R);
G = GetColor(ave,G);
B = GetColor(ave,B);
int p = GetR(R) + GetG(G) + GetB(B);
return color[p];
}
3.具体代码
BOOL Convert24To4Cai(LPCTSTR lpszSrcFile, LPCTSTR lpszDestFile)//24->4彩
{
BITMAPFILEHEADER bmHdr; // BMP文件头
BITMAPINFOHEADER bmInfo; // BMP文件信息
HANDLE hFile, hNewFile;
DWORD dwByteWritten = 0;
// 打开源文件句柄
hFile = CreateFile(lpszSrcFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
// 创建新文件
hNewFile = CreateFile(lpszDestFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hNewFile == INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
return FALSE;
}
// 读取源文件BMP头和文件信息
ReadFile(hFile, &bmHdr, sizeof(bmHdr), &dwByteWritten, NULL);
ReadFile(hFile, &bmInfo, sizeof(bmInfo), &dwByteWritten, NULL);
TRACE("biSize: %d , biWidth: %d , biHeight: %d , biBitCount: %d , biSizeImage: %d /n",bmInfo.biSize,bmInfo.biWidth,bmInfo.biHeight,bmInfo.biBitCount,bmInfo.biSizeImage);
TRACE("biX: %d , biY: %d , biClrUsed: %d , biClrImportant: %d /n",bmInfo.biXPelsPerMeter,bmInfo.biYPelsPerMeter,bmInfo.biClrUsed,bmInfo.biClrImportant);
// 只处理24位未压缩的图像
if (bmInfo.biBitCount != 24 || bmInfo.biCompression!=0)
{
CloseHandle(hNewFile);
CloseHandle(hFile);
DeleteFile(lpszDestFile);
return FALSE;
}
// 计算图像数据大小
DWORD dwOldSize = bmInfo.biSizeImage;
if(dwOldSize == 0) // 重新计算
{
dwOldSize = bmHdr.bfSize - sizeof(bmHdr) - sizeof(bmInfo);
}
TRACE("Old Width: %d , Old Height: %d ,Old Size: %d bytes/n",bmInfo.biWidth,bmInfo.biHeight,dwOldSize);
long wid = bmInfo.biWidth % 4;
if(wid>0)
{
wid = 4 - wid;
}
wid += bmInfo.biWidth;
DWORD dwNewSize;
dwNewSize = wid * bmInfo.biHeight / 2; //计算转换后新图象大小
TRACE("New Size: %d bytes/n", dwNewSize);
// 读取原始数据
UCHAR *pBuffer = NULL;
pBuffer = new UCHAR[dwOldSize]; // 申请原始数据空间
if(pBuffer == NULL)
{
CloseHandle(hNewFile);
CloseHandle(hFile);
DeleteFile(lpszDestFile);
return FALSE;
}
// 读取数据
ReadFile(hFile, pBuffer, dwOldSize, &dwByteWritten, NULL);
UCHAR *pNew = new UCHAR[dwNewSize];
DWORD dwIndex = 0, dwOldIndex = 0;
while( dwIndex < dwOldSize )//一字节表示两个像素
{
USHORT R,G,B;
////////////////////////////////////////////////////////////////
// 第一个像素
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
int maxcolor = GetRGB(R,G,B);
//第二个像素
B = pBuffer[dwIndex++];
G = pBuffer[dwIndex++];
R = pBuffer[dwIndex++];
int maxcolor2 = GetRGB(R,G,B);
pNew[dwOldIndex++] = ( maxcolor<<4 )| maxcolor2;//合成一个字节表示两个像素
}
// out.Close();
////////////////////////////////////////////////////////////////////////////////
// 完工, 把结果保存到新文件中
// 修改属性
bmHdr.bfSize = sizeof(bmHdr)+sizeof(bmInfo)+sizeof(RGBQUAD)*16+dwNewSize;
bmHdr.bfOffBits = bmHdr.bfSize - dwNewSize;
bmInfo.biBitCount = 4;
bmInfo.biSizeImage = dwNewSize;
// 创建调色板
RGBQUAD pa[16];
SetRGB(pa[0],0,0,0);
SetRGB(pa[1],0,0,128);
SetRGB(pa[2],0,0,255);
SetRGB(pa[3],0,128,0);
SetRGB(pa[4],0,128,128);
SetRGB(pa[5],0,255,0);
SetRGB(pa[6],0,255,255);
SetRGB(pa[7],128,0,0);
SetRGB(pa[8],128,0,128);
SetRGB(pa[9],128,128,0);
SetRGB(pa[10],128,128,128);
SetRGB(pa[11],255,255,255);
SetRGB(pa[12],255,0,0);
SetRGB(pa[13],255,0,255);
SetRGB(pa[14],255,255,0);
SetRGB(pa[15],64,64,64);
// BMP头
WriteFile(hNewFile, &bmHdr, sizeof(bmHdr), &dwByteWritten, NULL);
// 文件信息头
WriteFile(hNewFile, &bmInfo, sizeof(bmInfo), &dwByteWritten, NULL);
// 调色板
WriteFile(hNewFile, pa, sizeof(RGBQUAD)*16, &dwByteWritten, NULL);
// 文件数据
WriteFile(hNewFile, pNew, dwNewSize, &dwByteWritten, NULL);
delete []pBuffer;
delete []pNew;
// 关闭文件句柄
CloseHandle(hNewFile);
CloseHandle(hFile);
return TRUE;
}
相关文章推荐
- 实现1位,4位,8位,24位BMP位图的互相转换的方法,32位转24位
- 24位真彩位图转4位(16色)灰度图(BMP)
- 24位真彩位图转4位(16色)灰度图(BMP) .
- C/C++ BMP(24位真彩色)图像处理(1)------图像打开与数据区处理
- C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转
- BMP位图32位转为24位深度
- bmp文件格式中rgb555与rgb888之间的转换,24位与16位位图的转换
- 完整24位真彩色位图灰度化源代码
- C/C++ BMP(24位真彩色)图像处理(1)------图像の打开与数据区处理
- 把24位和32位BMP位图转为灰色bmp位图
- C语言实现将彩色BMP位图转化为二值图
- bmp24位彩色图像转8位灰度图像(纯C++)
- bmp位图文件:读取、写入、24位真彩转8位灰度、灰度图的二值化
- 完整24位真彩色位图灰度化源代码
- 为什么24位位图(真彩色)的biSizeImage不等于(biWidth*biBitCount+31)/32*4*biHeight?
- BMP的8位位图转换24位位图
- 24位真彩色位图转换成8位灰度图片的代码实现
- 将24位真彩色位图保存为256色(8位)位图
- C/C++ BMP(24位真彩色)图像处理(2)------图像截取
- BMP--24位真彩色转换为灰度图像