samwell
samwell

Reputation: 2797

Converting base64 image to an actual image with using only libraries java comes with

I'm creating an easter egg for an java swing application, it's will be used primarily internally.

I was planning on taking an image and converting it into base64, then when the easter egg is found, it'll convert the base64 image to an actual image, then finally have it show up in a JFrame or a dialog box. I know it's not that great, but I really don't have much time to do something, plus it was all that came up in my head.

I looked online for anything that does this, and I've found many tutorials showing Base64 decoding to an image, but they all involve external libraries. Is there a way to decode a base64 image to an actual image with using the libraries java comes with?

----------------------- EDIT -----------------------------

Using @IanRoberts comment: "There is a (rather well hidden) base64 encoder/decoder in the parse/printBase64Binary methods of javax.xml.bind.DatatypeConverter."

I was able to decode the image. Here is a pastebin of what I did.

Upvotes: 2

Views: 1688

Answers (2)

dinox0r
dinox0r

Reputation: 16039

A rather complex solution to hide an image in a java class, without including the file itself or using base64 (thus reducing the class java file size), is to use the following java program tool to convert an image to a collection of java byte arrays and method invocations that will assemble the original image:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

public class ImageDataGenerator {
    public static void main(String[] params) throws InterruptedException, FileNotFoundException, IOException {
        if (params.length != 2) {
            System.out.printf("Uso: java ImageDataGenerator <nombre_imagen> <archivo_imagen>\n");
            System.exit(1);
        }

        String imageName = params[0];

        FileInputStream fis = new FileInputStream(params[1]);
        PrintWriter p = new PrintWriter("imgData.txt");

        p.printf("   private byte[] get%sPart1() {\n", imageName);
        p.printf("       return new byte[] {");

        int readed = 0;
        int writed = 0;
        int numMethods = 1;
        while ((readed = fis.read()) != -1) {
            if (writed < 3000) {
                p.printf("%d,", (byte) readed);
            } else {
                writed = 0;
                p.printf("%d};\n", (byte) readed);
                p.printf("   }\n");
                numMethods++;
                p.printf("   private byte[] get%sPart%d() {\n", imageName, numMethods);
                p.printf("       return new byte[] {\n ");
            }

            if ((++writed % 500) == 0) {
                p.printf("\n");
            }
        }
        p.printf("};\n");
        p.printf("   }\n\n");

        p.println("    private BufferedImage createImageFromArrays(byte[]... arrays) throws IOException { ");
        p.println("        int size = 0;");
        p.println("        for (byte[] array : arrays) size = array.length;");
        p.println("        byte[] imageInByte = new byte[size];");
        p.println("        int pos = 0;");
        p.println("        for (byte[] array : arrays) {");
        p.println("            System.arraycopy(array, 0, imageInByte, pos, array.length);");
        p.println("            pos += array.length;");
        p.println("        }");
        p.println("        ");
        p.println("        InputStream in = new ByteArrayInputStream(imageInByte);");
        p.println("        return ImageIO.read(in);");
        p.println("    }");
        p.println("\n");

        p.println("// Insert this call anywhere in your code");
        p.printf("createImageFromArrays(");
        for (int i = 1; i <= numMethods; i++)
            p.printf("get%sPart%d()%s ", imageName, i, i <= numMethods - 1 ? "," : "");
        p.printf(");");

        p.flush();
        p.close();
    }
}

Use the tool typing: java ImageDataGenerator hiddenImage /path/to/image/image.png

It will generate a file named imgData.txt which content you must copy/paste inside your JFrame class declaration section. The last line of the generated file will contain a call to a method named createImageFromArrays which you must invoke in your JFrame onShow/onLoad event listener

(I used this tool before to hide images/resources in J2ME applications, hope it helps)

Upvotes: 0

Ian Roberts
Ian Roberts

Reputation: 122364

This solution uses only Java 6 core java. and javax. classes:

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;

String base64String = "...";
byte[] bytes = DatatypeConverter.parseBase64Binary(base64String);
ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
BufferedImage img = ImageIO.read(bin);
// NB ImageIO doesn't close the provided input stream, but ByteArrayInputStream
// doesn't need to be closed anyway so it doesn't matter.

Upvotes: 3

Related Questions