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. Note that with more recent versions of OS X, you need to change base64 -d in the script to base64 -D with a capital D (thanks to Interuptic for the tip).

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). Alternatively, grab the script from GitHub.

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 nt$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 " donen"

echo -ne "Removing empty photos..."
find photos -empty -exec rm -f {} +
echo -ne " donen"

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 " donen"