From e707d21b8508a08bbac13c2e93db7413000cfcb0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 30 Aug 2015 23:14:50 +1000 Subject: [PATCH] Some light refactoring Former-commit-id: 5c94066bc5e020d9fc34364573c62c049aa5103f Former-commit-id: 5e618f18b708c8b32d8014c1edf557bb9c6ddd64 Former-commit-id: b4c99c5191e2b0353853d50d34cd1d74148a91c7 --- src/ImageProcessor/Formats/Gif/LzwEncoder.cs | 192 +++++++++++-------- 1 file changed, 107 insertions(+), 85 deletions(-) diff --git a/src/ImageProcessor/Formats/Gif/LzwEncoder.cs b/src/ImageProcessor/Formats/Gif/LzwEncoder.cs index 28057496b..b6af73e5d 100644 --- a/src/ImageProcessor/Formats/Gif/LzwEncoder.cs +++ b/src/ImageProcessor/Formats/Gif/LzwEncoder.cs @@ -14,6 +14,45 @@ private readonly byte[] pixAry; private readonly int initCodeSize; + + // output + // + // Output the given code. + // Inputs: + // code: A n_bits-bit integer. If == -1, then EOF. This assumes + // that n_bits =< wordsize - 1. + // Outputs: + // Outputs code to the file. + // Assumptions: + // Chars are 8 bits long. + // Algorithm: + // Maintain a BITS character long buffer (so that 8 codes will + // fit in it exactly). Use the VAX insv instruction to insert each + // code in turn. When the buffer fills up empty it and start over. + private readonly int[] masks = + { + 0x0000, // 0 + 0x0001, // 1 + 0x0003, // 3 + 0x0007, // 7 + 0x000F, // 15 + 0x001F, // 31 + 0x003F, // 63 + 0x007F, // 127 + 0x00FF, // 255 + 0x01FF, // 511 + 0x03FF, // 1023 + 0x07FF, // 2047 + 0x0FFF, // 4095 + 0x1FFF, // 8191 + 0x3FFF, // 16383 + 0x7FFF, // 32767 + 0xFFFF // 65535 + }; + + // Define the storage for the packet accumulator + private readonly byte[] accumulatorBytes = new byte[256]; + private int remaining; private int curPixel; @@ -49,11 +88,11 @@ private int hsize = HSIZE; // for dynamic table sizing - private int free_ent = 0; // first unused entry + private int freeEntry = 0; // first unused entry // block compression parameters -- after all codes are used up, // and compression rate changes, start over. - private bool clear_flg; + private bool clearFlag; // Algorithm: use open addressing double hashing (no chaining) on the // prefix code / next character combination. We do a variant of Knuth's @@ -72,50 +111,15 @@ private int ClearCode; private int EOFCode; - // output - // - // Output the given code. - // Inputs: - // code: A n_bits-bit integer. If == -1, then EOF. This assumes - // that n_bits =< wordsize - 1. - // Outputs: - // Outputs code to the file. - // Assumptions: - // Chars are 8 bits long. - // Algorithm: - // Maintain a BITS character long buffer (so that 8 codes will - // fit in it exactly). Use the VAX insv instruction to insert each - // code in turn. When the buffer fills up empty it and start over. + private int currentAccumulator; - private int cur_accum = 0; - private int cur_bits = 0; + private int currentBits; - private readonly int[] masks = - { - 0x0000, // 0 - 0x0001, // 1 - 0x0003, // 3 - 0x0007, // 7 - 0x000F, // 15 - 0x001F, // 31 - 0x003F, // 63 - 0x007F, // 127 - 0x00FF, // 255 - 0x01FF, // 511 - 0x03FF, // 1023 - 0x07FF, // 2047 - 0x0FFF, // 4095 - 0x1FFF, // 8191 - 0x3FFF, // 16383 - 0x7FFF, // 32767 - 0xFFFF }; // 65535 - - // Number of characters so far in this 'packet' + /// + /// Number of characters so far in this 'packet' + /// private int accumulatorCount; - // Define the storage for the packet accumulator - private readonly byte[] accumulatorBytes = new byte[256]; - public LzwEncoder(int width, int height, byte[] pixels, int colorDepth) { this.imgW = width; @@ -124,13 +128,27 @@ this.initCodeSize = Math.Max(2, colorDepth); } + public void Encode(Stream stream) + { + stream.WriteByte((byte)this.initCodeSize); // write "initial code size" byte + + this.remaining = this.imgW * this.imgH; // reset navigation variables + this.curPixel = 0; + + this.Compress(this.initCodeSize + 1, stream); // compress and write the pixel data + + stream.WriteByte(0); // write block terminator + } + // Add a character to the end of the current packet, and if it is 254 // characters, flush the packet to disk. private void CharOut(byte character, Stream stream) { this.accumulatorBytes[this.accumulatorCount++] = character; if (this.accumulatorCount >= 254) + { this.FlushChar(stream); + } } // Clear out the hash table @@ -139,8 +157,8 @@ private void ClearBlock(Stream outs) { this.ClearHashTable(this.hsize); - this.free_ent = this.ClearCode + 2; - this.clear_flg = true; + this.freeEntry = this.ClearCode + 2; + this.clearFlag = true; this.Output(this.ClearCode, outs); } @@ -151,14 +169,12 @@ for (int i = 0; i < hsize; ++i) { this.htab[i] = -1; - } } private void Compress(int init_bits, Stream outs) { int fcode; - int i /* = 0 */; int c; int ent; int disp; @@ -169,13 +185,13 @@ this.globalInitialBits = init_bits; // Set up the necessary values - this.clear_flg = false; + this.clearFlag = false; this.numberOfBits = this.globalInitialBits; this.maxcode = this.MAXCODE(this.numberOfBits); this.ClearCode = 1 << (init_bits - 1); this.EOFCode = this.ClearCode + 1; - this.free_ent = this.ClearCode + 2; + this.freeEntry = this.ClearCode + 2; this.accumulatorCount = 0; // clear packet @@ -183,7 +199,10 @@ hshift = 0; for (fcode = this.hsize; fcode < 65536; fcode *= 2) + { ++hshift; + } + hshift = 8 - hshift; // set hash code range bound hsize_reg = this.hsize; @@ -196,7 +215,7 @@ while ((c = this.NextPixel()) != EOF) { fcode = (c << this.maxbits) + ent; - i = c << hshift ^ ent; // xor hashing + int i = c << hshift ^ ent; if (this.htab[i] == fcode) { @@ -204,29 +223,37 @@ continue; } - if (this.htab[i] >= 0) // non-empty slot + // non-empty slot + if (this.htab[i] >= 0) { disp = hsize_reg - i; // secondary hash (after G. Knott) - if (i == 0) disp = 1; + if (i == 0) + { + disp = 1; + } + do { - if ((i -= disp) < 0) i += hsize_reg; + if ((i -= disp) < 0) + { + i += hsize_reg; + } if (this.htab[i] == fcode) { ent = this.codetab[i]; goto outer_loop; } - - } while (this.htab[i] >= 0); + } + while (this.htab[i] >= 0); } this.Output(ent, outs); ent = c; - if (this.free_ent < this.maxmaxcode) + if (this.freeEntry < this.maxmaxcode) { - this.codetab[i] = this.free_ent++; // code -> hashtable + this.codetab[i] = this.freeEntry++; // code -> hashtable this.htab[i] = fcode; } else @@ -240,19 +267,6 @@ this.Output(this.EOFCode, outs); } - //---------------------------------------------------------------------------- - public void Encode(Stream stream) - { - stream.WriteByte((byte)this.initCodeSize); // write "initial code size" byte - - this.remaining = this.imgW * this.imgH; // reset navigation variables - this.curPixel = 0; - - this.Compress(this.initCodeSize + 1, stream); // compress and write the pixel data - - stream.WriteByte(0); // write block terminator - } - // Flush the packet to disk, and reset the accumulator private void FlushChar(Stream stream) { @@ -275,7 +289,9 @@ private int NextPixel() { if (this.remaining == 0) + { return EOF; + } --this.remaining; @@ -284,30 +300,36 @@ return pix & 0xff; } - void Output(int code, Stream outs) + private void Output(int code, Stream outs) { - this.cur_accum &= this.masks[this.cur_bits]; + this.currentAccumulator &= this.masks[this.currentBits]; - if (this.cur_bits > 0) this.cur_accum |= (code << this.cur_bits); - else this.cur_accum = code; + if (this.currentBits > 0) + { + this.currentAccumulator |= code << this.currentBits; + } + else + { + this.currentAccumulator = code; + } - this.cur_bits += this.numberOfBits; + this.currentBits += this.numberOfBits; - while (this.cur_bits >= 8) + while (this.currentBits >= 8) { - this.CharOut((byte)(this.cur_accum & 0xff), outs); - this.cur_accum >>= 8; - this.cur_bits -= 8; + this.CharOut((byte)(this.currentAccumulator & 0xff), outs); + this.currentAccumulator >>= 8; + this.currentBits -= 8; } // If the next entry is going to be too big for the code size, // then increase it, if possible. - if (this.free_ent > this.maxcode || this.clear_flg) + if (this.freeEntry > this.maxcode || this.clearFlag) { - if (this.clear_flg) + if (this.clearFlag) { this.maxcode = this.MAXCODE(this.numberOfBits = this.globalInitialBits); - this.clear_flg = false; + this.clearFlag = false; } else { @@ -321,11 +343,11 @@ if (code == this.EOFCode) { // At EOF, write the rest of the buffer. - while (this.cur_bits > 0) + while (this.currentBits > 0) { - this.CharOut((byte)(this.cur_accum & 0xff), outs); - this.cur_accum >>= 8; - this.cur_bits -= 8; + this.CharOut((byte)(this.currentAccumulator & 0xff), outs); + this.currentAccumulator >>= 8; + this.currentBits -= 8; } this.FlushChar(outs);