Il problema potrebbe essere che il PNG è stato convertito in modo errato in TBitmap32, perdendo le informazioni sulla trasparenza in transito. È un caso comune con immagini PNG con tavolozza. Altrimenti, non avresti dovuto usare "Bitmap.DrawMode: = dmTransparent" e "OuterColor". Se le informazioni in trasparenza da PNG fossero state trasferite correttamente in TBitmpa32, DrawMode: = dmBlend avrebbe funzionato, senza la necessità di impostare OuterColor.
Ciò che importa di più è come è stato caricato un PNG in TBitmap32. L'immagine TPng da Vcl.Imaging.L'unità pngimage (implementata in Delphi XE2 e versioni successive) può disegnare in modo trasparente su bitmap, preservando ciò che era presente in quei bitmap, combinando i colori usando il PNG alpha layer, ecc., ma non consente di convertire facilmente vari formati di trasparenza PNG (inclusi palettizzati) nel componente alfa di ciascun pixel di TBitmap32. Una volta che TPngImage ha disegnato un'immagine, si ottiene l'RGB combinato per ciascun pixel, ma il componente alfa non viene trasferito alla bitmap di destinazione.
Ci sono routine di supporto disponibili che tentano di caricare un PNG in un TBitmap32 con trasparenza, ma hanno svantaggi:
(1) “LoadPNGintoBitmap32” da http://graphics32.org/wiki/FAQ/ImageFormatRelated - si applica la trasparenza per due volte, in modo che le immagini con i valori alfa diversi da 0 o 255 appariranno in modo diverso rispetto ad altri software (il più evidente su immagini traslucide con effetti di vetro). Questo codice applicherà dapprima alpha a RGB e quindi imposta alpha come layer separato, quindi quando dipingi, alpha verrà nuovamente applicato. È possibile trovare ulteriori informazioni su questo problema qui: Delphi, GR32 + PngObject: converting to Bitmap32 doesn't work as expected . Oltre a ciò, non converte correttamente la trasparenza dalle immagini con tavolozza nello strato alfa di TBitmap32. Impostano manualmente la trasparenza alfa per i pixel di un determinato colore della bitmap di output (renderizzata in RGB) piuttosto che prima di renderizzare in RGB, quindi la trasparenza effettiva viene persa come nell'immagine di esempio quando tutti i pixel bianchi sono trasparenti.
(2) “LoadBitmap32FromPNG” dalla libreria gr32ex: https://code.google.com/archive/p/gr32ex/ - un po 'diversa attuazione lo stesso algoritmo (1), ed ha gli stessi problemi (1).
Quindi, le soluzioni sono:
- Non utilizzare TBitmap32; usa Vcl.Imaging.pngimage.TPngImage per disegnare direttamente su bitmap di destinazione (schermo, ecc.) - questo è il modo più compatibile per trattare correttamente con vari formati PNG.
- Utilizzare un instradamento di supporto per trasferire informazioni sulla trasparenza da Vcl.Imaging.pngimage.TPngImage a TBitmap32.
- Utilizzare la libreria PNG GR32 in grado di caricare in modo nativo un PNG in TBitmap32 https://sourceforge.net/projects/gr32pnglibrary/ Poiché ora si dispone di tutte le informazioni su questo problema, è possibile ottenere la soluzione giusta per l'utente.
come caricare lo strato alfa in un solo passaggio
Heinrich Ulbricht ha fatto un bel suggerimento per rimuovere lo strato di trasparenza prima di paining e poi a leggere di nuovo l'immagine. Per evitare di caricare l'immagine due volte, è possibile salvare il layer alfa prima di chiamare PNGObject.RemoveTransparency. Ecco il codice che applica correttamente il layer alfa e carica l'immagine solo una volta. Sfortunatamente, non funziona con le immagini a tavolo. Se sai come riempire correttamente lo strato alfa di TBitmap32 da qualsiasi immagine di tavolo, senza gli effetti descritti allo Transparent Png to TBitmap32 per favore fammi sapere.
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;
presumo che è a causa di "opacità", anche tu hai impostato "tmp.DrawMode: = dmBlend;", non ho usato GR32, ma direi che la differenza è dovuta all'opacità. – ComputerSaysNo
@Dorin Duminica, non lo è. L'esempio sul loro sito web mostra che la modalità dovrebbe essere dmBlend se c'è qualche trasparenza nell'immagine PNG caricata. Dal momento che so che tutte le mie immagini sono trasparenti, non devo fare controlli. – migajek