#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
__docformat__ = 'restructuredtext'
# import standard library
import os.path
from io import StringIO, BytesIO
# import interfaces
from pyams_file.interfaces import IWatermarker, IImage
# import packages
from PIL import Image, ImageEnhance
from pyams_utils.registry import utility_config
[docs]@utility_config(provides=IWatermarker)
class ImageWatermarker(object):
"""Image watermarker utility"""
def _reduce_opacity(self, image, opacity):
"""Returns an image with reduced opacity."""
assert 0 <= opacity <= 1
if image.mode != 'RGBA':
image = image.convert('RGBA')
else:
image = image.copy()
alpha = image.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
image.putalpha(alpha)
return image
[docs] def add_watermark(self, image, watermark, position='scale', opacity=1, format=None):
"""Adds a watermark to an image and return a new image"""
# init image
if IImage.providedBy(image):
image = image.data
if isinstance(image, bytes):
image = BytesIO(image)
elif isinstance(image, str) and not os.path.exists(image):
image = StringIO(image)
image = Image.open(image)
# check format
if not format:
format = image.format
format = format.upper()
if format not in ('GIF', 'JPEG', 'PNG'):
format = 'JPEG'
# check RGBA mode
if image.mode != 'RGBA':
image = image.convert('RGBA')
# init watermark
if isinstance(watermark, str) and os.path.exists(watermark):
watermark = Image.open(watermark)
else:
if IImage.providedBy(watermark):
watermark = Image.open(StringIO(watermark.data))
else:
watermark = Image.open(watermark)
if opacity < 1:
watermark = self._reduce_opacity(watermark, opacity)
# create a transparent layer the size of the image and draw the
# watermark in that layer.
layer = Image.new('RGBA', image.size, (0, 0, 0, 0))
if position == 'tile':
for y in range(0, image.size[1], watermark.size[1]):
for x in range(0, image.size[0], watermark.size[0]):
layer.paste(watermark, (x, y))
elif position == 'scale':
# scale, but preserve the aspect ratio
ratio = min(float(image.size[0]) / watermark.size[0], float(image.size[1]) / watermark.size[1])
w = int(watermark.size[0] * ratio)
h = int(watermark.size[1] * ratio)
watermark = watermark.resize((w, h))
layer.paste(watermark, (int((image.size[0] - w) / 2), int((image.size[1] - h) / 2)))
else:
layer.paste(watermark, position)
# composite the watermark with the layer
new = BytesIO()
composite = Image.composite(layer, image, layer)
if format == 'JPEG':
composite = composite.convert('RGB')
composite.save(new, format)
return new.getvalue(), format.lower()