如何提升GraphicsPath.IsVisible方法的执行效率?
优化C#中GraphicsPath.IsVisible判断效率的方案
一、预生成路径区域掩码(最有效优化)
把GraphicsPath对应的区域提前绘制到一张同尺寸的掩码位图中,后续判断点是否在路径内时,直接读取掩码的像素值即可,彻底避免反复调用IsVisible的昂贵计算。
实现步骤
- 创建与目标位图(
bmptest)尺寸一致的掩码Bitmap,推荐用Format32bppArgb格式。 - 用绘图上下文先填充掩码为黑色(代表路径外区域),再用白色填充
GraphicsPath覆盖的区域(代表路径内)。 - 对掩码执行
LockBits获取像素指针,后续通过坐标计算偏移量直接读取像素值判断归属。
代码示例
// 预生成路径掩码(建议在窗体加载或路径变更时执行,不要放在Paint事件重复生成) private Bitmap CreatePathMask(Bitmap targetBmp, GraphicsPath path) { Bitmap mask = new Bitmap(targetBmp.Width, targetBmp.Height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(mask)) { g.FillRectangle(Brushes.Black, 0, 0, mask.Width, mask.Height); g.FillPath(Brushes.White, path); } return mask; } // 在FindPoints中使用掩码判断 private void FindPoints(Bitmap bmp1, Bitmap bmp2, Bitmap bmptest, Bitmap pathMask) { // 省略获取bmp1、bmp2、bmptest像素数据的LockBits代码... // 锁定掩码像素数据 Rectangle maskRect = new Rectangle(0, 0, pathMask.Width, pathMask.Height); BitmapData maskData = pathMask.LockBits(maskRect, ImageLockMode.ReadOnly, pathMask.PixelFormat); IntPtr maskPtr = maskData.Scan0; int maskStride = maskData.Stride; int pixelByteSize = 4; // 32bppArgb每个像素占4字节 try { foreach (var point in cloudPoints) { int x = point.X; int y = point.Y; if (x < 0 || x >= pathMask.Width || y < 0 || y >= pathMask.Height) continue; // 计算掩码像素的内存偏移量 int offset = y * maskStride + x * pixelByteSize; // 读取红色通道值(白色的R通道为255) byte r = Marshal.ReadByte(maskPtr, offset + 2); if (r == 255) { // 设置bmptest对应像素为黄色的代码... } } } finally { pathMask.UnlockBits(maskData); // 解锁其他位图的BitmapData... } }
二、先过滤差异点范围
先获取GraphicsPath的外接矩形Bounds,只对落在这个矩形内的差异点执行IsVisible判断,减少无效调用:
Rectangle pathBounds = path.GetBounds().ToRectangle(); foreach (var point in cloudPoints) { if (!pathBounds.Contains(point)) continue; if (path.IsVisible(point)) { // 设置黄色像素... } }
三、并行处理差异点
如果差异点数量极大,可利用多核CPU并行处理:
Rectangle pathBounds = path.GetBounds().ToRectangle(); Parallel.ForEach(cloudPoints, point => { if (pathBounds.Contains(point) && path.IsVisible(point)) { // 注意:操作bmptest像素时,若用LockBits指针则线程安全(每个点内存地址独立) // 设置黄色像素的代码... } });
注意事项
- 路径掩码要缓存,仅当
GraphicsPath发生变化时重新生成,避免重复计算。 LockBits操作必须放在try-finally块中,确保位图能正常解锁,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

