1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51:
52: public class DecodeRLE4 extends BMPDecoder {
53:
54: public DecodeRLE4(BMPFileHeader fh, BMPInfoHeader ih){
55: super(fh, ih);
56: }
57:
58:
61: private static final byte ESCAPE = (byte)0;
62: private static final byte EOL = (byte)0;
63: private static final byte EOB = (byte)1;
64: private static final byte DELTA = (byte)2;
65:
66: public BufferedImage decode(ImageInputStream in) throws IOException, BMPException {
67: IndexColorModel palette = readPalette(in);
68: skipToImage(in);
69:
70: Dimension d = infoHeader.getSize();
71: int h = (int)d.getHeight();
72: int w = (int)d.getWidth();
73:
74: byte[] data = uncompress(w, h, in);
75: SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
76: w, h, 4);
77:
78: DataBuffer db = new DataBufferByte(data, w*h, 0);
79: WritableRaster raster = Raster.createWritableRaster(sm, db, null);
80:
81: return new BufferedImage(palette, raster, false, null);
82: }
83:
84: private byte[] uncompress(int w, int h, ImageInputStream in)
85: throws BMPException, IOException {
86: byte[] cmd = new byte[2];
87: byte[] data = new byte[w*h>>1];
88: int offIn = 0;
89: int x=0,y=0;
90:
91:
92: w += (w&1);
93: w = w >> 1;
94:
95: try {
96: while(((x>>1) + y*w) < w*h){
97: if(in.read(cmd) != 2)
98: throw new IOException("Error reading compressed data.");
99:
100: if(cmd[0] == ESCAPE){
101: switch(cmd[1]){
102: case EOB:
103: return data;
104: case EOL:
105: x = 0;
106: y++;
107: break;
108: case DELTA:
109: if(in.read(cmd) != 2)
110: throw new IOException("Error reading compressed data.");
111: int dx = cmd[0] & (0xFF);
112: int dy = cmd[1] & (0xFF);
113: x += dx;
114: y += dy;
115: break;
116:
117: default:
118:
119: int length = cmd[1] & (0xFF);
120:
121:
122: int bytesize = length;
123: bytesize += (bytesize & 1);
124: bytesize >>= 1;
125: bytesize += (bytesize & 1);
126:
127: byte[] run = new byte[bytesize];
128: if(in.read(run) != bytesize)
129: throw new IOException("Error reading compressed data.");
130:
131: if((x&1) == 0){
132: length += (length&1);
133: length >>= 1;
134: System.arraycopy(run, 0, data, ((x>>1) + w*(h-y-1)),
135: length);
136: } else {
137: for(int i=0;i<length;i++){
138: if((i&1) == 0)
139: data[((x+i)>>1) + w*(h-y-1)]
140: |= ((run[i>>1]&0xF0) >> 4);
141: else
142: data[((x+i)>>1) + w*(h-y-1)]
143: |= ((run[i>>1]&0x0F) << 4);
144: }
145: }
146: x += cmd[1] & (0xFF);
147: break;
148: }
149: } else {
150:
151: int length = cmd[0] & (0xFF);
152: if((x&1) == 0){
153: length += (length&1);
154: length >>= 1;
155: for(int i=0;i<length;i++)
156: data[(h-y-1)*w + i + (x >> 1)] = cmd[1];
157: } else {
158: for(int i=0;i<length;i++){
159: if((i&1) == 0)
160: data[((x+i)>>1) + w*(h-y-1)]
161: |= ((cmd[1]&0xF0) >> 4);
162: else
163: data[((x+i)>>1) + w*(h-y-1)]
164: |= ((cmd[1]&0x0F) << 4);
165: }
166: }
167: x += cmd[0] & (0xFF);
168: }
169: }
170: return data;
171: } catch(ArrayIndexOutOfBoundsException e){
172: throw new BMPException("Invalid RLE data.");
173: }
174: }
175: }