Delphi 为什么';这段D2006代码是不是可以使PNG图像褪色?

Delphi 为什么';这段D2006代码是不是可以使PNG图像褪色?,delphi,png,alphablending,delphi-2006,timage,Delphi,Png,Alphablending,Delphi 2006,Timage,这个问题源于前面的一个问题。大部分代码来自于建议的答案,这些答案可能在以后的Delphi版本中有效。在D2006中,我没有得到完整的不透明度范围,图像的透明部分显示为白色 图像来自。 它在运行时从PNGImageCollection加载到TImage中,因为我发现您必须这样做,因为保存DFM后图像不会保持完整。为了演示这种行为,您可能不需要PNGImageCollection,只需在设计时将PNG图像加载到TImage中,然后从IDE运行它即可 表单上有四个按钮-每个按钮设置不同的不透明度值。不

这个问题源于前面的一个问题。大部分代码来自于建议的答案,这些答案可能在以后的Delphi版本中有效。在D2006中,我没有得到完整的不透明度范围,图像的透明部分显示为白色

图像来自。
它在运行时从PNGImageCollection加载到TImage中,因为我发现您必须这样做,因为保存DFM后图像不会保持完整。为了演示这种行为,您可能不需要PNGImageCollection,只需在设计时将PNG图像加载到TImage中,然后从IDE运行它即可

表单上有四个按钮-每个按钮设置不同的不透明度值。不透明度=0可以正常工作(paintbox图像不可见,不透明度=16看起来正常,除了白色背景,不透明度=64,255相似-不透明度似乎在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.
**此代码(使用图形32 TImage32)几乎可以正常工作**

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.
**(更新)此代码(使用图形32 TImage32)不起作用**

以下代码在运行时成功地将PNG图像分配给Graphics32.TImage32。带有alpha通道的PNG图像加载到TPNGImageCollection(非常有用的组件,因为它允许任意大小的图像混合)在设计时。在表单创建时,它被写入流,然后使用从流读取到Image32。完成后,我可以通过指定TImage32.Bitmap.MasterAlpha来控制不透明度。无需使用OnPaint处理程序

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

但是png对象知道如何在画布上绘制透明度信息。因此解决方案将涉及在位图画布上绘制而不是指定图形,然后,由于没有Alpha通道,从
BLENDFUNCTION
中删除
AC\u SRC\u Alpha
标志

以下是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;

我认为透明度在调用TBitmap.Assign时丢失了。我正在研究如何修复这一问题,这将涉及直接操作Windows API函数。我使用的是D6的副本。实际上,在我在D6中运行的代码中,也使用Gustavo Daud的PNG单元,我认为透明度在PNG级别没有得到正确处理。我将现在尝试另一种方法,使用具有部分透明度的.ico文件,因为我确信它们工作正常!好吧,我放弃。我不相信这些旧版本的Delphi的Graphics.pas正确地支持部分透明度和alpha通道。如果你想用这些工具实现这一点,那么你需要做大量低级别的Win API工作。你的PNG ima据我所知,ge unit也不支持部分透明。我认为是时候升级到XE!+1了。我为旧Delphi提供的PNG代码不支持部分透明,因此avenue注定要失败。我真的很讨厌CodeGear接管此代码时所做的事——试图拒绝旧版本用户使用PNG的能力糟糕的公关@Sertac,@David谢谢你。我明天(凌晨3点)会在D2006下试一试.同时,我编辑了这个问题-使用TImage32似乎可行,除了当我在设计时将PNG加载到TImage32中时,我无法使alpha通道工作-图像的背景是黑色的,不是透明的。我可以通过将相同的图像加载到apha通道中使其工作,但我确实需要创建从图像中删除一个遮罩,这样图像的三角形部分可以有100%的不透明度。如何自动做到这一点?@用户放弃在设计时加载它。使用资源并在运行时执行。@用户注意,您可以向上投票,也可以接受!@Sertac derserves the rep!!;-)谢谢@David:)关于你的第一个评论,我从来不知道是这样的。如果有人需要,它有最新版本(支持部分透明)。