Meefik's Blog

Freedom and Open Source

Encoding and decoding data in PNG with compression

22 Feb 2020 | javascript

I want to talk about a couple of interesting ways to encode data - encoding in the form of a picture and embedding them into an existing picture. I experimented with the PNG format because it uses lossless compression and is supported in browsers in the canvas element. I am interested in JavaScript, so the implementation will be written in it. The code is implemented as a JS library and posted on GitHub under the MIT license.

The first encoding option is to generate a new picture based on arbitrary data. To do this, each byte of data is recorded sequentially in the RGB channels of the PNG picture, while the alpha channel is not touched, since when the alpha channel changes, the RGB colors partially change when unloading from canvas to PNG. In this variant, WIDTH * HEIGHT * 3 bytes of data can be packed in PNG. When encoding text, the image size is smaller than the source text, since Deflate compression is applied to the data.

// encode file to PNG
asPNG.encode(file).then(blob => {
  // encoded blob
});
// decode file from PNG
asPNG.decode(file).then(blob => {
  // decoded blob
});

aspng_encoded

The second encoding option is even more interesting and belongs to the area of steganography. The essence of the approach is that the encoded data is hidden among the original image data in such a way that the visually obtained image is almost indistinguishable from the original. The algorithm of my implementation is as follows:

In this variant, up to WIDTH * HEIGHT bytes of data can be packed in PNG.

// inject data to PNG image
asPNG.inject(data, img).then(blob => {
  // modified image
});
// extract data from PNG image
asPNG.extract(img).then(blob => {
  // extracted data
});

aspng_injected

Comments