【问题标题】:Multi image upload with EXIF rotation correction带 EXIF 旋转校正的多图像上传
【发布时间】:2018-10-12 14:14:02
【问题描述】:

希望有人能提供帮助吗?我已经阅读了一些关于 FileReader、Blobs、Base64 和 EXIF 的 SE 帖子,并拼凑了一些即将发布的内容。我在理解异步函数的结构和过程中的顺序/延迟时遇到问题。

下面的脚本循环遍历来自多部分表单的上传数组。在循环中,我使用 readAsDataURL 获取 Base64 字符串,然后尝试 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);
 }

}); // 文件变化

【问题讨论】:

    标签: asynchronous base64 blob


    【解决方案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));
    };
    

    上传的解决方案是截取post并使用AJAX和JQuery从input[type='image']构建POST数据

        $(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);
                }
            }); 
    
    });
    

    【讨论】:

    • 所以为了安全起见,我不能只在输入标签中上传 Base64 字符串或 blob。如何上传数组、base64 或 blob?
    • 已更新上传解决方案。
    猜你喜欢
    • 2016-06-02
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 2018-10-21
    • 2011-11-04
    • 1970-01-01
    • 2015-03-30
    • 2020-08-12
    相关资源
    最近更新 更多