Pull to refresh

django-headline или @font-face средствами Django

Reading time3 min
Views2.7K
На этой неделе в очередной раз столкнулся с проблемой «нестандартных» шрифтов, и если ранее можно было иногда обойтись самой обычной нарезкой в графическом редакторе или использовать какие-то клиентские приёмы подмены, то в этот раз задача стоит наиболее глобально. Динамических заголовков в надвигающемся проекте реально много.

Своими мыслями, поиском и конечным решением я и хотел бы поделиться с вами.


Преамбула


Итак, в принципе, какие у нас есть варианты:
  1. Заменять на Flash: sIFR, swftype;
  2. рисовать на canvas JavaScript`ом: cufon, typeface;
  3. использовать для этих целей сервер.

Первый вариант я уже использовал в паре проектов, правда не собственно sIFR, но не суть важно, результатом я остался не очень доволен. Сборки-пересборки Flash-файла со шрифтом, проверки на флеш, «рамочка» в IE7, не кошерно в конце концов. Второй вариант — всегда считал слишком тяжеловесным, как по трафику (файлы с отрендеренными шрифтами весят прилично, да ещё и не всегда корректно конвертируются), так и по нагрузке на процессор клиента. Так что в продакшен его ни разу не пустил.

Так я пришёл к третьему варианту. Однажды я уже прорабатывал этот способ на одном из тогда ещё php-проектов, вычитав идею на A List Apart. Работает и работает вполне сносно, хотя в этом методе по-прежнему использовался JavaScript. Более того, теперь мы разрабатываем проекты только на Django, так что я пошёл на поиски и через некоторое время нашёл два похожих проекта: django-cairo-text и django-image-replacement. Первый обладает достаточно широкими возможностями, но не умеет рисовать шрифтом из файла, только одним из установленных в систему, что в моём случае абсолютно не подходит, второй же слишком прост для моих нужд и использует не совсем удобные для меня подходы.

Но база есть, есть цель и я, как водится, решил написать свои костыли с турбо-приводом. Собственно то, что из этого получилось, я и хочу представить на ваше обозрение.

Итак django-headline


Что мы умеем на сегодня


  • Рендеринг картинок из шаблона тремя путями: фильтром, тегом и тегом, меняющим контекст
  • Естественно, кеширование ранее отрендеренных изображений
  • Определение стандартных стилей шрифта через классы
  • Автоматическая замена html-entities на юникодные символы
  • Разбиение текстовой строки по br или по словам
  • Собственные настройки расположения шрифтов и папки для кеша
  • Опциональная оптимизация выходного png, через внешние утилиты


Установка и настройка


Для работы требуются установленные: PIL и Freetype2

Разместите файл headline.py в папку templatetags вашего приложения.

Для настройки доступны такие параметры:

# Папка для кеша картинок (относительно вашего MEDIA_ROOT/MEDIA_URL)
HEADLINE_CACHE_DIR = 'upload/textcache'

# Папка для шрифтов (относительно вашего MEDIA_ROOT)
HEADLINE_FONTS_DIR = 'fonts'

# Если это требуется, путь к оптимизатору
HEADLINE_PNG_OPTIMIZER = "optipng -o7 %(file)s"

# Пресеты настроек отображения
HEADLINE_CLASSES = {
   "<class_name>": {
       'font': <file>,
       'size': <size>,
       'color': <hex color>,
       'decoration': ['underline', 'strikeout'], # Optional
   },
   ...
}


Примеры использования


{% load headline %}

Как фильтр


   {{ foo|headline:"font.ttf,20,#000" }}
   {{ foo|headline:"font.ttf,20,#000,underline,all" }}
   {{ foo|headline:"base,br" }}


Как тег


   {% headline "font.ttf,20,#000" %}Big {{ foo }}{% endheadline %}
   {% headline "font.ttf,20,#000,strikeout,none" %}Big {{ foo }}{% endheadline %}
   {% headline "base" %}Big {{ foo }}{% endheadline %}


Как тег, модифицирующий контекст


   {% headlines foo_list bar_dict baz_var "And some text" as headers "font.ttf,20,#000" %}
   {% headlines foo_list bar_dict baz_var "And some text" as headers "font.ttf,20,#000,all" %}
   {% headlines foo_list bar_dict baz_var "And some text" as headers "base" %}


В этом случае, в качестве параметров можно передавать как переменные и простые строки, заключенные в двойные кавычки, так и списки и словари. На выходе имеем список headers из объектов {file, text, width, height}:

   {% for head in headers %}
      <img src="{{ head.file }}" alt="{{ head.text }}" width="{{ head.width }}" height="{{ head.height }}" />
   {% endfor %}


Вот, что, к примеру, может получиться в финале. Я не дизайнер и шрифты подбирал «на глазок», так что за них прошу ногами не пинать.

Таким образом для клиента это выглядит как ручная нарезка, для сервера — нагрузка носит разовый характер, для разработчика всё просто и прозрачно. Профит!

Ещё раз ссылки по теме:


За сим спасибо, принимаю отзывы по теме, любой степени лестности.

Tags:
Hubs:
+25
Comments52

Articles

Change theme settings