degal/image.py
author Tero Marttila <terom@fixme.fi>
Wed, 01 Jul 2009 20:40:00 +0300
changeset 141 9387da0dc183
parent 128 f66bb9f6126a
permissions -rw-r--r--
move .config from filesystem to gallery/folder/image, rename degal_dir to app_dir
"""
    Per-image gallery state
"""

import filesystem, format, thumbnail, exif, utils
from utils import lazy_load

import PIL.Image

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)

        # use config from our folder
        self.config = self.parent.config

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

        # the .html file for this image
        # XXX: keep .jpg/etc file extension?
        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 ExifHandler object for this image.

            Returns None if no exif data was found
        """

        # look up using exif
        return exif.load(self.config, self)
    
    @lazy_load
    def orientation (self) :
        """
            Loads the orientation of this image as a (mirroring, rotation) tuple, or None, if the information is not available.
        """

        if self.config.with_exif and self.exif :
            # try and find it
            return self.exif.get_orientation()

        else :
            # no exif data
            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 = [
            ("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.with_exif and self.exif :
            exif_tag_name = dict(self.config.exif_tags)
            exif_tags = (tag for tag, name in self.config.exif_tags)

            # merge the wanted tags
            metadata.extend((
                (exif_tag_name[tag], value) for tag, value in self.exif.image_tags(exif_tags)
            ))

        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()
    
    def cleanup (self) :
        """
            Drop some memory-intensive cached values
        """
        
        utils.unload(self, 'img', 'exif', 'metadata')