您的位置:首页 > 其它

有关单色位图创建和保存的问题,大家帮我看看,谢谢啦~

2010-06-03 17:32 441 查看
我先准备了两张像素为100*100的单色位图(0.bmp 1.bmp),想将它们以二进制的形式复制(横向)并保存到compose.bmp 中,00.bmp 起到一个中转的作用,期间要对位图结构进行创建
由于从网上搜到的函数跟不是很匹配,而且不是对单色位图进行处理的,所以我就把下的自己改了一下
一开始调试运行,会生成901M的位图,后来发现是CreatBMP 和 SaveNewImage 两个函数的图片大小不知道怎么出问题了,所以我直接对新位图的尺寸进行赋值(原函数是通过函数取的),即宽 200 像素,高 100 像素
继续调试,这回生成的图片 20K ,但是图片是黑的,没有任何信息
于是,我想应该是调色板的部分出了问题,由于原函数调色板处,没看懂代码,所以我当时没有动那块儿
不过对单色位图的调色板不太会创建,所以请各位老大帮忙下,谢谢啦
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面的这个函数是对图片进行合并的函数
BOOL CTESTDlg::ImageCompose(CString strimage1, CString strimage2)
{
CDib image1,image2;//新建位图对象,CDib类网上很多下载
image1.Load(strimage1);//加载两幅图片 , load函数是DIB类里带的
image2.Load(strimage2);

//获得位图需要用到的信息,如尺寸和位图指针
//函数GetDIBInf返回一个指向BITMAPINFO结构的指针
BITMAPINFO *infoimage1 = image1.GetDIBInfo();
BITMAPINFO *infoimage2 = image2.GetDIBInfo();
//函数GetDIBBits获取image1的指针
unsigned char *dataimage1 = image1.GetDIBBits();
unsigned char *dataimage2 = image2.GetDIBBits();
//获取位图的宽、高
int wimage1 = infoimage1->bmiHeader.biWidth;
int himage1 = infoimage1->bmiHeader.biHeight;
int wimage2 = infoimage2->bmiHeader.biWidth;
int himage2 = infoimage2->bmiHeader.biHeight;
//获取新建位图的宽、高
int wnewimage,hnewimage;
wnewimage = wimage1+wimage2;
hnewimage = himage1;//取小值,否则报错
// CClientDC dc(&m_resultimage);

//新建NEWIMAGE,只要尺寸符合标准即可,此函数网上也很多,这是我自己写的,篇幅有限就没有粘贴上来。
//这块的CreatBMP是我自己从网上找的,然后自己改的,好像问题出在这里!!!
CDib temp;
HBITMAP hbit = temp.CreatBMP(wnewimage,hnewimage,1);

//保存新建的位图,方便后面调用
//这个SaveNewImage 也是我从网上找的,然后自己改的,貌似这个函数里面也有问题!!!
temp.SaveNewImage(hbit,"f://00.bmp",1);
CDib newimage;
if(newimage.Load("f://00.bmp")==false)
return FALSE;

//获得新位图NEWIMAGE的指针
unsigned char *dataimagenew = newimage.GetDIBBits();

//下面的一大段被我直接删掉了,因为不是很明白
// GetBMPImagePixelsPerLine(wnewimage)这个函数看注释是获得每行的字节数,但我的理解,图片在用二进制形式复制的话应该是按位复制吧?不知道我理解的是否正确?那个for循环式就是我按照这个理解写的。
//下面是关键算法:一行行“扫描”,有hnewimage行,1列。每一行有GetBMPImagePixelsPerLine(wnewimage)字节。这个函数是这样的:

//int CTESTDlg::GetBMPImagePixelsPerLine(int ImageX)//获得一个扫描行所占的字节数
//{
// int weishu = 24;//图像位数
// int bytes_per_line ;
// bytes_per_line=(ImageX*weishu+31)/8;
// bytes_per_line=bytes_per_line/4*4;//得到图像的一行的位数
// return bytes_per_line;
//}

// 我这里很多地方都乘以了3,是因为位图的位数位24位

// for (int i = 0; i <hnewimage; ++i ){
//
// //先将IMAGE1复制过去
// for (int j = 0; j < himage1; ++j ) {
// dataimagenew[j+i*GetBMPImagePixelsPerLine(wnewimage)] = dataimage1[j+i*GetBMPImagePixelsPerLine(wimage1)];
// }
//
////再将IMAGE2复制过去
// for (int n = 0; n < himage2; ++n) {
// dataimagenew[n+GetBMPImagePixelsPerLine(wimage1)+i*GetBMPImagePixelsPerLine(wnewimage)] = dataimage2[n+i*GetBMPImagePixelsPerLine(wimage2)];
// }
// }

for (int i = 0; i < 100; ++i)
{
//先将IMAGE1复制过去
for (int j = 0; j < 100; ++j)
{
dataimagenew[j+i*200] = dataimage1[j+i*100];
}

//再将IMAGE2复制过去
for (int n = 0; n < 100; ++n)
{
dataimagenew[n+100+i*200] = dataimage2[n+i*100];
}
}

//保存合并后的位图 save 函数是DIB类里带的
newimage.Save("f://compose.bmp");
DeleteObject(hbit);

return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
这个是CreatBMP,我从网上下了,改的
HBITMAP CDib::CreatBMP(int width, int height, unsigned short biBitCount)
{
int dwidth = width*biBitCount; //这块不太明白是什么意思
WORD color_num = 2; //还有这里

//compute the dib data size
//dwidth is the image data bits 's size

DWORD dwBitSize = dwidth*height + 40 + color_num*sizeof(RGBQUAD); //此处未完成,最后color_num*sizeof(RGBQUAD)不理解

LPSTR pDIB;//pointer to the DIB

HBITMAP hBitmap = (HBITMAP) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,dwBitSize);
if (hBitmap == 0)
{
return NULL;
}

pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hBitmap);

LPBITMAPINFO lpmf = (LPBITMAPINFO)pDIB;

lpmf-> bmiHeader.biSize = 40;
lpmf-> bmiHeader.biWidth = width;
lpmf-> bmiHeader.biHeight = height;
lpmf-> bmiHeader.biPlanes = 1;
lpmf-> bmiHeader.biBitCount = biBitCount;
lpmf-> bmiHeader.biCompression = BI_RGB;
lpmf-> bmiHeader.biSizeImage = dwidth*height;
lpmf-> bmiHeader.biXPelsPerMeter = 0;
lpmf-> bmiHeader.biYPelsPerMeter = 0;
lpmf-> bmiHeader.biClrUsed = 0;
lpmf-> bmiHeader.biClrImportant = 0;

//此处对调色板的处理不理解
if(color_num!=0)
{
int i;
for(i=0;i <color_num;i++)
{
lpmf-> bmiColors[i].rgbRed = (BYTE) i;
lpmf-> bmiColors[i].rgbGreen = (BYTE) i;
lpmf-> bmiColors[i].rgbBlue = (BYTE) i;
}
}

::GlobalUnlock((HGLOBAL) hBitmap);

return hBitmap;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CDib::SaveNewImage(HBITMAP hbitmap, LPSTR filename, int nColor)
{
BITMAP Bitmap;
HDC hDC;
DWORD dwPaletteSize=0 , dwBmBitsSize, dwDIBSize, dwWritten;
BITMAPFILEHEADER bmfHdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh, hDib, hPal,hOldPal=NULL;

if (nColor<= 8)
dwPaletteSize = (1<<nColor) *sizeof(RGBQUAD); //这里不明白是什么意思当时自己改的时候直接把 dwPaletteSize = 8
GetObject(hbitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = 200;
bi.biHeight = 100;
bi.biPlanes = 1;
bi.biBitCount = nColor;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth * nColor+31)/32*4)*Bitmap.bmHeight; //这里不明白为什么这样计算,我当时是直接用宽×高,直接复制20000
//为位图分配内存
hDib= GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
//设置调色板 这部分当时没看懂,后来改调色板时直接把这里删掉了,想自己用二进制方式创建一个的,不过貌似创建的有问题
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC, hbitmap, 0, Bitmap.bmHeight,
(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);
if (hOldPal)
{
SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL,hDC);
}
/////////////////////////////////////////////////////////////////////////////////////////////
我是这样创建的,不过这样做的话,*lpbi = bi 这一步就不行了,应为bi 要包含调色板,原来是不包含的,然后我就不太会了
bi.bmiColors[0].rgbBlue = 0x00;
bi.bmiColors[0].rgbGreen = 0x00;
bi.bmiColors[0].rgbRed = 0x00;
bi.bmiColors[0].rgbReserved = 0x00;
bi.bmiColors[1].rgbBlue = 0xff;
bi.bmiColors[1].rgbGreen = 0xff;
bi.bmiColors[1].rgbRed = 0xff;
bi.bmiColors[1].rgbReserved = 0x00;
/////////////////////////////////////////////////////////////////////////

fh = CreateFile(filename, GENERIC_WRITE,
0,//not be shared
NULL, //cannot be inherited
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);

if (fh == INVALID_HANDLE_VALUE)
return FALSE;
//设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+ dwPaletteSize;

//write file header
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);

//write bmp data
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);

GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
DeleteObject(hbitmap);
return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
至于DIB中的load 和save ,我改的主要是位图尺寸的取得方式,我直接给它们赋值,还有就是调色板大小,也是直接赋值的,8字节,觉得应该没什么问题,就不贴了,已经很多了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐