diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2011-05-05 08:42:04 -0400 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2011-05-05 08:42:04 -0400 |
commit | 536bc214c005fe697762fadebe8b3726bd2366e8 (patch) | |
tree | 43dfa248b19f4f4c9c51181b169069f4aa71c23e /PhotoAlbum.py | |
parent | Clean up date time conversions. (diff) | |
download | PhotoFloat-536bc214c005fe697762fadebe8b3726bd2366e8.tar.xz PhotoFloat-536bc214c005fe697762fadebe8b3726bd2366e8.zip |
Make thumbnails.
Diffstat (limited to 'PhotoAlbum.py')
-rw-r--r-- | PhotoAlbum.py | 114 |
1 files changed, 90 insertions, 24 deletions
diff --git a/PhotoAlbum.py b/PhotoAlbum.py index 0bbbb09..a8fe71d 100644 --- a/PhotoAlbum.py +++ b/PhotoAlbum.py @@ -6,6 +6,8 @@ from PIL.ExifTags import TAGS def set_cache_path_base(base): trim_base.base = base +def untrim_base(path): + return os.path.join(trim_base.base, path) def trim_base(path): if path.startswith(trim_base.base): path = path[len(trim_base.base):] @@ -41,7 +43,7 @@ class Album(object): def date(self): self._sort() if len(self._photos) == 0 and len(self._albums) == 0: - return datetime.min + return datetime(1900, 1, 1) elif len(self._photos) == 0: return self._albums[-1].date elif len(self._albums) == 0: @@ -77,7 +79,7 @@ class Album(object): def from_dict(dictionary, cripple=True): album = Album(dictionary["path"]) for photo in dictionary["photos"]: - album.add_photo(Photo.from_dict(photo, album.path)) + album.add_photo(Photo.from_dict(photo, untrim_base(album.path))) if not cripple: for subalbum in dictionary["albums"]: album.add_album(Album.from_dict(subalbum), cripple) @@ -90,46 +92,104 @@ class Album(object): else: subalbums = self._albums return { "path": self.path, "date": self.date, "albums": subalbums, "photos": self._photos } + def photo_from_path(self, path): + for photo in self._photos: + if trim_base(path) == photo._path: + print "cache hit %s" % path + return photo + return None class Photo(object): - def __init__(self, path, attributes=None): + def __init__(self, path, thumb_path=None, attributes=None): self._path = trim_base(path) self.is_valid = True mtime = datetime.fromtimestamp(os.path.getmtime(path)) - if attributes is not None and attributes["FileTime"] >= mtime: + if attributes is not None and attributes["DateTimeFile"] >= mtime: self._attributes = attributes return self._attributes = {} - self._attributes["FileTime"] = mtime + self._attributes["DateTimeFile"] = mtime try: - i = Image.open(path) + image = Image.open(path) except: self.is_valid = False return + self._metadata(image) + self._thumbnails(image, thumb_path) + def _metadata(self, image): try: - info = i._getexif() + info = image._getexif() except: - info = None - if info: - for tag, value in info.items(): - decoded = TAGS.get(tag, tag) - if not isinstance(decoded, int) and decoded not in ['JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'FileSource', 'MakerNote', 'UserComment', 'ImageDescription', 'ComponentsConfiguration']: - if isinstance(value, str): - value = value.strip() - if decoded.startswith("DateTime"): - try: - value = datetime.strptime(value, '%Y:%m:%d %H:%M:%S') - except: - pass - self._attributes[decoded] = value + return + for tag, value in info.items(): + decoded = TAGS.get(tag, tag) + if not isinstance(decoded, int) and decoded not in ['JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'FileSource', 'MakerNote', 'UserComment', 'ImageDescription', 'ComponentsConfiguration']: + if isinstance(value, str): + value = value.strip() + if decoded.startswith("DateTime"): + try: + value = datetime.strptime(value, '%Y:%m:%d %H:%M:%S') + except: + pass + self._attributes[decoded] = value + def _thumbnail(self, image, thumb_path, size, square=False): + if square: + suffix = str(size) + "s" + else: + suffix = str(size) + thumb_path = os.path.join(thumb_path, image_cache(self._path, suffix)) + if os.path.exists(thumb_path) and datetime.fromtimestamp(os.path.getmtime(thumb_path)) >= self._attributes["DateTimeFile"]: + return + image = image.copy() + if square: + if image.size[0] > image.size[1]: + left = (image.size[0] - image.size[1]) / 2 + top = 0 + right = image.size[0] - ((image.size[0] - image.size[1]) / 2) + bottom = image.size[1] + else: + left = 0 + top = (image.size[1] - image.size[0]) / 2 + right = image.size[0] + bottom = image.size[1] - ((image.size[1] - image.size[0]) / 2) + image = image.crop((left, top, right, bottom)) + image.thumbnail((size, size), Image.ANTIALIAS) + image.save(thumb_path, "JPEG") + print "saving %s" % thumb_path + + def _thumbnails(self, image, thumb_path): + orientation = self._attributes["Orientation"] + mirror = image + if orientation == 2: + # Vertical Mirror + mirror = image.transpose(Image.FLIP_LEFT_RIGHT) + elif orientation == 3: + # Rotation 180 + mirror = image.transpose(Image.ROTATE_180) + elif orientation == 4: + # Horizontal Mirror + mirror = image.transpose(Image.FLIP_TOP_BOTTOM) + elif orientation == 5: + # Horizontal Mirror + Rotation 270 + mirror = image.transpose(Image.FLIP_TOP_BOTTOM).transpose(Image.ROTATE_270) + elif orientation == 6: + # Rotation 270 + mirror = image.transpose(Image.ROTATE_270) + elif orientation == 7: + # Vertical Mirror + Rotation 270 + mirror = image.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_270) + elif orientation == 8: + # Rotation 90 + mirror = image.transpose(Image.ROTATE_90) + self._thumbnail(mirror, thumb_path, 100, True) + self._thumbnail(mirror, thumb_path, 640) + self._thumbnail(mirror, thumb_path, 1024) @property def name(self): return os.path.basename(self._path) def __str__(self): return self.name - def cache_path(self, size): - return image_cache(self.path, size) @property def date(self): if "DateTimeOriginal" in self._attributes: @@ -137,7 +197,7 @@ class Photo(object): elif "DateTime" in self._attributes: return self._attributes["DateTime"] else: - return self._attributes["FileTime"] + return self._attributes["DateTimeFile"] def __cmp__(self, other): return cmp(self.date, other.date) @property @@ -148,6 +208,12 @@ class Photo(object): del dictionary["date"] path = os.path.join(basepath, dictionary["name"]) del dictionary["name"] + for key, value in dictionary.items(): + if key.startswith("DateTime"): + try: + dictionary[key] = datetime.strptime(dictionary[key], "%a %b %d %H:%M:%S %Y") + except: + pass return Photo(path, dictionary) def to_dict(self): photo = { "name": self.name, "date": self.date } @@ -157,7 +223,7 @@ class Photo(object): class PhotoAlbumEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime): - return obj.isoformat() + return obj.strftime("%a %b %d %H:%M:%S %Y") if isinstance(obj, Album) or isinstance(obj, Photo): return obj.to_dict() return json.JSONEncoder.default(self, obj) |