jruby / image_voodoo

ImageScience-compatible image processing for JRuby
MIT License
26 stars 10 forks source link

Add auto_orient support #15

Closed PetrKaleta closed 9 years ago

PetrKaleta commented 10 years ago

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?

enebo commented 10 years ago

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...

PetrKaleta commented 9 years ago

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 ;)

enebo commented 9 years ago

yeah I am really hoping to not add a dependency but it would probably be the simplest mechanism to get it done...

PetrKaleta commented 9 years ago

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.

enebo commented 9 years ago

@PetrKaleta can you gist or provide a small image like this?

PetrKaleta commented 9 years ago

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.

enebo commented 9 years ago

@PetrKaleta I don't see anything in that comment

PetrKaleta commented 9 years ago

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.

enebo commented 9 years ago

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.

enebo commented 9 years ago

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...

PetrKaleta commented 9 years ago

Looks great, going to test it

PetrKaleta commented 9 years ago

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

enebo commented 9 years ago

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).

enebo commented 9 years ago

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...

enebo commented 9 years ago

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.

PetrKaleta commented 9 years ago

Works perfectly!!!

enebo commented 9 years ago

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...