Bash script to extract photos from vCard files —
If you ever find yourself wanting to extract the contact photos from vCard/VCF files then this may be the script for you. I know that this works on a vCard export of multiple contacts from the Contacts app in OS X Mountain Lion. It’s possible you might have to tweak it a bit for vCard files from other sources. This script also resizes the exported photos to 201×201 pixels. If you want to modify this conversion then just change the “convert” line near the bottom accordingly. If you don’t want to resize the photos then simply delete this line and the bit where it checks for the presence of ImageMagick (or comment these bits out). If you do want to resize the images then you’ll need to have
ImageMagick installed (“brew install imagemagick” if you’re on a Mac with Homebrew installed, which it really ought to be). You’ll also need to make sure you have base64 installed, which it probably already will be. If you’re copying and pasting this script, make sure you replace the ^M near the bottom of the script with a literal ^M (normally you type Ctrl-V then Ctrl-M to get a literal ^M). The script will take the vCard file you specify as input and create a subdirectory called photos containing the photos from your contacts.
#!/bin/bash
progname=$(basename $0)
usage="Usage:\t$progname -f vCard_file \n\t$progname -h"
while getopts "f:h" options ; do
case $options in
f) vcard_file=$OPTARG ;;
h) echo -e $usage ; exit ;;
esac
done
if [ ! "$vcard_file" ] ; then
echo -e $usage
exit 1
fi
if [[ ! $(head -1 $vcard_file) =~ "BEGIN:VCARD" ]] ; then
echo "$vcard_file does not appear to be a vCard file"
exit 1
fi
if ! which base64 > /dev/null ; then
echo "base64 is not installed"
exit 1
fi
if ! which convert > /dev/null ; then
echo "ImageMagick is not installed"
echo "Either install it or comment out the ImageMagick stuff"
exit 1
fi
if [ -d photos ] ; then
echo "photos directory already exists"
exit 1
fi
if ! mkdir photos ; then
echo "Failed to create photos directory"
exit 1
fi
regex1="^N:"
regex2="^PHOTO;"
regex3=":|;"
echo -ne "Extracting photos"
cat $vcard_file | while read line ; do
if [[ $line =~ $regex1 ]] ; then
filename=$(echo $line | awk -F '[:;]' '{printf("%s%s",$3,$2)}' | \
sed 's/[^a-zA-Z]//g')
echo -ne "."
cat /dev/null > photos/$filename.tmp
elif [[ $line =~ $regex2 ]] ; then
echo $line | sed 's/PHOTO;ENCODING=b;TYPE=JPEG://' >> photos/$filename.tmp
elif [[ ! $line =~ $regex3 ]] ; then
echo $line >> photos/$filename.tmp
fi
done
echo -ne " done\n"
echo -ne "Removing empty photos..."
find photos -empty -exec rm -f {} +
echo -ne " done\n"
echo -ne "Converting photos"
cd photos
for file in *.tmp ; do
filename=$(echo $file | awk -F '.' '{print $1}')
echo -ne "."
cat $file | tr -d '\n' | tr -d '^M' | base64 -d > $filename.jpg
convert $filename.jpg -resize 201x201 $filename.jpg
rm -f $file
done
echo -ne " done\n"
Categorised as: SysAdmin
Nice little script. My only suggestion would be maybe scatter a few comments in the code for explanation. Thanx!
Thanks. I take your point about the comments but I thought the way I’d laid it out with echo commands made it fairly clear what was going on. My time is limited and I wanted to get it posted in a working form today before I had to move onto something else, but I may come back and add comments etc. at a later date if I get a spare few minutes.
Alternatively, feel free to send me a version with comments added and if it looks OK I’ll update the post with credit given to yourself accordingly.
Otherwise, hope it proves useful! Cheers.
Using Ubuntu 12.10, with ImageMagick and base64 installed, and a vCard created by my Android phone, I get the errors:
Extracting photos. done
Removing empty photos… done
Converting photos.base64: invalid input
convert.im6: Not a JPEG file: starts with 0x3c 0×73 `JohnSmith.jpg’ @ error/jpeg.c/JPEGErrorHandler/316.
convert.im6: no images defined `JohnSmith.jpg’ @ error/convert.c/ConvertImageCommand/3044.
done
Any ideas? I’m probably missing something obvious. The vCard has the line: PHOTO;ENCODING=BASE64;JPEG:, and there is definitely a picture that shows up on my phone.
OK, after a little debugging:
In Ubuntu, at least, the line in the vCard file that starts with “PHOTO;ENCODING” is different. So you need to replace the line
echo $line | sed ‘s/PHOTO;ENCODING=b;TYPE=JPEG://’ >> photos/$filename.tmp
with
echo $line | sed ‘s/PHOTO;ENCODING=BASE64;JPEG://’ >> photos/$filename.tmp
There is probably a regexp that can handle both cases, if I figure it out I’ll post it here.
And in what I suspect is a Unix thing, looking for a ^M at the end of the line leads to an error, since Unix text lines only end with ‘\n’ (^J in your program, I believe). So in that case replace
cat $file | tr -d ‘\n’ | tr -d ‘^M’ | base64 -d > $filename.jpg
by
cat $file | tr -d ‘\n’ | base64 -d > $filename.jpg
There is a test to see if lines end with ^M^J or just ^M, again if I generalize the line I’ll post it here.
Once I did that, everything worked great. Thanks for the script, it made a difficult problem easy.
Thanks very much for all the handy feedback. Glad you got it working.
I’m hopefully getting an Android tablet to play with soon, so I’ll update this with a version which works on vCard files exported from both OS X and Android.