JavaScript如何检查图像是否存在截断/损坏的数据

15

我正在寻找如何检测图像数据是否被截断或损坏。例如,这张图片: enter image description here

图像数据不完整(在IE上更为明显,在Firefox控制台中有警告),但是img.onerror没有触发,img.completed为true。

演示:https://jsfiddle.net/7dd0ybb4/

var img = document.getElementById('MyPicture');

img.onerror = () => alert('error img');  
img.onload = () =>  console.log(img.complete); //true

img.src = "https://istack.dev59.com/nGkok.webp";

我希望能够知道如何判断一张图片是否存在无效数据。


原因是因为图片已经完全加载,且不是损坏的图片。如果网络活动中断,则会触发onerror事件。 - Akhil Arjun
@AkhilArjun,不是在寻找什么,而是如何做到。 - dovid
@lomed,你找到方法了吗? - Pradip Vaghasiya
@PradipVaghasiya 是的。 - dovid
谢谢兄弟。 :) ;) - rossanmol
显示剩余7条评论
3个回答

8
您可以将图像解码为字节数组:
var src = 'here comes your base64 data'
var imageData = Uint8Array.from(atob(src.replace('data:image/jpeg;base64,', '')), c => c.charCodeAt(0))

JPEG必须以字节FF D8开头,以FF D9结尾,因此我们检查创建的数组缓冲区的最后两个元素是否为255和217。请参见实时示例。
var imageCorrupted = ((imageData[imageData.length - 1] === 217) && (imageData[imageData.length - 2] === 255));

我们可以使用类似的检查方法来验证PNG文件(现场示例),其中以IEND块结尾并包含以下字节序列:
// in hex: 00 00 00 00 49 45 4e 44 ae 42 60 82
var sequence = [0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];

它对于此src不起作用(https://0bin.net/paste/VkxPPlgc9DWme4gw#jqp+X4qoIxlQi91s-mzMbW0S4INdxlMgcBZC5ek3kda),因为`imageCorrupted == false`。 - BuZZ-dEE
BMP格式怎么样? - carestad
在这里要小心解决方案。EOI字节(即255、217)并不总是出现在最后两个字节。大多数编码器通常会在EOI字节之后丢弃数据。 - Ravi Ranjan

4
你可以像下面这样使用canvas检查损坏的像素:

你可以通过以下代码使用canvas来检查损坏的像素

var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
    ctx.drawImage(img,0,0);
    var height=this.height;
    var width=this.width;
    var hCenter=Math.round(width/2);
    var corruptedRowsCount=0;
    for(var row=height;row>0;row--){
      var c = ctx.getImageData(hCenter, row, 1, 1).data;
      if(c[0]==0 && c[1]==0 && c[2]==0 && c[3]==0)
          corruptedRowsCount++;
      else 
          break;
    }
    console.log(Math.round(corruptedRowsCount*100/height)+" precent of image is corrupted");
};

img.src="data:image/jpeg;base64,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";
<canvas id="canvas">


+1 非常好!但仍然不是完整的答案。因为你的解决方案假设透明像素无效,这对JPG格式是正确的,但对于PNG格式却不是。请参见https://jsfiddle.net/7L01yfb2/1/。而且这张图片的数据是100%有效的。 - dovid
1
我改进了它 https://jsfiddle.net/7L01yfb2/7/,但这个解决方案对于 PNG 不完整。 - fingerpich

3
对于png文件,我决定需要一个更全面的解决方案,而不是仅检查文件的头部和尾部是否有效。我想要一种实际利用png文件内每个块嵌入的crc代码来检测文件所有数据完整性的解决方案。
幸运的是,我找到了一个成熟的库: https://github.com/lukeapage/pngjs 不幸的是,它有点大。浏览器版本将近500 kb。这是一个功能齐全的png文件处理库,这也就可以理解。如果您需要使用所有这些功能,则可能需要为其大小付费。但对于只想要验证png文件的简单用例而言,它太重了。
因此,我从中提取出验证代码,并制作了一个只包含验证代码的简单2.5 kb npm包: https://www.npmjs.com/package/png-validator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接