CreateDIBitmap:捕获的黑色图像

时间:2018-01-29 00:48:25

标签: delphi tbitmap

我已根据此C++ example构建了以下代码的一部分,目标是在捕获时不显示主要表单的情况下制作屏幕截图。

我的麻烦是因为我通过以下代码获取黑屏:

function MagImageScalingCallback(hwnd: hwnd; srcdata: Pointer;
  srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
  unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;
var
  lpbmih: TBitmapInfoHeader;
  lpbmi: TBitmapInfo;
  aBitmap: HBITMAP;
  aDC: HDC;
  bmp: TBitmap;
begin
  Fillchar(lpbmih, SizeOf(lpbmih), 0);
  lpbmih.biSize := SizeOf(lpbmih);
  lpbmih.biWidth := srcheader.width;
  lpbmih.biHeight := srcheader.height;
  lpbmih.biPlanes := 1;
  lpbmih.biBitCount := Floor(lpbmih.biSizeImage / lpbmih.biHeight /
    lpbmih.biWidth * 8);
  lpbmih.biCompression := BI_RGB;

  Fillchar(lpbmi, SizeOf(lpbmi), 0);
  lpbmi.bmiHeader.biSize := SizeOf(lpbmi.bmiHeader);
  lpbmi.bmiHeader.biWidth := srcheader.width;
  lpbmi.bmiHeader.biHeight := srcheader.height;
  lpbmi.bmiHeader.biPlanes := 1;
  lpbmi.bmiHeader.biBitCount :=
    Floor(lpbmi.bmiHeader.biSizeImage / lpbmi.bmiHeader.biHeight /
    lpbmi.bmiHeader.biWidth * 8);
  lpbmi.bmiHeader.biCompression := BI_RGB;

  aDC := GetWindowDC(hwnd);
  bmp := TBitmap.Create;
  aBitmap := 0;
  try
    aBitmap := CreateDIBitmap(aDC, lpbmih, 0, nil, lpbmi, DIB_RGB_COLORS);
    bmp.handle := aBitmap;
    bmp.SaveToFile('c:\screen.bmp');
  finally
    DeleteObject(aBitmap);
    DeleteDC(aDC);
    bmp.Free;
  end;
  Result := True;
end;

这是我的完整代码:

var
  Form1: TForm1;

implementation

uses
  Unit3, Magnification;

{$R *.dfm}

function MagImageScalingCallback(hwnd: hwnd; srcdata: Pointer;
  srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
  unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;
var
  lpbmih: TBitmapInfoHeader;
  lpbmi: TBitmapInfo;
  aBitmap: HBITMAP;
  aDC: HDC;
  bmp: TBitmap;
begin
  Fillchar(lpbmih, SizeOf(lpbmih), 0);
  lpbmih.biSize := SizeOf(lpbmih);
  lpbmih.biWidth := srcheader.width;
  lpbmih.biHeight := srcheader.height;
  lpbmih.biPlanes := 1;
  lpbmih.biBitCount := Floor(lpbmih.biSizeImage / lpbmih.biHeight /
    lpbmih.biWidth * 8);
  lpbmih.biCompression := BI_RGB;

  Fillchar(lpbmi, SizeOf(lpbmi), 0);
  lpbmi.bmiHeader.biSize := SizeOf(lpbmi.bmiHeader);
  lpbmi.bmiHeader.biWidth := srcheader.width;
  lpbmi.bmiHeader.biHeight := srcheader.height;
  lpbmi.bmiHeader.biPlanes := 1;
  lpbmi.bmiHeader.biBitCount :=
    Floor(lpbmi.bmiHeader.biSizeImage / lpbmi.bmiHeader.biHeight /
    lpbmi.bmiHeader.biWidth * 8);
  lpbmi.bmiHeader.biCompression := BI_RGB;

  aDC := GetWindowDC(hwnd);
  bmp := TBitmap.Create;
  aBitmap := 0;
  try
    aBitmap := CreateDIBitmap(aDC, lpbmih, 0, nil, lpbmi, DIB_RGB_COLORS);
    bmp.handle := aBitmap;
    bmp.SaveToFile('c:\screen.bmp');
  finally
    DeleteObject(aBitmap);
    DeleteDC(aDC);
    bmp.Free;
  end;
  Result := True;
end;

procedure MagScreenShot;
var
  desktop, hwndMag: hwnd;
  desktoprect, sourceRect: TRect;
  filterList: THWNDArray;
  m_ScreenX, m_ScreenY, m_ScreenT, m_ScreenL: Integer;
begin

  if not Form3.Showing then
    Form3.Show;

  desktop := GetDesktopWindow;
  GetWindowRect(desktop, desktoprect);

  m_ScreenT := desktoprect.Top;
  m_ScreenL := desktoprect.Left;
  m_ScreenX := desktoprect.right;
  m_ScreenY := desktoprect.bottom;

  if (not MagInitialize) then
  begin
    Application.MessageBox('Init magnification failed', 'Error',
      mb_Ok + mb_IconError);
    Exit;
  end;

  hwndMag := CreateWindow(WC_MAGNIFIER, 'MagnifierWindow',
    WS_CHILD or MS_SHOWMAGNIFIEDCURSOR or WS_VISIBLE, 0, 0, m_ScreenX,
    m_ScreenY, Form1.handle, 0, hInstance, nil);

  if (hwndMag = 0) then
  begin
    Application.MessageBox('MagnifierWindow creation failed', 'Error',
      mb_Ok + mb_IconError);
    Exit;
  end;

  if (not MagSetImageScalingCallback(hwndMag, MagImageScalingCallback)) then
  begin
    Application.MessageBox('Cannot set callback', 'Error',
      mb_Ok + mb_IconError);
    Exit;
  end;

  try
    filterList[0] := Form3.handle;
  except
  end;

  if (not MagSetWindowFilterList(hwndMag, MW_FILTERMODE_EXCLUDE, 1,
    @filterList[0])) then
  begin
    Application.MessageBox('Cannot exclude main window', 'Error',
      mb_Ok + mb_IconError);
    Exit;
  end;

  sourceRect.Top := m_ScreenT;
  sourceRect.Left := m_ScreenL;
  sourceRect.right := m_ScreenX;
  sourceRect.bottom := m_ScreenY;

  if (not MagSetWindowSource(hwndMag, sourceRect)) then
  begin
    Application.MessageBox('Cannot set source to MagnifierWindow', 'Error',
      mb_Ok + mb_IconError);
    Exit;
  end;

  { if (not MagUninitialize) then
    begin
    Application.MessageBox('Finalize magnification failed', 'Error',
    mb_Ok + mb_IconError);
    Exit;
    end; }
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  MagScreenShot;
end;

放大单位:

unit Magnification;

{$ALIGN ON}
{$MINENUMSIZE 4}

interface

uses
  Windows;

const
  // Magnifier Class Name
  WC_MAGNIFIERA: AnsiString = 'Magnifier';
  WC_MAGNIFIERW: WideString = 'Magnifier';
  WC_MAGNIFIER = 'Magnifier';

  // Magnifier Window Styles
  MS_SHOWMAGNIFIEDCURSOR = $0001;
  MS_CLIPAROUNDCURSOR = $0002;
  MS_INVERTCOLORS = $0004;

  // Filter Modes
  MW_FILTERMODE_EXCLUDE = 0;
  MW_FILTERMODE_INCLUDE = 1;

type
  tagMAGTRANSFORM = record
    v: array[1..3, 1..3] of Single;
  end;
  MAGTRANSFORM = tagMAGTRANSFORM;
  TMagTransform = tagMAGTRANSFORM;
  PMagTransform = ^TMagTransform;

  tagMAGIMAGEHEADER = record
    width: UINT;
    height: UINT;
    format: TGUID;
    stride: UINT;
    offset: UINT;
    cbSize: UINT;
  end;
  MAGIMAGEHEADER = tagMAGIMAGEHEADER;
  TMagImageHeader = tagMAGIMAGEHEADER;
  PMagImageHeader = ^TMagImageHeader;

  tagMAGCOLOREFFECT = record
    transform: array[1..5, 1..5] of Single;
  end;
  MAGCOLOREFFECT = tagMAGCOLOREFFECT;
  TMagColorEffect = tagMAGCOLOREFFECT;
  PMagColorEffect = ^TMagColorEffect;

  TMagImageScalingCallback = function (hwnd: HWND; srcdata: Pointer;
    srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
    unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;

  THWNDArray = array[0..0] of HWND;
  PHWNDArray = ^THWNDArray;

  // Public Functions
  function MagInitialize(): BOOL; stdcall;
  function MagUninitialize(): BOOL; stdcall;

  function MagSetWindowSource(hwnd: HWND; rect: TRect): BOOL; stdcall;
  function MagGetWindowSource(hwnd: HWND; var Rect: TRect): BOOL; stdcall;
  function MagSetWindowTransform(hwnd: HWND; var Transform: TMagTransform): BOOL; stdcall;
  function MagGetWindowTransform(hwnd: HWND; var Transform: TMagTransform): BOOL; stdcall;
  function MagSetWindowFilterList(hwnd: HWND; dwFilterMode: DWORD;
    count: Integer; pHWND: PHWNDArray): BOOL; stdcall;
  function MagGetWindowFilterList(hwnd: HWND; var dwFilterMode: DWORD;
    count: Integer; pHWND: PHWNDArray): Integer; stdcall;
  function MagSetImageScalingCallback(hwnd: HWND;
    MagImageScalingCallback: TMagImageScalingCallback): BOOL; stdcall;
//  MagImageScalingCallback WINAPI MagGetImageScalingCallback(HWND hwnd );
  function MagSetColorEffect(hwnd: HWND; var Effect: TMagColorEffect): BOOL; stdcall;
  function MagGetColorEffect(hwnd: HWND; var Effect: TMagColorEffect): BOOL; stdcall;

implementation

const
  MagnificationDll = 'Magnification.dll';

  function MagInitialize; external MagnificationDll name 'MagInitialize';
  function MagUninitialize; external MagnificationDll name 'MagUninitialize';
  function MagSetWindowSource; external MagnificationDll name 'MagSetWindowSource';
  function MagGetWindowSource; external MagnificationDll name 'MagGetWindowSource';
  function MagSetWindowTransform; external MagnificationDll name 'MagSetWindowTransform';
  function MagGetWindowTransform; external MagnificationDll name 'MagGetWindowTransform';
  function MagSetWindowFilterList; external MagnificationDll name 'MagSetWindowFilterList';
  function MagGetWindowFilterList; external MagnificationDll name 'MagGetWindowFilterList';
  function MagSetImageScalingCallback; external MagnificationDll name 'MagSetImageScalingCallback';
  function MagSetColorEffect; external MagnificationDll name 'MagSetColorEffect';
  function MagGetColorEffect; external MagnificationDll name 'MagGetColorEffect';

end.

版:

我最近在下面尝试了这个替代方案,但是生成了一个无效的bmp文件。

function SaveBitmapToFile(bitmap: PBITMAP; lpFileName: PChar;
  lpBuf: PChar): BOOL;
var
  dwWritten: DWORD;
  bmfHdr: BITMAPFILEHEADER;
  bi: BITMAPINFOHEADER;
  fh: THANDLE;
begin
  Result := False;
  fh := INVALID_HANDLE_VALUE;
  bi.biSize := sizeof(BITMAPINFOHEADER);
  bi.biWidth := bitmap^.bmWidth;
  bi.biHeight := bitmap^.bmHeight;
  bi.biPlanes := 1;
  bi.biBitCount := bitmap^.bmBitsPixel * 8;
  bi.biCompression := BI_RGB;
  bi.biSizeImage := 0;
  bi.biXPelsPerMeter := 0;
  bi.biYPelsPerMeter := 0;
  bi.biClrUsed := 0;
  bi.biClrImportant := 0;
  fh := CreateFile(lpFileName, GENERIC_WRITE, 0, Nil, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
  if (fh = INVALID_HANDLE_VALUE) then
    Exit;
  bmfHdr.bfType := $4D42; // "BM"
  bmfHdr.bfSize := sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
    bitmap^.bmWidth * bitmap^.bmHeight * bitmap^.bmBitsPixel;
  bmfHdr.bfReserved1 := 0;
  bmfHdr.bfReserved2 := 0;
  bmfHdr.bfOffBits := DWORD(sizeof(BITMAPFILEHEADER)) +
    DWORD(sizeof(BITMAPINFOHEADER));
  WriteFile(fh, PChar(@bmfHdr)^, sizeof(BITMAPFILEHEADER), dwWritten, nil);
  WriteFile(fh, PChar(@bi)^, sizeof(BITMAPINFOHEADER), dwWritten, nil);
  WriteFile(fh, PChar(lpBuf)^, bitmap^.bmWidth * bitmap^.bmHeight *
    bitmap^.bmBitsPixel, dwWritten, nil);
  FlushFileBuffers(fh);
  CloseHandle(fh);
  Result := true;
end;

function MagImageScalingCallback(hwnd: hwnd; srcdata: Pointer;
  srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
  unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;
var
  b: BITMAPINFO;
  hBitmap, hOld: Winapi.Windows.HBITMAP;
  bb: bitmap;
  hp: THANDLE;
  hDC, hcDC: Winapi.Windows.hDC;
  lpBuf: PChar;
begin

  hDC := GetDC(hwnd);
  hcDC := CreateCompatibleDC(hDC);
  hBitmap := CreateCompatibleBitmap(hDC, srcheader.width, srcheader.height);
  hOld := Winapi.Windows.HBITMAP(SelectObject(hcDC, hBitmap));
  BitBlt(hcDC, 0, 0, srcheader.width, srcheader.height, hDC, 0, 0, SRCCOPY);

  bb.bmWidth := srcheader.width;
  bb.bmHeight := srcheader.height;
  bb.bmPlanes := 1;
  bb.bmWidthBytes := bb.bmWidth * 3;
  bb.bmBitsPixel := 3;
  bb.bmType := 0;

  b.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
  b.bmiHeader.biHeight := srcheader.height;
  b.bmiHeader.biWidth := srcheader.width;
  b.bmiHeader.biSizeImage := srcheader.cbSize;
  b.bmiHeader.biPlanes := 1;
  b.bmiHeader.biBitCount := 3 * 8;
  b.bmiHeader.biCompression := BI_RGB;
  b.bmiHeader.biSizeImage := srcheader.cbSize;
  b.bmiHeader.biXPelsPerMeter := 0;
  b.bmiHeader.biYPelsPerMeter := 0;
  b.bmiHeader.biClrUsed := 0;
  b.bmiHeader.biClrImportant := 0;
  b.bmiColors[0].rgbBlue := 8;
  b.bmiColors[0].rgbGreen := 8;
  b.bmiColors[0].rgbRed := 8;
  b.bmiColors[0].rgbReserved := 0;

  hp := GetProcessHeap;
  lpBuf := PChar(HeapAlloc(hp, HEAP_ZERO_MEMORY, bb.bmHeight * bb.bmWidth * 4));
  GetDIBits(hcDC, hBitmap, 0, srcheader.height, lpBuf, b, DIB_RGB_COLORS);
  SaveBitmapToFile(@bb, 'c:\screen.bmp', lpBuf);

  ReleaseDC(hwnd, hDC);
  DeleteDC(hcDC);
  DeleteObject(hBitmap);
  DeleteObject(hOld);
  HeapFree(hp, 0, lpBuf);

  Result := true;
end;

Reference

1 个答案:

答案 0 :(得分:1)

biBitCount字段填充为零,但必须包含32之类的值 - 从源数据中获取它。此外,您不需要填充标题两次。

CreateDIBitmap函数调用不使用指向数据的指针(srcdata)。设置参数CBM_INIT和指向数据的指针。快速制作的工作示例:

var
  lpbmi: TBitmapInfo;
  bmp: TBitmap;
  SrcData: PByteArray;
  i: Integer;
  abitmap:HBitmap;
begin
  GetMem(SrcData, 256 * 256 * 4);
  for i := 0 to 256 * 256 - 1 do
    PInteger(@SrcData[i * 4])^ := Random($1000000);

  Fillchar(lpbmi, SizeOf(lpbmi), 0);
  lpbmi.bmiHeader.biSize := SizeOf(lpbmi.bmiHeader);
  lpbmi.bmiHeader.biWidth := 256;
  lpbmi.bmiHeader.biHeight := 256;
  lpbmi.bmiHeader.biPlanes := 1;
  lpbmi.bmiHeader.biBitCount := 32;
  lpbmi.bmiHeader.biCompression := BI_RGB;

  bmp := Tbitmap.Create;
  aBitmap := 0;
  try
    aBitmap := CreateDIBitmap(GetDC(0), lpbmi.bmiHeader, CBM_INIT, SrcData, lpbmi, DIB_RGB_COLORS);
    bmp.handle := aBitmap;
    Canvas.Draw(0, 0, bmp);
  finally
    DeleteObject(aBitmap);
    bmp.Free;
  end;
end;