Создание двух миниатюр из одного изображения в Django - PullRequest
0 голосов
/ 15 марта 2010

это кажется довольно простой проблемой, но я не могу понять, что здесь происходит. По сути, я хотел бы создать две разные миниатюры из одного изображения на модели Django. В итоге происходит то, что кажется, что оно зацикливается и воссоздает одно и то же изображение (при этом каждый раз добавляя подчеркивание к нему), пока оно не выдаст ошибку, что имя файла слишком большое. Итак, вы получите что-то вроде:

OSError: [Errno 36] File name too long: 'someimg________________etc.jpg'

Вот код (метод сохранения на модели Artist):

def save(self, *args, **kwargs):

  if self.image:
    iname = os.path.split(self.image.name)[-1]
    fname, ext = os.path.splitext(iname)
    tlname, tsname = fname + '_thumb_l' + ext, fname + '_thumb_s' + ext
    self.thumb_large.save(tlname, make_thumb(self.image, size=(250,250)))
    self.thumb_small.save(tsname, make_thumb(self.image, size=(100,100)))
  super(Artist, self).save(*args, **kwargs)

 def make_thumb(infile, size=(100,100)):
   infile.seek(0)
   image = Image.open(infile)

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

   image.thumbnail(size, Image.ANTIALIAS)

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

   return ContentFile(temp.getvalue())

Я не показывал импорт для краткости. Предположим, что в модели Artist есть два поля ImageField: thumb_large и thumb_small.

Способ, которым я проверяю, работает ли он в оболочке:

artist = Artist.objects.get(id=1)
artist.save() 
#error here after a little wait (until I assume it generates enough images that the OSError gets raised)

Если это не правильный способ, я буду признателен за любые отзывы. Спасибо!

1 Ответ

3 голосов
/ 15 марта 2010

Как правило, я хотел бы предоставить возможность создания эскизов автору шаблона в максимально возможной степени. Таким образом, они могут регулировать размер вещей в шаблоне. В то время как встраивание его в слой бизнес-логики является более фиксированным. Возможно, у вас есть причина.

Этот шаблонный фильтр должен генерировать файл при первой загрузке, а затем загружать файл при будущих загрузках. Это заимствовано из некоторого блога давным-давно, хотя я думаю, что я добавил функцию центра урожая. Есть, скорее всего, другие с еще большим количеством функций.

{% load thumbnailer %}
...
<img src="{{someimage|thumbnail_crop:'200x200'}}" />

файл appname / templatetags / thumbnailer.py

import os
import Image
from django.template import Library

register.filter(thumbnail)
from settings import MEDIA_ROOT, MEDIA_URL

def thumbnail_crop(file, size='104x104', noimage=''):
    # defining the size
    x, y = [int(x) for x in size.split('x')]
    # defining the filename and the miniature filename
    try:
        filehead, filetail = os.path.split(file.path)
    except:
        return '' # '/media/img/noimage.jpg'

    basename, format = os.path.splitext(filetail)
    #quick fix for format
    if format.lower() =='.gif':
        return (filehead + '/' + filetail).replace(MEDIA_ROOT, MEDIA_URL)

    miniature = basename + '_' + size + format
    filename = file.path
    miniature_filename = os.path.join(filehead, miniature)
    filehead, filetail = os.path.split(file.url)
    miniature_url = filehead + '/' + miniature
    if os.path.exists(miniature_filename) and os.path.getmtime(filename)>os.path.getmtime(miniature_filename):
        os.unlink(miniature_filename)
    # if the image wasn't already resized, resize it
    if not os.path.exists(miniature_filename):
        try:
            image = Image.open(filename)
        except:
            return noimage

        src_width, src_height = image.size
        src_ratio = float(src_width) / float(src_height)
        dst_width, dst_height = x, y
        dst_ratio = float(dst_width) / float(dst_height)

        if dst_ratio < src_ratio:
            crop_height = src_height
            crop_width = crop_height * dst_ratio
            x_offset = float(src_width - crop_width) / 2
            y_offset = 0
        else:
            crop_width = src_width
            crop_height = crop_width / dst_ratio
            x_offset = 0
            y_offset = float(src_height - crop_height) / 3
        image = image.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height)))
        image = image.resize((dst_width, dst_height), Image.ANTIALIAS)
        try:
            image.save(miniature_filename, image.format, quality=90, optimize=1)
        except:
            try:
                image.save(miniature_filename, image.format, quality=90)
            except:
                return '' #'/media/img/noimage.jpg'

    return miniature_url

register.filter(thumbnail_crop)
...