JavaScript diagram editor that renders diagrams from PNG images (open source)
Tags: javascript, webdev, programming, ux
Published: 2022-03-31 17:53:50


![Fig 1. dgrm.net can open diagrams from PNG images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrby3hhigxy5qwhw3zuj.gif)
_Fig 1. dgrm.net can open diagrams from PNG images_
  
[dgrm.net](https://dgrm.net/) | [GitHub](https://github.com/AlexeyBoiko/DgrmJS)

[<< Previous article](https://dev.to/alexboyko/javascript-svg-diagram-editor-39-kb-open-source-library-2eh)

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](https://www.w3.org/TR/PNG/)”.

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/045bsawxgmcvhdtiznxr.PNG)
_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).

```js
/**
 * @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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)

To read the data, you can wrap it in a [DataView](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://github.com/AlexeyBoiko/DgrmJS/blob/main/src/diagram-extensions/infrastructure/png-chunk-utils.js).

## 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](https://github.com/AlexeyBoiko/DgrmJS/blob/main/src/diagram-extensions/infrastructure/png-chunk-utils.js)

Usage example:

```js
// 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_

## Other articles about dgrm.net
 - [JavaScript SVG diagram editor 3.9 KB (open source library)](https://dev.to/alexboyko/javascript-svg-diagram-editor-39-kb-open-source-library-2eh)
 - JavaScript diagram editor that renders diagrams from PNG images (open source)
 - [JavaScript text editor for SVG](https://dev.to/alexboyko/javascript-text-editor-for-svg-13aa)
 - [Flowchart editor UI](https://dev.to/alexboyko/flowchart-editor-ui-58a1)
 - [JavaScript: Zoom like in maps for SVG/HTML](https://dev.to/alexboyko/javascript-zoom-like-in-maps-for-svghtml-2m3b)

## How to support the project

- Start using, tell us what you think.
  Any way: comments, private messages, on [GitHub](https://github.com/AlexeyBoiko/DgrmJS).  
  I read everything, I keep a list of proposals.
- Tell your friends.
- Give a start on [GitHub](https://github.com/AlexeyBoiko/DgrmJS).