MultClip » Мастерская » Как оптимизировать svg картинки: примеры алгоритмов работы

Как оптимизировать svg картинки: примеры алгоритмов работы

Как оптимизировать svg картинки: примеры алгоритмов работы

В этой статье мы оптимизируем svg картинку для добавления интерактивности. Под оптимизацией я подразумеваю процесс сокращения строк кода svg изображения, что позволит современным браузерам быстро загрузить документ из web, а также процесс грамотной систематизации svg элементов для подготовки к разработке интерактива. Опыт показывает, что размер файла, созданного с помощью сторонних редакторов (Inkscape или Adobe Illustrator), можно облегчить в 10-20 раз без заметной потери качества.

В каком случае стоит оптимизировать svg-документ? Скажем так. Оптимизация векторного рисунка для web занимает достаточно времени и это, если подходить серьёзно, ювелирный процесс. Например, в своей работе сталкиваюсь использованием на страницах интерактивной графики в форме карт. Карты, даже векторные, весят очень много: есть границы регионов и областей, реки, озёра и другие географические объекты. Каждый объект состоит из точек и координат, которые отрисовываются на веб странице. Поэтому, облегчая svg файл с 500 КБ до 60 КБ вы получаете не только эстетическое удовлетворение от результата, но и облегчаете работу браузера за счёт увеличения скорости работы javascript скрипта. Логика оптимизации, для меня, сводится к следующим тезисам:

Теперь рассмотрим пример. Предлагаю найти и скачать файл велосипеда из википедии upload.wikimedia.org/wikipedia/commons/c/c8/Bicycle_diagram-ru.svg, вес которого составляет порядка 341 КБ. Так как работа абсолютно свободна для распространения, редактирования и даже использования в коммерческих целях, мы её и возьмём для примера.

Для начала создадим копию (чтобы иметь первоисточник для наглядности) и продолжим работать с Bicycle_diagram-ru.svg. Откроем его в любом современном браузере и текстовом редакторе. Это позволит нам всякий раз смотреть за нашими изменениями и результатами.

Беглое ознакомление с файлом показывает: слои не подписаны. Это можно понять при просмотре атрибута id элементов и групп - он задаётся автоматически графическим редактором Inkscape цифровым кодом. Кстати, этот редактор во многих тегах оставил свои метки вида
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
множественные строки стилей style="color:#000000;fill:none;stroke:#1000ff;stroke-width…
Забегая вперёд скажу, что всё эти вещи нужно будет удалять, но с умом. Так как, например, удалённый стиль задаёт элементу автоматически чёрный цвет (можете, кстати, попробовать).

Ещё мне не нравится то, что координаты слишком уж не округлённые, поэтому принял решение оптимизировать их в бесплатном и свободном графическом редакторе Inkscape. Наберите название в поисковике и увидите ссылку на официальный сайт редактора. Тем, кто пользуется платформой PortableApps достаточно установить программу простым кликом мышки.

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

Выведем панель «Редактор XML (Shift+Ctr+X)» - он позволяет просматривать дерево тегов и структуру xml в svg документе. Это очень удобно, так как тут можно задавать собственные названия объектам и переименовывать те, что создавались автоматически. Также потребуется панель «Слои (Shift+Ctr+L)».

Посмотрел на колёса и заметил в них изъян: вместо круглой формы они имеют не форму эллипса. Это плохо в том случае, если решимся в будущем создавать крутящиеся колёса. По этой причине создал новый слой и принялся на нём собирать обод колеса, покрышку, спицы, протектор с учётом того, чтобы затем не рисовать копии колёс, а просто добавлять из библиотеки любое количество раз тегом use.

Зайдите в текстовый редактор, найдите тег defs, уберите в нём идентификаторы и смело очистите его:

<defs>
</defs>

Также полностью удаляем sodipodi:namedview… и тег metadata… вплоть до закрывающего тега. Если мы обновим страничку браузера и ошибок нам не пишут, то всё отлично. Теперь в самой верхней части svg документа svg… заменим на более лаконичный контент:

<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg
xmlns:svg='http://www.w3.org/2000/svg'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'
_width='1000' _height='500'
viewBox='0 0 1000 500'
version='1.1'
xml:space='preserve'
id='multclip.ru'
onload='Init(evt)'>

После сохранения обновим файл в браузере и нам выведут сообщения об ошибке. Причина в том, что нам нужно удалить из документа все записи, связанные со строками: inkscape и sodipodi. При удалении будем внимательны: необходимо удалять атрибут вместе со значениями, всякий раз обновляя страницу. Почувствуйте себя хирургом, искусно отсекающим из тела документа всё лишнее, ибо именно оно и является сором. Например, строка sodipodi:nodetypes="czz", inkscape:connector-curvature="0", sodipodi:nodetypes="cs" и др.

Обратим внимание на «раздувшиеся» текстовые поля. Вообще на нашей картинке (взгляните на первоисточник) два вида текстовых полей. Один вид текста представляет собой написание малых нежирных букв, а второй - больших жирных букв. Для этого достаточно настроить внутренний css код, через который и будем применять тот или иной стиль в зависимости от класса. Предлагаю добавить в наш документ следующий стиль:

<style type='text/css' >
<![CDATA[
rect{
	fill:#e6e6e6;
}
text{
	font-size:13px;
}
.txt_big{
	font-weight:bold;
	font-size:14px;
}
.te{
	text-anchor:end;
}
]]>
</style>

Заметили запись rect? Если не догадались, то она окрашивает все наши прямоугольники в серый цвет, что позволяет нам полностью убрать длинный код стиля прямоугольников и текста. Каждая группа с серым блоком и текстом (можете привести весь текст подписей в порядок: блоки находятся почти в самом конце документа) после оптимизации должна выглядеть примерно так:

<g transform='translate(-18.63,-6.161)'>
	<rect width='19.19' height='98.19' x='582.9' y='632.7' />
	<text x='588' y='726.4'>клапан</text>
	<text y='672.9' x='587.3'>спицы</text>
	<text y='686.2' x='587.3'>втулка</text>
	<text y='699.6' x='587.3'>обод колеса</text>
	<text y='712.9' x='587.6'>шина</text>
	<text x='587.1' y='645.9' class='txt_big'>Колесо:</text>
</g>

После того, как все текстовые теги были оптимизированы, ошибки сами собой исчезли, а размер svg файла уменьшился с 342 КБ до 193 КБ. Но на самом деле работы по оптимизации векторного изображения - непочатый край. Например, нет ничего сложного добавить стиль к маленьким красным кругам в сносках [ниже, для удобства, буду называть их точками] и ещё больше облегчить картинку велосипеда. Рисовал точки вручную в текстовом редакторе, выведя всё за пределы группы велосипеда Получилось что-то вида:

<g id='dot_pedal' class='dot'>
	<circle cx='260' cy='640' r='3'/>
	<circle cx='197' cy='693' r='3'/>
	<circle cx='281' cy='662' r='3'/>
	<circle cx='283' cy='685' r='3'/>
</g>

Просто и понятно. Причём, каждый пункт соответствует очерёдности текстовой подписи, так что теперь можно будет включать и выключать нужный пункт на интерактивной схеме с помощью javascript. Старый код точек сноски удаляем и… Документ уменьшился со 193 КБ до 184 КБ абсолютно пока без искажения качества оригинала. Погнали дальше.

<g transform='matrix(1,2,-2,1,-29,17)'
id='g4779'>

Все ранее оптимизированные вещи (точки и текстовые сноски) разместил в отдельной группе внизу кода. Это тоже оптимизация, хотя организационная.

Теперь есть смысл линии сносок в виде path обернуть своим css стилем, при этом избавившись от дублирующегося кода для каждой линии-сноски. Полученное также разместим снизу документа. Оптимизация старых сносок выиграла 10 КБ. Итог: уменьшили и оптимизировали с 184 КБ до 174 КБ. Все готовые элементы помещаем в отдельную группу и скроем её, чтобы она не мешала нам с дальнейшей оптимизацией. Готовим svg к интерактивности дальше.

<g id='snoski' style='display:none'>	
		<g id='lines'>
		…
		</g>
		<g id='dots'>
		…
		</g>
		<g id='texts'>
		…
		</g>
	</g>

Самое интересное и сложное - колёса. Если подойти к делу с серьезностью, то мы не только заметно уменьшим вес svg документа, но и подготовим колёса для последующей имитации движения. Шину протектора можно представить в виде прозрачного круга, указав ширину контура, то же самое выполним для протектора, придав обводке вид штриховой линии [ css.yoksel.ru/svg-fill-and-stroke/ ]. Колёса к моему велику будут идентичны. Все по порядку.

В современных браузерах svg можно просматривать в режиме разработчика словно обычную html страничку. Кликните по интересующему элементу, выберете пункт посмотреть код - и перед Вами в окошке будет выведен код элемента с координатами и атрибутами. Желающие могут просмотреть всё дерево xml или отдельные его ветви. Очень полезная штука, кстати.

На рисунке колёса не имеют симметрии, перенасыщены объектами вида path и абсолютно не поддаются оптимизации. Будем рисовать свои из circle со свойствами для возможности анимации. Легко сказать.

Методом проб и ошибок, моё колесо (пока ещё без спиц) состоит всего из пяти строк. Много это или мало? Это отлично. Только один лишь протектор колеса из оригинального файла состоит из небольших объектов аж минимум по 30 на каждом колесе. Мой протектор состоит из трёх прозрачных circle с применением к ним стилей с использованием stroke-dasharray.

После того, как были нарисовали колёсо и спицы, удалим основные колёса. Размер файла сократился до 99 КБ. Помимо этого пришлось добавить ось колеса (основу крепления спиц колеса), удалить старый вариант с эллипсами. Обработали переднюю вилку, сместив узлы в Inkscape, удалили лишние детали под вилкой.

Для малой шестерёнки (педали) обработал 1/4 в Inkscape, добавил ещё 3 части. Масштабировал малую шестерёнку и сделал из неё большую. Оптимизировал педаль в Inkscape. Результат - 81 КБ.

У нас есть ещё и задняя шестерёнка, которая занимает очень много тегов и стилей. Заменил её той же шестерёнкой, что и использовал на педалях. Также удалил на раме лишние детали для заднего колеса. Размер файла стал 50 КБ.

Обратите внимание на раму: элементы каркаса велосипеда ровные и прямые, однако каждая деталь почему-то состоит из path с многочисленными точками. Оптимизируем, так как нет смысла проводить детализацию прямых отрезков (в том числе бликов на раме). Уберём в редакторе Inkscape лишние точки. Также предлагаю избавиться от одного последнего элемента id='g4869', имеющего transform='matrix(0.6922,…. И у нас не останется свойства matrix вообще. Есть ещё один неоспоримый плюс: добавим стили к цвету рамы и бликам, что позволит менять цвет велосипеда из css. После оптимизации рамы велосипеда и элементов руля размер svg файла уменьшился до 44 КБ.

Как искать и править фигуры в svg? Для себя нашёл быстрый способ: открывать файлы и их дубли в Inkscape, текстовом редакторе (на Ubuntu у меня Notepadqq) и просмотр получающегося изображения в Chromium (не забываем обновлять). В качестве файлового менеджера выбрал Double Commander - там вкладки можно создавать и смотреть размер файла. Вот, собственно, и весь инструментарий. Тем, кто использует Brackets, можно установить плагин для автоматического сохранения. В Inkscape имеется редактор XML, по нему тоже можно производить поиск (Ctrl+F).

Велосипедная цепь - это дублированный прозрачный путь с разными стилями для придания реалистичности цепи. Используем use. Размер к тому времени уменьшился до 40 КБ.

Теперь компонуем объекты файла по слоям, группируя каркас велосипеда и элементы руля. Рукоятка руля тоже требует оптимизации, заменяем круглые объекты кругами с применением стилей. Не забываем удалять старые объекты. После оптимизации руля размер составил 31 КБ.

Итак, задача по оптимизации svg документа и уменьшению размера документа в 10 раз решена, но мы продолжаем оптимизацию. Узнаем, на сколько ещё можно оптимизировать изображение, созданное в редакторах в Inkscape, Illustrator и других векторных редакторах. Меняем тени от колёс на эллипсы, так как этот код намного меньше и вновь добавляем стили. Обрисовываем детали велосипеда и присваиваем им новые стили до того момента, пока каждый тег не будет доведён до оптимальной строчки.

Размер моего оптимизированного svg изображения в итоге стал равным 20 КБ, что в 17 раз меньше исходного оригинала.

Your browser does not support SVGs

В следующей статье мы будем создавать интерактив из этой картинки с использованием JavaScript.