前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 打造自己的图床升级篇 - PIL 为图片添加水印

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

作者头像
FungLeo
发布2019-05-27 08:55:00
7150
发布2019-05-27 08:55:00
举报

分析情况

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

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

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

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

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

最终代码

代码语言:javascript
复制
#!/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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年07月02日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分析情况
  • 最终代码
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档