C#如何实现PNG图片局部比对以跳过左上角时间戳差异
解决方案
.NET Framework 没有内置的 PNG 图片局部比对专用函数,但仅需要对你现有代码做少量修改即可实现跳过左上角时间戳区域的比对需求,具体实现逻辑如下:
- 提前确认左上角时间戳覆盖的区域尺寸,比如实际测试得出时间戳宽180px、高50px,可自行调整对应参数匹配你的业务场景。
- 增加前置校验逻辑:先判断两张待比对图片的宽、高是否完全一致,不一致直接返回不匹配,避免后续逻辑出错。
- 像素遍历时跳过左上角时间戳覆盖区域的像素,其余区域保持全量比对即可。
可直接运行的修改后代码
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; public bool CompareImageWithoutTimestamp(string masterPath, string testPath) { // 配置左上角时间戳区域尺寸,根据实际情况修改 const int TStampWidth = 180; const int TStampHeight = 50; using Bitmap master = (Bitmap)Bitmap.FromFile(masterPath); using Bitmap test = (Bitmap)Bitmap.FromFile(testPath); // 宽高不一致直接返回不匹配 if (master.Width != test.Width || master.Height != test.Height) return false; // 时间戳区域超过图片尺寸的话直接全量比对 if (TStampWidth >= master.Width || TStampHeight >= master.Height) return CompareAllPixels(master, test); Rectangle fullRect = new Rectangle(0, 0, master.Width, master.Height); BitmapData masterData = master.LockBits(fullRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData testData = test.LockBits(fullRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); try { int stride = masterData.Stride; int bytesPerPixel = 4; // 对应Format32bppArgb格式 byte[] masterBytes = new byte[stride * master.Height]; byte[] testBytes = new byte[stride * test.Height]; Marshal.Copy(masterData.Scan0, masterBytes, 0, masterBytes.Length); Marshal.Copy(testData.Scan0, testBytes, 0, testBytes.Length); // 逐行遍历像素 for (int y = 0; y < master.Height; y++) { // 每行起始字节位置 int rowStart = y * stride; // 当前行属于时间戳区域的话,跳过左侧时间戳宽度对应的字节 int startX = y < TStampHeight ? TStampWidth * bytesPerPixel : 0; for (int x = startX; x < stride; x++) { if (masterBytes[rowStart + x] != testBytes[rowStart + x]) return false; } } return true; } finally { master.UnlockBits(masterData); test.UnlockBits(testData); } } // 全量比对 fallback 方法 private bool CompareAllPixels(Bitmap master, Bitmap test) { Rectangle fullRect = new Rectangle(0, 0, master.Width, master.Height); BitmapData masterData = master.LockBits(fullRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData testData = test.LockBits(fullRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); try { int stride = masterData.Stride; int totalBytes = stride * master.Height; byte[] masterBytes = new byte[totalBytes]; byte[] testBytes = new byte[totalBytes]; Marshal.Copy(masterData.Scan0, masterBytes, 0, totalBytes); Marshal.Copy(testData.Scan0, testBytes, 0, totalBytes); for (int i = 0; i < totalBytes; i++) { if (masterBytes[i] != testBytes[i]) return false; } return true; } finally { master.UnlockBits(masterData); test.UnlockBits(testData); } }
注意:你原代码中的
object.Equals(original_image,test_image)逻辑无效,该方法判断的是对象引用是否相等,从不同文件加载的两个Bitmap对象即使像素完全一致,引用也不会相等,可以直接删除该判断。
内容的提问来源于stack exchange,提问作者A 786
相关产品推荐
相关产品推荐

