【问题标题】:Delphi 2006: Run-time assignment of PNG to TImage loses alpha transparencyDelphi 2006:PNG 到 TImage 的运行时分配失去了 alpha 透明度
【发布时间】:2011-07-19 08:36:36
【问题描述】:

Delphi 2006 的 TImage 不太支持 PNG。为了在我的表单上显示具有 alpha 透明度的图像,我必须在运行时加载它们。我可以在设计时加载它们,但它们无法生存,我认为是因为 PNG 没有保存在 DFM 文件中。我敢肯定,这在最新的 Delphi 中都是笨拙的,但我目前无法升级。

无论如何,我是在运行时加载它们的:

Image1.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ;

PNGImageCollection 组件包含我所有不同大小的 PNG(这些是在设计时创建和加载的),我在 FormCreate 事件中将它们分配给相应的 TImage。

这工作正常,直到我遇到问题,在表单上使用这些图像后,我试图在其他地方重复使用这些图像。我发现分配 TPicture 的行为已将其设置为空图像作为分配的结果。这发生在例程 TPicture.ForceType 中,AFAICT 检查 FGraphic 的类型,如果它不是所需的类型,它会释放 FGraphic 并创建所请求类型的新实例。

好的。因此,经过一番摸索,我发现也许我真的应该这样做:

Image1.Picture.Bitmap.Assign (PngImageCollection1.Items [0].PNGImage) ; 

这成功了,因为分配没有破坏图像,但图像现在显示为不透明的半透明位,即:

代替:

如何让此图像正确显示 alpha 透明位? (和补充问题:Image1.Picture.Bitmap.Assign 是正确的方法吗?)。

下面是更详细的代码:

在我遇到“重用”TImage 问题的代码中,顺序是:
在创建表单时:

LogoImage.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ; 

(PNGIMage 是公司标志,LogoImage1 在主窗体上)。

在打印报告标题上:

procedure PrintLogo (Report : TBaseReport) ;

var
    X1, Y1, LogoHeightMM    : Double ;

begin
with Report do
    begin
    LogoHeightMM  := CalcGraphicHeight (LogoWidthMM, MainForm.LogoImage.Picture.Graphic) ;
    X1            := PageWidth - MarginRight - LogoWidthMM ;
    Y1            := SectionBottom - LogoHeightMM ;
    PrintBitmapRect (X1, Y1, X1 + LogoWidthMM, Y1 + LogoHeightMM, MainForm.LogoImage.Picture.Bitmap) ;
    end ;
end ;

第一次调用打印徽标的例程时,它会正常执行,但在调用 PrintBitmapRect 后 LogoImage .Picture 会被清除。下次调用打印头例程时,对 CalcGraphicHeight 的调用将失败,因为图像的宽度和高度为零。

将 Picture.Assign 更改为 Picture.Bitmap.Assign 修复了标题打印例程中的 RTE,但是当我将相同的“修复”移植到从 PNG 分配的其他静态图像(如上面的齿轮)时,我丢失了 aplha频道。

【问题讨论】:

  • 我建议放弃问题上的其中一个标签,转而支持Delphi。应该有些开发者过去使用过以前的版本,但目前没有关注他们的标签。..
  • 最好是尝试在一个非常小的测试用例中重现,然后从那里开始工作。如果您可以发布那个小测试用例,它会很有帮助。

标签: delphi png delphi-2006 timage alpha-transparency


【解决方案1】:

您没有显示代码中真正相关的部分:您如何重用图像以使其具有特定类型。

当您将 TImage 分配给 TPngObject 时,图像的图形将包含一个 png 对象。只有当您专门请求位图时,它才会强制其图形为位图类型。比如这个,

  Bmp.Assign(Image1.Picture.Bitmap);

将强制 Image1 具有位图图形,如果其图形是 png 对象,它将被释放。虽然这样,

  Bmp.Assign(Image1.Picture.Graphic);

不会强制 Image1 具有位图图形,png 对象将执行分配并留在那里。

Delphi 的位图(至少到最新版本)不支持 alpha 通道,因此您不应该将 Image1.Picture.Bitmap.Assign(.. 用于部分透明的图像。


顺便说一句,您可以使用 png 图像集合中的图像作为源,而不是重复使用图像中的图形。..

【讨论】:

  • @rossmcm - 是 PrintBitmapRect(.. 行导致您的图像丢失 png 对象,因为您专门请求位图:MainForm.LogoImage.Picture.Bitmap。这正是答案中的第一个例子。如果“PrintBitmapRect”需要位图,则创建一个临时位图,设置其大小,使用答案中的第二个示例分配给它,传递给“PrintBitmapRect”,然后释放临时位图。
  • 那行得通。非常感谢。我发现第 3 方 PNG 支持非常脆弱和支离破碎。我认为对于当前版本的 Delphi 可能值得咬紧牙关,这样我就可以处理这种对 PNG 的支持的杂乱无章 - 你知道一套合理的 PNG 单元都来自一个地方吗?
  • @rossmcm - 我认为当你接受答案时,:) 不客气!...不,我想我们使用的是同一个库,除了我也有可能的例外Martijn Saly 的扩展,例如 TPngImageList。我再也无法在互联网上找到它们,但 Uwe Raabe 的 D2009 端口仍然可以在 cc.embarcadero.com/Item/26127 获得。最终,我强烈同意最好将它们与 VCL 一起使用,但我想我会等待 64 位..
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 2018-09-23
相关资源
最近更新 更多