[英]Delphi FMX TImage manual alpha transparency mapping failure
I am trying to create a TImage with alpha transparency using code. 我正在尝试使用代码创建具有Alpha透明度的TImage。 In this example, an anti-aliased circle.
在此示例中,是一个消除锯齿的圆圈。
I create an 8bit opacity map for the circle and then apply it to the TImage's TBitmap using this piece of code: 我为圆圈创建了一个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;
The result is the image on the left. 结果是左侧的图像。 The actual TBitmap seems to be good, calling "srcBitmap.SaveToFile('circle.png')" results in a PNG file with a valid alpha channel.
实际的TBitmap似乎很好,调用“srcBitmap.SaveToFile('circle.png')”会产生一个带有有效alpha通道的PNG文件。
I can work-around this issue by simply saving/loading the bitmap using a TMemoryStream. 我可以通过使用TMemoryStream保存/加载位图来解决这个问题。
How do I get the desired image on the right without the performance penalty of passing the image through a TMemoryStream? 如何在没有通过TMemoryStream传递图像的性能损失的情况下获得右侧所需的图像?
These screenshots are from the minimal example project demonstrating this issue : 这些屏幕截图来自演示此问题的最小示例项目:
https://github.com/bLightZP/AntiAliasedCircle https://github.com/bLightZP/AntiAliasedCircle
edit #1 : 编辑#1:
The github code linked above has been updated with an optimized (about 25% faster) version of Tom Brunberg's suggested fix. 上面链接的github代码已经更新了Tom Brunberg建议修复的优化(约25%更快)版本。
You can achieve your goal with applying alpha channel premultiplying to your overlay image. 您可以通过将Alpha通道预乘映射到叠加图像来实现目标。 For example in the loop where you add the alpha channel:
例如,在添加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;
The result looks like this (ofcourse without the stream work-around) 结果看起来像这样(当然没有流解决方案)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.