Sneak Peak: ImageMagick in MarkLogic

Author: Dave Cassel  |  Category: Software Development

Today I get to give you a sneak peak into a feature that’s not yet officially present, but you’ll find if you know where to look: XQuery-level integration with ImageMagick!

Before we go any further, let’s be clear that this is neither documented nor supported in the current version — and if it becomes official, the interface with the feature may very well change. If you are interested in this feature, please contact Stephen Buxton in Product Management and let him know.

With all that out of the way, let’s take a look.

ImageMagick is “a software suite to create, edit, compose or convert bitmap images”, as stated on its web site. If you have ImageMagick installed on your server when MarkLogic 5 starts up, you’ll see something like this line slide by in your ErrorLog.txt:

2012-01-09 17:10:41.557 Info: ImageMagick 6.7.4-4 2012-01-09 Q16 http://www.imagemagick.org

If you don’t have it installed, you’ll still see some reference to ImageMagick, but it will be a message indicating that it was not able to load ImageMagick.

Regular readers will have seen that I’m now running a site with the MarkLogic Express license: CurioVault.com. The site lets users upload information about collectibles they have, including when and where they got the item, an interesting story connected to it, and a picture of it. CurioVault is more about the stories than the pictures. It’s not Flickr — I don’t want the site to get bogged down with a bunch of multi-megabyte images. So, I set up the code so that I can specify a maximum size for an image in bytes, and automatically scale down any uploaded images that exceed that size. I also set up a maximum image dimension (in pixels) to use when scaling. Here’s the code that does it:

declare function item:scale-image($img as binary()) as binary()
{
  if (xdmp:binary-size($img) > $MAX-IMG-SIZE) then
    let $wand := magick:read-image(magick:wand(), $img)
    let $height := magick:get-image-height($wand)
    let $width := magick:get-image-width($wand)
    let $wand :=
      magick:scale-image(
        $wand,
        fn:min((fn:ceiling($width * $MAX-IMG-DIM div $height), $MAX-IMG-DIM)),
        fn:min((fn:ceiling($height * $MAX-IMG-DIM div $width), $MAX-IMG-DIM)))
    return magick:write-image($wand)
  else
    $img
};

The trickery with the 2nd and 3rd parameters to magick:scale-image() is to make sure the aspect ratio remains the same, while setting a maximum for either dimension. But simple as that, I pass in binary image that a user uploaded and when it comes back, I know that it won’t be huge. (People who do a lot of image manipulation may have suggestions for a better approach; such comments are welcome, but don’t let that distract you from celebrating this feature!) Previously, to accomplish this would have required calls out to MLJAM or a service.

This integration is so new that even the internal documentation is mostly references to ImageMagick’s documentation at this point. If you want to play around a bit, you can map the code above to the corresponding functions on ImageMagick’s documentation and probably figure out how to make some other kinds of calls.

Be sure to let Stephen know what you think.

Next up for CurioVault: letting users crop images at upload time.

Tags: , , , ,

One Response to “Sneak Peak: ImageMagick in MarkLogic”

  1. Norman Walsh Says:

    FWIW, I added support for this to the DocBook XSLT 2.0 stylesheets a while back. If you’re running them on MarkLogic 5 with ImageMagick support, the ImageMagick functions are used to compute the dimensions of embedded images.

Leave a Reply