使用EXIF旋转校正进行多图片上传

时间:2018-05-02 12:52:47

标签: asynchronous base64 blob

希望有人可以帮忙吗?我在FileReader,Blobs,Base64和EXIF上阅读了很多SE帖子,并拼凑了一些就在那里的东西。我在理解异步函数的结构和过程中的顺序/延迟时遇到了问题。

下面的脚本从多部分表单循环上传的数组。在循环中,我有readAsDataURL来获取Base64 String,然后在转换画布之前尝试readAsArrayBuffer从Blob获取EXIF方向代码。

我显然混淆了异步并且有点迷失。

在此阶段它显示图像(并正确定位第一个)但不读取新的EXIF方向,然后所有图像都旋转相同(可能是因为ArrayBuffer不同步?)。如果我一次上传更多图像,则会出现一些重复,这也是同步问题....

$(document).on('change', '#files', function(evt){
var files = evt.target.files;
var readerBase64;
var b64 = [];
var ab = [];
var c=0;
for (var i = 0; f = files[i]; i++) {
    console.log('LOOP');
    var blob = f;
    var readerBase64 = new FileReader(); 
    readerBase64.onload = function(evt){
        // console.log('BASE 64 ' + evt.target.result);
        b64.push(evt.target.result);
        var reader = new FileReader(); 
         reader.onloadend = (function(theFile) {
            console.log(this);
            console.log('READER');
             return function(e) {
                console.log('RETURN');
                ab.push(e.target.result);
                 console.log(ab[c]);

                 var view = new DataView(ab[c]);
                  ori = 1;
                    if (view.getUint16(0, false) != 0xFFD8){ori = -2};

                    var length = view.byteLength,
                        offset = 2;

                    while (offset < length) {
                      var marker = view.getUint16(offset, false);
                      offset += 2;

                      if (marker == 0xFFE1) {
                        if (view.getUint32(offset += 2, false) != 0x45786966) {
                          ori = -1;
                        }
                        var little = view.getUint16(offset += 6, false) == 0x4949;
                        offset += view.getUint32(offset + 4, little);
                        var tags = view.getUint16(offset, little);
                        offset += 2;

                        for (var i = 0; i < tags; i++)
                     if (view.getUint16(offset + (i * 12), little) == 0x0112)
                           ori = view.getUint16(offset + (i * 12) + 8, little);
                      }
                      else if ((marker & 0xFF00) != 0xFF00) break;
                      else offset += view.getUint16(offset, false);
                    }      
                 console.log('ori '+ori);
 //    console.log(b64[c]);

                    base64String = b64[c];
                    var img = document.createElement('img');

                    img.setAttribute('src',base64String);
                    //img.src = e.target.result;
                    img.onload = function () {
                    var canvas = document.createElement('canvas');

                    var MAX_WIDTH =1000;
                    var MAX_HEIGHT =800;
                    var width = img.width;
                    var height = img.height;

                    if (width > height) {
                      if (width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                      }
                    } else {
                      if (height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                      }
                    }
                    canvas.width = width;
                    canvas.height = height;
                    var ctx = canvas.getContext("2d");


                    // set proper canvas dimensions before transform & export
                    if (4 < ori && ori < 9) {
                    canvas.width = height;
                    canvas.height = width;
                    } else {
                    canvas.width = width;
                      canvas.height = height;
                    }

                    // transform context before drawing image
                        switch (ori) {
                      case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
                      case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;
                      case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;
                      case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
                      case 6: ctx.transform(0, 1, -1, 0, height , 0); break;
                      case 7: ctx.transform(0, -1, -1, 0, height , width); break;
                      case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
                      default: break;
                    }                       

                    ctx.drawImage(img, 0, 0, width, height);

                    var dataurl = canvas.toDataURL("image/jpg");

                    //alert(dataurl);
                     // Render thumbnail.
                     var span = document.createElement('span');
                    //var ii = $('#list span').length - 2;
                    // if(ii > 0){
                    //  span.setAttribute('class','hide');
                    //  $('#list span:nth-child(3) p').text("+"+ii);
                    //  }

                      span.innerHTML = 
                      [
                        '<input type="image" class="thumb" name="imgs[]" value="', 
                        dataurl,
                        '" src="', dataurl, 
                        '"/>'
                      ].join('');

                      document.getElementById('list').insertBefore(span, null);                  

                      c++;  
                 }
             }
         })(f);         
         reader.readAsArrayBuffer(blob.slice(0, 64 * 1024));
    }
    readerBase64.readAsDataURL(f);
    //      console.log(f);
 }

}); //文件更改

1 个答案:

答案 0 :(得分:1)

我已经解决了,但也许不是很优雅。已上载,已调整大小和方向更正的图像将添加到名为#list的元素中的表单中,以便发布到服务器。以下是其他任何人的代码:

$(document).on('change', '#files', function(evt){
var files = evt.target.files;
var f;
for (var i = 0; f = files[i]; i++) {
    var blob = f;
    getOrientation(f, function(ori , f) {
        console.log(f);
        var readerBase64 = new FileReader(); 
        readerBase64.onload = function(evt){

            console.log(ori);
            console.log(evt.target.result);
            base64String = evt.target.result;
            var img = document.createElement('img');

            img.setAttribute('src',base64String);
            //img.src = e.target.result;
            img.onload = function () {
            var canvas = document.createElement('canvas');

            var MAX_WIDTH =1000;
            var MAX_HEIGHT =800;
            var width = img.width;
            var height = img.height;

            if (width > height) {
              if (width > MAX_WIDTH) {
                height *= MAX_WIDTH / width;
                width = MAX_WIDTH;
              }
            } else {
              if (height > MAX_HEIGHT) {
                width *= MAX_HEIGHT / height;
                height = MAX_HEIGHT;
              }
            }
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext("2d");


            // set proper canvas dimensions before transform & export
            if (4 < ori && ori < 9) {
            canvas.width = height;
            canvas.height = width;
            } else {
            canvas.width = width;
              canvas.height = height;
            }

            // transform context before drawing image
                switch (ori) {
              case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
              case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;
              case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;
              case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
              case 6: ctx.transform(0, 1, -1, 0, height , 0); break;
              case 7: ctx.transform(0, -1, -1, 0, height , width); break;
              case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
              default: break;
            }                       

            ctx.drawImage(img, 0, 0, width, height);

            var dataurl = canvas.toDataURL("image/jpg");

            //alert(dataurl);
             // Render thumbnail.
             var span = document.createElement('span');
            //var ii = $('#list span').length - 2;
            // if(ii > 0){
            //  span.setAttribute('class','hide');
            //  $('#list span:nth-child(3) p').text("+"+ii);
            //  }

              span.innerHTML = 
              [
                '<input type="image" class="thumb" name="imgs[]" value="', 
                dataurl,
                '" src="', dataurl, 
                '"/>'
              ].join('');

              document.getElementById('list').insertBefore(span, null);             

            }

        };
        readerBase64.readAsDataURL(f);
    });
   }
});

使用我在这里发现的一个小改动的功能,将文件Blob与回调中的方向一起发回:

 //from http://stackoverflow.com/a/32490603
function getOrientation(file, callback) {
  var reader = new FileReader();

  reader.onload = function(event) {
    var view = new DataView(event.target.result);

    if (view.getUint16(0, false) != 0xFFD8) return callback(-2, file);

    var length = view.byteLength,
        offset = 2;

    while (offset < length) {
      var marker = view.getUint16(offset, false);
      offset += 2;

      if (marker == 0xFFE1) {
        if (view.getUint32(offset += 2, false) != 0x45786966) {
          return callback(-1 , file);
        }
        var little = view.getUint16(offset += 6, false) == 0x4949;
        offset += view.getUint32(offset + 4, little);
        var tags = view.getUint16(offset, little);
        offset += 2;

        for (var i = 0; i < tags; i++)
          if (view.getUint16(offset + (i * 12), little) == 0x0112)
            return callback(view.getUint16(offset + (i * 12) + 8, little) , file);
      }
      else if ((marker & 0xFF00) != 0xFF00) break;
      else offset += view.getUint16(offset, false);
    }
    return callback(-1 , file);
  };

  reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
};

上传的解决方案是拦截帖子并使用AJAX和JQuery从输入构建POST数据[type =&#39; image&#39;]

    $(document).on('submit',function(e){
    e.preventDefault();
    var data = $('#formFeed').serializeArray(); 
        var msg = $('textarea').val();
        data.push({name: 'msg', value: msg});
        var y;
        $('input[type="image"]').each(function(i, obj) {
            y = $(this).attr('src');
            data.push({name: 'img', value: y});
        });

        $.ajax({
            cache: false,
            type : 'POST',
            url  : 'http://localhost:3001/newFeed', 
            data: data,
            contentType: "application/x-www-form-urlencoded",
            success : function(data) {
                console.log(data);
            }
        }); 

});