3

I have a large (300x300px) PNG image which I need to rescale. In an other SO question I read about StretchBlt and HALFTONE in order for better scaling.

My problem is how do I draw the PNG image transparent, or at least paint the black corners white?

enter image description here

As you can see on the attached image I get black corners.

And here is the original image: enter image description here Here is what I've tried so far.

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.
Community
  • 1
  • 1
Jens Borrisholt
  • 6,174
  • 1
  • 33
  • 67
  • 1
    You want the entire image to be transparent, or 'not draw the corners'? The latter would be a problem because they are black, and I suppose while "draw *everything* that is black in white" will do that but is not the solution you are looking for. You would need a mask that covers the corners. Really, easiest way to get rid of the corners is to open the image in an image editor. – Jongware Oct 01 '15 at 08:32
  • Preferable I would like the corners to be transparent, and if thats hard to do then the cornors to be white. – Jens Borrisholt Oct 01 '15 at 08:36
  • 1
    The image is a screenshot of what you get at the moment. Can you also show the original image? If you cannot edit the original image, can you use another image as a mask? – Jongware Oct 01 '15 at 09:52
  • The screen shot is what I get today. And yes i can use an other image as a mask. I'll add the original image. – Jens Borrisholt Oct 01 '15 at 09:56
  • 1
    First I suggest you derive `TIRButton` from `TGraphicControl` (not `TImage`) which already exposes `Canvas` and suitable for such control. Second, I think `TPngImage` **should** support drawing scaled transparent PNG by design via `.Draw(ACanvas: TCanvas; const Rect: TRect)`. At least "older" [`TPngObject`](http://pngdelphi.sourceforge.net) supports it... – kobik Oct 01 '15 at 12:26
  • Thanks for you advise @kobik but I needed to draw my PNGImage the way I do, else it won't rescale nicly. About derive from TGraphicControl you got a point. – Jens Borrisholt Oct 01 '15 at 12:34

1 Answers1

2

The corners of the source image are transparent. It's not visible in the correct image because the white background. StretchBlt doesn't support transparency. Since it doesn't, transparent pixels are indistinguishable from black. (If the ARGB color is FF 00 00 00 and we remove the alpha channel, we're left with 00 00 00)

You need to use TransparentBlt.

For reference this is the image when placed on a green background. It makes it easier to see the transparency.

enter image description here

theB
  • 6,450
  • 1
  • 28
  • 38