Max1298492
Max1298492

Reputation: 91

How to copy part of an image in another one in Delphi without losing transparency

This is my code, I have a background picture width: 245 and height: 150 and a png picture 128x128, so I copy parts of the png picture inside the background picture.

I have also this information:

dstX = x-coordinate of destination point.

dstY = y-coordinate of destination point.

srcX = x-coordinate of source point.

srcY = y-coordinate of source point.

srcW = Source width.

srcH = Source height.

I try to user copyRect like this

procedure TMyClass.FillImage;
var
 bg,png: TPngImage;
  dstX,dstY,srcW,srcH,srcX,srcY: Integer;
begin
 bg := TPngImage.CreateBlank(COLOR_RGB,8,245,150);
 png := TPngImage.Create;
 png.LoadFromFile('C:\temp\example.png');
 dstX := 10;dstY:=0;srcW:=0;srcH:=118;srcX:=128;srcY:=10;
  bg.Canvas.CopyRect(Rect(dstX,dstY,srcW,srcH),png.Canvas,Rect(srcX,srcY,png.Width,png.Height));

//With this values not working, I have the same result as before, should start copy in position 138 of bg.
  dstX := 138;dstY:=0;srcW:=0;srcH:=118;srcX:=10;srcY:=10;
  bg.Canvas.CopyRect(Rect(dstX,dstY,srcW,srcH),png.Canvas,Rect(srcX,srcY,png.Width,png.Height));
end;

With CopyRect, I have two problems.

  1. When the destX is bigger than the png picture, it doen't start copy in the right position inside the background picture, bg. This is the main issue.
  2. I lose transparencies.

The background picture has not to be a png format at the beginning because it is created at the beginning with only the width and height but at the end has to be save as png.

I search about this problem, first to copy the image png inside bg I try this, but not success:

http://www.delphitricks.com/source-code/graphic/copy_part_of_one_image_to_another.html

Then for the transparency problem I read

Alphablend and TransparentBlt and Why am I losing transparency when calling BitBlt or CopyRect?

But in my case is different because I do not use a paintbox as you can see, and and using a png image and I copy parts of this image inside another with the information I put above. But maybe this post can inspire someone to help me.

Upvotes: 2

Views: 3906

Answers (1)

bummi
bummi

Reputation: 27377

As GDI + is supported since Delphi XE2 Delphi without external units, the easiest way is probably to ignore GDI due the limitations with alpha channels, and directly use the possibilities of GDI+.
Just create a TGPBitmap of the desired size for your destination PNG.
Create TGPImages providing the (PNG)Files you want to paint.
Draw these images using a TGPGraphics created with the TGPBitmap as Destination and draw the images at the desired position with width/height as you like, there are many overloads in GDIPOBJ for DrawImage with descriptive parameter naming.
Choose your encoder by mime type (e.g.image/bmp, image/jpeg, image/gif, image/tiff, image/png) and save the file using this encoder.

A short example:

uses PNGImage, GDIPOBJ, GDIPAPI, GDIPUTIL;

const
  C_FileName1 = 'C:\temp\red.png';
  C_FileName2 = 'C:\temp\Yellow.png';

procedure TDemo.Button1Click(Sender: TObject);
var
  gp: TGPGraphics;
  bg: TGpImage;
  gi1: TGpImage;
  gi2: TGpImage;
  encoderClsid: TGuid;
begin
  bg := TGPBitmap.Create(256, 150);
  try
    gi1 := TGpImage.Create(C_FileName1);
    try
      gi2 := TGpImage.Create(C_FileName2);
      try
        gp := TGPGraphics.Create(bg);
        try
          gp.DrawImage(gi1, 0, 0, 140, 140);
          gp.DrawImage(gi2, 20, 20, 30, 30);
          gp.DrawImage(gi2, 70, 70, 50, 50);
          // Take one of many overloads to crop the image as desired
          //function DrawImage(image: TGPImage; x, y, srcx, srcy, srcwidth, srcheight: Single; srcUnit: TUnit): TStatus; overload;
          gp.DrawImage(gi2, 150, 30, 60, 40, 60, 80, UnitPixel);
          //function TGPGraphics.DrawImage(image: TGPImage; const destRect: TGPRectF; srcx, srcy, srcwidth, srcheight: Single; srcUnit: TUnit; imageAttributes: TGPImageAttributes = nil; callback: DrawImageAbort = nil; callbackData: Pointer = nil): TStatus;
          gp.DrawImage(gi2, DestRect , 60, 40, 60, 80, UnitPixel);
        finally
          gp.Free
        end;
        GetEncoderClsid('image/png', encoderClsid);
        bg.Save('C:\temp\test.png', encoderClsid, nil);
        Image1.Picture.LoadFromFile('C:\temp\test.png');
      finally
        gi2.Free
      end;
    finally
      gi1.Free
    end;
  finally
    bg.Free;
  end;
end;

enter image description here

Since TGPGraphics can be used on every canvas (TGPGraphics.Create(aCanvas.Handle)) a peek into GDIPOBJ, GDIPAPI, GDIPUTIL might be interesting.

Upvotes: 3

Related Questions