Django中使用BytesIO获取图片大小与实际值不符该如何解决
问题根因
你的代码存在两处核心错误,导致获取的大小和实际值不符:
- 语法错误:
image_file_size = img.tell()这行调用对象错误。img是PIL的Image实例,它的tell()方法返回值不是文件大小,你应该调用存储了编码后图片的img_file(BytesIO实例)的tell()方法。 - 逻辑错误:你把用户上传的原始图片重新用JPEG格式压缩编码了一遍,计算出来的是重编码后的文件大小,和用户上传的原始文件大小自然不一致。
解决方案
根据你的实际需求二选一即可:
方案1:校验用户上传的原始图片大小(绝大多数场景用这个就行)
不需要调用PIL做编码处理,Django的上传文件对象自带size属性,直接读取即可,修改对应循环逻辑:
for x in images: # 直接读取原始文件大小,单位为字节 image_file_size = x.size if image_file_size > 150 * 1024: failure = "图片大小不能超过150KB" return render(request, 'Main/document_upload.html', {'failure':failure}) # 原有保存逻辑不变 fs = FileSystemStorage() filename = fs.save(x.name, x) Doc1 = Doc(user_id = unq_id, upload = x, name = name) Doc1.save() success = "You have successfully added documents, proceed to 'My documents' to see your documents"
方案2:校验重编码为JPEG后的图片大小(如果你后续存储的是重编码后的图片)
修正语法错误,同时注意BytesIO的指针问题:
for x in images: img = Image.open(x) img_file = BytesIO() img.save(img_file, 'jpeg') # 修正为调用BytesIO实例的tell方法获取大小 image_file_size = img_file.tell() if image_file_size > 150 * 1024: failure = "图片大小不能超过150KB" return render(request, 'Main/document_upload.html', {'failure':failure}) # 注意要把BytesIO的指针移到开头才能正常读取内容保存 img_file.seek(0) # 后续保存逻辑对应修改为存储img_file即可
额外注意
你的原代码还存在变量未定义的隐患:如果请求是GET方法,success变量没有提前赋值,渲染模板时会报错,建议在函数开头初始化success = ''。
内容的提问来源于stack exchange,提问作者tyzion
相关产品推荐
相关产品推荐

