Delphi FMX TImage手动alpha透明度映射失败

时间:2018-02-22 13:17:16

标签: delphi firemonkey alphablending alpha-transparency

我正在尝试使用代码创建具有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')"导致PNG文件具有有效的Alpha通道。

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

如何在没有通过TMemoryStream传递图像的性能损失的情况下获得所需的图像?

Bad_Alpha Workaround

这些截图来自最小的示例项目,展示了这个问题:
https://github.com/bLightZP/AntiAliasedCircle

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

1 个答案:

答案 0 :(得分:3)

您可以通过将Alpha通道预乘映射到叠加图像来实现目标。例如,在添加alpha通道的循环中:

componentDidMount

结果看起来像这样(当然没有流解决方案)

enter image description here