我在dll中需要把资源位图生成BMP文件,生成BMP的函数:
oid pascal creatbmp( BYTE * pData, int width, int height, const char * filename )
{
int size = width*height*3; // 每个像素点3个字节
// 位图第一部分,文件信息
BITMAPFILEHEADER bfh;
bfh.bfType=0X4d42;
bfh.bfSize = size + sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
bfh.bfReserved1 = 0; // reserved
bfh.bfReserved2 = 0; // reserved
bfh.bfOffBits = bfh.bfSize - size;
// 位图第二部分,数据信息
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = size;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE * fp = fopen( filename,"wb");
if( !fp ) return;
fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp );
fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp );
fwrite( pData, 1, size, fp );
fclose( fp );
}
加载并调用生成BMP的代码:
CBitmap bmp;
BYTE pData[59520];
int x=248;
int y=80;
bmp.LoadBitmap(IDB_BITMAP1);
bmp.GetBitmapBits(59520,pData);
creatbmp(pData,x,y,"jbs.bmp");
但是生成的BMP是灰色的,没有显示我在资源中加载的图片。
请各位看看为什么?
我分析的原因不知道对不:
1、我在引用bmp资源,vc提示不能在编辑器中打开,超过了256色,是不是我的图片有问题?
2、生成bmp文件的函数creatbmp中是不是需要有调色板信息》需要的话怎么加?
3、是不是我bmp.LoadBitmap(IDB_BITMAP1);bmp.GetBitmapBits(59520,pData);有问题?
怎么把bmp资源中的数据放到pData中?
4、我图片的大小248*80,引用到资源中的bmp文件大小是77.5K,是不是我读取数据的pData设置的小了?
请大家看看, 谁帮我分析解决下。
谢谢了。。。。。。。。。。。
39 个解决方案
#1
1。6是有这个问题,与bmp无关
2。看你的bih.biBitCount = 24;应该不需要调色板
3,4。大小248*80*24/8,
2。看你的bih.biBitCount = 24;应该不需要调色板
3,4。大小248*80*24/8,
#2
谢谢你的建议。
我还是不太明白。
为什么我的图片保存后还是一副灰色的图啊?
可以指导详细点么?
谢谢了。
我还是不太明白。
为什么我的图片保存后还是一副灰色的图啊?
可以指导详细点么?
谢谢了。
#3
不能用GetBitmapBits,而要用GetDIBits。
作为基础知识,你最好先弄弄明白DDB和DIB的区别。
作为基础知识,你最好先弄弄明白DDB和DIB的区别。
#4
int size = width*height*3; // 每个像素点3个字节
???????
bih.biBitCount = 24;
每个像素点24个字节,怎么成3个了
???????
bih.biBitCount = 24;
每个像素点24个字节,怎么成3个了
#5
哦 是的
#6
三楼你好。
我是不太明白,麻烦你可以给我具体的代码么?就是把资源数据读到数组pData中。
十分感谢。
#7
查MSDN,GetDIBits的函数说明,照着调用(在bmp.LoadBitmap(IDB_BITMAP1)之后)。
#8
GetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbi, UINT uUsage);
第一个参数:hdc怎么获得啊?我的是个动态库,是不是就可以为NULL?
第二个参数:hbmp位图句柄,怎么得到?bmp.LoadBitmap(IDB_BITMAP1)是不是就不可以用了?
第三个参数,uStartScan检索的第一个扫描线也不知道怎么弄?
第四个参数:cScanLines检索的扫描线数。
总之我还是不太明白各个参数怎么得到定义,所以麻烦你给个具体的代码。
学习中,十分感谢。
#9
hDC = ::GetDC(NULL); // 随便获取一个窗口的DC就可以,这里用的是桌面的DC。记得调用完成后ReleaseDC。
hbmp = bmp.GetSafeHandle();
uStartScan = 0; // 从第一行开始获取。
cScanLines = y; // 获取整个图像的所有行的数据。
lpvBits // 把你的pData传进去。获取的数据就放这里面。
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
uUsage = DIB_RGB_COLORS;
hbmp = bmp.GetSafeHandle();
uStartScan = 0; // 从第一行开始获取。
cScanLines = y; // 获取整个图像的所有行的数据。
lpvBits // 把你的pData传进去。获取的数据就放这里面。
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
uUsage = DIB_RGB_COLORS;
#10
不好意思,再次麻烦你了,
HBITMAP hbmp = bmp.GetSafeHandle(); 编译报错了。如下。
error C2440: 'initializing' : cannot convert from 'void *' to 'struct HBITMAP__ *'
cScanLines = y; y是怎么来的?
谢谢。
#11
HBITMAP hbmp = (HBITMAP)(bmp.GetSafeHandle());
int x=248;
int y=80;
这不是你自己定义的图像宽高吗?
int x=248;
int y=80;
这不是你自己定义的图像宽高吗?
#12
再次麻烦看下
HDC hdc=::GetDC(NULL);
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 240;
bih.biHeight = 80;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 80*240*3;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,&bih,DIB_RGB_COLORS);
编译报错:
error C2664: 'GetDIBits' : cannot convert parameter 6 from 'struct tagBITMAPINFOHEADER *' to 'struct tagBITMAPINFO *'
参数都传对了吧?是不是第6个参数报错了?
所以你得再帮我看下。
谢谢
#13
我明白了为什么报错,但是:
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
BITMAPINFO怎么附值啊?
BITMAPINFO bitinfo;
bitinfo.bmiHeader=biha;
bitinfo.bmiColors=BI_RGB; 这行就不对了,怎么弄还得你指点下。
谢谢了。
#14
把bitinfo.bmiColors=BI_RGB;这行去掉。bmiColors是调色板,你用24位位图,这个成员没用。
另外,24位位图是没有调色板的,所以,其实你就用12楼中的代码,在调用GetDIBits的时候用(BITMAPINFO *)&bih强制转换一下也可以。
另外,24位位图是没有调色板的,所以,其实你就用12楼中的代码,在调用GetDIBits的时候用(BITMAPINFO *)&bih强制转换一下也可以。
#15
太长了,没看,你可以先用LoadBitmap将资源加载到一个HBITMAP对象中去,然后将这个HBITMAP写入到BMP文件中去,下面的代码是将HBITMAP写入到BMP文件中去的,本身是写一个对话框类的按钮中的,你改一下:
int CCopyScreenDlg::BitMapToFile(HBITMAP hBitmap, LPSTR FileName)
{
HDC hdc;
int ibits;//当前显示模式下每个像素所占字节数
WORD wbitsCount;//位图中每个像素所占字节数。
DWORD dwpalettelsize=0;//调色板大小
DWORD dwbmdibitsize,dwdibsize,dwwritten;
BITMAP bitmap;
BITMAPFILEHEADER bmfhdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh,fdib,hpal,holdpal=NULL;
CString work;
hdc=CreateDC("display",NULL,NULL,NULL);
ibits=::GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
if(ibits<=1)
wbitsCount=1;
if(ibits<=4)
wbitsCount=4;
if(ibits<=8)
wbitsCount=8;
if(ibits<=16)
wbitsCount=16;
if(ibits<=24)
wbitsCount=24;
else
wbitsCount=32;
//以上代码中ibits返回的显示模式下,每个像素所占的位数,wbitsCount是位图上每个像素所占的位数。
if(wbitsCount<=8)
dwpalettelsize=(1<<wbitsCount)*sizeof(RGBQUAD);
GetObject(hBitmap,sizeof(BITMAP),(void *)&bitmap);//得到BITMAP的信息,这是一个BITMAP结构。
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bitmap.bmWidth;
bi.biHeight=bitmap.bmHeight;
bi.biPlanes=1;
bi.biBitCount=wbitsCount;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biYPelsPerMeter=0;
bi.biXPelsPerMeter=0;
dwbmdibitsize=((bitmap.bmWidth*wbitsCount+31)/8)*bitmap.bmHeight;
fdib=GlobalAlloc(GHND,dwbmdibitsize+dwpalettelsize+sizeof(BITMAPINFOHEADER));
lpbi=(LPBITMAPINFOHEADER)::GlobalLock(fdib);
*lpbi=bi;//将bi中的数据写入分配的内存中。
//处理调色板
hpal=::GetStockObject(DEFAULT_PALETTE);
if(hpal)
{
hdc=::GetDC(NULL);
holdpal=::SelectPalette(hdc,(HPALETTE)hpal,false);
::RealizePalette(hdc);
}
GetDIBits(hdc,hBitmap,0,(UINT)bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwpalettelsize,(BITMAPINFO *)lpbi,DIB_RGB_COLORS);
if(holdpal)
{
::SelectPalette(hdc,(HPALETTE)holdpal,true);
::RealizePalette(hdc);
::ReleaseDC(NULL,hdc);
}
//创建文件
fh=CreateFile(FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(fh==INVALID_HANDLE_VALUE)
return FALSE;
bmfhdr.bfType=0x4d42;
dwdibsize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwbmdibitsize+dwpalettelsize;
bmfhdr.bfSize=dwdibsize;
bmfhdr.bfReserved1=0;
bmfhdr.bfReserved2=0;
bmfhdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwpalettelsize;
::WriteFile(fh,(LPSTR)&bmfhdr,sizeof(BITMAPFILEHEADER),&dwwritten,NULL);
::WriteFile(fh,(LPSTR)lpbi,dwdibsize,&dwwritten,NULL);
::GlobalUnlock(fdib);
::GlobalFree(fdib);
::CloseHandle(fh);
return TRUE;
}
int CCopyScreenDlg::BitMapToFile(HBITMAP hBitmap, LPSTR FileName)
{
HDC hdc;
int ibits;//当前显示模式下每个像素所占字节数
WORD wbitsCount;//位图中每个像素所占字节数。
DWORD dwpalettelsize=0;//调色板大小
DWORD dwbmdibitsize,dwdibsize,dwwritten;
BITMAP bitmap;
BITMAPFILEHEADER bmfhdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh,fdib,hpal,holdpal=NULL;
CString work;
hdc=CreateDC("display",NULL,NULL,NULL);
ibits=::GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
if(ibits<=1)
wbitsCount=1;
if(ibits<=4)
wbitsCount=4;
if(ibits<=8)
wbitsCount=8;
if(ibits<=16)
wbitsCount=16;
if(ibits<=24)
wbitsCount=24;
else
wbitsCount=32;
//以上代码中ibits返回的显示模式下,每个像素所占的位数,wbitsCount是位图上每个像素所占的位数。
if(wbitsCount<=8)
dwpalettelsize=(1<<wbitsCount)*sizeof(RGBQUAD);
GetObject(hBitmap,sizeof(BITMAP),(void *)&bitmap);//得到BITMAP的信息,这是一个BITMAP结构。
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bitmap.bmWidth;
bi.biHeight=bitmap.bmHeight;
bi.biPlanes=1;
bi.biBitCount=wbitsCount;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biYPelsPerMeter=0;
bi.biXPelsPerMeter=0;
dwbmdibitsize=((bitmap.bmWidth*wbitsCount+31)/8)*bitmap.bmHeight;
fdib=GlobalAlloc(GHND,dwbmdibitsize+dwpalettelsize+sizeof(BITMAPINFOHEADER));
lpbi=(LPBITMAPINFOHEADER)::GlobalLock(fdib);
*lpbi=bi;//将bi中的数据写入分配的内存中。
//处理调色板
hpal=::GetStockObject(DEFAULT_PALETTE);
if(hpal)
{
hdc=::GetDC(NULL);
holdpal=::SelectPalette(hdc,(HPALETTE)hpal,false);
::RealizePalette(hdc);
}
GetDIBits(hdc,hBitmap,0,(UINT)bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwpalettelsize,(BITMAPINFO *)lpbi,DIB_RGB_COLORS);
if(holdpal)
{
::SelectPalette(hdc,(HPALETTE)holdpal,true);
::RealizePalette(hdc);
::ReleaseDC(NULL,hdc);
}
//创建文件
fh=CreateFile(FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(fh==INVALID_HANDLE_VALUE)
return FALSE;
bmfhdr.bfType=0x4d42;
dwdibsize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwbmdibitsize+dwpalettelsize;
bmfhdr.bfSize=dwdibsize;
bmfhdr.bfReserved1=0;
bmfhdr.bfReserved2=0;
bmfhdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwpalettelsize;
::WriteFile(fh,(LPSTR)&bmfhdr,sizeof(BITMAPFILEHEADER),&dwwritten,NULL);
::WriteFile(fh,(LPSTR)lpbi,dwdibsize,&dwwritten,NULL);
::GlobalUnlock(fdib);
::GlobalFree(fdib);
::CloseHandle(fh);
return TRUE;
}
#16
学习中。。。。。。。。。。。。
#17
不好意思,再得烦劳你了。
我按照你的指点,生成出来的bmp图还是张灰色的图片。
HDC hdc=::GetDC(NULL);
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER biha;
biha.biSize = sizeof(BITMAPINFOHEADER);
biha.biWidth = 240;
biha.biHeight = 80;
biha.biPlanes = 1;
biha.biBitCount = 24;
biha.biCompression = 0;
biha.biSizeImage = 80*240*3;
biha.biXPelsPerMeter = 0;
biha.biYPelsPerMeter = 0;
biha.biClrUsed = 0;
biha.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,(BITMAPINFO *)&biha,DIB_RGB_COLORS);
creatbmp(pData,240,80,"jbs.bmp"); 调用我最开始的方法。
是不是这个方法有问题啊,所以烦劳你再指点。
#18
你好。
谢谢你的代码。
我试了下, bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BitMapToFile(hbmp,"jbs.bmp");
直接把我的hbmp传进去。编译、连接都没问题,但是执行异常报错
是不是得把你的BitMapToFile方法需要改动?
麻烦你指点。
感谢。。。。
#19
代码应该没错了。检查一下你存出的图像文件,是不是有只读属性之类,导致你每次运行根本没有覆盖。要么你把那个输出文件先删了再运行一遍试试。
如果还不行的话,把你存出的图像文件上传上来我看一下。
如果还不行的话,把你存出的图像文件上传上来我看一下。
#20
删除了,但是还是灰色的。也不是只读属性。
还有,就是我把bmp文件先引用到资源中的,而且在v6中资源打不开,提示超过了256色。
是不是和这个有关系?
#21
你好。
我又看了下,发现我引用到资源的位图是:248*80 位深度32
所以我就把bih.biBitCount=24;修改bih.biBitCount = 32;
把宽度也增加到了248。
然后生成的图片打开是绘图失败!
是不是那些参数设置有问题啊?
谢谢了。。。。。
#22
超过256色图像的VC6都打不开,这是VC6的功能局限。你只要在资源管理器里看到那幅图像没问题就行了。
biBitCount不能改。24位跟32位的文件格式是不同的。
你把你的图像文件传上来看看吧,最好是原始的资源图像和你最后保存出来的灰的那幅都传上来。
biBitCount不能改。24位跟32位的文件格式是不同的。
你把你的图像文件传上来看看吧,最好是原始的资源图像和你最后保存出来的灰的那幅都传上来。
#23
可以发到你邮箱么?
你的油箱地址?发短消息给我。
谢谢了。。。
#24
用你的图像跟你的代码,运行完全成功,没有任何问题。代码如下:
CBitmap bmp;
BYTE pData[59520];
bmp.LoadBitmap(IDB_BITMAP1);
HDC hdc=::GetDC(NULL);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 248;
bih.biHeight = 80;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 80*248*3;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,(BITMAPINFO *)&bih,DIB_RGB_COLORS);
::ReleaseDC(NULL, hdc);
// 以下是你的creatbmp函数内的部分。bih借用了一下,就没有再弄新的了。
int size = 248*80*3; // 每个像素点3个字节
BITMAPFILEHEADER bfh;
bfh.bfType=0X4d42;
bfh.bfSize = size + sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
bfh.bfReserved1 = 0; // reserved
bfh.bfReserved2 = 0; // reserved
bfh.bfOffBits = bfh.bfSize - size;
FILE * fp = fopen("jbs.bmp","wb");
if( !fp ) return;
fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp );
fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp );
fwrite( pData, 1, size, fp );
fclose( fp );
#25
在你发给我的运行结果里,pData完全没赋值,仅仅是DEBUG版中,声明pData数组:BYTE pData[59520]时,系统给你赋的初始值,每个字节都是0xCC。所以你打开图像看的时候看到的都是一片灰色。你再仔细查查吧。
#26
没那么麻烦,把位图资源用FindResource,LoadResource打开,SizeofResource得到大小,在文件里先写入"BM",再写入Resource就行了。根本不用管位图格式。
#27
你好。
我用 if(hbmp==NULL){
AfxMessageBox("1111111111111");
}
else{
AfxMessageBox("2222222222222");
}
检查,发现hbmp是空的,也就是说bmp.LoadBitmap(IDB_BITMAP1);也是空的。
所以我的资源Load有问题!
为什么呢?
#28
1、从资源视图中,检查你的资源里是否确实有一个叫IDB_BITMAP1的位图。
2、查看IDB_BITMAP1的属性,看它所指向文件的全路径,然后去硬盘上看看这个路径\文件是否存在。
3、在解决方案视图里,看看你的工程是否把该文件包含在内。
2、查看IDB_BITMAP1的属性,看它所指向文件的全路径,然后去硬盘上看看这个路径\文件是否存在。
3、在解决方案视图里,看看你的工程是否把该文件包含在内。
#29
这段代码我用了很长时间了,应该没有问题吧,你先调试一下出行的是哪一行。
另外,
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BitMapToFile(hbmp,"jbs.bmp");
这个是不是太麻烦了一点,直接写成这样不是更好:
HBITMAP hbmp=::LoadBitmap(AfxGetApp()->m_hInstance,IDB_BITMAP1);
BitMapToFile(hbmp,"jbs.bmp");
#30
你好。我把刚那个资源删除,重新又引入了一边。
这下hbmp不为空了。
但是生成的bmp图片却和原始的大不一样了。
所以又的麻烦你了。我把输出生成的图片发给你的邮箱。你再看看。
#31
你再回去看看你导入的资源图片是不是也变成这样了。VC6不能打开32位bmp,如果你导入的时候顺便操作了一下的话,很可能就变成类似的样子了。
#32
我先是在资源管理里点击引入,再选到我要引入的bmp图。
打开后就提示超过了256色,无法打开。我点击确定。
就这个过程啊,我也没有操作它。
现在生成的图又换成了另外一个无标,一个对勾标志。
我都删了引,引了删了好几次了。
怎么还是不对?是不是我引入图有问题?
麻烦你了。
#33
你的代码没问题。
但是现在生成的图不是我资源加载的图。
是个复选框之类的图标。为什么啊?
和我上面代码生成的一样,都是没出来资源里的图。
是不是资源引入有问题啊?
#34
你好。
我这个工程是动态库,我在vb中调用调试。
每次生成dll后把它拷贝到vb中,调用。
发现每次生成的图片就是vb中的控件面版上的控件图片。前面几次是个对勾的复选框,这次有成了pictureBox了。是不是和这个有关系啊?
还是哪个句柄取错了?
#35
学习了
#36
我也是忽然发现你这个是个DLL。那么,你的每个输出函数里,有没有在最前面加上一句:AFX_MANAGE_STATE(AfxGetStaticModuleState( ));?
#37
恩。是没加,真不好意思忘了我,图片出来了。为什么这个?
还有现在报断言错误,APPINIT.CPP的ASSERT(afxCurrentAppName == NULL);段。
是不是哪个句柄没释放?我再找找原因。
真是感谢你了。
#38
谢谢了,出来,问题找出来了我。
AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0);
这句去掉了,前面没有APPINIT.CPP的ASSERT(afxCurrentAppName == NULL);需要
加AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0);
现在就好了。真是感谢你了。
要是有时间帮我解释下为什么?呵呵。
#39
什么为什么?为什么不加AFX_MANAGE_STATE会出错?很简单,以下全文引用MSDN:
By default, MFC uses the resource handle of the main application to load the resource template. If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. You need to switch the module state for the correct handle to be used. You can do this by adding the following code to the beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.
By default, MFC uses the resource handle of the main application to load the resource template. If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. You need to switch the module state for the correct handle to be used. You can do this by adding the following code to the beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.
#1
1。6是有这个问题,与bmp无关
2。看你的bih.biBitCount = 24;应该不需要调色板
3,4。大小248*80*24/8,
2。看你的bih.biBitCount = 24;应该不需要调色板
3,4。大小248*80*24/8,
#2
谢谢你的建议。
我还是不太明白。
为什么我的图片保存后还是一副灰色的图啊?
可以指导详细点么?
谢谢了。
我还是不太明白。
为什么我的图片保存后还是一副灰色的图啊?
可以指导详细点么?
谢谢了。
#3
不能用GetBitmapBits,而要用GetDIBits。
作为基础知识,你最好先弄弄明白DDB和DIB的区别。
作为基础知识,你最好先弄弄明白DDB和DIB的区别。
#4
int size = width*height*3; // 每个像素点3个字节
???????
bih.biBitCount = 24;
每个像素点24个字节,怎么成3个了
???????
bih.biBitCount = 24;
每个像素点24个字节,怎么成3个了
#5
哦 是的
#6
三楼你好。
我是不太明白,麻烦你可以给我具体的代码么?就是把资源数据读到数组pData中。
十分感谢。
#7
查MSDN,GetDIBits的函数说明,照着调用(在bmp.LoadBitmap(IDB_BITMAP1)之后)。
#8
GetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbi, UINT uUsage);
第一个参数:hdc怎么获得啊?我的是个动态库,是不是就可以为NULL?
第二个参数:hbmp位图句柄,怎么得到?bmp.LoadBitmap(IDB_BITMAP1)是不是就不可以用了?
第三个参数,uStartScan检索的第一个扫描线也不知道怎么弄?
第四个参数:cScanLines检索的扫描线数。
总之我还是不太明白各个参数怎么得到定义,所以麻烦你给个具体的代码。
学习中,十分感谢。
#9
hDC = ::GetDC(NULL); // 随便获取一个窗口的DC就可以,这里用的是桌面的DC。记得调用完成后ReleaseDC。
hbmp = bmp.GetSafeHandle();
uStartScan = 0; // 从第一行开始获取。
cScanLines = y; // 获取整个图像的所有行的数据。
lpvBits // 把你的pData传进去。获取的数据就放这里面。
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
uUsage = DIB_RGB_COLORS;
hbmp = bmp.GetSafeHandle();
uStartScan = 0; // 从第一行开始获取。
cScanLines = y; // 获取整个图像的所有行的数据。
lpvBits // 把你的pData传进去。获取的数据就放这里面。
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
uUsage = DIB_RGB_COLORS;
#10
不好意思,再次麻烦你了,
HBITMAP hbmp = bmp.GetSafeHandle(); 编译报错了。如下。
error C2440: 'initializing' : cannot convert from 'void *' to 'struct HBITMAP__ *'
cScanLines = y; y是怎么来的?
谢谢。
#11
HBITMAP hbmp = (HBITMAP)(bmp.GetSafeHandle());
int x=248;
int y=80;
这不是你自己定义的图像宽高吗?
int x=248;
int y=80;
这不是你自己定义的图像宽高吗?
#12
再次麻烦看下
HDC hdc=::GetDC(NULL);
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 240;
bih.biHeight = 80;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 80*240*3;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,&bih,DIB_RGB_COLORS);
编译报错:
error C2664: 'GetDIBits' : cannot convert parameter 6 from 'struct tagBITMAPINFOHEADER *' to 'struct tagBITMAPINFO *'
参数都传对了吧?是不是第6个参数报错了?
所以你得再帮我看下。
谢谢
#13
我明白了为什么报错,但是:
lpbi // 指定你所需要的bitmap的格式。跟你在creatbmp函数里弄出来的那个bih一样,弄一个BITMAPINFO变量并赋值,然后指针传进去。
BITMAPINFO怎么附值啊?
BITMAPINFO bitinfo;
bitinfo.bmiHeader=biha;
bitinfo.bmiColors=BI_RGB; 这行就不对了,怎么弄还得你指点下。
谢谢了。
#14
把bitinfo.bmiColors=BI_RGB;这行去掉。bmiColors是调色板,你用24位位图,这个成员没用。
另外,24位位图是没有调色板的,所以,其实你就用12楼中的代码,在调用GetDIBits的时候用(BITMAPINFO *)&bih强制转换一下也可以。
另外,24位位图是没有调色板的,所以,其实你就用12楼中的代码,在调用GetDIBits的时候用(BITMAPINFO *)&bih强制转换一下也可以。
#15
太长了,没看,你可以先用LoadBitmap将资源加载到一个HBITMAP对象中去,然后将这个HBITMAP写入到BMP文件中去,下面的代码是将HBITMAP写入到BMP文件中去的,本身是写一个对话框类的按钮中的,你改一下:
int CCopyScreenDlg::BitMapToFile(HBITMAP hBitmap, LPSTR FileName)
{
HDC hdc;
int ibits;//当前显示模式下每个像素所占字节数
WORD wbitsCount;//位图中每个像素所占字节数。
DWORD dwpalettelsize=0;//调色板大小
DWORD dwbmdibitsize,dwdibsize,dwwritten;
BITMAP bitmap;
BITMAPFILEHEADER bmfhdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh,fdib,hpal,holdpal=NULL;
CString work;
hdc=CreateDC("display",NULL,NULL,NULL);
ibits=::GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
if(ibits<=1)
wbitsCount=1;
if(ibits<=4)
wbitsCount=4;
if(ibits<=8)
wbitsCount=8;
if(ibits<=16)
wbitsCount=16;
if(ibits<=24)
wbitsCount=24;
else
wbitsCount=32;
//以上代码中ibits返回的显示模式下,每个像素所占的位数,wbitsCount是位图上每个像素所占的位数。
if(wbitsCount<=8)
dwpalettelsize=(1<<wbitsCount)*sizeof(RGBQUAD);
GetObject(hBitmap,sizeof(BITMAP),(void *)&bitmap);//得到BITMAP的信息,这是一个BITMAP结构。
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bitmap.bmWidth;
bi.biHeight=bitmap.bmHeight;
bi.biPlanes=1;
bi.biBitCount=wbitsCount;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biYPelsPerMeter=0;
bi.biXPelsPerMeter=0;
dwbmdibitsize=((bitmap.bmWidth*wbitsCount+31)/8)*bitmap.bmHeight;
fdib=GlobalAlloc(GHND,dwbmdibitsize+dwpalettelsize+sizeof(BITMAPINFOHEADER));
lpbi=(LPBITMAPINFOHEADER)::GlobalLock(fdib);
*lpbi=bi;//将bi中的数据写入分配的内存中。
//处理调色板
hpal=::GetStockObject(DEFAULT_PALETTE);
if(hpal)
{
hdc=::GetDC(NULL);
holdpal=::SelectPalette(hdc,(HPALETTE)hpal,false);
::RealizePalette(hdc);
}
GetDIBits(hdc,hBitmap,0,(UINT)bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwpalettelsize,(BITMAPINFO *)lpbi,DIB_RGB_COLORS);
if(holdpal)
{
::SelectPalette(hdc,(HPALETTE)holdpal,true);
::RealizePalette(hdc);
::ReleaseDC(NULL,hdc);
}
//创建文件
fh=CreateFile(FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(fh==INVALID_HANDLE_VALUE)
return FALSE;
bmfhdr.bfType=0x4d42;
dwdibsize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwbmdibitsize+dwpalettelsize;
bmfhdr.bfSize=dwdibsize;
bmfhdr.bfReserved1=0;
bmfhdr.bfReserved2=0;
bmfhdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwpalettelsize;
::WriteFile(fh,(LPSTR)&bmfhdr,sizeof(BITMAPFILEHEADER),&dwwritten,NULL);
::WriteFile(fh,(LPSTR)lpbi,dwdibsize,&dwwritten,NULL);
::GlobalUnlock(fdib);
::GlobalFree(fdib);
::CloseHandle(fh);
return TRUE;
}
int CCopyScreenDlg::BitMapToFile(HBITMAP hBitmap, LPSTR FileName)
{
HDC hdc;
int ibits;//当前显示模式下每个像素所占字节数
WORD wbitsCount;//位图中每个像素所占字节数。
DWORD dwpalettelsize=0;//调色板大小
DWORD dwbmdibitsize,dwdibsize,dwwritten;
BITMAP bitmap;
BITMAPFILEHEADER bmfhdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh,fdib,hpal,holdpal=NULL;
CString work;
hdc=CreateDC("display",NULL,NULL,NULL);
ibits=::GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
if(ibits<=1)
wbitsCount=1;
if(ibits<=4)
wbitsCount=4;
if(ibits<=8)
wbitsCount=8;
if(ibits<=16)
wbitsCount=16;
if(ibits<=24)
wbitsCount=24;
else
wbitsCount=32;
//以上代码中ibits返回的显示模式下,每个像素所占的位数,wbitsCount是位图上每个像素所占的位数。
if(wbitsCount<=8)
dwpalettelsize=(1<<wbitsCount)*sizeof(RGBQUAD);
GetObject(hBitmap,sizeof(BITMAP),(void *)&bitmap);//得到BITMAP的信息,这是一个BITMAP结构。
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bitmap.bmWidth;
bi.biHeight=bitmap.bmHeight;
bi.biPlanes=1;
bi.biBitCount=wbitsCount;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biYPelsPerMeter=0;
bi.biXPelsPerMeter=0;
dwbmdibitsize=((bitmap.bmWidth*wbitsCount+31)/8)*bitmap.bmHeight;
fdib=GlobalAlloc(GHND,dwbmdibitsize+dwpalettelsize+sizeof(BITMAPINFOHEADER));
lpbi=(LPBITMAPINFOHEADER)::GlobalLock(fdib);
*lpbi=bi;//将bi中的数据写入分配的内存中。
//处理调色板
hpal=::GetStockObject(DEFAULT_PALETTE);
if(hpal)
{
hdc=::GetDC(NULL);
holdpal=::SelectPalette(hdc,(HPALETTE)hpal,false);
::RealizePalette(hdc);
}
GetDIBits(hdc,hBitmap,0,(UINT)bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwpalettelsize,(BITMAPINFO *)lpbi,DIB_RGB_COLORS);
if(holdpal)
{
::SelectPalette(hdc,(HPALETTE)holdpal,true);
::RealizePalette(hdc);
::ReleaseDC(NULL,hdc);
}
//创建文件
fh=CreateFile(FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(fh==INVALID_HANDLE_VALUE)
return FALSE;
bmfhdr.bfType=0x4d42;
dwdibsize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwbmdibitsize+dwpalettelsize;
bmfhdr.bfSize=dwdibsize;
bmfhdr.bfReserved1=0;
bmfhdr.bfReserved2=0;
bmfhdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwpalettelsize;
::WriteFile(fh,(LPSTR)&bmfhdr,sizeof(BITMAPFILEHEADER),&dwwritten,NULL);
::WriteFile(fh,(LPSTR)lpbi,dwdibsize,&dwwritten,NULL);
::GlobalUnlock(fdib);
::GlobalFree(fdib);
::CloseHandle(fh);
return TRUE;
}
#16
学习中。。。。。。。。。。。。
#17
不好意思,再得烦劳你了。
我按照你的指点,生成出来的bmp图还是张灰色的图片。
HDC hdc=::GetDC(NULL);
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER biha;
biha.biSize = sizeof(BITMAPINFOHEADER);
biha.biWidth = 240;
biha.biHeight = 80;
biha.biPlanes = 1;
biha.biBitCount = 24;
biha.biCompression = 0;
biha.biSizeImage = 80*240*3;
biha.biXPelsPerMeter = 0;
biha.biYPelsPerMeter = 0;
biha.biClrUsed = 0;
biha.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,(BITMAPINFO *)&biha,DIB_RGB_COLORS);
creatbmp(pData,240,80,"jbs.bmp"); 调用我最开始的方法。
是不是这个方法有问题啊,所以烦劳你再指点。
#18
你好。
谢谢你的代码。
我试了下, bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BitMapToFile(hbmp,"jbs.bmp");
直接把我的hbmp传进去。编译、连接都没问题,但是执行异常报错
是不是得把你的BitMapToFile方法需要改动?
麻烦你指点。
感谢。。。。
#19
代码应该没错了。检查一下你存出的图像文件,是不是有只读属性之类,导致你每次运行根本没有覆盖。要么你把那个输出文件先删了再运行一遍试试。
如果还不行的话,把你存出的图像文件上传上来我看一下。
如果还不行的话,把你存出的图像文件上传上来我看一下。
#20
删除了,但是还是灰色的。也不是只读属性。
还有,就是我把bmp文件先引用到资源中的,而且在v6中资源打不开,提示超过了256色。
是不是和这个有关系?
#21
你好。
我又看了下,发现我引用到资源的位图是:248*80 位深度32
所以我就把bih.biBitCount=24;修改bih.biBitCount = 32;
把宽度也增加到了248。
然后生成的图片打开是绘图失败!
是不是那些参数设置有问题啊?
谢谢了。。。。。
#22
超过256色图像的VC6都打不开,这是VC6的功能局限。你只要在资源管理器里看到那幅图像没问题就行了。
biBitCount不能改。24位跟32位的文件格式是不同的。
你把你的图像文件传上来看看吧,最好是原始的资源图像和你最后保存出来的灰的那幅都传上来。
biBitCount不能改。24位跟32位的文件格式是不同的。
你把你的图像文件传上来看看吧,最好是原始的资源图像和你最后保存出来的灰的那幅都传上来。
#23
可以发到你邮箱么?
你的油箱地址?发短消息给我。
谢谢了。。。
#24
用你的图像跟你的代码,运行完全成功,没有任何问题。代码如下:
CBitmap bmp;
BYTE pData[59520];
bmp.LoadBitmap(IDB_BITMAP1);
HDC hdc=::GetDC(NULL);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 248;
bih.biHeight = 80;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 80*248*3;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
GetDIBits(hdc,hbmp,0,80,pData,(BITMAPINFO *)&bih,DIB_RGB_COLORS);
::ReleaseDC(NULL, hdc);
// 以下是你的creatbmp函数内的部分。bih借用了一下,就没有再弄新的了。
int size = 248*80*3; // 每个像素点3个字节
BITMAPFILEHEADER bfh;
bfh.bfType=0X4d42;
bfh.bfSize = size + sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
bfh.bfReserved1 = 0; // reserved
bfh.bfReserved2 = 0; // reserved
bfh.bfOffBits = bfh.bfSize - size;
FILE * fp = fopen("jbs.bmp","wb");
if( !fp ) return;
fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp );
fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp );
fwrite( pData, 1, size, fp );
fclose( fp );
#25
在你发给我的运行结果里,pData完全没赋值,仅仅是DEBUG版中,声明pData数组:BYTE pData[59520]时,系统给你赋的初始值,每个字节都是0xCC。所以你打开图像看的时候看到的都是一片灰色。你再仔细查查吧。
#26
没那么麻烦,把位图资源用FindResource,LoadResource打开,SizeofResource得到大小,在文件里先写入"BM",再写入Resource就行了。根本不用管位图格式。
#27
你好。
我用 if(hbmp==NULL){
AfxMessageBox("1111111111111");
}
else{
AfxMessageBox("2222222222222");
}
检查,发现hbmp是空的,也就是说bmp.LoadBitmap(IDB_BITMAP1);也是空的。
所以我的资源Load有问题!
为什么呢?
#28
1、从资源视图中,检查你的资源里是否确实有一个叫IDB_BITMAP1的位图。
2、查看IDB_BITMAP1的属性,看它所指向文件的全路径,然后去硬盘上看看这个路径\文件是否存在。
3、在解决方案视图里,看看你的工程是否把该文件包含在内。
2、查看IDB_BITMAP1的属性,看它所指向文件的全路径,然后去硬盘上看看这个路径\文件是否存在。
3、在解决方案视图里,看看你的工程是否把该文件包含在内。
#29
这段代码我用了很长时间了,应该没有问题吧,你先调试一下出行的是哪一行。
另外,
bmp.LoadBitmap(IDB_BITMAP1);
HBITMAP hbmp = HBITMAP(bmp.GetSafeHandle());
BitMapToFile(hbmp,"jbs.bmp");
这个是不是太麻烦了一点,直接写成这样不是更好:
HBITMAP hbmp=::LoadBitmap(AfxGetApp()->m_hInstance,IDB_BITMAP1);
BitMapToFile(hbmp,"jbs.bmp");
#30
你好。我把刚那个资源删除,重新又引入了一边。
这下hbmp不为空了。
但是生成的bmp图片却和原始的大不一样了。
所以又的麻烦你了。我把输出生成的图片发给你的邮箱。你再看看。
#31
你再回去看看你导入的资源图片是不是也变成这样了。VC6不能打开32位bmp,如果你导入的时候顺便操作了一下的话,很可能就变成类似的样子了。
#32
我先是在资源管理里点击引入,再选到我要引入的bmp图。
打开后就提示超过了256色,无法打开。我点击确定。
就这个过程啊,我也没有操作它。
现在生成的图又换成了另外一个无标,一个对勾标志。
我都删了引,引了删了好几次了。
怎么还是不对?是不是我引入图有问题?
麻烦你了。
#33
你的代码没问题。
但是现在生成的图不是我资源加载的图。
是个复选框之类的图标。为什么啊?
和我上面代码生成的一样,都是没出来资源里的图。
是不是资源引入有问题啊?
#34
你好。
我这个工程是动态库,我在vb中调用调试。
每次生成dll后把它拷贝到vb中,调用。
发现每次生成的图片就是vb中的控件面版上的控件图片。前面几次是个对勾的复选框,这次有成了pictureBox了。是不是和这个有关系啊?
还是哪个句柄取错了?
#35
学习了
#36
我也是忽然发现你这个是个DLL。那么,你的每个输出函数里,有没有在最前面加上一句:AFX_MANAGE_STATE(AfxGetStaticModuleState( ));?
#37
恩。是没加,真不好意思忘了我,图片出来了。为什么这个?
还有现在报断言错误,APPINIT.CPP的ASSERT(afxCurrentAppName == NULL);段。
是不是哪个句柄没释放?我再找找原因。
真是感谢你了。
#38
谢谢了,出来,问题找出来了我。
AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0);
这句去掉了,前面没有APPINIT.CPP的ASSERT(afxCurrentAppName == NULL);需要
加AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0);
现在就好了。真是感谢你了。
要是有时间帮我解释下为什么?呵呵。
#39
什么为什么?为什么不加AFX_MANAGE_STATE会出错?很简单,以下全文引用MSDN:
By default, MFC uses the resource handle of the main application to load the resource template. If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. You need to switch the module state for the correct handle to be used. You can do this by adding the following code to the beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.
By default, MFC uses the resource handle of the main application to load the resource template. If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. You need to switch the module state for the correct handle to be used. You can do this by adding the following code to the beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.