comparison dwt/internal/image/PngDeflater.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 1a8b3cb347e0
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
1 /*******************************************************************************
2 * Copyright (c) 2000, 2006 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 module dwt.internal.image;
12
13 import java.io.ByteArrayOutputStream;
14
15 public class PngDeflater {
16
17 static final int BASE = 65521;
18 static final int WINDOW = 32768;
19 static final int MIN_LENGTH = 3;
20 static final int MAX_MATCHES = 32;
21 static final int HASH = 8209;
22
23 byte[] in;
24 int inLength;
25
26 ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
27
28 int adler32 = 1;
29
30 int buffer, bitCount;
31
32 Link[] hashtable = new Link[HASH];
33 Link[] window = new Link[WINDOW];
34 int nextWindow;
35
36 static class Link {
37
38 int hash, value;
39 Link previous, next;
40
41 Link() {
42
43 this.hash = 0;
44 this.value = 0;
45 this.previous = null;
46 this.next = null;
47
48 }
49
50 }
51
52 static class Match {
53
54 int length, distance;
55
56 Match(int length, int distance) {
57
58 this.length = length;
59 this.distance = distance;
60
61 }
62
63 }
64
65 static final short mirrorBytes[] = {
66
67 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
68 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
69 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
70 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
71 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
72 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
73 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
74 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
75 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
76 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
77 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
78 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
79 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
80 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
81 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
82 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
83 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
84 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
85 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
86 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
87 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
88 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
89 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
90 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
91 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
92 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
93 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
94 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
95 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
96 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
97 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
98 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
99
100 };
101
102 static class Code {
103
104 int code, extraBits, min, max;
105
106 Code(int code, int extraBits, int min, int max) {
107
108 this.code = code;
109 this.extraBits = extraBits;
110 this.min = min;
111 this.max = max;
112
113 }
114
115 }
116
117 static final Code lengthCodes[] = {
118
119 new Code(257, 0, 3, 3),
120 new Code(258, 0, 4, 4),
121 new Code(259, 0, 5, 5),
122 new Code(260, 0, 6, 6),
123 new Code(261, 0, 7, 7),
124 new Code(262, 0, 8, 8),
125 new Code(263, 0, 9, 9),
126 new Code(264, 0, 10, 10),
127 new Code(265, 1, 11, 12),
128 new Code(266, 1, 13, 14),
129 new Code(267, 1, 15, 16),
130 new Code(268, 1, 17, 18),
131 new Code(269, 2, 19, 22),
132 new Code(270, 2, 23, 26),
133 new Code(271, 2, 27, 30),
134 new Code(272, 2, 31, 34),
135 new Code(273, 3, 35, 42),
136 new Code(274, 3, 43, 50),
137 new Code(275, 3, 51, 58),
138 new Code(276, 3, 59, 66),
139 new Code(277, 4, 67, 82),
140 new Code(278, 4, 83, 98),
141 new Code(279, 4, 99, 114),
142 new Code(280, 4, 115, 130),
143 new Code(281, 5, 131, 162),
144 new Code(282, 5, 163, 194),
145 new Code(283, 5, 195, 226),
146 new Code(284, 5, 227, 257),
147 new Code(285, 0, 258, 258)
148
149 };
150
151 static final Code distanceCodes[] = {
152
153 new Code(0, 0, 1, 1),
154 new Code(1, 0, 2, 2),
155 new Code(2, 0, 3, 3),
156 new Code(3, 0, 4, 4),
157 new Code(4, 1, 5, 6),
158 new Code(5, 1, 7, 8),
159 new Code(6, 2, 9, 12),
160 new Code(7, 2, 13, 16),
161 new Code(8, 3, 17, 24),
162 new Code(9, 3, 25, 32),
163 new Code(10, 4, 33, 48),
164 new Code(11, 4, 49, 64),
165 new Code(12, 5, 65, 96),
166 new Code(13, 5, 97, 128),
167 new Code(14, 6, 129, 192),
168 new Code(15, 6, 193, 256),
169 new Code(16, 7, 257, 384),
170 new Code(17, 7, 385, 512),
171 new Code(18, 8, 513, 768),
172 new Code(19, 8, 769, 1024),
173 new Code(20, 9, 1025, 1536),
174 new Code(21, 9, 1537, 2048),
175 new Code(22, 10, 2049, 3072),
176 new Code(23, 10, 3073, 4096),
177 new Code(24, 11, 4097, 6144),
178 new Code(25, 11, 6145, 8192),
179 new Code(26, 12, 8193, 12288),
180 new Code(27, 12, 12289, 16384),
181 new Code(28, 13, 16385, 24576),
182 new Code(29, 13, 24577, 32768)
183
184 };
185
186 void writeShortLSB(ByteArrayOutputStream baos, int theShort) {
187
188 byte byte1 = (byte) (theShort & 0xff);
189 byte byte2 = (byte) ((theShort >> 8) & 0xff);
190 byte[] temp = {byte1, byte2};
191 baos.write(temp, 0, 2);
192
193 }
194
195 void writeInt(ByteArrayOutputStream baos, int theInt) {
196
197 byte byte1 = (byte) ((theInt >> 24) & 0xff);
198 byte byte2 = (byte) ((theInt >> 16) & 0xff);
199 byte byte3 = (byte) ((theInt >> 8) & 0xff);
200 byte byte4 = (byte) (theInt & 0xff);
201 byte[] temp = {byte1, byte2, byte3, byte4};
202 baos.write(temp, 0, 4);
203
204 }
205
206 void updateAdler(byte value) {
207
208 int low = adler32 & 0xffff;
209 int high = (adler32 >> 16) & 0xffff;
210 int valueInt = value & 0xff;
211 low = (low + valueInt) % BASE;
212 high = (low + high) % BASE;
213 adler32 = (high << 16) | low;
214
215 }
216
217 int hash(byte[] bytes) {
218
219 int hash = ((bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16 | (bytes[2] & 0xff) << 8) % HASH;
220 if (hash < 0) {
221 hash = hash + HASH;
222 }
223 return hash;
224
225 }
226
227 void writeBits(int value, int count) {
228
229 buffer |= value << bitCount;
230 bitCount += count;
231 if (bitCount >= 16) {
232 bytes.write((byte) buffer);
233 bytes.write((byte) (buffer >>> 8));
234 buffer >>>= 16;
235 bitCount -= 16;
236 }
237
238 }
239
240 void alignToByte() {
241
242 if (bitCount > 0) {
243 bytes.write((byte) buffer);
244 if (bitCount > 8) bytes.write((byte) (buffer >>> 8));
245 }
246 buffer = 0;
247 bitCount = 0;
248
249 }
250
251 void outputLiteral(byte literal) {
252
253 int i = literal & 0xff;
254
255 if (i <= 143) {
256 // 0 through 143 are 8 bits long starting at 00110000
257 writeBits(mirrorBytes[0x30 + i], 8);
258 }
259 else {
260 // 144 through 255 are 9 bits long starting at 110010000
261 writeBits(1 + 2 * mirrorBytes[0x90 - 144 + i], 9);
262 }
263
264 }
265
266 Code findCode(int value, Code[] codes) {
267
268 int i, j, k;
269
270 i = -1;
271 j = codes.length;
272 while (true) {
273 k = (j + i) / 2;
274 if (value < codes[k].min) {
275 j = k;
276 }
277 else if (value > codes[k].max) {
278 i = k;
279 }
280 else {
281 return codes[k];
282 }
283 }
284
285 }
286
287 void outputMatch(int length, int distance) {
288
289 Code d, l;
290 int thisLength;
291
292 while (length > 0) {
293
294 // we can transmit matches of lengths 3 through 258 inclusive
295 // so if length exceeds 258, we must transmit in several steps,
296 // with 258 or less in each step
297
298 if (length > 260) {
299 thisLength = 258;
300 }
301 else if (length <= 258) {
302 thisLength = length;
303 }
304 else {
305 thisLength = length - 3;
306 }
307
308 length = length - thisLength;
309
310 // find length code
311 l = findCode(thisLength, lengthCodes);
312
313 // transmit the length code
314 // 256 through 279 are 7 bits long starting at 0000000
315 // 280 through 287 are 8 bits long starting at 11000000
316 if (l.code <= 279) {
317 writeBits(mirrorBytes[(l.code - 256) * 2], 7);
318 }
319 else {
320 writeBits(mirrorBytes[0xc0 - 280 + l.code], 8);
321 }
322
323 // transmit the extra bits
324 if (l.extraBits !is 0) {
325 writeBits(thisLength - l.min, l.extraBits);
326 }
327
328 // find distance code
329 d = findCode(distance, distanceCodes);
330
331 // transmit the distance code
332 // 5 bits long starting at 00000
333 writeBits(mirrorBytes[d.code * 8], 5);
334
335 // transmit the extra bits
336 if (d.extraBits !is 0) {
337 writeBits(distance - d.min, d.extraBits);
338 }
339
340 }
341
342 }
343
344 Match findLongestMatch(int position, Link firstPosition) {
345
346 Link link = firstPosition;
347 int numberOfMatches = 0;
348 Match bestMatch = new Match(-1, -1);
349
350 while (true) {
351
352 int matchPosition = link.value;
353
354 if (position - matchPosition < WINDOW && matchPosition !is 0) {
355
356 int i;
357
358 for (i = 1; position + i < inLength; i++) {
359 if (in[position + i] !is in[matchPosition + i]) {
360 break;
361 }
362 }
363
364 if (i >= MIN_LENGTH) {
365
366 if (i > bestMatch.length) {
367 bestMatch.length = i;
368 bestMatch.distance = position - matchPosition;
369 }
370
371 numberOfMatches = numberOfMatches + 1;
372
373 if (numberOfMatches is MAX_MATCHES) {
374 break;
375 }
376
377 }
378
379 }
380
381 link = link.next;
382 if (link is null) {
383 break;
384 }
385
386 }
387
388 if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) {
389 return null;
390 }
391
392 return bestMatch;
393
394 }
395
396 void updateHashtable(int to, int from) {
397
398 byte[] data = new byte[3];
399 int hash;
400 Link temp;
401
402 for (int i = to; i < from; i++) {
403
404 if (i + MIN_LENGTH > inLength) {
405 break;
406 }
407
408 data[0] = in[i];
409 data[1] = in[i + 1];
410 data[2] = in[i + 2];
411
412 hash = hash(data);
413
414 if (window[nextWindow].previous !is null) {
415 window[nextWindow].previous.next = null;
416 }
417 else if (window[nextWindow].hash !is 0) {
418 hashtable[window[nextWindow].hash].next = null;
419 }
420
421 window[nextWindow].hash = hash;
422 window[nextWindow].value = i;
423 window[nextWindow].previous = null;
424 temp = window[nextWindow].next = hashtable[hash].next;
425 hashtable[hash].next = window[nextWindow];
426 if (temp !is null) {
427 temp.previous = window[nextWindow];
428 }
429
430 nextWindow = nextWindow + 1;
431 if (nextWindow is WINDOW) {
432 nextWindow = 0;
433 }
434
435 }
436
437 }
438
439 void compress() {
440
441 int position, newPosition;
442 byte[] data = new byte[3];
443 int hash;
444 for (int i = 0; i < HASH; i++) {
445 hashtable[i] = new Link();
446 }
447 for (int i = 0; i < WINDOW; i++) {
448 window[i] = new Link();
449 }
450 nextWindow = 0;
451 Link firstPosition;
452 Match match;
453 int deferredPosition = -1;
454 Match deferredMatch = null;
455
456 writeBits(0x01, 1); // BFINAL = 0x01 (final block)
457 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes)
458
459 // just output first byte so we never match at zero
460 outputLiteral(in[0]);
461 position = 1;
462
463 while (position < inLength) {
464
465 if (inLength - position < MIN_LENGTH) {
466 outputLiteral(in[position]);
467 position = position + 1;
468 continue;
469 }
470
471 data[0] = in[position];
472 data[1] = in[position + 1];
473 data[2] = in[position + 2];
474
475 hash = hash(data);
476 firstPosition = hashtable[hash];
477
478 match = findLongestMatch(position, firstPosition);
479
480 updateHashtable(position, position + 1);
481
482 if (match !is null) {
483
484 if (deferredMatch !is null) {
485 if (match.length > deferredMatch.length + 1) {
486 // output literal at deferredPosition
487 outputLiteral(in[deferredPosition]);
488 // defer this match
489 deferredPosition = position;
490 deferredMatch = match;
491 position = position + 1;
492 }
493 else {
494 // output deferredMatch
495 outputMatch(deferredMatch.length, deferredMatch.distance);
496 newPosition = deferredPosition + deferredMatch.length;
497 deferredPosition = -1;
498 deferredMatch = null;
499 updateHashtable(position + 1, newPosition);
500 position = newPosition;
501 }
502 }
503 else {
504 // defer this match
505 deferredPosition = position;
506 deferredMatch = match;
507 position = position + 1;
508 }
509
510 }
511
512 else {
513
514 // no match found
515 if (deferredMatch !is null) {
516 outputMatch(deferredMatch.length, deferredMatch.distance);
517 newPosition = deferredPosition + deferredMatch.length;
518 deferredPosition = -1;
519 deferredMatch = null;
520 updateHashtable(position + 1, newPosition);
521 position = newPosition;
522 }
523 else {
524 outputLiteral(in[position]);
525 position = position + 1;
526 }
527
528 }
529
530 }
531
532 writeBits(0, 7); // end of block code
533 alignToByte();
534
535 }
536
537 void compressHuffmanOnly() {
538
539 int position;
540
541 writeBits(0x01, 1); // BFINAL = 0x01 (final block)
542 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes)
543
544 for (position = 0; position < inLength;) {
545
546 outputLiteral(in[position]);
547 position = position + 1;
548
549 }
550
551 writeBits(0, 7); // end of block code
552 alignToByte();
553
554 }
555
556 void store() {
557
558 // stored blocks are limited to 0xffff bytes
559
560 int start = 0;
561 int length = inLength;
562 int blockLength;
563 int BFINAL = 0x00; // BFINAL = 0x00 or 0x01 (if final block), BTYPE = 0x00 (no compression)
564
565 while (length > 0) {
566
567 if (length < 65535) {
568 blockLength = length;
569 BFINAL = 0x01;
570 }
571 else {
572 blockLength = 65535;
573 BFINAL = 0x00;
574 }
575
576 // write data header
577 bytes.write((byte) BFINAL);
578 writeShortLSB(bytes, blockLength); // LEN
579 writeShortLSB(bytes, blockLength ^ 0xffff); // NLEN (one's complement of LEN)
580
581 // write actual data
582 bytes.write(in, start, blockLength);
583
584 length = length - blockLength;
585 start = start + blockLength;
586
587 }
588
589 }
590
591 public byte[] deflate(byte[] input) {
592
593 in = input;
594 inLength = input.length;
595
596 // write zlib header
597 bytes.write((byte) 0x78); // window size = 0x70 (32768), compression method = 0x08
598 bytes.write((byte) 0x9C); // compression level = 0x80 (default), check bits = 0x1C
599
600 // compute checksum
601 for (int i = 0; i < inLength; i++) {
602 updateAdler(in[i]);
603 }
604
605 //store();
606
607 //compressHuffmanOnly();
608
609 compress();
610
611 // write checksum
612 writeInt(bytes, adler32);
613
614 return bytes.toByteArray();
615
616 }
617
618 }