求屏幕抓图并保存为图片文件的代码,要求用API实现,不引用Graphics和Forms(300)

  • 主题发起人 主题发起人 gaiyueyue
  • 开始时间 开始时间
G

gaiyueyue

Unregistered / Unconfirmed
GUEST, unregistred user!
想抓取屏幕并保存为图片文件,不要引用那个Graphics,太大了,要API实现这个功能,高手们帮帮我吧找了好几天代码,看到的全是C写的,我也看不懂呀,翻译不出来,麻烦高手们帮我找找相关代码,要DELPHI的下面是我在网上找到的C的代码HBITMAP CopyScreenToBitmap(LPRECT lpRect){//屏幕和内存设备描述表HDC hSrcDC, hMemDC;//位图句柄HBITMAP hBitmap, hOldBitmap;//选定区域坐标int nX, nY, nX2, nY2;//位图宽度和高度int nWidth, nHeight;//屏幕分辨率int xScrn, yScrn;//确保选定区域不为空矩形if(IsRectEmpty(lpRect)) return NULL;//为屏幕创建设备描述表hSrcDC = CreateDC("DISPLAY", NULL, NULL, NULL);//为屏幕设备描述表创建兼容的内存设备描述表hMemDC = CreateCompatibleDC(hSrcDC);//获得选定区域坐标nX = lpRect->left;nY = lpRect->top;nX2 = lpRect->right;nY2 = lpRect->bottom;//获得屏幕分辨率xScrn = GetDeviceCaps(hSrcDC, HORZRES);yScrn = GetDeviceCaps(hSrcDC, VERTRES);//确保选定区域是可见的if(nX<0) nX = 0;if(nY<0) nY = 0;if(nX2>xScrn) nX2 = xScrn;if(nY2>yScrn) nY2 = yScrn;nWidth = nX2 - nX;nHeight = nY2 - nY;//创建一个与屏幕设备描述表兼容的位图hBitmap = CreateCompatibleBitmap(hSrcDC, nWidth, nHeight);//把新位图选到内存设备描述表中hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//把屏幕设备描述表拷贝到内存设备描述表中BitBlt(hMemDC, 0, 0, nWidth, nHeight, hSrcDC, nX, nY, SRCCOPY);//得到屏幕位图的句柄hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);//清除DeleteDC(hSrcDC);DeleteDC(hMemDC);//返回位置句柄}*/HBITMAP CopyScreenToBitmap(int x1, int x2, int y1, int y2){//屏幕和内存设备描述表HDC hSrcDC, hMemDC;//位图句柄HBITMAP hBitmap, hOldBitmap;//选定区域坐标int nX, nY, nX2, nY2;//位图宽度和高度int nWidth, nHeight;//屏幕分辨率int xScrn, yScrn;/*//确保选定区域不为空矩形if(IsRectEmpty(lpRect)) return NULL;*///为屏幕创建设备描述表hSrcDC = CreateDC("DISPLAY", NULL, NULL, NULL);//为屏幕设备描述表创建兼容的内存设备描述表hMemDC = CreateCompatibleDC(hSrcDC);//获得选定区域坐标nX = x1;nY = y1;nX2 = x2;nY2 = y2;//获得屏幕分辨率xScrn = GetDeviceCaps(hSrcDC, HORZRES);yScrn = GetDeviceCaps(hSrcDC, VERTRES);//确保选定区域是可见的if(nX<0) nX = 0;if(nY<0) nY = 0;if(nX2>xScrn) nX2 = xScrn;if(nY2>yScrn) nY2 = yScrn;nWidth = nX2 - nX;nHeight = nY2 - nY;//创建一个与屏幕设备描述表兼容的位图hBitmap = CreateCompatibleBitmap(hSrcDC, nWidth, nHeight);//把新位图选到内存设备描述表中hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//把屏幕设备描述表拷贝到内存设备描述表中BitBlt(hMemDC, 0, 0, nWidth, nHeight, hSrcDC, nX, nY, SRCCOPY);//得到屏幕位图的句柄hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);//清除DeleteDC(hSrcDC);DeleteDC(hMemDC);//返回位置句柄return hBitmap;}BOOL SaveCapturedBitmap(HBITMAP hBitmap, CString FileName){if(hBitmap==NULL || FileName.IsEmpty()){ AfxMessageBox("参数错误"); return false;}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); 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;}int main(){HBITMAP hCaptureBitmap = CopyScreenToBitmap(100, 700, 100, 700);SaveCapturedBitmap(hCaptureBitmap, "Hello.bmp");return 0;}
 
几乎不用翻译就可以用了,吧=变成:=把类似 (HBITMAP)SelectObject(hMemDC, hBitmap);换为 SelectObject(hMemDC, hBitmap);(DWORD)sizeof(BITMAPFILEHEADER)-->sizeof(BITMAPFILEHEADER)WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);-->WriteFile(fh, pchar(@bmfHdr), sizeof(BITMAPFILEHEADER), dwWritten, 0);等等,呵呵
 
会着不难,难者不会。就是用一些WindowsAPI处理,多看看吧。正如 wql 所说,基本上都写好了,改动一下就好哦。
 
高手们帮我看看这个错在哪里了procedure SaveCapturedBitmap(var hBitmapp:HBITMAP;FileName:Pchar);varhdcc:HDC;//当前分辨率下每象素所占字节数 iBits:integer;//位图中每象素所占字节数 wBitCount:WORD;//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数//DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;dwPaletteSize, dwBmBitsSize, dwDIBSize, dwWritten :DWORD;//位图属性结构 Bitmapp:BITMAP;//位图文件头结构 bmfHdr:BITMAPFILEHEADER;//位图信息头结构 bi:BITMAPINFOHEADER;//指向位图信息头结构 lpbi:PBITMAPINFOHEADER; lpbmi :PBITMAPINFO;//定义文件,分配内存句柄,调色板句柄//HANDLE fh, hDib, hPal,hOldPal=NULL; fh, hDib, hPal,hOldPal:THANDLE;//计算位图文件每个像素所占字节数beginhDCc := CreateDC('DISPLAY5', nil, nil, nil);iBits := GetDeviceCaps(hDCc, BITSPIXEL) * GetDeviceCaps(hDCc, PLANES);DeleteDC(hDCc);if (iBits <= 1) then wBitCount := 1else if (iBits <= 4) then wBitCount := 4else if (iBits <= 8) then wBitCount := 8else wBitCount := 24;GetObject(hBitmapp, sizeof(Bitmapp), @Bitmapp);bi.biSize := sizeof(BITMAPINFOHEADER);bi.biWidth := Bitmapp.bmWidth;bi.biHeight := Bitmapp.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 := ((Bitmapp.bmWidth * wBitCount + 31) div 32) * 4 * Bitmapp.bmHeight; if lpbmi<> nil then FreeMem(lpbmi); GetMem(lpbmi,SizeOf(BITMAPINFOHEADER) + NumColors * sizeof(TRGBQuad));//为位图内容分配内存hDib := GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));//lpbi := GlobalLock(hDib);//lpbi^ := bi;lpbi := PBITMAPINFOHEADER(GlobalLock(hDib));//lpbi^ := bi; // CreateDIBitmap// 处理调色板hPal := GetStockObject(DEFAULT_PALETTE);//if hPal <> 0then//begin hDCc := GetDC(0); hOldPal := SelectPalette(hDCc, hPal, FALSE); RealizePalette(hDCc);//end;// 获取该调色板下新的像素值GetDIBits(hDCc, hBitmapp, 0, Bitmapp.bmHeight,Pchar(integer(lpbi) + sizeof(BITMAPINFOHEADER) +dwPaletteSize),lpbmi^,DIB_RGB_COLORS); //PBITMAPINFO(@lpbi)^//恢复调色板 if hOldPal <> 0 thenbegin SelectPalette(hDCc, hOldPal, TRUE); RealizePalette(hDCc); ReleaseDC(0, hDCc);end;//创建位图文件 fh := CreateFile(FileName, GENERIC_WRITE,0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);//if (fh == INVALID_HANDLE_VALUE) return FALSE;// 设置位图文件头bmfHdr.bfType := $4D42; // "BM"dwDIBSize := sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;bmfHdr.bfSize := dwDIBSize;bmfHdr.bfReserved1 := 0;bmfHdr.bfReserved2 := 0;bmfHdr.bfOffBits := sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize;// 写入位图文件头WriteFile(fh, bmfHdr, sizeof(BITMAPFILEHEADER), dwWritten, nil);// 写入位图文件其余内容WriteFile(fh, lpbi, dwDIBSize, dwWritten, nil);//清除GlobalUnlock(hDib);GlobalFree(hDib);CloseHandle(fh);end;
 
if lpbmi <> nil then FreeMem(lpbmi);由于lpbmi没有初始化,其值很随机,导致发生异常。不过,解决该问题后,执行虽然没异常,但产生的文件只有1K,应该无效。
 
谁再帮我改改这个代码,让它好用呀,小弟谢谢了
 
哪位朋友,帮我修改下这代码叫它好用呀,我弄不明白勒
 
因为我们的桌面基本上是16位色和32位色,所以我的代码里没有考虑调色板,用文件流而不用CreateFile和ReadFile,WriteFile是为了写程序简单一点你如果一定要用的话就自己改一下,因为我喜欢用文件流来处理program Project1;uses Windows,Classes;var g_hBmp:HBitmap; g_hScrDC:HDC;function CopyScreenToBitmap(ART:TRect):HBitmap;var hMemDC:HDC; hBmp,hOldBmp:HBitmap; nX,nY,nX2,nY2:Integer; nWidth,nHeight:Integer; xScrn,yScrn:Integer;begin result:=0; if IsRectEmpty(ART) then exit; g_hScrDC:=CreateDC('DISPLAY',nil,nil,nil); hMemDC:=CreateCompatibleDC(g_hScrDC); nX:=ART.Left; nY:=ART.Top; nX2:=ART.Right; nY2:=ART.Bottom; xScrn:=GetDeviceCaps(g_hScrDC,HORZRES); yScrn:=GetDeviceCaps(g_hScrDC,VERTRES); if nX<0 then nX:=0; if nY<0 then nY:=0; if nX2>xScrn then nX2:=xScrn; if nY2>yScrn then nY2:=yScrn; nWidth:=nX2-nX; nHeight:=nY2-nY; hBmp:=CreateCompatibleBitmap(g_hScrDC,nWidth,nHeight); hOldBmp:=SelectObject(hMemDC,hBmp); BitBlt(hMemDC,0,0,nWidth,nHeight,g_hScrDC,nX,nY,SRCCOPY); SelectObject(hMemDC,hOldBmp); DeleteObject(hOldBmp); DeleteDC(hMemDC); result:=hBmp;end;procedure SaveCapturedBitmap(fn:string);var bi:BITMAPINFO; pData:PByte; bm:BITMAP; bf:TBitmapFileHeader; fs:TFileStream; ImgSize:Integer;begin GetObject(g_hBmp,sizeof(bm),@bm); ImgSize:=bm.bmWidth*bm.bmHeight*bm.bmBitsPixel div 8; GetMem(pData,ImgSize); fillchar(bi,sizeof(bi),0); bi.bmiHeader.biSize:=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth:=bm.bmWidth; bi.bmiHeader.biHeight:=bm.bmHeight; bi.bmiHeader.biPlanes:=1; bi.bmiHeader.biBitCount:=bm.bmBitsPixel; GetDIBits(g_hScrDC,g_hBmp,0,bm.bmHeight,pData,bi,DIB_RGB_COLORS); bf.bfType:=$4D42; bf.bfSize:=sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER)+ImgSize; bf.bfReserved1:=0; bf.bfReserved2:=0; bf.bfOffBits:=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); fs:=TFileStream.Create(fn,fmCreate); try fs.WriteBuffer(bf,sizeof(bf)); fs.WriteBuffer(bi,sizeof(bi)); fs.WriteBuffer(pData^,ImgSize); finally fs.Free; end; FreeMem(pData);end;begin g_hBmp:=CopyScreenToBitmap(Rect(0,0,200,200)); SaveCapturedBitmap('c:/1.bmp'); DeleteObject(g_hBmp); DeleteDC(g_hScrDC);end.
 
后退
顶部