7

Chrome auto-rotates any image from a file input drawn to a canvas based on it's exif data. This is great, but iOS doesn't do the same. Is there a way to prevent this behavior in so I can just transform the image myself. With a fix I wrote it works in iOS, disabling that fix works on Android ... would rather disable/enable then play the browser identifying game.

I've tried setting the style of the image to image-orientation: none; .... but that didn't do anything. Still rotated it.

Edit: I detected this by looking to see if the 'imageOrientation' on the style object was undefined or an empty string on a newly create img tag. Maybe not a perfect test, but it worked for my situations I tested. Not sure on how future proof it is.

Chase R Lewis
  • 2,119
  • 1
  • 22
  • 47
  • Have you had a chance to figure out from which version it auto rotates? – bks Apr 25 '20 at 09:18
  • 2
    It's since Chrome 81 @bks I basically detected this by looking to see if the stylesheet property of 'image-orientation' was undefined or an empty string by default on a newly created image. – Chase R Lewis Apr 28 '20 at 17:40
  • that's genius! Thank you – bks Apr 28 '20 at 19:56

5 Answers5

4

This should be future proof:

// returns a promise that resolves to true  if the browser automatically
// rotates images based on exif data and false otherwise
function browserAutoRotates () {
    return new Promise((resolve, reject) => {
        // load an image with exif rotation and see if the browser rotates it
        const image = new Image();
        image.onload = () => {
            resolve(image.naturalWidth === 1);
        };
        image.onerror = reject;
        // this jpeg is 2x1 with orientation=6 so it should rotate to 1x2
        image.src = 'data:image/jpeg;base64,/9j/4QBiRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAYAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAAITAAMAAAABAAEAAAAAAAAAAABIAAAAAQAAAEgAAAAB/9sAQwAEAwMEAwMEBAMEBQQEBQYKBwYGBgYNCQoICg8NEBAPDQ8OERMYFBESFxIODxUcFRcZGRsbGxAUHR8dGh8YGhsa/9sAQwEEBQUGBQYMBwcMGhEPERoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoa/8IAEQgAAQACAwERAAIRAQMRAf/EABQAAQAAAAAAAAAAAAAAAAAAAAf/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAF/P//EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAQUCf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEABj8Cf//EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAT8hf//aAAwDAQACAAMAAAAQH//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Qf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Qf//EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAT8Qf//Z';
    });
}

The only way to really find out for sure if the browser rotates based on exif data: Load up an image with exif ratation and see how it comes out.

JasonWoof
  • 4,176
  • 1
  • 19
  • 28
  • 1
    that's a good solution. I'd consider caching the result though so multiple calls don't trigger the image load after the first attempt, overall probably the best solution. – Chase R Lewis Jun 16 '20 at 17:08
  • :) yeah, I cached the promise in my project, just wanted to post the minimal example. – JasonWoof Jun 16 '20 at 17:36
  • This answer is probably correct, but too complicated. See matt burns' answer below for a simpler solution. This answer may be improved by adding that as an alternative. Please note that the famous Dropzone library uses something similar: `getComputedStyle(document.body)["imageOrientation"] == "from-image"`. – Jan Bradáč Mar 14 '21 at 18:27
  • Too complicated for what? The code simply loads an image and checks whether it got rotated or not. That should be pretty reliable and future proof. Some people may want to take a chance on the hackier solutions to save 1KiB of source code. I used this because I want my code to still work in 7 years without updates. – JasonWoof Mar 16 '21 at 22:30
3

This is due to an update in Chrome 81 that now has and respects the 'image-orientation' property. https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation

Chrome now defaults all images to 'from-image' meaning it will read the EXIF data to determine the rotation data of the image. Below is basically what I did to detect if the browser supports functionality like this since future versions of iOS and other browsers expect to do this also.

function browserImageRotationSupport(){
    let imgTag = document.createElement('img');
    return imgTag.style.imageOrientation !== undefined;
}
Chase R Lewis
  • 2,119
  • 1
  • 22
  • 47
  • 3
    This didn't work in Firefox. I found that the following code can detect if the browser automatically rotates images: `let browserAutoRotates = getComputedStyle(document.body)['imageOrientation'] == 'from-image';` – David Barnes May 05 '20 at 19:05
3

I was able to use this test to differentiate the browsers:

if (CSS.supports("image-orientation", "from-image")) {
    ...
}
matt burns
  • 24,742
  • 13
  • 105
  • 107
0
const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);

I use this snippet to check if it is IOS and only rotate the canvas ctx if it is IOS. I think older versions of android don't auto-rotate the image because I still have bugreports coming in from android users.

ThommyBE
  • 3
  • 2
  • Hey Thommy, I was able to detect this by checking the style.imageOrientation property of a newly created img tag that isn't mounted to the DOM . If it is undefined that means I'm in a version of Chrome that doesn't rotate it or on iOS. If it is an empty string than I don't rotate it since Chrome will handle that for me. – Chase R Lewis Apr 30 '20 at 21:36
0

Setting the CSS on the canvas element as opposed to the img will fix this if you're drawing to a canvas that is part of the DOM.

canvas {
    image-orientation: none;
}

As of writing the element has to be in the DOM because it uses the computed style. That only exists in a DOM context. You can read more in the issue on the Chromium tracker.

https://bugs.chromium.org/p/chromium/issues/detail?id=158753

Elle H
  • 11,837
  • 7
  • 39
  • 42