TIFF数据 保存为 BMP 颜色失真

怎嘛回事 2014-09-12 01:19:08
资源: 16位的TIFF灰度图像。
目标:16位的BMP图像。
结果:
左侧tiff图像,右侧bmp图像。

保存为bmp时未使用调色板(不会用,tiff中无调色板)。

BYTE* pBmpData; //Bmp文件数据
BYTE ** pData; // 二维数组按照条带存放数据
BITMAPFILEHEADER bmpFileHeader; // Bmp文件头
BITMAPINFOHEADER bmpInfoHeader; // Bmp信息头指针

bool myTIFF::TiffDataToBMP() // Tiff 图像数据转为BMP数据
{
memset(&bmpFileHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&bmpInfoHeader, 0, sizeof(BITMAPINFOHEADER));
DWORD bfSize = ceil(double((iWidth*iHeight*2+54)/4.0))*4; // 用于4个字节对齐
bmpFileHeader.bfType = 0x4d42;
bmpFileHeader.bfSize = bfSize;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpFileHeader.bfReserved1 = 0 ;
bmpFileHeader.bfReserved2 = 0 ;

bmpInfoHeader.biBitCount = 16 ;
bmpInfoHeader.biWidth = iWidth ;
bmpInfoHeader.biHeight = iHeight ;
bmpInfoHeader.biPlanes = 1 ;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER) ;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biClrImportant = 0 ;
bmpInfoHeader.biClrUsed = 0 ;
bmpInfoHeader.biCompression = BI_RGB ;
bmpInfoHeader.biXPelsPerMeter = 0 ;
bmpInfoHeader.biYPelsPerMeter = 0 ;

if(pBmpData)
{
delete []pBmpData;
pBmpData = NULL;
}
DWORD dataSize = ceil(double((iWidth*iHeight*2)/4.0))*4;
pBmpData = new BYTE[dataSize];
memset(pBmpData,0,dataSize);
int lineLen = iWidth*iBit/8; // 每行的字节数
DWORD counts = 0; // 已拷贝到pBmpData的字节数(倒叙拷贝)
for (int i=0;i<iStripCounts;i++) // 条带数
{ // 数据的拷贝应该都没问题,因为图像显示是正确的,只是存在失真问题
int ij = FourByte2Dword(byteCounts,(iStripCounts-1-i)*iStripOffsetType)/lineLen;
for (int j=0;j<ij;j++)
{
StrictCpy(pBmpData,counts,pData[iStripCounts-1-i],j*lineLen,lineLen);
counts += lineLen;
}
}


delete []byteCounts;
byteCounts = NULL;

for (int k=0;k<iStripCounts;k++)
{
delete []pData[k];
}
delete []pData;

return true;
}

DWORD myTIFF::StrictCpy(BYTE*des,int pos,BYTE*src,int iBegin,int len) // 目标串 目标串位置 源串 源串开始位置 拷贝长度
{
ASSERT(des);
ASSERT(src);

int i = 0;
for (i=0;i<len;i++)
{
des[pos+i] = src[iBegin+i];
}
return (pos+len);
}

void myTIFF::DrawImage(HDC hdc, int iLeft, int iTop, int Width, int Height) // 用于绘图到控件,显示图像效果同保存后效果
{
if(!hdc || pBmpData == NULL)
return;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth = iWidth;
bmi.bmiHeader.biHeight = iHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = iBit;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = ceil(double((iWidth*iHeight*2+54)/4.0))*4;
StretchDIBits(hdc, iLeft, iTop, Width, Height,0, 0, iWidth,iHeight,pBmpData, &bmi, DIB_RGB_COLORS, SRCCOPY);// StretchDIBits
}

bool myTIFF::SaveBitmap(CString path) // 保存为BMP文件 未添加调色板
{
//保存文件
CFile fp;
fp.Open(path,CFile::modeCreate | CFile::modeWrite);
fp.Write((LPSTR)&bmpFileHeader,sizeof(BITMAPFILEHEADER)); //写文件头
fp.Write((LPSTR)&bmpInfoHeader,sizeof(BITMAPINFOHEADER)); //写信息头
fp.Write(pBmpData,ceil(double((iWidth*iHeight*2+54)/4.0))*4);//写数据
fp.Close();
return true;
}
DWORD myTIFF::FourByte2Dword(BYTE*pBuf,int idx)
{
ASSERT(pBuf);
ASSERT(idx>=0);
DWORD location = 0;
location = (pBuf[idx]<<24) + (pBuf[idx+1]<<16) + (pBuf[idx+2]<<8) + pBuf[idx+3];
return location;
}

请问,应该如何处理失真问题呢?
如果需要添加调色板的话,那么调色板应该怎么添加呢?16位bitmap
...全文
397 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
柠檬小栈 2015-07-30
  • 打赏
  • 举报
回复
我想问下楼主按照 BI_BITFIELD 重叠 RGB 的mask这种方法可以实现吗? 我现在要做的正好是由一组16位灰度数据生成16位bmp或tif文件,查阅很长世间发现,bmp无法对16位灰度进行生成。
引用 6 楼 songlinok 的回复:
[quote=引用 3 楼 Idle_ 的回复:] 如果希望在16bit bmp中最大可能保留灰度值的精度,那么你的bmiHeader.biCompression必须设置成BI_BITFIELD, 然后在调色板的位置(即&bmi.bmiColors[0])放3个DWORD分别对应R, G, B颜色的mask, 然后将这3个mask设置成相同的值(即rgb的通道位置重叠),你可以尝试都设置成0xFFFF看看Windows是否能够正确显示。
如果不能正确显示或存在某些像素显示错误,那么表示windows不支持16位深灰度,你只能想办法缩减成8位深度灰度值,可以直接在mask上做文章(比如设置mask=0xFF00),或者将mask设为0xFF然后复制像素时缩减每像素的灰度值。[/quote] [/quote]
怎嘛回事 2014-09-15
  • 打赏
  • 举报
回复
引用 5 楼 Idle_ 的回复:
[quote=引用 4 楼 songlinok 的回复:] [quote=引用 2 楼 Idle_ 的回复:] 16 bit bmp没有调色板。按你在bitmapinfoheader中的设置,这是一幅16位彩色图,每个pixel 占16 bit(实际使用15bit,r,g,b分别占5bit,最高位bit未使用),而你的源图是16bit灰度图,每个像素只有一种灰度值,因此你转换时必须将16bit的灰度值缩减成5bit,然后分别复制到16bit bmp每像素相应的r,g,b上。颜色失真是必然的,因为是由65536种灰度缩小成32种灰度。
我希望仍然能保持16位的深度,也就是65536颜色,应该怎么办呢? 为什么BMP就不能用16位的呢?我也是2个字节保存的一个像素值呀。 感谢回答。[/quote]
引用 3 楼 Idle_ 的回复:
如果希望在16bit bmp中最大可能保留灰度值的精度,那么你的bmiHeader.biCompression必须设置成BI_BITFIELD, 然后在调色板的位置(即&bmi.bmiColors[0])放3个DWORD分别对应R, G, B颜色的mask, 然后将这3个mask设置成相同的值(即rgb的通道位置重叠),你可以尝试都设置成0xFFFF看看Windows是否能够正确显示。
如果不能正确显示或存在某些像素显示错误,那么表示windows不支持16位深灰度,你只能想办法缩减成8位深度灰度值,可以直接在mask上做文章(比如设置mask=0xFF00),或者将mask设为0xFF然后复制像素时缩减每像素的灰度值。[/quote] 谢谢。 我去试试,现在对这个还不是太熟,要边查资料边做。 如果最后还是搞不定的话,那我就只有用CImage这种类库来显示了,这种类库显示的不是真,但是位深被改了,可能就是你说的那种原因吧,不支持16位深,因此被改成8位的了。 我打算用类库显示图像,但是在计算图像某点像素的灰度值时,我使用原始数据来计算,目前只能这样了。 感谢解惑。 过两天来给分。
阿呆_ 2014-09-14
  • 打赏
  • 举报
回复
引用 4 楼 songlinok 的回复:
[quote=引用 2 楼 Idle_ 的回复:] 16 bit bmp没有调色板。按你在bitmapinfoheader中的设置,这是一幅16位彩色图,每个pixel 占16 bit(实际使用15bit,r,g,b分别占5bit,最高位bit未使用),而你的源图是16bit灰度图,每个像素只有一种灰度值,因此你转换时必须将16bit的灰度值缩减成5bit,然后分别复制到16bit bmp每像素相应的r,g,b上。颜色失真是必然的,因为是由65536种灰度缩小成32种灰度。
我希望仍然能保持16位的深度,也就是65536颜色,应该怎么办呢? 为什么BMP就不能用16位的呢?我也是2个字节保存的一个像素值呀。 感谢回答。[/quote]
引用 3 楼 Idle_ 的回复:
如果希望在16bit bmp中最大可能保留灰度值的精度,那么你的bmiHeader.biCompression必须设置成BI_BITFIELD, 然后在调色板的位置(即&bmi.bmiColors[0])放3个DWORD分别对应R, G, B颜色的mask, 然后将这3个mask设置成相同的值(即rgb的通道位置重叠),你可以尝试都设置成0xFFFF看看Windows是否能够正确显示。
如果不能正确显示或存在某些像素显示错误,那么表示windows不支持16位深灰度,你只能想办法缩减成8位深度灰度值,可以直接在mask上做文章(比如设置mask=0xFF00),或者将mask设为0xFF然后复制像素时缩减每像素的灰度值。
怎嘛回事 2014-09-13
  • 打赏
  • 举报
回复
没有人回答吗 自己顶一下
怎嘛回事 2014-09-13
  • 打赏
  • 举报
回复
引用 2 楼 Idle_ 的回复:
16 bit bmp没有调色板。按你在bitmapinfoheader中的设置,这是一幅16位彩色图,每个pixel 占16 bit(实际使用15bit,r,g,b分别占5bit,最高位bit未使用),而你的源图是16bit灰度图,每个像素只有一种灰度值,因此你转换时必须将16bit的灰度值缩减成5bit,然后分别复制到16bit bmp每像素相应的r,g,b上。颜色失真是必然的,因为是由65536种灰度缩小成32种灰度。
我希望仍然能保持16位的深度,也就是65536颜色,应该怎么办呢? 为什么BMP就不能用16位的呢?我也是2个字节保存的一个像素值呀。 感谢回答。
阿呆_ 2014-09-13
  • 打赏
  • 举报
回复
如果希望在16bit bmp中最大可能保留灰度值的精度,那么你的bmiHeader.biCompression必须设置成BI_BITFIELD, 然后在调色板的位置(即&bmi.bmiColors[0])放3个DWORD分别对应R, G, B颜色的mask, 然后将这3个mask设置成相同的值(即rgb的通道位置重叠),你可以尝试都设置成0xFFFF看看Windows是否能够正确显示。
阿呆_ 2014-09-13
  • 打赏
  • 举报
回复
16 bit bmp没有调色板。按你在bitmapinfoheader中的设置,这是一幅16位彩色图,每个pixel 占16 bit(实际使用15bit,r,g,b分别占5bit,最高位bit未使用),而你的源图是16bit灰度图,每个像素只有一种灰度值,因此你转换时必须将16bit的灰度值缩减成5bit,然后分别复制到16bit bmp每像素相应的r,g,b上。颜色失真是必然的,因为是由65536种灰度缩小成32种灰度。

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧