vrchat-emoji-manager/dep/gifuct/lzw.js
2024-10-12 21:48:16 -07:00

119 lines
2.8 KiB
JavaScript

/**
* javascript port of java LZW decompression
* Original java author url: https://gist.github.com/devunwired/4479231
*/
export const lzw = (minCodeSize, data, pixelCount) => {
const MAX_STACK_SIZE = 4096
const nullCode = -1
const npix = pixelCount
var available,
clear,
code_mask,
code_size,
end_of_information,
in_code,
old_code,
bits,
code,
i,
datum,
data_size,
first,
top,
bi,
pi
const dstPixels = new Array(pixelCount)
const prefix = new Array(MAX_STACK_SIZE)
const suffix = new Array(MAX_STACK_SIZE)
const pixelStack = new Array(MAX_STACK_SIZE + 1)
// Initialize GIF data stream decoder.
data_size = minCodeSize
clear = 1 << data_size
end_of_information = clear + 1
available = clear + 2
old_code = nullCode
code_size = data_size + 1
code_mask = (1 << code_size) - 1
for (code = 0; code < clear; code++) {
prefix[code] = 0
suffix[code] = code
}
// Decode GIF pixel stream.
var datum, bits, count, first, top, pi, bi
datum = bits = count = first = top = pi = bi = 0
for (i = 0; i < npix; ) {
if (top === 0) {
if (bits < code_size) {
// get the next byte
datum += data[bi] << bits
bits += 8
bi++
continue
}
// Get the next code.
code = datum & code_mask
datum >>= code_size
bits -= code_size
// Interpret the code
if (code > available || code == end_of_information) {
break
}
if (code == clear) {
// Reset decoder.
code_size = data_size + 1
code_mask = (1 << code_size) - 1
available = clear + 2
old_code = nullCode
continue
}
if (old_code == nullCode) {
pixelStack[top++] = suffix[code]
old_code = code
first = code
continue
}
in_code = code
if (code == available) {
pixelStack[top++] = first
code = old_code
}
while (code > clear) {
pixelStack[top++] = suffix[code]
code = prefix[code]
}
first = suffix[code] & 0xff
pixelStack[top++] = first
// add a new string to the table, but only if space is available
// if not, just continue with current table until a clear code is found
// (deferred clear code implementation as per GIF spec)
if (available < MAX_STACK_SIZE) {
prefix[available] = old_code
suffix[available] = first
available++
if ((available & code_mask) === 0 && available < MAX_STACK_SIZE) {
code_size++
code_mask += available
}
}
old_code = in_code
}
// Pop a pixel off the pixel stack.
top--
dstPixels[pi++] = pixelStack[top]
i++
}
for (i = pi; i < npix; i++) {
dstPixels[i] = 0 // clear missing pixels
}
return dstPixels
}