返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Python

Implementing Image Watermarking with Python

Preface I've been so busy lately that I haven't updated the blog in a long time. I haven't written much code, but I've accumulated quite a few things. I'll start updating whenever I have some time~ This article records the process of implementing image watermarking with Python Let's see the results first Using the WeChat official account cover as material The original image looks like this codelab The effect after adding a watermark temp Implementation code The main implementation is based on a GitHub project: https://github.com/2Dou/watermarker It uses the Pillow library. Please

曦远 (DealiAxy)约 13 分钟
目录8 个章节

Preface

I've been so busy lately that I haven't updated the blog in a long time. I haven't written much code, but I've accumulated quite a few things. I'll start updating whenever I have some time~

This article records the process of implementing image watermarking with Python

Let's See the Results First

Using the WeChat official account cover as material

The original image looks like this

codelab

The effect after adding a watermark

temp

Implementation Code

The main implementation is based on a GitHub project: https://github.com/2Dou/watermarker

It uses the Pillow library. Please install it before use. Generally, you also need this library to save images in Django, so this dependency can be considered fairly friendly.

This project is a command-line tool, but I use it in a Django project, so I customized it

The core code is as follows (this code is inside a class I encapsulated)

origin_image = Image.open(self.image_path)
origin_image = ImageOps.exif_transpose(origin_image)

# 计算字体的宽度、高度
width = len(self.text) * self.size
height = round(self.size * self.font_height_crop)

# 创建水印图片
watermark_image = Image.new(mode='RGBA', size=(width, height))

# 生成文字
draw_table = ImageDraw.Draw(im=watermark_image)
draw_table.text(
    xy=(0, 0),
    text=self.text,
    fill=self.color,
    font=ImageFont.truetype(self.font_file, size=self.size)
)
del draw_table

# 裁剪空白
watermark_image = Watermarker.crop_image_edge(watermark_image)

# 设置透明度
Watermarker.set_image_opacity(watermark_image, self.opacity)

# 计算斜边长度
c = int(math.sqrt(origin_image.size[0] * origin_image.size[0] + origin_image.size[1] * origin_image.size[1]))

# 以斜边长度为宽高创建大图(旋转后大图才足以覆盖原图)用于覆盖在原图之上
watermark_mask = Image.new(mode='RGBA', size=(c, c))

# 在大图上生成水印文字
y, idx = 0, 0
while y < c:
    # 制造x坐标错位
    x = -int((watermark_image.size[0] + self.space) * 0.5 * idx)
    idx = (idx + 1) % 2

    while x < c:
        # 在该位置粘贴mark水印图片
        watermark_mask.paste(watermark_image, (x, y))
        x = x + watermark_image.size[0] + self.space
    y = y + watermark_image.size[1] + self.space

# 将大图旋转一定角度
watermark_mask = watermark_mask.rotate(self.angle)

# 在原图上添加大图水印
if origin_image.mode != 'RGBA':
    origin_image = origin_image.convert('RGBA')
origin_image.paste(
    watermark_mask,  # 大图
    (int((origin_image.size[0] - c) / 2), int((origin_image.size[1] - c) / 2)),  # 坐标
    mask=watermark_mask.split()[3]
)
del watermark_mask

I encapsulated this watermarking functionality into a class

class Watermarker(object):
    """图片水印工具"""
        django_support = False

    def __init__(
            self, image_path: str, text: str,
            angle=30,
            color='#8B8B1B',
            font_file='青鸟华光简琥珀.ttf',
            font_height_crop=1.2,
            opacity=0.15,
            quality=80,
            size=50,
            space=75,
    ):
        ...
    @staticmethod
    def set_image_opacity(image: Image, opacity: float):
        ...
    @staticmethod
    def crop_image_edge(image: Image):
        ...
    @property
    def image(self):
        ...
    def save(self, file_path: str, image_format: str = 'png'):
        ...
    def show(self):
        ...

Usage

Simple Usage

w = Watermarker('codelab.png', '程序设计实验室', size=200)
# 显示加了水印的图片
w.show()
# 保存
w.save('save.png')

Using in Django

Taking my encapsulated DjangoStarter framework as an example, write the Image object directly into the HTTP response

from io import BytesIO
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse
from django_starter.contrib.watermark import Watermarker

def add_watermark(request, pk):
    text = request.GET.get('text', timezone.now().strftime('%Y-%m-%d %H:%M:%S'))
    photo = get_object_or_404(Photo, pk=pk)
    image = Watermarker(photo.photo.path, text).image

    # 将图片保存到内存中
    with BytesIO() as f:
        image.save(f, 'png')
        # 返回图片数据流
        return HttpResponse(f.getvalue(), content_type='image/png')

URL configuration

from django.urls import path
from . import views

app_name = 'photo'
urlpatterns = [
    path('photo/<int:pk>/add_watermark/', views.add_watermark, name='add_watermark'),
]

After this configuration, visit the URL: http://[host]:[port]/photo/1/add_watermark/

and you can see the watermarked image

The effect is as follows

image-20220929172532412

Done~

Command-Line Usage

The project this one is based on

Complete Code

GitHub gist address: https://gist.github.com/Deali-Axy/e22ea79bfbe785f9017b2e3cd7fdb3eb

PS: GitHub gist is a code snippet tool. I just started using it recently, and it feels pretty nice

Sometimes it's convenient for recording and sharing code snippets, without needing to create a dedicated repository

_EOF_

Implementing Image Watermarking with Python

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

自己动手开发简单消息队列(异步任务队列):Python实现

又是造轮子系列咯,Python上有很多成熟完善的异步任务队列框架可以用,比如Celery,或者RQ,不过这些都不自带消息队列服务,都需要使用Redis、RabbitMQ之类的消息队列才行,我用到小项目中又不需要附带这么多东西,于是自己动手来实现咯。 思路 将需要异步执行的任务添加到队列 自动从队列中取出任务,创建新线程执行 保存任务的执行结果和输出 任务完成,调用回调函数,处理返回的数据 使用输出

2021-12-18 · Python · 约 1 分钟

Python实现从Excel生成Model和导入脚本

前言 最近遇到一个需求,有几十个Excel,每个的字段都不一样,然后都差不多是第一行是表头,后面几千上万的数据,需要把这些Excel中的数据全都加入某个已经上线的Django项目 这就需要每个Excel建个表,然后一个个导入了 这样的效率太低,不能忍 所以我造了个自动生成 Model 和导入脚本的轮子 思路 首先拿出 pandas,它的 DataFrame 用来处理数据很方便 pandas 加载

2022-11-22 · Python · 约 1 分钟

关于Python的异常处理

前言 异常处理在任何一门编程语言里都是值得关注的一个话题,良好的异常处理可以让你的程序更加健壮,清晰的错误信息更能帮助你快速修复问题。在Python中,和部分高级语言一样,使用了try/except/finally语句块来处理异常,如果你有其他编程语言的经验,实践起来并不难。 Python 中(至少)有两种错误:语法错误和异常( syntax errors 和 exceptions )。下面稍微介

2022-05-27 · Python · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…