Delphi 如何将包含TPngImage的图像保存为位图文件?

Delphi 如何将包含TPngImage的图像保存为位图文件?,delphi,bitmap,png,delphi-10.4-sydney,Delphi,Bitmap,Png,Delphi 10.4 Sydney,在Delphi 10.4中,我在设计时将PNG图像(32BPP,Alpha通道透明度)加载到TImage的Picture属性中。下面是它在运行时的表现: 以下是TImage组件的副本(可在设计时粘贴到任何Delphi VCL应用程序项目中): 现在,在运行时,我尝试将此图像保存为位图图像文件(.bmp): 但是,当我在运行时执行此代码时,会发生一些非常奇怪的事情:TImage组件消失(它显然不可见!),并且创建的.bmp文件的大小为零(0字节) 但是,当我执行此代码而不是上述代码时: proc

在Delphi 10.4中,我在设计时将
PNG
图像(32BPP,Alpha通道透明度)加载到
TImage
Picture
属性中。下面是它在运行时的表现:

以下是
TImage
组件的副本(可在设计时粘贴到任何Delphi VCL应用程序项目中):

现在,在运行时,我尝试将此图像保存为位图图像文件(.bmp):

但是,当我在运行时执行此代码时,会发生一些非常奇怪的事情:
TImage
组件消失(它显然不可见!),并且创建的.bmp文件的大小为零(0字节)

但是,当我执行此代码而不是上述代码时:

procedure TForm1.btnSaveTImageToBitmapClick(Sender: TObject);
begin
  Image1.Picture.SaveToFile('Y:\Downloads\test.bmp');
end;
…然后生成的文件是一个
.PNG
文件,扩展名是错误的
.BMP
文件

那么,如何将此图像保存为有效的位图(
.BMP
)文件


编辑:@Andreas Rejbrand和@Remy Lebeau的答案提供了广泛的解释和解决问题的方法。

您必须创建一个
TBitmap
并将
图片分配给它。图形

程序TForm3.btnSaveClick(发送方:TObject);
变量
bm:TBitmap;
开始
bm:=TBitmap.Create;
尝试
bm.Assign(Image1.Picture.Graphic);
SaveToFile('C:\Users\Andreas-Rejbrand\Desktop\bitmap.bmp');
最后
bm.Free;
结束;
结束;
你的做法:

Image1.Picture.Bitmap.SaveToFile('Y:\Downloads\test.bmp');
Image1.Picture.SaveToFile('Y:\Downloads\test.bmp');
无法工作,因为
图片
不包含位图。从财产的文件中:

当图片对象包含位图时,使用位图引用该对象。如果在图片包含图元文件或图标图形时引用位图,则不会转换图形(图形对象的类型)。相反,图片的原始内容被丢弃,位图返回一个新的空白位图

这种方法:

Image1.Picture.Bitmap.SaveToFile('Y:\Downloads\test.bmp');
Image1.Picture.SaveToFile('Y:\Downloads\test.bmp');
做它应该做的事情。它按原样将
Picture.Graphic
保存到指定的文件中,在您的情况下,它恰好是PNG图像。您为PNG图像选择了一个奇怪的扩展,但VCL并没有试图纠正这一点

处理PNG透明度 如果PNG文件具有alpha通道,
bm.Assign
将非常忠实地创建带有alpha通道的位图图像。从某种意义上说,这很好,因为这样您就不会丢失任何信息:您获得的BMP包含PNG中的所有图形数据,包括整个alpha通道。因此,原则上,您可以将此BMP渲染到任何背景上,并且看起来与PNG一样漂亮

但从另一个角度看,这毕竟没那么好。因为几乎没有图像查看器或编辑器支持带有alpha通道的BMP。这些应用程序可能会忽略alpha通道,有效地使每个像素完全不透明。那看起来很可怕

因此,如果要创建不带alpha通道的普通BMP,则需要使用其alpha通道将PNG“渲染”到您选择的背景上,然后保存不透明结果。您获得的BMP将不包含原始PNG的alpha通道,因此您将丢失信息。BMP将不透明。例如,如果您将其绘制到白色背景上,则即使您将其放置在屏幕的红色区域上,图标/主题后面始终会有一个白色矩形

程序TForm3.Image1Click(发送方:TObject);
变量
bm:TBitmap;
开始
bm:=TBitmap.Create;
尝试
bm.SetSize(Image1.Picture.Width,Image1.Picture.Height);
bm.Canvas.Brush.Color:=clSkyBlue;{*}
bm.Canvas.FillRect(Rect(0,0,bm.Width,bm.Height));{*}
bm.Canvas.Draw(0,0,Image1.Picture.Graphic);
SaveToFile('C:\Users\Andreas Rejbrand\Desktop\bitmap2_1.bmp');
最后
bm.Free;
结束;
结束;

如果您对默认背景色(白色)满意,可以省略带星号(*)的行。

这是否回答了您的问题?它本质上也是一个重复的评论,不用于扩展讨论;这段对话已经结束。