Как сохранить Windows.tagBitmap для потоковой передачи как полный DIB?

От стороннего компонента я получаю PBitmap который является указателем на Windows.tagBitmap запись.

{ Bitmap Header Definition }
  PBitmap = ^TBitmap;
  {$EXTERNALSYM tagBITMAP}
  tagBITMAP = record
    bmType: Longint;
    bmWidth: Longint;
    bmHeight: Longint;
    bmWidthBytes: Longint;
    bmPlanes: Word;
    bmBitsPixel: Word;
    bmBits: Pointer;
  end;
  TBitmap = tagBITMAP;
  {$EXTERNALSYM TBitmap}
  BITMAP = tagBITMAP;
  {$EXTERNALSYM BITMAP}

Я хотел бы преобразовать данные, содержащиеся в этом указателе, в обычный DIB и сохранить эти данные в поток. Как только Graphics.TBitmap.SaveToStream делает. Поэтому желательно, чтобы у меня была такая процедура:

procedure SavetagBitmapAsDIBToStream(const ABitmap: PBitmap; var AStream: TStream);

Я попытался найти информацию об этой структуре в MSDN, но ни один из заголовков, описанных там (BITMAPFILEHEADER, BITMAPINFOHEADER и т.д.) похоже соответствует tagBITMAP,

Может ли кто-то опытный в этом вопросе помочь мне?

Отредактировано: пример в C \ C++ также будет хорошо для меня.

2 ответа

Решение

Вот черновик решения. Это должно помочь кому-то построить правильный с обработкой ошибок / более красивым кодом и т. Д.

function CreateBitmapInfoStruct(pBmp: PBitmap): TBitmapInfo;
var
  bmi: TBitmapInfo;
  cClrBits: Word;
begin
  cClrBits := pBmp.bmPlanes * pBmp.bmBitsPixel;
  if (cClrBits = 1) then
      cClrBits := 1
  else if (cClrBits <= 4) then
      cClrBits := 4
  else if (cClrBits <= 8) then
      cClrBits := 8
  else if (cClrBits <= 16) then
      cClrBits := 16
  else if (cClrBits <= 24) then
      cClrBits := 24
  else cClrBits := 32;

  bmi.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
  bmi.bmiHeader.biWidth := pBmp.bmWidth;
  bmi.bmiHeader.biHeight := pBmp.bmHeight;
  bmi.bmiHeader.biPlanes := pBmp.bmPlanes;
  bmi.bmiHeader.biBitCount := pBmp.bmBitsPixel;
  if (cClrBits < 24) then
      bmi.bmiHeader.biClrUsed := (1 shl cClrBits)
  else
    bmi.bmiHeader.biClrUsed := 0;

  bmi.bmiHeader.biCompression := BI_RGB;
  bmi.bmiHeader.biSizeImage := ((bmi.bmiHeader.biWidth * cClrBits + 31) and (not 31)) div 8
      * bmi.bmiHeader.biHeight;
  bmi.bmiHeader.biClrImportant := 0;
  Result := bmi;
end;

procedure SavetagBitmapAsDIBToStream(const ABitmap: PBitmap; AStream: TStream);
var
  pbi: TBitmapInfo;
  lHDC: HDC;
  pbih: BITMAPINFOHEADER ;
  hdr: BITMAPFILEHEADER;
  lpBits: PByte;
  hBMP: HBITMAP;
begin
  pbi := CreateBitmapInfoStruct(ABitmap);
  lHDC := CreateCompatibleDC(0);
  GetMem(lpBits, pbih.biSizeImage);
  hBmp := CreateBitmapIndirect(ABitmap^);
  try
    pbih := pbi.bmiHeader;
    GetDIBits(lHDC, hBMP, 0, pbih.biHeight, lpBits, pbi, DIB_RGB_COLORS);
    hdr.bfType := $4d42;
    hdr.bfSize := sizeof(BITMAPFILEHEADER) + pbih.biSize + pbih.biClrUsed
          * sizeof(RGBQUAD) + pbih.biSizeImage;
    hdr.bfReserved1 := 0;
    hdr.bfReserved2 := 0;
    hdr.bfOffBits := sizeof(BITMAPFILEHEADER) +
        pbih.biSize + pbih.biClrUsed
        * sizeof (RGBQUAD);

    AStream.Write(hdr, SizeOf(BITMAPFILEHEADER));
    AStream.Write(pbih, SizeOf(BITMAPINFOHEADER) + pbih.biClrUsed * SizeOf(RGBQUAD));
    AStream.Write(lpBits^, pbih.biSizeImage);
  finally
    FreeMem(lpBits);
    DeleteObject(hBMP);
    ReleaseDC(0, lHDC);
  end;
end;

Спасибо Реми за помощь и спасибо за отрицательный ответ на мой вопрос. Держи их наливая!:)

Используйте Win32 API CreateBitmapIndirect() функция для создания DDB HBITMAP справиться с вашим tagBITMAP структура, а затем назначить, что HBITMAP к Handle свойство VCL TBitmap объект и сохранить объект в свой TStream (это сохранит как DIB).

uses
  Winapi.Windows, Vcl.Graphics;

procedure SavetagBitmapAsDIBToStream(const ABitmap: PBitmap; var AStream: TStream);
var
  Bmp: Vcl.Graphics.TBitmap;
begin
  Bmp := Vcl.Graphics.TBitmap.Create;
  try
    Bmp.Handle := CreateBitmapIndirect(ABitmap);
    Bmp.HandleType := bmDIB; // optional
    Bmp.SaveToStream(AStream);
  finally
    Bmp.Free;
  end;
end;
Другие вопросы по тегам