degal/image.py
author Tero Marttila <terom@fixme.fi>
Sun, 14 Jun 2009 18:08:55 +0300
changeset 115 d5aa320697df
parent 111 ecceaf23c969
child 118 60b126ff0b74
permissions -rw-r--r--
rename Image.pil_image -> Image.img, and shave off ~30ms per image by using Image.resize instead of Image.copy/Image.thumbnail
"""
    Per-image gallery state
"""

from __future__ import with_statement

import filesystem, format, thumbnail
from utils import lazy_load

import PIL.Image
from lib import EXIF

class Image (filesystem.File) :
    """
        An Image is a filesystem File that represents an image that can be thumbnailed, and handled.
    """

    def __init__ (self, *args, **kwargs) :
        """
            Initialize as an Image based on the given Node, linked with the given previous node
        """

        super(Image, self).__init__(*args, **kwargs)

        # links
        self.prev = None
        self.next = None

        # the .html file for this image
        self.html = self.parent.subfile(self.basename + '.html')

        # our preview/thumbnail
        self.preview = thumbnail.Thumbnail(self, self.parent.preview_dir, self.config.preview_size)
        self.thumb = thumbnail.Thumbnail(self, self.parent.thumb_dir, self.config.thumb_size)

        # info
        self.title = self.name
        self.description = None

    @lazy_load
    def img (self) :
        """
            Loads the image as a PIL.Image
        """
        
        # open it up
        return PIL.Image.open(self.path)
    
    @property
    def img_size (self) :
        """
            Returns the pixel (width, height) resolution tuple of this image.
        """

        return self.img.size

    @lazy_load
    def exif (self) :
        """
            Loads the EXIF data for the image and returns as a dict of EXIF tag names -> values.

            Returns None if no exif data was found
        """

        # load
        with self.open('rb') as fh :
            # XXX: details=False?
            exif = EXIF.process_file(fh)
            
        # empty dict -> no exif data
        if exif :
            return exif

        else :
            return None
    
    @lazy_load
    def metadata (self) :
        """
            Load and return the metadata for the image as a dictionary
        """

        # load stuff
        stat = self.stat()

        # XXX: avoid having to open the image?
        size = self.img_size
        
        # build
        metadata = dict({
            "File name":        self.name,
            "Resolution":       "%dx%d" % size,
            "File size":        format.filesize(stat.st_size),
            "Last modified":    format.filetime(stat.st_mtime),
        })
        
        # optionally load Exif metadata
        if self.config.exif_enabled :
            exif = self.exif

            # Get the wanted tags
            metadata.update(dict(
                (name, exif[tag]) for tag, name in self.config.exif_tags if exif and tag in exif
            ))

        return metadata
    
    def stale (self) :
        """
            Tests if this Image is stale, based on preview/thumb.
        """

        return self.preview.stale() or self.thumb.stale()
    
    def update (self) :
        """
            Updates this Image's thumb/preview
        """
        
        self.preview.update()
        self.thumb.update()