mirror of
https://github.com/1disk/edp445.git
synced 2024-08-14 22:47:02 +00:00
Changed alot of things.
This commit is contained in:
parent
a5a0523e5a
commit
3513d5390c
2016 changed files with 336930 additions and 9 deletions
353
node_modules/@skyra/gifenc/dist/lib/LZWEncoder.js
generated
vendored
Normal file
353
node_modules/@skyra/gifenc/dist/lib/LZWEncoder.js
generated
vendored
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
"use strict";
|
||||
/**
|
||||
* LZWEncoder
|
||||
*
|
||||
* Authors
|
||||
* - Kevin Weiner (original Java version - kweiner@fmsware.com)
|
||||
* - Thibault Imbert (AS3 version - bytearray.org)
|
||||
* - Johan Nordberg (JS version - code@johan-nordberg.com)
|
||||
* - Antonio Román (TS version - kyradiscord@gmail.com)
|
||||
*
|
||||
* Acknowledgements
|
||||
* - GIFCOMPR.C - GIF Image compression routines
|
||||
* - Lempel-Ziv compression based on 'compress'. GIF modifications by
|
||||
* - David Rowley (mgardi@watdcsu.waterloo.edu)
|
||||
* GIF Image compression - modified 'compress'
|
||||
* Based on: compress.c - File compression ala IEEE Computer, June 1984.
|
||||
* By Authors:
|
||||
* - Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
|
||||
* - Jim McKie (decvax!mcvax!jim)
|
||||
* - Steve Davies (decvax!vax135!petsd!peora!srd)
|
||||
* - Ken Turkowski (decvax!decwrl!turtlevax!ken)
|
||||
* - James A. Woods (decvax!ihnp4!ames!jaw)
|
||||
* - Joe Orost (decvax!vax135!petsd!joe)
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.LZWEncoder = void 0;
|
||||
const EOF = -1;
|
||||
const BITS = 12;
|
||||
const HASH_SIZE = 5003; // 80% occupancy
|
||||
const masks = new Uint16Array([
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||
]);
|
||||
/**
|
||||
* @summary
|
||||
* Algorithm: use open addressing double hashing (no chaining) on the prefix code / next character combination.
|
||||
*
|
||||
* We do a variant of Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
|
||||
* Here, the modular division first probe is gives way to a faster exclusive-or manipulation. Also do block compression
|
||||
* with an adaptive reset, whereby the code table is cleared when the compression ratio decreases, but after the table
|
||||
* fills. The variable-length output codes are re-sized at this point, and a special CLEAR code is generated for the
|
||||
* decompression.
|
||||
*
|
||||
* **Late addition**: construct the table according to file size for noticeable speed improvement on small files. Please
|
||||
* direct questions about this implementation to ames!jaw.
|
||||
*/
|
||||
class LZWEncoder {
|
||||
/**
|
||||
* Constructs a {@link LZWEncoder} instance.
|
||||
* @param width The width of the image.
|
||||
* @param height The height of the image.
|
||||
* @param pixels The pixel data in RGB format.
|
||||
* @param colorDepth The color depth.
|
||||
*/
|
||||
constructor(width, height, pixels, colorDepth) {
|
||||
/**
|
||||
* The GIF image's width, between `1` and `65536`.
|
||||
*/
|
||||
Object.defineProperty(this, "width", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
/**
|
||||
* The GIF image's height, between `1` and `65536`.
|
||||
*/
|
||||
Object.defineProperty(this, "height", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "pixels", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "initCodeSize", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "currentAccumulator", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "currentBits", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "currentPixel", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "accumulator", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "firstUnusedEntry", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
}); // first unused entry
|
||||
Object.defineProperty(this, "maximumCode", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "remaining", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "bitSize", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
// block compression parameters -- after all codes are used up,
|
||||
// and compression rate changes, start over.
|
||||
Object.defineProperty(this, "clearFlag", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: false
|
||||
});
|
||||
Object.defineProperty(this, "globalInitialBits", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "clearCode", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "endOfFrameCode", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "accumulators", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new Uint8Array(256)
|
||||
});
|
||||
Object.defineProperty(this, "hashes", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new Int32Array(HASH_SIZE)
|
||||
});
|
||||
Object.defineProperty(this, "codes", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new Int32Array(HASH_SIZE)
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.pixels = pixels;
|
||||
this.initCodeSize = Math.max(2, colorDepth);
|
||||
}
|
||||
/**
|
||||
* Encodes the image into the output.
|
||||
* @param output The byte buffer to write to.
|
||||
*/
|
||||
encode(output) {
|
||||
output.writeByte(this.initCodeSize); // write "initial code size" byte
|
||||
this.remaining = this.width * this.height; // reset navigation variables
|
||||
this.currentPixel = 0;
|
||||
this.compress(this.initCodeSize + 1, output); // compress and write the pixel data
|
||||
output.writeByte(0); // write block terminator
|
||||
}
|
||||
/**
|
||||
* Compresses the GIF data.
|
||||
* @param initialBits The initial bits for the compression.
|
||||
* @param output The byte buffer to write to.
|
||||
*/
|
||||
compress(initialBits, output) {
|
||||
// Set up the globals: globalInitialBits - initial number of bits
|
||||
this.globalInitialBits = initialBits;
|
||||
// Set up the necessary values
|
||||
this.clearFlag = false;
|
||||
this.bitSize = this.globalInitialBits;
|
||||
this.maximumCode = this.getMaximumCode(this.bitSize);
|
||||
this.clearCode = 1 << (initialBits - 1);
|
||||
this.endOfFrameCode = this.clearCode + 1;
|
||||
this.firstUnusedEntry = this.clearCode + 2;
|
||||
// Clear packet
|
||||
this.accumulator = 0;
|
||||
let code = this.nextPixel();
|
||||
let hash = 80048;
|
||||
const hashShift = 4;
|
||||
const hashSizeRegion = HASH_SIZE;
|
||||
this.resetHashRange(hashSizeRegion);
|
||||
this.processOutput(this.clearCode, output);
|
||||
let c;
|
||||
outerLoop: while ((c = this.nextPixel()) !== EOF) {
|
||||
hash = (c << BITS) + code;
|
||||
// XOR hashing:
|
||||
let i = (c << hashShift) ^ code;
|
||||
if (this.hashes[i] === hash) {
|
||||
code = this.codes[i];
|
||||
continue;
|
||||
}
|
||||
if (this.hashes[i] >= 0) {
|
||||
// Non-empty slot, perform secondary hash (after G. Knott):
|
||||
let dispose = hashSizeRegion - i;
|
||||
if (i === 0)
|
||||
dispose = 1;
|
||||
do {
|
||||
if ((i -= dispose) < 0)
|
||||
i += hashSizeRegion;
|
||||
if (this.hashes[i] === hash) {
|
||||
code = this.codes[i];
|
||||
continue outerLoop;
|
||||
}
|
||||
} while (this.hashes[i] >= 0);
|
||||
}
|
||||
this.processOutput(code, output);
|
||||
code = c;
|
||||
if (this.firstUnusedEntry < 1 << BITS) {
|
||||
// code -> hash-table
|
||||
this.codes[i] = this.firstUnusedEntry++;
|
||||
this.hashes[i] = hash;
|
||||
}
|
||||
else {
|
||||
this.clearCodeTable(output);
|
||||
}
|
||||
}
|
||||
// Put out the final code:
|
||||
this.processOutput(code, output);
|
||||
this.processOutput(this.endOfFrameCode, output);
|
||||
}
|
||||
/**
|
||||
* Adds a character to the end of the current packet, and if it is at 254 characters, it flushes the packet to disk
|
||||
* via {@link LZWEncoder.flushPacket}.
|
||||
* @param c The character code to add.
|
||||
* @param output The byte buffer to write to.
|
||||
*/
|
||||
addCharacter(c, output) {
|
||||
this.accumulators[this.accumulator++] = c;
|
||||
if (this.accumulator >= 254)
|
||||
this.flushPacket(output);
|
||||
}
|
||||
/**
|
||||
* Clears out the hash table for block compress.
|
||||
* @param output The byte buffer to write to.
|
||||
*/
|
||||
clearCodeTable(output) {
|
||||
this.resetHashRange(HASH_SIZE);
|
||||
this.firstUnusedEntry = this.clearCode + 2;
|
||||
this.clearFlag = true;
|
||||
this.processOutput(this.clearCode, output);
|
||||
}
|
||||
/**
|
||||
* Resets the hash table given an amount of hashes.
|
||||
* @param hashSize The amount of hashes to reset.
|
||||
*/
|
||||
resetHashRange(hashSize) {
|
||||
this.hashes.fill(-1, 0, hashSize);
|
||||
}
|
||||
/**
|
||||
* Flushes the packet to disk, and reset the accumulator.
|
||||
* @param output The byte buffer to write to.
|
||||
*/
|
||||
flushPacket(output) {
|
||||
if (this.accumulator > 0) {
|
||||
output.writeByte(this.accumulator);
|
||||
output.writeBytes(this.accumulators, 0, this.accumulator);
|
||||
this.accumulator = 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the maximum representable number for a given amount of bits.
|
||||
* @param size The bit size to get the number from.
|
||||
* @returns The maximum code given a number of bits.
|
||||
* @example
|
||||
* ```typescript
|
||||
* getMaximumCode(6);
|
||||
* // ➡ 0b0011_1111
|
||||
* ```
|
||||
*/
|
||||
getMaximumCode(size) {
|
||||
return (1 << size) - 1;
|
||||
}
|
||||
/**
|
||||
* Gets the next pixel from the image.
|
||||
* @returns The next pixel from the image.
|
||||
*/
|
||||
nextPixel() {
|
||||
if (this.remaining === 0)
|
||||
return EOF;
|
||||
--this.remaining;
|
||||
const pixel = this.pixels[this.currentPixel++];
|
||||
return pixel & 0xff;
|
||||
}
|
||||
processOutput(code, outs) {
|
||||
this.currentAccumulator &= masks[this.currentBits];
|
||||
this.currentAccumulator = this.currentBits > 0 ? (this.currentAccumulator |= code << this.currentBits) : code;
|
||||
this.currentBits += this.bitSize;
|
||||
while (this.currentBits >= 8) {
|
||||
this.addCharacter(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.firstUnusedEntry > this.maximumCode || this.clearFlag) {
|
||||
if (this.clearFlag) {
|
||||
this.maximumCode = this.getMaximumCode((this.bitSize = this.globalInitialBits));
|
||||
this.clearFlag = false;
|
||||
}
|
||||
else {
|
||||
++this.bitSize;
|
||||
if (this.bitSize === BITS)
|
||||
this.maximumCode = 1 << BITS;
|
||||
else
|
||||
this.maximumCode = this.getMaximumCode(this.bitSize);
|
||||
}
|
||||
}
|
||||
if (code === this.endOfFrameCode) {
|
||||
// At EOF, write the rest of the buffer.
|
||||
while (this.currentBits > 0) {
|
||||
this.addCharacter(this.currentAccumulator & 0xff, outs);
|
||||
this.currentAccumulator >>= 8;
|
||||
this.currentBits -= 8;
|
||||
}
|
||||
this.flushPacket(outs);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.LZWEncoder = LZWEncoder;
|
||||
//# sourceMappingURL=LZWEncoder.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue