使用Django进行图片缩放?
我刚开始接触Django(还有Python),在尝试自己搞明白一些事情之前,我不想直接使用别人的应用。我现在有点困惑,不太明白在Django(或者Python)中,事情是怎么安排的。我想弄清楚的是,如何在上传图片后调整它的大小。我已经把我的模型设置得很好,并且在后台管理中也能正常使用,图片也能顺利上传到指定的文件夹:
from django.db import models
# This is to list all the countries
# For starters though, this will be just United Kingdom (GB)
class Country(models.Model):
name = models.CharField(max_length=120, help_text="Full name of country")
code = models.CharField(max_length=2, help_text="This is the ISO 3166 2-letter country code (see: http://www.theodora.com/country_digraphs.html)")
flag = models.ImageField(upload_to="images/uploaded/country/", max_length=150, help_text="The flag image of the country.", blank=True)
class Meta:
verbose_name_plural = "Countries"
def __unicode__(self):
return self.name
现在我遇到的问题是,如何把这个文件做成一个缩略图。正如我所说的,我希望在不使用其他人应用的情况下(暂时),自己实现这个功能。我从DjangoSnippets上找到了这段代码:
from PIL import Image
import os.path
import StringIO
def thumbnail(filename, size=(50, 50), output_filename=None):
image = Image.open(filename)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
image = image.resize(size, Image.ANTIALIAS)
# get the thumbnail data in memory.
if not output_filename:
output_filename = get_default_thumbnail_filename(filename)
image.save(output_filename, image.format)
return output_filename
def thumbnail_string(buf, size=(50, 50)):
f = StringIO.StringIO(buf)
image = Image.open(f)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
image = image.resize(size, Image.ANTIALIAS)
o = StringIO.StringIO()
image.save(o, "JPEG")
return o.getvalue()
def get_default_thumbnail_filename(filename):
path, ext = os.path.splitext(filename)
return path + '.thumb.jpg'
...但这让我更加困惑了...因为我不知道这段代码应该如何融入到我的Django应用中?而且,这真的是制作成功上传的图片缩略图的最佳解决方案吗?有没有人能给我展示一个简单、可靠的方法,让像我这样的初学者能够正确学习这个?比如,应该把这段代码放在哪里(models.py?forms.py?...)以及它在实际应用中是如何工作的?...我只是需要一点帮助,来理解和解决这个问题。
谢谢!
12 个回答
我对你发的代码不太确定,因为我从来不使用那种模型,不过还有另一种方法。
你可以自己实现一个 FileUploadHandler
来处理图片文件的上传。示例可以在这里找到。就在第37行(dest.close()
)之后,使用 thumbnail(upload_dir + upload.name)
这个函数(就是你发的那个)。
希望这对你有帮助。
这是我在我的模型中用来保存新缩略图的代码,前提是上传的图片发生了变化。这段代码是基于另一个Django的代码片段写的,但我记不清是谁写的。如果你知道的话,请留言告诉我,这样我可以给他们一些认可。
from PIL import Image
from django.db import models
from django.contrib.auth.models import User
import os
import settings
class Photo_Ex(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
photo = models.ImageField(upload_to='photos')
thumbnail = models.ImageField(upload_to='profile_thumb', blank=True,
null=True, editable=False)
def save(self, *args, **kwargs):
size = (256,256)
if not self.id and not self.photo:
return
try:
old_obj = Photo_Ex.objects.get(pk=self.pk)
old_path = old_obj.photo.path
except:
pass
thumb_update = False
if self.thumbnail:
try:
statinfo1 = os.stat(self.photo.path)
statinfo2 = os.stat(self.thumbnail.path)
if statinfo1 > statinfo2:
thumb_update = True
except:
thumb_update = True
pw = self.photo.width
ph = self.photo.height
nw = size[0]
nh = size[1]
if self.photo and not self.thumbnail or thumb_update:
# only do this if the image needs resizing
if (pw, ph) != (nw, nh):
filename = str(self.photo.path)
image = Image.open(filename)
pr = float(pw) / float(ph)
nr = float(nw) / float(nh)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
if pr > nr:
# photo aspect is wider than destination ratio
tw = int(round(nh * pr))
image = image.resize((tw, nh), Image.ANTIALIAS)
l = int(round(( tw - nw ) / 2.0))
image = image.crop((l, 0, l + nw, nh))
elif pr < nr:
# photo aspect is taller than destination ratio
th = int(round(nw / pr))
image = image.resize((nw, th), Image.ANTIALIAS)
t = int(round(( th - nh ) / 2.0))
image = image.crop((0, t, nw, t + nh))
else:
# photo aspect matches the destination ratio
image = image.resize(size, Image.ANTIALIAS)
image.save(self.get_thumbnail_path())
(a, b) = os.path.split(self.photo.name)
self.thumbnail = a + '/thumbs/' + b
super(Photo_Ex, self).save()
try:
os.remove(old_path)
os.remove(self.get_old_thumbnail_path(old_path))
except:
pass
def get_thumbnail_path(self):
(head, tail) = os.path.split(self.photo.path)
if not os.path.isdir(head + '/thumbs'):
os.mkdir(head + '/thumbs')
return head + '/thumbs/' + tail
def get_old_thumbnail_path(self, old_photo_path):
(head, tail) = os.path.split(old_photo_path)
return head + '/thumbs/' + tail
如果你觉得可以的话,这里有一个现成的Django应用,它正好可以满足你的需求:https://github.com/sorl/sorl-thumbnail