4

Python实现给图片加水印功能 - 程序设计实验室

 1 year ago
source link: https://www.cnblogs.com/deali/p/16742548.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Python实现给图片加水印功能 - 程序设计实验室 - 博客园

最近忙得连轴转,很久没更新博客了,代码倒是没啥写,积累了好些东西,接下来一有时间就来更新吧~

本文记录使用Python实现给图片添加水印的功能实现过程

把公众号的封面作为素材

原图是这样的

866942-20220929180609829-841943239.png

加个水印的效果

866942-20220929180622228-305715711.png

主要实现是参考GitHub上一个项目的:https://github.com/2Dou/watermarker

用到了Pillow库,使用前请先安装,一般要在Django中保存图片也需要安装这个库的。所以这个依赖可以说是比较友好的。

这个项目是命令行工具,而我是在Django项目中用,所以我做了魔改

核心代码如下(这段代码是在我封装的一个类里面)

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

我把这个加水印的功能封装成了一个类

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):
        ...
w = Watermarker('codelab.png', '程序设计实验室', size=200)
# 显示加了水印的图片
w.show()
# 保存
w.save('save.png')

在Django中使用

以我封装的 DjangoStarter 框架为例,直接把Image对象写入Http响应里

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')
from django.urls import path
from . import views

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

这样配置之后,访问链接:http://[host]:[port]/photo/1/add_watermark/

就可以看到加了水印的图片了

866942-20220929180637323-678973210.png

命令行使用

本项目参考的那个项目

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

PS:Github gist是个代码片段工具,最近刚刚用起来,感觉还蛮不错的

有时候用来记录和分享一些代码片段很方便,不需要专门创建一个仓库

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK