class ImageThumbnailer(ContextAdapter): """Image thumbnailer adapter""" label = _("Default thumbnail") section = _("Default thumbnail") weight = 1 def get_default_geometry(self, options=None): # pylint: disable=unused-argument """Default thumbnail geometry""" geometry = ThumbnailGeometry() width, height = self.context.get_image_size() geometry.x1 = 0 # pylint: disable=invalid-name geometry.y1 = 0 # pylint: disable=invalid-name geometry.x2 = width # pylint: disable=invalid-name geometry.y2 = height # pylint: disable=invalid-name return geometry def create_thumbnail(self, target, format=None): # pylint: disable=redefined-builtin,too-many-branches """Create thumbnail of given size and format :param target: size or geometry of the thumbnail :param format: image format """ # check thumbnail name if isinstance(target, str): width, height = tuple(map(int, target.split('x'))) elif IThumbnailGeometry.providedBy(target): width = target.x2 - target.x1 height = target.y2 - target.y1 elif isinstance(target, tuple): width, height = target else: return None # check format with self.context as blob: try: if blob is None: return None image = Image.open(blob) if not format: format = image.format format = format.upper() if format not in WEB_FORMATS: format = 'JPEG' # check image mode if image.mode in ('P', 'RGBA'): if format == 'JPEG': image = image.convert('RGB') elif image.mode != 'RGBA': image = image.convert('RGBA') # generate thumbnail new_image = BytesIO() image.resize((width, height), Image.ANTIALIAS) \ .filter(ImageFilter.UnsharpMask(radius=0.5, percent=100, threshold=0)) \ .save(new_image, format) return new_image, format.lower() finally: if blob is not None: blob.close()
class ImageCardThumbnailer(ImageHorizontalThumbnailer): """Image card thumbnail adapter""" label = _("Card thumbnail") weight = 8 ratio = (2, 1)
class ImageBannerThumbnailer(ImageRatioThumbnailer): """Image banner thumbnail adapter""" label = _("Banner thumbnail") weight = 9 ratio = (5, 1)
class ImagePanoThumbnailer(ImageHorizontalThumbnailer): """Image panoramic thumbnail adapter""" label = _("Panoramic thumbnail") weight = 7 ratio = (16, 9)
class ImageSquareThumbnailer(ImageRatioThumbnailer): """Image square thumbnail adapter""" label = _("Square thumbnail") weight = 6 ratio = (1, 1)
class ImagePortraitThumbnailer(ImageRatioThumbnailer): """Image portrait thumbnail adapter""" label = _("Portrait thumbnail") weight = 5 ratio = (3, 4)
class ImageSelectionThumbnailer(ImageThumbnailer): """Image thumbnailer based on user selection""" section = _("Custom selections") def create_thumbnail(self, target, format=None): # pylint: disable=redefined-builtin,too-many-branches # get thumbnail size if isinstance(target, str): # pylint: disable=assignment-from-no-return geometry = IThumbnails(self.context).get_geometry(target) match = THUMB_SIZE.match(target) if match: width, height = tuple(map(int, match.groups())) else: width = abs(geometry.x2 - geometry.x1) height = abs(geometry.y2 - geometry.y1) elif IThumbnailGeometry.providedBy(target): geometry = target width = abs(geometry.x2 - geometry.x1) height = abs(geometry.y2 - geometry.y1) elif isinstance(target, tuple): width, height = target geometry = self.get_default_geometry() else: return None # check format with self.context as blob: try: if blob is None: return None image = Image.open(blob) if not format: format = image.format format = format.upper() if format not in WEB_FORMATS: format = 'JPEG' # check image mode if image.mode in ('P', 'RGBA'): if format == 'JPEG': image = image.convert('RGB') elif image.mode != 'RGBA': image = image.convert('RGBA') # generate thumbnail new_image = BytesIO() thumb_size = self.get_thumb_size(width, height, geometry) image.crop((geometry.x1, geometry.y1, geometry.x2, geometry.y2)) \ .resize(thumb_size, Image.ANTIALIAS) \ .filter(ImageFilter.UnsharpMask(radius=0.5, percent=100, threshold=0)) \ .save(new_image, format) return new_image, format.lower() finally: if blob is not None: blob.close() def get_thumb_size(self, width, height, geometry): # pylint: disable=no-self-use,unused-argument """Get thumbnail size based on given dimensions""" return width, height
class IFileInfo(Interface): """File extended information""" title = TextLine(title=_("Title"), required=False) description = Text(title=_("Description"), required=False) filename = TextLine(title=_("Save file as..."), description=_("Name under which the file will be saved"), required=False) language = Choice(title=_("Language"), description=_("File's content language"), vocabulary=BASE_LANGUAGES_VOCABULARY_NAME, required=False)
class XlImageThumbnailer(ResponsiveImageThumbnailer): """EXtra-Large responsive image thumbnailer""" label = _("Extra-large screen thumbnail") weight = 14
class LgImageThumbnailer(ResponsiveImageThumbnailer): """LarGe responsive image thumbnailer""" label = _("Large screen thumbnail") weight = 13
class MdImageThumbnailer(ResponsiveImageThumbnailer): """MeDium responsive image thumbnailer""" label = _("Medium screen thumbnail") weight = 12
class SmImageThumbnailer(ResponsiveImageThumbnailer): """SMall responsive image thumbnailer""" label = _("Tablet thumbnail") weight = 11
class XsImageThumbnailer(ResponsiveImageThumbnailer): """eXtra-Small responsive image thumbnailer""" label = _("Smartphone thumbnail") weight = 10
class ResponsiveImageThumbnailer(ImageSelectionThumbnailer): """Responsive image thumbnailer""" section = _("Responsive selections")