« Automated self.down in Rails Migrations | Main | Learning Web Development »

October 16, 2007

Lesson #1 after using the iPhone: Automatic Orientation

Remember those days of downloading your photos from your camera, then going through them, one by one... and rotating each picture right-side up until you get drowsy or give up? Such tedious work! Oh, and did you click save after you rotated?

Apparently, pictures taken from the iPhone and many new digital cameras (though none from the world's largest camera manufacturer) comes embedded with orientation information! To put it simply, it means that these digital photos already know if they are landscape or portrait - How cool is that?

Unfortunately, not all software makes use of this piece of information to save you the labor. And this includes even cool sites like Flickr :-( What a shame. And it doesn't help that most image upload/resize/crop HOWTOs doesn't talk about it either.

SharedCopy is cooler than that. Though imaging is not our forte, and its just done for your little profile picture, things are set up such that your profile picture will be right-side up :-D And now, with the help of some monkey-patching, your Rails/Ruby-powered website can be as cool too!

RMagick users, simply include the code below (e.g. append to config/environment.rb):

require 'RMagick' unless defined?(Magick)
Magick::Image.class_eval do
  class << self
    def read_with_auto_upright(*args, &block)
      self.read_without_auto_upright(*args, &block).collect do |img|
        begin
          # if there's nothing to rotate, auto_orient! will return nil
          img.auto_orient! || img
        rescue NotImplementedError
          # Older versions of ImageMagick has no auto_orient!
          case img.get_exif_by_entry("Orientation") && img["EXIF:Orientation"]
          # img["EXIF:Orientation"] might not be ready until get_exif_by_entry() is called
          when "6"
            # Magick::RightTopOrientation
            img.rotate!(90)
            img["EXIF:Orientation"] = "1"
          when "3"
            # Magick::BottomRightOrientation
            img.rotate!(180)
            img["EXIF:Orientation"] = "1"
          when "8"
            # Magick::LeftBottomOrientation
            img.rotate!(270)
            img["EXIF:Orientation"] = "1"
          end
          img
        end
      end
    end

    # wrap around RMagick::Image#read method so that
    # any images loaded in memory are already upright
    alias :read_without_auto_upright :read
    alias :read :read_with_auto_upright
    # note: not using alias_method_chain so that this
    #       snippet can be used outside of Rails
  end
end

  ImageScience users, if you trust my C++ code, just place this patched image_science.rb in your vendor/ directory. Otherwise you can apply this patch manually:

--- lib/image_science.rb	2007-10-16 12:11:08.000000000 +0800
+++ lib/image_science.rb.new 2007-10-16 12:11:01.000000000 +0800
@@ -150,6 +150,21 @@
           VALUE result = Qnil;
           int flags = fif == FIF_JPEG ? JPEG_ACCURATE : 0;
           if (bitmap = FreeImage_Load(fif, input, flags)) {
+            FITAG *tagValue = NULL;
+            FreeImage_GetMetadata(FIMD_EXIF_MAIN, bitmap, "Orientation", &tagValue);
+            switch (tagValue == NULL ? 0 : *((short *) FreeImage_GetTagValue(tagValue))) {
+              case 6:
+                bitmap = FreeImage_RotateClassic(bitmap, 270);
+                break;
+              case 3:
+                bitmap = FreeImage_RotateClassic(bitmap, 180);
+                break;
+              case 8:
+                bitmap = FreeImage_RotateClassic(bitmap, 90);
+                break;
+              default:
+               break;
+            }
             result = wrap_and_yield(bitmap, self, fif);
           }
           return result;

What's done here (for both) is that images loaded into memory will be checked for orientation information and have its orientation corrected if possible (otherwise its left untouched). In memory. So all your image operations like "width", "resize" will be magically "correct".

No modifications required to your routine. Heck, you can even pretend the whole scenario never existed!

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00e398212d6f883300e54ef859358833

Listed below are links to weblogs that reference Lesson #1 after using the iPhone: Automatic Orientation:

Comments

This is awesome. Just what I'm looking for. Thanks for sharing it.

One more vote for awesome. Saved me a lot of trouble. Thanks!

Many thanks! Really great explanation, I also added another method to rotate on demand by n degrees.

##
# Rotates the image by rotate
# filter and yields the new image.

def rotate(degrees) # :yields: image
end


and in the inline builder bit:

builder.c <<-"END"
VALUE rotate(long d) {
GET_BITMAP(bitmap);
FIBITMAP *image = FreeImage_RotateClassic(bitmap, 270);
if (image) {
copy_icc_profile(self, bitmap, image);
return wrap_and_yield(image, self, 0);
}
return Qnil;
}
END

Note for ImageScience users:

Just place the patched version of image_science.rb in the /lib directory from the root of your rails app and it should work.

The instructions say to place it in your /vendor directory, and I don't think that is the right place to put it. Please correct me if I am wrong.

@adc technically, both "lib" and "vendor" would work.

My own convention is to put project specific code that is written by team members into "lib". And code from anyone else (or for other projects) is placed inside "vendor".

in this way, should there be rights / licensing / permissions questions, the project owner can easily & quickly single out the stuff inside "vendor".

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Blog powered by TypePad