Прозрачные PNG не сохраняют прозрачность после преобразования (Django + PIL)

Я использую sorl-thumbnail, PIL и Django на веб-сервере для динамического создания эскизов в шаблонах.

PIL устанавливается с поддержкой PNG, но по какой-то причине преобразования создают некоторые действительно причудливые артефакты на прозрачных участках изображений.

Я использовал этот gist на Github для установки необходимых зависимостей: https://raw.github.com/gist/1225180/eb87ceaa7277078f17f76a89a066101ba2254391/patch.sh

Вот код шаблона, который генерирует изображения (я не думаю, что это проблема, но не может помешать вам показать):

{% thumbnail project.image "148x108" crop="center" as im %}
  <img src='{{ im.url }}' />
{% endthumbnail %}

Ниже приведен пример того, что происходит. Любая помощь очень ценится!

Перед

Image with transparency

После

Image with artifacts

Ответ 1

Похоже, что получившееся изображение - это JPEG. Формат JPEG не поддерживает прозрачность. Попробуйте изменить шаблон миниатюр на это:

{% thumbnail project.image "148x108" crop="center" format="PNG" as im %}

Ответ 2

Или:

  • добавить format='PNG'.
  • добавить THUMBNAIL_PRESERVE_FORMAT=True в настройки.
  • или используйте настраиваемый движок, как описано здесь:

http://yuji.wordpress.com/2012/02/26/sorl-thumbnail-convert-png-to-jpeg-with-background-color/

"""
Sorl Thumbnail Engine that accepts background color
---------------------------------------------------

Created on Sunday, February 2012 by Yuji Tomita
"""
from PIL import Image, ImageColor
from sorl.thumbnail.engines.pil_engine import Engine


class Engine(Engine):
    def create(self, image, geometry, options):
        thumb = super(Engine, self).create(image, geometry, options)
        if options.get('background'):      
            try:
                background = Image.new('RGB', thumb.size, ImageColor.getcolor(options.get('background'), 'RGB'))
                background.paste(thumb, mask=thumb.split()[3]) # 3 is the alpha of an RGBA image.
                return background
            except Exception, e:
                return thumb
        return thumb

в настройках:

THUMBNAIL_ENGINE = 'path.to.Engine'

Вы можете использовать эту опцию сейчас:

{% thumbnail my_file "100x100" format="JPEG" background="#333333" as thumb %}
   <img src="{{ thumb.url }}" />
{% endthumbnail %}

Ответ 3

Я бы посоветовал вам лучше изучить, как скрэйл PIL backend обрабатывает масштабирование. Я предполагаю, что он создает некоторое вспомогательное изображение для применения дополнительных эффектов, а затем сообщает PIL о масштабировании оригинала на этом. Вы должны убедиться, что пункт назначения использует режим RGBA для поддержки прозрачности и что он начинается с того, что его альфа-установка равна нулю (а не чисто белая или черно-синяя или что-то подобное). Если ваше изображение использует индексированную палитру, тогда возможно, что оно не преобразуется в RGBA. В индексированном режиме PNG хранят прозрачный индекс цвета в своих метаданных, но процесс создания эскиза изменяет пиксели из-за сглаживания, поэтому вы не можете сохранить индексированную прозрачность в:

source = Image.open('dead-parrot.png')
source.convert('RGBA')
dest = source.resize((100, 100), resample=Image.ANTIALIAS)
dest.save('ex-parrot.png')