Finding the Dimensions of a JPEG file in Python

Andrew Stephens, Saturday the 14th of September, 2013 in Computing

For a project I am working on I had to quickly throw together a Python function to grab the width and height of JPEG files on disk . There is nothing in the python standard library to do this and although some third party projects that read JPEG files (micro-jpeg-visulaizer, PIL) they seem like overkill if all you want are the dimensions.

A quick trip to the JPEG standards document provided the information I needed. In case anyone else needs something similar, here is what I came up with:

from struct import unpack

def GetWidthAndHeight(stream):
    """ Extract the dimensions from a jpeg file as a tuple (width, height)

    Keyword arguments:
    stream -- a stream (eg: open()ed). Must be opened in binary mode

    Author: Andrew Stephens http://sandfly.net.nz/
    License: use in any way you wish
    """
    while (True):
        data = stream.read(2)
        marker, = unpack(">H", data)

        # some markers stand alone
        if (marker == 0xffd8):  # start of image
            continue
        if (marker == 0xffd9):  # end of image
            return;
        if ((marker >= 0xffd0) and (marker <= 0xffd7)): # restart markers
            continue
        if (marker == 0xff01): # private marker:
            continue

        # all other markers specify chunks with lengths
        data = stream.read(2)
        length, = unpack(">H", data)

        if (marker == 0xffc0):  # baseline DCT chunk, has the info we want
            data = stream.read(5)
            t, height, width = unpack(">BHH", data)
            return (width, height)

        # not the chunk we want, skip it
        stream.seek(length - 2, 1)

This should be quicker than other solutions since it skips over parts of the stream it doesn't need and is flexible enough to work on anything that looks like a seekable file. Beware, it may misbehave on malformed files.

Usage is simple:

f = open("somepicture.jpg", "rb")   # need to open the stream in binary mode
w, h = GetWidthAndHeight(f)
f.close()