代码之家  ›  专栏  ›  技术社区  ›  Coder12345

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

  •  1
  • Coder12345  · 技术社区  · 6 年前

    我有一个 TImageList 它包含透明图标(32位,带alpha通道)。我想做的是保存单个图标的图像索引为PNG文件(s)的基础上,同时保留alpha通道的透明度。使用RAD Studio 2010 TPngImage Add a png image to a imagelist in runtime using Delphi XE -因此在加载时保持透明度。现在我需要单独保存它们,换句话说,从已经加载到TImageList的sprite图像中提取单独的图像。

    到目前为止我的代码是:

    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");
    

    上面的工作,但它以白色背景保存(保存后不保留透明度)。我可能错过了一个简单的步骤,但无法找到它。

    Delphi代码也很受欢迎,应该不难翻译。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Josef Å vejk    6 年前

    是的,您可以从 TImageList 添加的位置。下面的代码允许您这样做!
    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;
    

    看这幅画。它描述了如果我们设置或不设置这样的代码行会发生什么:

    ContentBmp.AlphaFormat := afIgnored;
    

    enter image description here
    afIgnored 设置 afDefined .

    原始图像是一个名为图1的图像

    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;