Fine Border for Your Photos: ImageMagick and Exiv2 to the rescue!

on February 16, 2009

Photos without a frame are like out from their living space. Would you put your favorite pictures on the desktop or on the wall with no frame? Even digital images have found their own form of framing.

So, why not adding a fine border to your pictures before publishing on Flickr, for example? I am not talking about obtrusive, noisy, complicated and bumped borders: I am talking about (sort of) fine art! :)

ImageMagick and Exiv2 (man exiv2) are the perfect combination to create fancy, black and white borders along with a professional signature. Also, instead of having your visitors figure out the settings you used, why not adding them (e.g., aperture, shutter and ISO speed, focal length) right at the bottom of the picture? Take a look a the sample below.

And here is the details.

EXIF data on the signature.
My name and year at the right of the picture.

If not installed, you would need to install exiv2 and ImageMagick. With MacPorts this is as easy as typing:

$ sudo port install imagemagick exiv2

Second, let’s build two tiny scripts to extract the metadata of interest. In my case, I created ~/bin/exiv_data and ~/bin/exiv_year which return an empty string if something goes wrong. For instance, if you forget to embed metadata on your picture we want the scripts to fail in an educate manner.

#!/bin/sh
#File: $HOME/bin/exiv_data
time=$(exiv2 -PEkt pr $1 2 >/dev/null | tr -s " " " " | grep -E "\.ExposureTime" | awk '{print $2}')
focal=$(exiv2 -PEkt pr $1 2 >/dev/null | tr -s " " " " | grep -E "\.FocalLength" | awk '{print $2}')
aperture=$(exiv2 -PEkt pr $1 2 >/dev/null | tr -s " " " " | grep -E "\.ApertureValue" | awk '{print $2}')
iso=$(exiv2 -PEkt pr $1 2 >/dev/null | tr -s " " " " | grep -E "\.ISOSpeedRatings" | awk '{print $2}')

if [ -n "$time" -a -n "$focal" -a -n "$aperture" -a -n "$iso" ]
then
	echo $focal"mm, "$time" @ "$aperture" (ISO " $iso")"
fi

The second script is super tiny:

#!/bin/sh
#File: $HOME/bin/exiv_year

exiv2 $1 2>/dev/null | grep timestamp | grep -oE '[0-9]{4}'

Don’t forget to make them executable with:

$ chmod +x ~/bin/exiv_*

At this point you are ready to try them out with your own pictures. For instance:

$ ~/bin/exiv_data foo.jpg
105.0mm, 1/400 @ F11 (ISO  100)

What about the borders? If you want to obtain a border like the above one, you can re-use my ~/bin/lr_borderscript. Or, you can modify it as you please.

#!/bin/sh
#File: ~/bin/lr_border

year=$($HOME/bin/exiv_year $1)
data=$($HOME/bin/exiv_data $1)

name="Federico Maggi"

if [ -n "$year" ]
then
	name=$name", "$year
fi

mogrify -border 5x5 -bordercolor black $1
mogrify -border 1x1 -bordercolor grey $1
mogrify -border 20x20 -bordercolor black $1

if [ -n "$data" ]
then
	mogrify -pointsize 9 -fill gray -gravity SouthEast -annotate +25+6 "$name" -gravity SouthWest -annotate +25+6 "$data" $1
else
	mogrify -pointsize 9 -fill gray -gravity SouthEast -annotate +25+6 "$name" $1
fi

Remember that this script will modify the original image file! So, if unsure, I’d recommend a backup before.

$ ls *.jpg | while read file; do cp $file $file.bak && ~/bin/lr_border $file; done

Just add a simple loop and you are done!

If you found this post useful just bookmark it!
  • Digg
  • del.icio.us
  • Facebook
  • email
  • LinkedIn
  • Ma.gnolia
  • MySpace
  • StumbleUpon
  • Technorati
  • TwitThis
  • YahooMyWeb

—Federico

10 comments

Comments

10 Responses to “Fine Border for Your Photos: ImageMagick and Exiv2 to the rescue!”

  1. Mato on July 6th, 2009 3:04 am

    Hi! Nice scripts! But it doesn’t work in my Ubuntu Jaunty.
    The error I Get is:

    mato@mato-jaunty:~/bin$ ls *.jpg | while read file; do cp $file $file.bak && ~/bin/lr_border $file; done
    Exiv2 exception in print action for file IMG_0187.jpg:
    Failed to read image data
    2: Failed to open the file
    /home/mato/bin/exiv_year: 3: gt: not found
    /home/mato/bin/exiv_year: 3: /dev/null: Permission denied
    Exiv2 exception in print action for file IMG_0187.jpg:
    Failed to read image data
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 3: gt: not found
    /home/mato/bin/exiv_data: 3: /dev/null: Permission denied
    Exiv2 exception in print action for file IMG_0187.jpg:
    Failed to read image data
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 4: gt: not found
    /home/mato/bin/exiv_data: 4: /dev/null: Permission denied
    Exiv2 exception in print action for file IMG_0187.jpg:
    Failed to read image data
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 5: gt: not found
    /home/mato/bin/exiv_data: 5: /dev/null: Permission denied
    Exiv2 exception in print action for file IMG_0187.jpg:
    Failed to read image data
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 6: gt: not found
    /home/mato/bin/exiv_data: 6: /dev/null: Permission denied
    mogrify: Premature end of JPEG file `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/226.
    mogrify: JPEG datastream contains no image `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/231.
    mogrify: Premature end of JPEG file `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/226.
    mogrify: JPEG datastream contains no image `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/231.
    mogrify: Premature end of JPEG file `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/226.
    mogrify: JPEG datastream contains no image `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/231.
    mogrify: Premature end of JPEG file `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/226.
    mogrify: JPEG datastream contains no image `IMG_0187.jpg’ @ coders/jpeg.c/EmitMessage/231.

    What is wrong?

    Thanks!!!!

  2. Mato on July 6th, 2009 4:16 am

    Well, one of the problems seems to be that the jpg file was broken.. Now I fixed, but it still doesn’t work:

    mato@mato-jaunty:~/bin$ ls *.jpg | while read file; do cp $file $file.bak && ~/bin/lr_border $file; done
    2: Failed to open the file
    /home/mato/bin/exiv_year: 3: gt: not found
    /home/mato/bin/exiv_year: 3: /dev/null: Permission denied
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 3: gt: not found
    /home/mato/bin/exiv_data: 3: /dev/null: Permission denied
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 4: gt: not found
    /home/mato/bin/exiv_data: 4: /dev/null: Permission denied
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 5: gt: not found
    /home/mato/bin/exiv_data: 5: /dev/null: Permission denied
    2: Failed to open the file
    Exiv2 exception in print action for file 2:
    2: Failed to open the data source: (2)
    /home/mato/bin/exiv_data: 6: gt: not found
    /home/mato/bin/exiv_data: 6: /dev/null: Permission denied

  3. Max on November 19th, 2009 4:50 pm

    Hi, your scritp is very useful, i use this to read DateTimeOriginal:

    exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.DateTimeOriginal” | awk ‘{print $2}’

    can u help me please? i need data in this format: 19/11/2009

    Thanks in advance

  4. admin on December 23rd, 2009 1:42 am

    @Max, what is the output of that pipe?

  5. cla on January 23rd, 2010 3:59 pm

    @Max, run:

    exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.DateTimeOriginal” | sed -e ’s@:@/@g’

  6. Alex on February 13th, 2010 11:57 am

    For those having problems with

    gt: not found

    That a problem related to copy and paste from the web page. Replace the ‘2 >’ by ‘2>’ in your text editor.

    I would also remove the if block at the end. Otherwise you might end up having no info if any of the values is missing. For instance, in my Olympus I had to change ApertureValue by FNumber ;)

  7. Alex on February 13th, 2010 11:59 am

    Ok.:) The text filter blown away the ampersand :D

    Change ‘2 AMPERSAND SEMICOLON GREATER-THAN’ by ‘2GREATER-THAN’

  8. Alex on February 13th, 2010 12:00 pm

    By the way, thanks a lot for the script!! It saves A TON of work ;)

  9. Carl Wainwright on March 4th, 2010 10:04 am

    In the script you need to replace > with the > symbol. I picked this up from the comment from Max.

    One thing I noticed is what I run this on my Minolta image files the output is different, obviously because the EXIF data is presented differently..

    With a few tweaks I was able to come up with this lines

    time=$(exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.Photo\.ExposureTime” | awk ‘{print $2}’)
    focal=$(exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.FocalLength ” | awk ‘{print $2}’)
    aperture=$(exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.Photo\.FNumber” | awk ‘{print $2}’)
    iso=$(exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.ISOSpeedRatings” | awk ‘{print $2}’)

    Also I made an additional script to write a new image using convert to create a carbon copy to manipulate.

    Thumbs up and this is certainly a good start for me to work on and move forward. With the Minolta it also gives you the Lens info :-)

  10. Carl Wainwright on March 4th, 2010 10:05 am

    Oops, it convert the “& gt ;” to a >

    But I guess you know what I mean here…




More details »

Fresh deli