
<< предыдущая статья | следующая статья >>
dgrm.net - это редактор диаграмм, с прицелом на трансформацию в карту знаний.
Отличительные особенности:
аскетичность,
работает на телефонах (одно из немногих web-решений),
открытый исходный код.
В процессе разработки появляются интересные моменты. Статья про один из таких моментов: чтение данных из PNG. Исходный код для использования в своих проектах прилагается.
Зачем открывать диаграммы из PNG изображений
Пользовательские интерфейсы сделанные разработчиками славятся своей самобытностью. Возможно, идея использовать изображения в качестве файлов проекта как раз этот случай. Как минимум подход оригинальный.
Все редакторы используют свои файлы проекта. Но это же неудобно:
нет превьюшек,
при пересылке изображения, надо еще и исходник пересылать.
Удобнее иметь картинку диаграммы, которую при необходимости можно отредактировать.
Глядя на рисунок 1 можно предположить что используется стеганография, или распознавание изображений. На самом деле гораздо проще, и без хаков - формат PNG поддерживает хранение дополнительной информации, например метки времени, имени автора, или любой другой.
dgrm.net записывает в png-файлы JSON с данными диаграммы.
PNG Chunks
Формат PNG хорошо описан на Хабре в статье “PNG — not GIF!”.
Основной момент:
png-файлы состоят из блоков, которые называются chunk-и,
в файл можно добавлять свои chunk-и.
Для своих данных имя chunk-a (например “dgRm”):
Можно придумать любое, лишь бы оно не было зарезервировано;
Длина имени строго 4 латинских буквы;
Регистр букв имеет значение. Для самодельных chunk-ов ставьте все буквы в нижнем регистре, а 3-ю в верхнем.
Таким образом, для хранения строки JSON внутри файла PNG нужно добавить в файл свой chunk.
Чтение/запись PNG chunk-ов на JavaScript в браузере
Чтение chunk-а
Chunk-и следуют друг за другом, нужный chunk находится перебором.
Алгоритм поиска chunk-а (листинг 1):
берем название ��ервого chunk;
если название не совпадает с искомым:
a. берем длину chunk (первые 4 байта см. рис 2);
b. зная длину chunk смещаем курсор на начало следующего chunk.повторяем 1 и 2 пока не найдем нужный chunk или 'IEND' (конец файла).
/** * @param {ArrayBuffer} pngData * @param {number} chunkNameUint32 chunk name as Uint32 * @returns {DataView | null} chunk data */ function chunkGet(pngData, chunkNameUint32) { const dataView = new DataView(pngData, 8); // 8 byte - png signature let chunkPosition = 0; let chunkUint = dataView.getUint32(4); let chunkLenght; while (chunkUint !== 1229278788) { // last chunk 'IEND' chunkLenght = dataView.getUint32(chunkPosition); if (chunkUint === chunkNameUint32) { return new DataView(pngData, chunkPosition + 16, chunkLenght); } chunkPosition = chunkPosition + 12 + chunkLenght; chunkUint = dataView.getUint32(chunkPosition + 4); } return null; }
Листинг 1. Функция поиска chunk-а
Краткая справка:
В JavaScript интересный способ работы с бинарными данными.
Цитата:
Объект ArrayBuffer используется для работы с бинарными данными. Он представляет собой ссылку на поток "сырых" двоичных данных, однако работать с ними напрямую возможности не даёт.
developer.mozilla.orgДля чтения данных можно обернуть их в DataView. DataView позволяет прочитать данные в любой позиции в виде числа (с помощью методов getInt8(), getUint32() и др.).
Запись chunk-а
Для записи chunk-а, нужно вставить новый chunk в цепочку. Если chunk с данным именем уже есть - его нужно заменить.
Реализацию можно посмотреть на GitHub - функция chunkSet.
Исходный код
Функции работы с PNG chunk-ами вынесены в один файл. У файла нет зависимостей, поэтому его можно просто скопировать в свой проект.
png-chunk-utils.js
Пример использования:
// Запись chunk-а, на выходе новый blob const newPngBlob = await pngChunkSet( // png-изображение pngBlob, // имя chunk-а 'dgRm', // значение chunk-а: строка в виде массива byte new TextEncoder().encode('...')); // чтение chuk-а const dgrmChunkVal = await pngChunkGet(newPngBlob, 'dgRm'); const str = new TextDecoder().decode(dgrmChunkVal);
Листинг 2. Вызов функций записи и чтения PNG chunk-ов
Другие статьи про dgrm.net
JavaScript редактор диаграмм, который открывает диаграммы из PNG картинок (open source)
