Sự cố có thể là PNG đã chuyển đổi thành TBitmap32 không chính xác, mất thông tin trong suốt khi chuyển tiếp. Nó là một trường hợp phổ biến với hình ảnh PNG paletted. Nếu không, bạn sẽ không phải sử dụng „Bitmap.DrawMode: = dmTransparent” và „OuterColor”. Nếu thông tin transparencry từ PNG sẽ được chuyển đúng vào TBitmpa32, DrawMode: = dmBlend sẽ làm việc, mà không cần phải đặt OuterColor.
Điều quan trọng nhất là cách bạn tải PNG vào TBitmap32. TPngImage từ Vcl.Imaging.đơn vị pngimage (được triển khai trong Delphi XE2 và sau này) có thể vẽ một cách rõ ràng trên bitmap, bảo toàn những gì trên bitmap đó, kết hợp màu sắc bằng cách sử dụng lớp alpha alpha, v.v.) vào thành phần alpha của mỗi pixel của TBitmap32. Khi TPngImage đã vẽ một hình ảnh, bạn nhận được RGB kết hợp cho mỗi pixel, nhưng thành phần alpha không được chuyển sang bitmap đích.
Có thói quen helper sẵn mà cố gắng để tải một PNG vào một TBitmap32 với tính minh bạch, nhưng họ có nhiều nhược điểm:
(1) “LoadPNGintoBitmap32” từ http://graphics32.org/wiki/FAQ/ImageFormatRelated - nó áp dụng tính minh bạch hai lần, vì vậy những hình ảnh với giá trị alpha khác 0 hoặc 255 sẽ khác với các phần mềm khác (đáng chú ý nhất trên hình ảnh mờ với hiệu ứng kính). Trước tiên, mã này sẽ áp dụng alpha thành RGB và sau đó đặt alpha làm lớp riêng biệt, vì vậy khi bạn vẽ, alpha sẽ được áp dụng lại. Bạn có thể tìm thêm thông tin về vấn đề này tại đây: Delphi, GR32 + PngObject: converting to Bitmap32 doesn't work as expected . Bên cạnh đó, nó không chuyển đổi một cách chính xác độ trong suốt từ các hình ảnh được paletted thành lớp alpha của TBitmap32. Chúng tự thiết lập độ trong suốt cho các pixel của một màu nhất định của bitmap đầu ra (được render thành RGB) thay vì làm trước khi render sang RGB, vì vậy độ trong suốt thực sự bị mất như trên ảnh mẫu của bạn khi tất cả các pixel trắng trong suốt.
(2) “LoadBitmap32FromPNG” từ thư viện gr32ex: https://code.google.com/archive/p/gr32ex/ - triển khai hơi khác cùng một thuật toán như (1) và có cùng vấn đề với (1).
Vì vậy, giải pháp là:
- Không sử dụng TBitmap32; sử dụng Vcl.Imaging.pngimage.TPngImage vẽ trực tiếp trên bitmap đích (màn hình, vv) - đây là cách tương thích nhất để giao dịch chính xác với các định dạng PNG khác nhau.
- Sử dụng định tuyến trợ giúp để chuyển thông tin minh bạch từ Vcl.Imaging.pngimage.TPngImage sang TBitmap32.
- Sử dụng thư viện PNG GR32 có thể tải một PNG vào TBitmap32 https://sourceforge.net/projects/gr32pnglibrary/ Vì bây giờ bạn có tất cả thông tin về vấn đề này, bạn có thể nhận được giải pháp phù hợp với mình.
Làm thế nào để tải các lớp alpha trong một đường chuyền
Heinrich Ulbricht làm một gợi ý tốt đẹp để loại bỏ các lớp minh bạch trước paining và sau đó để đọc hình ảnh một lần nữa. Để tránh tải hình ảnh hai lần, bạn có thể lưu lớp alpha trước khi gọi PNGObject.RemoveTransparency. Đây là mã áp dụng chính xác lớp alpha và chỉ tải hình ảnh một lần. Thật không may, nó không hoạt động với hình ảnh paletted. Nếu bạn biết cách điền chính xác lớp alpha của TBitmap32 từ bất kỳ hình ảnh paletted nào, mà không có các hiệu ứng được mô tả tại Transparent Png to TBitmap32 hãy cho tôi biết.
procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32; SrcStream: TStream; out AlphaChannelUsed: Boolean);
var
PNGObject: TPngImage;
PixelPtr: PColor32;
AlphaPtr: PByte;
SaveAlpha: PByte;
I, AlphaSize: Integer;
begin
AlphaChannelUsed := False;
PNGObject := TPngImage.Create;
try
PNGObject.LoadFromStream(SrcStream);
AlphaPtr := PByte(PNGObject.AlphaScanline[0]);
if Assigned(AlphaPtr) then
begin
AlphaSize := PNGObject.Width * PNGObject.Height;
if AlphaSize <= 0 then raise Exception.Create('PNG files with zero dimensions are not supported to be loaded to TBitmap32');
GetMem(SaveAlpha, AlphaSize);
try
Move(AlphaPtr^, SaveAlpha^, AlphaSize);
PNGObject.RemoveTransparency;
DstBitmap.Assign(PNGObject);
DstBitmap.ResetAlpha;
PixelPtr := PColor32(@DstBitmap.Bits[0]);
AlphaPtr := SaveAlpha;
for I := 0 to AlphaSize-1 do
begin
PixelPtr^ := (PixelPtr^ and $00FFFFFF) or (TColor32(AlphaPtr^) shl 24);
Inc(PixelPtr);
Inc(AlphaPtr);
end;
finally
FreeMem(SaveAlpha, AlphaSize);
end;
AlphaChannelUsed := True;
end else
if PNGObject.TransparencyMode = ptmNone then
begin
DstBitmap.Assign(PNGObject);
end else
begin
raise Exception.Create('Paletted PNG images are not supported in LoadPNGintoBitmap32, transparency cannot be stored to TBitmap32');
end;
finally
FreeAndNil(PNGObject);
end;
end;
Tôi cho rằng đó là do "độ mờ", bạn cũng đã đặt "tmp.DrawMode: = dmBlend;", tôi chưa sử dụng GR32, nhưng tôi đoán rằng sự khác biệt là do độ mờ. – ComputerSaysNo
@Dorin Duminica, không phải vậy. Ví dụ trên trang web của họ cho thấy rằng chế độ sẽ là dmBlend nếu có bất kỳ sự minh bạch nào trong hình ảnh PNG được tải. Vì tôi biết tất cả hình ảnh của tôi đều trong suốt nên tôi không phải kiểm tra. – migajek