Skip to content
This repository has been archived by the owner. It is now read-only.

Image rotation after upload #3530

Closed
includebrasil opened this issue Nov 7, 2019 · 18 comments
Closed

Image rotation after upload #3530

includebrasil opened this issue Nov 7, 2019 · 18 comments

Comments

@includebrasil
Copy link

includebrasil commented Nov 7, 2019

Hello,

I saw some issues with rotating images after uploading, and realized that most are old issues! I have the same problem, I need to insert some code snippet or just the setting that exists in the script is enough. I use the default script setting.

I honestly do not know what to do!

In the script example the image appears normal:
https://monosnap.com/file/aKGbooVXUWKXGeiP1i2UXVVAa470l1

In my script the image is rotated:
https://monosnap.com/file/ofrTpAIDXWvUNMxhmuNy0CSu1YUsVD

Any suggestion?

@blueimp
Copy link
Owner

blueimp commented Nov 10, 2019

Hi @includebrasil ,

rotation of images has two aspects:

  • The orientation of the pixel data in the image
  • The orientation information stored in image headers, usually EXIF

If you make a picture with your camera, one in landscape and one in portrait mode, the camera stores both of them in the same pixel format, let's assume in an aspect ratio of 4:3.
The portrait mode picture however has added meta info (EXIF orientation) that tells any viewer software to rotate the picture accordingly when displaying it.

When using jQuery File Upload, it gets more complex, due to the following aspects:

  • Browsers using the EXIF info to rotate images when viewed in their own tab/window
  • JavaScript code to automatically rotate the preview images based on the EXIF info
  • JavaScript code to automatically rotate and override the original images (not enabled by default)
  • Server-side code to automatically rotate images (enabled in the example PHP version, not available in the example Golang/Python App Engine versions)

If you enable client-side image re-orientation for the original images, but keep the meta-data intact, you might have a mismatch between image data and EXIF orientation.
If you remove the image meta-data (including EXIF) but don't re-orient the images, you will also have a mismatch between the orientation of the image data and the actual orientation of the picture.

So my advice is to look into all of these aspects and then apply the appropriate configs according to your setup and requirements.

Please also kindly note that this issue tracker is not meant for support-requests:

This project is actively maintained, but there is no official support channel.
If you have a question that another developer might help you with, please post to Stack Overflow and tag your question with blueimp jquery file upload.
https://github.com/blueimp/jQuery-File-Upload#support

@blueimp
Copy link
Owner

blueimp commented Feb 17, 2020

Closing this as support request.

@blueimp blueimp closed this as completed Feb 17, 2020
@mjau-mjau
Copy link

mjau-mjau commented May 21, 2020

Sorry for re-opening this issue, but there is a fundamental flaw in the auto-rotate feature, especially now in 2020 that many browsers support EXIF rotation, also for inline images.

My main question is: When you rotate an image with jQuery-File-Upload, is there no way to simultaneously correct the rotation value that is stored in the EXIF meta data?

As it works now:

  1. Image with EXIF rotation gets uploaded.
  2. Rotation is corrected by jQuery-File-Upload.
  3. EXIF orientation values remain intact, and are now wrong.
  4. Since many browsers now read the EXIF rotation value, images will display incorrectly rotated.

Furthermore, let's say we want to rotate images and/or create thumbnails in PHP, based on the EXIF orientation value. PHP will now attempt to rotate the image based on EXIF rotation, but it has no idea that the image is already rotated. The result will be a duplicate rotation, causing more havoc. There is no way for PHP to know now what the correct orientation of the image is.

Server orientation
Just for reference, as I'm sure you know, if an image is rotated in PHP (based on EXIF), it will also auto-correct the orientation value stored in the image EXIF. This is of course the optimal solution.

disableImageMetaDataSave
Of course, one could bypass the effect if setting disableImageMetaDataSave to true, but this is not productive. Website galleries will often want to use the EXIF and IPTC from the image.

imageOrientation false
One could also disable imageOrientation, but that would basically be on the premise that it really doesn't work properly. Would definitely be most optimal to rotate an image on upload, instead of rotating it on server, which requires a JPG to be re-compressed.

So the question remains, is it not possible to correct the EXIF orientation value after rotate? If so, surely there is no reason to not do this.

@blueimp
Copy link
Owner

blueimp commented May 21, 2020

Hi Karl,

my answer above is somewhat out-of-date, since jQuery File Upload does update the EXIF orientation value after auto-rotation since version 10.12.0, or more specifically, since commit f9550f8.

The specific code is here:

if (data.orientation && data.exifOffsets) {
// Reset Exif Orientation data:
loadImage.writeExifData(data.imageHead, data, 'Orientation', 1);
}

Since image orientation is part of blueimp-load-image, the documentation for this feature is here:
https://github.com/blueimp/JavaScript-Load-Image/blob/master/README.md#exif-writer

@mjau-mjau
Copy link

mjau-mjau commented May 21, 2020

Oh wow, indeed. I was testing from 10.8.0. Thanks, and great job with everything!

@blueimp
Copy link
Owner

blueimp commented May 21, 2020

Thanks! ☺️

@mjau-mjau
Copy link

mjau-mjau commented May 30, 2020

I think I came across a bug, possibly new: When imageOrientation is set to false and resize is enabled, it will still rotate the uploaded image based on EXIF orientation. However, in this case, the EXIF orientation value is not corrected in the resulting upload (which would be correct, except it shouldn't be rotating in the first place).

When imageOrientation is set to false, shouldn't it NOT rotate the image, regardless of resize option? Thanks.

For the record, I discovered this because our app has an option to 1. rotate on upload (jQuery-File-Upload), or 2. Rotate by PHP after upload. In the case option 2 is selected, imageOrientation is disabled in jQuery-File-Upload options. However, I noticed that the image first got rotated on upload (by jQuery-File-Upload), with original image orientation remains in Exif, causing PHP to rotate the file based on EXIF, on top of the initial rotation.

In the case imageOrientation is enabled, everything works perfectly: jQuery-File-Upload will rotate the image, and also correct EXIF orientation values.

@Sherbert99
Copy link

Sherbert99 commented Jun 2, 2020

I agree with mjau-mjau. I am having the same problem. For some reason when imageOrientation is set to false and disableImageResize is false, the uploaded image is getting rotated.

Any idea how to fix this?

@blueimp
Copy link
Owner

blueimp commented Jun 8, 2020

@mjau-mjau and @Sherbert99:

imageOrientation:false only disables the image orientation functionality applied by the library, but not the automatic image orientation by the browser.

Unfortunately as of now, it is not possible to disable the browser image orientation for images loaded outside of the DOM, see my related comment here: w3c/csswg-drafts#4666 (comment)

What you can do is instruct the library to re-orient auto-oriented images back to their original orientation with the setting imageOrientation:1.

See also the orientation documentation for the underlying blueimp-load-image library here:
https://github.com/blueimp/JavaScript-Load-Image/blob/master/README.md#orientation

@mjau-mjau
Copy link

mjau-mjau commented Jun 8, 2020

@blueimp I must object. I am not talking about https://caniuse.com/#feat=css-image-orientation, which most browsers now do automatically. Besides, you can prevent the browser from automatically orienting image to EXIF by using CSS image-orientation: none; on the <img> tag https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation.

I'm saying that jQuery-File-Upload actually rotates the image physically, even when imageOrientation:false.

imageOrientation:false only disables the image orientation functionality applied by the library, but not the automatic image orientation by the browser.

That is not the case though. The library is applying orientation even when imageOrientation:false, regardless of browser applying or not applying orientation from EXIF.

Would be happy to create a test case. For the record, I have been developing www.photo.gallery for 15 years, and I know all the problematics involved with image orientation. I was very glad to see that JFU now corrects the EXIF tag after it rotates the image. However, it is still rotating the image now with imageOrientation:false. Great lib!

@mjau-mjau
Copy link

mjau-mjau commented Jun 8, 2020

Or maybe there is something I am not aware of after reading your post on w3c. Seems very strange if this is the case. Basically it means it's not feasible to use imageOrientation:false, because JFU will do it anyway. If set to false, the issue becomes worse, because it won't even update the EXIF in the resulting image ... Only solution is to always force imageOrientation:true.

@blueimp
Copy link
Owner

blueimp commented Jun 8, 2020

@blueimp I must object. I am not talking about https://caniuse.com/#feat=css-image-orientation, which most browsers now do automatically. Besides, you can prevent the browser from automatically orienting image to EXIF by using CSS image-orientation: none; on the tag https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation.

This is only true for images loaded inside of the DOM, as CSS is simply not applied to img elements outside of the DOM and is exactly what the comment I already linked above is referring to: w3c/csswg-drafts#4666 (comment)

My comment there also includes a link to a test page that showcases the browser behaviors for img and canvas elements constructed in and outside of the DOM:
https://image-orientation-test.now.sh/

The library is applying orientation even when imageOrientation:false, regardless of browser applying or not applying orientation from EXIF.

If you're scaling images, the library has to draw them to a canvas and then create Blob objects from the resulting image pixel data.
With automatic browser image orientation (which is now enabled in the latest versions of Chrome, Firefox and Safari), this means that unless you reset the image orientation to the original orientation with imageOrientation:1, the resulting pixel data in a scaled image will be that of an automatically oriented one.

@mjau-mjau
Copy link

mjau-mjau commented Jun 8, 2020

Hmmm, I think I get it 🤔 So basically, JFU has no idea about the image-orientation when it's loaded into canvas, image-orientation: none does not apply, and then the resized image will simply inherit the rotation of the image as displayed in Canvas?

With this in mind, you would have to agree that imageOrientation:false makes little sense now? Essentially, at least in most new browsers, it leads to images being oriented from EXIF on resize, while original EXIF orientation values remain in the image, now incorrect. This means it's impossible to create a resized (thumbnail) image from the uploaded image, because the PHP doesn't know if it can rely on the EXIF orientation or not.

@blueimp
Copy link
Owner

blueimp commented Jun 8, 2020

Hmmm, I think I get it 🤔 So basically, JFU has no idea about the image-orientation when it's loaded into canvas, image-orientation: none does not apply, and then the resized image will simply inherit the rotation of the image as displayed in Canvas?

Correct.
Basically, browser makers deliberately decided to break backwards compatibility by changing the default image orientation behavior and unfortunately did not consider the use case of preventing this for images loaded outside of the DOM.

blueimp-load-image can detect if the browser does auto-orientation (with this code), but it cannot prevent it, only reset it by doing an inverse rotation.

orientation: false (or orientation: undefined) has always meant "take the image as it is provided by the browser".
orientation: 1 means use the original image orientation, disregarding the EXIF orientation and blueimp-load-image actively applies an inverse rotation for browsers with automatic image orientation enabled.

With this in mind, you would have to agree that imageOrientation:false makes little sense now? Essentially, at least in most new browsers, it leads to images being oriented from EXIF on resize, while original EXIF orientation values remain in the image, now incorrect. This means it's impossible to create a resized (thumbnail) image from the uploaded image, because the PHP doesn't know if it can rely on the EXIF orientation or not.

I think useful settings depend on what you want to achieve, see e.g. a list of useful Options for image orientation here:
https://github.com/blueimp/jQuery-File-Upload/wiki/Orientation

@mjau-mjau
Copy link

mjau-mjau commented Jun 9, 2020

I think useful settings depend on what you want to achieve:

Thanks for your explanation. Much appreciated.

I think useful settings depend on what you want to achieve:

I think the idea is to be able to 1) resize image on client side, 2) without affecting original image orientation, and without affecting original EXIF. Thus to handle image orientation either from browser/CSS, or from the app backend. From your suggestions, that leads to combo #4:

  1. To upload images resized on client-side, with their original pixel data orientation and meta data preserved, use the following options:
    {
      disableExif: true,
      imageOrientation: 1,
      disableImageResize: false
    }

I have tried this using latest 10.30.0, but it yields the same result as setting imageOrientation: false: The image gets rotated after upload.

Here is an image with EXIF rotation (download original). For reference, this is what the original looks like in modern browser, correctly oriented by browser based on the image's EXIF orientation:

If I set CSS image-orientation: none;, it will no longer be oriented to EXIF orientation. That is also correct behavior of course:

So, the idea is basically to upload that image, resized, without affecting orientation in any way. When I upload with disableExif: true, imageOrientation: 1, disableImageResize: false, it yields the same result as setting imageOrientation: false: The image gets rotated after upload (download uploaded version).

Here is the uploaded version in browser. With the browser now orienting the image based on EXIF, the orientation is now wrong:

If I set CSS image-orientation: none;, it will now be correctly oriented, because the image has been rotated on upload:

This of course is not the expected behavior. We would like to keep the uploaded image orientation identical to the original. Furthermore, in this case, the image's EXIF orientation value is now wrong (because the image has been rotated, yet the EXIF orientation remains the same). This if course makes it impossible to anticipate anything when further processing the image: We can't use the EXIF value when creating server-resized versions of the upload, and the only safe way to display the original image, would be to set CSS image-orientation: none;.

That leaves the now flawless option of imageOrientation: true (cred!). In this case, the image gets oriented correctly, while image EXIF value also gets corrected. The result is that the image displays correctly in browser, regardless of CSS image-orientation.


This of course means there will not be any problems whatsoever creating resized images, or displaying the image in browser. In a dream scenario, one might have hoped that all images were always rotated correctly, and that EXIF orientation did not exist. That is not the case unfortunately.

From the perspective of a gallery app, it therefore seems hopeless to even consider any other option than imageOrientation: true for uploads. Images that are resized, will be resized correctly by JQF. Images that are NOT resized by JQF, can be corrected on server side based on original EXIF orientation. Otherwise, it seems impossible to upload an image (with EXIF orientation) without affecting the image orientation, which in turn messes up post-processing.

Your efforts are truly appreciated in this orientation-madness!

@blueimp
Copy link
Owner

blueimp commented Jun 9, 2020

I wrote out the examples without testing all combinations properly; disableExif:true was actually not a good suggestion, since you need Exif data to reset the browser auto-orientation.

I've updated the Orientation examples (and tested them all) and also released a patch version (10.30.1) to override the Exif data for the case of imageOrientation:false and automatic browser orientation.

@mjau-mjau
Copy link

mjau-mjau commented Jun 9, 2020

I wrote out the examples without testing all combinations properly; disableExif:true was actually not a good suggestion, since you need Exif data to reset the browser auto-orientation.

Works 👍Image is resized, while original rotation is retained (also in EXIF).

I've updated the Orientation examples (and tested them all) and also released a patch version (10.30.1) to override the Exif data for the case of imageOrientation:false and automatic browser orientation.

Also works 👍

However, I would like to note that imageOrientation:false now seems to do the same as imageOrientation:true. It corrects the orientation, and also corrects the EXIF orientation. All good, although expected behavior with imageOrientation:false (from a developers perspective) would be that the image retains original orientation (and original EXIF orientation). At least now, the resulting EXIF orientation value is correct. I am guessing the difference is now browser-based? Eg. imageOrientation:true will always correct the orientation, regardless of browser, while imageOrientation:false will correct the orientation only in browsers that apply imageOrientation in canvas.

From a usability perspective, for most apps and today's browsers, I can only conclude the following:

  1. Always use imageOrientation: true.
  2. On upload, check EXIF orientation on server and rotate if necessary (in case the image was not resized by JFU).

imageForceResize: true
The option imageForceResize: true is interesting, because it allows JFU to correct the image orientation on upload, even when the image does not require resizing, and in this case, there would be no need to check and correct orientation on server. However, it should be a goal to avoid re-compressing JPG images that don't get resized ... In the case an image has EXIF orientation (other than 1), this is acceptable of course (because there is no other way, and even rotating an image on server would cause re-compression). But for images without EXIF orientation (or orientation = 1), it would be useful to avoid. Just thinking aloud 😆it would be cool with some option imageForceResize: 'orientation' or imageForceResizeOnOrientation: true or imageOrientation: 'always'. I can see this could get complicated, as it might require always loading image into canvas, and discarding if orientation is not required.

CSS imageOrientation
In the future, once CSS image-orientation is properly adopted, one might lean towards always retaining original image orientation (also in EXIF) after upload/resize (option #4). In this case, images would always get oriented correctly in browser from EXIF. There would be challenges in html layouts that require width/height (for example popups and some JS grid layouts) since width/height is inverted, but that could be solved by server detecting EXIF orientation and re-assigning width/height appropriately.

Anyway. Thanks again for top effort and great lib! Now all seems good, and I don't intend to steal more time 👍👏

@blueimp
Copy link
Owner

blueimp commented Jun 9, 2020

However, I would like to note that imageOrientation:false now seems to do the same as imageOrientation:true. It corrects the orientation, and also corrects the EXIF orientation. All good, although expected behavior with imageOrientation:false (from a developers perspective) would be that the image retains original orientation (and original EXIF orientation). At least now, the resulting EXIF orientation value is correct. I am guessing the difference is now browser-based? Eg. imageOrientation:true will always correct the orientation, regardless of browser, while imageOrientation:false will correct the orientation only in browsers that apply imageOrientation in canvas.

Yeah, like I wrote above:
orientation: false (or orientation: undefined) has always meant "take the image as it is provided by the browser".

blueimp-load-image tries to do the least amount of work and if you do not override the default options, it will simply load the image as is (as provided by the browser) and return it.

If image-orientation:none should ever become available for out-of-DOM operations, I'll gladly add support for it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants