degal/image.py
author Tero Marttila <terom@fixme.fi>
Fri, 05 Jun 2009 23:05:11 +0300
changeset 70 67dd32adf159
parent 57 8d06e0283b88
child 76 e22d9f699081
permissions -rw-r--r--
remove old Folder, Image code, wrap up both
"""
    Per-image gallery state
"""

from __future__ import with_statement

import filesystem, render, html

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, node, prev) :
        """
            Initialize as an Image based on the given Node, linked with the given previous node
        """

        super(Image, self).__init__(node)

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

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

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

        # lazy-loading
        self.img = None
        self.exif = None
        self.metadata = None
        self.stat_data = None

    def load_stat (self) :
        """
            Load and return the os.stat info for this file
        """

        if not self.stat_data :
            self.stat_data = self.stat()

        return self.stat_data

    def load_image (self) :
        """
            Loads the image as a PIL.Image
        """
        
        if not self.img :
            # open it up
            self.img = PIL.Image.open(self.path)

        return self.img

    def load_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
        """

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

        else :
            return None

    def load_metadata (self) :
        """
            Load and return the metadata for the image as a dictionary
        """

        if not self.metadata :
            # load stuff
            stat = self.load_stat()
            exif = self.load_exif()

            # XXX: avoid having to open the image?
            size = self.load_image().size
            
            # build
            self.metadata = dict({
                "File name":        self.name,
                "Resolution":       "%dx%d" % size,
                "File size":        format.filesize(stat.st_size),
                "Last modified":    format.filetime(stat.st_mtime),
            }, **dict(
                (name, exif[tag]) for tag, name in self.config.exif_tags if exif and tag in exif
            ))

        return self.metadata
    
    @lazy_load
    def thumb (self) :
        """
            Load and update the thumbnail if needed
        """

        # renderer to use
        # XXX: get from elsewhere
        render_machine = self.config.get_renderer()

        # render if needed
        return render_machine.render_lazy(self
            self.config.thumb_size, self.parent.load_thumb_dir.subnode(self.name)
        )
    
    @lazy_load
    def preview (self) :
        """
            Load and update the preview if needed
        """

        # renderer to use
        # XXX: get from elsewhere
        render_machine = self.config.get_renderer()

        return render_machine.render_lazy(self, 
            self.config.preview_size, self.parent.load_preview_dir.subnode(self.name)
        )