- from PIL import Image, ImageOps, ImageEnhance, ExifTags
- from dominate.tags import *
- import dominate
- import glob as g, os
- import json
- import traceback
-
- class GalleryHTML:
- """A maker of thumbnails, HTML galleries, and simple JSON indices"""
-
- def __init__(self):
- # Set some defaults:
- self.output_dir = '.'
- self.base_url = ""
- self.extensions = ['JPG', 'jpg', 'jpeg', 'png', 'gif', 'bmp']
- self.image_list = []
- self.x = 200
- self.y = 200
- self.square = False
- self.overwrite = False
-
- def add_images_from(self, source):
- # Ensure that thumbnail directory exists:
- thumb_directory = self.output_dir + "/Thumbs"
- os.makedirs(thumb_directory, exist_ok=True)
-
- for image in sorted(self._get_images(source)):
- image_basename = os.path.basename(image)
- thumbnail_src = self.base_url + 'Thumbs/' + image_basename
- image_href = self.base_url + image_basename
-
- image_size = self._thumbnailize(image, thumb_directory + '/' + image_basename)
- self.image_list.append((thumbnail_src, image_href, image_size))
-
- def _get_images(self, source):
- """Get a list of images from a source directory or pattern."""
- images = []
-
- if os.path.isdir(source):
- # Grab things with common file extensions out of dirs:
- for extension in self.extensions:
- images.extend(g.glob(source + '/*.' + extension))
- else:
- # Assume a pattern or single filename:
- images.extend(g.glob(source))
-
- return images
-
- def images_html(self):
- """Return HTML for an image list."""
- html_output = ''
- for display_image in self.image_list:
- (x, y) = display_image[2]
- html_output += a(img(src=display_image[0], width=x, height=y),
- href=display_image[1]).render() + "\n"
- return html_output.strip()
-
- def images_json(self):
- """Return JSON for an image list."""
- return json.dumps(self.image_list)
-
- def _handle_exif(self, source_image):
- """
- Handle EXIF rotation data, maybe - per:
- https://stackoverflow.com/questions/4228530/pil-thumbnail-is-rotating-my-image
- """
-
- # PNG files don't have EXIF data; avoid an exception on _getexif():
- if source_image.format == 'PNG':
- return source_image
-
- try:
- for tag in ExifTags.TAGS.keys():
- if ExifTags.TAGS[tag] == 'Orientation':
- break
-
- if source_image._getexif():
- # We have EXIF metadata to work with:
- exif = dict(source_image._getexif().items())
-
- orientation = exif.get(tag, False)
-
- if orientation == 3:
- source_image = source_image.rotate(180, expand=True)
- elif orientation == 6:
- source_image = source_image.rotate(270, expand=True)
- elif orientation == 8:
- source_image = source_image.rotate(90, expand=True)
- except:
- traceback.print_exc()
-
- return source_image;
-
- def _thumbnailize(self, image, thumbnail_file):
- """Write thumbnails."""
- image_size = (self.x, self.y)
-
- if os.path.isfile(thumbnail_file) and (not self.overwrite):
- # Skip existing files, unless we've been told to overwrite, but make
- # sure we know the correct width and height for them:
- with open(thumbnail_file, 'r+b') as f:
- with Image.open(f) as existing_thumbnail:
- image_size = existing_thumbnail.size
- else:
- # Write a new thumbnail:
- with open(image, 'r+b') as f:
- with Image.open(f) as source_image:
- source_image = self._handle_exif(source_image);
- # thumb = ImageEnhance.Sharpness(ImageOps.fit(source_image, (thumb_x, thumb_y))).enhance(0.15)
- if self.square:
- # Square things off, then make and save thumbnail
- smaller_dim = min(source_image.size)
- thumb = ImageOps.fit(source_image, (smaller_dim, smaller_dim))
- else:
- thumb = source_image
-
- thumb.thumbnail((self.x, self.y))
- image_size = thumb.size
- thumb.save(thumbnail_file, source_image.format)
-
- return image_size
|