【问题标题】:on Firemonkey, how to draw masked bitmap on canvas?在 Firemonkey 上,如何在画布上绘制蒙版位图?
【发布时间】:2017-09-15 14:25:33
【问题描述】:

我有一个位图和一个掩码(还有一个位图)。我想在蒙版上绘制位图(如下图所示)

如何在 Delphi 上使用 Firemonkey 做到这一点?

【问题讨论】:

    标签: delphi firemonkey


    【解决方案1】:

    使用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;
    

    还有图片(为了更好的演示,修改了背景颜色):

    【讨论】:

    • 一句话,我的面具是透明的+暗的。当我执行 CreateFromBitmapAndMask 时,生成的图像是完全透明的 :( 我错过了什么?
    • 好的,我找到了,我们想要图片的区域必须是白色的,而我们想要透明的区域必须是黑色的......
    • 我不知道你是否还有这个应用的demo,但是你有没有注意到实际上黑色不是透明的而是白色的?我没有找到让结果图像透明的方法....它只输出白色
    • @john ,我明天再看看,我住的地方现在大约是午夜,好吗?
    • :) 对我来说也差不多是午夜了 :) 也许我们离得很近 ;) 当然没关系,我已经感谢你的帮助了!
    【解决方案2】:

    结果图片 - 带有透明背景的星号。在您的蒙版中使用白色以显示图像的可见部分。
    检查了 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;
    

    Sample project

    【讨论】:

    • 我发现我在一年前做了一些测试和修改,但不知怎的被打断了,从未完成。因此,我现在用我当时打算发布的内容编辑了我的答案,这是基于像素和 alpha 的预乘。有趣的是,保存到流中会产生相同的效果,你是怎么想的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2013-07-24
    • 2015-11-03
    相关资源
    最近更新 更多