Mercurial > projects > dwt-mac
diff dwt/internal/image/PngDeflater.d @ 34:5123b17c98ef
Ported dwt.events.*, dwt.graphics.GC, Region, dwt.internal.image.*
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sun, 14 Sep 2008 01:45:57 +0200 |
parents | e831403a80a9 |
children |
line wrap: on
line diff
--- a/dwt/internal/image/PngDeflater.d Fri Sep 12 13:53:21 2008 +0200 +++ b/dwt/internal/image/PngDeflater.d Sun Sep 14 01:45:57 2008 +0200 @@ -1,5 +1,5 @@ -/******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,44 +7,50 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> *******************************************************************************/ -module dwt.internal.image; +module dwt.internal.image.PngDeflater; -import java.io.ByteArrayOutputStream; +import dwt.dwthelper.ByteArrayOutputStream; public class PngDeflater { - static final int BASE = 65521; - static final int WINDOW = 32768; - static final int MIN_LENGTH = 3; - static final int MAX_MATCHES = 32; - static final int HASH = 8209; - - byte[] in; + static const int BASE = 65521; + static const int WINDOW = 32768; + static const int MIN_LENGTH = 3; + static const int MAX_MATCHES = 32; + static const int HASH = 8209; + + byte[] istr; int inLength; - - ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024); - + + ByteArrayOutputStream bytes; + int adler32 = 1; - + int buffer, bitCount; - - Link[] hashtable = new Link[HASH]; - Link[] window = new Link[WINDOW]; + + Link[HASH] hashtable;// = new Link[HASH]; + Link[WINDOW] window;// = new Link[WINDOW]; int nextWindow; -static class Link { +public this(){ + bytes = new ByteArrayOutputStream(1024); +} + +class Link { int hash, value; Link previous, next; - + this() { - + this.hash = 0; this.value = 0; this.previous = null; this.next = null; - + } } @@ -52,17 +58,17 @@ static class Match { int length, distance; - + this(int length, int distance) { - + this.length = length; this.distance = distance; - + } } -static final short mirrorBytes[] = { +static const short mirrorBytes[] = [ cast(short) 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, @@ -97,97 +103,96 @@ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, -}; +]; static class Code { int code, extraBits, min, max; - + this(int code, int extraBits, int min, int max) { - + this.code = code; this.extraBits = extraBits; this.min = min; this.max = max; - + } } -static final Code lengthCodes[] = { - - new Code(257, 0, 3, 3), - new Code(258, 0, 4, 4), - new Code(259, 0, 5, 5), - new Code(260, 0, 6, 6), - new Code(261, 0, 7, 7), - new Code(262, 0, 8, 8), - new Code(263, 0, 9, 9), - new Code(264, 0, 10, 10), - new Code(265, 1, 11, 12), - new Code(266, 1, 13, 14), - new Code(267, 1, 15, 16), - new Code(268, 1, 17, 18), - new Code(269, 2, 19, 22), - new Code(270, 2, 23, 26), - new Code(271, 2, 27, 30), - new Code(272, 2, 31, 34), - new Code(273, 3, 35, 42), - new Code(274, 3, 43, 50), - new Code(275, 3, 51, 58), - new Code(276, 3, 59, 66), - new Code(277, 4, 67, 82), - new Code(278, 4, 83, 98), - new Code(279, 4, 99, 114), - new Code(280, 4, 115, 130), - new Code(281, 5, 131, 162), - new Code(282, 5, 163, 194), - new Code(283, 5, 195, 226), - new Code(284, 5, 227, 257), - new Code(285, 0, 258, 258) - -}; +static const Code lengthCodes[]; +static const Code distanceCodes[]; -static final Code distanceCodes[] = { +static this() { + lengthCodes = [ + new Code(257, 0, 3, 3), + new Code(258, 0, 4, 4), + new Code(259, 0, 5, 5), + new Code(260, 0, 6, 6), + new Code(261, 0, 7, 7), + new Code(262, 0, 8, 8), + new Code(263, 0, 9, 9), + new Code(264, 0, 10, 10), + new Code(265, 1, 11, 12), + new Code(266, 1, 13, 14), + new Code(267, 1, 15, 16), + new Code(268, 1, 17, 18), + new Code(269, 2, 19, 22), + new Code(270, 2, 23, 26), + new Code(271, 2, 27, 30), + new Code(272, 2, 31, 34), + new Code(273, 3, 35, 42), + new Code(274, 3, 43, 50), + new Code(275, 3, 51, 58), + new Code(276, 3, 59, 66), + new Code(277, 4, 67, 82), + new Code(278, 4, 83, 98), + new Code(279, 4, 99, 114), + new Code(280, 4, 115, 130), + new Code(281, 5, 131, 162), + new Code(282, 5, 163, 194), + new Code(283, 5, 195, 226), + new Code(284, 5, 227, 257), + new Code(285, 0, 258, 258)]; - new Code(0, 0, 1, 1), - new Code(1, 0, 2, 2), - new Code(2, 0, 3, 3), - new Code(3, 0, 4, 4), - new Code(4, 1, 5, 6), - new Code(5, 1, 7, 8), - new Code(6, 2, 9, 12), - new Code(7, 2, 13, 16), - new Code(8, 3, 17, 24), - new Code(9, 3, 25, 32), - new Code(10, 4, 33, 48), - new Code(11, 4, 49, 64), - new Code(12, 5, 65, 96), - new Code(13, 5, 97, 128), - new Code(14, 6, 129, 192), - new Code(15, 6, 193, 256), - new Code(16, 7, 257, 384), - new Code(17, 7, 385, 512), - new Code(18, 8, 513, 768), - new Code(19, 8, 769, 1024), - new Code(20, 9, 1025, 1536), - new Code(21, 9, 1537, 2048), - new Code(22, 10, 2049, 3072), - new Code(23, 10, 3073, 4096), - new Code(24, 11, 4097, 6144), - new Code(25, 11, 6145, 8192), - new Code(26, 12, 8193, 12288), - new Code(27, 12, 12289, 16384), - new Code(28, 13, 16385, 24576), - new Code(29, 13, 24577, 32768) - -}; + distanceCodes = [ + new Code(0, 0, 1, 1), + new Code(1, 0, 2, 2), + new Code(2, 0, 3, 3), + new Code(3, 0, 4, 4), + new Code(4, 1, 5, 6), + new Code(5, 1, 7, 8), + new Code(6, 2, 9, 12), + new Code(7, 2, 13, 16), + new Code(8, 3, 17, 24), + new Code(9, 3, 25, 32), + new Code(10, 4, 33, 48), + new Code(11, 4, 49, 64), + new Code(12, 5, 65, 96), + new Code(13, 5, 97, 128), + new Code(14, 6, 129, 192), + new Code(15, 6, 193, 256), + new Code(16, 7, 257, 384), + new Code(17, 7, 385, 512), + new Code(18, 8, 513, 768), + new Code(19, 8, 769, 1024), + new Code(20, 9, 1025, 1536), + new Code(21, 9, 1537, 2048), + new Code(22, 10, 2049, 3072), + new Code(23, 10, 3073, 4096), + new Code(24, 11, 4097, 6144), + new Code(25, 11, 6145, 8192), + new Code(26, 12, 8193, 12288), + new Code(27, 12, 12289, 16384), + new Code(28, 13, 16385, 24576), + new Code(29, 13, 24577, 32768)]; +} void writeShortLSB(ByteArrayOutputStream baos, int theShort) { byte byte1 = cast(byte) (theShort & 0xff); byte byte2 = cast(byte) ((theShort >> 8) & 0xff); - byte[] temp = {byte1, byte2}; + byte[] temp = [byte1, byte2]; baos.write(temp, 0, 2); } @@ -198,7 +203,7 @@ byte byte2 = cast(byte) ((theInt >> 16) & 0xff); byte byte3 = cast(byte) ((theInt >> 8) & 0xff); byte byte4 = cast(byte) (theInt & 0xff); - byte[] temp = {byte1, byte2, byte3, byte4}; + byte[] temp = [byte1, byte2, byte3, byte4]; baos.write(temp, 0, 4); } @@ -251,7 +256,7 @@ void outputLiteral(byte literal) { int i = literal & 0xff; - + if (i <= 143) { // 0 through 143 are 8 bits long starting at 00110000 writeBits(mirrorBytes[0x30 + i], 8); @@ -266,7 +271,7 @@ Code findCode(int value, Code[] codes) { int i, j, k; - + i = -1; j = codes.length; while (true) { @@ -288,13 +293,13 @@ Code d, l; int thisLength; - + while (length > 0) { // we can transmit matches of lengths 3 through 258 inclusive // so if length exceeds 258, we must transmit in several steps, // with 258 or less in each step - + if (length > 260) { thisLength = 258; } @@ -304,12 +309,12 @@ else { thisLength = length - 3; } - + length = length - thisLength; - + // find length code l = findCode(thisLength, lengthCodes); - + // transmit the length code // 256 through 279 are 7 bits long starting at 0000000 // 280 through 287 are 8 bits long starting at 11000000 @@ -319,24 +324,24 @@ else { writeBits(mirrorBytes[0xc0 - 280 + l.code], 8); } - + // transmit the extra bits if (l.extraBits !is 0) { writeBits(thisLength - l.min, l.extraBits); } - + // find distance code d = findCode(distance, distanceCodes); - + // transmit the distance code // 5 bits long starting at 00000 writeBits(mirrorBytes[d.code * 8], 5); - + // transmit the extra bits if (d.extraBits !is 0) { writeBits(distance - d.min, d.extraBits); } - + } } @@ -346,92 +351,92 @@ Link link = firstPosition; int numberOfMatches = 0; Match bestMatch = new Match(-1, -1); - + while (true) { - + int matchPosition = link.value; - + if (position - matchPosition < WINDOW && matchPosition !is 0) { int i; - + for (i = 1; position + i < inLength; i++) { - if (in[position + i] !is in[matchPosition + i]) { + if (istr[position + i] !is istr[matchPosition + i]) { break; } } - + if (i >= MIN_LENGTH) { - + if (i > bestMatch.length) { bestMatch.length = i; bestMatch.distance = position - matchPosition; } - + numberOfMatches = numberOfMatches + 1; - + if (numberOfMatches is MAX_MATCHES) { break; } - + } - + } - + link = link.next; if (link is null) { break; } - + } - + if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) { return null; } - - return bestMatch; + + return bestMatch; } void updateHashtable(int to, int from) { byte[] data = new byte[3]; - int hash; + int hashval; Link temp; - + for (int i = to; i < from; i++) { - + if (i + MIN_LENGTH > inLength) { break; } - - data[0] = in[i]; - data[1] = in[i + 1]; - data[2] = in[i + 2]; - - hash = hash(data); - + + data[0] = istr[i]; + data[1] = istr[i + 1]; + data[2] = istr[i + 2]; + + hashval = hash(data); + if (window[nextWindow].previous !is null) { window[nextWindow].previous.next = null; } else if (window[nextWindow].hash !is 0) { hashtable[window[nextWindow].hash].next = null; } - - window[nextWindow].hash = hash; + + window[nextWindow].hash = hashval; window[nextWindow].value = i; window[nextWindow].previous = null; - temp = window[nextWindow].next = hashtable[hash].next; - hashtable[hash].next = window[nextWindow]; + temp = window[nextWindow].next = hashtable[hashval].next; + hashtable[hashval].next = window[nextWindow]; if (temp !is null) { temp.previous = window[nextWindow]; } - + nextWindow = nextWindow + 1; if (nextWindow is WINDOW) { nextWindow = 0; } - + } } @@ -440,7 +445,7 @@ int position, newPosition; byte[] data = new byte[3]; - int hash; + int hashval; for (int i = 0; i < HASH; i++) { hashtable[i] = new Link(); } @@ -452,39 +457,39 @@ Match match; int deferredPosition = -1; Match deferredMatch = null; - + writeBits(0x01, 1); // BFINAL = 0x01 (final block) writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) - + // just output first byte so we never match at zero - outputLiteral(in[0]); + outputLiteral(istr[0]); position = 1; - + while (position < inLength) { - + if (inLength - position < MIN_LENGTH) { - outputLiteral(in[position]); + outputLiteral(istr[position]); position = position + 1; continue; } - - data[0] = in[position]; - data[1] = in[position + 1]; - data[2] = in[position + 2]; - - hash = hash(data); - firstPosition = hashtable[hash]; - + + data[0] = istr[position]; + data[1] = istr[position + 1]; + data[2] = istr[position + 2]; + + hashval = hash(data); + firstPosition = hashtable[hashval]; + match = findLongestMatch(position, firstPosition); - + updateHashtable(position, position + 1); - + if (match !is null) { - + if (deferredMatch !is null) { if (match.length > deferredMatch.length + 1) { // output literal at deferredPosition - outputLiteral(in[deferredPosition]); + outputLiteral(istr[deferredPosition]); // defer this match deferredPosition = position; deferredMatch = match; @@ -506,11 +511,11 @@ deferredMatch = match; position = position + 1; } - + } - + else { - + // no match found if (deferredMatch !is null) { outputMatch(deferredMatch.length, deferredMatch.distance); @@ -521,14 +526,14 @@ position = newPosition; } else { - outputLiteral(in[position]); + outputLiteral(istr[position]); position = position + 1; } - + } - + } - + writeBits(0, 7); // end of block code alignToByte(); @@ -537,17 +542,17 @@ void compressHuffmanOnly() { int position; - + writeBits(0x01, 1); // BFINAL = 0x01 (final block) writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) - + for (position = 0; position < inLength;) { - - outputLiteral(in[position]); + + outputLiteral(istr[position]); position = position + 1; - + } - + writeBits(0, 7); // end of block code alignToByte(); @@ -556,14 +561,14 @@ void store() { // stored blocks are limited to 0xffff bytes - + int start = 0; int length = inLength; int blockLength; int BFINAL = 0x00; // BFINAL = 0x00 or 0x01 (if final block), BTYPE = 0x00 (no compression) - + while (length > 0) { - + if (length < 65535) { blockLength = length; BFINAL = 0x01; @@ -572,45 +577,45 @@ blockLength = 65535; BFINAL = 0x00; } - + // write data header bytes.write(cast(byte) BFINAL); writeShortLSB(bytes, blockLength); // LEN writeShortLSB(bytes, blockLength ^ 0xffff); // NLEN (one's complement of LEN) - + // write actual data - bytes.write(in, start, blockLength); - + bytes.write(istr, start, blockLength); + length = length - blockLength; start = start + blockLength; - + } } public byte[] deflate(byte[] input) { - in = input; + istr = input; inLength = input.length; - + // write zlib header bytes.write(cast(byte) 0x78); // window size = 0x70 (32768), compression method = 0x08 bytes.write(cast(byte) 0x9C); // compression level = 0x80 (default), check bits = 0x1C - + // compute checksum for (int i = 0; i < inLength; i++) { - updateAdler(in[i]); + updateAdler(istr[i]); } - + //store(); - + //compressHuffmanOnly(); - + compress(); - + // write checksum writeInt(bytes, adler32); - + return bytes.toByteArray(); }