Skip to main content

EXIF Orientation Handling Is a Ghetto

Mình thấy nội dung này hay nên copy qua trang để lưu trữ và share cho các bạn. Có thể xem nội dung gốc tại đây.

One of my favourite services at the moment is Transloadit, who provide an image processing API that works a treat on top of platforms like Heroku, where there are strict request timeout limits that make large uploads difficult. They handle auto-orientation of images automagically by default, and normally I’m not even aware of it happening during testing since my camera and OSX also handle auto-orientation transparently.
Recently one particular image stuck out on the staging server as un-rotated, while it worked fine locally using ImageMagick/Dragonfly. Not only that, but the width and height seemed to be wrong, warping the image (the app I’m working on uses a tiled layout, and requires the width and height of each image to be explicitly set in CSS).
I put together a few test images, and have been talking it over via email with Transloadit for the last couple of days (who’ve been super-helpful), and just for kicks thought I’d try uploading the test images to a few other sites to see how everyone else handles it. So began a descent into EXIF madness…

Eh? EXIF Orientation?

The EXIF (exchangeable image file format) standard specifies a set of tags that can be embedded in images (among other things). One of these tags specifies the orientation of the photo, and has 8 possible values which cover every possible combination of rotation and mirroring of an image. This enables you to take a picture with your camera sideways or upside-down (or even inside-out), and stand a reasonable chance of having it display properly on your computer.
This diagram from 80sidea explains the 8 orientations pretty succinctly:

Sounds simple enough…

The problem is that there doesn’t seem to be any consensus on how to handle these orientation tags on the web. Results vary wildly across sites, between different products from the same company, between browsers, and even within a single browser depending on context (yes I’m looking at you Safari). Images with the same orientation value may also be rotated differently on some sites depending on whether they’re landscape or portrait.
Yet another complication is that the seemingly basic concepts of width and heightbecome a bit more abstract when you throw orientation tags into the mix. Is a 640x480 landscape picture with a 90° rotation tag technically landscape or portrait? Is it 640x480 or 480x640? (Short answer - it depends).
Consider the following ImageMagick example using a (technically) ‘Landscape’ image, with an orientation tag value of 5 that makes it a ‘Portrait’ image:

1
2
3
4
5
> identify Portrait_5.jpg
Portrait_5.jpg JPEG 600x450 600x450+0+0 8-bit DirectClass 134KB 0.000u 0:00.009
> convert Portrait_5.jpg -auto-orient Portrait_5_Oriented.jpg
> identify Portrait_5_Oriented.jpg
Portrait_5_Oriented.jpg JPEG 450x600 450x600+0+0 8-bit DirectClass 130KB 0.000u 0:00.000

According to ImageMagick, the original image is 600x450, and the second (auto-oriented) image is 450x600. According to OSX however, they’re both 450x600. Who is correct? I have no idea.
"Landscape tagged with orientation 5 on the left, auto-oriented on the right."

Without further ado…

Let’s take a look at how some of the biggest names on the internet handle EXIF orientation tags. All of the screenshots are of Chrome on OSX unless otherwise specified. A couple of the screenshots (e.g. Gmail) have been cropped and joined for ease of viewing as they are normally displayed as a vertical list, but none of the test images within the screenshots have been altered in any way.
Some of the sites on the ‘bad’ list are of the didn’t-even-try variety, which is possibly one of the saner reactions to this problem and not necessarily ‘bad’. I do feel there should be a consensus on how to handle this though.
The test images are all available on GitHub - try uploading them to your own site to experience the fun first-hand (the good news is that if you’re using ImageMagick you’re probably ok… -auto-orient seems pretty solid apart from the width/height reporting).

The Bad

Surprisingly, Google tops the list here (and how), failing to even display images tagged with 4 out of the 8 orientations in the EXIF standard (the four mirrored orientations). They’re clearly using a centralized image-handling service across Google+, Blogger and Picasa.

Google Plus

Broken.
"Google Plus"

Blogger

Broken.
"Blogger"

Picasa

Broken.
"Picasa"

Google Drive

Didn’t even try - a reasonable approach for a file storage service I guess.
"Google Drive"

Gmail

This is a composite of screenshots laid side-by-side, since they’re usually in a vertical list.
  • Gets tag values 1, 2, 3 and 4 right for landscape pictures (these only involve 0° or 180° rotations, so the aspect-ratio doesn’t change).
  • Fails to rotate 90° rotated landscape images (tag values 5, 6, 7 and 8).
  • Handles portrait tag values 1, 5, 6 and 8 ok (odd, since 6 and 8 don’t work for landscape images), but not 2, 3, 4 or 7 (odd, since 3 and 4 do work for landscape images).
"Gmail"

Dropbox

Handles rotation ok, but not mirroring. This is a composite of large-sized image screenshots, since the thumbnails were too small to make out.
"Dropbox"

Github

GitHub is interesting because it highlights some of the differences that can occur even within the same browser. In desktop Safari, images are not rotated in the context of an HTML page, but the same image is auto-rotated when opened in a new tab by itself (there’s a long discussion related to this on the webkit bug tracker):
"Github on desktop Safari"
On mobile safari however, the orientation tags are interpreted correctly in the context of an HTML page, which trips up GitHub since they’re obviously depending on dimensions returned by something like ImageMagick, which have width and height swapped for 90°-tagged images (note the mis-matched checkered background on landscape-5):
"Github on mobile Safari"

Posterous

Posterous appear to have mirroring figured out, but choke on 90° rotation tags (5, 6, 7 and 8) for landscape images. Interestingly, portrait image rotation for tag values 5, 6, 7 and 8 works. Posterous was the only service to accidentally (I assume) crop photos - portrait-5 and portrait-7. This is a composite image, since the thumbnail view was too small to make out.
"Posterous"

SmugMug

This is a weird one - they’ve managed to rotate all of the ‘mirrored’ images (tag values 2, 4, 5 and 7) 180° so they appear upside-down. They do appear to have un-mirrored them though.
"SmugMug"

Imgur

Close, but chokes on 90° rotated, mirrored images (tag values 5 and 7). A half-SmugMug, if you will.
"Imgur"

Snapfish

The same problems as Posterous, but without the random cropping.
"Snapfish"

SkyDrive

Didn’t even try. As a file storage service, fair enough I guess.
"SkyDrive"

Pinterest

Didn’t even try.
"Pinterest"

Tumblr

Didn’t even try.
"Tumblr"

WordPress.com

Didn’t even try.
"WordPress.com"

Shutterfly

Didn’t even try.
"Shutterfly"

Close, but no cigar

I forgot about 500px.com originally - thanks to Sebastion in the comments for mentioning them. They get all of the rotation and mirroring right, but have a couple of unexpected cropping issues with mirrored, 90°-rotated images (tag values 5 & 7).
"500px"
They don’t have the same problem when viewing a larger version of the image however, which is interesting:
"500px"
Better than most.

The Good

Only a couple of the sites I looked at handle orientation as you’d expect. No great surprises with the first 3 considering their heavy photo pedigree, but nice to see TwitPic on the list.

Facebook

"Facebook"

Flickr

"Flickr"

Photoshop.com

"Photoshop.com"

TwitPic

"TwitPic"

So what?

Web Standards.
However, people smarter than I’ll ever hope to be have been wrestling with this for a while by the look of it:
There’s also some suggestion of ditching the EXIF orientation tag entirely, and putting the onus on device makers to rotate photos properly. This could be problematic for embedded devices with memory or CPU restrictions, but I imagine most modern cameras and phones could manage it.
With the rise of smartphone cameras, where portrait is the default orientation, the problem is only going to get worse. I don’t claim to have any answers, but the one thing that stands out is that every site out there is re-inventing the wheel, and a lot of them are getting it wrong.
If Google can’t handle images consistently across their own sites, on a browser that they built, what hope do the rest of us have?

Comments

Popular posts from this blog

So sánh những framework hỗ trợ viết ứng dụng trên SmartPhone

Khi lập trình trên SmartPhone bạn không nhất thiết phải học những ngôn ngữ đặc thù trên từng loại hệ điều hành thì mới có thể lập trình được. Ví dụ như muốn lập trình trên iOS thì phải học ngôn ngữ Objective-C hay Swift, muốn lập trình được trên Android thì học ngôn ngữ Java, muốn lập trình trên WinPhone thì học ngôn ngữ C#. Hiện nay có rất nhiều những framework giúp đỡ cho các bạn rất nhiều khi các bạn muốn viết trên nhiều nền tảng smartphone bằng ngôn ngữ mà bạn yêu thích. Theo mình thấy thì hiện nay có 3 loại như: Native App, Hybrid Mobile App, Native Cross-Platform App. 1. Native App: là những ứng dụng sử dụng những framework và ngôn ngữ lập trình của hệ thống cung cấp sẵn. Ví dụ như bạn muốn lập trình iOS thì phải cài XCode, học ngôn ngữ Objective-C hay Swift, lập trình Android thì cài Android Studio và học ngôn ngữ Java. - Ưu điểm: Hiệu năng thực thi ứng dụng trên nền tảng nhanh và hiệu quả. Không bị phụ thuộc vào bên thứ 3. Khi phát hành ứng dụng trên những Mobile Store cũng dễ...

Phân biệt biến kiểu Property, Public, Protected, Private trong ngôn ngữ Objective C

- Theo kinh nghiệm làm việc của mình với các bạn trong nhóm khi lập trình Objective-C và cũng đọc qua code của những project cũ. Ít khi nào mọi người để ý và khai báo đúng với ý đồ của từng đối tượng, và vi phạm quy tắc tính đóng gói, tính bảo mật thông tin của đối tượng trong lập trình hướng đối tượng (Tham khảo lý thuyết Lập trình hướng đối tượng tại trang Wiki ). - Theo ngôn ngữ lập trình Java, người ta khuyến khích mỗi khi dùng biến kiểu public thì nên đặt 1 biến private và hỗ trợ những hàm getter/setter để truy suất biến private đó.     + Nguyên nhân họ nói là đảm bảo tính đóng gói, và nếu sau này có thay đổi gì trên biến đó bạn có thể sửa được dễ dàng, chi tiết về vấn đề này ở đây .     + Nói tóm tại thì nguyên nhân chính là có thể kiểm soát được truy xuất đến giá trị của 1 đối tượng từ bên ngoài, có thể dễ dàng mở rộng code bằng cách override lại những hàm getter/setter. - Các bạn có thể áp dụng nguyên tắc đó từ bên Java qua ngôn ngữ lập trình Object...

Hướng dẫn dùng Serverless sử dụng Lambda AWS

1. Lambda function là gì? AWS Lambda cho phép bạn chạy mã mà không cần cung cấp hay quản lý máy chủ. Bạn chỉ phải trả tiền cho thời gian xử lý thông tin đã sử dụng. Với Lambda, bạn có thể chạy mã cho gần như toàn bộ các loại ứng dụng hay dịch vụ backend – tất cả đều không cần quản trị. Chỉ cần tải đoạn mã của bạn lên và Lambda sẽ lo hết những gì cần làm để chạy và mở rộng mã của bạn với mức độ có sẵn cao. Bạn có thể thiết lập mã của bạn tự động kích hoạt từ các dịch vụ AWS khác, hoặc gọi trực tiếp từ bất cứ ứng dụng web hay di động nào. Chi phí chạy trên lambda function rẻ so với chi phí bạn mua 1 con server, duy trì và quản trị nó ( ví dụ như bạn phải xử lý bất đồng bộ những request, khi lượng user bạn tăng đột biến bạn phải có cơ chế auto scale, chứ không thì server bị sẽ bị treo, khi server bị treo bạn phải tự động khởi động lại sẽ mất thời gian,... ).