00 把自定义的矩形区域保存为bmp硬盘文件

Post date: 2012/4/10 上午 08:19:36

如何把自定义的矩形区域保存为bmp硬盘文件!给段小代码呗![问题点数:120分,结帖人:java_lover_]

楼主

发表于:2009-05-07 19:57:15

如何把自定义的矩形区域保存为bmp硬盘文件!给段小代码呗!

回复次数:18

#1楼 得分:40

wendysen用户头像

回复于:2009-05-07 23:00:35

你的自定义举行区域应该是在某个设备上下文中吧?下面两个函数应该可以

HBITMAP CopyDCToBitmap(HDC hScrDC, LPRECT lpRect)

{

HDC hMemDC;

// 屏幕和内存设备描述表

HBITMAP hBitmap,hOldBitmap;

// 位图句柄

int nX, nY, nX2, nY2;

// 选定区域坐标

int nWidth, nHeight;

// 位图宽度和高度

// 确保选定区域不为空矩形

if ( IsRectEmpty( lpRect ) ) return NULL;

// 获得选定区域坐标

nX= lpRect->left;

nY= lpRect->top;

nX2 = lpRect->right;

nY2 = lpRect->bottom;

nWidth = nX2 - nX;

nHeight = nY2 - nY;

//为屏幕设备描述表创建兼容的内存设备描述表

hMemDC= CreateCompatibleDC( hScrDC );

// 创建一个与屏幕设备描述表兼容的位图

hBitmap = CreateCompatibleBitmap( hScrDC, nWidth, nHeight );

// 把新位图选到内存设备描述表中

hOldBitmap = ( HBITMAP )SelectObject( hMemDC, hBitmap );

// 把屏幕设备描述表拷贝到内存设备描述表中

StretchBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, nWidth, nHeight, SRCCOPY );

//得到屏幕位图的句柄

hBitmap = ( HBITMAP )SelectObject( hMemDC, hOldBitmap );

//清除

DeleteDC( hMemDC );

DeleteObject( hOldBitmap );

//返回位图句柄

return hBitmap;

}

BOOL SaveBmp(HBITMAP hBitmap, CString FileName)

{

HDC hDC;

//当前分辨率下每象素所占字节数

int iBits;

//位图中每象素所占字节数

WORD wBitCount;

//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数

DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;

//位图属性结构

BITMAP Bitmap;

//位图文件头结构

BITMAPFILEHEADER bmfHdr;

//位图信息头结构

BITMAPINFOHEADER bi;

//指向位图信息头结构

LPBITMAPINFOHEADER lpbi;

//定义文件,分配内存句柄,调色板句柄

HANDLE fh, hDib, hPal,hOldPal=NULL;

//计算位图文件每个像素所占字节数

hDC = CreateDC("DISPLAY", NULL, NULL, NULL);

iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);

DeleteDC(hDC);

if (iBits <= 1) wBitCount = 1;

else if (iBits <= 4) wBitCount = 4;

else if (iBits <= 8) wBitCount = 8;

else wBitCount = 24;

GetObject( hBitmap, sizeof( Bitmap ), ( LPSTR )&Bitmap );

bi.biSize = sizeof( BITMAPINFOHEADER );

bi.biWidth = Bitmap.bmWidth;

bi.biHeight = Bitmap.bmHeight;

bi.biPlanes = 1;

bi.biBitCount = wBitCount;

bi.biCompression = BI_RGB;

bi.biSizeImage = 0;

bi.biXPelsPerMeter = 0;

bi.biYPelsPerMeter = 0;

bi.biClrImportant = 0;

bi.biClrUsed = 0;

dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;

//为位图内容分配内存

hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));

lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);

*lpbi = bi;

// 处理调色板

hPal = GetStockObject(DEFAULT_PALETTE);

if (hPal)

{

hDC = ::GetDC(NULL);

//hDC = m_pDc->GetSafeHdc();

hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);

RealizePalette(hDC);

}

// 获取该调色板下新的像素值

GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)

+dwPaletteSize, (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; // "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;

// 写入位图文件头

WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);

// 写入位图文件其余内容

WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);

//清除

GlobalUnlock(hDib);

GlobalFree(hDib);

CloseHandle(fh);

return TRUE;

}

#2楼 得分:0

java_lover_用户头像

回复于:2009-05-08 00:10:11

引用 1 楼 wendysen 的回复:

你的自定义举行区域应该是在某个设备上下文中吧?下面两个函数应该可以

HBITMAP CopyDCToBitmap(HDC hScrDC, LPRECT lpRect)

{

HDC hMemDC;

// 屏幕和内存设备描述表

HBITMAP hBitmap,hOldBitmap;

// 位图句柄

int nX, nY, nX2, nY2;

// 选定区域坐标

int nWidth, nHeight;

// 位图宽度和高度

// 确保选定区域不为空矩形

if ( IsRectEmpty( lpRect ) ) retur…

我试试!

#3楼 得分:0

java_lover_用户头像

回复于:2009-05-08 00:45:23

引用 1 楼 wendysen 的回复:

你的自定义举行区域应该是在某个设备上下文中吧?下面两个函数应该可以

HBITMAP CopyDCToBitmap(HDC hScrDC, LPRECT lpRect)

{

HDC hMemDC;

// 屏幕和内存设备描述表

HBITMAP hBitmap,hOldBitmap;

// 位图句柄

int nX, nY, nX2, nY2;

// 选定区域坐标

int nWidth, nHeight;

// 位图宽度和高度

// 确保选定区域不为空矩形

if ( IsRectEmpty( lpRect ) ) retur…

非常感谢大哥的帮忙,这两个函数已经可以满足把窗口客户区范围以内的区域保存为bmp文件了。但是我画的区域不只是此范围以内,而且已经延伸到该区域之外,甚至是屏幕范围以外。不知道,可不可以利用这两个函数实现正确的保存功能。

#4楼 得分:0

lyserver用户头像

回复于:2009-05-08 00:58:01

他的代码是根据内存DC生成BMP,区域外也没问题。

        • 2
        • 3

#5楼 得分:0

java_lover_用户头像

回复于:2009-05-08 10:11:56

是吗,我是这么用的!

先定义一个

C/C++ code

BOOL SaveBmpFile = FALSE;

然后在 想用鼠标左键双击时

C/C++ code

SaveBmpFile = TRUE; InvalidateRect(&DrawArea,TRUE); //DrawArea是我要保存的区域,其边界超过了屏幕 RedrawWindow(&DrawArea,NULL,RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

然后在OnPaint中

C/C++ code

CPaintDC dc(this); CDC MemDC; //创建内存DC并在这里面画图,之后再将其拷贝的PaintDC MemDC.CreateCompatibleDC( &dc ); CRect rect; GetClientRect(rect); CBitmap bmpFace; bmpFace.CreateCompatibleBitmap ( &dc, rect.Width(), rect.Height() ); CBitmap* pOldBmp = NULL; pOldBmp = MemDC.SelectObject(&bmpFace); ...//其中MemDC中绘图已经超出了屏幕区域 if ( SaveBmpFile ) { SaveBmpFile = FALSE; if ( SaveBmp( CopyDCToBitmap( MemDC.m_hDC, &DrawArea ), "波形图.bmp" ) ) MessageBox ( "波形图已经保存到程序所在目录的 \''波形图.bmp\"" ); } dc.BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&MemDC,rect.left,rect.top,SRCCOPY); //将内存DC中的内容拷贝到设备DC MemDC.SelectObject(pOldBmp); bmpFace.DeleteObject();

这样做,保存的位图尺寸确实跟DrawArea一样,但是屏幕以外那部分是黑色的,窗口客户区以外屏幕以内的那部分是屏幕上的内容!

奇了怪了,我保存的不是内存DC中的内容吗。怎么还会出现屏幕上的内容!

希望给与关注,分不够再加!

#6楼 得分:20

lyserver用户头像

回复于:2009-05-08 10:30:50

由于你的DC是过程内部的临时变量,肯定会这样。

解决办法,在绘图完比之后,MemDC.SelectObject(pOldBmp)语句后进行保存。

或者,创建一个全局内存DC变量,在窗口类的开始处进行初始化,所有绘图均在这个内存DC里进行,在类的PAINT事件里用BibBlt进行输出。这也就是人们常说的双缓冲。

或者,在创建窗口类时,指定CS_OWNDC属性。

        • 2
        • 3

#7楼 得分:0

liao05050075用户头像

回复于:2009-05-08 10:36:14

MARK

#8楼 得分:0

yurenwjq用户头像

回复于:2009-05-08 10:41:09

上面的很详细了, 我。。。

#9楼 得分:10

lyserver用户头像

回复于:2009-05-08 10:48:23

没仔细看,原来那个代码有点问题,将StretchBlt改为BitBlt。

        • 2
        • 3

#10楼 得分:0

java_lover_用户头像

回复于:2009-05-08 11:23:10

好,我再试试!

#11楼 得分:10

hendriclee用户头像

回复于:2009-05-08 11:27:19

就是类似截图的功能嘛,静态截图程序模拟实现

#12楼 得分:0

java_lover_用户头像

回复于:2009-05-08 13:52:31

引用 9 楼 lyserver 的回复:

没仔细看,原来那个代码有点问题,将StretchBlt改为BitBlt。

不行啊,改了之后,窗口客户区以外,屏幕以内确实已不是屏幕上的内容了,但这部分区域和屏幕区域以外的区域一样了,变成了黑色了!郁闷!。。。。continue......

#13楼 得分:20

lyserver用户头像

回复于:2009-05-08 18:13:16

        • 2
        • 3

C/C++ code

int Save(HDC hDC,LPCSTR szFileName,UINT nLeft=0,UINT nTop=0,UINT nWidth=0,UINT nHeight=0) { HDC hMemDC; HBITMAP hMemBmp,hOldBmp; int retVal=0; if( nWidth<nLeft || nHeight<nTop)return 0; hMemDC = CreateCompatibleDC(hDC); hMemBmp = CreateCompatibleBitmap(hDC,(nWidth-nLeft),(nHeight-nTop)); hOldBmp = (HBITMAP)SelectObject(hMemDC,hMemBmp); BitBlt(hMemDC,nLeft,nTop,(nWidth-nLeft),(nHeight-nTop),hDC,nLeft,nTop,SRCCOPY); PICTDESC ps; IPicture* pIPic=NULL; ps.cbSizeofstruct = sizeof(PICTDESC); ps.picType = PICTYPE_BITMAP; ps.bmp.hbitmap = hMemBmp; ps.bmp.hpal = NULL; if(OleCreatePictureIndirect(&ps,IID_IPicture,TRUE,(LPVOID*)&pIPic)==ERROR_SUCCESS) { LONG lSize = 0; IStream* pIStm = NULL; CreateStreamOnHGlobal(NULL,TRUE,&pIStm); if(pIPic->SaveAsFile(pIStm,TRUE,&lSize) == ERROR_SUCCESS) { LARGE_INTEGER li; li.HighPart = 0; li.LowPart = 0; ULARGE_INTEGER uli; uli.HighPart = 0; uli.LowPart = 0; pIStm->Seek(li, STREAM_SEEK_SET, &uli); char buffer[1024]; HANDLE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); DWORD dwRead = 1,dwWrite=0; while(dwRead>0) { pIStm->Read(buffer, 1024, &dwRead); if(dwRead > 0)WriteFile(hFile, buffer, dwRead, &dwWrite, NULL); } CloseHandle(hFile); retVal=1; } pIPic->Release(); pIStm->Release(); } DeleteObject(SelectObject(hMemDC,hOldBmp)); DeleteDC(hMemDC); return retVal; }

#14楼 得分:10

lyserver用户头像

回复于:2009-05-08 18:29:38

        • 2

俺这个函数已通过测试,测试代码如下:

C/C++ code

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { HDC hDesktopDC,hDC; HBITMAP hBmp,hOldBmp; hDesktopDC=GetDC(NULL); hDC=CreateCompatibleDC(hDesktopDC); hBmp=CreateCompatibleBitmap(hDesktopDC,1000,2000); hOldBmp=(HBITMAP)SelectObject(hDC,hBmp); RECT rc; SetRect(&rc,0,0,1000,2000); FillRect(hDC,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH)); MoveToEx(hDC,10,10,NULL); LineTo(hDC,900,1900); Rectangle(hDC,500,500,900,1400); Save(hDC,"c:\\temp.bmp",0,0,1000,2000); DeleteObject(SelectObject(hDC,hOldBmp)); DeleteDC(hDC); ReleaseDC(NULL,hDesktopDC); MessageBox(NULL,"保存完毕!","",MB_OK); return 0; }

        • 3

#15楼 得分:10

lambochan用户头像

回复于:2009-05-08 18:46:25

怎么画出来的啊?

怎么画出来就怎么存回去,,有那么复杂吗?

不过有些地方看不明:

什么叫做超出屏幕?

意思是你画的东西不是在客户区画,而是window屏幕上画?

还是说你画的东西在你的客户区有部分是看不见的啊?

其实道理一样..Create个足够大的BMP(你总会知道你画的内容的宽和高吧),在这个BMP上画不就得了.

然后,要保存的话,就easy job了.

#17楼 得分:0

lyserver用户头像

回复于:2009-05-13 14:18:45

        • 2
        • 3

C/C++ code

#include "stdafx.h" #include <ocidl.h> #include <olectl.h> // //////////////////////////////////////// // 函数名称:DC2File // 函数功能:将指定DC中的位图保存为BMP文件 // //////////////////////////////////////// BOOL DC2File(HDC hDC,LPCSTR szFileName,UINT nLeft=0,UINT nTop=0,UINT nWidth=0,UINT nHeight=0) { HDC hMemDC; BITMAP bmp; HBITMAP hSrcBmp,hMemBmp,hOldBmp; BOOL retVal=FALSE; hSrcBmp=(HBITMAP)GetCurrentObject(hDC,OBJ_BITMAP); if(hSrcBmp==NULL)return FALSE; GetObject(hSrcBmp,sizeof(BITMAP),&bmp); if(nWidth>(UINT)bmp.bmWidth)nWidth=(UINT)bmp.bmWidth; if(nHeight>(UINT)bmp.bmHeight)nHeight=(UINT)bmp.bmHeight; if( nWidth<nLeft || nHeight<nTop)return 0; hMemDC = CreateCompatibleDC(hDC); hMemBmp = CreateCompatibleBitmap(hDC,(nWidth-nLeft),(nHeight-nTop)); hOldBmp = (HBITMAP)SelectObject(hMemDC,hMemBmp); BitBlt(hMemDC,nLeft,nTop,(nWidth-nLeft),(nHeight-nTop),hDC,nLeft,nTop,SRCCOPY); PICTDESC ps; IPicture* pIPic=NULL; ps.cbSizeofstruct = sizeof(PICTDESC); ps.picType = PICTYPE_BITMAP; ps.bmp.hbitmap = hMemBmp; ps.bmp.hpal = NULL; if(OleCreatePictureIndirect(&ps,IID_IPicture,TRUE,(LPVOID*)&pIPic)==ERROR_SUCCESS) { LONG lSize = 0; IStream* pIStm = NULL; CreateStreamOnHGlobal(NULL,TRUE,&pIStm); if(pIPic->SaveAsFile(pIStm,TRUE,&lSize) == ERROR_SUCCESS) { LARGE_INTEGER li; li.HighPart = 0; li.LowPart = 0; ULARGE_INTEGER uli; uli.HighPart = 0; uli.LowPart = 0; pIStm->Seek(li, STREAM_SEEK_SET, &uli); char buffer[1024]; HANDLE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); DWORD dwRead = 1,dwWrite=0; while(dwRead>0) { pIStm->Read(buffer, 1024, &dwRead); if(dwRead > 0)WriteFile(hFile, buffer, dwRead, &dwWrite, NULL); } CloseHandle(hFile); retVal=TRUE; } pIPic->Release(); pIStm->Release(); } DeleteObject(SelectObject(hMemDC,hOldBmp)); DeleteDC(hMemDC); return retVal; }

#18楼 得分:0

lhslktg用户头像

回复于:2009-11-11 15:53:20

lm

相关问题

公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告

北京创新乐知信息技术有限公司 版权所有, 京 ICP 证 070598 号

世纪乐知(北京)网络技术有限公司 提供技术支持

江苏乐知网络技术有限公司 提供商务支持

Email:webmaster@csdn.net

Copyright © 1999-2012, CSDN.NET, All Rights Reserved

GongshangLogo