我有一个网站,每天都有多个大尺寸图像在上线后上传,因为大尺寸需要时间,所以我想在上传图像时生成缩略图版本:
class Image(models.Model):
license_type = (
('Royalty-Free','Royalty-Free'),
('Rights-Managed','Rights-Managed')
)
image_number = models.CharField(default=random_image_number,max_length=12,unique=True)
title = models.CharField(default=random_image_number,max_length = 100)
image = models.ImageField(upload_to = 'image' , default = 'demo/demo.png')
thumbnail = models.ImageField(upload_to='thumbs', editable=False)
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.CASCADE)
shoot = models.ForeignKey(ImageShoot, on_delete=models.CASCADE, related_name='Image', null=True,blank=True)
image_keyword = models.TextField(max_length=1000)
credit = models.CharField(max_length=150, null=True)
location = models.CharField(max_length=100, null=True)
license_type = models.CharField(max_length=20,choices=license_type, default='')
uploaded_at = models.TimeField(auto_now_add=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super(Image, self).save(*args, **kwargs)
if not self.make_thumbnail():
raise Exception('Could not create thumbnail - is the file type valid?')
def make_thumbnail(self):
fh = storage.open(self.Image.name)
try:
image = PILImage.open(fh)
except:
return False
image.thumbnail((400,400),PILImage.ANTIALIAS)
fh.close()
thumb_name, thumb_extension = os.path.splitext(self.Image.name)
thumb_extension = thumb_extension.lower()
thumb_filename = thumb_name + '_thumb' + thumb_extension
if thumb_extension in ['.jpg', '.jpeg']:
FTYPE = 'JPEG'
elif thumb_extension == '.gif':
FTYPE = 'GIF'
elif thumb_extension == '.png':
FTYPE = 'PNG'
else:
return False # Unrecognized file type
# Save thumbnail to in-memory file as StringIO
temp_thumb = StringIO()
image.save(temp_thumb, FTYPE)
temp_thumb.seek(0)
# Load a ContentFile into the thumbnail field so it gets saved
self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
temp_thumb.close()
return True
admin.py:
@admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
readonly_fields=['image_number','uploaded_at']
fields = ['title','image_number','shoot','category',
'image','image_keyword','credit','license_type','location','uploaded_at']
现在这是错误:
string argument expected, got 'bytes'
回溯:
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/JpegImagePlugin.py", line 779, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/ImageFile.py", line 513, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'
当我使用BytesIO时:
我得到这个错误:
maximum recursion depth exceeded in comparison
回溯:
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/TiffImagePlugin.py", line 319, in __init__
if isinstance(value, Fraction):
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/abc.py", line 139, in __instancecheck__
return _abc_instancecheck(cls, instance)
RecursionError:相比之下超过了最大递归深度
我目前正在从管理员上传图像,但也要使用drf。目前它没有创建缩略图………………………………………………………………………………………………………………………
正如评论中所说,您可以改用base64编码图像。为此,首先将缩略图字段更改为以下内容:
thumbnail = models.CharField(max_length=2000, blank=True, null=True)
然后,覆盖模型保存方法并添加以下代码:
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if not self.image:
self.thumbnail = None
else:
thumbnail_size = 50, 50
data_img = BytesIO()
tiny_img = Image.open(self.image)
tiny_img.thumbnail(thumbnail_size)
tiny_img.save(data_img, format="BMP")
tiny_img.close()
try:
self.thumbnail = "data:image/jpg;base64,{}".format(
base64.b64encode(data_img.getvalue()).decode("utf-8")
)
except UnicodeDecodeError:
self.blurred_image = None
super(Image, self).save(force_insert, force_update, using, update_fields)
您可以更改thumbnail_size变量以满足您的需要。最后,将以下内容添加到您的导入部分:
import base64
from io import BytesIO
别忘了运行mak移民和迁移命令!如果您有任何问题,请告诉我。