Python: Reading EXIF and IPTC tags from JPG/TIFF image files

Wow this was a bit of an "antigravity" moment for me (XKCD #353).

All I really needed to do was choose my poison:

  • Pillow (an actively maintained PIL fork which unofficially supports basic EXIF tag reading)
  • ExifRead (EXIF reader) v1.4.2 at time of writing
  • IPTCInfo (IPTC reader) v1.9.5-6 at time of writing


I'd just like to point out some things I learned the hard way.

  • If something isn't showing up in the EXIF tag data, then it's most likely saved as IPTC metadata (like title, subject and tags/comments in the screenshot below).
  • The fields XPTitle, XPComment, XPAuthor, XPKeywords and XPSubject are encoded in UCS2 (UTF-16). This will need to be converted, unless you like dealing with hex strings or byte arrays.
  • Combining an EXIF and IPTC method together will be your best way of extracting metadata from the file.



Using Pillow

This one reads some of the basic EXIF data but tended to be a bit clunky to use.

Helper function:

And to use it, simply pass in the values from Image._getexif(). The helper function convert_exif_to_dict() will make it easier for you to read information off, rather than referring to data by ID.

Would I recommend it? Probably not. ExifRead below is a much better candidate.

Using ExifRead

This alternative to using PIL can extract much more information and also makes it easier to fetch information, but it also does require you to install another library.

As you can see, this one is much cleaner to use, except for the weird problem where you have to access exif['something'].values instead of exif['something'].

It's not gonna ruin your day, but I guess you could write a helper function for it if it really bothered you.

There's also another bit in the snippet where I use join/map/unichr. That's because the values for those fields need to be converted from an array of bytes to a string which Python can understand.

Using IPTCInfo

Lastly there's IPTC, which I've NEVER heard of until I started trying to pull metadata from JPG/TIFF files. This was my antigravity moment where I just looked for a library, installed it and "it just works".

Sadly, it feels a little bit like a Java developer wrote it. Mainly because of little things like iptc.getData() where you can just use

You'll also feel a little lost without knowing which data keys to use, so can get a list of all the possible data key names by examining:

from iptcinfo import c_datasets, c_datasets_r

Those two dictionary objects will tell you what's available so it shouldn't be too hard to write a nice little wrapper for it. These kinda feel like Java enums =\

Are you ready to handle all this big data?


Python 2: Converting bytes array to String

This handy little snippet lets you convert an array of bytes to a string.

u"".join(map(unichr, bytesArray))

If you know you're working with ASCII, you can replace unichr with chr.

Once you got the string, you'll have to determine if decoding the string is necessary. You'll kinda have to know/guess the input encoding before you can convert it properly for 100% coverage.


Django: How to read current select_related() values

This was a bit of a tricky bit of information to get out. The information for select_related() is stored as a nested map. You'll need some recursive code to fetch that back out.

def generate_field_key(map, key, ancestor=None):
values = []
if ancestor:
parent = '%s__%s' % (ancestor, key)
parent = key
for k, v in map.items():
values.extend(generate_field_key(v, k, parent))
return values

# Select related is a nested map
qs = Something.objects.all().select_related('hey', 'hey__there')
select_related_data = qs.query.select_related
select_related = []

# This can be a map or False
if select_related_data:
for key, items in select_related_data.items():
select_related += generate_field_key(items, key, None)

print select_related

All good?

Remote Firebug-like web content debugging for your mobile device

Debugging browser quirks on your mobile device is a pain in the ass. There's no such Firebug or developer console or anything nice like their desktop counterparts.

The ability to quickly modify CSS on the fly easily saves hours of work. If only we had something like that for mobile web dev...

One could go mad debugging mobile CSS quirks...

One option is to use Firebug Lite, but to be honest, screen space is valuable and I personally would not be stuffed typing in names of CSS style properties on an on-screen keyboard.

In comes weinre to the rescue. This unfortunately named tool stands for WEb INspector REmote and is supposed to be pronounced "winery", but I always end up calling it "weener".

This gives you remote access to the content in the browser, via a another browser. It's as close as we'll get to a remote web Firebug for now.


I'm sorry to say but we'll need NodeJS for this. At time of writing I installed v0.10.18.

  • Download and install NodeJS.
  • Now open up the normal Windows Command Prompt (not the NodeJS one)
  • Type in:

npm -g install weinre

  • This installs weinre (v2.0.0-pre-HH0SN197 at time of writing)

Setup and debugging

  • Once it's all done, type:

weinre --bound -all-

  • Ensure that there are no firewall rules blocking this service (node.exe, allow inbound on port 8080 - such as uTorrent)
  • Edit your HTML and add this script into the <head> tag

<script src="http://YourWeinreIP:8080/target/target-script-min.js"></script>

  • Open up a desktop browser page to http://YourWeinreIP:8080/client
  • Load your test page on the mobile device and it should appear in the client list under "Targets"


  • Click on the link for the target so it turns green
  • Click "Elements" in the top menu
  • You should now see a familiar Chrome/Firebug style element tree and a CSS panel on the right.
  • The rest (resources, network, timeline, console) should be fairly straight forward.
  • Enjoy =)


Sublime Text: Automatically pretty format JSON and/or XML

I love the ability to quickly extend functionality in Sublime Text. For a while now I've been wanting a quick formatter for chunks of JSON/XML, so here's how I got it up and running on my Sublime Text 2.


You'll need to download these files from my github repo:


To install these files, you'll have to move them to the right place first.

  • Open up Sublime Text (I'm using v2.0.2 at time of writing)
  • Click on "Preferences" in the menu
  • Click on "Browse Packages..."
  • Open the "User" folder
  • Move and there
  • Check if "Main.sublime-menu" also exists in that folder
  • Open it in Sublime Text and paste in the following. If there is already some text in there, please merge them carefully. It shouldn't be too hard.

Now you should have to add it into the menu for easy access.


Update 19/05/15

Updated links to github raw source files. Fixes the issue where people were using "save files as" from this page and getting "greyed out menus".


Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog