Quick Magick

What is QuickMagick

QuickMagick is a gem built by BadrIT (www.badrit.com) for easily accessing ImageMagick command line tools from Ruby programs.

When to use QuickMagick

QuickMagick is a library that allows you to create and manipulate images. When you are faced with a problem that requires high quality manipulation of images you can use QuickMagick. Use QuickMagick to:

  • Check uploaded images dimensions.

  • Generate captchas.

  • Generate graphical reports and charts.

  • Convert uploaded images formats.

  • Display pdfs as images.

Features

  • Open an existing image from disk and determine basic info like width, height.

  • Open an image from blob. For example, an image read from an upload form.

  • Do basic and advanced operations on images like resize, rotate, shear, motion blur and other.

  • Create an image from scratch and draw basic elements on it like line, circle and text. This allows making captchas for example.

  • Combine images using ImageList to make a multipage or animated images.

  • API is very simple and powerful.

  • Minimizes disk access by calling command line tools only when required.

How to install

First, you should install ImageMagick (www.imagemagick.org/) on your machine. Command line tools of ImageMagick must be in your system path. You can check this by running the command:

identify -version

Now to install QuickMagick just type at your command line:

gem install quick_magick

… and it’s done. You don’t have to install any libraries or compile code from source.

What is different?

But what’s different from other gems like RMagick and mini-magick?

The story begins when I was working on a project at BadrIT (www.badrit.com) using Ruby on Rails. In this projects users were uploading images in many formats like pdf, tiff and png. We were using Flex as a front end to display and annotate these images. Flex has a limitation in that it can open images up to 8192x8192. Unfortunately, users were uploading images much larger than this. Another issue is that Flex can only open .jpg, .png and .gif files. The solution was to convert all images uploaded to one of these formats and resizing them down to at most 8192x8192.

First, I used ImageMagick as a command line tool and was calling it using system calls. This accomplished the work perfectly but my source code was a rubbish. It has many lines of code to handle creating temporary files and accessing multipage tiff and pdf files. I found RMagick at that time and decided to use it. It caused the code to be much simple without affecting performance notably. It worked with me well while I was using my application with test images. Once I decided to test it with real images it failed. For example, when I transform a tiff image from 14400x9600 to 8192x8192 while transforming it to gif, my machine runs out of memory (2GB RAM). When I tried to make the same operation from command line using (convert) it was working much better. It did not finish in a second but at least it worked correctly. The solution was to return back to command line.

I searched for alternatives and found MiniMagick. MiniMagick is a gem that allows you to perform basic operations using ImageMagick through command line tools. I tried to use it but it was not good enough. First, it writes temporary images and files as it is working which makes it slow for nothing. Second, it doesn’t handle multipage images. I tried it with a .pdf file and I found that it handled the first page only. Third, it doesn’t give an API to draw images from scratch. Actually, I didn’t need this feature, but I may need it in the future.

At this point I decided to make my own gem and QuickMagick was born. I addressed the problems of MiniMagick while using the same main idea. First, QuickMagick doesn’t write any temporary image files to disk. It doesn’t issue any command line commands till the very end when you are saving the image. Second, I made an API similar to RMagick which allows for accessing multipage images. Third, I added API commands to create images from scratch and drawing simple primitives on images. I tested my gem, compared it to MiniMagick and RMagick and it pleased me.

Comparison

I’ve made some test benches to compare the speed of QuickMagick, MiniMagick and RMagick. All denoted numbers are in seconds. Here are the results:

Test 1: resize a normal image

                user     system      total        real
mini          0.030000   0.040000   3.640000 (  3.585617)
quick         0.010000   0.030000   3.330000 (  3.295369)
rmagick       1.680000   1.660000   3.340000 (  3.150202)

It’s clear that QuickMagick is faster than MiniMagick. RMagick was the fastest as it accesses the requested operations directly without the need to load an executable file or parse a command line.

Test 2: resize a large image

                user     system      total        real
mini          0.000000   0.040000  57.150000 (130.609229)
quick         0.010000   0.010000  56.510000 ( 58.426361)

Again QuickMagick is faster than MiniMagick. However, RMagick has failed to pass this test. It kept working and eating memory, cpu and harddisk till I had to unplug my computer to stop it. So, I removed it from this test bench.

Test 3: generate random captchas

                user     system      total        real
quick         0.000000   0.000000   0.290000 (  3.623418)
rmagick       0.150000   0.120000   0.270000 (  3.171975)

In this last test, RMagick was about 12% faster than QuickMagick. This is normal because it works in memory and doesn’t have to parse a command line string to know what to draw. I couldn’t test MiniMagick for this because it doesn’t support an API for drawing functions.

Conclusion

QuickMagick is very easy to install, very easy to use and allows you to access most features of ImageMagick. RMagick is a bit faster but it’s a bit hard to install. Also RMagick sometimes fail when it tries to handle large images. MiniMagick is proved to be slower than QuickMagick with no advantage. So, it’s better to use QuickMagick when your application is not image-centric. This means, you’re not going to build an image manipulation tool or something like this. For normal operations like resize, rotate, generating captchas … etc, QuickMagick will be a good friend of you.

Examples

Determine image information i = QuickMagick::Image.read(‘test.jpg’).first i.width # Retrieves width in pixels i.height # Retrieves height in pixels

Resize an image i = QuickMagick::Image.read(‘test.jpg’).first i.resize “300x300!” i.save “resized_image.jpg” or i.append_to_operators ‘resize’, “300x300!” or i.resize 300, 300, nil, nil, QuickMagick::AspectGeometry

Access multipage image i = QuickMagick::Image.read(“multipage.pdf”) {|image| image.density = 300} i.size # number of pages i.each_with_index do |page, i| i.save “page_#i.jpg” end

From blob i = QuickMagick::Image.from_blob(blob_data).first i.sample “100x100!” i.save

Modify a file (mogrify) i = QuickMagick::Image.read(‘test.jpg’) i.resize “100x100!” i.save!

You can also display an image to Xserver i = QuickMagick::Image.read(‘test.jpg’) i.display

QuickMagick supports also ImageList s # Batch convert a list of jpg files to gif while resizing them il = QuickMagick::ImageList.new(‘test.jpg’, ‘test2.jpg’) il << QuickMagick::Image.read(‘test3.jpg’) il.format = ‘gif’ il.resize “300x300>” il.save!

You can also create images from scratch # Create a 300x300 gradient image from yellow to red i1 = QuickMagick::Image::gradient(300, 300, QuickMagick::RadialGradient, :yellow, :red) i1.save ‘gradient.png’ # Create a 100x200 CheckerBoard image i1 = QuickMagick::Image::pattern(100, 200, :checkerboard) i1.display

… and draw primitives on them i = QuickMagick::Image::solid(100, 100, :white) i.draw_line(0,0,50,50) i.draw_text(30, 30, “Hello world!”, :rotate=>45) i.save ‘hello.jpg’

… you can then convert it to blob using

i.to_blob

(new) You can now access single pixels using QuickMagick # Create a 300x300 gradient image from yellow to red i1 = QuickMagick::Image::gradient(300, 300, QuickMagick::RadialGradient, :yellow, :red) i1.save ‘gradient.png’ # Now you can access single pixel values i1.get_pixel(10,10) # [255, 0, 0] i1.get_pixel(50,50) # [255, 15, 0]

For more information on drawing API visit: www.imagemagick.org/Usage/draw/

Check all command line options of ImageMagick at: www.imagemagick.org/script/convert.php