CodeX
Published in

CodeX

JavaScript diagram editor that renders diagrams from PNG images (open source)

Fig 1. dgrm.net can open diagrams from PNG images

dgrm.net | GitHub

<< Previous article

dgrm.net — is a diagram editor, with an eye to transformation into a knowledge map tool.

Distinctive features:

  • asceticism,
  • works on phones,
  • open source.

In the development process, interesting moments appear. Today we will talk about reading data from PNG. The source code for use in your projects is attached.

Why open diagrams from PNG images?

Developer-made user interfaces are notorious for being weird. Perhaps the idea of using images as project files is just that. At least the approach is original.

All editors use their own project files. But this is inconvenient:

  • no previews,
  • when sending an image, you must also send the source.

It is more convenient to have a picture of the diagram, which can be edited if necessary.

Looking at Figure 1, we can assume that steganography, or image recognition, is being used. It’s actually much simpler, and without hacks — the PNG format supports storing additional information, such as a timestamp, author’s name, or any other.

dgrm.net writes JSON with diagram data to png files.

PNG Chunks

Here is the PNG specification: “Portable Network Graphics (PNG) Specification”.

Highlight:

  • png files are made up of blocks called chunks,
  • you can add your own chunks to the file.
Fig 2. Structure of one PNG chunk

For custom data you can think of any chunk name (for example “dgRm”):

  • The length of the name is strictly 4 Latin letters;
  • Letter case matters. For custom chunks, put all letters in lowercase, and the 3rd in uppercase.

Thus, to store a JSON string inside a PNG file, you need to add your own chunk to the file.

Read/Write PNG chunks in JavaScript in the browser

Read a chunk

Chunks follow each other, the required chunk is searched by enumeration.

Chunk search algorithm (listing 1):

  1. take the name of the first chunk
  2. if the name does not match the search one
    - take the length of the chunk (the first 4 bytes see Fig. 2)
    - knowing the length of the chunk, move the cursor to the beginning of the next chunk
  3. repeat 1 and 2 until we find the desired chunk or ‘IEND’ (end of file).
/**
* @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;
}

Listing 1. Chunk lookup function

Quick reference:
JavaScript has an interesting way of working with binary data.

Quote:
The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. …
You cannot directly manipulate the contents of an ArrayBuffer
developer.mozilla.org

To read the data, you can wrap it in a DataView. The DataView allows you to read the data in any position as a number (using the getInt8(), getUint32() methods, etc.).

Write a chunk

To write a chunk, you need to insert a new chunk into the chain. If a chunk with the given name already exists, it must be replaced.

See implementation on GitHub — the chunkSet function.

Source code

Functions for working with PNG chunks are located in one file. The file has no dependencies, so you can simply copy it into your project.

png-chunk-utils.js

Usage example:

// Write a chunk, new blob output
const newPngBlob = await pngChunkSet(
// png-image
pngBlob,
// chunk name
'dgRm',
// chunk value: string as a bytes
new TextEncoder().encode('...'));


// read a chuk
const dgrmChunkVal = await pngChunkGet(newPngBlob, 'dgRm');
const str = new TextDecoder().decode(dgrmChunkVal);

Listing 2. Calling functions to write and read PNG chunks

How to support the project

  • Start using, tell us what you think.
    Any way: comments, private messages, on GitHub.
    I read everything, I keep a list of proposals.
  • Tell your friends.
  • Put stars on GitHub.

--

--

--

Everything connected with Tech & Code. Follow to join our 900K+ monthly readers

Recommended from Medium

The be-all and end-all advice about Javascript (non) strict equals

Testing React Apps that use React Router

Better Git Commit Messages

14 Useful Extensions For VSCode For React And React Native Developers

Friday Frontend: Rough Week Edition

Friday Frontend: Beginning of the Roundups Edition

Solving HackerRank’s 2D Array with Javascript

JavaScript Integration with Docker.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexey Boyko

Alexey Boyko

https://boyko.tech/ , https://github.com/AlexeyBoiko , https://linkedin.com/in/alexey-boyko-tech

More from Medium

How to Implement Camera Access from Web Browsers in 5 Minutes

Introduction to Tonic — the component framework

Performance considerations when using and abusing functions in JavaScript/V8

Ternary Operators in Javascript​ : Short-hand Syntax