"""
This plugin uses the metadata from JPEG images (EXIF and IPTC) to construct a meaningful page or gallery.
Possible uses are gallery pages or a blog article that's mainly about an image.
With this tool, it's posible to just dump an image without any extra data/linkage to create coherent output.
The note here is that the extension is `jpeg_article` so it doesn't pick up {attach} or other static resources.
"""
import logging
from datetime import datetime
from os import makedirs, sep
from os.path import join, dirname, isdir, splitext
from typing import Tuple
from PIL import Image
from pelican import signals
from pelican.readers import BaseReader
from pelican.urlwrappers import URLWrapper, Category, Author, Tag
from .constants import Exiv, PelicanConfig, PelicanMetadata, PelicanClass
from .exiv2_parser import Exiv2Parser
class JpegReader(BaseReader):
logger = logging.getLogger('JpegReader')
enabled = True
file_extensions = ('jpeg_article')
thumb_size = 250, 250
def __init__(self, settings):
super(JpegReader, self).__init__(settings)
def read(self, source_path):
try:
if Exiv2Parser.get_exiv2_version() is not None:
content, metadata = self.parse_jpeg(source_path=source_path)
except ValueError: # if file can't be parsed, ignore it
pass
else:
return content, metadata
def parse_jpeg(self, *, source_path: str) -> Tuple[str, dict]:
JpegReader.logger.info(source_path)
img = Image.open(source_path)
image_data = Exiv2Parser.get_values(source_path)
title = image_data.get(Exiv.DESCRIPTION.value, 'Untitled')
author = image_data.get(Exiv.ARTIST.value, 'Unknown')
date_string = image_data.get(Exiv.DATETIME.value, '')
date = datetime.strptime(date_string, "%Y:%m:%d %H:%M:%S")
slug = URLWrapper(image_data.get(Exiv.HEADLINE.value, title), self.settings).slug
description_long = image_data.get(Exiv.COMMENT.value, '')
summary = image_data.get(Exiv.CAPTION.value, description_long[:140])
tags = [Tag(tag, self.settings) for tag in image_data.get(Exiv.KEYWORDS.value, list())]
content_root = self.settings[PelicanConfig.PATH.value]
path_output = self.settings[PelicanConfig.OUTPUT_PATH.value]
relative_source = dirname(source_path[len(content_root):]).lstrip(sep)
if self.settings[PelicanConfig.USE_FOLDER_AS_CATEGORY.value]:
category = relative_source.split(sep)[-1]
else:
category = image_data.get(Exiv.CATEGORY.value, None)
type_of_content = relative_source.split(sep)[0] # either 'blog' or 'pages' as far as I know.
url_site = self.settings[PelicanConfig.SITE_URL.value]
if type_of_content.lower() == PelicanClass.PAGES.value:
url_document = self.settings[PelicanConfig.PAGE_URL.value]
document_save_as = self.settings[PelicanConfig.PAGE_SAVE_AS.value]
else: # Assume PelicanClass.BLOG
url_document = self.settings[PelicanConfig.ARTICLE_URL.value]
document_save_as = self.settings[PelicanConfig.ARTICLE_SAVE_AS.value]
page_url_complete = join(url_site, url_document)
author_wrapper = Author(author, self.settings)
# Move image in place:
metadata = {PelicanMetadata.TITLE.value: title, PelicanMetadata.AUTHORS.value: [author_wrapper],
PelicanMetadata.DATE.value: date, PelicanMetadata.SLUG.value: slug,
PelicanMetadata.TAGS.value: tags,
PelicanMetadata.CUSTOM_ALL.value: image_data}
if category is not None:
metadata[PelicanMetadata.CATEGORY.value] = Category(category, self.settings)
thumb_name = '{0}_thumb.jpg'.format(slug)
original_name = '{0}.jpg'.format(slug)
path_output_html = join(path_output, document_save_as).format(**metadata)
path_output_dir = dirname(path_output_html)
path_output_original = join(path_output_dir, original_name)
path_output_thumb = join(path_output_dir, thumb_name)
# Here we generate the summary info incase this is used for articles we get nice thumbnails and summary
metadata[PelicanMetadata.SUMMARY.value] = summary
metadata[PelicanMetadata.FEATURED_IMAGE.value] = join(url_site, path_output_thumb[len(path_output):])
if Exiv.OBJECT_NAME.value in image_data:
metadata[PelicanMetadata.TEMPLATE.value] = image_data[Exiv.OBJECT_NAME.value]
# Write the size/HTML out before we reduce the image to a thumb
content = "
{body}
" \ .format(src=original_name, alt=title, width=img.width, height=img.height, body=description_long) # Ensure the directory levels exist if not isdir(path_output_dir): makedirs(path_output_dir) img.save(path_output_original) img.thumbnail(self.thumb_size) img.save(path_output_thumb) # Debug info if we need it JpegReader.logger.debug(content) JpegReader.logger.debug(str(metadata)) JpegReader.logger.debug(path_output_html) return content, metadata def add_reader(readers): readers.reader_classes['jpeg_article'] = JpegReader def register(): signals.readers_init.connect(add_reader)