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 f开发者_StackOverflow中文版rom a canvas with toDataURL
-method.
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.
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.
Hmm, here’s a partial libpng implementation in JS: http://www.xarg.org/download/pnglib.js.
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:
You'll notice that the noise added is barely visible.
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.
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.
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.
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.
精彩评论