问题描述
这个问题源于一个较早的问题.大多数代码来自可能在更高版本的Delphi中起作用的建议答案.在D2006中,我没有得到全部的不透明度,并且图像的透明部分显示为白色.
This question springs from an earlier one. Most of the code is from suggested answers that probably worked in later versions of Delphi. In D2006 I don't get the full range of opacity, and the transparent part of the image shows as white.
图片来自 http://upload.wikimedia.org/wikipedia /commons/6/61/Icon_attention_s.png .
它在运行时从PNGImageCollection加载到TImage中,因为我发现您必须执行此操作,因为保存DFM后图像不会保持完整.为了演示该行为,您可能不需要PNGImageCollection,而可以在设计时将PNG图像加载到TImage中,然后从IDE中运行它.
Image is from http://upload.wikimedia.org/wikipedia/commons/6/61/Icon_attention_s.png.
It is loaded from the PNGImageCollection into the TImage at run-time because I have found you have to do this as the image doesn't remain intact after the DFM is saved. For the purposes of demonstrating the behaviour you probably don't need the PNGImageCollection and can just load the PNG image into the TImage at design time and then run it from the IDE.
表单上有四个按钮-每个按钮设置不同的不透明度值.不透明度= 0可以正常工作(颜料盒图像不可见,除白色背景外,不透明度= 16看起来还可以,不透明度= 64、255相似-不透明度似乎在10%左右饱和.
There are four buttons on the form - each one sets a different value of opacity. Opacity=0 works fine (paintbox image is not visible, opacity=16 looks OK except for the white background, opacity=64, 255 are similar - the opacity seems to saturate at around 10%.
有什么想法吗?
unit Unit18;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, pngimage, StdCtrls, Spin, PngImageList;
type
TAlphaBlendForm = class(TForm)
PaintBox1: TPaintBox;
Image1: TImage;
PngImageCollection1: TPngImageCollection;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure PaintBox1Paint(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
FOpacity : Integer ;
FBitmap : TBitmap ;
{ Private declarations }
public
{ Public declarations }
end;
var
AlphaBlendForm: TAlphaBlendForm;
implementation
{$R *.dfm}
procedure TAlphaBlendForm.Button1Click(Sender: TObject);
begin
FOpacity:= 0 ;
PaintBox1.Invalidate;
end;
procedure TAlphaBlendForm.Button2Click(Sender: TObject);
begin
FOpacity:= 16 ;
PaintBox1.Invalidate;
end;
procedure TAlphaBlendForm.Button3Click(Sender: TObject);
begin
FOpacity:= 64 ;
PaintBox1.Invalidate;
end;
procedure TAlphaBlendForm.Button4Click(Sender: TObject);
begin
FOpacity:= 255 ;
PaintBox1.Invalidate;
end;
procedure TAlphaBlendForm.FormCreate(Sender: TObject);
begin
Image1.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ;
FBitmap := TBitmap.Create;
FBitmap.Assign(Image1.Picture.Graphic);//Image1 contains a transparent PNG
FBitmap.PixelFormat := pf32bit ;
PaintBox1.Width := FBitmap.Width;
PaintBox1.Height := FBitmap.Height;
end;
procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject);
var
fn: TBlendFunction;
begin
fn.BlendOp := AC_SRC_OVER;
fn.BlendFlags := 0;
fn.SourceConstantAlpha := FOpacity;
fn.AlphaFormat := AC_SRC_ALPHA;
Windows.AlphaBlend(
PaintBox1.Canvas.Handle,
0,
0,
PaintBox1.Width,
PaintBox1.Height,
FBitmap.Canvas.Handle,
0,
0,
FBitmap.Width,
FBitmap.Height,
fn
);
end;
end.
**这段代码(使用graphics32 TImage32)几乎可以工作**
** This code (using graphics32 TImage32) almost works **
unit Unit18;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, pngimage, StdCtrls, Spin, PngImageList, GR32_Image;
type
TAlphaBlendForm = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Image321: TImage32;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
AlphaBlendForm: TAlphaBlendForm;
implementation
{$R *.dfm}
procedure TAlphaBlendForm.Button1Click(Sender: TObject);
begin
Image321.Bitmap.MasterAlpha := 0 ;
end;
procedure TAlphaBlendForm.Button2Click(Sender: TObject);
begin
Image321.Bitmap.MasterAlpha := 16 ;
end;
procedure TAlphaBlendForm.Button3Click(Sender: TObject);
begin
Image321.Bitmap.MasterAlpha := 64 ;
end;
procedure TAlphaBlendForm.Button4Click(Sender: TObject);
begin
Image321.Bitmap.MasterAlpha := 255 ;
end;
end.
**(更新)此代码(使用graphics32 TImage32)有效**
** (UPDATE) This code (using graphics32 TImage32) DOES work **
以下代码在运行时成功将PNG图像分配给Graphics32.TImage32.在设计时,将具有Alpha通道的PNG图像加载到TPNGImageCollection(非常有用的组件,因为它允许混合任意大小的图像).创建表单时,将其写入流,然后使用 LoadPNGintoBitmap32 从流中读取到Image32.完成此操作后,我可以通过分配给TImage32.Bitmap.MasterAlpha来控制不透明度.无需打扰OnPaint处理程序.
The following code is successful in assigning a PNG image to the Graphics32.TImage32 at run-time. The PNG image with alpha channel is loaded into a TPNGImageCollection (really useful component as it allows mixtures of images of arbitrary size) at design time. On form creation it is written to a stream, then read from the stream into the Image32 using LoadPNGintoBitmap32. Once this is done I can control the opacity by assigning to TImage32.Bitmap.MasterAlpha. No bothering with OnPaint handlers.
procedure TAlphaBlendForm.FormCreate(Sender: TObject);
var
FStream : TMemoryStream ;
AlphaChannelUsed : boolean ;
begin
FStream := TMemoryStream.Create ;
try
PngImageCollection1.Items [0].PngImage.SaveToStream (FStream) ;
FStream.Position := 0 ;
LoadPNGintoBitmap32 (Image321.Bitmap, FStream, AlphaChannelUsed) ;
finally
FStream.Free ;
end;
end ;
推荐答案
正如David在回答问题时,将图形分配给位图时,alpha通道信息会丢失.因此,在分配后没有必要将像素格式设置为pf32bit
,除了防止AlphaBlend
调用失败外,位图中也没有按像素的Alpha.
As David commented to the question, the alpha channel information is lost when you assign the graphic to the bitmap. As such there's no point in setting the pixel format to pf32bit
after the assignment, apart from preventing AlphaBlend
call to fail, there's no per-pixel alpha in the bitmap anyway.
但是png对象知道如何在画布上绘制,并且要考虑透明度信息.因此,解决方案将涉及在位图画布上绘制而不是分配图形,然后,由于没有Alpha通道,请从BLENDFUNCTION
中删除AC_SRC_ALPHA
标志.
But the png object knows how to draw on a canvas taking into consideration the transparency information. So the solution would involve drawing on the bitmap canvas instead of assigning the graphic, and then, since there's no Alpha channel, remove the AC_SRC_ALPHA
flag from the BLENDFUNCTION
.
以下是D2007上的工作代码:
Below is working code here on D2007:
procedure TAlphaBlendForm.FormCreate(Sender: TObject);
begin
Image1.Picture.LoadFromFile(
ExtractFilePath(Application.ExeName) + 'Icon_attention_s.png');
FBitmap := TBitmap.Create;
FBitmap.Width := Image1.Picture.Graphic.Width;
FBitmap.Height := Image1.Picture.Graphic.Height;
FBitmap.Canvas.Brush.Color := Color; // background color for the image
FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect);
FBitmap.Canvas.Draw(0, 0, Image1.Picture.Graphic);
PaintBox1.Width := FBitmap.Width;
PaintBox1.Height := FBitmap.Height;
end;
procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject);
var
fn: TBlendFunction;
begin
fn.BlendOp := AC_SRC_OVER;
fn.BlendFlags := 0;
fn.SourceConstantAlpha := FOpacity;
fn.AlphaFormat := 0;
Windows.AlphaBlend(
PaintBox1.Canvas.Handle,
0,
0,
PaintBox1.Width,
PaintBox1.Height,
FBitmap.Canvas.Handle,
0,
0,
FBitmap.Width,
FBitmap.Height,
fn
);
end;
或不使用中间TImage
:
procedure TAlphaBlendForm.FormCreate(Sender: TObject);
var
PNG: TPNGObject;
begin
PNG := TPNGObject.Create;
try
PNG.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Icon_attention_s.png');
FBitmap := TBitmap.Create;
FBitmap.Width := PNG.Width;
FBitmap.Height := PNG.Height;
FBitmap.Canvas.Brush.Color := Color;
FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect);
PNG.Draw(FBitmap.Canvas, FBitmap.Canvas.ClipRect);
PaintBox1.Width := FBitmap.Width;
PaintBox1.Height := FBitmap.Height;
finally
PNG.Free;
end;
end;
这篇关于为什么此D2006代码无法淡入PNG图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!