如何用C#与jQuery判断图片是否一致?Blazor对比异常问题
问题描述
使用VS2022、C#、Blazor和jQuery开发时,先将本地路径C:\Images\defaultImage.png加载到页面Canvas区域:
<canvas id="CanvasId" @ref="canvasElement"></canvas>
await JS.InvokeVoidAsync("loadImageOnCanvas", "CanvasId", "/scripts/defaultImage.png");
图片存入数据库后,日后从数据库取回并加载到Canvas,需要判断该图片是否与本地C:\Images\defaultImage.png一致,但对比结果始终不相等——Canvas中的图片字节数总是比原文件大1KB左右。用于对比的代码如下:
// Retrieve the image that was loaded on canvas var canvasImage = await JS.InvokeAsync<string>("captureCanvasImage", "CanvasId"); canvasImage = canvasImage.Replace("data:image/png;base64,", String.Empty); // byte[27980] byte[] imageOnCanvas_Bytes = Convert.FromBase64String(canvasImage); // byte[26978] byte[] defaultImage_Bytes = File.ReadAllBytes("wwwroot/scripts/defaultImage.png"); // Compare as string returns FALSE var result = canvasImage == Convert.ToBase64String(defaultImage_Bytes); // Compare byte arrays returns FALSE var result2 = imageOnCanvas_Bytes.SequenceEqual(defaultImage_Bytes);
原因分析
- Canvas导出PNG时会重新编码图像,即使像素完全一致,编码参数(如压缩级别、颜色配置)和原文件也可能存在差异,导致字节数和内容不同。
- 原PNG文件可能包含元数据(如EXIF信息、注释),而Canvas导出的PNG不会保留这些额外数据,或会添加自身默认的元数据。
- 浏览器加载图片到Canvas的过程中,可能会进行颜色空间转换或像素格式调整,再次导出时就会和原文件产生差异。
解决方案
方案1:基于像素数据对比哈希值
不直接对比文件字节,而是对比Canvas图像与原图像的像素数据哈希:
- 编写JS函数获取像素哈希:
// 获取Canvas图像的像素哈希 function getCanvasPixelHash(canvasId) { const canvas = document.getElementById(canvasId); const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const pixels = imageData.data; let hash = 0; // 累加所有像素的RGBA值计算哈希(小图足够用,复杂场景可换MD5等算法) for (let i = 0; i < pixels.length; i += 4) { hash += pixels[i] + pixels[i+1] + pixels[i+2] + pixels[i+3]; } return hash.toString(16); } // 获取本地图片的像素哈希 function getLocalImagePixelHash(imageUrl) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = function() { const tempCanvas = document.createElement('canvas'); tempCanvas.width = img.width; tempCanvas.height = img.height; const ctx = tempCanvas.getContext('2d'); ctx.drawImage(img, 0, 0); const imageData = ctx.getImageData(0, 0, tempCanvas.width, tempCanvas.height); const pixels = imageData.data; let hash = 0; for (let i = 0; i < pixels.length; i += 4) { hash += pixels[i] + pixels[i+1] + pixels[i+2] + pixels[i+3]; } resolve(hash.toString(16)); }; img.onerror = reject; img.src = imageUrl; }); }
- 在Blazor中调用对比:
var canvasHash = await JS.InvokeAsync<string>("getCanvasPixelHash", "CanvasId"); var localImageHash = await JS.InvokeAsync<string>("getLocalImagePixelHash", "/scripts/defaultImage.png"); var isEqual = canvasHash == localImageHash;
方案2:精确像素对比(适合小尺寸图片)
由于你的图片尺寸仅241px×154px,可以直接对比每个像素的RGBA值:
function compareCanvasAndLocalImage(canvasId, imageUrl) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = function() { const canvas = document.getElementById(canvasId); // 先对比尺寸 if (canvas.width !== img.width || canvas.height !== img.height) { resolve(false); return; } const ctx = canvas.getContext('2d'); const canvasPixels = ctx.getImageData(0, 0, canvas.width, canvas.height).data; const tempCanvas = document.createElement('canvas'); tempCanvas.width = img.width; tempCanvas.height = img.height; const tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(img, 0, 0); const localPixels = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height).data; // 逐像素对比RGBA值 for (let i = 0; i < canvasPixels.length; i++) { if (canvasPixels[i] !== localPixels[i]) { resolve(false); return; } } resolve(true); }; img.onerror = reject; img.src = imageUrl; }); }
Blazor中调用:
var isEqual = await JS.InvokeAsync<bool>("compareCanvasAndLocalImage", "CanvasId", "/scripts/defaultImage.png");
方案3:预存原图片像素哈希到数据库
首次将图片存入数据库时,提前计算原图片的像素哈希并一同存储。日后从数据库取回图片加载到Canvas后,直接对比Canvas的像素哈希与数据库中存储的哈希值,无需每次读取本地文件。
内容的提问来源于stack exchange,提问作者Ben Junior
相关产品推荐
相关产品推荐

