You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi Rio FireMonkey中快速替换TPathData区域指定颜色的方法

快速替换FireMonkey TBitmap路径内的颜色(替代逐像素遍历)

你遇到的问题很典型:逐像素调用PtInPath并修改像素是纯CPU操作,对于稍大的Bitmap来说性能极差,尤其是需要实时响应用户操作的时候。FireMonkey本身提供了GPU加速的绘图能力,我们可以利用这个特性来大幅提升速度。

核心优化思路

通过FireMonkey Canvas的路径裁剪和颜色混合模式,让GPU来处理区域内的颜色替换,而不是CPU逐像素判断。这个方法的性能提升非常明显,尤其是在大尺寸图像或复杂路径下。

优化后的代码实现

procedure TForm1.ChangePathColorFast(Npath: TPathData; TopV: Integer; BotV: Integer);
var
  TempBitmap: TBitmap;
  ClipRect: TRectF;
begin
  // 创建与原图像尺寸一致的临时Bitmap
  TempBitmap := TBitmap.Create(Image1.Bitmap.Width, Image1.Bitmap.Height);
  try
    // 复制原图像内容到临时Bitmap
    TempBitmap.Assign(Image1.Bitmap);
    
    // 获取路径的边界矩形,缩小后续绘图范围(进一步优化性能)
    ClipRect := Npath.GetBounds;
    // 结合传入的TopV和BotV限制绘制区域
    ClipRect.Top := Max(ClipRect.Top, TopV);
    ClipRect.Bottom := Min(ClipRect.Bottom, BotV);
    
    // 开始临时Bitmap的绘图场景
    TempBitmap.Canvas.BeginScene;
    try
      // 设置裁剪路径:后续所有绘图仅在该路径内部生效
      TempBitmap.Canvas.BeginClipPath(Npath);
      try
        // 设置混合模式:仅保留原图像中不透明的像素,用红色覆盖
        // 这样透明背景不会被修改,只有原来的黑色文字会被替换
        TempBitmap.Canvas.BlendMode := TBlendMode.bmSrcIn;
        
        // 填充裁剪区域为红色
        TempBitmap.Canvas.Fill.Color := TAlphaColors.Red;
        TempBitmap.Canvas.FillRect(ClipRect, 0, 0, [], 1);
      finally
        // 结束裁剪路径
        TempBitmap.Canvas.EndClipPath;
      end;
    finally
      // 结束绘图场景,确保所有GPU操作完成
      TempBitmap.Canvas.EndScene;
    end;
    
    // 将修改后的图像赋值回Image1
    Image1.Bitmap.Assign(TempBitmap);
  finally
    TempBitmap.Free;
  end;
end;

为什么这个方法更快?

  1. GPU加速:裁剪路径和填充操作都是由FireMonkey的GPU渲染管线处理,相比CPU逐像素遍历,速度能提升几十甚至上百倍。
  2. 减少无效操作:通过GetBounds获取路径的最小包围矩形,只在这个范围内绘图,避免了对路径外像素的无用处理。
  3. 精准的混合模式:bmSrcIn混合模式确保只有原图像中不透明的部分(也就是你的黑色文字)会被红色覆盖,透明背景完全不受影响,完美匹配你的需求。

进阶优化:精确颜色替换(可选)

如果你需要更精确的颜色替换(比如只替换严格的黑色,而不是所有低R值的像素),可以结合TColorMatrixEffect来实现:

procedure TForm1.ChangePathColorExact(Npath: TPathData; TopV: Integer; BotV: Integer);
var
  TempBitmap: TBitmap;
  ClipRect: TRectF;
  ColorEffect: TColorMatrixEffect;
begin
  TempBitmap := TBitmap.Create(Image1.Bitmap.Width, Image1.Bitmap.Height);
  ColorEffect := TColorMatrixEffect.Create(nil);
  try
    TempBitmap.Assign(Image1.Bitmap);
    ClipRect := Npath.GetBounds;
    ClipRect.Top := Max(ClipRect.Top, TopV);
    ClipRect.Bottom := Min(ClipRect.Bottom, BotV);
    
    // 配置颜色矩阵:将黑色(RGB=0,0,0)转为红色(RGB=255,0,0),其他颜色保持不变
    ColorEffect.ColorMatrix := TColorMatrix.Create(
      1, 0, 0, 0, 0,   // 保留原始R通道
      0, 1, 0, 0, 0,   // 保留原始G通道
      0, 0, 1, 0, 0,   // 保留原始B通道
      0, 0, 0, 1, 0,   // 保留原始Alpha通道
      255, 0, 0, 0, 1  // 仅当R=0时,添加255转为红色
    );
    
    TempBitmap.Canvas.BeginScene;
    try
      TempBitmap.Canvas.BeginClipPath(Npath);
      try
        // 应用颜色矩阵效果到裁剪区域
        TempBitmap.Canvas.DrawBitmap(TempBitmap, ClipRect, ClipRect, 1, [ColorEffect]);
      finally
        TempBitmap.Canvas.EndClipPath;
      end;
    finally
      TempBitmap.Canvas.EndScene;
    end;
    
    Image1.Bitmap.Assign(TempBitmap);
  finally
    ColorEffect.Free;
    TempBitmap.Free;
  end;
end;

这个方法可以精准控制颜色替换的规则,同时依然保持GPU加速的性能优势。

内容的提问来源于stack exchange,提问作者Baloush

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:09:36