3

I need a solution for previewing images with the right EXIF orientation before uploading with XMLHttpRequest or ajax. I've been able to preview the image and correct the orientation on an iPhone OR submit it via XMLHttpRequest, but not both at the same time.

Please feel free to suggest other solution that accomplishes this:

Allow the user to use an iPhone/Android to preview an image with the right orientation and extract the image's EXIF info before uploading it

I'm using Fengyuan Chen's exif.js with the following code:

HTML

<form action="upload.php" id="form" method="POST" enctype="multipart/form-data">
 <div class="docs-preview docs-dropzone">
  <input id="upload" type="file" name="file" accept="image/*" />
    <label for="upload">
     <div id="image-preview"><img src="../_images/upload.svg"></div>
    </label>
  <button id='btn'>Upload</button>
 </div>
</form>

<script src="jquery-2.2.4.min.js"></script>
<script src="1.9.2/jquery-ui.min.js"></script>
<script src="exif.js"></script>
<script src="main.js"></script>

main.js

const ORIENT_TRANSFORMS = {
    1: '',
    2: 'rotateY(180deg)',
    3: 'rotate(180deg)',
    4: 'rotate(180deg) rotateY(180deg)',
    5: 'rotate(270deg) rotateY(180deg)',
    6: 'rotate(90deg)',
    7: 'rotate(90deg) rotateY(180deg)',
    8: 'rotate(270deg)'
}
function getOrientation( file ) {
  return new Promise( ( resolve, reject ) => {
      const reader = new FileReader();
      reader.onerror = reject
      reader.onload = ( { target } ) => {
          try {
              const view = new DataView( target.result ),
                    length = view.byteLength
              let offset = 2
              if( view.getUint16(0, false) != 0xFFD8 ) {
                  return reject( new Error( 'File is not a .jpeg' ) )
              }
              while( offset < length ) {
                  const marker = view.getUint16( offset, false )
                  offset += 2;
                  if (marker == 0xFFE1) {
                      if( view.getUint32( offset += 2, false ) != 0x45786966 ) {
                          return resolve()
                      }
                      const little = view.getUint16(offset += 6, false) == 0x4949
                      offset += view.getUint32(offset + 4, little)
                      const tags = view.getUint16(offset, little)
                      offset += 2
                      for( var i = 0; i < tags; i++ ) {
                          if( view.getUint16( offset + ( i * 12 ), little ) == 0x0112 ) {
                              return resolve( view.getUint16( offset + ( i * 12 ) + 8, little ) )
                          }
                      }
                  } else if( ( marker & 0xFF00 ) != 0xFF00 ) {
                      break;
                  } else {
                      offset += view.getUint16( offset, false )
                  }
              }
              return resolve()
          } catch( err ) {
              return reject( err )
          }
      };
      reader.readAsArrayBuffer( file.slice( 0, 64 * 1024 ) );
  } )
}
window.onload = function () {
  'use strict';
  var Exif = window.Exif;
  var URL = window.URL || window.webkitURL;
  var preview = document.getElementsByClassName('docs-preview')[0];
  var dropzone = document.getElementsByClassName('docs-dropzone')[0];
  var fileInput = dropzone.getElementsByTagName('input')[0];
  var options = {
        done: function (tags) {
          var segments = [];
          var tag;
          for (tag in tags) {
            if (tags.hasOwnProperty(tag)) {
              if (tag == 'Orientation') {
                var orientation = tags[tag];
                console.log(+orientation);
                img.style.transform = ORIENT_TRANSFORMS[ getOrientation(fileInput) ];
              }
            }
          }
        },
        fail: function (message) {
          console.log(message);
        }
      };
  function readExif() {
    return new Exif(preview.getElementsByTagName('img')[0], options);
  }
  function readExifFromFile(file) {
    var image;
    if (file.type === 'image/jpeg') {
      if (URL) {
        image = new Image();
        image.onload = function () {
          this.onload = null;
          URL.revokeObjectURL(file);
        };
        image.src = URL.createObjectURL(file);
        // Clear existing image
        preview.innerHTML = '';
        preview.appendChild(image);
      }
      // Clear chosen file
      fileInput.value = '';
      return new Exif(file, options);
    } else {
      window.alert('Por favor envie uma imagem JPEG.');
    }
  }
  readExif();
  fileInput.onchange = function (e) {
    var files = e.target.files;
    if (files && files.length) {
      readExifFromFile(files[0]);
    }
  };
  dropzone.ondragover = function (e) {
    e.preventDefault();
  };
  dropzone.ondrop = function (e) {
    var files = e.dataTransfer.files;

    e.preventDefault();

    if (files && files.length) {
      readExifFromFile(files[0]);
    }
  };
};
var $formUpload = document.getElementById('form'),
    $preview = document.getElementById('btn'),
    i = 0;

$formUpload.addEventListener('submit', function(event){
  event.preventDefault();
  var xhr = new XMLHttpRequest();
  xhr.open("POST", $formUpload.getAttribute('action'));
  var formData = new FormData($formUpload);
  formData.append("i", i++);
  xhr.send(formData);
  xhr.addEventListener('readystatechange', function() {
    if (xhr.readyState === 4 && xhr.status == 200) {
      var json = JSON.parse(xhr.responseText);
      if (!json.error && json.status === 'ok') {
        $preview.innerHTML += 'File sent!';
      } else {
        $preview.innerHTML = 'File not sent';
        console.log(json.error);
      }
    } else {
      $preview.innerHTML = xhr.statusText;
    }
  });
  xhr.upload.addEventListener("progress", function(e) {
    if (e.lengthComputable) {
      var percentage = Math.round((e.loaded * 100) / e.total);
      $preview.innerHTML = String(percentage) + '%';
    }
  }, false);
  xhr.upload.addEventListener("load", function(e){
    $preview.innerHTML = String(100) + '%';
  }, false);
}, false);

upload.php

<?php
date_default_timezone_set('America/Sao_Paulo');
$dir = 'upload/';
$today = date('Y-m-d');
 if (isset($_FILES['file'])) {
    $name = $_FILES['file']['name'];
    $tmp_name = $_FILES['file']['tmp_name'];
    $path = $_FILES['file']['name'];
    $extension = pathinfo($path, PATHINFO_EXTENSION);
    if ($extension == 'jpeg') {
      $ext = '.jpg';
    } else {
      $ext = strtolower(substr($_FILES['file']['name'],-4));
    }
    $new_name = $today."_"."01".$ext;
    $error = $_FILES['file']['error'];
    if ($error !== UPLOAD_ERR_OK) {
        $ret = 'Upload error:'. $error;
    } elseif (move_uploaded_file($tmp_name, $dir . $new_name)) {
        $ret = array('status' => 'ok');  
    }
} else {
    header('Content-Type: application/json');
    $ret = array('error' => 'no_file');
    echo json_encode($ret);
    exit;
} ?>

I can preview the image correctly on my iPhone but have been getting the message "no_file" on the console. Or I can upload the file when disabling the EXIF preview.

Any ideas? Thanks in advance!

Vini Goulart
  • 91
  • 1
  • 5

0 Answers0