从图像中删除EXIF数据

20

我如何通过JavaScript从上传的图像中删除EXIF数据?我目前可以使用这个exif-js插件访问EXIF数据,就像这样:

EXIF.getData(oimg, function() {
    var orientation = EXIF.getTag(this, "Orientation");
});

然而,我并没有找到任何实际删除Exif数据的方法,只能检索它。

更具体地说,我正在尝试这样做是为了摆脱方向Exif数据,在某些浏览器上旋转我的图像。


@alex 目前似乎无法使用 PHP 完成此任务。即使没有本地 JavaScript 函数可以实现,插件也是可以接受的。我该如何编辑我的问题以使其更加具体? - Praxis Ashelin
@alex,即使使用nodejs,你也不需要用JS来处理这个问题,情况并没有那么极端。即使这个问题与此无关。 - fejese
2个回答

27

这是一个小演示,选择带有方向数据的图像,查看它在有或没有该数据的情况下的展示效果(仅限现代浏览器)。

http://jsfiddle.net/mowglisanu/frhwm2xe/3/

var input = document.querySelector('#erd');
input.addEventListener('change', load);
function load(){
    var fr = new FileReader();
    fr.onload = process;
    fr.readAsArrayBuffer(this.files[0]);
    document.querySelector('#orig').src = URL.createObjectURL(this.files[0]);
}
function process(){
    var dv = new DataView(this.result);
    var offset = 0, recess = 0;
    var pieces = [];
    var i = 0;
    if (dv.getUint16(offset) == 0xffd8){
        offset += 2;
        var app1 = dv.getUint16(offset);
        offset += 2;
        while (offset < dv.byteLength){
            //console.log(offset, '0x'+app1.toString(16), recess);
            if (app1 == 0xffe1){

                pieces[i] = {recess:recess,offset:offset-2};
                recess = offset + dv.getUint16(offset);
                i++;
            }
            else if (app1 == 0xffda){
                break;
            }
            offset += dv.getUint16(offset);
            var app1 = dv.getUint16(offset);
            offset += 2;
        }
        if (pieces.length > 0){
            var newPieces = [];
            pieces.forEach(function(v){
                newPieces.push(this.result.slice(v.recess, v.offset));
            }, this);
            newPieces.push(this.result.slice(recess));
            var br = new Blob(newPieces, {type: 'image/jpeg'});
            document.querySelector('#mod').src = URL.createObjectURL(br);
        }
    }       
}
img{
    max-width:200px;
}
<input id="erd" type="file"/><br>
<img id="orig" title="Original">
<img id="mod" title="Modified">


3
有没有一种方法可以用数字1替换方向而不是删除所有的exif数据?@Musa - danial
1
@danial 确实,你只需要知道方向数据在哪里,并在数据视图中设置值,就像 dataview.setUint16(orientationOffset, newValue) 这样。 - Musa
1
查找文件格式和exif格式。 - Musa
你好,我尝试将你的代码适应到另一件事情上。你介意解释一下这些代码(0xffd8和0xffda)是用来做什么的吗?因为我的Jpeg肯定是不同的代码... - Silom
1
我只是把它变成了一个问题。这里可能有一个错误:http://stackoverflow.com/questions/41490122/strip-exif-data-from-image-node-js-addressing-a-possible-bug-in-the-original-v - jcalfee314
显示剩余8条评论

0

从图像中删除EXIF数据。

EXIF数据仅存在于TIFF、JPEG(JPG)和HEIC格式的图像中,而不包含在png和gif图像中。

首先,让我们了解图像包含的内容。

图像的内容

图像缓冲区包含一个头部(2个字节)+数据。

数据部分包含许多段,每个段都包含一个头部(2个字节)+数据。

段的长度在数据的第一个字节中表示(或在段开始后的2个字节之后)。

Exif缓冲段以'0xFFE1'开头

[头部=标记]

删除EXIF数据的步骤

  1. 将图像读取为缓冲区
  2. 遍历每个段
  3. 如果一个段包含EXIF数据,则删除该段

下面的代码是TS(只需删除类型,它将在js中工作)

const cleanBuffer = (arrayBuffer: ArrayBuffer) => {
  let dataView = new DataView(arrayBuffer);
  const exifMarker = 0xffe1;
  let offset = 2; // Skip the first two bytes (0xFFD8)

  while (offset < dataView.byteLength) {
    if (dataView.getUint16(offset) === exifMarker) {
      // Found an EXIF marker
      const segmentLength = dataView.getUint16(offset + 2, false) + 2;

      // Update the arrayBuffer and dataView
      arrayBuffer = removeSegment(arrayBuffer, offset, segmentLength);
      dataView = new DataView(arrayBuffer)
    } else {
      // Move to the next marker
      offset += 2 + dataView.getUint16(offset + 2, false);
    }
  }

  return arrayBuffer;
};

const removeSegment = (buffer: ArrayBuffer, offset: number, length: number) => {
  // Create a new buffer without the specified segment
  const modifiedBuffer = new Uint8Array(buffer.byteLength - length);
  modifiedBuffer.set(new Uint8Array(buffer.slice(0, offset)), 0);
  modifiedBuffer.set(new Uint8Array(buffer.slice(offset + length)), offset);

  return modifiedBuffer.buffer;
};
const removeExifData = (file: File): Promise<File> => {
  return new Promise((resolve) => {
    if (file && file.type.startsWith('image/')) {
      const fr = new FileReader();
      fr.onload = function (this: FileReader) {
        const cleanedBuffer = cleanBuffer(this.result as ArrayBuffer);
        const blob = new Blob([cleanedBuffer], { type: file.type });
        const newFile = new File([blob], file.name, { type: file.type });
        resolve(newFile);
      };
      fr.readAsArrayBuffer(file);
    } else resolve(file);
  });
};


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