forked from olcxjas-softworks/LarpixClient
big updat:
- update dependencies - add webp support and webp conversion for profile images
This commit is contained in:
parent
19c3dbb42d
commit
95aaaa69ea
244 changed files with 121382 additions and 86 deletions
3
node_modules/gifuct-js/.babelrc
generated
vendored
Normal file
3
node_modules/gifuct-js/.babelrc
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
||||
7
node_modules/gifuct-js/.prettierrc
generated
vendored
Normal file
7
node_modules/gifuct-js/.prettierrc
generated
vendored
Normal 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
22
node_modules/gifuct-js/LICENSE
generated
vendored
Normal 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
115
node_modules/gifuct-js/README.md
generated
vendored
Normal 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
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
0
node_modules/gifuct-js/demo/demo.css
generated
vendored
Normal file
230
node_modules/gifuct-js/demo/demo.js
generated
vendored
Normal file
230
node_modules/gifuct-js/demo/demo.js
generated
vendored
Normal 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
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
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
29
node_modules/gifuct-js/demo/index.html
generated
vendored
Normal 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
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
101
node_modules/gifuct-js/index.d.ts
generated
vendored
Normal 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
35
node_modules/gifuct-js/lib/deinterlace.js
generated
vendored
Normal 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
105
node_modules/gifuct-js/lib/index.js
generated
vendored
Normal 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
118
node_modules/gifuct-js/lib/lzw.js
generated
vendored
Normal 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
36
node_modules/gifuct-js/package.json
generated
vendored
Normal 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
26
node_modules/gifuct-js/src/deinterlace.js
generated
vendored
Normal 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
85
node_modules/gifuct-js/src/index.js
generated
vendored
Normal 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
118
node_modules/gifuct-js/src/lzw.js
generated
vendored
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue