最近忙得連軸轉,很久沒更新部落格了,程式碼倒是沒啥寫,積累了好些東西,接下來一有時間就來更新吧~
本文記錄使用Python實現給圖片新增水印的功能實現過程
把公眾號的封面作為素材
原圖是這樣的
加個水印的效果
主要實現是參考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')
以我封裝的 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/
就可以看到加了水印的圖片了
效果如下
搞定~
本專案參考的那個專案
GitHub gist:https://gist.github.com/Deali-Axy/e22ea79bfbe785f9017b2e3cd7fdb3eb
PS:Github gist是個程式碼片段工具,最近剛剛用起來,感覺還蠻不錯的
有時候用來記錄和分享一些程式碼片段很方便,不需要專門建立一個倉庫