WebHelpers / webhelpers /

"""Multimedia helpers for images, etc."""

import logging
import os
import struct
import sys

__all__ = ["choose_height", "get_dimensions_pil", "get_dimensions"]

def choose_height(new_width, width, height):
    """Return the height corresponding to ``new_width`` that's proportional
       to the original size (``width`` x ``height``).
    proportion = float(height) / float(width)
    return int(new_width * proportion)

def get_dimensions_pil(path, default=(None, None)):
    """Get an image's size using the Python Imaging Library (PIL)

    Returns ``(width, height)`` as two integers, or ``default`` if the size
    could not be ascertained.  Failuer usually means the file does not exist
    or is not in a format recognized by PIL.

    Depends on the Python Imaging Library (
    See ``get_dimensions()`` if your application is not otherwise using PIL.
    import Image
        im = Image(path)
    except Exception:
        return default
    return im.size

def get_dimensions(path, default=(None, None)):
    """Get an image's size using only the Python standard library

    Returns ``(width, height)`` as two integers, or ``default`` if the size
    could not be ascertained.  Failure usually means the file does not exist
    or is not in a recognized format.  Only JPG/PNG/GIF/BMP are supported at
    this time.

    The algorithms are based on a PyCode recipe by Perenzo/Welch/Ray.

    This helper recognizes fewer image formats and is potentially less
    accurate than ``get_dimensions_pil()``.
    apath = os.path.abspath(path)
        f = open(path, "rb")
    except IOError:
        return default
        header =
        # JPG
        if header.startswith("\xFF\xD8"):
            width = height = None
            while True:
                length = 4
                buf =
                    marker, code, length = struct.unpack("!ccH", buf)
                except Exception:
                if marker != "\xff":
                if 0xc0 <= ord(code) <= 0xc3:
                    length = 5
                    buf =
                    height, width = struct.unpack("!xHH", buf)
            return width, height
        # PNG
        elif header.startswith("\x89PNG\x0d\x0a\x1a\x0a") or \
            control =
            if control in ["IHDR", "MHDR"]:
                buf =
                width, height = struct.unpack("!II", buf)
                return width, height
        # GIF
        elif header.startswith("GIF87a") or header.startswith("GIF89a"):
            buf =
            width, height, flags, bci, par = struct.unpack("<HHBBB", buf)
            return width, height
        # BMP
        elif header.startswith("BM"):
            buf =
            width, height = struct.unpack("<II", buf)
            return width, height
        # Unknown
        return default

def test_get_dimensions():
    files = sys.argv[1:]
    if not files:
        sys.exit("usage: %s FILES ...\nPrints dimensions of each image")
    for file in files:
        apath = os.path.abspath(file)
        print "%s:" % apath,
        if not os.path.isfile(file):
            print "does not exist or is not a plain file"
        width, height = get_dimensions(file)
        if width is None and height is None:
            print "could not get dimensions"
            if width is None:
                width = "UNKNOWN"
            if height is None:
                height = "UNKNOWN"
            print "%s x %s" % (width, height)

if __name__ == "__main__":  test_get_dimensions()