delphi - 从 TImageList 保存透明(alpha 通道)PNG
问题描述
我有一个TImageList
包含透明图标(32 位,带 alpha 通道)。我想要做的是将基于图像索引的单个图标保存为 PNG 文件,同时保留 alpha 通道透明度。使用 RAD Studio 2010 所以它有TPngImage
支持,不需要第三方库。使用此处的方法将图像从 PNG“sprite”图像加载到 TImageList -使用 Delphi XE 在运行时将 png 图像添加到图像列表- 因此在加载时会保留透明度。现在我需要单独保存它们,换句话说,从已经加载到 TImageList 中的精灵图像中提取单个图像。
到目前为止我的代码:
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 代码也很受欢迎,应该不难翻译。
解决方案
是的,您可以从添加的位置获取 PNG 图像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;
图一是设置的结果,afIgnored
第二个图是未设置的结果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;
推荐阅读
- javascript - Mongoose find - 从查询中返回所有匹配的至少一个
- julia - Julia中函数调用的歧义
- f# - F# LiteDB [
] 被忽略? - javascript - 如何检查身份验证令牌是否已过期并强制注销?
- android - 如何将雅虎天气 API 中的日期解析为 Java 日期
- javascript - 尝试将 JSON POST 发送到 Discord Webhook 时,urlFetchApp.fetch() 似乎静默失败
- android - 如何将activity_main布局文件连接到非主要活动
- java - .split() 包含字符“++”的字符串
- python - UnicodeDecodeError:“ascii”编解码器无法解码位置 412200 中的字节 0x9a:序数不在范围内(128)
- python - 使用ansible从windows获取文件到远程主机没有被正确复制