Delphi 12.1 FireMonkey捕获屏幕出现黑块问题求助
解决FireMonkey桌面截图出现黑色矩形的问题
问题根源
FireMonkey的TBitmap与VCL的TBitmap底层实现完全不同,它的Handle属性并非直接对应GDI的HBITMAP,直接调用BitBlt写入会导致无法正确捕获图像,最终生成黑色矩形。
解决方案(无需额外外部库)
方法1:使用FMX原生屏幕捕获(推荐)
FireMonkey自带屏幕捕获API,代码简洁且避免格式兼容问题:
var ScreenShot: TBitmap; begin ScreenShot := TBitmap.Create(Round(aRect.Width), Round(aRect.Height)); try // 捕获指定区域的屏幕内容 ScreenShot.CaptureFromScreen(aRect); ScreenShot.SaveToFile('test.bmp'); finally ScreenShot.Free; end; end;
方法2:GDI位图中转(底层控制场景)
如果需要更底层的GDI操作,可通过GDI位图捕获后转换为FMX格式:
const CAPTUREBLT = $40000000; var GdiBitmap: HBITMAP; GdiMemDC: HDC; ScreenDC: HDC; FmxBitmap: TBitmap; BitmapInfo: TBitmapInfo; BitmapData: Pointer; begin ScreenDC := GetDC(0); try // 初始化GDI位图信息 ZeroMemory(@BitmapInfo, SizeOf(BitmapInfo)); BitmapInfo.bmiHeader.biSize := SizeOf(BitmapInfo.bmiHeader); BitmapInfo.bmiHeader.biWidth := 300; BitmapInfo.bmiHeader.biHeight := -300; // 负高度表示从上到下的图像 BitmapInfo.bmiHeader.biPlanes := 1; BitmapInfo.bmiHeader.biBitCount := 32; BitmapInfo.bmiHeader.biCompression := BI_RGB; GdiMemDC := CreateCompatibleDC(ScreenDC); try GdiBitmap := CreateDIBSection(ScreenDC, BitmapInfo, DIB_RGB_COLORS, BitmapData, 0, 0); if GdiBitmap <> 0 then try SelectObject(GdiMemDC, GdiBitmap); // 捕获屏幕到GDI位图 BitBlt(GdiMemDC, 0, 0, 300, 300, ScreenDC, Round(aRect.Left), Round(aRect.Top), SRCCOPY or CAPTUREBLT); // 转换为FMX TBitmap(处理BGRA转RGBA格式差异) FmxBitmap := TBitmap.Create(300, 300); try FmxBitmap.Map(TMapAccess.Write); try var SrcPtr := PByte(BitmapData); var DestPtr := PByte(FmxBitmap.Scanline[0]); for y := 0 to FmxBitmap.Height - 1 do begin var RowSrc := SrcPtr; var RowDest := DestPtr; for x := 0 to FmxBitmap.Width - 1 do begin RowDest^ := RowSrc[2]; // R通道 Inc(RowDest); RowDest^ := RowSrc[1]; // G通道 Inc(RowDest); RowDest^ := RowSrc[0]; // B通道 Inc(RowDest); RowDest^ := RowSrc[3]; // A通道 Inc(RowDest); Inc(RowSrc, 4); end; Inc(SrcPtr, 300 * 4); Inc(DestPtr, FmxBitmap.RowBytes); end; finally FmxBitmap.Unmap; end; FmxBitmap.SaveToFile('test.bmp'); finally FmxBitmap.Free; end; finally DeleteObject(GdiBitmap); end; finally DeleteDC(GdiMemDC); end; finally ReleaseDC(0, ScreenDC); end; end;
关键说明
- 方法1是FMX原生实现,无需处理像素格式转换,代码更简洁,优先选用。
- 方法2需注意GDI的32位位图为BGRA格式,而FMX的
TBitmap为RGBA格式,必须转换通道顺序才能显示正确图像。
内容的提问来源于stack exchange,提问作者Peter Jones
相关产品推荐
相关产品推荐

