Delphi 2006: Run-time assignment of PNG to TImage loses alpha transparency
Delphi 2006's TImage doesn't quit开发者_如何学运维e support PNGs. In order to have images with alpha transparency on my forms I have to load them at run-time. I can load them at design time but they don't survive, I think because PNGs are not saved in the DFM file. I'm sure this is all hunky-dory in the latest Delphi but I can't upgrade right at the moment.
Anyway, I was loading them at run-time with:
Image1.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ;
The PNGImageCollection component holds all my PNGs of various sizes (these are created and loaded at design-time), and I assign them to the respective TImages in the FormCreate event.
This has worked OK, until I had a problem where I was trying to reuse one of these images somewhere else after it had been used on a form. I discovered that the act of assigning the TPicture had set it to an empty image as a result of the Assign. This was happening in the routine TPicture.ForceType, which AFAICT checks the type of FGraphic, and if it is not the desired type, it frees FGraphic and creates a new instance of the requested type.
OK. So after a bit of scratching around, I see that maybe I should really be doing this:
Image1.Picture.Bitmap.Assign (PngImageCollection1.Items [0].PNGImage) ;
This did the trick, in that the Assign did not clobber the image, but the image now shows with the semi-transparent bits as opaque, i.e.:
instead of:
How can I get this image to display the alpha-transparent bits properly? (and supplementary question: Is Image1.Picture.Bitmap.Assign the correct way to do it?).
Here's the code in a bit more detail:
In the code where I had the problem "reusing" a TImage, the sequence was:
On form create:LogoImage.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ;
(PNGIMage is a company logo, LogoImage1 is on the main form).
On print report header:
procedure PrintLogo (Report : TBaseReport) ;
var
X1, Y1, LogoHeightMM : Double ;
begin
with Report do
begin
LogoHeightMM := CalcGraphicHeight (LogoWidthMM, MainForm.LogoImage.Picture.Graphic) ;
X1 := PageWidth - MarginRight - LogoWidthMM ;
Y1 := SectionBottom - LogoHeightMM ;
PrintBitmapRect (X1, Y1, X1 + LogoWidthMM, Y1 + LogoHeightMM, MainForm.LogoImage.Picture.Bitmap) ;
end ;
end ;
The first time the routine to print the logo is called it executes without error, but the LogoImage .Picture is left cleared after the call to PrintBitmapRect. The next time the print header routine is called, the call to CalcGraphicHeight fails because the width and height of the image are zero.
Changing the Picture.Assign to a Picture.Bitmap.Assign fixes the RTE in the header print routine, but when I transplanted the same "fix" to other static images assigned from PNGs (like the gears above) I lost the aplha channel.
You're not showing the really relevant part of your code: how are you re-using the image that would cause it to have a particular type.
When you assign a TImage a TPngObject, the graphic of the image holds a png object. Only when you request specifically a bitmap, it will force its graphic to be of a bitmap type. For instance, this,
Bmp.Assign(Image1.Picture.Bitmap);
will force Image1 to have a bitmap graphic, if its graphic was a png object it will be freed. While this,
Bmp.Assign(Image1.Picture.Graphic);
will not force Image1 to have a bitmap graphic, the png object will carry out the assignment and stay there.
Delphi's bitmaps (at least up to recent versions), do not support alpha-channels, so you shouldn't be using Image1.Picture.Bitmap.Assign(..
for partially transparent images.
BTW, instead of re-using the graphic in the image, you could probably use the image in your png image collection as the source..
精彩评论