big updat:

- update dependencies
- add webp support and webp conversion for profile images
This commit is contained in:
olcxja 2026-07-02 22:40:46 +02:00
commit 95aaaa69ea
244 changed files with 121382 additions and 86 deletions

3
node_modules/gifuct-js/.babelrc generated vendored Normal file
View file

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}

7
node_modules/gifuct-js/.prettierrc generated vendored Normal file
View file

@ -0,0 +1,7 @@
{
"singleQuote": true,
"write": true,
"semi": false,
"tabWidth": 2,
"printWidth": 80
}

22
node_modules/gifuct-js/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Matt Way
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

115
node_modules/gifuct-js/README.md generated vendored Normal file
View file

@ -0,0 +1,115 @@
# gifuct-js
A Simple to use javascript .GIF decoder.
We needed to be able to efficiently load and manipulate GIF files for the **[Ruffle][1]** hybrid app (for mobiles). There are a couple of example libraries out there like [jsgif][2] & its derivative [libgif-js][3], however these are admittedly inefficient, and a mess. After pulling our hair out trying to understand the ancient, mystic gif format (hence the project name), we decided to just roll our own. This library also removes any specific drawing code, and simply parses, and decompresses gif files so that you can manipulate and display them however you like. We do include `imageData` patch construction though to get you most of the way there.
### Demo
You can see a demo of this library in action **[here][4]**
### Usage
_Installation:_
npm install gifuct-js
_Decoding:_
This decoder uses **[js-binary-schema-parser][5]** to parse the gif files (you can examine the schema in the source). This means the gif file must firstly be converted into a `Uint8Array` buffer in order to decode it. Some examples:
- _fetch_
import { parseGIF, decompressFrames } from 'gifuct-js'
var promisedGif = fetch(gifURL)
.then(resp => resp.arrayBuffer())
.then(buff => parseGIF(buff))
.then(gif => decompressFrames(gif, true));
- _XMLHttpRequest_
import { parseGIF, decompressFrames } from 'gifuct-js'
var oReq = new XMLHttpRequest();
oReq.open("GET", gifURL, true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var gif = parseGIF(arrayBuffer);
var frames = decompressFrames(gif, true);
// do something with the frame data
}
};
oReq.send(null);
_Result:_
The result of the `decompressFrames(gif, buildPatch)` function returns an array of all the GIF image frames, and their meta data. Here is a an example frame:
{
// The color table lookup index for each pixel
pixels: [...],
// the dimensions of the gif frame (see disposal method)
dims: {
top: 0,
left: 10,
width: 100,
height: 50
},
// the time in milliseconds that this frame should be shown
delay: 50,
// the disposal method (see below)
disposalType: 1,
// an array of colors that the pixel data points to
colorTable: [...],
// An optional color index that represents transparency (see below)
transparentIndex: 33,
// Uint8ClampedArray color converted patch information for drawing
patch: [...]
}
_Automatic Patch Generation:_
If the `buildPatch` param of the `dcompressFrames()` function is `true`, the parser will not only return the parsed and decompressed gif frames, but will also create canvas ready `Uint8ClampedArray` arrays of each gif frame image, so that they can easily be drawn using `ctx.putImageData()` for example. This requirement is common, however it was made optional because it makes assumptions about transparency. The [demo][4] makes use of this option.
_Disposal Method:_
The `pixel` data is stored as a list of indexes for each pixel. These each point to a value in the `colorTable` array, which contain the color that each pixel should be drawn. Each frame of the gif may not be the full size, but instead a patch that needs to be drawn over a particular location. The `disposalType` defines how that patch should be drawn over the gif canvas. In most cases, that value will be `1`, indicating that the gif frame should be simply drawn over the existing gif canvas without altering any pixels outside the frames patch dimensions. More can be read about this [here][6].
_Transparency:_
If a `transparentIndex` is defined for a frame, it means that any pixel within the pixel data that matches this index should not be drawn. When drawing the patch using canvas, this means setting the alpha value for this pixel to `0`.
### Drawing the GIF
Check out the **[demo][4]** for an example of how to draw/manipulate a gif using this library. We wanted the library to be drawing agnostic to allow users to do what they wish with the raw gif data, rather than impose a method that has to be altered. On this note however, we provide an easy interface for creating commonly used canvas pixel data for drawing ease.
### Thanks to
We underestimated the convolutedness of the GIF format, so this library couldn't have been made without the help of:
- [Project: What's In A GIF - Bit by Byte][7] - An amazingly detailed blog by Matthew Flickinger
- [jsgif][2]
- The [*almost correct*] LZW decompression from [this neat gist][8]
### Who are we?
[Matt Way][9] & [Nick Drewe][10]
[Wethrift.com][11]
[1]: https://www.producthunt.com/posts/ruffle
[2]: http://slbkbs.org/jsgif/
[3]: https://github.com/buzzfeed/libgif-js
[4]: http://matt-way.github.io/gifuct-js/
[5]: https://github.com/matt-way/jsBinarySchemaParser
[6]: http://www.matthewflickinger.com/lab/whatsinagif/animation_and_transparency.asp
[7]: http://www.matthewflickinger.com/lab/whatsinagif/index.html
[8]: https://gist.github.com/devunwired/4479231
[9]: https://twitter.com/_MattWay
[10]: https://twitter.com/nickdrewe
[11]: https://wethrift.com

1018
node_modules/gifuct-js/demo/demo.build.js generated vendored Normal file

File diff suppressed because it is too large Load diff

0
node_modules/gifuct-js/demo/demo.css generated vendored Normal file
View file

230
node_modules/gifuct-js/demo/demo.js generated vendored Normal file
View file

@ -0,0 +1,230 @@
import { parseGIF, decompressFrames } from '../lib/index.js'
// user canvas
var c = document.getElementById('c')
var ctx = c.getContext('2d')
// gif patch canvas
var tempCanvas = document.createElement('canvas')
var tempCtx = tempCanvas.getContext('2d')
// full gif canvas
var gifCanvas = document.createElement('canvas')
var gifCtx = gifCanvas.getContext('2d')
var url = document.getElementById('url')
// default gif
url.value = '/demo/horses.gif'
document.getElementById('loadGIF').onclick = loadGIF
document.getElementById('playpause').onclick = playpause
document.getElementById('edgedetect').onchange = () => {
bEdgeDetect = !bEdgeDetect
}
document.getElementById('grayscale').onchange = () => {
bGrayscale = !bGrayscale
}
document.getElementById('invert').onchange = () => {
bInvert = !bInvert
}
document.getElementById('pixels').onchange = e => {
pixelPercent = e.target.value
}
// load the default gif
loadGIF()
var gif
// load a gif with the current input url value
function loadGIF() {
var oReq = new XMLHttpRequest()
oReq.open('GET', url.value, true)
oReq.responseType = 'arraybuffer'
oReq.onload = function(oEvent) {
var arrayBuffer = oReq.response // Note: not oReq.responseText
if (arrayBuffer) {
gif = parseGIF(arrayBuffer)
var frames = decompressFrames(gif, true)
// render the gif
renderGIF(frames)
}
}
oReq.send(null)
}
var playing = false
var bEdgeDetect = false
var bInvert = false
var bGrayscale = false
var pixelPercent = 100
var loadedFrames
var frameIndex
function playpause() {
playing = !playing
if (playing) {
renderFrame()
}
}
function renderGIF(frames) {
loadedFrames = frames
frameIndex = 0
c.width = frames[0].dims.width
c.height = frames[0].dims.height
gifCanvas.width = c.width
gifCanvas.height = c.height
if (!playing) {
playpause()
}
}
var frameImageData
function drawPatch(frame) {
var dims = frame.dims
if (
!frameImageData ||
dims.width != frameImageData.width ||
dims.height != frameImageData.height
) {
tempCanvas.width = dims.width
tempCanvas.height = dims.height
frameImageData = tempCtx.createImageData(dims.width, dims.height)
}
// set the patch data as an override
frameImageData.data.set(frame.patch)
// draw the patch back over the canvas
tempCtx.putImageData(frameImageData, 0, 0)
gifCtx.drawImage(tempCanvas, dims.left, dims.top)
}
var edge = function(data, output) {
var odata = output.data
var width = gif.lsd.width
var height = gif.lsd.height
var conv = [-1, -1, -1, -1, 8, -1, -1, -1, -1]
var halfside = Math.floor(3 / 2)
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var r = 0,
g = 0,
b = 0
for (var cy = 0; cy < 3; cy++) {
for (var cx = 0; cx < 3; cx++) {
var scy = y - halfside + cy
var scx = x - halfside + cx
if (scy >= 0 && scy < height && scx >= 0 && scx < width) {
var src = (scy * width + scx) * 4
var f = cy * 3 + cx
r += data[src] * conv[f]
g += data[src + 1] * conv[f]
b += data[src + 2] * conv[f]
}
}
}
var i = (y * width + x) * 4
odata[i] = r
odata[i + 1] = g
odata[i + 2] = b
odata[i + 3] = 255
}
}
return output
}
var invert = function(data) {
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i] // red
data[i + 1] = 255 - data[i + 1] // green
data[i + 2] = 255 - data[i + 2] // blue
data[i + 3] = 255
}
}
var grayscale = function(data) {
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i + 1] + data[i + 2]) / 3
data[i] = avg // red
data[i + 1] = avg // green
data[i + 2] = avg // blue
data[i + 3] = 255
}
}
function manipulate() {
var imageData = gifCtx.getImageData(0, 0, gifCanvas.width, gifCanvas.height)
var other = gifCtx.createImageData(gifCanvas.width, gifCanvas.height)
if (bEdgeDetect) {
imageData = edge(imageData.data, other)
}
if (bInvert) {
invert(imageData.data)
}
if (bGrayscale) {
grayscale(imageData.data)
}
// do pixelation
var pixelsX = 5 + Math.floor((pixelPercent / 100) * (c.width - 5))
var pixelsY = (pixelsX * c.height) / c.width
if (pixelPercent != 100) {
ctx.mozImageSmoothingEnabled = false
ctx.webkitImageSmoothingEnabled = false
ctx.imageSmoothingEnabled = false
}
ctx.putImageData(imageData, 0, 0)
ctx.drawImage(c, 0, 0, c.width, c.height, 0, 0, pixelsX, pixelsY)
ctx.drawImage(c, 0, 0, pixelsX, pixelsY, 0, 0, c.width, c.height)
}
function renderFrame() {
// get the frame
var frame = loadedFrames[frameIndex]
var start = new Date().getTime()
if (frame.disposalType === 2) {
gifCtx.clearRect(0, 0, c.width, c.height)
}
// draw the patch
drawPatch(frame)
// perform manipulation
manipulate()
// update the frame index
frameIndex++
if (frameIndex >= loadedFrames.length) {
frameIndex = 0
}
var end = new Date().getTime()
var diff = end - start
if (playing) {
// delay the next gif frame
setTimeout(function() {
requestAnimationFrame(renderFrame)
//renderFrame();
}, Math.max(0, Math.floor(frame.delay - diff)))
}
}

BIN
node_modules/gifuct-js/demo/dog.gif generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
node_modules/gifuct-js/demo/horses.gif generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

29
node_modules/gifuct-js/demo/index.html generated vendored Normal file
View file

@ -0,0 +1,29 @@
<html>
<head>
<title>gifuct-js demo</title>
</head>
<body>
<div>
<canvas id="c"></canvas>
</div>
<div style="margin: 10px 0;">
<input id="url" type="text" />
<button id="loadGIF">Load</button>
<button id="playpause">Play/Pause</button>
</div>
<div style="margin-bottom: 10px;">
<input id="edgedetect" type="checkbox" />
Edge Detect
<input id="invert" type="checkbox" />
Invert Colours
<input id="grayscale" type="checkbox" />
Grayscale
</div>
<div>
<input id="pixels" type="range" min="0" max="100" step="1" value="100" />
Pixelate Amount
</div>
<script src="demo.build.js"></script>
</body>
</html>

BIN
node_modules/gifuct-js/demo/jblack.gif generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

101
node_modules/gifuct-js/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,101 @@
type Application = {
application: {
blockSize: number
blocks: number[]
codes: number[]
id: string
}
}
type Frame = {
gce: {
byteSize: number
codes: number[]
delay: number
terminator: number
transparentColorIndex: number
extras: {
userInput: boolean
transparentColorGiven: boolean
future: number
disposal: number
}
}
image: {
code: number
data: {
minCodeSize: number
blocks: number[]
}
descriptor: {
top: number
left: number
width: number
height: number
lct: {
exists: boolean
future: number
interlaced: boolean
size: number
sort: boolean
}
}
}
}
export type ParsedGif = {
frames: (Application | Frame)[]
gct: [number, number, number][]
header: {
signature: string
version: string
}
lsd: {
backgroundColorIndex: number
gct: {
exists: boolean
resolution: number
size: number
sort: boolean
}
height: number
width: number
pixelAspectRatio: number
}
}
export type ParsedFrame = {
dims: { width: number; height: number; top: number; left: number }
colorTable: [number, number, number][]
delay: number
disposalType: number
patch: Uint8ClampedArray
pixels: number[]
transparentIndex: number
}
export type ParsedFrameWithoutPatch = Omit<ParsedFrame, 'patch'>
export function parseGIF(arrayBuffer: ArrayBuffer): ParsedGif
export function decompressFrames(
parsedGif: ParsedGif,
buildImagePatches: true
): ParsedFrame[]
export function decompressFrames(
parsedGif: ParsedGif,
buildImagePatches: false
): ParsedFrameWithoutPatch[]
export function decompressFrame(
frame: Frame,
gct: [number, number, number][],
buildImagePatches: true
): ParsedFrame
export function decompressFrame(
frame: Frame,
gct: [number, number, number][],
buildImagePatches: false
): ParsedFrameWithoutPatch

35
node_modules/gifuct-js/lib/deinterlace.js generated vendored Normal file
View file

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.deinterlace = void 0;
/**
* Deinterlace function from https://github.com/shachaf/jsgif
*/
var deinterlace = function deinterlace(pixels, width) {
var newPixels = new Array(pixels.length);
var rows = pixels.length / width;
var cpRow = function cpRow(toRow, fromRow) {
var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
}; // See appendix E.
var offsets = [0, 4, 2, 1];
var steps = [8, 8, 4, 2];
var fromRow = 0;
for (var pass = 0; pass < 4; pass++) {
for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
cpRow(toRow, fromRow);
fromRow++;
}
}
return newPixels;
};
exports.deinterlace = deinterlace;

105
node_modules/gifuct-js/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,105 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.decompressFrames = exports.decompressFrame = exports.parseGIF = void 0;
var _gif = _interopRequireDefault(require("js-binary-schema-parser/lib/schemas/gif"));
var _jsBinarySchemaParser = require("js-binary-schema-parser");
var _uint = require("js-binary-schema-parser/lib/parsers/uint8");
var _deinterlace = require("./deinterlace");
var _lzw = require("./lzw");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var parseGIF = function parseGIF(arrayBuffer) {
var byteData = new Uint8Array(arrayBuffer);
return (0, _jsBinarySchemaParser.parse)((0, _uint.buildStream)(byteData), _gif["default"]);
};
exports.parseGIF = parseGIF;
var generatePatch = function generatePatch(image) {
var totalPixels = image.pixels.length;
var patchData = new Uint8ClampedArray(totalPixels * 4);
for (var i = 0; i < totalPixels; i++) {
var pos = i * 4;
var colorIndex = image.pixels[i];
var color = image.colorTable[colorIndex] || [0, 0, 0];
patchData[pos] = color[0];
patchData[pos + 1] = color[1];
patchData[pos + 2] = color[2];
patchData[pos + 3] = colorIndex !== image.transparentIndex ? 255 : 0;
}
return patchData;
};
var decompressFrame = function decompressFrame(frame, gct, buildImagePatch) {
if (!frame.image) {
console.warn('gif frame does not have associated image.');
return;
}
var image = frame.image; // get the number of pixels
var totalPixels = image.descriptor.width * image.descriptor.height; // do lzw decompression
var pixels = (0, _lzw.lzw)(image.data.minCodeSize, image.data.blocks, totalPixels); // deal with interlacing if necessary
if (image.descriptor.lct.interlaced) {
pixels = (0, _deinterlace.deinterlace)(pixels, image.descriptor.width);
}
var resultImage = {
pixels: pixels,
dims: {
top: frame.image.descriptor.top,
left: frame.image.descriptor.left,
width: frame.image.descriptor.width,
height: frame.image.descriptor.height
}
}; // color table
if (image.descriptor.lct && image.descriptor.lct.exists) {
resultImage.colorTable = image.lct;
} else {
resultImage.colorTable = gct;
} // add per frame relevant gce information
if (frame.gce) {
resultImage.delay = (frame.gce.delay || 10) * 10; // convert to ms
resultImage.disposalType = frame.gce.extras.disposal; // transparency
if (frame.gce.extras.transparentColorGiven) {
resultImage.transparentIndex = frame.gce.transparentColorIndex;
}
} // create canvas usable imagedata if desired
if (buildImagePatch) {
resultImage.patch = generatePatch(resultImage);
}
return resultImage;
};
exports.decompressFrame = decompressFrame;
var decompressFrames = function decompressFrames(parsedGif, buildImagePatches) {
return parsedGif.frames.filter(function (f) {
return f.image;
}).map(function (f) {
return decompressFrame(f, parsedGif.gct, buildImagePatches);
});
};
exports.decompressFrames = decompressFrames;

118
node_modules/gifuct-js/lib/lzw.js generated vendored Normal file
View file

@ -0,0 +1,118 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.lzw = void 0;
/**
* javascript port of java LZW decompression
* Original java author url: https://gist.github.com/devunwired/4479231
*/
var lzw = function lzw(minCodeSize, data, pixelCount) {
var MAX_STACK_SIZE = 4096;
var nullCode = -1;
var 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;
var dstPixels = new Array(pixelCount);
var prefix = new Array(MAX_STACK_SIZE);
var suffix = new Array(MAX_STACK_SIZE);
var 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;
};
exports.lzw = lzw;

36
node_modules/gifuct-js/package.json generated vendored Normal file
View file

@ -0,0 +1,36 @@
{
"name": "gifuct-js",
"version": "2.1.2",
"description": "Easy to use efficient .GIF parsing in javascript",
"main": "lib/index.js",
"types": "index.d.ts",
"scripts": {
"build": "babel src --out-dir lib",
"build-demo": "webpack demo/demo.js -o demo/demo.build.js --mode=\"none\""
},
"repository": {
"type": "git",
"url": "https://github.com/matt-way/gifuct-js.git"
},
"keywords": [
"gif",
"parser",
"javascript"
],
"author": "Matt Way",
"license": "MIT",
"bugs": {
"url": "https://github.com/matt-way/gifuct-js/issues"
},
"homepage": "https://github.com/matt-way/gifuct-js",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"js-binary-schema-parser": "^2.0.3"
}
}

26
node_modules/gifuct-js/src/deinterlace.js generated vendored Normal file
View file

@ -0,0 +1,26 @@
/**
* Deinterlace function from https://github.com/shachaf/jsgif
*/
export const deinterlace = (pixels, width) => {
const newPixels = new Array(pixels.length)
const rows = pixels.length / width
const cpRow = function(toRow, fromRow) {
const fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width)
newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels))
}
// See appendix E.
const offsets = [0, 4, 2, 1]
const steps = [8, 8, 4, 2]
var fromRow = 0
for (var pass = 0; pass < 4; pass++) {
for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
cpRow(toRow, fromRow)
fromRow++
}
}
return newPixels
}

85
node_modules/gifuct-js/src/index.js generated vendored Normal file
View file

@ -0,0 +1,85 @@
import GIF from 'js-binary-schema-parser/lib/schemas/gif'
import { parse } from 'js-binary-schema-parser'
import { buildStream } from 'js-binary-schema-parser/lib/parsers/uint8'
import { deinterlace } from './deinterlace'
import { lzw } from './lzw'
export const parseGIF = arrayBuffer => {
const byteData = new Uint8Array(arrayBuffer)
return parse(buildStream(byteData), GIF)
}
const generatePatch = image => {
const totalPixels = image.pixels.length
const patchData = new Uint8ClampedArray(totalPixels * 4)
for (var i = 0; i < totalPixels; i++) {
const pos = i * 4
const colorIndex = image.pixels[i]
const color = image.colorTable[colorIndex] || [0, 0, 0]
patchData[pos] = color[0]
patchData[pos + 1] = color[1]
patchData[pos + 2] = color[2]
patchData[pos + 3] = colorIndex !== image.transparentIndex ? 255 : 0
}
return patchData
}
export const decompressFrame = (frame, gct, buildImagePatch) => {
if (!frame.image) {
console.warn('gif frame does not have associated image.')
return
}
const { image } = frame
// get the number of pixels
const totalPixels = image.descriptor.width * image.descriptor.height
// do lzw decompression
var pixels = lzw(image.data.minCodeSize, image.data.blocks, totalPixels)
// deal with interlacing if necessary
if (image.descriptor.lct.interlaced) {
pixels = deinterlace(pixels, image.descriptor.width)
}
const resultImage = {
pixels: pixels,
dims: {
top: frame.image.descriptor.top,
left: frame.image.descriptor.left,
width: frame.image.descriptor.width,
height: frame.image.descriptor.height
}
}
// color table
if (image.descriptor.lct && image.descriptor.lct.exists) {
resultImage.colorTable = image.lct
} else {
resultImage.colorTable = gct
}
// add per frame relevant gce information
if (frame.gce) {
resultImage.delay = (frame.gce.delay || 10) * 10 // convert to ms
resultImage.disposalType = frame.gce.extras.disposal
// transparency
if (frame.gce.extras.transparentColorGiven) {
resultImage.transparentIndex = frame.gce.transparentColorIndex
}
}
// create canvas usable imagedata if desired
if (buildImagePatch) {
resultImage.patch = generatePatch(resultImage)
}
return resultImage
}
export const decompressFrames = (parsedGif, buildImagePatches) => {
return parsedGif.frames
.filter(f => f.image)
.map(f => decompressFrame(f, parsedGif.gct, buildImagePatches))
}

118
node_modules/gifuct-js/src/lzw.js generated vendored Normal file
View file

@ -0,0 +1,118 @@
/**
* 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
}