Вводная: на нашем сайте есть файловый менеджер, который может загружать любой файл на сайт; при этом файлу нужно автоматически сопоставить значок по его MIME-типу.

Проблема: MIME-типов очень много, собирать значки для них вручную каждый раз — очень долго (и глупо). Требуется какое-то автоматическое решение.

Решение: в этой заметке я собрал простой рецепт самостоятельного изготовления CSS-спрайтов для подключения их в дальнейшем в качестве MIME-описателей на сайте на основе значков из установленных в дистрибутив Ubuntu пакетов тем GTK/Qt.

В дистрибутивах linux ubuntu по адресу /usr/share/icons хранятся системные значки, в том числе и для представления файлов по их MIME-типу. Лицензия значков — в соответствии с пакетом, из которого в дистрибутив ставятся эти значки.
1. Найдём установленные в системе папки со значками MIME. Если нам нужен определённый размер файлов, отсортируем только его.

find /usr/share/icons -type d | grep mime | grep 48

Просмотрим найденные папки и выберем подходящие значки.
2. Создадим новые папки для значков и скопируем в них значки. Например, значки Gnome 48x48:

mkdir ./icons
cp `find /usr/share/icons/gnome/48x48/mimetypes/* -type f` ./icons -R

Мы разделяем значки и символические ссылки для уменьшения итогового объёма информации.
3. Это дополнительный шаг — он может понадобиться, только если мы получаем изображения в формате svg (масштабируемой векторной графики).
Нам нужно пройти все значки в папке ./icons и преобразовать их в формат PNG:

inkscape -z -f icons/authors.svg -e authors.png

Поскольку мы работаем с SVG, мы можем масштабировать оригинал при конвертации до нужного размера в точках путём задания параметра DPI (значение 90 приравнено к 100% оригинального размера значка, в нашем случае 48х48):

inkscape -z -f icons/authors.svg -e authors.png -d 120

Мы делаем это в цикле таким образом:

for fname in icons/*.svg; do inkscape -z -f $fname -e ${fname%%.svg}.png; done

4. Для создания CSS-спрайтов нам понадобится проект glue, написанный на Питоне.

sudo pip install glue

Если он уже установлен, мы сможем сразу же создать нужный пакет значков. Мы хотим очистить папку от лишних файлов, и оставить только png для обработки.

find ./icons/* ! -name "*.png" -delete
glue icons mimetypes

Попытка прохода по реальным значкам выявила ошибку в скрипте. Он не понимает двойной плюс в имени С++, и считает файлы text-x-c.png и text-x-c++.png одинаковыми (режет плюсы в имени CSS-класса). Выход нашёлся в замене плюсов на pp.

rename 's/\+\+/pp/' icons/*.png

5. Почистим за собой:

mv mimetypes/* ./
rm icons links mimetypes -fr

Эту команду можно не использовать, если нужно исследовать промежуточные результаты.
6. На выходе мы получаем рабочий css-спрайт для (практически всех) актуальных файлов по их MIME-типу.
Мы можем собрать все команды в единый скрипт-генератор:

#!/bin/bash

mkdir ./icons
cp `find $1/* -type f` ./icons -R

for fname in icons/*.svg; do
    inkscape -z -f $fname -e ${fname%%.svg}.png
done

find ./icons/* ! -name "*.png" -delete
rename 's/\+\+/pp/' icons/*.png
glue icons mimetypes

mv mimetypes/* ./
rm icons links mimetypes -fr

Передайте на вход скрипта папку-исходник и он создаст css-спрайт в текущей папке.

За бортом остался вопрос установки ссылок на идентичные типы файлов (например, текстовый документ LibreOffice/MS Office может иметь одинаковый значок). Получить эту информацию можно по адресу /usr/share/mime/, где находятся файлы xml с описанием типа MIME, используемого значка, названием формата файла в нескольких локалях. Там же можно получить информацию для сопоставления одного значка с другим по родственному типу файлов.

Комментарии (8)


  1. DjPhoeniX
    15.04.2015 00:47

    Во-первых, не делайте так. Пора уходить от растра к вектору — благо, 100% актуальных браузеров умеют SVG. Хотите CSS — используйте векторный шрифт, сгенерированный, например, IcoMoon. Или сразу в CSS пропишите иконки в SVG. Это хорошо, кроссбраузерно и красиво на любом разрешении при любом зуме страницы.
    Во-вторых, если уж перешли на тёмную сторону — хотя бы пройдитесь по PNG каким-нибудь оптимизатором, обычно это уменьшает размер файла в 2-3 раза (не забываем, что в CSS все PNG кодируются base64, что увеличивает их объём ещё в 4/3 раза).


    1. galadhon Автор
      15.04.2015 07:40

      Согласен, вектор сейчас лучше, а IcoMoon.app в качестве генератора шрифтов — вполне неплохой выход, добавлю в закладки.

      Но передо мной стояла задача быстрого изготовления набора значков фиксированного размера для показа ими MIME-типа документа в файловом менеджере на сайте. Причём, чтобы название mime-типа уже было прокодировано в файлах-исходниках значков (не выполнять сопоставления вручную), чтобы тип mime учитывался при построении CSS-спрайта и использовался в стилях CSS.

      Вопрос встраивания результата сборки в проект я преднамеренно вынес за рамки статьи, поскольку gulp/grunt позволяют в том числе и автоматически оптимизировать изображения для уменьшения их размера. С учётом же увеличения размера изображения при кодировании его в base64 и встраивании в CSS, я вообще и не думал применять эту технику.

      Встречный вопрос: у Вас есть ссылка на SVG-шрифт, содержащий глифы всех MIME-типов и чтобы лицензия была GPL/CC?


      1. DjPhoeniX
        15.04.2015 11:03

        Ссылок нету, но IcoMoon имеет довольно простой формат, который можно сгенерировать динамически, и импортировать те же файлы из Linux, которые вы перегоняли в PNG. Но я бы (с учётом, что иконки могут быть и цветные) остановился на CSS со встроенными в data-URI SVG. Полностью покрывает вашу задачу и генерируется скриптом на node в 20 строк.


    1. faiwer
      15.04.2015 07:52

      не забываем, что в CSS все PNG кодируются base64, что увеличивает их объём ещё в 4/3 раза
      А разве gZIP не нивелирует разницу?

      используйте векторный шрифт, сгенерированный, например, IcoMoon
      На одном из проектов заявлена поддержка msie8. Использую fontello. msie8 даже на тестовых примерах от fontello у меня умудряется показывать вместо иконок какую-то чушь, с некоторой большой вероятностью. Теперь стою перед вопросом решения… Похоже придётся из шрифта генерировать спрайт.

      Ещё вопрос. Я так понимаю, вы активно используете SVG. Какие подходы там используются, чтобы не городить ради 20 иконок — 20 запросов? Что-то вроде спрайтов?


      1. galadhon Автор
        15.04.2015 08:16
        +1

        Я? Нет, в своей практике я SVG не использую, пока что в этом не было нужны.

        Беглый поиск в гугле по ключу css svg icons привёл меня на обзорную статью http://css.yoksel.ru/svg-icons/. Кроме того, для Web можно описывать и подключать SVG-шрифты.


        1. faiwer
          15.04.2015 08:20

          Мой комментарий был в ответ на комментарий DjPhoeniX. Приглядитесь. За статью — спасибо, почитаю.


      1. DjPhoeniX
        15.04.2015 10:59

        Что бы не городить 20 запросов — можно вставить SVG прямо в CSS через Data-URI. Спрайт из SVG, конечно, собрать можно, но есть сомнения в целесообразности такого решения — браузеру надо будет отрисовать весь спрайт (после чего обрезать по границам) для каждого элемента.
        Для msie8 можно было бы сделать fallback-css с обычными иконками. Ну или разобраться в причинах проблем — они, обычно, решаемы, всё таки это не IE6.


      1. DjPhoeniX
        15.04.2015 11:05

        Вдогонку про gzip — использование «data:image/svg+xml;utf-8,...» с gzip сверху даст гораздо лучшее сжатие :)