需求背景:Python3.6.7+django+PIL+Mongodb django开放一个图片下载接口,因为图片大小为10+M,所以要后端压缩后再返回给前端。
解决问题思路:图片存在mongodb中,以二进制的形式存储,django获取到二进制,PiL读取,压缩,返回压缩后的二进制,转为base64,json形式返回给前端
话不多说,上代码,先普及一下python中二进制内存中存储方法
# 如果要操作二进制数据,就需要使用BytesIO。
# BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes
from io import BytesIO
fb = BytesIO()
fb.write("中国".encode("utf-8"))
fb.write("美丽".encode("utf-8"))
print(fb.getvalue().decode("utf-8"))
# 中国美丽
fb.close()
# 像读文件一样读取
fb1 = BytesIO("中国".encode("utf-8"))
print(fb1.read())
# b'\xe4\xb8\xad\xe5\x9b\xbd'
fb1.close()
重点来了,图片缩放
class PostDownloadImage(APIView):
authentication_classes = [Authentication, ] # 启动token验证
def post(self, request):
fileName = request.data.get('fileName')
print("准备下载", fileName)
try:
client = MongoClient('mongodb://{0}:{1}@{2}:{3}'.format(
Mongodb_account, Mongodb_pass, MongodbIP, MongodbPort))
db = client[DataBase_image]
gridfs_col = GridFS(db, collection='image')
file_data_bytes = gridfs_col.get_version(filename=fileName).read()
# file_data_str = base64.b64encode(file_data_bytes).decode('ascii') # 二进制流解码成字符串
# with open(out_name, 'wb') as file_w:
# file_w.write(file_data)
read_byte_io = BytesIO(file_data_bytes) # 新建IO通道
image = Image.open(read_byte_io)
width = image.width
height = image.height
rate = 1.0 # 压缩率
# 根据图像大小设置压缩率
if width >= 2000 or height >= 2000:
rate = 0.3
elif width >= 1000 or height >= 1000:
rate = 0.5
elif width >= 500 or height >= 500:
rate = 0.9
width = int(width * rate) # 新的宽
height = int(height * rate) # 新的高
image.thumbnail((width, height), Image.ANTIALIAS) # 生成缩略图
# image对象转为二进制
imgByteArr = BytesIO()
image.save(imgByteArr,format="PNG")
result_bytes = imgByteArr.getvalue()
imgByteArr.close() # 关闭byteio
read_byte_io.close() # 关闭IO通道
file_data_str = base64.b64encode(result_bytes).decode('ascii') # 二进制流解码成字符串
ret = {'code': 1000, 'msg': None, "rate": rate, "result": file_data_str}
print("下载成功", fileName)
except Exception as e:
print(e)
ret = {'code': 1001, 'msg': '图片下载失败', 'result': None}
print("下载失败", fileName)
return JsonResponse(ret)