Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

PIL Engine does not persist EXIF data in original storage (e.g. Images with ORIENTATION exif field are only properly rotated on first load) #136

Closed
mdrcode opened this Issue Nov 27, 2012 · 10 comments

Comments

Projects
None yet
5 participants

mdrcode commented Nov 27, 2012

I believe this issue is closely related to:

globocom#94

When Thumbor first fetches an image, it stores it locally for quick access on subsequent requests. Notably: it does not store the raw bytes as directly received from the loader, rather it attempts to store an optimized version of the image which has already been processed by the engine (albeit without transforms, filters, etc). You can see the relevant code in action here:

https://github.com/globocom/thumbor/blob/master/thumbor/handlers/__init__.py#L226

If this processing has mutative side effects, there can be unexpected behavior on subsequent fetches of the image. For example, the Python Imaging Library does not save exif metadata (at least, according to an hour of my Googling and reading the docs). So if you use the PIL engine in Thumbor, all the exif data will be stripped when saving the image files. This can cause a serious issue if you were relying on ORIENTATION exif data to rotate the image properly.

Here's an example repro:

  • Setup Thumbor to use PIL engine and normal file storage
  • Enable the awesome RESPECT_ORIENTATION flag
  • Load an image from the web (via http) that has an 'Orientation' field set in exif metadata
  • First time - the image is rotated correctly
  • All subsequent fetches, the image is NOT rotated
  • (If you examine the saved image in Thumbor's internal storage, you can see that it has no exif data whatsoever - it has been stripped)

Then if you just disable Thumbor storage, the image will always be rotated correctly. So clearly, it is the storage step that's involved here.

Since the underlying PIL library does not support exif persistence, I'm not entirely sure about the best way to fix this?

Perhaps a config option like FORCE_STORE_TRUE_ORIGINAL that will save the bytes directly from the loader instead of the first processing by the engine?

I am testing with 3.6.7 on OS X Mountain Lion. Feel free to use this test image:

https://s3.amazonaws.com/premise-mike/894dfa36-621f-4fdc-abf5-a29e1b4ae70e.jpg

Thank you guys for this great piece of code.

  • Mike

mdrcode commented Nov 27, 2012

One possible solution is to apply the RESPECT_ORIENTATION processing at the time of first load/store. I think this would be valid because it's an inherent property of the source image and not a per request / transform thing...

Owner

heynemann commented Dec 14, 2012

I would think that storing the exif headers would be more appropriate... What do you think?

mdrcode commented Dec 14, 2012

Definitely, I agree that persisting (all) exif headers would be a very appropriate thing to do.

Any alternative to PIL that can do it? having real trouble with the rotation thing.

Owner

heynemann commented May 15, 2013

Not really. We need to change PIL engine to respect orientation like Mike
said. Haven't had time to get around it yet.

Maybe you can send a pull request our way Bibhas?

Bernardo Heynemann
Developer @ globo.com

On Wed, May 15, 2013 at 6:17 PM, Bibhas notifications@github.com wrote:

Any alternative to PIL that can do it? having real trouble with the
rotation thing.


Reply to this email directly or view it on GitHubhttps://github.com/globocom/thumbor/issues/136#issuecomment-17966912
.

Even the img._getexif() at create_image() returns nothing. That doesn't seem right.

Owner

heynemann commented Aug 31, 2013

@iambibhas this has been open for a while now. Any idea if you can help us fix it?

Contributor

igorsobreira commented Dec 3, 2013

I believe I'm having a problem related to this. I have a gif with transparent background, and using filters:format(png) gives me a png with transparent background in the first request (while the image is not saved on file system), then the second request gives an image with black background.

After reading this issue I've downloaded the first (correct, with transparent background) and the second and used exiftool to see the difference:

exiftool upper_right_logo.png
ExifTool Version Number         : 9.20
File Name                       : upper_right_logo.png
Directory                       : .
File Size                       : 7.1 kB
File Modification Date/Time     : 2013:12:02 10:54:02-10:00
File Access Date/Time           : 2013:12:02 10:54:02-10:00
File Inode Change Date/Time     : 2013:12:02 10:54:02-10:00
File Permissions                : rw-------
File Type                       : PNG
MIME Type                       : image/png
Image Width                     : 350
Image Height                    : 50
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Image Size                      : 350x50
exiftool upper_right_logo-1.png
ExifTool Version Number         : 9.20
File Name                       : upper_right_logo-1.png
Directory                       : .
File Size                       : 3.8 kB
File Modification Date/Time     : 2013:12:02 10:54:25-10:00
File Access Date/Time           : 2013:12:02 10:54:26-10:00
File Inode Change Date/Time     : 2013:12:02 10:54:25-10:00
File Permissions                : rw-------
File Type                       : PNG
MIME Type                       : image/png
Image Width                     : 350
Image Height                    : 50
Bit Depth                       : 8
Color Type                      : RGB
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Image Size                      : 350x50

Note that the first one has Color Type : RGB with Alpha but the second doesn't have with Alpha. And the image on the server, as thumbor saved on disk has:

exiftool storage/b0/81db8748a97df1082317550fa0929dd60d16b8
ExifTool Version Number         : 8.50
File Name                       : 81db8748a97df1082317550fa0929dd60d16b8
Directory                       : storage/b0
File Size                       : 5.7 kB
File Modification Date/Time     : 2013:12:03 00:28:44+00:00
File Permissions                : rw-rw-r--
File Type                       : GIF
MIME Type                       : image/gif
GIF Version                     : 87a
Image Width                     : 350
Image Height                    : 50
Has Color Map                   : Yes
Color Resolution Depth          : 1
Bits Per Pixel                  : 6
Background Color                : 0
Image Size                      : 350x50

I tried to attach the original image I'm using bellow, not sure if github is going to modify it.
upper_right_logo-1

This is my pip freeze:

Pillow==2.1.0
derpconf==0.4.9
pgmagick==0.5.7
pycrypto==2.6.1
pycurl==7.19.0.2
python-magic==0.4.6
six==1.4.1
thumbor==3.14.7
tornado==3.1.1

(pgmagick is here because I tried to replace pil, but it just segfaults, maybe because it's a gif, I don't know)

Contributor

robolson commented Jan 15, 2014

I am experiencing many instances of incorrect rotation for images with EXIF orientation so I am trying to figure out if I am affected by this bug or a different one. Anecdotally, I have seen instances where the rotation was wrong on the first request and fixed for every request after that.

In this thread it is mentioned that the "PIL library does not support exif persistence". If that is true how is the rotation working for me at all?

Owner

heynemann commented Mar 10, 2014

This should be working now. Closing issue.

@heynemann heynemann closed this Mar 10, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment