2009-03-08 19 views
14

イメージをDjangoにアップロードした後で簡単にイメージのサイズを変更できますか?私はDjango 1.0.2を使用しており、PILをインストールしました。イメージを保存時にサイズ変更する

私はModelのsave()メソッドをオーバーライドしてサイズを変更しようと考えていましたが、実際に始める方法と上書きする方法はわかりません。

誰かが正しい方向に向かうことができますか? GuðmundurH @

:-)ありがとう:ジャンゴ・stdimageパッケージは、Windows上で動作しないため は、これは動作しませんで示したようにあなたは、アップロードされたファイルを処理する方法を使用する必要があります:-(

答えて

12

この方法ではDjango documentation

、あなたは、(むしろ直接ディスクに書き込むよりも)変数にチャンクを連結し、その変数からPILイメージを作成し、画像のサイズを変更し、それをディスクに保存することができます。

PILでは、Image.fromstringImage.resizeをご覧ください。 。

22

django-stdimageからStdImageFieldを使用することをお勧めします。汚い作業はすべて処理する必要があります。それはあなただけのフィールド定義にリサイズした画像の大きさを指定し、使いやすいです:

class MyModel(models.Model): 
    image = StdImageField(upload_to='path/to/img', size=(640, 480)) 

チェックアウトドキュメントを - それはまた、サムネイルを行うことができます。

+0

これはWindowsマシンでは動作しません:-(django-stdimageパッケージの既知のバグです。再帰エラー –

+11

があります。Windowsは再帰できません.Linuxの機能です:) – Codygman

+0

works私のためにwin32で。 –

6

画像のサイズ変更を簡単かつ透過的に処理するため、sorl-thumbnailアプリを強くお勧めします。私が始めたすべてのDjangoプロジェクトに入ります。

+0

[sorl-thumbnail](https://github.com/sorl/sorl-thumbnail)プロジェクトはgithubbtwに移動しました。 – Raj

+0

ソールは新しいマンティナーを抱えていて、すぐに新しいリリースを準備しています。http://github.com/mariocesar/sorl-thumbnail –

11

私はこのコードを使って、アップロードした画像を処理し、メモリに保存して(ディスクに永久に保存しないで)、Django ImageFieldに親指を保存します。 希望は助けることができます。

def handle_uploaded_image(i): 
     import StringIO 
     from PIL import Image, ImageOps 
     import os 
     from django.core.files import File 
     # read image from InMemoryUploadedFile 
     image_str = “” 
     for c in i.chunks(): 
      image_str += c 

     # create PIL Image instance 
     imagefile = StringIO.StringIO(image_str) 
     image = Image.open(imagefile) 

     # if not RGB, convert 
     if image.mode not in (“L”, “RGB”): 
      image = image.convert(“RGB”) 

     #define file output dimensions (ex 60x60) 
     x = 130 
     y = 130 

     #get orginal image ratio 
     img_ratio = float(image.size[0])/image.size[1] 

     # resize but constrain proportions? 
     if x==0.0: 
      x = y * img_ratio 
     elif y==0.0: 
      y = x/img_ratio 

     # output file ratio 
     resize_ratio = float(x)/y 
     x = int(x); y = int(y) 

     # get output with and height to do the first crop 
     if(img_ratio > resize_ratio): 
      output_width = x * image.size[1]/y 
      output_height = image.size[1] 
      originX = image.size[0]/2 - output_width/2 
      originY = 0 
     else: 
      output_width = image.size[0] 
      output_height = y * image.size[0]/x 
      originX = 0 
      originY = image.size[1]/2 - output_height/2 

     #crop 
     cropBox = (originX, originY, originX + output_width, originY + output_height) 
     image = image.crop(cropBox) 

     # resize (doing a thumb) 
     image.thumbnail([x, y], Image.ANTIALIAS) 

     # re-initialize imageFile and set a hash (unique filename) 
     imagefile = StringIO.StringIO() 
     filename = hashlib.md5(imagefile.getvalue()).hexdigest()+’.jpg’ 

     #save to disk 
     imagefile = open(os.path.join(‘/tmp’,filename), ‘w’) 
     image.save(imagefile,’JPEG’, quality=90) 
     imagefile = open(os.path.join(‘/tmp’,filename), ‘r’) 
     content = File(imagefile) 

     return (filename, content) 

#views.py 

    form = YourModelForm(request.POST, request.FILES, instance=profile) 
     if form.is_valid(): 
      ob = form.save(commit=False) 
      try: 
       t = handle_uploaded_image(request.FILES[‘icon’]) 
       ob.image.save(t[0],t[1]) 
      except KeyError: 
       ob.save() 
+0

更新: これはutf8画像ファイル名を受け入れるでしょう。 –

+2

あなたの方法はうまくいきます。コードをありがとう!私は、上記の変数名をstrから別のものに変更することをお勧めします。これは、PythonのBIF関数str()を隠すためです。誰かがあなたが書いたコードを少し変更してBIFを使って変数宣言をした場合、エラーが発生します(pythonはstrが呼び出し可能ではないと言っています) – rvnovaes

+0

更新ありがとう! –

2

私はこれが古いですけど、そうでない場合は誰もがそれにつまずきのために、自動的に指定したサイズでサムネイルを生成し、パッケージ、Django-thumbs - Easy powerful thumbnails for Django integrated with StorageBackenddjango-thumbs、またはnoneがあります。次に、必要なサムネイルを呼び出す。

たとえば、イメージのサムネイルを64x64と128x128にする場合は、thumbs.models.ImageWithThumbsFieldをインポートしてImageFieldの代わりに使用します。

{{ ClassName.field_name.url_64x64 }} 

{{ ClassName.field_name.url_128x128 }} 

をサムネイルを表示するには:その後、お使いのテンプレートから呼び出すことができ、フィールド定義にパラメータsizes=((64,64),(128,128))を追加します。 Voila!すべての作業はこのパッケージで行われます。

+0

データベースのメンテナンスのために南を使用する場合、あなたはまた、のような、イントロスペクションを追加する必要があります: – Furbeenator

+0

'south.modelsinspectorインポートadd_introspection_rules add_introspection_rules([ ( [models.ImageField]、#クラス(ES)これらが適用から []、#位置引数(未使用) {#キーワード引数 "サイズ":[ "サイズ"、{ "デフォルト":なし}]、 }、 )、 ]、[ "^ django_thumbs \。 db \ .models \ .ImageWithThumbsField "])' – Furbeenator

2

ここでは、フォームを使用するための完全なソリューションです。私はこのために、管理ビューを使用:

class MyInventoryItemForm(forms.ModelForm): 

    class Meta: 
     model = InventoryItem 
     exclude = ['thumbnail', 'price', 'active'] 

    def clean_photo(self): 
     import StringIO 
     image_field = self.cleaned_data['photo'] 
     photo_new = StringIO.StringIO(image_field.read()) 

     try: 
      from PIL import Image, ImageOps 

     except ImportError: 
      import Image 
      import ImageOps 

     image = Image.open(photo_new) 

     # ImageOps compatible mode 
     if image.mode not in ("L", "RGB"): 
      image = image.convert("RGB") 

     image.thumbnail((200, 200), Image.ANTIALIAS) 

     image_file = StringIO.StringIO() 
     image.save(image_file, 'png') 

     image_field.file = image_file 

     return image_field 

マイ在庫モデルは次のようになります。

class InventoryItem(models.Model): 

    class Meta: 
     ordering = ['name'] 
     verbose_name_plural = "Items" 

    def get_absolute_url(self): 
     return "/products/{0}/".format(self.slug) 

    def get_file_path(instance, filename): 

     if InventoryItem.objects.filter(pk=instance.pk): 
      cur_inventory = InventoryItem.objects.get(pk=instance.pk) 
      if cur_inventory.photo: 
       old_filename = str(cur_inventory.photo) 
       os.remove(os.path.join(MEDIA_ROOT, old_filename)) 

     ext = filename.split('.')[-1] 
     filename = "{0}.{1}".format(uuid.uuid4(), ext) 
     return os.path.join('inventory', filename) 
     #return os.path.join(filename) 

    def admin_image(self): 
     return '<img height="50px" src="{0}/{1}"/>'.format(MEDIA_URL, self.photo) 
    admin_image.allow_tags = True 

    photo = models.ImageField(_('Image'), upload_to=get_file_path, storage=fs, blank=False, null=False) 
    thumbnail = models.ImageField(_('Thumbnail'), upload_to="thumbnails/", storage=fs,  blank=True, null=True) 

....

私はだけではなく、写真をリサイズの写真と親指を保存する代わりに、モデルの機能を保存上書き終了:

def save(self): 

    # Save this photo instance first 
    super(InventoryItem, self).save() 

    from PIL import Image 
    from cStringIO import StringIO 
    from django.core.files.uploadedfile import SimpleUploadedFile 

    # Set our max thumbnail size in a tuple (max width, max height) 
    THUMBNAIL_SIZE = (200, 200) 

    # Open original photo which we want to thumbnail using PIL's Image object 
    image = Image.open(os.path.join(MEDIA_ROOT, self.photo.name)) 

    if image.mode not in ('L', 'RGB'): 
     image = image.convert('RGB') 

    image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS) 

    # Save the thumbnail 
    temp_handle = StringIO() 
    image.save(temp_handle, 'png') # image stored to stringIO 

    temp_handle.seek(0) # sets position of file to 0 

    # Save to the thumbnail field 
    suf = SimpleUploadedFile(os.path.split(self.photo.name)[-1], 
     temp_handle.read(), content_type='image/png') # reads in the file to save it 

    self.thumbnail.save(suf.name+'.png', suf, save=False) 

    #Save this photo instance again to save the thumbnail 
    super(InventoryItem, self).save() 

は、あなたが何をしたいかにもよるが素晴らしい仕事両:)

関連する問題