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 This post was automatically imported from my old sandfly.net.nz blog. It may look a little weird since it was not originally written for this format.. 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()