【问题标题】:Delphi FMX TImage manual alpha transparency mapping failureDelphi FMX TImage 手动 alpha 透明度映射失败
【发布时间】:2018-02-22 13:17:16
【问题描述】:

我正在尝试使用代码创建具有 alpha 透明度的 TImage。 在这个例子中,一个消除锯齿的圆圈。

我为圆创建了一个 8 位不透明度贴图,然后使用这段代码将其应用到 TImage 的 TBitmap:

type
  TOpacityMap = Array[0..4095] of PByteArray;

procedure DrawAntiAliasedCircle(srcBitmap: TBitmap; FillColor : TAlphaColor; CenterX, CenterY, Radius, LineWidth, Feather: single);
var
  FillR                      : Integer;
  FillG                      : Integer;
  FillB                      : Integer;
  FillRGB                    : Integer;
  OpacityMap                 : TOpacityMap;
  AlphaScanLine              : Array[0..4095] of TAlphaColor;
  bitmapData                 : FMX.Graphics.TBitmapData;
  tmpScanLine                : Pointer;
  X,Y                        : Integer;
  tmpMS                      : TMemoryStream;

begin
  {Initialization}
  FillR  := TAlphaColorRec(FillColor).R;
  FillG  := TAlphaColorRec(FillColor).G;
  FillB  := TAlphaColorRec(FillColor).B;

  CreateAntiAliasedCircleOpacityMap(OpacityMap, srcBitmap.Width, srcBitmap.Height, CenterX, CenterY, Radius, LineWidth, Feather);

  {create image based on opacity map and free memory}
  If srcBitmap.Map(TMapAccess.Write, bitmapData) then
  try
    FillRGB := (FillR shl 16)+(FillG shl 8)+FillB;

    for Y := 0 to srcBitmap.Height-1 do
    begin
      for X := 0 to srcBitmap.Width-1 do
        AlphaScanLine[X] := (OpacityMap[Y][X] shl 24)+FillRGB; // Opacity

      tmpScanLine := bitmapData.GetScanline(Y);
      AlphaColorToScanLine(@AlphaScanLine,tmpScanLine,srcBitmap.Width,srcBitmap.PixelFormat);
      FreeMem(OpacityMap[Y]);
    end;
  finally
    srcBitmap.Unmap(bitmapData);
  end;

  // Work-around fix
  {tmpMS := TMemoryStream.Create;
  srcBitmap.SaveToStream(tmpMS);
  srcBitmap.LoadFromStream(tmpMS);
  tmpMS.Free;}
end;

结果是左边的图像。 实际的 TBitmap 似乎不错,调用“srcBitmap.SaveToFile('circle.png')”会生成一个带有有效 alpha 通道的 PNG 文件。

我可以通过简单地使用 TMemoryStream 保存/加载位图来解决这个问题。

如何在右侧获得所需的图像,而不会因通过 TMemoryStream 传递图像而造成性能损失?

这些屏幕截图来自演示此问题的最小示例项目:
https://github.com/bLightZP/AntiAliasedCircle

编辑#1:
上面链接的 github 代码已更新为 Tom Brunberg 建议修复的优化(大约快 25%)版本。

【问题讨论】:

    标签: delphi firemonkey alphablending alpha-transparency


    【解决方案1】:

    您可以通过对叠加图像应用 Alpha 通道预乘来实现您的目标。例如在添加 alpha 通道的循环中:

      for X := 0 to srcBitmap.Width-1 do
      begin
        AlphaScanLine[X] := (OpacityMap[Y][X] shl 24)+FillRGB;
        AlphaScanLine[X] := PremultiplyAlpha(AlphaScanLine[X]); // Add this for premultiplied Alpha
      end;
    

    结果看起来像这样(当然没有流变通方法)

    【讨论】:

    • 感谢 Tom,这很有效,它比通过内存流快得多,但仍然有很多开销。在我将此标记为答案之前,您能解释一下为什么当只有 Alpha 通道应该控制每个像素的不透明度时,为什么需要修改 RGB 值(这就是调用 PremultiplyAlpha 所做的)?
    • 您提出的附加问题过于宽泛,无法在 cmets 中深入回答,我已经回答了您的实际问题。不同之处在于框架中组合(混合)两个图像的公式需要预先计算的像素。预先计算的图像在另一张图像上显示的速度稍快。
    猜你喜欢
    • 2023-03-24
    • 2011-07-19
    • 2015-02-27
    • 2017-12-13
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多