Browse Source

Some light refactoring

Former-commit-id: 5c94066bc5e020d9fc34364573c62c049aa5103f
Former-commit-id: 5e618f18b708c8b32d8014c1edf557bb9c6ddd64
Former-commit-id: b4c99c5191e2b0353853d50d34cd1d74148a91c7
af/merge-core
James Jackson-South 11 years ago
parent
commit
e707d21b85
  1. 192
      src/ImageProcessor/Formats/Gif/LzwEncoder.cs

192
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'
/// <summary>
/// Number of characters so far in this 'packet'
/// </summary>
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);

Loading…
Cancel
Save