工作中应用图片时会觉得图片能压缩又不失去显示效果,岂不美哉,果断用 tinify 来压缩图片,一来可以减小图片占用空间大小,二来放到服务器后还能节省存储空间,用于显示时也能提高图片的访问速度。
之前已经在 django 博客项目中使用 django-qiniu-storage 做过 从 ckeditor 把图片上传到七牛云。
目前又闪出一个想法,在 django 中实现:图片先压缩再上传到七牛云。压缩图片使用 tinify(使用了 tinify 之后多了一套文件上传和下载过程,可能会造成上传一张图片的速度比之前慢上许多,也可能因网络问题造成失败)
前端上传的图片到 Django 时,把图片传给 tinify, tinify 返回图片,再把 返回的图片传给 七牛云,得到图片链接。
# ckeditor_storage.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: yinzhuoqun
@site: http://zhuoqun.info/
@email: yin@zhuoqun.info
@time: 2019/7/9 16:57
"""
import datetime
import uuid
import tinify
from django.core.files.storage import Storage
from qiniu import Auth, put_data
from joyoo.settings import QINIU_ACCESS_KEY, QINIU_SECRET_KEY, QINIU_BUCKET_DOMAIN_FILE, QINIU_BUCKET_NAME_FILE, \
TINIFY_ON, TINIFY_KEY, TINIFY_KEY_USE_MAX
from logger.logger import logger
class StorageObject(Storage):
def __init__(self):
self.now = datetime.datetime.now()
self.file = None
def _new_name(self, name):
new_name = "file/{0}/{1}.{2}".format(self.now.strftime("%Y/%m/%d"), str(uuid.uuid4()).replace('-', ''),
name.split(".").pop())
return new_name
def _open(self, name, mode):
return self.file
def _to_tinify(self, content):
if self.file.name.lower().endswith(("jpg", "png")) and TINIFY_ON:
tinify.key = TINIFY_KEY
try:
tinify.validate()
except Exception as e:
# Validation of API key failed.
pass
compressions_this_month = tinify.compression_count
logger.info("提示:tinify 本月压缩次数已使用 %s/500" % compressions_this_month)
if compressions_this_month < TINIFY_KEY_USE_MAX:
try:
file_data = tinify.from_file(content.file).to_buffer()
except Exception as e:
logger.error(e)
file_data = content.file.read()
else:
file_data = content.file.read()
else:
file_data = content.file.read()
return file_data
def _save(self, name, content):
"""
上传文件到七牛
"""
# 构建鉴权对象
q = Auth(QINIU_ACCESS_KEY, QINIU_SECRET_KEY)
token = q.upload_token(QINIU_BUCKET_NAME_FILE)
self.file = content
# file_data = content.file.read()
file_data = self._to_tinify(content)
ret, info = put_data(token, self._new_name(name), file_data)
if info.status_code == 200:
base_url = 'http://%s/%s' % (QINIU_BUCKET_DOMAIN_FILE, ret.get("key"))
# 表示上传成功, 返回文件名
return base_url
else:
# 上传失败
raise Exception("上传七牛失败")
def exists(self, name):
# 验证文件是否存在,因为我这边会去生成一个新的名字去存储到七牛,所以没有必要验证
return False
def url(self, name):
# 上传完之后,已经返回的是全路径了
return name
# settings.py
# tinify.key 图片压缩配置
TINIFY_ON = True # 压缩开关
TINIFY_KEY = "xxxxxxxZC" # 免费版每月 500 张图片
TINIFY_KEY_USE_MAX = 500 # 免费版每月 500 张图片
# 上传过程
[24/Sep/2019 22:35:26] "GET /static/images/favicon.ico HTTP/1.1" 200 1150
11 <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
22 <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
提示:tinify 压缩次数本月已使用 2/500
[24/Sep/2019 22:35:50] "POST /ckeditor/upload/?CKEditor=id_content&CKEditorFuncNum=1&langCode=zh-cn HTTP/1.1" 200 207
# 压缩前后比较
直接改 tinify, django 收到前端传来的图片,把图片传给 tinify, tinify 直接把压缩好的图片传给七牛云,压缩的图片不用回传,tinify 返回图片地址。这种方法,目前还没搞定怎么弄,只是个想法。