Как сохранить 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;