24
5
You are a secret agent trying to communicate with your fatherland. Of course the information needs to be hidden so no one eaves drops your message. What would be better suited than a cat? Everyone loves funny pictures of cats [citation needed], so they won't suspect secret information hiding in there!
Inspired by the algorithm the game Monaco uses to save the level information of shared levels it is your tasks to write a program that encoded information into the least significant bit of the colors of an image.
Encoding format:
- The first 24 bits determine the length of the remaining encoded byte-string in bits
- The image is read from left to right and from top to bottom, obviously starting in the upper left pixel
- The channels are read from red to green to blue
- The least significant bit from each channel is read
- Bits are saved in Big Endian order
Rules:
- Your program takes a single byte-string to be encoded and a single image filename for the base image
- The resulting image must be come out as a true color PNG file
- You may use I/O in whatever form you like (ARGV, STDIN, STDOUT, writing / reading from a file), as long as you state how to use your program
- You must choose a random image of a funny cat and encode your program into it to show that your program works
- You may assume that you are only provided valid input, if the amount of bits are not sufficient, the image is not in true color format, the image does not exist or similar problems you may do what you want
- You may assume that the provided image does not contain any alpha channel
- Length is counted in UTF-8 bytes without BOM
You may use this PHP script to test your solution, provide the name of the PNG file as the first command line argument:
<?php
if ($argc === 1) die('Provide the filename of the PNG to read from');
$imageSize = @getimagesize($argv[1]);
if ($imageSize === false) die('Not a PNG file');
list($width, $height) = $imageSize;
$image = imagecreatefrompng($argv[1]);
$read = 0;
$bits = '';
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
$colorAt = imagecolorat($image, $x, $y);
$red = ($colorAt >> 16) & 0xFF;
$green = ($colorAt >> 8) & 0xFF;
$blue = ($colorAt >> 0) & 0xFF;
$bits .= ($red & 1).($green & 1).($blue & 1);
$read += 3;
if ($read == 24) {
$length = (int) bindec($bits);
$bits = '';
}
else if ($read > 24 && ($read - 24) > $length) {
$bits = substr($bits, 0, $length);
break 2;
}
}
}
if (strlen($bits) !== $length) die('Not enough bits read to fulfill the length');
$parts = str_split($bits, 8);
foreach ($parts as $part) {
echo chr(bindec($part));
}
@TimWolla Would it be valid to get the cat to swallow a memory stick then take a picture of it? – Sonic Atom – 2016-01-07T12:19:24.107
@SonicAtom Can you get the information back, afterwards? – TimWolla – 2016-01-07T15:56:29.150
1@TimWolla From the cat? Keep it indoors and monitor the litter tray. From the photo? If you take a high enough resolution X-ray photo you may be able to see the state of the individual transistors in the flash chip. I'm certain this must be the most efficient method of passing secret information ever devised, although the cat may have other ideas. – Sonic Atom – 2016-01-07T18:18:13.847
Your specification says "your program takes a single image as a base". In Mathematica an image is actually just an expression like everything else, so technically this specification would allow me to do the file-loading outside of the code that performs the computation (with the input parameter being an actual image instead of the image's file name). If you don't want stuff like that, you might want to specify that the program needs to take an image's file name as input. – Martin Ender – 2014-04-07T20:42:04.313
4ME helpimtrappedinacatfactory OW – TheDoctor – 2014-04-07T20:43:48.680
Also, do the bits not used for encoding need to remain untouched? Or can we set them to whatever we want (since that won't really affect image quality and doesn't matter for decoding)? – Martin Ender – 2014-04-07T20:47:55.517
@m.buettner Do whatever you want with the unused bits. About the Mathematica issue: Thanks, I'll see what I do. – TimWolla – 2014-04-07T20:57:41.373
@TimWolla cheers. Another question: you only said we may assume the input image is true colour. May we also assume it has an alpha channel? – Martin Ender – 2014-04-07T21:12:24.440
@m.buettner I don't see how this helps, would you explain it? – TimWolla – 2014-04-07T21:24:20.933
@TimWolla well if there is already an alpha channel I have to skip it during encoding (assuming we're only encoding in the RGB channels as in the article you linked). If there is no alpha channel, I don't have to skip any channels. That does make a difference in my implementation. It also kind of matters for the output. Does the output need to preserve alpha channel? Is it allowed to introduce a alpha channel filled with all
255
if there was no alpha channel in the input? And so on... Of course it would be easiest if we could assume that there is never any alpha present. – Martin Ender – 2014-04-07T21:30:11.797@m.buettner I see. I just added „- You may assume that the provided image does not contain any alpha channel“ – TimWolla – 2014-04-07T21:32:38.167
To be explicit, you're expecting us to write an encoder and not a decoder? And what's the endianness of the conversion between bitstream and bytes? – Peter Taylor – 2014-04-07T21:32:59.010
@PeterTaylor An encoder, yes. My decoder assumes Big Endian. – TimWolla – 2014-04-07T21:34:00.067
1Can I use a non-built-in library to load and save the png file, eg PIL in Python? – Claudiu – 2014-04-07T23:45:09.997
@Claudiu Yes, you don't have to build PNG writing by hand. (I am using GD library in PHP myself) – TimWolla – 2014-04-08T09:24:51.543