HunterP HunterP - 7 months ago 52
Java Question

Byte array to an 8 bit truecolor image

I'm attempting to rip some sprites from an old PC game. I've found the sprites and have ripped them to individual files, in grayscale. Now I'm trying to work out how to color them. There does not appear to be any palette data in the executable, or its data files - this, coupled with the color depth the game required (256 colors) leads me to believe that each byte is actually an 8 bit truecolor value.

Say that I have a (shortened in this case) array that looks as such:

12 11 12 11
0A 13 12 11
13 12 11 0A
12 11 13 13


Some example code similar to what I'm using to write the image looks like so:

DataInputStream dis = new DataInputStream(new FileInputStream("GAME.EXE"));

dis.skipBytes(bytesToImage);

BufferedImage bufferedImage = new BufferedImage(columns, rows, BufferedImage.TYPE_BYTE_INDEXED);

for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
byte pixel = dis.readByte();

System.out.print(toHexString(pixel));

//For now, greyscale everything.
int value = pixel << 16 | pixel << 8 | pixel;

bufferedImage.setRGB(j, i, value);
}

System.out.print(System.getProperty("line.separator"));
}

ImageIO.write(bufferedImage, "PNG", new File("test.png"));


I've messed around with both the imageType passed in to the constructor and passing in a ColorModel manually, but neither seem to do anything useful. Doing a binary AND on the pixel and some bit shifting mostly just sets the image to a deep red color.

How would I go about setting each pixel to the correct truecolor value in this case?

Answer

8-bit true color means that bits 7 to 5 contains red, bits 4 to 2 contain green, and bits 1 and 0 contain blue. (ie. RRRGGGBB) You need to shift these to the high-order bits in a 24 bit true color model.

Use a color model with 24 bits for RGB color like TYPE_INT_RGB or TYPE_INT_ARGB and derive your 24 bit pixel value from the 8 bit value:

int pixel24 = 
    ((pixel & (128+64+32)) << (16+5-5)) |
    ((pixel & (16+8+4))    << (8+5-2))  |
    ((pixel & (2+1))       << 6);

In other words:

int pixel24 = 
    ((pixel & 224) << 16) | ((pixel & 28) << 11) | ((pixel & 3) << 6);

Or

int pixel24 = 
    ((pixel & 0xE0) << 16) | ((pixel & 0x1C) << 11) | ((pixel & 0x03) << 6);
Comments