sysadmin-vlg.ru

SVG. Масштабируемая векторная графика. Часть 2

2017-08-10 12:18:37 TrefAS

Пишем файл SVG своими руками.
В прошлой части статьи мы уже выяснили, что файлы SVG текстовые, а стало быть фраза «написать пейзаж» приобрела второй, более привычный простому обывателю смысл. Итак минимальная заготовка файла SVG включает в себя следующий код:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<!-- Content -->
</svg>
Здесь в первой строке стандартный для всех файлов семейства XML пролог (лат.: - вступление). Ведь для вас не секрет, что файлы SVG из этого семейства. Во второй строке парный тэг <svg> ограничивающий тело документа и это для вас очевидный факт, ведь в последней строке вы видите его "хвост" - закрывающий тэг </svg>. Надеюсь, что стандартный комментарий (в третьей строке) указывающий куда мы будем писать дальше, тоже никого не напугал. Тем же, для кого все вышесказанное - "темный лес", а желание освоить материал все-таки присутствует рекомендую отыскать на просторах интернета толковый учебник по XML 1.0
С теми, кто все еще в строю, едем дальше... Разработаем схему нашего рисунка, а для начала найдем себе референсы в сети, либо нарисуем от руки, то что хотим увидеть в итоге. Я применил оба подхода и накопав кучу малоприемлемых картинок нарисовал (по аналогии с одним из понравившихся) свой:
Вот так, наскоро набросав ручкой на листке, отсканировав и разукрасив в Фотошопе я получил растровый эскиз будущего векторного рисунка.
Начнем со схемы документа и структура SVG файла "нам в помощь". Ведь то, что находится на заднем плане должно идти вначале, а то, что будет указано в файле в последнюю очередь отобразиться на рисунке в верхнем (наружном) слое, т.е. на переднем плане. И не будем забывать об оптимизации кода, о его минимализации. Итак, подложкой на нашей картине станет прямоугольник закрашенный сложным градиентом, где в верхней части мы переходим от темно-синего к светло-синему, а ниже от белого к темно-синему изображая, таким образом, небо и воду (еще не решил что это - море или озеро) эффектно выделив горизонт. Затем у нас будут идти три сгруппированных объекта, которые мы назовем "кочки" или "островки", кому как больше понравиться. Почему мы говорим о группах? Да просто, так мы нарисовав один сложный (составной) объект можем скопировав его и слегка трансформировав получить новый. Таким образом, сначала рисуется правая (на рисунке) "кочка", затем она увеличивается и переносится немного влево, затем сделаем еще одну копию и повторим увеличение и перенос.
Два деревца на двух передних "кочках" это тоже клоны для которых применена трансформация "масштаб+перенос". Облака отражающиеся в воде, это тоже пары, где клон имеет масштаб равный " 1" по оси Y и "+1" по оси Х, что приводит к отражению Y координат относительно оси Х (эффект "зеркала"). То же касается и пролеска, который виден вдали (может это островок, а может противоположный берег залива, решайте сами). Ну и в последнюю очередь идут облака которые мирно висят посреди нашего неба и не имеют отражений.
Теперь "копнем поглубже" и поговорим о группах - сложных объектах состоящих из нескольких контуров. На моей картинке я вижу таких несколько: это "кочки" о которых мы уже говорили, а так же отражающиеся облака и деревья. С облаками все просто, тут по два контура, где на заднем плане (напоминаю, что в файле он будет идти впереди/вначале) контур с белым фоном, ближе контур залитый голубой краской. Чуть больше работы предстоит с деревьями, ведь тут у нас крона из трех контуров с разными оттенками зеленого, но вперед мы изобразим ствол дерева в виде контура залитого коричневой краской (простите, забыл покрасить в Фотошопе) и тогда крона идущая в файле следом за ним накроет его на картине. И наконец, "высший пилотаж", наши "островки-кочки"... Здесь залитая градиентом от темно-зеленого к светлому основа представленная контуром ограниченному ДВУМЯ точками, но об этом позже. На первом и втором клоне добавлены тропинки, чтобы картинка не получилась совсем уж скучной пав жертвой моего желания оптимизировать/минимизировать. И цветочки повсюду, что может быть чудесней, один контур и градиент по схеме красный-красный-белый-белый, т.е. нам не нужно рисовать серединку и лепестки отдельно, а выделить этот факт цветом. К тому же сделав несколько вариантов градиента для цветов мы сможем сделать красивые и пестрые газончики.
Ну вот, первый этап нами уже пройден и мы можем начертить схему документа, который будем писать на SVG. Формат SVG являясь членом семейства XML наследует от него важный признак - древовидную структуру, которую мы и отображаем в нашей схеме:
Файл который мы напишем лишь слегка отличается, дополняя ее нюансами реализации.
В своем проекте мы будем использовать только два графических примитива - это прямоугольник и контур, но для "общего развития" сообщу, что в спецификации SVG описаны еще несколько, это: круг, овал, линия, полилиния и полигон (многоугольник), и еще (чуть не забыл) текст.
Начнем вникать в тонкости описания примитивов. С прямоугольником, который представлен тэгом <rect />, что вполне естественно, никаких сложностей быть не может. Тут среди прочих нам важны четыре атрибута, два на позицию (положение на холсте - Х и Y) и два на размер (ширина и высота). Гораздо сложнее примитив "контур" - тэг <path /> у которого есть атрибут под названием "d" (от англ. data - данные) - это и есть собственно путь по которому пойдет перо рисуя наш контур. Давайте подробнее разбираться, ведь в спецификации этой теме посвящена вся восьмая глава...
Итак, про атрибут "d" в спецификации сказано, что он - "определяет контур фигуры". Осталось выяснить как он это делает. Читаем спецификацию дальше и находим вот что: "атрибут ´d´ содержит инструкции для перемещения, рисования линии, дуги, кривой Безье (и квадратичной и кубической), а также закрытия (замыкания).". Эти инструкции (команды) записываются латинскими буквами и ниже я привожу таблицу с их определением:
M или m (x, y)
Начинает новый подконтур в заданных (x, y) координатах. М. (прописная буква) указывает, что далее следуют абсолютные координаты; м. (строчная) указывает, что координаты относительные. Если эта команда сопровождается многократными парами координат, следующие пары это неявные команды рисования линий (L / l). Следовательно, неявные команды будут относительны, если команда перемещения пера относительна, и абсолютны, в противном случае. Если (m) появляется как первый элемент контура, то эту команду принимают как (М) с парой абсолютных координат, но в этом случае, все последующие пары координат считаются относительными несмотря на то, что начальная команда интерпретируется как перенос пера в абсолютной системе координат.

Z или z без параметров
Закрывает текущий контур, рисуя прямую линию от текущей точки до начальной точки текущего подконтура. Так как Z и z не берут никакие параметры, они имеют идентичный эффект.

L или l (x, y)
Рисует линию от текущей точки до заданной (x, y) координатами, которые становятся новой текущей точкой. L (прописная буква) указывает, что далее следуют абсолютные координаты; l (строчная) указывает, что будут следовать относительные координаты. Множество пар координат может быть определено, чтобы рисовать «ломаную» линию. В конце команды, новая текущая точка устанавливается на заключительный набор координат.


H или h (x)

Рисует горизонтальную линию от текущей точки (cpx, cpy) к (x, cpy). H (прописная буква) указывает, что будут следовать абсолютные координаты; h (строчная) указывает, что будут следовать относительные координаты. "x" можно указать многократно (хотя обычно это не имеет смысла). В конце команды, новой текущей точкой становится (x, cpy) в последнем x.

V или v (x)
Рисует вертикальную линию от текущей точки (cpx, cpy) к (срx, y). V (прописная буква) указывает, что будут следовать абсолютные координаты; v (строчная) указывает, что будут следовать относительные координаты. "x" можно указать многократно (хотя обычно это не имеет смысла). В конце команды, новой текущей точкой становится (cpx, y) в последнем y.

C или с (x1, y1, x2, y2, x, y)
Рисует кубическую кривую Безье от текущей точки до (x, y) используя (x1, y1) как контрольный пункт в начале кривой и (x2, y2) как контрольный пункт в конце кривой. C (прописная буква) указывает, что абсолютные координаты будут следовать; c (строчная) указывает, что относительные координаты будут следовать. Могут быть определены многократные наборы координат, чтобы рисовать полилинию Безье. В конце команды, новой текущей точкой становится последняя (x, y) пара координат, используемая в полилинии Безье.

S или s (x2, y2, x, y)
Рисует кубическую кривую Безье от текущей точки до (x, y). Первым контрольным пунктом (вначале кривой) считается отражение второго контрольного пункта на предыдущей команде относительно текущей точки. (Если нет никакой предыдущей команды или если предыдущая команда не была C, c, S или s, считается, что первый контрольный пункт совпадает с текущей точкой.) (x2, y2) - второй контрольный пункт (то есть, контрольный пункт в конце кривой). S (прописная буква) указывает, что абсолютные координаты будут следовать; s (строчная) указывает, что относительные координаты будут следовать. Многократные наборы координат могут быть определены, чтобы рисовать полилинию Безье. В конце команды, новой текущей точкой становится последняя (x, y) пара координат, используемая в полилинии Безье.


Q или q (x1, y1, x, y)

Рисует квадратичную кривую Безье от текущей точки до (x, y) используя (x1, y1) как контрольный пункт. Q (прописная буква) указывает, что абсолютные координаты будут следовать; q (строчная) указывает, что относительные координаты будут следовать. Многократные наборы координат могут быть определены, чтобы рисовать полилинию Безье. В конце команды, новой текущей точкой становится последняя (x, y) пара координат, используемая в полилинии Безье.

T или t (x, y)
Рисует квадратичную кривую Безье от текущей точки до (x, y). Контрольный пункт принят, чтобы быть отражением контрольного пункта на предыдущей команде относительно текущей точки. (Если нет никакой предыдущей команды или если предыдущая команда не была Q, q, T или t, предполагется, что контрольный пункт совпадает с текущей точкой.) T (прописная буква) указывает, что абсолютные координаты будут следовать; t (строчная) указывает, что относительные координаты будут следовать. В конце команды, новой текущей точкой становится последняя (x, y) пара координат, используемая в полилинии Безье.

A или а (rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y)
Рисует краткую дугу от текущей точки до (x, y). Размер и ориентация эллипса определяют два радиуса (rx, ry) и угол x-axis-rotation, который указывает, как эллипс в целом вращается относительно текущей системы координаты. Центр (cx, cy) эллипса рассчитан автоматически, чтобы удовлетворить ограничениям, наложенным другими параметрами. large-arc-flag и sweep-flag вносят вклад в автоматические вычисления, и помогают определить, как дуга оттянута.

У нас готово почти все чтобы начать писать файл с нашим пейзажем, а пока "лирическое отступление"...
Перед началом самостоятельной работы с SVG я рекомендую почитать файлы сгенерированые графическими редакторами. Ничего (к сожалению) не могу сказать о Adobe Illustrator'e, потому что им я никогда не пользовался. Знаю Corel Draw экспортирует, но он является продуктом коммерческим и не каждый осилит его приобретение только для того, чтобы поэкспериментировать с экспортом в SVG. Я рекомендую скачать редактор векторной графики Inkscape с одноименного сайта http://www.inkscape.org. Этот редактор распространяется бесплатно, и что самое главное, SVG его родной формат. Сохраняйте файлы в режиме "Оптимизированный SVG" и открывайте их "Блокнотом" (любым текстовым редактором). В режиме оптимизации мы видим минимум "мусора" в коде файла и если вам лень "просчитывать" ваши рисунки можете использовать Inkscape как основной инструмент для создания SVG файлов.
В следующей части статьи мы просчитаем контуры наших объектов, научимся их трансформировать и размещать на холсте, затем приступим к заполнению нашего файла-болванки.