Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (121)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Embedding Bitmaps  (Read 3060 times)
0 Members and 1 Guest are viewing this topic.
Offline zeroone
« Posted 2011-03-12 20:19:06 »

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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
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'.  

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
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.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
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.
Offline Nate

JGO Kernel


Medals: 150
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #1 - Posted 2011-03-13 04:09:35 »

RLE might help, unless you lose the savings in the decoding code.

Offline Alan_W

JGO Knight


Medals: 8
Projects: 3


Java tames rock!


« Reply #2 - Posted 2011-03-13 09:47:34 »

I tried storing everything as 2 colour bitmaps, followed by a list of 6 bit (RRGGBB) colour fills.  All images must be line drawings, otherwise the fills bleed into adjoining spaces.  At run-time the game does a line scan and floodfills the first white pixel it finds with the first colour fill.  The line scan then continues until it finds another white pixel and does another flood fill.  The flood-fill code does repeated scans of the entire image.  On each scan any white pixel with an orthogonally adjacent pixel in any colour than black, gets filled.  The scan also has to be able to distinguish between original black and white pixels, and one's that have subsequently been filled. 

The decoder is fairly compact and works well for line images with a few large areas of solid fill.  Next year I might tweak it a bit to allow cel-shading.

Now comes the part that may well be non-optimum.  I line scanned the 2 bit image, packing each 32 bit block of data into 5 characters for storage in a string.  This only used characters in the normal ASCI range (32-126). However that might not give the best pack200 compression.  It might be best for images that are a multiple of 32 bits width; but I also have many 16 bit width images.

Not so happy with my efforts on Level Data: I run length encoded the level data for Valentino, but this was probably a waste of time.  At least it reduced the amount of crud in the source code.


Time flies like a bird. Fruit flies like a banana.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Damocles
« Reply #3 - Posted 2011-03-17 16:12:53 »

Thanks for sharing your code,


I have tried a RLE, but in the end, the additional overhead for the unpacking code killed the effect,
AND the higher entropy (by precomressing it) reduced the effect of the better jar/pack compression.

Offline zammbi

JGO Coder


Medals: 4



« Reply #4 - Posted 2011-03-17 17:25:44 »

Compressing the image with an application like Pngguantlet compresses the image to 3604 bytes. This sounds better then converting to strings?

Current project - Rename and Sort
Offline zeroone
« Reply #5 - Posted 2011-03-17 17:29:57 »

Quote
Compressing the image with an application like Pngguantlet compresses the image to 3604 bytes. This sounds better then converting to strings?

Nice.  But, what's the best way to load it?
Offline Alan_W

JGO Knight


Medals: 8
Projects: 3


Java tames rock!


« Reply #6 - Posted 2011-03-17 19:00:35 »

Compressing the image with an application like Pngguantlet compresses the image to 3604 bytes. This sounds better then converting to strings?

Sadly the png is already compressed, so most of those bytes will appear in the pack file. Cry

Time flies like a bird. Fruit flies like a banana.
Offline zeroone
« Reply #7 - Posted 2011-03-17 19:14:44 »

Quote
Sadly the png is already compressed, so most of those bytes will appear in the pack file.

How would you get the image into the pack file and how you would load it?
Offline zeroone
« Reply #8 - Posted 2011-03-19 19:11:49 »

Quote
RLE might help, unless you lose the savings in the decoding code.

Before creating an RLE encoder, I did some analysis on the image.  I wrote a method that computes the frequency of each color, the maximum run-length and the average run-length.  Here are the results:

colors[0] = 7674
colors[1] = 1264
colors[2] = 3074
colors[3] = 12564

maximum run-length: 157
average run-length: 3

Color 1 (dark gray) appears the fewest times.  8-bits are required to capture the maximum run-length.

The RLE encoder below borrows ideas from the PCX file format.  It uses the following scheme:

If the run-length is 1 and the color is not 1, then encode the color directly as a 2-bit number; otherwise, add the following bits:

01 cc xxxxxxxx

where 01 is an identifier (1 is used since it is least frequent color), cc is the color (2-bits) and xxxxxxxx is the run-length (8-bits).

The resultant bit sequence is converted into a Unicode string with some 0's padded at the end.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;

public class Converter3 {

  public static final String sourcePath = "...";

  public static void main(String... args) throws Throwable {

    BufferedImage image = ImageIO.read(new File(sourcePath + "0.png"));

    //countColors(image);
    //measureMaxLength(image);

    int[] pixels = new int[image.getWidth() * image.getHeight() + 1];
    for(int y = 0; y < image.getHeight(); y++) {
      for(int x = 0; x < image.getWidth(); x++) {
        pixels[y * image.getWidth() + x]
            = getColor(image.getRGB(x, y) & 0xFF);
      }
    }
    pixels[pixels.length - 1] = -1;

    int color = pixels[0];
    int length = 0;

    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < pixels.length; i++) {
      if (color == pixels[i]) {
        length++;
      } else {
        if (length == 1 && color != 1) {
          sb.append(String.format("%2s",
              Integer.toBinaryString(color)).replace(" ", "0"));
        } else {
          sb.append("01");
          sb.append(String.format("%2s",
              Integer.toBinaryString(color)).replace(" ", "0"));
          sb.append(String.format("%8s",
              Integer.toBinaryString(length)).replace(" ", "0"));
        }

        color = pixels[i];
        length = 1;
      }
    }

    for(int i = (sb.length() % 16) - 1; i >= 0; i--) {
      sb.append("0");
    }

    StringBuffer sb2 = new StringBuffer();
    for(int i = 0; i < sb.length(); i += 16) {
      printValue(sb2, Integer.parseInt(new StringBuilder(
          sb.substring(i, i + 16)).reverse().toString(), 2));
    }
   
    System.out.print(sb2);
  }

  private static void measureMaxLength(BufferedImage image) {

    int[] lens = new int[158];

    int maxLength = 0;
    int lengths = 0;
    int lengthTotal = 0;

    int color = -1;
    int length = 0;

    for(int y = 0; y < image.getHeight(); y++) {
      for(int x = 0; x < image.getWidth(); x++) {
        if (color == getColor(image.getRGB(x, y) & 0xFF)) {
          length++;
          if (length > maxLength) {
            maxLength = length;
          }
        } else {

          lens[length]++;
          lengthTotal += length;
          lengths++;

          color = getColor(image.getRGB(x, y) & 0xFF);
          length = 1;
        }
      }
    }

    lens[length]++;
    lengthTotal += length;
    lengths++;

    System.out.format("max length: %d%n", maxLength);
    System.out.format("average length: %d%n", lengthTotal / lengths);

    for(int i = 0; i < 158; i++) {
      System.out.format("lens[%d] = %d%n", i, lens[i]);
    }
  }

  private static void countColors(BufferedImage image) {
    int[] colors = new int[4];

    for(int y = 0; y < image.getHeight(); y++) {
      for(int x = 0; x < image.getWidth(); x++) {
        colors[getColor(image.getRGB(x, y) & 0xFF)]++;
      }
    }

    for(int i = 0; i < 4; i++) {
      System.out.format("colors[%d] = %d%n", i, colors[i]);
    }
  }

  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;
      }
    }
  }
}


Here is the decoder (the Unicode string was shortened to fit within the forum message limit):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
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 = "\u27ce\u4e40\u602a\u2f2e\u0a20\u24e4...";

    int i = 0;
    int j = 0;
    int x;
    int y;

    int length = 0;

    // decompress sprite
    StringBuilder sb = new StringBuilder();
    for(i = 0; i < S.length(); i++) {
      for(j = 0; j < 16; j++) {
        sb.append((char)('0' + ((S.charAt(i) >> j) & 1)));
      }
    }
    i = 0;

    BufferedImage image = new BufferedImage(128, 192, 1);
    for(y = 0; y < 192; y++) {
      for(x = 0; x < 128; x++) {
        if (length == 0) {
          j = Integer.parseInt(sb.substring(i, i + 2), 2);
          i += 2;
          if (j != 1) {
            length = 1;
          } else {
            j = Integer.parseInt(sb.substring(i, i + 2), 2);
            i += 2;
            length = Integer.parseInt(sb.substring(i, i + 8), 2);
            i += 8;
          }
        }
        image.setRGB(x, y, j == 0 ? 0 : j == 1 ? 0x606060
            : j == 2 ? 0xA8A8A8 : 0xF8F8F8);
        length--;
      }
    }

    Graphics2D g = null;

    while(true) {

      if (g == null) {
        g = (Graphics2D)getGraphics();
      } else {
        g.drawImage(image, 0, 0, 256, 384, null);
      }

      Thread.yield();
    }
  }
}


Unfortunately, the result is 5775 bytes!

Offline zeroone
« Reply #9 - Posted 2011-03-19 19:16:05 »

Quote
Compressing the image with an application like Pngguantlet compresses the image to 3604 bytes. This sounds better then converting to strings?

I'm not so sure.  After subtracting an estimate for the overhead (discussed in the opening post), the Unicode String encoding technique produced a 3617 byte file.  If I come up with a scheme for loading a PNG directly, I'll post the results.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline appel

JGO Wizard


Medals: 51
Projects: 4


I always win!


« Reply #10 - Posted 2011-03-20 00:20:18 »

Don't you ever sleep?  Grin

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

theagentd (20 views)
2014-10-25 15:46:29

Longarmx (53 views)
2014-10-17 03:59:02

Norakomi (47 views)
2014-10-16 15:22:06

Norakomi (35 views)
2014-10-16 15:20:20

lcass (39 views)
2014-10-15 16:18:58

TehJavaDev (69 views)
2014-10-14 00:39:48

TehJavaDev (69 views)
2014-10-14 00:35:47

TehJavaDev (61 views)
2014-10-14 00:32:37

BurntPizza (74 views)
2014-10-11 23:24:42

BurntPizza (47 views)
2014-10-11 23:10:45
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!