Проблема может заключаться в том, что PNG неправильно преобразован в TBitmap32, теряя информацию о прозрачности при передаче.Это частый случай с PNG-изображениями с палитрой.В противном случае вам не пришлось бы использовать «Bitmap.DrawMode: = dmTransparent» и «OuterColor».Если бы информация о прозрачности из PNG была бы правильно передана в TBitmpa32, DrawMode: = dmBlend сработал бы, не устанавливая OuterColor.
Самое важное, как вы загрузили PNG в TBitmap32.TPngImage из модуля Vcl.Imaging.pngimage (реализованный в Delphi XE2 и более поздних версиях) может рисовать прозрачно на растровых изображениях, сохраняя то, что было на этих растровых изображениях, комбинируя цвета с использованием альфа-слоя PNG и т. Д., Но не позволяет легко преобразовывать различныеформаты прозрачности PNG (включая палитру) в альфа-компонент каждого пикселя TBitmap32.После того, как TPngImage нарисовал изображение, вы получаете объединенный RGB для каждого пикселя, но альфа-компонент не переносится в целевое растровое изображение.
Доступны вспомогательные процедуры, которые пытаются загрузить PNG в TBitmap32 с прозрачностью, но у них есть недостатки:
(1) «LoadPNGintoBitmap32» из http://graphics32.org/wiki/FAQ/ImageFormatRelated - он применяет прозрачность дважды, поэтому изображения с альфа-значениями, отличными от 0 или 255, будут выглядеть иначе, чем в других программах.(наиболее заметно на полупрозрачных изображениях со стеклянными эффектами).Этот код сначала применяет альфа к RGB, а затем устанавливает альфа как отдельный слой, поэтому при рисовании альфа будет применена снова.Вы можете найти более подробную информацию по этому вопросу здесь: Delphi, GR32 + PngObject: преобразование в Bitmap32 не работает должным образом .Кроме того, он неправильно конвертирует прозрачность из палитровых изображений в альфа-слой TBitmap32.Они вручную устанавливают альфа-прозрачность для пикселей определенного цвета выходного растрового изображения (отрисованного в RGB), делая это до рендеринга в RGB, поэтому фактическая прозрачность теряется, как на образце изображения, когда все белые пиксели прозрачны.
(2) «LoadBitmap32FromPNG» из библиотеки gr32ex: https://code.google.com/archive/p/gr32ex/ - немного отличающаяся реализация того же алгоритма, что и (1), и имеет те же проблемы, что и (1).
Итак, решения следующие:
- Не использовать TBitmap32;используйте Vcl.Imaging.pngimage.TPngImage для рисования непосредственно на целевом растровом изображении (экране и т. д.) - это наиболее совместимый способ, который корректно работает с различными форматами PNG.
- Использование вспомогательной маршрутизации для передачи информации о прозрачности изVcl.Imaging.pngimage.TPngImage to TBitmap32.
- Используйте библиотеку GR32 PNG, которая может загружать PNG-файл в TBitmap32 https://sourceforge.net/projects/gr32pnglibrary/, так как теперь у вас есть вся информация по этому вопросу, вы можете получитьправильное решение для вас.
Как загрузить альфа-слой за один проход
Генрих Ульбрихт сделал хорошее предложение удалить слой прозрачности перед нанесением краски, а затем снова прочитать изображение.Чтобы избежать двойной загрузки изображения, вы можете сохранить альфа-слой перед вызовом PNGObject.RemoveTransparency.Вот код, который правильно применяет альфа-слой и загружает изображение только один раз.К сожалению, он не работает с палитры изображений.Если вы знаете, как правильно заполнить альфа-слой TBitmap32 из любого изображения с палитрой, без эффектов, описанных в Прозрачный Png to TBitmap32 , пожалуйста, дайте мне знать.
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;