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.
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!
—Federico
Comments
10 Responses to “Fine Border for Your Photos: ImageMagick and Exiv2 to the rescue!”
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!!!!
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
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
@Max, what is the output of that pipe?
@Max, run:
exiv2 -PEkt pr $1 2>/dev/null | tr -s ” ” ” ” | grep -E “\.DateTimeOriginal” | sed -e ’s@:@/@g’
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 ;)
Ok.:) The text filter blown away the ampersand :D
Change ‘2 AMPERSAND SEMICOLON GREATER-THAN’ by ‘2GREATER-THAN’
By the way, thanks a lot for the script!! It saves A TON of work ;)
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 :-)
Oops, it convert the “& gt ;” to a >
But I guess you know what I mean here…