绘制透明缩放的PNG图片

3

我有一张大的PNG图片(300x300px),需要重新调整大小。在SO问题中,我了解到可以使用StretchBltHALFTONE以获得更好的缩放效果。

我的问题是如何绘制透明的PNG图像,或者至少将黑色角落涂成白色?

enter image description here

正如您在附加的图像中看到的那样,我得到了黑色的角落。

这是原始图像:enter image description here 这是我迄今为止尝试过的方法。

unit MainU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TFormMain = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;

implementation

{$R *.dfm}
uses
  Pngimage;

type
  TIRButton = class(TImage)
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TGraphicControlAcess = class(TGraphicControl);
  TGraphicAcess = class(TGraphic);

  THalfTonePngImage = class(TPngImage)
  protected
    procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
  end;

  { TIRButton }

constructor TIRButton.Create(AOwner: TComponent);
begin
  inherited;
  Center := True;
  Proportional := True;
end;

procedure TIRButton.Paint;
var
  ParentCanvas: TCanvas;
begin
  ParentCanvas := TGraphicControlAcess(Self).Canvas;
  TGraphicAcess(Picture.Graphic).Draw(ParentCanvas, DestRect);
end;

{ THalfTonePngImage }

procedure THalfTonePngImage.Draw(ACanvas: TCanvas; const Rect: TRect);
var
  p: TPoint;
  dc: HDC;
begin
  dc := ACanvas.Handle;
  GetBrushOrgEx(dc, p);
  SetStretchBltMode(dc, HALFTONE);
  SetBrushOrgEx(dc, p.X, p.Y, @p);

  ACanvas.Brush.Color := clWhite;
  ACanvas.FillRect(Classes.Rect(0, 0, Width, Height));

  StretchBlt(
    dc, 0, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top,
    Canvas.Handle, 0, 0, Width, Height, ACanvas.CopyMode
    );
end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  Image: THalfTonePngImage;
begin
  Image := THalfTonePngImage.Create;
  Image.LoadFromFile('X200IR_11_EmgBrake.png');

  with TIRButton.Create(Self) do
  begin
    Width := 100;
    Height := 100;
    Picture.Assign(Image);
    Parent := Self;
    Anchors := [akLeft, akTop, akRight, akBottom];
  end;

  Image.Free;
end;

end.

1
你想让整个图像透明,还是“不绘制角落”?后者会有问题,因为它们是黑色的,我想,“绘制白色中所有的黑色”虽然可以做到这一点,但并不是你要寻找的解决方案。你需要一个覆盖角落的遮罩。实际上,最简单的方法是在图像编辑器中打开图像来摆脱角落。 - Jongware
最好是将角落变成透明的,如果难以实现,则将角落变成白色。 - Jens Borrisholt
1
这张图片是当前的屏幕截图。你能否也展示原始图片?如果你无法编辑原始图片,你能否使用另一张图片作为遮罩? - Jongware
这是我今天得到的屏幕截图。是的,我可以使用另一张图片作为遮罩。我会添加原始图片。 - Jens Borrisholt
1
首先,我建议您从TGraphicControl(而不是TImage)派生TIRButton,它已经公开了Canvas并适用于此类控件。其次,我认为TPngImage应该通过.Draw(ACanvas: TCanvas; const Rect: TRect)设计支持绘制缩放的透明PNG。至少“旧版”TPngObject支持它... - kobik
谢谢你的建议@kobik,但我需要按照自己的方式绘制PNGImage,否则它不会很好地重新缩放。关于从TGraphicControl派生,你说得对。 - Jens Borrisholt
1个回答

2
源图像的角落是透明的。在正确的图像中,由于有白色背景,所以不可见。StretchBlt不支持透明度。因为它不支持,透明像素与黑色像素无法区分。(如果ARGB颜色是FF 00 00 00并且我们移除了alpha通道,我们就会得到00 00 00)。你需要使用TransparentBlt
供参考,这是将图像放在绿色背景上时的图像。这样更容易看到透明度。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接