如何在Delphi中复制另一个图像的一部分而不失透明度

时间:2015-01-07 11:32:50

标签: image delphi delphi-xe5

这是我的代码,我有一个背景图片宽度:245和高度:150和一张png图片128x128,所以我在背景图片中复制部分png图片。

我也有这个信息:

dstX =目的地点的x坐标。

dstY =目的地点的y坐标。

srcX =源点的x坐标。

srcY =源点的y坐标。

srcW =来源宽度。

srcH =来源高度。

我尝试像这样使用copyRect

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;

使用CopyRect,我有两个问题。

  1. 当destX大于png图片时,它不会在背景图片bg内的正确位置开始复制。这是主要问题。
  2. 我丢失了透明胶片。
  3. 背景图片一开始不是png格式,因为它在开头只创建宽度和高度,但最后必须保存为png。

    我搜索了这个问题,首先将图像png复制到bg中我试试这个,但没有成功:

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

    然后我读了透明度问题

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

    但在我的情况下是不同的,因为我没有使用你可以看到的绘图框,并使用png图像,我用上面提供的信息将这个图像的一部分复制到另一个图像中。但也许这篇文章可以激励别人帮助我。

1 个答案:

答案 0 :(得分:3)

由于自没有外部设备的Delphi XE2 Delphi支持GDI +,最简单的方法可能是忽略了GDI,因为alpha通道的限制,并直接使用GDI +的可能性。
只需为目标PNG创建所需大小的TGPBitmap 创建提供要绘制的(PNG)文件的TGPImages 使用以TGPBitmap为目标创建的TGPGraphics绘制这些图像,并根据需要在宽度/高度的所需位置绘制图像,GDIPOBJ中有许多带有描述性参数命名的DrawImage重载。
按mime类型选择编码器(例如image / bmp,image / jpeg,image / gif,image / tiff,image / png)并使用此编码器保存文件。

一个简短的例子:

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

由于可以在每个画布上使用TGPGraphics(TGPGraphics.Create(aCanvas.Handle)),一看GDIPOBJ,GDIPAPI,GDIPUTIL可能会很有趣。