diff --git a/AUTHORS b/AUTHORS index 215c7da..d8ed820 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,6 +5,7 @@ alphabetical order): - Andreas Sieferlinger - Antoine Pitrou - Christophe-Marie Duquesne +- @franek (François D.) - Giel van Schijndel - Jamie Starke - @jdn06 diff --git a/sigal/gallery.py b/sigal/gallery.py index 9eef6c8..507732c 100644 --- a/sigal/gallery.py +++ b/sigal/gallery.py @@ -3,6 +3,7 @@ # Copyright (c) 2009-2014 - Simon Conseil # Copyright (c) 2013 - Christophe-Marie Duquesne # Copyright (c) 2014 - Jonas Kaufmann +# Copyright (c) 2015 - François D. # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -41,7 +42,7 @@ from PIL import Image as PILImage from . import image, video, signals from .compat import PY2, UnicodeMixin, strxfrm, url_quote, text_type -from .image import process_image, get_exif_tags, get_exif_data +from .image import process_image, get_exif_tags, get_exif_data, get_size from .settings import get_thumb from .utils import (Devnull, copy, check_or_create_dir, url_from_path, read_markdown, cached_property, is_valid_html5_video, @@ -168,6 +169,14 @@ class Image(Media): self.src_path) return None + @cached_property + def size(self): + return get_size(self.dst_path) + + @cached_property + def thumb_size(self): + return get_size(self.thumb_path) + class Video(Media): """Gather all informations on a video file.""" @@ -370,17 +379,18 @@ class Album(UnicodeMixin): for f in self.medias: ext = splitext(f.filename)[1] if ext.lower() in Image.extensions: - try: - im = PILImage.open(f.src_path) - except: - self.logger.error("Failed to open %s", f.src_path) - else: - if im.size[0] > im.size[1]: - self._thumbnail = join(self.name, f.thumbnail) - self.logger.debug( - "Use 1st landscape image as thumbnail for %r :" - " %s", self, self._thumbnail) - return url_from_path(self._thumbnail) + # Use f.size if available as it is quicker (in cache), but + # fallback to the size of src_path if dst_path is missing + size = f.size + if size is None: + size = get_size(f.src_path) + + if size['width'] > size['height']: + self._thumbnail = join(self.name, f.thumbnail) + self.logger.debug( + "Use 1st landscape image as thumbnail for %r :" + " %s", self, self._thumbnail) + return url_from_path(self._thumbnail) # else simply return the 1st media file if not self._thumbnail and self.medias: diff --git a/sigal/image.py b/sigal/image.py index 0450ded..d77ff08 100644 --- a/sigal/image.py +++ b/sigal/image.py @@ -1,6 +1,7 @@ # -*- coding:utf-8 -*- # Copyright (c) 2009-2014 - Simon Conseil +# Copyright (c) 2015 - François D. # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -151,8 +152,8 @@ def process_image(filepath, outpath, settings): if settings['make_thumbs']: thumb_name = os.path.join(outpath, get_thumb(settings, filename)) generate_thumbnail(outname, thumb_name, settings['thumb_size'], - settings['thumb_video_delay'], fit=settings['thumb_fit'], - options=options) + settings['thumb_video_delay'], + fit=settings['thumb_fit'], options=options) except Exception as e: logger.info('Failed to process: %r', e) return Status.FAILURE @@ -160,6 +161,21 @@ def process_image(filepath, outpath, settings): return Status.SUCCESS +def get_size(file_path): + """Return image size (width and height).""" + try: + im = PILImage.open(file_path) + except (IOError, IndexError, TypeError, AttributeError) as e: + logger = logging.getLogger(__name__) + logger.error("Could not read size of %s due to %r", file_path, e) + else: + width, height = im.size + return { + 'width': width, + 'height': height + } + + def get_exif_data(filename): """Return a dict with the raw EXIF data.""" diff --git a/tests/test_image.py b/tests/test_image.py index b6c27b2..638ac26 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -6,7 +6,7 @@ from PIL import Image from sigal import init_logging from sigal.image import (generate_image, generate_thumbnail, get_exif_tags, - get_exif_data) + get_exif_data, get_size) from sigal.settings import create_settings CURRENT_DIR = os.path.dirname(__file__) @@ -115,3 +115,22 @@ def test_exif_gps(tmpdir): assert abs(simple['gps']['lat'] - lat) < 0.0001 assert abs(simple['gps']['lon'] - lon) < 0.0001 + +def test_get_size(tmpdir): + """Test reading out image size""" + + test_image = 'flickr_jerquiaga_2394751088_cc-by-nc.jpg' + src_file = os.path.join(CURRENT_DIR, 'sample', 'pictures', 'dir1', 'test1', + test_image) + + result = get_size(src_file) + assert result == {'height': 800, 'width': 600} + +def test_get_size_with_invalid_path(tmpdir): + """Test reading out image size with a missing file""" + + test_image = 'missing-file.jpg' + src_file = os.path.join(CURRENT_DIR, test_image) + + result = get_size(src_file) + assert result == None \ No newline at end of file