1
0
Fork 0
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:
koelo 2022-12-03 05:44:44 +00:00
parent a5a0523e5a
commit 3513d5390c
2016 changed files with 336930 additions and 9 deletions

16
node_modules/@skyra/gifenc/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,16 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [1.0.1](https://github.com/skyra-project/gifenc/compare/v1.0.0...v1.0.1) (2022-10-29)
### Bug Fixes
* NodeNext moduleResolution ([#158](https://github.com/skyra-project/gifenc/issues/158)) ([119a318](https://github.com/skyra-project/gifenc/commit/119a3189a4e0af47262062cc5c7a20bd2bc509d4))
## 1.0.0 (2021-07-27)
### Features
- implementation ([#1](https://github.com/skyra-project/gifenc/issues/1)) ([b96df46](https://github.com/skyra-project/gifenc/commit/b96df463fe8e311174425d167515aedf60c37a64))

24
node_modules/@skyra/gifenc/LICENSE.md generated vendored Normal file
View file

@ -0,0 +1,24 @@
# The MIT License (MIT)
Copyright © `2021` `Skyra Project`
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.

159
node_modules/@skyra/gifenc/README.md generated vendored Normal file
View file

@ -0,0 +1,159 @@
<div align="center">
# @skyra/gifenc
**A very fast server-side animated GIF generation for Node.js**
[![GitHub](https://img.shields.io/github/license/skyra-project/gifenc)](https://github.com/skyra-project/gifenc/blob/main/LICENSE.md)
[![npm](https://img.shields.io/npm/v/@skyra/gifenc?color=crimson&label=NPM&logo=npm)](https://www.npmjs.com/package/@skyra/gifenc)
![npm bundle size minified (scoped)](https://img.shields.io/bundlephobia/min/@skyra/gifenc?label=minified&logo=webpack)
![npm bundle size minzipped (scoped)](https://img.shields.io/bundlephobia/minzip/@skyra/gifenc?label=minified&logo=webpack)
[![Support Server](https://discord.com/api/guilds/254360814063058944/embed.png?style=banner2)](https://join.skyra.pw)
</div>
---
## Features
- @skyra/gifenc is a GIF encoding utility library to build your next GIFs.
- Supports CommonJS and ES Module.
- Heavily based on [`gifencoder`](https://github.com/eugeneware/gifencoder), this module wouldn't have existed without its author.
## Installation
You can use the following command to install this package, or replace `npm install` with your package manager of choice.
```sh
npm install @skyra/gifenc
```
## Usage
> `@skyra/gifenc` is very close to a drop-in replacement for [`gifencoder`](https://www.npmjs.com/package/gifencoder). There are only 2 differences to account for. First of all, the encoder class is named `GifEncoder` and not `GIFEncoder`, and secondly, the metadata methods are chainable.
### Streaming API - Writing to a file
```js
const { GifEncoder } = require('@skyra/gifenc');
const { createWriteStream } = require('node:fs');
const encoder = new GifEncoder(400, 400);
// Set the repeat mode: 0 for repeat, -1 for no-repeat:
.setRepeat(0)
// Set the frame delay in milliseconds:
.setDelay(500)
// Set the image quality, 10 is default:
.setQuality(10);
// Create a read stream and pipe it into a file write stream:
encoder.createReadStream()
.pipe(createWriteStream('my-file.gif'));
encoder.start();
// `getFrames` enumerates over frames
for (const frame of getFrames()) {
encoder.addFrame(frame);
}
encoder.finish();
```
### Streaming API - Get resulting Buffer
We can use [`streamConsumers.buffer()`](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html#streamconsumersbufferstream) from Node.js to convert the stream into a buffer starting with Node.js v16.7.0, if you're using an older version, consider making a function using stream's async iterator (Node.js v10+) or use a package.
```js
const { GifEncoder } = require('@skyra/gifenc');
const { buffer } = require('node:stream/consumers');
const encoder = new GifEncoder(400, 400);
const stream = encoder.createReadStream();
encoder.setRepeat(0).setDelay(500).setQuality(10).start();
// `getFrames` enumerates over frames
for (const frame of getFrames()) {
encoder.addFrame(frame);
}
encoder.finish();
const result = await buffer(stream);
```
### Using with canvas-constructor
```js
const { GifEncoder } = require('@skyra/gifenc');
const { Canvas } = require('canvas-constructor/skia');
// const { Canvas } = require('canvas-constructor/cairo');
const canvas = new Canvas(400, 400);
const encoder = new GifEncoder(400, 400);
const stream = encoder.createReadStream();
encoder.setRepeat(0).setDelay(500).setQuality(10).start();
const colors = ['#98DDCA', '#D5ECC2', '#FFD3B4', '#FFAAA7'];
for (const color of colors) {
canvas.setColor(color).printRectangle(0, 0, 400, 400);
encoder.addFrame(canvas);
}
// ...
```
### Using with ECMAScript Modules
`@skyra/gifenc` supports ESM out of the box. To import the `GifEncoder` class, you use the following statement:
```ts
import { GifEncoder } from '@skyra/gifenc';
```
## Buy us some doughnuts
Skyra Project is open source and always will be, even if we don't get donations. That said, we know there are amazing people who
may still want to donate just to show their appreciation. Thanks you very much in advance!
We accept donations through Patreon, BitCoin, Ethereum, and Litecoin. You can use the buttons below to donate through your method of choice.
| Donate With | QR | Address |
| :---------: | :----------------: | :---------------------------------------------------------------------------------------------------------------------------------------: |
| Patreon | ![PatreonImage][] | [Click Here](https://www.patreon.com/kyranet) |
| PayPal | ![PayPalImage][] | [Click Here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CET28NRZTDQ8L) |
| BitCoin | ![BitcoinImage][] | [3JNzCHMTFtxYFWBnVtDM9Tt34zFbKvdwco](bitcoin:3JNzCHMTFtxYFWBnVtDM9Tt34zFbKvdwco?amount=0.01&label=Skyra%20Discord%20Bot) |
| Ethereum | ![EthereumImage][] | [0xcB5EDB76Bc9E389514F905D9680589004C00190c](ethereum:0xcB5EDB76Bc9E389514F905D9680589004C00190c?amount=0.01&label=Skyra%20Discord%20Bot) |
| Litecoin | ![LitecoinImage][] | [MNVT1keYGMfGp7vWmcYjCS8ntU8LNvjnqM](litecoin:MNVT1keYGMfGp7vWmcYjCS8ntU8LNvjnqM?amount=0.01&label=Skyra%20Discord%20Bot) |
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/kyranet"><img src="https://avatars0.githubusercontent.com/u/24852502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Antonio Román</b></sub></a><br /><a href="https://github.com/skyra-project/gifenc/commits?author=kyranet" title="Code">💻</a> <a href="#ideas-kyranet" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-kyranet" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center"><a href="https://favware.tech/"><img src="https://avatars.githubusercontent.com/u/4019718?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeroen Claassens</b></sub></a><br /><a href="#infra-Favna" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-Favna" title="Maintenance">🚧</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
<!-- LINK DUMP -->
[patreonimage]: https://cdn.skyra.pw/gh-assets/patreon.png
[paypalimage]: https://cdn.skyra.pw/gh-assets/paypal.png
[bitcoinimage]: https://cdn.skyra.pw/gh-assets/bitcoin.png
[ethereumimage]: https://cdn.skyra.pw/gh-assets/ethereum.png
[litecoinimage]: https://cdn.skyra.pw/gh-assets/litecoin.png

3
node_modules/@skyra/gifenc/dist/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,3 @@
export * from './lib/GifEncoder';
export { GifEncoder as JiffEncoder } from './lib/GifEncoder';
//# sourceMappingURL=index.d.ts.map

1
node_modules/@skyra/gifenc/dist/index.d.ts.map generated vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAC"}

8
node_modules/@skyra/gifenc/dist/index.js generated vendored Normal file
View file

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JiffEncoder = void 0;
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./lib/GifEncoder"), exports);
var GifEncoder_1 = require("./lib/GifEncoder");
Object.defineProperty(exports, "JiffEncoder", { enumerable: true, get: function () { return GifEncoder_1.GifEncoder; } });
//# sourceMappingURL=index.js.map

1
node_modules/@skyra/gifenc/dist/index.js.map generated vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,2DAAiC;AACjC,+CAA6D;AAApD,yGAAA,UAAU,OAAe"}

5
node_modules/@skyra/gifenc/dist/index.mjs generated vendored Normal file
View file

@ -0,0 +1,5 @@
import mod from "./index.js";
export default mod;
export const GifEncoder = mod.GifEncoder;
export const JiffEncoder = mod.JiffEncoder;

51
node_modules/@skyra/gifenc/dist/lib/ByteBuffer.d.ts generated vendored Normal file
View file

@ -0,0 +1,51 @@
/// <reference types="node" />
export declare class ByteBuffer {
private written;
private data;
/**
* Constructs the instance.
* @param size The amount of bytes to reserve, defaults to 8KB.
*/
constructor(size?: number);
/**
* Gets the written data.
*/
get length(): number;
/**
* Resets the data.
* @note This does not de-allocate the data, instead, it sets the {@link ByteBuffer.written position} to zero.
*/
reset(): void;
/**
* Writes a single byte into the buffer.
* @param byte The byte to write, between `0x00` and `0xFF`.
*/
writeByte(byte: number): void;
/**
* Writes the `byte` value `times` times.
* @param byte The byte to write `times` times.
* @param times The amount of times to write the `byte`.
*/
writeTimes(byte: number, times: number): void;
/**
* Writes `bytes` into the data.
* @param bytes The bytes to write.
*/
writeBytes(bytes: ArrayLike<number>, start?: number, end?: number): void;
/**
* Gets a sub-array of what was written so far.
* @returns The written section of the data.
*/
toArray(): Buffer;
/**
* Fills the data with the `byte` value given a range.
* @param byte The value to write.
* @param start The start index, defaults to `0`.
* @param end The end index, defaults to {@link Uint8Array.length `this.data.length`}.
*/
fill(byte: number, start?: number, end?: number): void;
private ensureByte;
private ensureBytes;
private copyBytes;
}
//# sourceMappingURL=ByteBuffer.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"ByteBuffer.d.ts","sourceRoot":"","sources":["../../src/lib/ByteBuffer.ts"],"names":[],"mappings":";AAAA,qBAAa,UAAU;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,IAAI,CAAS;IAErB;;;OAGG;gBACgB,IAAI,SAAO;IAI9B;;OAEG;IACH,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED;;;OAGG;IACI,KAAK,IAAI,IAAI;IAIpB;;;OAGG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKpC;;;;OAIG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQpD;;;OAGG;IACI,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,SAAI,EAAE,GAAG,SAAe,GAAG,IAAI;IAQhF;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;;;;OAKG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAI7D,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,SAAS;CASjB"}

103
node_modules/@skyra/gifenc/dist/lib/ByteBuffer.js generated vendored Normal file
View file

@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ByteBuffer = void 0;
class ByteBuffer {
/**
* Constructs the instance.
* @param size The amount of bytes to reserve, defaults to 8KB.
*/
constructor(size = 8192) {
Object.defineProperty(this, "written", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "data", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.data = Buffer.allocUnsafe(size);
}
/**
* Gets the written data.
*/
get length() {
return this.written;
}
/**
* Resets the data.
* @note This does not de-allocate the data, instead, it sets the {@link ByteBuffer.written position} to zero.
*/
reset() {
this.written = 0;
}
/**
* Writes a single byte into the buffer.
* @param byte The byte to write, between `0x00` and `0xFF`.
*/
writeByte(byte) {
this.ensureByte();
this.data[this.written++] = byte;
}
/**
* Writes the `byte` value `times` times.
* @param byte The byte to write `times` times.
* @param times The amount of times to write the `byte`.
*/
writeTimes(byte, times) {
this.ensureBytes(times);
for (let i = 0; i < times; i++) {
this.data[this.written++] = byte;
}
}
/**
* Writes `bytes` into the data.
* @param bytes The bytes to write.
*/
writeBytes(bytes, start = 0, end = bytes.length) {
this.ensureBytes(end - start);
for (let i = start; i < end; i++) {
this.data[this.written++] = bytes[i];
}
}
/**
* Gets a sub-array of what was written so far.
* @returns The written section of the data.
*/
toArray() {
return this.data.subarray(0, this.written);
}
/**
* Fills the data with the `byte` value given a range.
* @param byte The value to write.
* @param start The start index, defaults to `0`.
* @param end The end index, defaults to {@link Uint8Array.length `this.data.length`}.
*/
fill(byte, start, end) {
this.data.fill(byte, start, end);
}
ensureByte() {
if (this.written + 1 >= this.data.length) {
const size = this.data.length * 2;
this.data = this.copyBytes(size);
}
}
ensureBytes(n) {
if (this.written + n >= this.data.length) {
const size = Math.pow(2, Math.ceil(Math.log(this.written + n) / Math.log(2)));
this.data = this.copyBytes(size);
}
}
copyBytes(size) {
const data = Buffer.allocUnsafe(size);
for (let i = 0; i < this.written; ++i) {
data[i] = this.data[i];
}
return data;
}
}
exports.ByteBuffer = ByteBuffer;
//# sourceMappingURL=ByteBuffer.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"ByteBuffer.js","sourceRoot":"","sources":["../../src/lib/ByteBuffer.ts"],"names":[],"mappings":"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"}

279
node_modules/@skyra/gifenc/dist/lib/GifEncoder.d.ts generated vendored Normal file
View file

@ -0,0 +1,279 @@
/**
* GifEncoder
*
* Authors
* - Kevin Weiner (original Java version - kweiner@fmsware.com)
* - Thibault Imbert (AS3 version - bytearray.org)
* - Johan Nordberg (JS version - code@johan-nordberg.com)
* - Eugene Ware (node.js streaming version - eugene@noblesmaurai.com)
* - Antonio Román (TS version - kyradiscord@gmail.com)
*/
/// <reference types="node" />
import { Duplex, Readable } from 'stream';
/**
* The disposal method code.
*
* - `0`: No disposal specified. The decoder is not required to take any action.
* - `1`: Do not dispose. The graphic is to be left in place.
* - `2`: Restore to background color. The area used by the graphic must be restored to the background color.
* - `3`: Restore to previous. The decoder is required to restore the area overwritten by the graphic with what was
* there prior to rendering the graphic.
* - `4` - `7`: To be defined.
*/
export declare type DisposalCode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export interface EncoderOptions {
/**
* The frame delay in milliseconds.
* @default 0
*/
delay?: number;
/**
* The frames per second, supersedes {@link EncoderOptions.delay} if set.
* @default 0
*/
framerate?: number;
/**
* The GIF frame disposal code for the last added frame and any subsequent frames.
*
* Defaults to one of the following values:
* - `0` : If `transparent` is set
* - `2` : Otherwise
*/
dispose?: DisposalCode;
/**
* The number of times to repeat the GIF, between `0` and `65536`, with two special cases:
* - `-1`: play once
* - `0`: repeat indefinitely
* @default -1
* @note When set to a value different to `-1`, the GIF will use the Netscape 2.0 extension.
*/
repeat?: number;
/**
* The transparent color for the last added frame and any subsequent frames. Since all colors are subject to
* modification in the quantization process, the color in the final palette for each frame closest to the given
* color becomes the transparent color for that frame. May be set to null to indicate no transparent color.
*/
transparent?: number | null;
/**
* The quality of color quantization (conversion of images to the maximum 256 colors allowed by the GIF
* specification) between `1` and `30`. Lower values (closer to 1) produce better colors but require significantly
* more resources and processing. `10` is the default value as it produces good color mapping at reasonable speeds.
*
* @note Values greater than 20 do not yield significant improvements in speed.
*/
quality?: number;
}
export declare class GifEncoder {
/**
* The GIF image's width, between `1` and `65536`.
*/
readonly width: number;
/**
* The GIF image's height, between `1` and `65536`.
*/
readonly height: number;
/**
* The transparent color, `null` if no transparent color is given.
*/
private transparent;
/**
* The transparent index in the color table.
*/
private transparentIndex;
/**
* Number between `-1` and `65536`, `-1` indicating no repeat (GIF89a specification), otherwise repeating `repeat`
* times with the exception of `0`, which repeats indefinitely.
*/
private repeat;
/**
* Frame delay in hundredths of a second (1 = 10ms).
*/
private delay;
/**
* The current frame.
*/
private image;
/**
* The BGR byte array from the current frame.
*/
private pixels;
/**
* The converted frame indexed to the palette.
*/
private indexedPixels;
/**
* The number of bit planes.
*/
private colorDepth;
/**
* The RGB palette.
*/
private colorPalette;
/**
* The active palette entries.
*/
private usedEntry;
/**
* The disposal code (`-1` = determine defaults).
*/
private disposalMode;
/**
* Whether or not this is the first frame.
*/
private firstFrame;
/**
* The sample interval for the quantifier.
*/
private sample;
/**
* Whether or not we started encoding.
*/
private started;
/**
* The readable streams.
*/
private readableStreams;
/**
* The output buffer.
*/
private byteBuffer;
/**
* Constructs the GIF encoder.
* @param width An integer representing the GIF image's width, between `1` and `65536`.
* @param height An integer representing the GIF image's height, between `1` and `65536`.
*/
constructor(width: number, height: number);
/**
* Creates a readable stream and pushes it to the encoder's {@link GifEncoder.readableStreams readable streams}.
* @returns The new readable stream.
* @example
* ```javascript
* const encoder = new GifEncoder(320, 240);
*
* // Stream the results as they are available into hello.gif
* encoder.createReadStream().pipe(fs.createWriteStream('hello.gif'));
* ```
*/
createReadStream(): Readable;
/**
* Uses an existing readable stream and pushes it to the encoder's {@link GifEncoder.readableStreams readable streams}.
* @param readable The readable stream to use.
* @returns The given readable stream.
*/
createReadStream<T extends Readable>(readable: T): T;
/**
* Creates a write stream.
* @param options The options for the write stream.
* @returns A {@link Duplex}.
* @example
* ```typescript
* const { GifEncoder } = require('@skyra/gifenc');
* const encoder = new GifEncoder(400, 200);
*
* pngStreamGenerator() // A user-defined `Readable`.
* .pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
* .pipe(fs.createWriteStream('runningKitten.gif'));
* ```
*/
createWriteStream(options?: EncoderOptions): Duplex;
/**
* Sets the delay time between each frame, or changes it for subsequent frames (applies to the next frame added).
* @param delay The delay between frames, in milliseconds. Must be a number between `655360` and `10`.
*/
setDelay(delay: number): this;
/**
* Sets frame rate in frames per second.
* @param fps The amount of frames per second, maximum is `100` frames per second.
*/
setFramerate(fps: number): this;
/**
* Sets the GIF frame disposal code for the last added frame and any subsequent frames.
*
* Defaults to one of the following values:
* - `0` : If `transparent` is set
* - `2` : Otherwise
*
* @param disposalCode The disposal code.
* @see {@link DisposalCode}
*/
setDispose(disposalCode: DisposalCode): this;
/**
* Sets the number of times the set of GIF frames should be played.
* @param repeat The number of times between `-1` and `65536` to repeat the GIF, with two special cases:
* - `-1` (**default**): play once
* - `0`: repeat indefinitely
*
* @note This method has no effect after the first image was added.
*/
setRepeat(repeat: number): this;
/**
* Sets the transparent color for the last added frame and any subsequent frames. Since all colors are subject to
* modification in the quantization process, the color in the final palette for each frame closest to the given
* color becomes the transparent color for that frame. May be set to null to indicate no transparent color.
* @param color The color to be set in transparent pixels.
*/
setTransparent(color: number | null): this;
/**
* Sets the quality of color quantization (conversion of images to the maximum 256 colors allowed by the GIF
* specification). Lower values (`minimum` = 1) produce better colors, but slow processing significantly. `10` is
* the default, and produces good color mapping at reasonable speeds. Values greater than 20 do not yield
* significant improvements in speed.
* @param quality A number between `1` and `30`.
*/
setQuality(quality: number): this;
/**
* Adds the next GIF frame. The frame is not written immediately, but is actually deferred until the next frame is
* received so that timing data can be inserted. Calling {@link GifEncoder.finish} will flush all frames.
* @param imageData The image data to add into the next frame.
*/
addFrame(imageData: Pick<CanvasRenderingContext2D, 'getImageData'> | Uint8ClampedArray): void;
/**
* Adds final trailer to the GIF stream, if you don't call the finish method the GIF stream will not be valid.
*/
finish(): void;
/**
* Writes the GIF file header
*/
start(): void;
private end;
private emit;
/**
* Analyzes current frame colors and creates a color map.
*/
private analyzePixels;
/**
* Returns index of palette color closest to c.
* @param color The color to compare.
*/
private findClosest;
/**
* Updates {@link GifEncoder.pixels} by creating an RGB-formatted {@link Uint8Array} from the RGBA-formatted data.
*/
private getImagePixels;
/**
* Writes the GCE (Graphic Control Extension).
*/
private writeGraphicControlExtension;
/**
* Writes the ID (Image Descriptor).
*/
private writeImageDescriptor;
/**
* Writes the LSD (Logical Screen Descriptor)
*/
private writeLogicalScreenDescriptor;
/**
* Writes the Netscape application extension to define repeat count.
*/
private writeNetscapeExtension;
/**
* Writes the color table palette.
*/
private writePalette;
private writeShort;
/**
* Encodes and writes pixel data into {@link GifEncoder.byteBuffer}.
*/
private writePixels;
}
//# sourceMappingURL=GifEncoder.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"GifEncoder.d.ts","sourceRoot":"","sources":["../../src/lib/GifEncoder.ts"],"names":[],"mappings":"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"}

562
node_modules/@skyra/gifenc/dist/lib/GifEncoder.js generated vendored Normal file
View file

@ -0,0 +1,562 @@
"use strict";
/**
* GifEncoder
*
* Authors
* - Kevin Weiner (original Java version - kweiner@fmsware.com)
* - Thibault Imbert (AS3 version - bytearray.org)
* - Johan Nordberg (JS version - code@johan-nordberg.com)
* - Eugene Ware (node.js streaming version - eugene@noblesmaurai.com)
* - Antonio Román (TS version - kyradiscord@gmail.com)
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GifEncoder = void 0;
const stream_1 = require("stream");
const util_1 = require("util");
const ByteBuffer_1 = require("./ByteBuffer");
const LZWEncoder_1 = require("./LZWEncoder");
const NeuQuant_1 = require("./NeuQuant");
const NOP = () => {
// no-op
};
const GIF_HEADER = new TextEncoder().encode('GIF89a');
const NETSCAPE_HEADER = new Uint8Array([0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30]); // NETSCAPE2.0
/**
* The color table size (bits - 1).
*/
const PALETTE_SIZE = 7;
class GifEncoder {
/**
* Constructs the GIF encoder.
* @param width An integer representing the GIF image's width, between `1` and `65536`.
* @param height An integer representing the GIF image's height, between `1` and `65536`.
*/
constructor(width, height) {
/**
* 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
});
/**
* The transparent color, `null` if no transparent color is given.
*/
Object.defineProperty(this, "transparent", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The transparent index in the color table.
*/
Object.defineProperty(this, "transparentIndex", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
/**
* Number between `-1` and `65536`, `-1` indicating no repeat (GIF89a specification), otherwise repeating `repeat`
* times with the exception of `0`, which repeats indefinitely.
*/
Object.defineProperty(this, "repeat", {
enumerable: true,
configurable: true,
writable: true,
value: -1
});
/**
* Frame delay in hundredths of a second (1 = 10ms).
*/
Object.defineProperty(this, "delay", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
/**
* The current frame.
*/
Object.defineProperty(this, "image", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The BGR byte array from the current frame.
*/
Object.defineProperty(this, "pixels", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The converted frame indexed to the palette.
*/
Object.defineProperty(this, "indexedPixels", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The number of bit planes.
*/
Object.defineProperty(this, "colorDepth", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The RGB palette.
*/
Object.defineProperty(this, "colorPalette", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
/**
* The active palette entries.
*/
Object.defineProperty(this, "usedEntry", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
/**
* The disposal code (`-1` = determine defaults).
*/
Object.defineProperty(this, "disposalMode", {
enumerable: true,
configurable: true,
writable: true,
value: -1
});
/**
* Whether or not this is the first frame.
*/
Object.defineProperty(this, "firstFrame", {
enumerable: true,
configurable: true,
writable: true,
value: true
});
/**
* The sample interval for the quantifier.
*/
Object.defineProperty(this, "sample", {
enumerable: true,
configurable: true,
writable: true,
value: 10
});
/**
* Whether or not we started encoding.
*/
Object.defineProperty(this, "started", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
/**
* The readable streams.
*/
Object.defineProperty(this, "readableStreams", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
/**
* The output buffer.
*/
Object.defineProperty(this, "byteBuffer", {
enumerable: true,
configurable: true,
writable: true,
value: new ByteBuffer_1.ByteBuffer()
});
this.width = ~~width;
this.height = ~~height;
}
createReadStream(readable) {
if (!readable) {
readable = new stream_1.Readable();
readable._read = NOP;
}
this.readableStreams.push(readable);
return readable;
}
/**
* Creates a write stream.
* @param options The options for the write stream.
* @returns A {@link Duplex}.
* @example
* ```typescript
* const { GifEncoder } = require('@skyra/gifenc');
* const encoder = new GifEncoder(400, 200);
*
* pngStreamGenerator() // A user-defined `Readable`.
* .pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
* .pipe(fs.createWriteStream('runningKitten.gif'));
* ```
*/
createWriteStream(options) {
if (options) {
if (options.delay !== undefined)
this.setDelay(options.delay);
if (options.framerate !== undefined)
this.setFramerate(options.framerate);
if (options.dispose !== undefined)
this.setDispose(options.dispose);
if (options.repeat !== undefined)
this.setRepeat(options.repeat);
if (options.transparent !== undefined)
this.setTransparent(options.transparent);
if (options.quality !== undefined)
this.setQuality(options.quality);
}
const duplex = new stream_1.Duplex({ objectMode: true });
duplex._read = NOP;
this.createReadStream(duplex);
duplex._write = (data, _enc, next) => {
if (!this.started)
this.start();
this.addFrame(data);
next();
};
const end = duplex.end.bind(duplex);
// @ts-expect-error This is a Node 17 issue and it should not break using the library
duplex.end = (...args) => {
end(...args);
this.finish();
};
return duplex;
}
/**
* Sets the delay time between each frame, or changes it for subsequent frames (applies to the next frame added).
* @param delay The delay between frames, in milliseconds. Must be a number between `655360` and `10`.
*/
setDelay(delay) {
this.delay = Math.round(delay / 10);
return this;
}
/**
* Sets frame rate in frames per second.
* @param fps The amount of frames per second, maximum is `100` frames per second.
*/
setFramerate(fps) {
this.delay = Math.round(100 / fps);
return this;
}
/**
* Sets the GIF frame disposal code for the last added frame and any subsequent frames.
*
* Defaults to one of the following values:
* - `0` : If `transparent` is set
* - `2` : Otherwise
*
* @param disposalCode The disposal code.
* @see {@link DisposalCode}
*/
setDispose(disposalCode) {
if (disposalCode >= 0)
this.disposalMode = disposalCode;
return this;
}
/**
* Sets the number of times the set of GIF frames should be played.
* @param repeat The number of times between `-1` and `65536` to repeat the GIF, with two special cases:
* - `-1` (**default**): play once
* - `0`: repeat indefinitely
*
* @note This method has no effect after the first image was added.
*/
setRepeat(repeat) {
this.repeat = repeat;
return this;
}
/**
* Sets the transparent color for the last added frame and any subsequent frames. Since all colors are subject to
* modification in the quantization process, the color in the final palette for each frame closest to the given
* color becomes the transparent color for that frame. May be set to null to indicate no transparent color.
* @param color The color to be set in transparent pixels.
*/
setTransparent(color) {
this.transparent = color;
return this;
}
/**
* Sets the quality of color quantization (conversion of images to the maximum 256 colors allowed by the GIF
* specification). Lower values (`minimum` = 1) produce better colors, but slow processing significantly. `10` is
* the default, and produces good color mapping at reasonable speeds. Values greater than 20 do not yield
* significant improvements in speed.
* @param quality A number between `1` and `30`.
*/
setQuality(quality) {
if (quality < 1)
quality = 1;
this.sample = quality;
return this;
}
/**
* Adds the next GIF frame. The frame is not written immediately, but is actually deferred until the next frame is
* received so that timing data can be inserted. Calling {@link GifEncoder.finish} will flush all frames.
* @param imageData The image data to add into the next frame.
*/
addFrame(imageData) {
if (util_1.types.isUint8ClampedArray(imageData)) {
this.image = imageData;
}
else {
this.image = imageData.getImageData(0, 0, this.width, this.height).data;
}
this.getImagePixels(); // convert to correct format if necessary
this.analyzePixels(); // build color table & map pixels
if (this.firstFrame) {
this.writeLogicalScreenDescriptor(); // logical screen descriptor
this.writePalette(); // global color table
if (this.repeat >= 0) {
// use NS app extension to indicate reps
this.writeNetscapeExtension();
}
}
this.writeGraphicControlExtension(); // write graphic control extension
this.writeImageDescriptor(); // image descriptor
if (!this.firstFrame)
this.writePalette(); // local color table
this.writePixels(); // encode and write pixel data
this.firstFrame = false;
this.emit();
}
/**
* Adds final trailer to the GIF stream, if you don't call the finish method the GIF stream will not be valid.
*/
finish() {
this.byteBuffer.writeByte(0x3b); // gif trailer
this.end();
}
/**
* Writes the GIF file header
*/
start() {
this.byteBuffer.writeBytes(GIF_HEADER);
this.started = true;
this.emit();
}
end() {
if (this.readableStreams.length === 0)
return;
this.emit();
for (const stream of this.readableStreams) {
stream.push(null);
}
this.readableStreams = [];
}
emit() {
if (this.readableStreams.length === 0 || this.byteBuffer.length === 0)
return;
const data = this.byteBuffer.toArray();
for (const stream of this.readableStreams) {
stream.push(Buffer.from(data));
}
this.byteBuffer.reset();
}
/**
* Analyzes current frame colors and creates a color map.
*/
analyzePixels() {
const pixels = this.pixels;
const pixelByteCount = pixels.length;
const pixelCount = pixelByteCount / 3;
this.indexedPixels = new Uint8Array(pixelCount);
const quantifier = new NeuQuant_1.NeuQuant(pixels, this.sample);
this.colorPalette = quantifier.getColorMap();
// Map image pixels to new palette:
let k = 0;
for (let j = 0; j < pixelCount; j++) {
const r = pixels[k++] & 0xff;
const g = pixels[k++] & 0xff;
const b = pixels[k++] & 0xff;
const index = quantifier.lookupRGB(r, g, b);
this.usedEntry[index] = true;
this.indexedPixels[j] = index;
}
this.pixels = null;
this.colorDepth = 8;
// Get closest match to transparent color if specified:
if (this.transparent === null)
return;
this.transparentIndex = this.findClosest(this.transparent);
// Ensure that pixels with full transparency in the RGBA image are using
// the selected transparent color index in the indexed image.
for (let pixelIndex = 0; pixelIndex < pixelCount; pixelIndex++) {
if (this.image[pixelIndex * 4 + 3] === 0) {
this.indexedPixels[pixelIndex] = this.transparentIndex;
}
}
}
/**
* Returns index of palette color closest to c.
* @param color The color to compare.
*/
findClosest(color) {
if (this.colorPalette === null)
return -1;
const r = (color & 0xff0000) >> 16;
const g = (color & 0x00ff00) >> 8;
const b = color & 0x0000ff;
let minimumIndex = 0;
let distanceMinimum = 256 * 256 * 256;
const len = this.colorPalette.length;
for (let i = 0; i < len;) {
const index = i / 3;
const dr = r - (this.colorPalette[i++] & 0xff);
const dg = g - (this.colorPalette[i++] & 0xff);
const db = b - (this.colorPalette[i++] & 0xff);
const d = dr * dr + dg * dg + db * db;
if (this.usedEntry[index] && d < distanceMinimum) {
distanceMinimum = d;
minimumIndex = index;
}
}
return minimumIndex;
}
/**
* Updates {@link GifEncoder.pixels} by creating an RGB-formatted {@link Uint8Array} from the RGBA-formatted data.
*/
getImagePixels() {
const w = this.width;
const h = this.height;
this.pixels = new Uint8Array(w * h * 3);
const data = this.image;
for (let i = 0, count = 0; i < h; i++) {
for (let j = 0; j < w; j++) {
const b = i * w * 4 + j * 4;
this.pixels[count++] = data[b];
this.pixels[count++] = data[b + 1];
this.pixels[count++] = data[b + 2];
}
}
}
/**
* Writes the GCE (Graphic Control Extension).
*/
writeGraphicControlExtension() {
this.byteBuffer.writeByte(0x21); // extension introducer
this.byteBuffer.writeByte(0xf9); // GCE label
this.byteBuffer.writeByte(4); // data block size
let transparency;
let dispose;
if (this.transparent === null) {
transparency = 0;
dispose = 0; // dispose = no action
}
else {
transparency = 1;
dispose = 2; // force clear if using transparent color
}
if (this.disposalMode >= 0) {
dispose = this.disposalMode & 7; // user override
}
dispose <<= 2;
// Write GCP's packed fields
const fields = 0 | // XXX0_0000 : Reserved
dispose | // 000X_XX00 : Disposal Method
0 | // 0000_00X0 : User Input Flag
transparency; // 0000_000X : Transparent Color Flag
this.byteBuffer.writeByte(fields);
this.writeShort(this.delay); // delay x 1 / 100 sec
this.byteBuffer.writeByte(this.transparentIndex); // transparent color index
this.byteBuffer.writeByte(0); // block terminator
}
/**
* Writes the ID (Image Descriptor).
*/
writeImageDescriptor() {
this.byteBuffer.writeByte(0x2c); // Image Descriptor block identifier
this.writeShort(0); // Image Left Position
this.writeShort(0); // Image Top Position
this.writeShort(this.width); // Image Width
this.writeShort(this.height); // Image Height
// Write the LCT (Local Color Table):
const fields = this.firstFrame
? 0 // The first frame uses the GCT (Global Color Table)
: 128 | // X000_0000 : Local Color Table Flag = 1
0 | // 0X00_0000 : Interlace Flag = 0
0 | // 00X0_0000 : Sort Flag = 0
0 | // 000X_X000 : Reserved
PALETTE_SIZE; // 0000_0XXX : Size of Local Color Table
this.byteBuffer.writeByte(fields);
}
/**
* Writes the LSD (Logical Screen Descriptor)
*/
writeLogicalScreenDescriptor() {
// logical screen size
this.writeShort(this.width);
this.writeShort(this.height);
// Write the GCT (Global Color Table):
const fields = 128 | // X000_0000 : GCT (Global Color Table) flag = 1
112 | // 0XXX_0000 : Color Resolution = 7
0 | // 0000_X000 : GCT sort flag = 0
0 | // 0000_0X00 : Reserved
PALETTE_SIZE; // 0000_00XX : GCT (Global Color Table) size
this.byteBuffer.writeByte(fields);
this.byteBuffer.writeByte(0x000000); // background color index
this.byteBuffer.writeByte(0); // pixel aspect ratio - assume 1:1
}
/**
* Writes the Netscape application extension to define repeat count.
*/
writeNetscapeExtension() {
// Reference: http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
this.byteBuffer.writeByte(0x21); // Extension
this.byteBuffer.writeByte(0xff); // Application Extension
this.byteBuffer.writeByte(0x0b); // Block Size
this.byteBuffer.writeBytes(NETSCAPE_HEADER); // Application Identifier + Application Authentication Code
this.byteBuffer.writeByte(0x03); // Sub-block data size
this.byteBuffer.writeByte(0x01); // Sub-block ID
this.writeShort(this.repeat); // Loop Count (up to 2 bytes, `0` = repeat forever)
this.byteBuffer.writeByte(0); // Block Terminator
}
/**
* Writes the color table palette.
*/
writePalette() {
this.byteBuffer.writeBytes(this.colorPalette);
this.byteBuffer.writeTimes(0, 3 * 256 - this.colorPalette.length);
}
writeShort(pValue) {
this.byteBuffer.writeByte(pValue & 0xff);
this.byteBuffer.writeByte((pValue >> 8) & 0xff);
}
/**
* Encodes and writes pixel data into {@link GifEncoder.byteBuffer}.
*/
writePixels() {
const enc = new LZWEncoder_1.LZWEncoder(this.width, this.height, this.indexedPixels, this.colorDepth);
enc.encode(this.byteBuffer);
}
}
exports.GifEncoder = GifEncoder;
//# sourceMappingURL=GifEncoder.js.map

File diff suppressed because one or more lines are too long

123
node_modules/@skyra/gifenc/dist/lib/LZWEncoder.d.ts generated vendored Normal file
View file

@ -0,0 +1,123 @@
/**
* 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)
*/
import type { ByteBuffer } from './ByteBuffer';
/**
* @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.
*/
export declare class LZWEncoder {
/**
* The GIF image's width, between `1` and `65536`.
*/
readonly width: number;
/**
* The GIF image's height, between `1` and `65536`.
*/
readonly height: number;
private pixels;
private readonly initCodeSize;
private currentAccumulator;
private currentBits;
private currentPixel;
private accumulator;
private firstUnusedEntry;
private maximumCode;
private remaining;
private bitSize;
private clearFlag;
private globalInitialBits;
private clearCode;
private endOfFrameCode;
private readonly accumulators;
private readonly hashes;
private readonly codes;
/**
* 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: number, height: number, pixels: Uint8Array, colorDepth: number);
/**
* Encodes the image into the output.
* @param output The byte buffer to write to.
*/
encode(output: ByteBuffer): void;
/**
* Compresses the GIF data.
* @param initialBits The initial bits for the compression.
* @param output The byte buffer to write to.
*/
private compress;
/**
* 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.
*/
private addCharacter;
/**
* Clears out the hash table for block compress.
* @param output The byte buffer to write to.
*/
private clearCodeTable;
/**
* Resets the hash table given an amount of hashes.
* @param hashSize The amount of hashes to reset.
*/
private resetHashRange;
/**
* Flushes the packet to disk, and reset the accumulator.
* @param output The byte buffer to write to.
*/
private flushPacket;
/**
* 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
* ```
*/
private getMaximumCode;
/**
* Gets the next pixel from the image.
* @returns The next pixel from the image.
*/
private nextPixel;
private processOutput;
}
//# sourceMappingURL=LZWEncoder.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"LZWEncoder.d.ts","sourceRoot":"","sources":["../../src/lib/LZWEncoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAS/C;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAU;IACtB;;OAEG;IACH,SAAgB,KAAK,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAK;IAIpB,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,cAAc,CAAK;IAE3B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuB;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IAEnD;;;;;;OAMG;gBACgB,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM;IAOxF;;;OAGG;IACI,MAAM,CAAC,MAAM,EAAE,UAAU;IAQhC;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAgEhB;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAKpB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,aAAa;CAmCrB"}

353
node_modules/@skyra/gifenc/dist/lib/LZWEncoder.js generated vendored Normal file
View 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

File diff suppressed because one or more lines are too long

121
node_modules/@skyra/gifenc/dist/lib/NeuQuant.d.ts generated vendored Normal file
View file

@ -0,0 +1,121 @@
/**
* NeuQuant Neural-Net Quantization Algorithm
* ------------------------------------------
*
* Copyright (c) 1994 Anthony Dekker
*
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
* See "Kohonen neural networks for optimal colour quantization"
* in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
* for a discussion of the algorithm.
* See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
*
* Any party obtaining a copy of these files from the author, directly or
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
* world-wide, paid up, royalty-free, nonexclusive right and license to deal
* in this software and documentation files (the "Software"), including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons who receive
* copies from any such party to do so, with the only requirement being
* that this copyright notice remain intact.
*
* (JavaScript port 2012 by Johan Nordberg)
* (TypeScript port 2021 by Antonio Román)
*/
export declare class NeuQuant {
/**
* Array of pixels in RGB format, as such that it's decoded as `[r, g, b, r, g, b, r, g, b, ...]`.
*/
private pixels;
/**
* Sampling factor from `1` to `30`, where lower is better quality.
*/
private sampleFactorial;
/**
* The neural networks, composed by {@link maximumColorsSize} {@link Float64Array float arrays} of size 4.
*/
private networks;
/**
* Network lookup indexes, composed by 256 indexes.
*/
private networkIndexes;
private biases;
private frequencies;
private radiusPowers;
/**
* Creates the neural quantifier instance.
* @param pixels Array of pixels in RGB format, as such that it's decoded as `[r, g, b, r, g, b, r, g, b, ...]`.
* @param sampleFactorial Sampling factor from `1` to `30`, where lower is better quality.
*/
constructor(pixels: Uint8Array, sampleFactorial: number);
/**
* Builds the networks' color map.
* @returns A RGB-encoded {@link Float64Array}.
*/
getColorMap(): Float64Array;
/**
* Searches for BGR values 0..255 and returns a color index
* @param b The blue color byte, between 0 and 255.
* @param g The green color byte, between 0 and 255.
* @param r The red color byte, between 0 and 255.
* @returns The best color index.
*/
lookupRGB(b: number, g: number, r: number): number;
/**
* Initializes the state for the arrays.
*/
private init;
/**
* Un-biases network to give byte values 0..255 and record position i to prepare for sort.
*/
private unBiasNetwork;
/**
* Moves neuron `i` towards biased (`B`, `G`, `R`) by factor `alpha`.
* @param alpha The factor at which the neuron `i` should move towards.
* @param i The neuron's index.
* @param b The blue color.
* @param g The green color.
* @param r The red color.
*/
private alterSingle;
/**
* Moves neurons in a `radius` around index `i` towards biased (`B`, `G`, `R`) by factor
* {@link NeuQuant.radiusPowers `radiusPower[m]`}.
* @param radius The radius around `i` to alter.
* @param i The neuron's index.
* @param b The blue color.
* @param g The green color.
* @param r The red color.
*/
private alterNeighbors;
/**
* Searches for biased BGR values.
*
* - Finds the closest neuron (minimum distance) and updates {@link NeuQuant.frequencies}.
* - Finds the best neuron (minimum distance-bias) and returns the position.
*
* For frequently chosen neurons, {@link NeuQuant.frequencies `frequencies[i]`} is high and
* {@link NeuQuant.biases `biases[i]`} is negative.
*
* The latter is determined by the multiplication of `gamma` with the subtraction of the inverse of
* {@link maximumColorsSize} with {@link NeuQuant.frequencies `frequencies[i]`}:
*
* ```typescript
* biases[i] = gamma * ((1 / maximumColorsSize) - frequencies[i])
* ```
* @param b The blue color.
* @param g The green color.
* @param r The red color.
* @returns The best bias position.
*/
private contest;
/**
* Sorts the neural network and builds {@link NeuQuant.networkIndexes `networkIndex[0..255]`}.
*/
private buildIndexes;
/**
* Runs the main learning loop.
*/
private learn;
}
//# sourceMappingURL=NeuQuant.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"NeuQuant.d.ts","sourceRoot":"","sources":["../../src/lib/NeuQuant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA2CH,qBAAa,QAAQ;IACpB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAa;IAE3B;;OAEG;IACH,OAAO,CAAC,eAAe,CAAS;IAEhC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAiB;IAEjC;;OAEG;IACH,OAAO,CAAC,cAAc,CAAa;IAGnC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,YAAY,CAAa;IAEjC;;;;OAIG;gBACgB,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM;IAe9D;;;OAGG;IACI,WAAW;IAkBlB;;;;;;OAMG;IACI,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM;IAwDhD;;OAEG;IACH,OAAO,CAAC,IAAI;IASZ;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IA2BtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,OAAO;IAgCf;;OAEG;IACH,OAAO,CAAC,YAAY;IA4CpB;;OAEG;IACH,OAAO,CAAC,KAAK;CA0Db"}

427
node_modules/@skyra/gifenc/dist/lib/NeuQuant.js generated vendored Normal file
View file

@ -0,0 +1,427 @@
"use strict";
/**
* NeuQuant Neural-Net Quantization Algorithm
* ------------------------------------------
*
* Copyright (c) 1994 Anthony Dekker
*
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
* See "Kohonen neural networks for optimal colour quantization"
* in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
* for a discussion of the algorithm.
* See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
*
* Any party obtaining a copy of these files from the author, directly or
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
* world-wide, paid up, royalty-free, nonexclusive right and license to deal
* in this software and documentation files (the "Software"), including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons who receive
* copies from any such party to do so, with the only requirement being
* that this copyright notice remain intact.
*
* (JavaScript port 2012 by Johan Nordberg)
* (TypeScript port 2021 by Antonio Román)
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.NeuQuant = void 0;
/* eslint-disable prefer-destructuring, no-negated-condition */
const learningCycles = 100; // Number of learning cycles.
const maximumColorsSize = 256; // Number of colors used.
const maximumColorsPosition = maximumColorsSize - 1;
// defs for freq and bias
const networkBiasShift = 4; // Bias for color values.
const integerBiasShift = 16; // Bias for fractions.
const integerBias = 1 << integerBiasShift;
const gammaShift = 10;
const betaShift = 10;
const beta = integerBias >> betaShift; // `beta` = 1 / 1024
const betaGamma = integerBias << (gammaShift - betaShift);
// Defaults for decreasing radius factor:
// -> For 256 colors, radius starts at 32.0 biased by 6 bits and decreases by a factor of 1 / 30 each cycle.
const maximumRadius = maximumColorsSize >> 3;
const initialRadiusBiasShift = 6;
const initialRadiusBias = 1 << initialRadiusBiasShift;
const initialRadius = maximumRadius * initialRadiusBias;
const initialRadiusDecrement = 30;
// Defaults for decreasing alpha factor:
// -> Alpha starts at 1.0
const alphaBiasShift = 10;
const initialAlpha = 1 << alphaBiasShift;
// Constants used for radius power calculation:
const radiusBiasShift = 8;
const radiusBias = 1 << radiusBiasShift;
const alphaRadiusBiasShift = alphaBiasShift + radiusBiasShift;
const alphaRadiusBias = 1 << alphaRadiusBiasShift;
// Four primes near 500 - assume no image has a length so large that it is divisible by all four primes:
const prime1 = 499;
const prime2 = 491;
const prime3 = 487;
const prime4 = 503;
const minimumPictureBytes = 3 * prime4;
class NeuQuant {
/**
* Creates the neural quantifier instance.
* @param pixels Array of pixels in RGB format, as such that it's decoded as `[r, g, b, r, g, b, r, g, b, ...]`.
* @param sampleFactorial Sampling factor from `1` to `30`, where lower is better quality.
*/
constructor(pixels, sampleFactorial) {
/**
* Array of pixels in RGB format, as such that it's decoded as `[r, g, b, r, g, b, r, g, b, ...]`.
*/
Object.defineProperty(this, "pixels", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
/**
* Sampling factor from `1` to `30`, where lower is better quality.
*/
Object.defineProperty(this, "sampleFactorial", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
/**
* The neural networks, composed by {@link maximumColorsSize} {@link Float64Array float arrays} of size 4.
*/
Object.defineProperty(this, "networks", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
/**
* Network lookup indexes, composed by 256 indexes.
*/
Object.defineProperty(this, "networkIndexes", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
// bias and freq arrays for learning
Object.defineProperty(this, "biases", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "frequencies", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "radiusPowers", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.pixels = pixels;
this.sampleFactorial = sampleFactorial;
this.networks = [];
this.networkIndexes = new Int32Array(256);
this.biases = new Int32Array(maximumColorsSize);
this.frequencies = new Int32Array(maximumColorsSize);
this.radiusPowers = new Int32Array(maximumColorsSize >> 3);
this.init();
this.learn();
this.unBiasNetwork();
this.buildIndexes();
}
/**
* Builds the networks' color map.
* @returns A RGB-encoded {@link Float64Array}.
*/
getColorMap() {
const map = new Float64Array(maximumColorsSize * 3);
const index = new Float64Array(maximumColorsSize);
for (let i = 0; i < maximumColorsSize; i++) {
index[this.networks[i][3]] = i;
}
for (let l = 0, k = 0; l < maximumColorsSize; l++) {
const network = this.networks[index[l]];
map[k++] = network[0];
map[k++] = network[1];
map[k++] = network[2];
}
return map;
}
/**
* Searches for BGR values 0..255 and returns a color index
* @param b The blue color byte, between 0 and 255.
* @param g The green color byte, between 0 and 255.
* @param r The red color byte, between 0 and 255.
* @returns The best color index.
*/
lookupRGB(b, g, r) {
// Biggest possible distance is 256 * 3, so we will define the biggest as an out-of-bounds number.
let bestDistance = 1000;
let best = -1;
const index = this.networkIndexes[g];
// Index on `g`
for (let i = index; i < maximumColorsSize; ++i) {
const network = this.networks[i];
// Compare the distance of the green element, break if it's too big:
let distance = network[1] - g;
if (distance >= bestDistance)
break;
// If `distance` is negative, make it positive:
if (distance < 0)
distance = -distance;
// Compare the distance with the blue element added, continue if it's too big:
distance += Math.abs(network[0] - b);
if (distance >= bestDistance)
continue;
// Compare the distance with the red element added, continue if it's too big:
distance += Math.abs(network[2] - r);
if (distance >= bestDistance)
continue;
bestDistance = distance;
best = network[3];
}
// Start at networkIndex[g] and work outwards
for (let j = index - 1; j >= 0; --j) {
const network = this.networks[j];
// Compare the distance of the green element, break if it's too big:
let distance = g - network[1];
if (distance >= bestDistance)
break;
// If `distance` is negative, make it positive:
if (distance < 0)
distance = -distance;
// Compare the distance with the blue element added, continue if it's too big:
distance += Math.abs(network[0] - b);
if (distance >= bestDistance)
continue;
// Compare the distance with the red element added, continue if it's too big:
distance += Math.abs(network[2] - r);
if (distance >= bestDistance)
continue;
bestDistance = distance;
best = network[3];
}
return best;
}
/**
* Initializes the state for the arrays.
*/
init() {
for (let i = 0; i < maximumColorsSize; i++) {
const v = (i << (networkBiasShift + 8)) / maximumColorsSize;
this.networks[i] = new Float64Array([v, v, v, 0]);
this.frequencies[i] = integerBias / maximumColorsSize;
this.biases[i] = 0;
}
}
/**
* Un-biases network to give byte values 0..255 and record position i to prepare for sort.
*/
unBiasNetwork() {
for (let i = 0; i < maximumColorsSize; i++) {
const network = this.networks[i];
network[0] >>= networkBiasShift;
network[1] >>= networkBiasShift;
network[2] >>= networkBiasShift;
network[3] = i; // record color number
}
}
/**
* Moves neuron `i` towards biased (`B`, `G`, `R`) by factor `alpha`.
* @param alpha The factor at which the neuron `i` should move towards.
* @param i The neuron's index.
* @param b The blue color.
* @param g The green color.
* @param r The red color.
*/
alterSingle(alpha, i, b, g, r) {
const network = this.networks[i];
network[0] -= (alpha * (network[0] - b)) / initialAlpha;
network[1] -= (alpha * (network[1] - g)) / initialAlpha;
network[2] -= (alpha * (network[2] - r)) / initialAlpha;
}
/**
* Moves neurons in a `radius` around index `i` towards biased (`B`, `G`, `R`) by factor
* {@link NeuQuant.radiusPowers `radiusPower[m]`}.
* @param radius The radius around `i` to alter.
* @param i The neuron's index.
* @param b The blue color.
* @param g The green color.
* @param r The red color.
*/
alterNeighbors(radius, i, b, g, r) {
const lo = Math.abs(i - radius);
const hi = Math.min(i + radius, maximumColorsSize);
let j = i + 1;
let k = i - 1;
let m = 1;
while (j < hi || k > lo) {
const alpha = this.radiusPowers[m++];
if (j < hi) {
const network = this.networks[j++];
network[0] -= (alpha * (network[0] - b)) / alphaRadiusBias;
network[1] -= (alpha * (network[1] - g)) / alphaRadiusBias;
network[2] -= (alpha * (network[2] - r)) / alphaRadiusBias;
}
if (k > lo) {
const network = this.networks[k--];
network[0] -= (alpha * (network[0] - b)) / alphaRadiusBias;
network[1] -= (alpha * (network[1] - g)) / alphaRadiusBias;
network[2] -= (alpha * (network[2] - r)) / alphaRadiusBias;
}
}
}
/**
* Searches for biased BGR values.
*
* - Finds the closest neuron (minimum distance) and updates {@link NeuQuant.frequencies}.
* - Finds the best neuron (minimum distance-bias) and returns the position.
*
* For frequently chosen neurons, {@link NeuQuant.frequencies `frequencies[i]`} is high and
* {@link NeuQuant.biases `biases[i]`} is negative.
*
* The latter is determined by the multiplication of `gamma` with the subtraction of the inverse of
* {@link maximumColorsSize} with {@link NeuQuant.frequencies `frequencies[i]`}:
*
* ```typescript
* biases[i] = gamma * ((1 / maximumColorsSize) - frequencies[i])
* ```
* @param b The blue color.
* @param g The green color.
* @param r The red color.
* @returns The best bias position.
*/
contest(b, g, r) {
let bestDistance = ~(1 << 31);
let bestBiasDistance = bestDistance;
let bestPosition = -1;
let bestBiasPosition = bestPosition;
for (let i = 0; i < maximumColorsSize; i++) {
const network = this.networks[i];
const distance = Math.abs(network[0] - b) + Math.abs(network[1] - g) + Math.abs(network[2] - r);
if (distance < bestDistance) {
bestDistance = distance;
bestPosition = i;
}
const biasDistance = distance - (this.biases[i] >> (integerBiasShift - networkBiasShift));
if (biasDistance < bestBiasDistance) {
bestBiasDistance = biasDistance;
bestBiasPosition = i;
}
const betaFrequency = this.frequencies[i] >> betaShift;
this.frequencies[i] -= betaFrequency;
this.biases[i] += betaFrequency << gammaShift;
}
this.frequencies[bestPosition] += beta;
this.biases[bestPosition] -= betaGamma;
return bestBiasPosition;
}
/**
* Sorts the neural network and builds {@link NeuQuant.networkIndexes `networkIndex[0..255]`}.
*/
buildIndexes() {
let previousColor = 0;
let startPosition = 0;
for (let i = 0; i < maximumColorsSize; i++) {
const network = this.networks[i];
let smallestPosition = i;
let smallestValue = network[1]; // index on g
// Find smallest in [i .. maximumColorsSize - 1]
for (let j = i + 1; j < maximumColorsSize; j++) {
const q = this.networks[j];
if (q[1] < smallestValue) {
smallestPosition = j;
smallestValue = q[1]; // index on g
}
}
// Swap network (i) and q (smallestPosition) entries:
if (i !== smallestPosition) {
const q = this.networks[smallestPosition];
[q[0], network[0]] = [network[0], q[0]];
[q[1], network[1]] = [network[1], q[1]];
[q[2], network[2]] = [network[2], q[2]];
[q[3], network[3]] = [network[3], q[3]];
}
// smallestValue entry is now in position i
if (smallestValue !== previousColor) {
this.networkIndexes[previousColor] = (startPosition + i) >> 1;
for (let j = previousColor + 1; j < smallestValue; j++) {
this.networkIndexes[j] = i;
}
previousColor = smallestValue;
startPosition = i;
}
}
this.networkIndexes[previousColor] = (startPosition + maximumColorsPosition) >> 1;
for (let j = previousColor + 1; j < 256; j++) {
this.networkIndexes[j] = maximumColorsPosition;
}
}
/**
* Runs the main learning loop.
*/
learn() {
const length = this.pixels.length;
const alphaDecrement = 30 + (this.sampleFactorial - 1) / 3;
const samplePixels = length / (3 * this.sampleFactorial);
let delta = ~~(samplePixels / learningCycles);
let alpha = initialAlpha;
let radius = initialRadius;
let localRadius = radius >> initialRadiusBiasShift;
if (localRadius <= 1)
localRadius = 0;
for (let i = 0; i < localRadius; i++) {
this.radiusPowers[i] = alpha * (((localRadius * localRadius - i * i) * radiusBias) / (localRadius * localRadius));
}
let step;
if (length < minimumPictureBytes) {
this.sampleFactorial = 1;
step = 3;
}
else if (length % prime1 !== 0) {
step = 3 * prime1;
}
else if (length % prime2 !== 0) {
step = 3 * prime2;
}
else if (length % prime3 !== 0) {
step = 3 * prime3;
}
else {
step = 3 * prime4;
}
let pixelPosition = 0;
let i = 0;
while (i < samplePixels) {
const b = (this.pixels[pixelPosition] & 0xff) << networkBiasShift;
const g = (this.pixels[pixelPosition + 1] & 0xff) << networkBiasShift;
const r = (this.pixels[pixelPosition + 2] & 0xff) << networkBiasShift;
let j = this.contest(b, g, r);
this.alterSingle(alpha, j, b, g, r);
if (localRadius !== 0)
this.alterNeighbors(localRadius, j, b, g, r);
pixelPosition += step;
if (pixelPosition >= length)
pixelPosition -= length;
if (delta === 0)
delta = 1;
++i;
if (i % delta !== 0)
continue;
alpha -= alpha / alphaDecrement;
radius -= radius / initialRadiusDecrement;
localRadius = radius >> initialRadiusBiasShift;
if (localRadius <= 1)
localRadius = 0;
for (j = 0; j < localRadius; j++) {
this.radiusPowers[j] = alpha * (((localRadius * localRadius - j * j) * radiusBias) / (localRadius * localRadius));
}
}
}
}
exports.NeuQuant = NeuQuant;
//# sourceMappingURL=NeuQuant.js.map

1
node_modules/@skyra/gifenc/dist/lib/NeuQuant.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

104
node_modules/@skyra/gifenc/package.json generated vendored Normal file
View file

@ -0,0 +1,104 @@
{
"name": "@skyra/gifenc",
"version": "1.0.1",
"description": "A very fast server-side animated GIF generation for Node.js",
"author": "@skyra",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"sideEffects": false,
"homepage": "https://skyra-project.github.io/gifenc",
"files": [
"dist",
"!dist/tsconfig.tsbuildinfo"
],
"scripts": {
"lint": "eslint src --ext ts --fix",
"format": "prettier --write \"{src}/**/*.ts\"",
"docs": "typedoc",
"update": "yarn up \"@*/*\" -i && yarn up \"*\" -i",
"build": "tsc -b src && gen-esm-wrapper dist/index.js dist/index.mjs",
"watch": "yarn build -w",
"clean": "node scripts/clean-dist.mjs",
"sversion": "standard-version",
"prepublishOnly": "yarn clean && yarn build",
"prepare": "husky install .github/husky"
},
"dependencies": {
"tslib": "^2.4.0"
},
"devDependencies": {
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@sapphire/eslint-config": "^4.3.8",
"@sapphire/prettier-config": "^1.4.4",
"@sapphire/ts-config": "^3.3.4",
"@types/jest": "^29.2.0",
"@types/node": "^17.0.18",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"gen-esm-wrapper": "^1.1.3",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"standard-version": "^9.3.2",
"typedoc": "^0.23.17",
"typescript": "^4.8.4"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"minimist": "^1.2.7"
},
"repository": {
"type": "git",
"url": "git+https://github.com/skyra-project/gifenc.git"
},
"engines": {
"node": ">=v14.18.0",
"npm": ">=7.24.2"
},
"keywords": [
"typescript",
"ts",
"yarn",
"gif",
"gifenc",
"encoder",
"utility"
],
"bugs": {
"url": "https://github.com/skyra-project/gifenc/issues"
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"lint-staged": {
"*.{mjs,js,ts}": "eslint --fix --ext mjs,js,ts"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"publishConfig": {
"access": "public"
},
"eslintConfig": {
"extends": "@sapphire"
},
"prettier": "@sapphire/prettier-config",
"packageManager": "yarn@3.2.4"
}