python - 如何在 Python 中改进水印图像?

标签 python python-imaging-library watermark

我正在使用 python 制作来自 this 的水印图像源代码

import Image
import ImageEnhance
import random


def _percent(var):
    """
    Just a simple interface to the _val function with a more meaningful name.
    """
    return _val(var, True)


def _int(var):
    """
    Just a simple interface to the _val function with a more meaningful name.
    """
    return _val(var)


def _val(var, is_percent=False):
    """
    Tries to determine the appropriate value of a particular variable that is
    passed in.  If the value is supposed to be a percentage, a whole integer
    will be sought after and then turned into a floating point number between
    0 and 1.  If the value is supposed to be an integer, the variable is cast
    into an integer.
    """
    try:
        if is_percent:
            var = float(int(var.strip('%')) / 100.0)
        else:
            var = int(var)
    except ValueError:
        raise ValueError('invalid watermark parameter: ' + var)
    return var


def reduce_opacity(img, opacity):
    """
    Returns an image with reduced opacity.
    """
    assert opacity >= 0 and opacity <= 1

    if img.mode != 'RGBA':
        img = img.convert('RGBA')
    else:
        img = img.copy()

    alpha = img.split()[3]
    alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
    img.putalpha(alpha)

    return img


def determine_scale(scale, img, mark):
    """
    Scales an image using a specified ratio or 'F'.  If `scale` is 'F', the
    image is scaled to be as big as possible to fit in `img` without falling off
    the edges.  Returns the scaled `mark`.
    """

    if scale:
        try:
            scale = float(scale)
        except (ValueError, TypeError):
            pass
        if type(scale) in (str, unicode) and scale.lower() == 'f':
            # scale, but preserve the aspect ratio
            scale = min(
                float(img.size[0]) / mark.size[0],
                float(img.size[1]) / mark.size[1]
            )
        elif type(scale) not in (float, int):
            raise ValueError(
                'Invalid scale value "%s"!  Valid values are 1) "F" for ratio-preserving scaling and 2) floating-point numbers and integers greater than 0.' % (
                    scale,))

        # determine the new width and height
        w = int(mark.size[0] * float(scale)) / 2
        h = int(mark.size[1] * float(scale)) / 2
        print w, h
        # apply the new width and height, and return the new `mark`
        return (w, h)
    else:
        print 'Mark Size', mark.size
        return mark.size


def determine_rotation(rotation, mark):
    """
    Determines the number of degrees to rotate the watermark image.
    """

    if (isinstance(rotation, str) or isinstance(rotation, unicode)) \
        and rotation.lower() == 'r':
        rotation = random.randint(0, 359)
    else:
        rotation = _int(rotation)

    return rotation


def determine_position(position, img, mark):
    """
    Options:
        TL: top-left
        TR: top-right
        BR: bottom-right
        BL: bottom-left
        C: centered
        R: random
        X%xY%: relative positioning on both the X and Y axes
        X%xY: relative positioning on the X axis and absolute positioning on the
              Y axis
        XxY%: absolute positioning on the X axis and relative positioning on the
              Y axis
        XxY: absolute positioning on both the X and Y axes
    """

    max_left = max(img.size[0] - mark.size[0], 0)
    max_top = max(img.size[1] - mark.size[1], 0)

    if not position:
        position = 'r'

    if isinstance(position, tuple):
        left, top = position
    elif isinstance(position, str) or isinstance(position, unicode):
        position = position.lower()

        # corner positioning
        if position in ['tl', 'tr', 'br', 'bl']:
            if 't' in position:
                top = 0
            elif 'b' in position:
                top = max_top
            if 'l' in position:
                left = 0
            elif 'r' in position:
                left = max_left

        # center positioning
        elif position == 'c':
            left = int(max_left / 2)
            top = int(max_top / 2)

        # random positioning
        elif position == 'r':
            left = random.randint(0, max_left)
            top = random.randint(0, max_top)

        # relative or absolute positioning
        elif 'x' in position:
            left, top = position.split('x')

            if '%' in left:
                left = max_left * _percent(left)
            else:
                left = _int(left)

            if '%' in top:
                top = max_top * _percent(top)
            else:
                top = _int(top)
    print 'top left', left, top
    return (left, top)


def watermark(img, mark, position=(0, 0), opacity=1, scale=1.0, tile=False,
              greyscale=False, rotation=0, return_name=False, **kwargs):
    """
    Adds a watermark to an image.
    """
    if opacity < 1:
        mark = reduce_opacity(mark, opacity)

    if type(scale) != tuple:
        scale = determine_scale(scale, img, mark)
    print 'mark mode', mark.mode
    mark = mark.resize(scale)

    if greyscale and mark.mode != 'LA':
        mark = mark.convert('LA')

    rotation = determine_rotation(rotation, mark)
    if rotation != 0:
        # give some leeway for rotation overlapping
        new_w = mark.size[0]
        new_h = mark.size[1]
        new_mark = Image.new('RGBA', (new_w, new_h), (0, 0, 0, 0))
        # new_mark.putalpha()
        # center the watermark in the newly resized image
        new_l = (new_w - mark.size[0]) / 2
        new_t = (new_h - mark.size[1]) / 2
        new_mark.paste(mark, (new_l, new_t))

        mark = new_mark.rotate(rotation, Image.BICUBIC, expand=True)

    position = determine_position(position, img, mark)
    print 'image mode', img.mode
    print 'mark mode', mark.mode
    if img.mode != 'RGBA':
        img = img.convert('RGBA')
    print 'image ---', img.mode
    alpha = img.split()[3]
    alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
    img.putalpha(alpha)
    # make sure we have a tuple for a position now
    assert isinstance(position, tuple), 'Invalid position "%s"!' % position

    # create a transparent layer the size of the image and draw the
    # watermark in that layer.
    layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
    if tile:
        first_y = position[1] % mark.size[1] - mark.size[1]
        first_x = position[0] % mark.size[0] - mark.size[0]

        for y in range(first_y, img.size[1], mark.size[1]):
            for x in range(first_x, img.size[0], mark.size[0]):
                layer.paste(mark, (x, y))
    else:
        layer.paste(mark, position)

    # composite the watermark with the layer
    return Image.composite(layer, img, layer)


def test():
    im = Image.open('/home/chanhle/0450034_a (4th copy).jpg')
    mark = Image.open('/home/chanhle/UMA LOGO.png')
    # im.save('/home/chanhle/0120047_a.png')
    watermark(im, mark,
              position='C',
              opacity=0.8,
              scale='f',
              rotation=45).save('/home/chanhle/test3.jpg', 'JPEG')


if __name__ == '__main__':
    test()

这是我要加水印的图片 Orignal Image 这是标志 Logo Image

运行上面代码时的结果 Result Image

当我使用在线工具时,结果很漂亮。 enter image description here 正如您在结果中看到的那样, Logo 水印不够清晰,没有我预期的那么漂亮。 如何提高这种品质? 感谢支持。

最佳答案

改变:

mark = mark.resize(scale)

到:

mark = mark.resize(scale, Image.ANTIALIAS)

将不透明度更改为 0.5。并尝试另存为 PNG 图像或将 quality=100 添加到保存参数(如果使用 JPEG)。

关于python - 如何在 Python 中改进水印图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20837646/

相关文章:

python - 如何通过方法使用 numba.jit

python - PIL 透明度似乎不起作用

python - Python 中的 PIL 提示 PixelAccess 没有 'size' 属性,我做错了什么?

python - PIL : pasting an image onto another image, 计算位置

metadata - 如何识别 PDF 水印并使用 PDFBox 将其删除

java - 保护从 iTextPdf 生成的 PDF

python - 如何配置python环境

python - 为什么 `if None.__eq__("a")` 似乎评估为 True(但不完全)?

python - 如何生成超出最大 token 限制的 gpt-3 补全

python - 将视频与具有额外属性的 ffmpeg(或替代品)合并(叠加)