There are many techniques discussed on various threads on this forum to embed bitmaps. In my entries, I used 1-bit or 2-bit images and I packed those bits into long Unicode Strings. I never actually compared that technique to any of the others; so, I decided to run an experiment. Here’s the tile map used in the first world of Super Mario Land, one of the Game Boy launch titles from 1989 and also the basis of one of my 4K entries:
The png file is 6025 bytes. It’s composed of 8x8 pixels, 2-bit (4 colors) tiles. The colors are black, dark gray, light gray and white; however, one of those colors (usually white) is considered transparent for the sprites.
The experiment consists of programs that display the image. To begin, I created the following template:
import java.applet.Applet;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class a extends Applet implements Runnable {
@Override
public void start() {
new Thread(this).start();
}
public void run() {
BufferedImage image = new BufferedImage(128, 192, 1);
Graphics2D g = null;
while(true) {
if (g == null) {
g = (Graphics2D)getGraphics();
} else {
g.drawImage(image, 0, 0, 256, 384, null);
}
Thread.yield();
}
}
}
It creates an empty, all-black image of the same dimensions as the png and it displays the image scaled by a factor of 2. Compile 'n Shrink generates a 318 byte file from the template. I’ll use that size as an estimate of the overhead.
Next, here’s a program that generates a long Unicode String out of the image:
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class Converter1 {
public static final String sourcePath = "...";
public static void main(String... args) throws Throwable {
StringBuffer sb = new StringBuffer();
BufferedImage image = ImageIO.read(new File(sourcePath + "0.png"));
for(int y = 0; y < image.getHeight(); y++) {
for(int x = 0; x < image.getWidth(); x += 8) {
int value = 0;
for(int i = 0; i < 8; i++) {
value |= getColor(0xFF & image.getRGB(x + i, y)) << 16;
value >>= 2;
}
printValue(sb, value);
}
}
System.out.print(sb.toString());
}
private static int getColor(int pixel) {
switch(pixel) {
case 0x00:
return 0;
case 0x60:
return 1;
case 0xA8:
return 2;
default:
return 3;
}
}
private static void printValue(StringBuffer sb, int value) {
switch(value) {
case 0x0008:
sb.append("\\b");
break;
case 0x0009:
sb.append("\\t");
break;
case 0x000a:
sb.append("\\n");
break;
case 0x000c:
sb.append("\\f");
break;
case 0x000d:
sb.append("\\r");
break;
case 0x0022:
sb.append("\\\"");
break;
case 0x0027:
sb.append("\\'");
break;
case 0x005c:
sb.append("\\\\");
break;
default: {
String s = Integer.toHexString(value);
while(s.length() < 4) {
s = "0" + s;
}
sb.append("\\u").append(s);
break;
}
}
}
}
It processes the image one row at a time from left to right. It converts an 8 pixel segment of a row into a 16-bit Unicode character substituting each pixel with a 2-bit value. The getColor method returns 0, 1, 2 or 3 based on the color of the associated pixel. The printValue method typically generates values of the form \uXXXX, where the X’s are hexadecimal digits; however, 8 values need to be escaped before packing it into a String.
Here’s the modified template that reverses the encoding process and display the image:
import java.applet.Applet;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class a extends Applet implements Runnable {
@Override
public void start() {
new Thread(this).start();
}
public void run() {
final String S = "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u0fff\uffff\uffff\uffff\uffff\u03ff\uffc0\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u500f\uffff\uffff\uffff\uffff\u00ff\uff00\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\ua553\uffff\uffff\uffff\uffff\u00ff\uff20\uffff\uffff\uffff\uffff\u3fff\ufff0\u0fff\ufffc\ucfff\ufa94\uffff\ueaff\u0fff\ufffc\u003f\uffea\uffff\u0fff\u0fff\ufffc\u0fff\ufc00\u03ff\uff00\u28ff\uffa4\u0fff\ueafc\u003f\uffc0\u803f\uffa2\uffff\u03bf\u03ff\uff00\u03ff\uff8a\u80ff\uffe2\ubaff\uffe4\u03ff\uf000\ua2ff\uff00\u800f\uffea\uf03f\u88af\u80ff\uffe2\u20ff\ufea8\u083f\uffaa\ufe3f\uff94\u80ff\uf0e2\u8abf\ufe88\u800f\uffea\uc00f\ua02f\u083f\uffaa\ua0ff\ufe0a\ua83f\uff82\uf8ff\uff93\u083f\uf0aa\ua0ff\ufe8a\u000f\ufff2\u0003\u083f\ua83f\uff82\uafff\uffaa\uabff\uffea\ua83f\uff82\ua83f\ufc02\ua83f\uffd5\u500f\uffd9\u0000\ua8ff\uabff\uffea\u00ff\ufff1\u40ff\ufffc\uabff\uffea\uabff\uff2a\u003f\uff5a\ua40f\uffd5\u0003\u90ff\u10ff\ufff4\u00af\ufa81\u403f\ufff0\u00ff\ufeb1\u103f\uffc4\u003f\uff56\u6f3f\ufff5\uc00f\u15cf\u103f\uff04\u03af\ufa07\ue83f\uffdd\u00bf\ufea0\u500b\uf3d0\u40ff\uff40\ua7ff\uffd5\uf03f\u740f\u72bf\ufe0d\u55ff\ufcf5\u597f\uffd5\u55af\uffd5\ud5eb\uf075\u1fff\uffd0\u95ff\uffd6\uffff\u540f\u56bf\ufe95\u553f\ufc15\u55ff\ufff0\u553f\ufff5\u553b\uf055\u1fff\ufcc4\u957f\uff56\uffff\u57ff\uc3ff\uffc3\uf43f\ufc17\u03ff\uffc0\u350f\ufffc\u540f\ufff5\uffff\ufc01\u555f\uff55\uffff\uffff\uc0ff\uff03\uc0ff\uffff\u03ff\ufffc\u3fcf\ufff0\ud7cf\uffff\uffff\uff03\u5557\uff55\uffff\uffff\u03ff\ufff0\uffff\uffff\u03ff\ufff0\uffff\u3fa4\uffff\ueaff\u03ff\ufffc\uffff\uffff\uffff\uffff\u00ff\uff00\u0fff\uffc0\u00ff\uff00\uffff\u1e93\u03ff\ue8b0\u003f\ufe00\uffff\u03ff\u0fff\uffc0\ua0ff\uffe8\u03ff\ufc00\ua0ff\uffe8\uffff\uc54f\u00ff\uea00\u8aff\ufa82\uffff\ua8fc\u03ff\uff00\u823f\ufeaa\u83ff\uffa2\u823f\ufeaa\uffff\uf03f\ua0ff\uc028\uaabf\ufa58\uffff\ufe30\u00ff\uff20\uaa0f\ufea2\u08ff\ufaaa\uaa0f\ufea2\uffff\uffff\u823f\uc2aa\u82af\uffda\uffff\ufc03\u003f\uffea\uaa0f\uff00\ua83f\ufa8a\uaa0f\uff00\uf03f\uffff\uaa0f\uf2a2\ua0af\uff50\uffff\uc0c1\u803f\uffa2\ua8ff\uffea\ua83f\ufc02\ua8ff\uffea\uc54f\uffff\uaa0f\uf000\u2aff\ufd4a\uffff\u0e80\u800f\uffea\u04ff\ufff4\ua3ff\uffaa\u003f\ufff1\u1e53\uffff\ua0ff\ufc2a\u103f\ufd6a\uffff\uaa82\u800f\uffea\u043f\uffc4\u04ff\ufff5\u013f\ufff8\u00ff\ufa91\u400f\uff04\u003f\uff5a\u288c\u5555\u0003\ufff2\u040f\uff04\u053f\ufeb0\u017f\uffe8\u003f\ufa91\u420f\uff44\u403f\uffc1\u0448\uffff\u5c03\uffd9\u5c0f\ufc0d\u057f\ufa80\u557f\uffe9\u56af\ufcd7\u5a8f\ucf57\u54ff\ufc01\uf004\u00ff\u9fff\uffd5\u56af\ufea5\u550f\ufa80\u55ff\uffd5\u57af\ufc05\u52bf\uc155\u57ff\ufca0\u0000\u5400\u9fff\uffa6\u56bf\uffa5\u550f\uffd4\u15ff\uffd4\u543f\ufc05\u4143\uc155\u5fff\ucfa8\u08f0\u4000\u57ff\uffaa\ud57f\uff55\uf50f\uffd5\u13ff\ufff0\u543f\ufc0d\u0543\uc154\uffff\uc059\uaa3f\u0002\u55ff\uffd5\uf03f\uff03\uffcf\uff03\uc0ff\ufff3\ufc3f\uffff\ud543\uffff\uffff\uf007\u2a3f\u0ffc\u557f\uffd5\uf00f\ufc03\uffff\ufc03\u03ff\uffff\uf0ff\uffff\ufff3\uffff\uffff\ufc0f\uc03f\uffff\u555f\uff55\uffff\uffff\u823f\ufeaa\uffff\uffff\u04ff\uffc0\u03ff\ufff0\u9c03\ufbda\uffff\u3a25\u03ff\uc03f\uffff\uffff\uaa3f\ufea2\u03ff\ufff0\u15ff\ufff4\u00ff\uffc0\u570f\ufa95\uffc0\u1a23\u00ff\u3f3f\uffff\uffff\ua83f\uff00\u00ff\uff00\u557f\ufff5\u003f\uff02\u6bff\uffa5\uff28\u1628\u00ff\uea3f\uffff\uffff\ua90f\ufc2a\ua0ff\uffe8\u557f\uffd1\ua03f\uff2a\ua9ff\ufffa\ufcfc\u0515\ua03f\u0a3f\uffff\uffff\u0e0f\ufc8c\u823f\ufeaa\u5543\uffd4\u200f\uff22\u557f\ufff5\uf3fc\uc015\u203f\uf23f\u03ff\ufff0\u568f\ufe95\uaa0f\ufea2\ud543\uffd5\ua00f\uff2a\u555f\uffd5\uf0fc\uf000\ua00f\u50f0\u00ff\uff00\u503f\ufc05\uaa0f\uea00\uf5c3\uff03\ua003\uffe8\u5557\uffd5\ucc00\uff00\ua00f\b\ua0ff\uffe8\uf00f\uf00f\u28ff\ufa00\ufff3\ufc03\u0003\ufff2\u5555\uffd5\u3a2a\uffff\u000f\ua8cc\u900f\uffda\uc000\uc0c0\uc000\uc300\uf000\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u540f\uff55\ucaa8\uc8c8\ucaa8\uc828\uc2a8\ucfcf\uffcf\ucf3f\ucfcf\ucfcc\ucf03\ucfc3\uc0c3\uc00c\u683f\uffa5\uc080\uc808\uc008\uc828\uca08\u3333\uff33\u330f\u3333\u33cc\u33f3\u333c\uc0c0\u3c0c\ua7ff\uffe9\ufc8f\ucaa8\uf2a8\uc888\uc8c8\u3333\uff33\u333f\u333f\u33cc\u33c3\u33c3\uc0c3\u3c0c\u95ff\uffda\ufc8f\uc808\uf008\uca88\uc8c8\u3333\uff33\u333f\u33cf\u3300\u333f\u330c\uc0c3\uc00c\u557f\uff55\ufc8f\uc8c8\uc008\uca08\uca08\u3333\uff33\u333f\u33f3\u33cf\u333f\u333c\u00c3\ufc0c\u555f\uff55\ufc8f\uc8c8\ucaa8\uc8c8\uc2a8\ucfcf\uffcf\ucf3f\ucf03\ucfcf\ucfc3\ucfc3\u03c3\ufc0f\u5557\uff55\ufc0f\uc0c0\uc000\uc0c0\uf000\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u0323\ufe0a\ufe0a\uffff\uffff\u0000\uf000\uffff\uf000\uffff\uffff\uf00f\uffff\uffff\uffff\uffff\uac03\uffaa\u3faa\u03ff\uffc0\u00fc\u2300\uffc0\u2300\uf00f\uffff\uc3c3\u0fff\ufc3f\uffff\uffff\u00f3\ufc00\u3c00\u00ff\uff00\ufc00\u223f\uff00\u223f\uc0c3\ufffc\uc033\uf0ff\uf28f\uffff\uffff\uf003\uf23f\uf23f\u3cf0\uffa2\uffc0\uf000\uffa2\uf000\uc033\ufff3\uc033\uff3f\uc623\u0fff\uffc0\ufc0f\u2003\u2003\u1ccc\ufaaa\u0043\u0c54\u0aaa\ufc54\uc033\uf3cf\uc003\uffcf\uf0af\u03ff\uff00\u003f\uf050\uf050\u00c8\ufa8a\u500f\u0c15\uaa8a\ufc15\uc003\ucc3f\uf00f\uffcf\ufc7f\uf3c3\uff88\u03ff\u3c15\ufc15\u03c8\ufc02\u00ff\uaf00\u0c02\uff00\uf00f\u3fff\uffff\ufff3\uffff\u7333\ufea8\u3fff\u3f00\uff00\uaf28\uffaa\u0fff\u0ff0\u0faa\ufff0\uffff\uebff\uffff\uffff\u80ff\u382a\u80ff\u00ff\uf000\u000f\u3c00\u000f\uffff\uffff\u3fff\ufffc\uafbf\ufff3\uffff\uffff\ubcff\u3eaa\ubcff\u0f3f\ucfc0\ua230\uc0cc\ua23f\uffff\uffff\ucfff\uffff\ubebe\uffce\uffff\uffff\u00ff\u3c00\u00ff\u03cf\u3c00\uf330\u0002\uf33f\uc03f\uffff\uf3ff\ubffa\ubffa\uffca\u0fff\uf000\ua3c3\uc332\ua3ff\u83cf\u3fa2\u5130\u3a01\u513f\u0f03\uffff\ua8ff\uabaa\uafea\ufff2\uf3ff\ucfc0\uf3c3\u000b\uf3ff\u08cf\u3aaa\u510f\u3500\u510f\u0000\uffff\ua3ff\uaaaa\uaaaa\ufff2\u3cff\u3000\u533f\u3801\u533f\ua80f\u3a8a\u003f\uc000\u0030\u0003\uffff\u8fff\uaaa2\uaaa8\ufffc\u0cff\u3e28\u0fff\u3400\u0fc3\ua80f\u3c02\u00ff\uc000\u00f0\uc03f\ufffc\u3fff\u0a80\u2aa3\uffff\u80ff\u3aa0\uffff\uc000\uffc3\ua3cf\u3faa\u0fff\uf000\u0ff0\uffff\ufff3\uffff\uc00f\uc00f\uffff\uc003\uc003\uc003\uf00f\uffff\uffff\uffff\u0ff0\uf00f\u00ff\f\ufffc\ufff8\uffff\u0000\u0000\u0aa8\u3c3c\u0aa8\ucaa3\uc0c3\uffbf\uff3f\u300f\ud5e7\uaa3f\uaaa2\ufc02\ufff8\uffff\ufffc\u0fff\u0808\u33cc\u0808\u2aa8\u0a2c\uffbf\uff3f\u0ff0\u0000\ufe0f\ufffb\uf2af\uffe8\uffff\uaaac\u0aaa\u0a88\u30fc\u0a88\u2aa8\u0aac\ueaaa\uc000\u0000\u2008\uffa3\uffff\uf2ff\uffa3\uffff\ua8ec\u08ea\u0a88\u3c3c\u0a88\u0000\u0aa8\ufaab\uf003\u0000\u0000\uffe3\uffff\ucaff\uea8f\uffff\ua82c\u082a\u02a8\u3ffc\u02a8\ucff3\uc2a3\ufeaf\ufc0f\u02c0\u0000\ufff8\u3ff3\ucbff\ua54f\uaaaf\uaaac\u0aaa\u0000\u3c3c\u0000\ucff3\uf08f\ufaab\uf003\u0000\u2008\ufff8\u3ff3\u1bff\u903f\u5016\u0000\u0000\uc003\uc003\uc003\uf00f\ufc3f\uebfa\uc3f0\u0c30\u0000\ufff8\uffff\u1bff\u0fff\u0fc0\u0000\u0000\uf00f\uffff\ufc3f\u2aa8\u3ffc\u2008\uffff\uff30\uffff\uff3c\uffff\uffff\u1bff\uffff\uc3ff\uffff\uc003\uffff\uf28f\u0aa0\u3ffc\u2828\uffff\uff3c\uffff\ufec0\uffff\uffff\u1aff\uffff\ufcff\uffff\u0c30\uffff\uca23\uc283\u0ff0\ucaa3\uffff\ufec0\uffff\uc08f\uf00f\ufaaf\u16ff\ucfff\ua3cf\uffff\u0c30\uf00f\ucaa3\uf00f\u0ff0\uf00f\uffff\uc083\uffff\u308f\uc0c3\ueaeb\uc6ff\uffff\uf8cf\u0000\u0000\uc003\u2aa0\u3c3c\u23c8\u3c3c\uffff\u308f\uffc3\u0083\uc033\ueabb\uc5af\u3f3f\u2e3f\u0000\ufaaf\u0c30\u22a8\u0c30\u23c8\u0c30\uffc3\u00bf\uff3c\u82bf\uc033\ueabb\uf16a\ub3ff\ufbbc\uffff\uca83\ufaaf\u2aa8\uc003\u23c8\uc003\uff3c\u82bf\uff30\uea3f\uc003\ueaab\ufc55\u2fff\u3cb3\uffff\uc30f\u0ff0\u0a88\uf00f\u23c8\uf00f\uff30\u280f\uff30\u030f\uf00f\ufaaf\uff00\uc8cf\u0f8f\uffff\uffff\uffff\uffff\uffff\u000f\ufffc\u003f\ufff0\u3fff\ufffc\u3fff\u2028\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uba43\ufff1\ue90f\uffc6\u83ff\uffc1\u0fff\u2303\ufc0f\uffff\uffff\uffff\uff0f\uf0ff\uffff\uffff\u0003\uffc0\u000f\uff00\ua8ff\uff16\u03ff\u23cf\ufc8f\uffff\uffff\uffff\ufcf3\ucf3f\uffff\uffff\u48fc\uff2e\u23f3\ufcb9\ua80f\uf01a\u00ff\u23ff\ufc8f\uffff\uffff\uffff\uf3f3\ucfcf\uffff\uffff\u08cc\uff00\u2333\ufc00\ua8f3\ucf1a\u00ff\u080f\ufc8f\uffff\uffff\uffff\u33a3\ucacc\u3fc3\uc3fc\u4800\uff2e\u2003\ufcb9\u80fc\u3f02\uc00f\uca8f\ufc8f\uffff\uffff\uffff\u8383\uc2c2\u833c\u3cc2\u0aa8\uff00\u230f\ufc00\ua8ac\u3a1a\uffc0\u003c\ufc8f\uffff\uffff\uffff\u3c0f\uf03c\u3cfc\u3f3c\u42a8\ufff1\u23ff\uffc5\u0300\u00c0\uffff\ucc00\ufc8f\uffff\uffff\uffff\u8cff\uff32\u8ce8\u2b32\ua003\ufc01\u23ff\ufc06\u000f\ufc0f\uf03f\u0f03\ufc8f\uffff\uffff\uffff\u00f0\u0f00\u0003\uc000\ua83f\uf056\u200f\uf15a\u5ac3\uc060\uc00f\uc3ff\ufc8f\uffff\uffff\uffff\u3cc0\u0333\uccff\uff3c\uaacf\uc5aa\u8a8f\uc6aa\u0003\uc5a0\u00cf\ubc3f\ufc8f\uffff\uffff\uffff\u3c0f\uf033\ucc0f\uf03c\u0ab3\u06a8\u203f\u06a0\ucaa8\u1a86\u03cf\uabcf\uc000\uffff\uffff\uffff\u03ff\uffc0\u0303\uc0c0\ub2b3\u1aaa\ucacf\u1aaa\u0808\u1a80\u03c3\u6aa3\ucffc\uffff\uffff\uffff\u8fff\ufff2\u8fff\ufff2\u00b0\u1aa8\u02b3\u1aa8\ucaa8\u1a86\u3ff0\u12a3\uf3f3\uffff\uffff\uffff\u800f\uf002\u00ff\uff00\uaca8\u06aa\ub2b3\u06aa\u0aa8\u1a80\ufffc\uc223\ufccf\uffff\uffff\uffff\u3f03\uc0fc\uf03f\ufc0f\u0003\uc000\u000f\uc000\u0003\uc000\uffff\ufc03\uff3f\uffff\uffff\uffff\uffff\uf03f\uffff\uffff\uffff\uffff\u0000\uffff\u000f\uffff\u2aa8\u0000\uffff\u0003\ufc00\uffff\uffff\uc3cf\uc00f\uffff\uc00f\uffff\u1bf9\uffff\u2aa3\ufffc\u2003\u1bf9\uffff\uea53\uf16f\uffff\uc00f\ucff3\u23f3\uffff\u0003\ufffc\u0000\uffc0\u6aa8\ufffc\u2aa3\u0000\uffff\u0003\uf000\uffff\u23f3\ucbf3\u63c8\ufffc\u0280\uffc0\u1af9\ufc0f\u6a08\ufffc\u2a8f\u1af9\ufff0\u200f\uc6bf\uffff\u63c8\ucabc\u63c8\uc00c\u2aa0\ufc00\u8000\uf0ea\u5a08\uc000\u003c\uc000\uff0f\u2333\uc000\uffff\u63c8\uc2ac\u6828\u3ff0\u0280\uffc0\u0552\uf3a8\u16a8\u35d7\ucc00\ua542\u3cea\ua333\u1aca\uffff\u6828\uf00c\u1a80\u3fff\u0003\ufff0\uf290\u01ab\u02a8\u35d7\u0f03\u2a90\u0380\ua800\b\uffff\u1aa0\uffc3\u023f\u0ea0\uc00f\uffff\uaca4\uf1aa\u3c03\uc000\ucfff\ucaac\u053f\uaaa8\u1bca\uffff\u02a8\uf000\u0003\uf00f\uffff\uffff\uacac\uf1aa\uffff\uffff\u0fff\ub2ac\uc4aa\u000f\uf000\uc820\u0c03\uc1df\u0fff\ucdd7\uf003\uffff\ua2ab\uc1a2\uffff\uffff\u3fff\ub2ab\uc6aa\u0003\uc000\u28a8\u0fff\ucdd7\u33ff\ucdf4\u06a0\uffc0\u061a\uc6a0\uffff\uffff\ucfff\ua21a\uc6aa\ua8a0\u028a\u20a0\u33cf\ucdf4\ufccf\uf000\u5bfc\uc005\uc146\uc6a3\uffff\uffff\ub00f\u4946\uc6aa\u2aa8\u0aaa\u0323\ufcc3\uf000\ufcc3\ucff3\u6ffc\uff05\ufc01\uc128\uffff\uffff\uafe3\u0041\ucaa9\uaa28\u0a2a\ucf23\u003c\u0000\u003c\u0000\u16a3\ufff0\u3ffc\uf0a2\uffff\uffff\u6aa8\uaa0c\u1aaa\ua2a0\u02a2\ucfc3\ufcc3\uf3fc\ufcc3\ucff3\uc00f\uffff\u3fff\uff0a\uffff\uffff\u1888\u223f\u16aa\u0000\u0000\uffcf\uffcf\uffff\uffcf\uffff\uffff\uffff\u3fff\uffc0\uffff\uffff\uc000\u003f\uc000\u0000\u0000\uffcf\uc00f\uf00f\uf00f\uffff\uffff\ud55f\uc003\u5555\uaaaa\ufc3f\uc003\u0000\u0000\uff3f\uc003\uc003\u0fc3\uc6e3\uc553\uf00f\ufc0f\u7037\u1be4\u5555\uaaaa\ufc3f\u1554\u3f3f\u0aa0\uff3f\u003c\u0aa8\u0003\uc553\u1694\uc3c3\u0003\u7ff7\u0000\u5555\uaaaa\ufc0f\u1554\u3f3f\u0aa0\ufccf\u0000\u0aa8\uc00f\uf00f\u1be4\ucc33\ue280\ud55f\u1be4\u5555\uaaaa\ufc00\u1554\u3f3f\uc003\ufccf\ucae3\u02a8\ufcff\ufc3f\u1be4\ucc33\uaa08\ufdff\u0000\u5555\uaaaa\uff00\u1554\u3f3f\u0000\uf3f3\ucae3\uc003\u0cc3\u0000\u1694\uc3c3\u82a8\u5dd7\u1be4\u5555\uaaaa\uffff\u1554\u2a2a\u0aa0\uf2a3\u0000\uffff\uc00f\u16b8\uc553\uf00f\ueaab\ud55f\uc693\u5555\uaaaa\uffff\u1554\u1515\u0aa0\uf2a3\u003c\uffff\uf03f\u16b8\uf00f\uffff\uffff\uf57f\uf00f\u5555\uaaaa\uffff\uc003\u0000\uc003\uf003\uc003\uffff\u00ff\uff00\u6acf\uf154\ufc0f\uffff\uf00f\ufc3f\ufc3f\uffff\uffff\uffff\uffff\ua7da\uffff\ufc3f\uacff\uff06\u5bcf\uf100\uf2a3\uffff\uc3c3\uf2af\ufc3f\uffff\uffff\uffff\uffff\udff7\uffff\ufc3f\uacff\uff06\u3ccf\uf022\ucae8\uffff\uc0f3\uf2af\ufc3f\uc00f\ufffc\uf0fc\uffff\u7ffd\uffff\uf03f\uacff\uff06\u82cf\uf221\uc8f8\u00ff\uc0f3\uf2af\ufc3f\u7cf3\ufc3f\ucf3f\uff00\uffff\uffff\u003f\uac3f\ufc16\u6b0f\uf218\uc8f8\u003f\uc0f3\uf2af\ufc3f\u40cc\uf00c\u3cfc\ufc00\uffff\uffff\u00ff\uab0f\uf01a\u1f3f\uf1c7\uca28\uf03f\uc0f3\uf2af\ufc3f\u4000\ufc3c\ucf3c\ufc0f\ufebf\uffff\uffff\uaacf\uf05a\uc0ff\ufc30\uf2a3\ufc3f\uc3c3\uf2af\ufc3f\u4003\ufffc\uf0fc\ufc3f\ufaaf\uffff\uffff\u02cf\uf16a\uffff\uffff\ufc0f\ufc3f\uf00f\ufc3f\ufc3f\uc00f\ufffc\ufffc\ufc3f\ue96b\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uf00f\ufc3f\uf00f\uf003\uf00f\uf003\uf00f\uc003\uf00f\uf00f\uf00f\uf003\uf00f\uf003\uc003\uc003\uc3c3\ufc0f\uc0f3\uc0ff\uf0c3\uffc3\uffc3\uc3ff\uc0f3\uc0f3\uc0f3\uc3c3\uc3c3\uc0f3\uffc3\uffc3\uc3c3\ufc3f\uc0ff\uf00f\uf0f3\uf003\uf003\uf0ff\uf00f\uc0f3\uc0f3\uf003\uffc3\uc0f3\uf003\uffc3\uc3c3\ufc3f\uf00f\uc0ff\uc0f3\uc0ff\uc3c3\ufc3f\uc0f3\uc00f\uc003\uc3c3\uffc3\uc0f3\uffc3\uf003\uc3c3\ufc3f\uff03\uc0ff\uc003\uc0f3\uc3c3\ufc0f\uc0f3\uc0ff\uc0f3\uc3c3\uc3c3\uc0f3\uffc3\uffc3\uf00f\uf00f\uc003\uf003\uf0ff\uf00f\uf00f\ufc0f\uf00f\uf00f\uc0f3\uf003\uf00f\uf003\uc003\uffc3\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u0000\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uf00f\uc3f3\uf00f\uffc0\uc3c3\uffc3\uc3f3\uc3f3\uf00f\uf003\uf00f\uf003\uf00f\uc003\uc3f3\uc3f3\uc3c3\uc3f3\ufc3f\uaaf0\uf0c3\uffc3\uc0c3\uc3c3\uc3c3\uc3c3\ucfc3\uc3c3\uffc3\ufc3f\uc3f3\uc3f3\uffc3\uc003\ufc3f\u56bc\ufc03\uffc3\uc003\uc303\uc3c3\uc3c3\ucfc3\uc3c3\uf00f\ufc3f\uc3f3\uc3f3\uc0c3\uc3f3\ufc3f\u01ac\ufc03\uffc3\uc333\uc033\uc3c3\uf003\uccc3\uf003\uc0ff\ufc3f\uc3f3\uc3f3\uc3c3\uc3f3\ufc3f\u006c\uf0c3\uffc3\uc3f3\uc0f3\uc3c3\uffc3\uf3c3\ufcc3\uc0f3\ufc3f\uc0f3\uf0cf\uc00f\uc3f3\uf00f\u006c\uc3c3\uc003\uc3f3\uc3f3\uf00f\uffc3\ucc0f\uc3c3\uf00f\ufc3f\uf00f\ufc3f\uffff\uffff\uffff\u006c\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\u0000\uffff\uffff\u006c\uffff\uffff\uffff\uffff\uffff\ufc0f\uffff\uffff\u00c0\ue003\u8000\uc3f3\u01ff\uc3c3\uffff\u006c\uffff\uffff\uc003\uf03f\uffff\uf2a3\uffff\uffff\uff3f\u8000\u8000\uc3f3\u06aa\uc3c3\uffff\u006c\uff0f\uffff\uc0ff\uf03f\uffff\ucae8\uf3f3\uffff\u5715\u8aa8\u8ff8\uc333\u1a55\uf00f\uffff\u006c\uff0f\uffff\uf03f\uf03f\uf00f\uc8f8\ufccf\uffff\u5715\u8ff8\u8ff8\uc003\u1800\ufc3f\uffff\u006c\uffff\uff0f\ufc0f\uf03f\uf00f\uc8f8\uff3f\uffff\u0000\u8000\u8000\uc0c3\u1800\ufc3f\uff0f\u006c\uff0f\uff0f\uff03\uffff\uffff\uca28\ufccf\uffff\u0000\u8000\u8000\uc3f3\u1800\ufc3f\uff0f\u006c\uff0f\uff3f\uc003\uf03f\uffff\uf2a3\uf3f3\uffff\uffff\u8ff8\u8ff8\uffff\u1800\uffff\uffff\uaaac\uffff\uffcf\uffff\uffff\uffff\ufc0f\uffff\uffff\uffff\u8ff8\u8ff8\u00c0\u3fff\uf03f\uff03\u3fff\uf557\u3fff\ud557\uffff\u1800\u3fff\uffff\u3ffc\u0000\ufffc\u000f\uff3f\u3fff\ucfcf\ufcfc\u0fff\uf7f7\ucfff\u56a5\uff3f\u1800\uc3ff\uffff\u3ff3\u3fff\ufffc\u0003\u5715\u3fff\u00f3\uf3f0\u33ff\uf777\uf3ff\u5aa9\ufc0f\u1800\uccff\ufeff\u3fcf\u3fff\ufffc\ua8a0\u5715\u3fff\u0cf3\uf3cf\u3cff\ufddf\ufcff\u5aa9\uf003\u1800\uf0ff\ufebf\u3f3f\u3fff\ufffc\u2aa8\u0000\u3fff\u3f3f\uff3f\u3f3f\ufddf\uff3f\u5aa9\uffff\u1800\uff0f\ufbef\u3cff\u3fff\ufffc\uaa28\u0000\u3fff\u3f3f\uff3f\u3fcf\ufddf\uffcf\u5aa9\uff3f\u1800\uff33\ufbfb\u33ff\u3fff\ufffc\ua2a0\uffff\u3fff\u3fff\uffff\u3ff3\ufd5f\ufff3\u56a5\ufc0f\u1800\uffc3\uefbe\u0fff\u3fff\ufffc\u0000\uffff\u3fff\u3fff\uffff\u3ffc\uffff\ufffc\ud557\uf003\u1aaa\ufffc\ubeaf\u3fff\u3fff\u0000\u0000\uaaaa\uffff\uffff\uffff\u3fff\ufffc\uafbf\ufff3\u00ff\ufff0\uc00f\ufcff\uffff\u0000\u0000\u0000\uffff\uffff\uffff\uffff\ucfff\uffff\ubebe\uffce\ucf3f\uffc3\uf3ff\u03ff\uff00\u0000\u0000\ufffc\uaaaa\u0fff\ufffc\uffff\uf3ff\ubffa\ubffa\uffca\uc00f\uffcf\uc0ff\uffff\uf0ff\ua8a0\u028a\ufffc\uffff\uf0ff\ufff3\uffff\ua8ff\uabaa\uafea\ufff2\ucfcf\uff0f\uff3f\uffff\ucfff\u2aa8\u0aaa\ufffc\uaaaa\uff3f\uf3cf\uffff\ua3ff\uaaaa\uaaaa\ufff2\u0c33\uff3f\uc00f\u03ff\u3ffc\uaa28\u0a2a\ufffc\uffff\uffcf\ucc3f\uffff\u8fff\uaaa2\uaaa8\ufffc\u3ff3\uff3f\ufff0\ufc3f\u3fff\ua2a0\u02a2\ufffc\uaaaa\uffcf\u3fff\ufffc\u3fff\u0a80\u2aa3\uffff\u3fc3\uff3f\ufccc\ucf3f\u3ff3\u0000\u0000\ufffc\uffff\ufff3\uebff\ufff3\uffff\uc00f\uc00f\uffff\u0fcf\uff00\u0000\u0000\uc000\u0000\u0000\ufffc\ufffc\u0000\u3fff\uaaaa\uf000\uffff\uffff\ucfc3\uc300\uffff\uffff\ucff3\uffcf\uffff\ufffc\uffff\ufffc\uffff\u3fff\uaaaa\uc000\ufc3f\u0000\u003c\u333c\u0ff3\ucfc0\ucff3\uffcf\uff7f\ufff3\uffff\ufffc\uffff\u3fff\uaaaa\u028a\uf3cf\u3ffc\ucfc3\uc300\u33f3\ucf3f\ucff3\u00c3\ufd5f\uffcf\uffff\ufffc\uffff\u3fff\uaaaa\u0aaa\ucc33\ucff3\uffff\uffff\u00f3\u033c\u0ff3\u3cc0\ufd5f\uff3f\uffff\ufffc\uffff\u3fff\uaaaa\u0a2a\ucc33\uf00f\uc003\uf003\u3cf3\u333c\u3ff3\uc3f3\uf557\ufcff\uffff\ufffc\uffff\u3fff\uaaaa\u02a2\uf3cf\uffff\u3ffc\ucf0c\u3ff3\u3300\u3ff3\uc3f3\uf5d7\uf3ff\uffff\ufffc\uffff\u3fff\uaaaa\u0000\ufc3f\ucccc\uc003\u030c\u0003\u33cf\u3ff3\u3cf3\uf5d7\ucfff\uffff\ufffc\uffff\u3fff\uaaaa\u0000\uffff\u3333\uffff\uf003\u0033\u03cc\u0ff3\u00f0\ufd5f\u3fff\uffff\u0000\uaaaa\uc003\uc003\u0000\u000f\uf000\uc00f\u000f\u0000\uf000\u0000\uffff\u0000\u0000\uffff\uffff\uaaaa\u0aa8\u0ffc\u8a8a\u0003\uc000\u0fc3\u0003\u0000\uc000\u2828\uffff\u0000\u0000\uffff\u0000\u0000\u0808\u003c\u8a8a\ua8a0\u028a\u3ff0\u0000\u0000\u0000\u2828\uffff\ua8a0\u028a\uffff\u0000\u5555\u0a88\u003c\u8a8a\u2aa8\u0aaa\u3ffc\u0000\u0000\u0000\u2828\uffff\u2aa8\u0aaa\uffff\u0000\u0000\u0a88\u003c\u0000\uaa28\u0a2a\u0ffc\u0300\u0303\u0303\u0000\uffff\uaa28\u0a2a\uffff\ua8aa\u5555\u02a8\u0000\ua8a8\ua2a0\u02a2\u0ffc\u3330\u3333\u3333\uffff\uffff\ua2a0\u02a2\uffff\uaaa2\u0000\u0000\u0000\ua8a8\u0000\u0000\u00c0\u3333\u3333\u3333\uffff\uffff\u0000\u0000\uffff\u2a2a\u0000\uc003\uc003\ua8a8\u0000\u0000\u0003\u3f33\u3f3f\uf33f\uffff\uffff\u0000\u0000\uffff\u0000\u0000\uaaa3\uc16a\u3000\u0300\uaaa0\ua2a8\ua8aa\ua82a\f\u2a8a\uc3c3\u0000\u0000\uc003\uaaa8\u015a\uaaa3\uc16a\u82a8\ua8aa\uaa82\ua2a8\ua8aa\ua82a\u2a82\u2a8a\u2828\uffff\u3f3f\u1554\uaaa8\u015a\uaaa3\uc16a\ua2a8\ua8aa\uaa0a\ua2a8\ua8aa\ua82a\u2a8a\u2a8a\u2828\u0000\u3f3f\u1554\uaaa8\u015a\uaaa3\uc16a\ua2a8\ua8aa\uaa2a\ua154\ua8aa\ua82a\u2a8a\u154a\u2828\uaaaa\u3f3f\u1554\uaaa8\u015a\u000f\uf000\ua2a8\ua8aa\u002a\u5154\u5455\u0005\u2a8a\u1545\u2828\u5555\u3f3f\u1554\u0000\u0000\uaaa3\uc16a\ua2a8\ua8aa\ua82a\u5000\u5455\uaa01\u2a8a\u0005\u2828\u0000\u2a2a\u1554\uaaa3\uc16a\uaaa3\uc16a\ua2a8\ua8aa\ua82a\u0000\u0000\uaa80\u2a8a\u0000\u2828\u0000\u1515\u1554\uaaa3\uc16a\uaaa3\uc16a\ua2a8\ua8aa\ua82a\u3000\u0300\uaaa0\u2a8a\f\uc3c3\u0000\u0000\uc003";
int i;
int j;
int x;
int y;
// decompress sprite
BufferedImage image = new BufferedImage(128, 192, 1);
for(y = 0; y < 192; y++) {
for(x = 0; x < 128; x += 8) {
for(i = 0; i < 8; i++) {
j = ((S.charAt((y << 4) + (x >> 3)) >> (i << 1)) & 3);
image.setRGB(x + i, y, j == 0 ? 0 : j == 1 ? 0x606060
: j == 2 ? 0xA8A8A8 : 0xF8F8F8);
}
}
}
Graphics2D g = null;
while(true) {
if (g == null) {
g = (Graphics2D)getGraphics();
} else {
g.drawImage(image, 0, 0, 256, 384, null);
}
Thread.yield();
}
}
}
Compile 'n Shrink now produces a 3935 byte file.
The other common technique is to store each colored pixel value as a distinct character in a String. The following program scans across each row, from left to right, converting each pixel value into the characters ‘0’, ‘1’, ‘2’ or ‘3’.
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class Converter2 {
public static final String sourcePath = "...";
public static void main(String... args) throws Throwable {
StringBuffer sb = new StringBuffer();
BufferedImage image = ImageIO.read(new File(sourcePath + "0.png"));
for(int y = 0; y < image.getHeight(); y++) {
for(int x = 0; x < image.getWidth(); x++) {
sb.append(getColor(0xFF & image.getRGB(x, y)));
}
}
System.out.print(sb.toString());
}
private static int getColor(int pixel) {
switch(pixel) {
case 0x00:
return 0;
case 0x60:
return 1;
case 0xA8:
return 2;
default:
return 3;
}
}
}
Below is the program to decode the String, but due to forum message size limitations, I trimmed the long String. If you actually want to run this code, restore the String using the above encoder.
import java.applet.Applet;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class a extends Applet implements Runnable {
@Override
public void start() {
new Thread(this).start();
}
public void run() {
final String S = "33333333...";
int j;
int x;
int y;
// decompress sprite
BufferedImage image = new BufferedImage(128, 192, 1);
for(y = 0; y < 192; y++) {
for(x = 0; x < 128; x++) {
j = S.charAt((y << 7) + x) - '0';
image.setRGB(x, y, j == 0 ? 0 : j == 1 ? 0x606060
: j == 2 ? 0xA8A8A8 : 0xF8F8F8);
}
}
Graphics2D g = null;
while(true) {
if (g == null) {
g = (Graphics2D)getGraphics();
} else {
g.drawImage(image, 0, 0, 256, 384, null);
}
Thread.yield();
}
}
}
Compile 'n Shrink generates a 4023 byte file from this template, which is slightly larger than the Unicode technique.
3935 - 318 = 3617
4023 - 318 = 3705
100 * (3705/3617 - 1) = 2.43%
3705 - 3617 = 88
The second technique used an additional 88 bytes. It’s 2.43% larger. That’s pretty insignificant, but it may make the difference between fitting under 4K or not. Still it’s good to know that Compile 'n Shrink does an amazing job on both techniques.
I would recommend using the first technique for bitmaps and the second for level maps. Levels are sparse; they mostly contain empty space. But, the non-empty regions may consist of a large number of tile types. The second technique probably compresses well regardless of the number of distinct characters used as long as it is relatively sparse.
I only tested these 2 techniques. If you are familiar with some others, I encourage you to test it out and share your findings.