terom@57: """ terom@57: Per-image gallery state terom@57: """ terom@57: terom@128: import filesystem, format, thumbnail, exif, utils terom@76: from utils import lazy_load terom@12: terom@12: import PIL.Image terom@33: terom@57: class Image (filesystem.File) : terom@57: """ terom@57: An Image is a filesystem File that represents an image that can be thumbnailed, and handled. terom@57: """ terom@44: terom@76: def __init__ (self, *args, **kwargs) : terom@57: """ terom@57: Initialize as an Image based on the given Node, linked with the given previous node terom@57: """ terom@57: terom@77: super(Image, self).__init__(*args, **kwargs) terom@57: terom@141: # use config from our folder terom@141: self.config = self.parent.config terom@141: terom@57: # links terom@76: self.prev = None terom@57: self.next = None terom@57: terom@57: # the .html file for this image terom@141: # XXX: keep .jpg/etc file extension? terom@57: self.html = self.parent.subfile(self.basename + '.html') terom@57: terom@85: # our preview/thumbnail terom@85: self.preview = thumbnail.Thumbnail(self, self.parent.preview_dir, self.config.preview_size) terom@85: self.thumb = thumbnail.Thumbnail(self, self.parent.thumb_dir, self.config.thumb_size) terom@85: terom@57: # info terom@57: self.title = self.name terom@57: self.description = None terom@57: terom@77: @lazy_load terom@115: def img (self) : terom@57: """ terom@57: Loads the image as a PIL.Image terom@57: """ terom@57: terom@77: # open it up terom@77: return PIL.Image.open(self.path) terom@115: terom@115: @property terom@115: def img_size (self) : terom@115: """ terom@115: Returns the pixel (width, height) resolution tuple of this image. terom@115: """ terom@115: terom@115: return self.img.size terom@57: terom@77: @lazy_load terom@77: def exif (self) : terom@57: """ terom@120: Loads the ExifHandler object for this image. terom@57: terom@57: Returns None if no exif data was found terom@57: """ terom@57: terom@120: # look up using exif terom@120: return exif.load(self.config, self) terom@77: terom@77: @lazy_load terom@122: def orientation (self) : terom@122: """ terom@122: Loads the orientation of this image as a (mirroring, rotation) tuple, or None, if the information is not available. terom@122: """ terom@122: terom@122: if self.config.with_exif and self.exif : terom@122: # try and find it terom@122: return self.exif.get_orientation() terom@122: terom@122: else : terom@122: # no exif data terom@122: return None terom@122: terom@122: @lazy_load terom@77: def metadata (self) : terom@57: """ terom@57: Load and return the metadata for the image as a dictionary terom@57: """ terom@57: terom@77: # load stuff terom@85: stat = self.stat() terom@57: terom@77: # XXX: avoid having to open the image? terom@115: size = self.img_size terom@77: terom@77: # build terom@120: metadata = [ terom@120: ("File name", self.name), terom@120: ("Resolution", "%dx%d" % size), terom@120: ("File size", format.filesize(stat.st_size)), terom@120: ("Last modified", format.filetime(stat.st_mtime)), terom@120: ] terom@111: terom@111: # optionally load Exif metadata terom@120: if self.config.with_exif and self.exif : terom@120: exif_tag_name = dict(self.config.exif_tags) terom@120: exif_tags = (tag for tag, name in self.config.exif_tags) terom@111: terom@120: # merge the wanted tags terom@120: metadata.extend(( terom@120: (exif_tag_name[tag], value) for tag, value in self.exif.image_tags(exif_tags) terom@111: )) terom@111: terom@111: return metadata terom@57: terom@85: def stale (self) : terom@57: """ terom@85: Tests if this Image is stale, based on preview/thumb. terom@57: """ terom@57: terom@85: return self.preview.stale() or self.thumb.stale() terom@70: terom@85: def update (self) : terom@70: """ terom@85: Updates this Image's thumb/preview terom@70: """ terom@85: terom@91: self.preview.update() terom@91: self.thumb.update() terom@123: terom@123: def cleanup (self) : terom@123: """ terom@125: Drop some memory-intensive cached values terom@123: """ terom@128: terom@128: utils.unload(self, 'img', 'exif', 'metadata') terom@57: