读书人

■关于 BMP24位图中间象素数据的对齐有

发布时间: 2012-02-09 18:22:27 作者: rapoo

■关于 BMP24位图中间象素数据的对齐问题
// 打开位图文件
CFile file;
if( !file.Open( strTempPath, CFile::modeRead) )
{
ASSERT(FALSE);
return FALSE;
}

// ....

// 读取位图信息
BITMAPINFOHEADER stInfo = {0};
file.Read( &stInfo, sizeof(stInfo));

const int COLOR_DEPTH = 24;
ASSERT( stInfo.biBitCount == COLOR_DEPTH );
ASSERT( stInfo.biCompression == 0 );


// 计算象素区图像大小
DWORD dwBytes = ((DWORD) stInfo.biWidth * stInfo.biBitCount) / 4;
if(((DWORD) stInfo.biWidth * stInfo.biBitCount) % 4)
dwBytes++;
dwBytes *= 3;
DWORD dwImageSize = dwBytes * stInfo.biHeight;


// 读取象素信息
LPBYTE pBuf = new BYTE[dwImageSize];
::ZeroMemory( pBuf, dwImageSize);
file.Seek( sizeof(stInfo), CFile::begin);
file.Read( pBuf, dwImageSize);
file.Close();


// 更具位图创建非规则窗体
for( int y = 0; y < stInfo.biHeight; y++)
{
int offset = (stInfo.biWidth*3%4) * y;
for( int x = 0; x < stInfo.biWidth; x++)
{
// Get pixel color
bBlue= pBuf[y*stInfo.biWidth*3 + offset + 3*x];
bGreen= pBuf[y*stInfo.biWidth*3 + offset + 3*x+1];
bRed= pBuf[y*stInfo.biWidth*3 + offset + 3*x+2];

if( RGB( bRed, bGreen, bBlue) == m_crTransparentColor )
continue;

// Combine regions
// .....
}
}


这段代码我调试了很久终于正常工作了,不过我还是很不了解一下细节

///////////////////////////
问题1:
DWORD dwBytes = ((DWORD) stInfo.biWidth * stInfo.biBitCount) / 4;
if(((DWORD) stInfo.biWidth * stInfo.biBitCount) % 4)
dwBytes++;
dwBytes *= 3;
DWORD dwImageSize = dwBytes * stInfo.biHeight;
这里计算出来的象素区大小是不是一定是以4倍对齐的呢? 是不是64位计算机上也是一样? 这个的根据到底是什么?

///////////////////////////
问题2:
int offset = (stInfo.biWidth*3%4) * y;
这个是我调试的时候看内存地址看出来的,但这个推断对不对?


[解决办法]
这种方法对齐,只能说结果可能是对的,但没找到原因。Bitmap要求以4象素(x方向)进行对齐,了解这一点,自己写代码就简单了。
[解决办法]
for(int i=pro.height-1;i> =0;i--)
{
for(int j=0;j <pro.width;j++)
{
b = pro.ImageData[i*pro.w+j*3];
g = pro.ImageData[i*pro.w+j*3+1];
r = pro.ImageData[i*pro.w+j*3+2];
pDC-> SetPixel(j,pro.height-i,RGB(r,g,b));
}
}

if(width * 3 % 4 != 0)
w = width * 3 + (4 - width * 3 % 4);
else
w = width * 3;
[解决办法]
it is a piece of cake

DWORD dwBytes = ((DWORD) stInfo.biWidth * stInfo.biBitCount) /8;
//for 4 byte alignment
dwBytes = (dwBytes+3)&~3;



------解决方案--------------------


indows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;


所以位图数据的排列与像素宽度有关
如果图像宽度是4整数倍
则其字节必然是4整数倍

否则扫描的时候必然要在每一行末,添加0
将行数字节数%4,令这个余数为extra
余1,则填3个0,余2,添两个,以此类推


所以对于第x行,第y类像素
其三个颜色分量在内存的位置分别为
lpvBits[x*3+y*(w*3+extra)+0]
lpvBits[x*3+y*(w*3+extra)+1]
lpvBits[x*3+y*(w*3+extra)+2]

反相就是
int extra=3*w%4;
lpvBits[x*3+y*(w*3+extra)+0] =255-lpvBits[x*3+y*(w*3+extra)+0];
lpvBits[x*3+y*(w*3+extra)+1] =255-lpvBits[x*3+y*(w*3+extra)+1];
lpvBits[x*3+y*(w*3+extra)+2] =255-lpvBits[x*3+y*(w*3+extra)+2];

同理纯红就是
lpvBits[x*3+y*(w*3+extra)+0] =0;
lpvBits[x*3+y*(w*3+extra)+1] =0;
lpvBits[x*3+y*(w*3+extra)+2] =255;

用4的倍数一定跟内存对齐有关,具体的不懂了
[解决办法]
mmx 指令要求数据4字节对齐
sse2 现在要求16字节对齐

主要是数据加载指令 不对齐的比对齐的慢
为了效率

读书人网 >VC/MFC

热点推荐