重複の可能性:
保存時に画像のサイズを変更する
djangoでサムネイルを作成しようとしていますが、サムネイルの生成に使用するカスタムクラスを作成しようとしています。次のように
from cStringIO import StringIO
from PIL import Image
class Thumbnail(object):
SIZE = (50, 50)
def __init__(self, source):
self.source = source
self.output = None
def generate(self, size=None, fit=True):
if not size:
size = self.SIZE
if not isinstance(size, tuple):
raise TypeError('Thumbnail class: The size parameter must be an instance of a tuple.')
# resize properties
box = size
factor = 1
image = Image.open(self.source)
# Convert to RGB if necessary
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
while image.size[0]/factor > 2*box[0] and image.size[1]*2/factor > 2*box[1]:
factor *=2
if factor > 1:
image.thumbnail((image.size[0]/factor, image.size[1]/factor), Image.NEAREST)
#calculate the cropping box and get the cropped part
if fit:
x1 = y1 = 0
x2, y2 = image.size
wRatio = 1.0 * x2/box[0]
hRatio = 1.0 * y2/box[1]
if hRatio > wRatio:
y1 = int(y2/2-box[1]*wRatio/2)
y2 = int(y2/2+box[1]*wRatio/2)
else:
x1 = int(x2/2-box[0]*hRatio/2)
x2 = int(x2/2+box[0]*hRatio/2)
image = image.crop((x1,y1,x2,y2))
#Resize the image with best quality algorithm ANTI-ALIAS
image.thumbnail(box, Image.ANTIALIAS)
# save image to memory
temp_handle = StringIO()
image.save(temp_handle, 'png')
temp_handle.seek(0)
self.output = temp_handle
return self
def get_output(self):
self.output.seek(0)
return self.output.read()
このクラスの目的は、さまざまな場所で使用して、その場でサムネイルを生成できるようにすることです。クラスは完全に機能します。ビューの下で直接テストしました。フォームのsaveメソッド内にサムネイルクラスを実装して、保存時に元の画像のサイズを変更しました。
私のデザインでは、サムネイル用に2つのフィールドがあります。1つのサムネイルを生成できましたが、2つ生成しようとするとクラッシュし、何が問題なのかわからないまま何時間も立ち往生しています。
これが私のモデルです
class Image(models.Model):
article = models.ForeignKey(Article)
title = models.CharField(max_length=100, null=True, blank=True)
src = models.ImageField(upload_to='publication/image/')
r128 = models.ImageField(upload_to='publication/image/128/', blank=True, null=True)
r200 = models.ImageField(upload_to='publication/image/200/', blank=True, null=True)
uploaded_at = models.DateTimeField(auto_now=True)
これが私のフォームです
class ImageForm(models.ModelForm):
"""
"""
class Meta:
model = Image
fields = ('src',)
def save(self, commit=True):
instance = super(ImageForm, self).save(commit=True)
instance.r128 = SimpleUploadedFile(
instance.src.name,
Thumbnail(instance.src).generate((128, 128)).get_output(),
content_type='image/png'
)
instance.r200 = SimpleUploadedFile(
instance.src.name,
Thumbnail(instance.src).generate((200, 200)).get_output(),
content_type='image/png'
)
if commit:
instance.save()
return instance
奇妙な部分は、saveの形式でinstance.r200を含む行を削除したときです。正常に動作し、サムネイルを作成して正常に保存します。2番目のサムネイルを追加すると、失敗します。
ここで何が間違っているのか考えてみてください。
ありがとう
アップデート:
コメントリクエストに従って、エラートレースを追加しています
IOError at /en/publication/new/
cannot identify image file
Request Method: POST
Request URL: http://127.0.0.1:8000/en/publication/new/?image-extra=
Django Version: 1.4.2
Exception Type: IOError
Exception Value:
cannot identify image file
Exception Location: /Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py in open, line 1980
Python Executable: /Users/mo/Projects/pythonic/snowflake-env/bin/python
Python Version: 2.7.2
アップデート
印刷ステートメントを作成しようとしましたが、以下が出力です
Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
return func(*args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
formset.save()
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
obj = form.save(commit=False)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
Thumbnail(instance.src).generate((200, 200)).get_output(),
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 23, in generate
image = Image.open(self.source)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
ご覧のとおり、最初の画像は正常に印刷および処理され、2番目の画像は失敗しています。
アップデート
サムネイルクラスにcopy()を適用した後のトレースバックエラーの更新
ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
return func(*args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
formset.save()
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
obj = form.save(commit=False)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
f128.write(Thumbnail(instance.src).generate((128, 128)).get_output())
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 15, in __init__
self._pilImage = Image.open(self.source)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
アップデート
最後に、私はそれを機能させることができましたが、ファイルを以下のようにself.sourceにストリーミングする必要がありました
def __init__(self, source):
self.source = StringIO(file(source.path, "rb").read())
self.output = None
self._pilImage = Image.open(self.source)
上記の理想的なアプローチは何ですか?ヒットするたびにファイルを読み取るのは良い考えですか?いいえの場合、私の選択肢は何ですか?