【发布时间】:2017-09-15 14:25:33
【问题描述】:
我有一个位图和一个掩码(还有一个位图)。我想在蒙版上绘制位图(如下图所示)
如何在 Delphi 上使用 Firemonkey 做到这一点?
【问题讨论】:
标签: delphi firemonkey
我有一个位图和一个掩码(还有一个位图)。我想在蒙版上绘制位图(如下图所示)
如何在 Delphi 上使用 Firemonkey 做到这一点?
【问题讨论】:
标签: delphi firemonkey
使用TBitmap.CreateFromBitmapAndMask()
constructor CreateFromBitmapAndMask(const Bitmap, Mask: TBitmap);
文档说:
创建的TBitmap有每种颜色的Alpha通道的值 像素等于 Mask 中红色通道的值。
还有:
提示:为获得更好的效果,请为遮罩使用灰度图像。它有一个 等量的绿色、红色和蓝色。
提示:掩码和基本位图必须具有相同的尺寸。 否则,新的 TBitmap 的维度将等于 0。
在一个简单的测试中:
procedure TForm19.Button1Click(Sender: TObject);
var
bmp, msk: TBitmap;
begin
bmp := nil;
msk := nil;
try
bmp := TBitmap.Create;
msk := TBitmap.Create;
bmp.LoadFromFile('C:\tmp\Imgs\4.bmp');
msk.LoadFromFile('C:\tmp\Imgs\TestImage04.bmp');
Image1.Bitmap := bmp;
Image2.Bitmap := msk;
Image3.Bitmap.CreateFromBitmapAndMask(bmp, msk);
finally
bmp.Free;
msk.Free;
end;
end;
结果如下所示:
编辑
为了使CreateFromBitmapAndMask(bmp, msk); 的结果在窗体上透明地绘制,它必须在分配给Image3 之前是premultiplied。我们需要以下程序,
procedure PremultiplyBitmapAlpha(bmp:TBitmap);
var
X, Y: Integer;
M: TBitmapData;
C: PAlphaColorRec;
begin
if bmp.Map(TMapAccess.ReadWrite, M) then
try
for Y := 0 to bmp.Height - 1 do
for X := 0 to bmp.Width - 1 do
begin
C := @PAlphaColorArray(M.Data)[Y * (M.Pitch div 4) + X];
C^.Color := PremultiplyAlpha(C^.Color);
end;
finally
bmp.Unmap(M);
end;
end;
和另一个临时位图res 用于此目的。测试代码现在如下所示:
procedure TForm14.Button1Click(Sender: TObject);
var
bmp, msk, res: TBitmap;
begin
bmp := nil;
msk := nil;
res := nil;
try
bmp := TBitmap.Create;
msk := TBitmap.Create;
bmp.LoadFromFile('C:\tmp\Imgs\4.bmp');
msk.LoadFromFile('C:\tmp\Imgs\TestImage04.bmp');
Image1.Bitmap := bmp;
Image2.Bitmap := msk;
res := TBitmap.Create;
res.CreateFromBitmapAndMask(bmp, msk);
PremultiplyBitmapAlpha(res);
Image3.Bitmap := res;
finally
bmp.Free;
msk.Free;
res.Free;
end;
end;
还有图片(为了更好的演示,修改了背景颜色):
【讨论】:
结果图片 - 带有透明背景的星号。在您的蒙版中使用白色以显示图像的可见部分。
检查了 Delphi Berlin 和 Windows。
procedure TForm1.Button1Click(Sender: TObject);
var
ImageRes: TResourceStream;
Result: TBitmap;
tmpMS : TMemoryStream;
begin
ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA);
try
Image1.Bitmap.CreateFromStream(ImageRes);
Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png');
Result := TBitmap.Create;
Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap);
// applying alpha channel to Bitmap - workaround. If you can improve write here how
tmpMS := TMemoryStream.Create;
Result.SaveToStream(tmpMS);
Result.LoadFromStream(tmpMS);
tmpMS.Free;
Image3.Bitmap.Assign(Result);
finally
ImageRes.Free;
Result.Free;
end;
end;
【讨论】: