[Из песочницы] Генерация картинок для Android приложения из SVG

Введение Здравствуйте. Не так давно я решил попробовать себя в качестве разработчика под известную каждому платформу Android. На пути разработки я столкнулся с многими проблемами и одной из них оказалась создание картинок под разные разрешения экранов. Сначала я пробовал создать картинки в PhotoShop, но это оказалось муторно, нужно сохранять при любом изменении 5 картинок в разных разрешениях, да и не гений я этой программы. И тут мне пришла в голову мысль нарисовать картинки в SVG, до этого у меня был опыт работы с данным форматом, я делал визуализацию к курсачу по системам массового обслуживания (смайлики бегали в кассу и иногда скапливались в очереди).Реализация Итак, я в Sublime Text накодил нужные картинки, всё здорово и масштабируемо, но как бы автоматически сохранить в разных разрешениях эти SVG. Для Java есть библиотечки, которые конвертируют данный вид графики, но оказалось они не понимают к примеру теги. В итоге, я подумал и решил сам написать приложение, которое бы сохраняло всё в нужных разрешениях по своим папкам. Язык на который пал мой выбор, это JavaScript и платформа Node.js, так как с ними у меня связана основная занятость.Начал я с поиска модуля для Node.js, который мог бы преобразовывать SVG в обычные PNG картинки, но найденные модули, сохраняли картинку только в том разрешении, которое было задано у картинки параметрами width и height. Поплевавшись, я решил написать всё сам. Небольшой список задач поставленный перед приложением:

Клиентская часть, преобразовывающая картинки Сервер, который даёт нужную информацию клиенту и сохраняет картинки Описание в формате json, какую картинку в каких разрешениях сохранить После преобразования всех картинок должна закрыться страница в браузере и остановиться сервер Клиентская часть Далее представлен алгоритм работы клиентской части.Загружаем информацию о картинках и о разрешениях, в которые их нужно преобразовать Загружаем в теге img исходную SVG и вешаемся на событие load После загрузки, рисуем эту картинку на элементе Вытаскиваем картинку из  в текстовом формате с помощью вызова функции toDataURL ('image/png') Отправляем на сервер текст картинки и, если у нас есть еще что преобразовать, возвращаемся к пункту 2 или 3, в зависимости о того нужно ли загрузить другую картинку, иначе закрываем страницу (function () { var DRAWABLE_RES_TYPES = [ 'ldpi', 'mdpi', 'hdpi', 'xhdpi', 'xxhdpi' ] , SVG_IMAGE_NAME_REGEXP = /[.*]*\/([^\/]+)\.svg$/i;

var canvas = document.querySelector ('canvas') , context = canvas.getContext ('2d') , image = document.getElementById ('origin_image');

sendMsg ('get_image_list', {}, function (imageInfo) { imageInfo.forEachAsync (function (group, callback) { group.imageList.forEachAsync (function (imagePath, callback) { var imageName = imagePath.match (SVG_IMAGE_NAME_REGEXP)[1];

image.setAttribute ('src', imagePath); image.addEventListener ('load', function () { image.removeEventListener ('load', arguments.callee);

DRAWABLE_RES_TYPES.forEachAsync (function (drawableType, callback) { if (!(drawableType in group.sizes)) return callback ();

canvas.width = group.sizes[drawableType].width; canvas.height = group.sizes[drawableType].height; context.drawImage (image, 0, 0, canvas.width, canvas.height);

sendMsg ('save_image', { name: imageName, type: drawableType, body: canvas.toDataURL ('image/png') }, callback); }, callback); }); }, callback); }, function () { sendMsg ('all_is_done', {}, function () { window.close (); }); }); }); })(); Вспомогательные функции function sendMsg (action, data, callback) { var xhr = new XMLHttpRequest ();

xhr.open ('POST', 'http://127.0.0.1:1337/' + action, true); xhr.addEventListener ('readystatechange', function () { if (xhr.readyState === xhr.DONE) { if (xhr.status === 200) { try { var parsedAnswer = JSON.parse (xhr.responseText); } catch (e) { console.log (e); } callback (parsedAnswer); } else console.log ('Error with code ' + xhr.status + ': ' + xhr.statusText); } }); xhr.send (JSON.stringify (data)); }

Array.prototype.forEachAsync = function (handler, callback) { var self = this , index = -1 , tempCallback = function () { index++;

if (self.length === index) callback && callback (); else handler (self[index], tempCallback); };

tempCallback (); } Серверная часть Тут всё понятно, обычный сервер на Node.js, который отвечает на запросы клиента и сохраняет картинки, пришедшие с клиента. Внимания, на мой взгляд заслуживает только функция сохранения картинки, остальное можно будет посмотреть на GitHub, ссылка на репозиторий будет размещена ниже. Итак функция сохранения выглядит следующим образом: function saveImage (options, callback) { var regex = /^data:.+\/(.+); base64,(.*)$/ , matches = options.body.match (regex) , imageExt = matches[1] , imageBody = new Buffer (matches[2], 'base64') , imagePath = config.outputFolder + '\\drawable-' + options.type + '\\' + options.name + '.' + imageExt;

if (! fs.existsSync (config.outputFolder + '\\drawable-' + options.type)) fs.mkdirSync (config.outputFolder + '\\drawable-' + options.type);

fs.writeFile (imagePath, imageBody, function (err) { if (err) throw err;

var msg = 'File ' + imagePath + ' is created.';

console.log (msg); callback (err, { msg: msg }); }); } Тут всё достаточно просто, в параметре options приходят параметры с клиента, содержащие текст картинки, название и тип ресурсов для Android. Данные обрабатываются и записываются в файл. На серверной стороне используются модуль fs, http и один сторонний под названием open, который предоставляет функцию для открытия ссылки в дефолтном браузере.

config.json В данном файле хранится основная информация. Информация о сервере с полями port и hostname. Путь к папке с ресурсами приложения, для которого нужно генерировать картинки. И конечно же информация о SVG, их путь и размеры для разных разрешений. Для примера приведен всего один объект, в который помещен список файлов, информация о разрешениях и описание, которое нигде не используется, а служит просто для удобства. Если для других картинок нужно своё разрешение, мы просто создаем новый объект во входных данных. Пример: { «server»: { «port»: 1337, «hostname»:»127.0.0.1» }, «input»: [{ «description»: «Action bar icons», «imageList»: [ »/svg/ic_bar_add.svg», »/svg/other_picture.scg» ], «sizes»: { «ldpi»: { «width»: 24, «height»: 24 }, «mdpi»: { «width»: 32, «height»: 32 }, «hdpi»: { «width»: 48, «height»: 48 }, «xhdpi»: { «width»: 64, «height»: 64 }, «xxhdpi»: { «width»: 96, «height»: 96 } } }], «outputFolder»: «C:\\svg-android\\out» } Заключение Проект можно скачать с GitHub по данной ссылке.Для запуска ввести в консоли следующую строку: node index.js

Не забываем указать папку, в которую нужно сохранить картинки, она должна существовать.

© Habrahabr.ru