我真的需要能夠創建一個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