Embed text into PNG
Asked Answered
T

8

6

I'm looking for a tool that'd let me embed json-formatted information inside a PNG -file.

This far it's been quite quiet. Do I have to write it myself?

I'd be especially interested of doing it with javascript. Into an image I extract from a canvas with toDataURL -method.

Teddie answered 26/7, 2010 at 13:29 Comment(7)
You want to draw text on top of the image, or do some steganography?Irisirisa
Could you throw something over the image instead? (2 seconds after ^)Priapism
I was just going to ask that after I put up my answer...steganography or overlay?Haldi
Oh. I didn't explain it clearly enough after all. What I look for is to get some JSON-encoded data embedded into the image so I don't need to supply it separately into my javascript-game.Teddie
So you basically want to hide information in an image?Haldi
Yes. Though it's not hiding, more like embedding.Teddie
Regardless of the semantics of what you want to do, you want to embed information inside an image that is not shown to the user. That's called 'steganography' if you want to learn more.Haldi
I
6

If you want to embed text you may want to look at this in particular, which comes from the PNG specification. It seems a little on the complicated side.

The "easy" steganographic method looks a little more simple.

What may actually be better suited for your purpose is to create a javascript object that contains the image data and the JSON data - then just pass that object around wherever you need it.

Irisirisa answered 26/7, 2010 at 15:6 Comment(0)
H
2

I am completely unfamiliar with Python, however if you can access any of the prominent image processing libraries it is possible.

Take a look here for ImageMagick<->Python solutions.


Edit

You may wish to take a look at this blog post for information regarding steganography (hiding information within an image) and an offshoot of the ImageMagick library. It uses C++ here but I'm sure you could figure out a way to incorporate the base processes in Python.

Haldi answered 26/7, 2010 at 13:35 Comment(0)
I
2

Copying another answer of mine in another question:

Here's an old not too-fancy module I did for a friend once (Python 2.x code):

the code

from __future__ import division

import math, os, array, random
import itertools as it
import Image as I
import sys

def encode(txtfn, imgfn):
    with open(txtfn, "rb") as ifp:
        txtdata= ifp.read()
    txtdata= txtdata.encode('zip')

    img= I.open(imgfn).convert("RGB")
    pixelcount= img.size[0]*img.size[1]
##  sys.stderr.write("image %dx%d\n" % img.size)

    factor= len(txtdata) / pixelcount
    width= int(math.ceil(img.size[0]*factor**.5))
    height= int(math.ceil(img.size[1]*factor**.5))

    pixelcount= width * height
    if pixelcount < len(txtdata): # just a sanity check
        sys.stderr.write("phase 2, %d bytes in %d pixels?\n" % (len(txtdata), pixelcount))
        sys.exit(1)
##  sys.stderr.write("%d bytes in %d pixels (%dx%d)\n" % (len(txtdata), pixelcount, width, height))
    img= img.resize( (width, height), I.ANTIALIAS)

    txtarr= array.array('B')
    txtarr.fromstring(txtdata)
    txtarr.extend(random.randrange(256) for x in xrange(len(txtdata) - pixelcount))

    newimg= img.copy()
    newimg.putdata([
        (
            r & 0xf8 |(c & 0xe0)>>5,
            g & 0xfc |(c & 0x18)>>3,
            b & 0xf8 |(c & 0x07),
        )
        for (r, g, b), c in it.izip(img.getdata(), txtarr)])
    newimg.save(os.path.splitext(imgfn)[0]+'.png', optimize=1, compression=9)

def decode(imgfn, txtfn):
    img= I.open(imgfn)
    with open(txtfn, 'wb') as ofp:
        arrdata= array.array('B',
            ((r & 0x7) << 5 | (g & 0x3) << 3 | (b & 0x7)
            for r, g, b in img.getdata())).tostring()
        findata= arrdata.decode('zip')
        ofp.write(findata)

if __name__ == "__main__":
    if sys.argv[1] == 'e':
        encode(sys.argv[2], sys.argv[3])
    elif sys.argv[1] == 'd':
        decode(sys.argv[2], sys.argv[3])

the algorithm

It stores a byte of data per image pixel using: the 3 least-significant bits of the blue band, the 2 LSB of the green one and the 3 LSB of the red one.

encode function: An input text file is compressed by zlib, and the input image is resized (keeping proportions) to ensure that there are at least as many pixels as compressed bytes. A PNG image with the same name as the input image (so don't use a ".png" filename as input if you leave the code as-is :) is saved containing the steganographic data.

decode function: The previously stored zlib-compressed data are extracted from the input image, and saved uncompressed under the provided filename.

I verified the old code still runs, so here's an example image containing steganographic data:

contains steganographic data

You'll notice that the noise added is barely visible.

Intersex answered 31/10, 2010 at 16:25 Comment(0)
C
2

The answers here have seriously over-engineered the question. I am sorry you had to wait 11 years for the answer. The ability to do this is standard and part of the PNG spec. Tons of apps use this today.

You can drop JSON or any other data right into PNGs. You can do this in like 3 lines of JavaScript with the npm "png-chunk-text" (https://www.npmjs.com/package/png-chunk-text)

Now you can read and write JSON inside of PNGs at lightning speed and it took you 30 seconds to develop it, and the process is standard, i.e., other tools can read it too.

Cadet answered 18/8, 2021 at 17:55 Comment(0)
G
1

Hmm, here’s a partial libpng implementation in JS: http://www.xarg.org/download/pnglib.js.

Gump answered 26/7, 2010 at 13:38 Comment(0)
T
1

You can use the recently released JavaScript library steganography.js. Have a look at the showcase and the documentation for the basic usage.
The library makes use of a HTML canvas and embeds the information in the alpha channel of the image. Basically you just need to use steg.encode(message, image) and pass the JSON-data (as string) as message and the image as dataURL. To read this information from the image use steg.decode(image) and pass the image as dataURL again.

After reading the information again you get the JSON-data as string so you will have to parse it to a JavaScript object again. So besides the parsing from/to string I hope it fits your requirements.

Tremblay answered 23/9, 2013 at 17:1 Comment(0)
O
0

Someone has already attempted to embed a Mario-like platformer game in a PNG image. Using getImageData is the key to reading out the data; the object that that method returns gives a one-dimensional array holding the individual RGBA values of each pixel.

Note that this does not "hide" the data within the area that the user sees, but you could probably use a CSS sprite like technique (or "crop" the image using multiple canvases) to show only the part of a combined image you want to.

Oligochaete answered 31/10, 2010 at 16:32 Comment(0)
C
0

Why not just use this tool?

http://www.jsclasses.org/package/324-JavaScript-Embed-encoded-text-in-images-using-steganography.html

and here on github:

https://github.com/blauharley/LoremImageCryptonator

It's a normal object that can be used for embedding text into each color-channel(red, green...).

When embedding text into the alpha-channel there should not be as much noise as embedding text on other color-channels, so you should not see any difference before and after inserting text into an image.

Commiserate answered 24/5, 2014 at 15:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.