2
votes

I am currently trying to write a program to encode text into a png file only changing the least significant bit for each letter i want to encode in the picture, example I have a 'A' which is 65 and I use 8 different bytes to encode the letter A. So 01010100<- 10101101<- 11011010<- 10101010<- each of these I change the last bit and the put 10110110<- 01010100<- 01010100<- 01010101<- them together so 65 is 01000001 each number by the arrow is changed according to the 65.

If I should approach this a different way suggestions would be awesome :). This is just a fun little project I wanted to do. But anyways back to my question.

When I read in a image that is only 4 pixels big I get like 680 bytes which is crazy, or at least I think it is, maybe im wrong? 4 pixels with ARGB at 8 bits each should be 16 bytes with a few bytes im sure to tell the operating system that it is a png and how to handle it. So i was expecting maybe like 30 bytes. Maybe less. Am I looking at this the wrong way? When png images are compressed do they become bigger if it is a small picture? And also, when I was saving it back to the Hard drive I always got a larger file. The original picture was 8,554 kb and then it turned into like 16kb when I saved it back. Here is the code for getting the image bytes and for saving the image. Maybe I am doing something wrong or I am just not understanding it correctly.

These are the ways I get the image (I tried 2 different things)

// BufferedImage img = ImageIO.read(new File("image.png"));
BufferedImage img= robot.createScreenCapture(new Rectangle(1,2,2,2));

how I saved two different ways again.

try {
InputStream in = new ByteArrayInputStream(imgBytes);
BufferedImage bImageFromConvert = ImageIO.read(in);
ImageIO.write(bImageFromConvert, "png", new File( "image.png"));

//FileOutputStream fos = new FileOutputStream("image.png");
//fos.write(b);
//fos.close();
}catch(Exception e){}

How I got the bytes from the Image, again I tried two different ways, the second way that is commented out actually did give me the 16 bytes like I want but when I saved it the Windows couldnt Open it because it didnt know what it was i guess? Not sure, just said file not supported.

byte[] imageBytes = null;
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", baos );
baos.flush();
imageBytes = baos.toByteArray();
baos.close();
}catch(IOException e){System.out.println(e.getMessage());}

// imageBytes = ((DataBufferByte) image.getData().getDataBuffer()).getData();
return imageBytes;

Thanks!

2

2 Answers

1
votes

A png consists of a lot of image meta data as well as the raw image data. That is what is giving you crazy 680 bytes.

0
votes

I had pretty much the same problem with my barcode fonts. I just wanted to encode 5 bits of data into the smallest PNG I could get. What I didn't want to do is write a custom program, based on libpng. I tried quite a few editors and the smallest file size I could get was around 170 bytes.

Finally I found Gimp 2.0. There is a feature you can use to export a PNG file without all the metadata. I also changed to 8 bit grayscale. I think I could shave a couple of bytes off by switching to 2 bit grayscale, but Gimp wouldn't do that for me. In the end, I was happy with ~75 bytes per character.