专栏首页地方网络工作室的专栏Python 打造自己的图床升级篇 - PIL 为图片添加水印

Python 打造自己的图床升级篇 - PIL 为图片添加水印

分析情况

如上图中所示,我们直接将读取到的二进制文件,直接存储到了硬盘中。而我们要给图片添加水印,则就是在这里进行处理。

首先,我们需要判断图片是否为 jpg 图片,非 jpg 图片我不准备做添加水印的处理,否则,可能会写坏掉一些 gif 的动图。png 图片在我的博文中使用得也比较少,所以不做处理了。

然后就是,一些过分小的图片,就不要添加水印了,否则有碍图片的观瞻。

另外,还有一个问题是, PILImage.open() 函数,接收的是一个图片的地址,而我这边是已经拿到了图片的二进制,并且存在了内存中。我一开始想,莫非需要我先保存到硬盘,然后读取到 PIL 中,进行水印处理,然后再一次写入硬盘。

但是,我个人认为这个逻辑虽然说不是不可以,但是在我看来比较蠢。我希望在内存中直接解决,然后一次性存储到硬盘,因此,我找到了 BytesIO 这个可爱的方法。

最终代码

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from sanic import Sanic
from sanic.response import json, text, file
import os, sys
import hashlib
from PIL import Image
from io import BytesIO

app = Sanic()
baseDir = '/Users/fungleo/Documents/Blog/articles/image/'

# 成功以及失败的返回脚本
def ok(data):
    return json({"data": data, "status": 0})

def fail(data):
    return json({"data": data, "status": 1})

# 字节码转16进制字符串
def bytes2hex(bytes):
    hexstr = u""
    for i in range(10):
        t = u"%x" % bytes[i]
        if len(t) % 2:
            hexstr += u"0"
        hexstr += t
    return hexstr.lower()

# 根据16进制字符串获取文件后缀
def getSuffix(hexStr):
    print(hexStr)
    SUPPORT_TYPE = {
            'ffd8ffe':'jpg',
            '89504e470d0a1a0a0000':'png',
            '474946383961':'gif',
        }
    for i in SUPPORT_TYPE:
        if i in hexStr:
            return SUPPORT_TYPE[i]
    return 'error type'

def saveImage(savePath, image):
    tempFile = open(savePath, 'wb')
    tempFile.write(image)
    tempFile.close()

# 上传文件接口
@app.route('/upimg', methods=['POST'])
async def upimg(request):

    # 判断参数是否正确
    if not request.files and not request.files.get('file'):
        return fail('error args')
    image = request.files.get('file').body

    # 判断文件是否支持
    imageSuffix = getSuffix(bytes2hex(image))
    if 'error' in imageSuffix:
        return fail(imageSuffix)

    # 组织图片存储路径
    m1 = hashlib.md5()
    m1.update(image)
    md5Name = m1.hexdigest()

    saveDir = baseDir + md5Name[0:2] + '/'
    savePath = saveDir + md5Name[2:] + '.' + imageSuffix
    resPath = '/' + md5Name[0:2] + '/' + md5Name[2:] + '.' + imageSuffix

    # 如果文件夹不存在,就创建文件夹
    if not os.path.exists(saveDir):
        os.makedirs(saveDir)

    # 如果是 jpg 图片,则添加水印
    if imageSuffix == 'jpg':
        bImg = BytesIO(image)
        img = Image.open(bImg)
        imgW = img.size[0]
        imgH = img.size[1]

        if imgW >= 300 and imgH >= 100:
            mark = Image.open("mark.png")
            layer = Image.new('RGBA', img.size, (0,0,0,0))
            layer.paste(mark, (imgW - 180, imgH - 60))
            out = Image.composite(layer, img, layer)
            out.save(savePath, 'JPEG', quality = 100)
        else:
            saveImage(savePath, image)

    # 否则直接将文件写入到硬盘
    else:
        saveImage(savePath, image)

    # 给客户端返回结果
    return ok({"path": resPath})

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=7000)

因为需要经过两次判断,else 时都是直接写入硬盘,因此,将原来的写入硬盘的方法直接封装为一个函数。

如上,当图片尺寸小于 300*100 的时候,就不添加水印了。

关键是,直接保存图片的话,图片的存储质量并不是很好,因此,我加上了指定质量为 100

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python3 初学实践案例(14)打造一个私人图床服务器

    版权声明:本文为 FengCms FungLeo 原创文章,允许转载,但转载必须注明出处并附带首发链接 ...

    FungLeo
  • Python3 初学实践案例(2)将源目录中的图片用MD5命名并可以设定目标目录

    Python3 初学实践案例(2)将源目录中的图片用MD5重命名后移动或复制到目标文件夹 尝试了一下用 python 实现了一个生成密码的程序。感觉还是比较好上...

    FungLeo
  • vue3.0 Composition API 上手初体验 普通组件的开发与使用

    通过前面的章节的讲解,我相信大家对于 vue 3.0 的新特性的基本使用,已经没有问题了。但是新的问题来了,组件是怎么玩的呢?

    FungLeo
  • 移动搜索SEO分享:利用Meta声明来做百度开放适配

     前天,张戈博客终于搞定了网站静态缓存下的移动端站点切换,从而也多了一个移动二级域名。于是又开始纠结这个 2 二级域名是否需要屏蔽搜索引擎的收录,毕竟内容一摸一...

    张戈
  • JAVA 并发真讨厌

    互联网行业随着商业化,信息化,快速发展至今,借助人口大国和时代催生,早已到了秀才不出门便知天下事的年代,80后吃饭就着菜,90后吃饭就着肉,00...

    疯狂的KK
  • iptables回流方法

    用户2135432
  • .NET常用的扩展方法整理

    跟着阿笨一起玩NET
  • 去哪儿网春招开发面试经历

    牛客网
  • 怒薅羊毛:白嫖GitHub作为个人博客免费图床

    很多小伙伴私信反馈说,个人博客搭建完以后,写文章时,图片上传和存放成了一个问题。我看很多人都把图片放在仓库一起,然后试图通过相对路径的方式来引用图片,结果很多人...

    AI算法与图像处理
  • 什么样的系统算是坑

    最近很“荣幸”工作上被安排成为一个项目的主要负责人,美其名曰:项目经理。前任项目经理直到要离职的时候也基本上没有交接什么,实际上也没有什么可以交接的。临了丢给我...

    SAP梦心

扫码关注云+社区

领取腾讯云代金券