Small maker of thumbnails and spitter-out of HTML for galleries.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

121 lines
4.5 KiB

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