Answers
- "Three may keep a secret, if two of them are dead." (Benjamin Franklin)
- A key (and maybe the kite can also be viewed as on the line).
Code (Java)
The code is pretty much self-explanatory. Images are converted to a bit array from the channel last bits which is then used for the decoding. The helper function getAsInt() returns the bits in a range as int which is more or less all that's needed to decode the messages.
package so;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class App {
public static void main(String[] args) {
System.out.println(decode1(toChannelLastBits(readImage("<path>/MBlXyTSp.png"))));
showImage(decode2(toChannelLastBits(readImage("<path>/mCeETXDs.png"))));
}
private static BufferedImage readImage(String path) {
try {
return ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static int[] toChannelLastBits(BufferedImage img) {
int[] bits = new int[img.getWidth() * img.getHeight() * 3];
int pos = 0;
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = img.getRGB(x, y);
bits[pos++] = (pixel >> 16) & 1; // red
bits[pos++] = (pixel >> 8) & 1; // green
bits[pos++] = (pixel & 1); // blue
}
}
return bits;
}
private static String decode1(int[] bits) {
int len = getAsInt(bits, 2, 18) >> 3;
char[] message = new char[len];
for (int i = 0; i < len; i++)
message[i] = (char) getAsInt(bits, 18 + (i << 3), 26 + (i << 3));
return new String(message);
}
private static BufferedImage decode2(int[] bits) {
int w = getAsInt(bits, 2, 18);
int h = getAsInt(bits, 18, 34);
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for (int y = 0, i = 34; y < h; y++)
for (int x = 0; x < w; x++)
img.setRGB(x, y, bits[i++] * 0xFFFFFF);
return img;
}
private static int getAsInt(int[] bits, int from, int to) {
int r = 0;
for (int i = from; i < to; i++)
r = (r << 1) | bits[i];
return r;
}
public static void showImage(BufferedImage img) {
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JFrame frame = new JFrame("Image Display");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}