简体   繁体   English

从TImageList保存透明(alpha通道)PNG

[英]Saving transparent (alpha channel) PNG from TImageList

I have a TImageList which contains transparent icons (32bit, with alpha channel). 我有一个TImageList ,其中包含透明图标(32位,带有alpha通道)。 What I want to do is to save individual icons based on image index as PNG file(s), while preserving alpha channel transparency. 我想要做的是将基于图像索引的单个图标另存为PNG文件,同时保留Alpha通道的透明度。 Using RAD Studio 2010 so it has TPngImage support, no need for third party libraries. 使用RAD Studio 2010,它具有TPngImage支持,不需要第三方库。 Images are loaded into TImageList from PNG "sprite" image using the method here - Add a png image to a imagelist in runtime using Delphi XE - so the transparency is preserved upon loading. 使用此处的方法将图像从PNG“ sprite”图像加载到TImageList中- 使用Delphi XE在运行时将png图像添加到图像列表中 -这样,透明性在加载时得以保留。 Now I need to save them out individually, in other words, extract individual images from sprite images which is already loaded into TImageList. 现在,我需要单独保存它们,换句话说,从已经加载到TImageList中的精灵图像中提取单个图像。

My code so far: 到目前为止,我的代码:

int imageindex = 123;
boost::scoped_ptr<TPngImage>         png(new TPngImage);
boost::scoped_ptr<Graphics::TBitmap> bmp(new Graphics::TBitmap);

MyImageList->GetBitmap(imageindex, bmp.get()); // Using GetBitmap to copy TImageList image into separate TBitmap

png->Assign(bmp.get()); // Assign that bitmap to TPngImage
png->SaveToFile("C:\\filename.png");

The above works but it saves with the white background (transparency is not preserved after saving). 上面的方法有效,但是它以白色背景保存(保存后不保留透明度)。 I am probably missing a simple step but can't figure it out. 我可能缺少一个简单的步骤,但无法弄清楚。

Delphi code is also welcome, shouldn't be hard to translate. 也欢迎使用Delphi代码,应该不难翻译。

Yes, you can obtain PNG-image from TImageList where it was added. 是的,您可以从添加了它的TImageList获得PNG图像。 Code below allows you to do this! 下面的代码允许您执行此操作!
Firstly, add PngImage to your uses clause. 首先,加PngImage到您的uses条款。

procedure LoadPNGFromImageList(AImageList: TCustomImageList; AIndex: Integer; var ADestPNG: TPngImage);
const
  PixelsQuad = MaxInt div SizeOf(TRGBQuad) - 1;
type
  TRGBAArray = Array [0..PixelsQuad - 1] of TRGBQuad;
  PRGBAArray = ^TRGBAArray;
var
  ContentBmp: TBitmap;
  RowInOut: PRGBAArray;
  RowAlpha: PByteArray;
  X: Integer;
  Y: Integer;
begin
  if not Assigned(AImageList) or (AIndex < 0) or
     (AIndex > AImageList.Count - 1) or not Assigned(ADestPNG)
  then
    Exit;

  ContentBmp := TBitmap.Create;
  try
    ContentBmp.SetSize(ADestPNG.Width, ADestPNG.Height);
    ContentBmp.PixelFormat := pf32bit;

    // Allocate zero alpha-channel
    for Y:=0 to ContentBmp.Height - 1 do
      begin
        RowInOut := ContentBmp.ScanLine[Y];
        for X:=0 to ContentBmp.Width - 1 do
          RowInOut[X].rgbReserved := 0;
      end;
    ContentBmp.AlphaFormat := afDefined;

    // Copy image
    AImageList.Draw(ContentBmp.Canvas, 0, 0, AIndex, true);

    // Now ContentBmp has premultiplied alpha value, but it will
    // make bitmap too dark after converting it to PNG. Setting
    // AlphaFormat property to afIgnored helps to unpremultiply
    // alpha value of each pixel in bitmap.
    ContentBmp.AlphaFormat := afIgnored;

    // Copy graphical data and alpha-channel values
    ADestPNG.Assign(ContentBmp);
    ADestPNG.CreateAlpha;
    for Y:=0 to ContentBmp.Height - 1 do
      begin
        RowInOut := ContentBmp.ScanLine[Y];
        RowAlpha := ADestPNG.AlphaScanline[Y];
        for X:=0 to ContentBmp.Width - 1 do
          RowAlpha[X] := RowInOut[X].rgbReserved;
      end;
  finally
    ContentBmp.Free;
  end;
end;

Look at the picture. 看图片。 It is depicts what will happen if we set or not set such line of code: 它描述了如果我们设置或不设置这样的代码行,将会发生什么:

ContentBmp.AlphaFormat := afIgnored;

在此处输入图片说明
Figure 1 is a result of setting afIgnored and the second one figure is a result of not setting afIgnored , allowing to use previously set afDefined . 图1是设置afIgnored的结果,第二个图是设置afIgnored的结果,允许使用先前设置的afDefined

Original image is an image named Figure 1 原始图像是名为图1的图像

Using of code above in application: 在应用程序中使用以上代码:

procedure TForm1.aButton1Click(Sender: TObject);
var
  DestPNG: TPngImage;
begin
  DestPNG := TPNGImage.Create;
  try
    // Initialize PNG
    DestPNG.CreateBlank(COLOR_RGBALPHA, 8, 60, 60);

    // Obtain PNG from image list
    LoadPNGFromImageList(ImageList1, 0, DestPNG);

    // Output PNG onto Canvas
    DestPNG.Draw(Canvas, Rect(0, 0, 60, 60));
    DestPNG.SaveToFile('C:\MyPNGIcon.png');
  finally
    DestPNG.Free;
  end;
end;  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM