我真的需要能够创建一个32位RGBA格式的任意大小的完全透明(和空白/空白)TBitmap。多次。 Lazarus能够将这样的位图加载到TBitmap中,并且在加载后,您可以使用scanline处理它,并且不使用RGBA格式。但是,当你自己创建TBitmap时,它不起作用。像素格式似乎完全被忽略。所以我所做的是非常现成的,而且很简单,它几乎是AMUZING(!)。但它是实用的,超级好,并且完全独立于LCL和任何第三方库。即使不依赖Graphics单元,因为它会生成实际的32位RGBA BMP文件(我将它生成为TMemoryStream,您可以生成不同的文件)。然后,一旦拥有它,在代码中的其他地方,您可以使用TBitmap.LoadFrom源代码或TPicture.LoadFrom源代码加载它。
故事背景 我最初想生成以下格式正确格式的BMP文件,如下所述:http://www.fileformat.info/format/bmp/egff.htm 但也有BMP格式的几个变种,我并不清楚哪一个,我应该遵循。所以我决定采用逆向工程方法,但格式描述后来对我有所帮助。我使用了图形编辑器(我使用GIMP)来创建一个空的1x1像素32 RGBA BMP文件,并将其命名为alpha1p.bmp,它只包含透明度。 然后我将画布大小调整为10x10像素,并保存为alpha10p。bmp文件。 然后我比较了两个文件: compating two bmp files in vbindiff on Ubuntu 所以我发现唯一的区别是添加的像素(每个都是4个字节全零RGBA),并且在头部还有其他几个字节。由于链接的I共享的格式文档,我发现它们是:FileSize
(以字节为单位),BitmapWidth
(以像素为单位),BitmapHeight
(以像素为单位)和BitmapDataSize
(以字节为单位)。最后一个是BitmapWidth*BitmapHeight*4
,因为RGBA中的每个像素都是4个字节。所以现在,我可以生成alpha1p.bmp文件中看到的整个字节序列,从结尾减去4个字节(BitmapData
的第1个字节),然后为每个像素的RGBA数据添加4个字节(全零) BMP我想要生成,然后回到初始序列并更新可变部分:文件大小,宽度,高度和BMP数据大小。它的工作完美无瑕!我只需要为BigEndian添加测试,并在写入之前交换单词和双字数字。这将成为在BigEndian工作的ARM平台的问题。
代码
const
C_BLANK_ALPHA_BMP32_PREFIX : array[0..137]of byte
= ($42, $4D, $00, $00, $00, $00, $00, $00, $00, $00, $8A, $00, $00, $00, $7C, $00,
$00, $00, $0A, $00, $00, $00, $0A, $00, $00, $00, $01, $00, $20, $00, $03, $00,
$00, $00, $90, $01, $00, $00, $13, $0B, $00, $00, $13, $0B, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $FF,
$00, $00, $FF, $00, $00, $00, $42, $47, $52, $73, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $02, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00);
(...)
Function RenderEmptyAlphaBitmap(AWidth,AHeight: integer): TMemoryStream;
var
buf : array[1..4096]of byte;
i,p : int64;
w : word;
dw : dword;
BE : Boolean;
begin
buf[low(buf)] := $00; //this is jyst to prevent compiler warning about not initializing buf variable
Result := TMemoryStream.Create;
if(AWidth <1)then AWidth := 1;
if(AHeight<1)then AHeight := 1;
//Write File Header:
Result.Write(C_BLANK_ALPHA_BMP32_PREFIX, SizeOf(C_BLANK_ALPHA_BMP32_PREFIX));
//Now start writing the pixels:
FillChar(buf[Low(buf)],Length(buf),$00);
p := Result.Position;
Result.Size := Result.Size+int64(AWidth)*int64(AHeight)*4;
Result.Position := p;
i := int64(AWidth)*int64(AHeight)*4; //4 because RGBA has 4 bytes
while(i>0)do
begin
if(i>Length(buf))
then w := Length(buf)
else w := i;
Result.Write(buf[Low(buf)], w);
dec(i,w);
end;
//Go back to the original header and update FileSize, Width, Height, and offset fields:
BE := IsBigEndian;
Result.Position := 2; dw := Result.Size;
if BE then SwapEndian(dw); Result.Write(dw, SizeOf(dw));
Result.Position := 18; dw := AWidth;
if BE then SwapEndian(dw); Result.Write(dw, SizeOf(dw));
Result.Position := 22; dw := AHeight;
if BE then SwapEndian(dw); Result.Write(dw, SizeOf(dw));
Result.Position := 34; dw := AWidth*AHeight*4;
if BE then SwapEndian(dw); Result.Write(dw, SizeOf(dw));
//Done:
Result.Position := 0;
end;
注意C_BLANK_ALPHA_BMP32_PREFIX
常数如何基本上是字节序列从我的样本alpha1p.bmp文件副本,减去最后4个字节,这是RGBA的像素。 :d
而且,我使用IsBigEndian
函数是这样的:
Function IsBigEndian: Boolean;
type
Q = record case Boolean of
True : (i: Integer);
False : (p: array[1..4] of Byte);
end;
var
x : ^Q;
begin
New(x);
x^.i := 5;
Result := (x^.p[4]=5);
Dispose(x);
end;
这是自拉撒路维基复制:http://wiki.freepascal.org/Writing_portable_code_regarding_the_processor_architecture你可以跳过这一部分,如果你不与大尾端平台交易,或者你可以使用编译器IFDEF指令。问题是,如果你使用{$IFDEF ENDIAN_BIG}
那么编译器就是这样,而函数实际上是测试系统。这在链接的wiki中有解释。
使用范例
Procedure TForm1.Button1Click(Sender: TObject);
var
MS : TMemoryStream;
begin
MS := RenderEmptyAlphaBitmap(Image1.Width, Image1.Height);
try
if Assigned(MS)then Image1.Picture.LoadFromStream(MS);
//you can also MS.SaveToFile('my_file.bmp'); if you want
finally
FreeAndNil(MS);
end;
end;
如果你遵循会发生什么[这](http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Graphics_TBitmap_TransparentMode.html )例子? –
你只想画什么?你想要一个完整的透明位图绘制? – Shambhala
@尚巴拉不,我想画一个(小)部分。 – NGLN