Add auto_orient support
Closed this issue · 17 comments
One of the very common tasks we must do on our server is to auto_orient images based on its EXIF. iOS devices are not rotating images "physically" but just changing its EXIF.
While we were using ImageMagick, we used --auto-orient flag which did this job perfectly. I was looking for any possible solutions with BufferedImage but it seems to be a hard one :/ Any suggestions?
Are these always more of a landscape/portrait thing or are they somehow rotating by arbtrary amounts (or some weird projection)? Perhaps we can extract the relevant fields from the XML we can extract via Java imaging APIs and apply a rotate but it if it is not a simple angle then I have no idea...
Hey Thomas,
please take a look at this http://stackoverflow.com/questions/5905868/am-i-making-this-too-complicated-image-rotation and yes, its simple angles. Believe me, everyone who's processing photos taken with iPhone/iPad/iPod will love you, once you add support for this ;)
yeah I am really hoping to not add a dependency but it would probably be the simplest mechanism to get it done...
dependencies sucks ...
On Nov 25, 2014, at 10:59 PM, Thomas E Enebo notifications@github.com wrote:
yeah I am really hoping to not add a dependency but it would probably be the simplest mechanism to get it done...
—
Reply to this email directly or view it on GitHub.
@PetrKaleta can you gist or provide a small image like this?
Try this one Thomas
Sent from my iPhone
On 25 Nov 2014, at 23:04, Thomas E Enebo notifications@github.com wrote:
@PetrKaleta can you gist or provide a small image like this?
—
Reply to this email directly or view it on GitHub.
@PetrKaleta I don't see anything in that comment
Sorry Github has removed attached photo. Here is a link to Dropbox https://www.dropbox.com/s/vhi7i4bx7c2qc2m/Photo%2025-11-14%2023%2007%2043.jpg?dl=0
Sent from my iPhone
On 26 Nov 2014, at 00:07, Thomas E Enebo notifications@github.com wrote:
@PetrKaleta I don't see anything in that comment
—
Reply to this email directly or view it on GitHub.
Ok so this is fun so far:
require 'metadata-extractor-2.6.2.jar'
class com::drew::metadata::Directory
def [](tag)
end
end
file = java.io.File.new ARGV.shift
metadata = com.drew.imaging.ImageMetadataReader.read_metadata file
metadata.directories.each do |directory|
puts "DIRECTORY: #{directory.name}"
directory.tags.each do |tag|
puts " Tag: #{tag.tag_name} #{tag.tag_type} - #{tag.description}"
if tag.tag_name == "Orientation"
puts "Orientation: #{directory.get_int(tag.tag_type)}"
end
end
end
output:
system ~/work/image_voodoo master * 596% jruby -Ivendor test2.rb rotated_photo.jpg
DIRECTORY: Jpeg
Tag: Compression Type -3 - Baseline
Tag: Data Precision 0 - 8 bits
Tag: Image Height 1 - 2448 pixels
Tag: Image Width 3 - 3264 pixels
Tag: Number of Components 5 - 3
Tag: Component 1 6 - Y component: Quantization table 0, Sampling factors 2 horiz/2 vert
Tag: Component 2 7 - Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
Tag: Component 3 8 - Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
DIRECTORY: Exif SubIFD
Tag: Exposure Time 33434 - 1/15 sec
Tag: F-Number 33437 - F2.2
Tag: Exposure Program 34850 - Program normal
Tag: ISO Speed Ratings 34855 - 250
Tag: Exif Version 36864 - 2.21
Tag: Date/Time Original 36867 - 2014:11:25 23:07:43
Tag: Date/Time Digitized 36868 - 2014:11:25 23:07:43
Tag: Components Configuration 37121 - YCbCr
Tag: Shutter Speed Value 37377 - 1/15 sec
Tag: Aperture Value 37378 - F2.2
Tag: Brightness Value 37379 - 1467/5114
Tag: Exposure Bias Value 37380 - 0 EV
Tag: Metering Mode 37383 - Multi-segment
Tag: Flash 37385 - Flash did not fire, auto
Tag: Focal Length 37386 - 4.15 mm
Tag: Subject Location 37396 - 1631 1223 1795 1077
Tag: Sub-Sec Time Original 37521 - 016
Tag: Sub-Sec Time Digitized 37522 - 016
Tag: FlashPix Version 40960 - 1.00
Tag: Color Space 40961 - sRGB
Tag: Exif Image Width 40962 - 3264 pixels
Tag: Exif Image Height 40963 - 2448 pixels
Tag: Sensing Method 41495 - One-chip color area sensor
Tag: Scene Type 41729 - Directly photographed image
Tag: Exposure Mode 41986 - Auto exposure
Tag: White Balance Mode 41987 - Auto white balance
Tag: Focal Length 35 41989 - 29mm
Tag: Scene Capture Type 41990 - Standard
Tag: Lens Specification 42034 - 83/20 83/20 11/5 11/5
Tag: Lens Make 42035 - Apple
Tag: Lens Model 42036 - iPhone 6 back camera 4.15mm f/2.2
DIRECTORY: Exif IFD0
Tag: Make 271 - Apple
Tag: Model 272 - iPhone 6
Tag: Orientation 274 - Bottom, right side (Rotate 180)
Orientation: 3
Tag: X Resolution 282 - 72 dots per inch
Tag: Y Resolution 283 - 72 dots per inch
Tag: Resolution Unit 296 - Inch
Tag: Software 305 - 8.1.1
Tag: Date/Time 306 - 2014:11:25 23:07:43
Tag: YCbCr Positioning 531 - Center of pixel array
DIRECTORY: GPS
Tag: GPS Latitude Ref 1 - N
Tag: GPS Latitude 2 - 49.0° 39.0' 48.29000000000349"
Tag: GPS Longitude Ref 3 - E
Tag: GPS Longitude 4 - 18.0° 40.0' 57.69000000000091"
Tag: GPS Altitude Ref 5 - Sea level
Tag: GPS Altitude 6 - 345 metres
Tag: GPS Time-Stamp 7 - 22:7:42 UTC
Tag: GPS Speed Ref 12 - kph
Tag: GPS Speed 13 - 0
Tag: GPS Img Direction Ref 16 - True direction
Tag: GPS Img Direction 17 - 113.74 degrees
Tag: GPS Dest Bearing Ref 23 - True direction
Tag: GPS Dest Bearing 24 - 293.74 degrees
Tag: GPS Date Stamp 29 - 2014:11:25
DIRECTORY: Exif Thumbnail
Tag: Thumbnail Compression 259 - JPEG (old-style)
Tag: X Resolution 282 - 72 dots per inch
Tag: Y Resolution 283 - 72 dots per inch
Tag: Resolution Unit 296 - Inch
Tag: Thumbnail Offset 513 - 1980 bytes
Tag: Thumbnail Length 514 - 9224 bytes
What is weird about this library is the numbers on each tag are a specific value of the tag called tag_type. If you want the real raw type you need to know that Orientation which has tag_type of 274 is an integer and then ask the Directory to get_int(274) to return the real value of 3. I am sure there is a good reason why you want to query like this but for Ruby wrapper I think I will add smarts so we just do something like:
meta_data['Exif IFD0']['Orientation'] #=> 3
I thought about making these arefs into first class methods but it appears a tag name can have almost any character in it, so I will treat these like data in a hash.
commit a50f8f4 implements correcting by orientation. It also adds beginning of design to expose any metadata in an image although I only implement orientation. I think this still needs tests, more use cases, and probably images for all orientations (I only tests 3 from the source image you provided).
I ended up vendoring metadata-extractor but perhaps I should gemify it and make it a gem dep.
The only downside of this library (which I realized after being a ways in is it will not allow rewriting metadata. I guess no point in boiling the ocean...
Looks great, going to test it
I am getting no method 'readMetadata' for arguments (java.io.ByteArrayInputStream) on Java::ComDrewImaging::ImageMetadataReader
. I am using ImageVoodoo.with_bytes
maybe thats the case
Ah. I wrote that blindly but it indicates I need tests. The problem is that the library does not take InputStream but instead BufferedInputStream. So I will add some wrap logic to make the inputstream work. It is funny because I am using the one case where bufferedinputstream hurts performance (bytearrayinputstream).
Wait this is pretty weird the Javadocs says it is an inputstream so that error is pretty baffling unless his docs represent something newer than I am using...
Ah I pushed an unreleased version of metadata-extractor which uses the proper signature (InputStream). The version I used was more than 2 years old and it looks like he has not released in 2 years even though he has been pretty active lately. I now plan on making a new gem for metadata and will rip this stuff out. Still I can release with what is here once we get it stable enough to be usable.
with_bytes does work now and I would commit the test but I don't want to use your image since it is pretty large. I think I will look around for small source images.
Works perfectly!!!
I am resolving this. I have only tested 2 of the Orientation settings so it would probably be good to find more and test them all but I had a hard time finding the other values...