igneosaur igneosaur - 6 months ago 19
Node.js Question

How can I get my Express app to respect the Orientation EXIF data on upload?

I have an Express application that uses multer to upload images to an S3 bucket. I'm not doing anything special, just a straight upload, but when they are displayed in the browser some of the iPhone images are sideways.

I know this is technically a browser bug and Firefox now supports the

rule, but Chrome still displays the images on their side.

Is there a way I can have Express read the EXIF data and just rotate them before uploading?

Answer

Right, I figured it out. I used a combination of JavaScript Load Image and the FormData API.

First I'm using Load Image to get the orientation of the image from the exif data and rotating it. I'm then converting the canvas output that Load Image provides and converting that to a blob (you may also need the .toBlob() polyfill for iOS as it does not support this yet.

That blob is then attached to the FormData object and I'm also putting it back in the DOM for a file preview.

// We need a new FormData object for submission.
var formData = new FormData();

// Load the image.
loadImage.parseMetaData(event.target.files[0], function (data) {
  var options = {};

  // Get the orientation of the image.
  if (data.exif) {
    options.orientation = data.exif.get('Orientation');
  }

  // Load the image.
  loadImage(event.target.files[0], function(canvas) {
    canvas.toBlob(function(blob) {
      // Set the blob to the image form data.
      formData.append('image', blob, 'thanksapple.jpg');
      // Read it out and stop loading.
      reader.readAsDataURL(blob);

      event.target.labels[0].innerHTML = labelContent;
    }, 'image/jpeg');
  }, options);

  reader.onload = function(loadEvent) {
    // Show a little image preview.
    $(IMAGE_PREVIEW).attr('src', loadEvent.target.result).fadeIn();
    // Now deal with the form submission.
    $(event.target.form).submit(function(event) {
      // Do it over ajax.
      uploadImage(event, formData);
      return false;
    });
  };
});

Now for the uploadImage function which I'm using jQuery's AJAX method for. Note the processData and contentType flags, they are important.

function uploadImage(event, formData) {
  var form = event.target;

  $.ajax({
    url: form.action,
    method: form.method,
    processData: false,
    contentType: false,
    data: formData
  }).done(function(response) {
    // And we're done!
  });

  // Remove the event listener.
  $(event.target).off('submit');
}

All the info is out there but it's spread across multiple resources, hopefully this will save someone a lot of time and guessing.