2

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.

Community
  • 1
  • 1
Max1298492
  • 91
  • 3
  • 8
  • Take a look at your RECTs(L,R,T,B) the values are not plausible. Could you mention your Delphi version, depending on the version Draw and StretchDraw should work, with XE2 + you would be able to use GDI+ without external units. – bummi Jan 07 '15 at 12:16
  • @kobik my code is different I am not coping and png inside another one exactly, I copy part of one png in another png in some position, that post you put do not do that. – Max1298492 Jan 07 '15 at 17:00

1 Answers1

3

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.

bummi
  • 27,123
  • 14
  • 62
  • 101
  • Almost good,the paremeters of the function DrawImage: gp.DrawImage(gi1, 'x-coordinate of destination point', 'y-coordinate of destination point', Source width, Source height); But also I need to copy only part of the source picture, not all with new width and height, so I need to add in some point: x-coordinate of source point and y-coordinate of source point. So I copy the part of the source picture: From x,y coordinate a given width and height to the background picture in some position. At the momment what I haven't got it is the crop part of the source image. – Max1298492 Jan 08 '15 at 10:33
  • @Max1298492 I did an edit to show some of the existing overrides for DrawImage, take a look to GDIPOBJ to find the one which will fit best for you. – bummi Jan 08 '15 at 11:57