Tôi thực sự cần thiết để có thể tạo một TBitmap hoàn toàn minh bạch (và nếu không trống/trống) có kích thước tùy ý ở định dạng 32 bit RGBA. Nhiều lần. Lazarus có thể tải bitmap như vậy vào TBitmap và sau khi nó được tải, bạn có thể thao tác nó với scanline và những gì không sử dụng định dạng RGBA. Nhưng nó không hoạt động khi bạn tạo bản thân TBitmap. Định dạng pixel dường như bị bỏ qua hoàn toàn. Vì vậy, những gì tôi đã làm là như vậy out-of-the box, và đơn giản, rằng nó gần như AMUZING (!). Nhưng nó là thực tế, hoạt động siêu đẹp, và hoàn toàn độc lập với LCL và bất kỳ thư viện của bên thứ ba nào. Thậm chí không phụ thuộc vào đơn vị đồ họa, bởi vì nó tạo ra các tập tin 32 bit RGBA BMP thực tế (tôi tạo ra nó để TMemoryStream, bạn có thể tạo ra một cách khác nhau). Sau đó, một khi bạn có nó, ở nơi khác trong mã của bạn, bạn chỉ có thể tải nó bằng cách sử dụng nguồn TBitmap.LoadFrom nguồn hoặc TPicture.LoadFrom.
Câu chuyện nền ban đầu tôi muốn tạo ra định dạng đúng tập tin BMP sau định dạng như mô tả ở đây: http://www.fileformat.info/format/bmp/egff.htm Nhưng có vài biến thể của định dạng BMP, và tôi đã không rõ ràng về cái nào tôi phải làm theo . Vì vậy, tôi quyết định đi với một cách tiếp cận kỹ thuật đảo ngược, nhưng mô tả định dạng đã giúp tôi sau này. Tôi đã sử dụng một trình soạn thảo đồ họa (tôi đã sử dụng GIMP) để tạo một tệp ảnh RGB1 32 RGBA BMP trống rỗng, và được gọi là alpha1p.bmp, nó chỉ chứa trong suốt không có gì khác. Sau đó, tôi đã đổi kích thước canvas thành 10x10 pixel và được lưu dưới dạng alpha10p.tệp bmp. Sau đó, tôi so sánh hai tệp: compating two bmp files in vbindiff on Ubuntu Vì vậy, tôi phát hiện ra rằng sự khác biệt duy nhất là pixel được thêm (mỗi pixel là 4 byte tất cả các số không RGBA) và một vài byte khác trong tiêu đề. Bởi vì các tài liệu định dạng tại liên kết tôi chia sẻ, tôi đã tìm ra rằng đó là: FileSize
(theo byte), BitmapWidth
(tính bằng pixel), BitmapHeight
(tính bằng pixel) và BitmapDataSize
(theo byte). Cái cuối cùng là BitmapWidth*BitmapHeight*4
, bởi vì mỗi pixel trong RGBA là 4 byte. Vì vậy, bây giờ, tôi chỉ có thể tạo ra rằng toàn bộ chuỗi các byte như đã thấy bên trong alpha1p.bmp file, trừ đi 4 byte từ ngày kết thúc (ngày 1 của BitmapData
), sau đó thêm 4 byte (tất cả zero) của dữ liệu RGBA cho mỗi điểm ảnh của BMP Tôi muốn tạo ra, sau đó quay trở lại trình tự ban đầu và cập nhật các phần biến: FileSize, chiều rộng, chiều cao và kích thước dữ liệu BMP. Và nó hoạt động hoàn hảo! Tôi chỉ cần thêm bài kiểm tra cho BigEndian và sẽ đổi số từ và dword trước khi viết. Điều đó sẽ trở thành vấn đề trên nền tảng ARM hoạt động trong BigEndian.
Mã
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;
Chú ý cách C_BLANK_ALPHA_BMP32_PREFIX
liên tục về cơ bản là bản sao của chuỗi byte từ file mẫu alpha1p.bmp của tôi, trừ đi 4 byte cuối cùng, đó là những điểm ảnh RGBA. : D
Ngoài ra, tôi đang sử dụng IsBigEndian
chức năng mà đi như thế này:
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;
này được sao chép từ Lazarus Wiki: http://wiki.freepascal.org/Writing_portable_code_regarding_the_processor_architecture bạn có thể bỏ qua phần này nếu bạn không đối phó với các nền tảng BigEndian, hoặc bạn có thể sử dụng một trình biên dịch IFDEF chỉ thị. Cái này là nếu bạn sử dụng {$IFDEF ENDIAN_BIG}
sau đó nó là những gì trình biên dịch mọi thứ là trường hợp, trong khi chức năng thực sự kiểm tra hệ thống. Điều này được giải thích trong wiki được liên kết.
sử dụng mẫu
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;
gì sẽ xảy ra nếu bạn làm theo [này] (http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Graphics_TBitmap_TransparentMode.html) thí dụ ? –
Bạn có muốn vẽ gì không? Bạn có muốn một Bitmap trong suốt hoàn chỉnh được vẽ không? – Shambhala
@Shamballa Không, tôi muốn vẽ một phần nhỏ. – NGLN