2009-03-08 13 views
14

장고에서 이미지를 업로드 한 후 이미지 크기를 쉽게 조정할 수 있습니까? 장고 1.0.2를 사용하고 PIL을 설치했습니다.저장시 이미지 크기 변경

크기를 조정하기 위해 모델의 save() 메서드를 재정의하려고 생각했지만 실제로 시작하고 재정의하는 방법을 알지 못합니다.

누군가 나를 올바른 방향으로 안내 할 수 있습니까? 덕분에

Guðmundur H @

:-) : 장고 - stdimage 패키지 당신은 업로드 된 파일을 처리하는 방법을 사용한다

답변

12

:-(Windows에서 작동하지 않기 때문에에서 입증 된 바와 같이 이 작동하지 않습니다 이 방법에서 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가 재귀를 할 수 없습니다. – Codygman

+0

works 나를 위해 win32에. –

6

이미지 크기 조정을 쉽고 투명하게 처리하려면 sorl-thumbnail 앱을 사용하는 것이 좋습니다. 내가 시작하는 모든 장고 프로젝트에 들어갑니다.

+0

[sorl-thumbnail] (https://github.com/sorl/sorl-thumbnail) 프로젝트가 githubbtw로 이동했습니다. – Raj

+0

Sorl은 새로운 mantainer를 보유하고 있으며 곧 새 릴리스를 준비 중입니다. 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를 사용하여 변수 선언을 작성하면 오류가 발생합니다 (파이썬은 str이 호출 가능하지 않다고 말합니다) – rvnovaes

+0

감사합니다. –

2

나는이 오래 알고 있지만, 그것을 바탕으로 비틀 거리는 사람을 위해 자동으로 그렇게하지 않으면 사용자가 지정하지 않거나 아무도 크기의 썸네일을 생성하는 패키지 Django-thumbs - Easy powerful thumbnails for Django integrated with StorageBackend에서 django-thumbs,있다. 그런 다음 원하는 크기로 원하는 축소판 그림을 호출합니다.

예를 들어, 이미지의 축소판 그림이 64x64 및 128x128로 표시되도록하려면 thumbs.models.ImageWithThumbsField을 가져 와서 ImageField 대신 사용하십시오. 다음 템플릿에서 당신이 호출 할 수있는, 필드 정의에 매개 변수 sizes=((64,64),(128,128))를 추가

{{ ClassName.field_name.url_64x64 }} 

{{ ClassName.field_name.url_128x128 }} 

축소판을 표시합니다. 빌라! 모든 작업은이 패키지에서 수행됩니다.

+0

, 당신은 또한 같은 성찰을 추가해야합니다 – Furbeenator

+0

를'south.modelsinspector 가져 오기 add_introspection_rules에서 add_introspection_rules ([ ( 은 [models.ImageField] # 클래스 (들)이이 적용 [], (사용되지 않음) # 위치 인수 {# 키워드 인수 "크기": [ "크기", { "기본": 없음}], }, ), ], [ "^ 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() 

모두 큰하지만 당신이 원하는 무슨에 따라 작동 :)

: 내가 대신 사진 및 엄지 손가락을 저장 모델의 저장 기능을 덮어 쓰지 않고 바로 사진의 크기를 조정 끝났다