diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..f2c16c9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: matmen, evanwashere + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. ... + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Platform:** + - OS: [e.g. iOS, Windows] + - Environment [e.g. Chrome, Firefox, NodeJS, Deno] + - Version [e.g. 1.0.1, 1.1.20] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..7cbe67c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FR]" +labels: enhancement +assignees: matmen + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/codacy-analysis.yml b/.github/workflows/codacy-analysis.yml new file mode 100644 index 0000000..94d1293 --- /dev/null +++ b/.github/workflows/codacy-analysis.yml @@ -0,0 +1,49 @@ +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '0 12 * * *' + +jobs: + codacy-security-scan: + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v2 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@1.1.0 + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: results.sarif diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index c26282d..0000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,28 +0,0 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: Node.js CI - -on: - push: - branches: [ master, dev ] - pull_request: - branches: [ master, dev ] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [12.x, 14.x, 15.x] - - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: npm run build --if-present - - run: npm test diff --git a/.github/workflows/webpack.yml b/.github/workflows/webpack.yml new file mode 100644 index 0000000..5b6f327 --- /dev/null +++ b/.github/workflows/webpack.yml @@ -0,0 +1,29 @@ +name: Webpack CI + +on: + push: + branches: [ browser ] + pull_request: + branches: [ browser ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [ 16.x ] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm i --global webpack webpack-cli + - run: npm run build + - run: git config --local user.name "github-actions[bot]" + - run: git config --local user.email "github-actions[bot]@users.noreply.github.com" + - run: git add -A + - run: git commit -m "Update bundle" && git push || echo "Nothing to bundle!" diff --git a/.gitignore b/.gitignore index 4f4dcc2..d229b68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +old/ .idea/ -.nyc_output/ coverage/ -.node_modules/ \ No newline at end of file +.DS_Store +.nyc_output/ +node_modules/ \ No newline at end of file diff --git a/ImageScript.d.ts b/ImageScript.d.ts new file mode 100644 index 0000000..c613baa --- /dev/null +++ b/ImageScript.d.ts @@ -0,0 +1,955 @@ +export class Image { + private __width__: number; + private __height__: number; + private __buffer__: ArrayBuffer; + private __view__: DataView; + private __u32__: Uint32Array; + bitmap: Uint8ClampedArray; + + constructor(width: number, height: number); + + private toString(): `Image<${number}x${number}>`; + + get width(): number; + + get height(): number; + + *[Symbol.iterator](): void; + + *iterateWithColors(): Generator< + [x: number, y: number, color: number], + void, + unknown + >; + + static rgbaToColor(r: number, g: number, b: number, a: number): number; + + static rgbToColor(r: number, g: number, b: number): number; + + static hslaToColor(h: number, s: number, l: number, a: number): number; + + static hslToColor(h: number, s: number, l: number): number; + + static rgbaToHSLA(r: number, g: number, b: number, a: number): number[]; + + static colorToRGBA(color: number): number[]; + + static colorToRGB(color: number): number[]; + + getPixelAt(x: number, y: number): number; + + getRGBAAt(x: number, y: number): Uint8ClampedArray; + + setPixelAt(x: number, y: number, pixelColor: number): this; + + private __set_pixel__(x: number, y: number, pixelColor: number): void; + + private __check_boundaries__(x: number, y: number): void; + + private static get __out_of_bounds__(): string; + + /** + * Fills the entire image with the supplied color. + * + * @param color + */ + fill(color: number | ColorFunction): this; + + clone(): Image; + + /** + * Use + * {@link https://en.wikipedia.org/wiki/Image_scaling#Nearest-neighbor_interpolation Nearest-neighbor} + * resizing. + */ + static get RESIZE_NEAREST_NEIGHBOR(): "RESIZE_NEAREST_NEIGHBOR"; + + /** + * Used for automatically preserving an image's aspect ratio when resizing. + */ + static get RESIZE_AUTO(): -1; + + /** + * Resizes the image by the given factor. + * + * @param factor Fraction, where: + * - `0.5` is "50%" (half) + * - `1.0` is "100%" (same size) + * - `2.0` is "200%" (double) + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + scale(factor: number, mode?: ResizeMode): this; + + private __scale__(factor: number, mode?: ResizeMode); + + /** + * Resizes the image to the given dimensions. + * Use {@link Image.RESIZE_AUTO} as either width or height to automatically + * preserve the aspect ratio. + * + * @param width The new width. + * @param height The new height. + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + resize(width: number, height: number, mode?: ResizeMode): this; + + /** + * Resizes the image so it is contained in the given bounding box. + * Can return an image with one axis smaller than the given bounding box. + * + * @param width The width of the bounding box + * @param height The height of the bounding box + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + contain(width: number, height: number, mode?: ResizeMode): this; + + /** + * Resizes the image so it is contained in the given bounding box, placing it in the center of the given bounding box. + * Always returns the exact dimensions of the bounding box. + * + * @param width The width of the bounding box + * @param height The height of the bounding box + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + fit(width: number, height: number, mode?: ResizeMode): this; + + /** + * Resizes the image so it covers the given bounding box, cropping the overflowing edges. + * Always returns the exact dimensions of the bounding box. + * + * @param width The width of the bounding box + * @param height The height of the bounding box + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + cover(width: number, height: number, mode?: ResizeMode): this; + + private __resize__(width: number, height: number, mode?: ResizeMode): this; + + private __resize_nearest_neighbor__(width: number, height: number): this; + + crop(x: number, y: number, width: number, height: number): this; + + private __crop__(x: number, y: number, width: number, height: number): this; + + /** + * Draws a box at the specified coordinates. + */ + drawBox( + x: number, + y: number, + width: number, + height: number, + color: number | ColorFunction + ): this; + + private __fast_box__( + x: number, + y: number, + width: number, + height: number, + color: number + ): this; + + /** + * Draws a circle at the specified coordinates with the specified radius. + */ + drawCircle( + x: number, + y: number, + radius: number, + color: number | ColorFunction + ): this; + + /** + * Crops the image into a circle. + * + * @param max Whether to use the larger dimension for the size. Default: `false` + * @param feathering How much feathering to apply to the edges. Default: `0` + */ + cropCircle(max?: boolean, feathering?: number): this; + + /** + * Sets the image's opacity. + * + * @param opacity `0`-`1`, where `0` is completely transparent and + * `1` is completely opaque. + * @param absolute Whether to scale the current opacity (`false`) or + * just set the new opacity (`true`). Default: `false` + */ + opacity(opacity: number, absolute?: boolean): this; + + /** + * Set the red channel's saturation value. + * + * @param saturation `0`-`1` + * @param absolute Whether to scale the current saturation (`false`) or + * just set the new saturation (`true`). Default: `false` + */ + red(saturation: number, absolute?: boolean): this; + + /** + * Set the green channel's saturation value. + * + * @param saturation `0`-`1` + * @param absolute Whether to scale the current saturation (`false`) or + * just set the new saturation (`true`). Default: `false` + */ + green(saturation: number, absolute?: boolean): this; + + /** + * Set the blue channel's saturation value. + * + * @param saturation `0`-`1` + * @param absolute Whether to scale the current saturation (`false`) or + * just set the new saturation (`true`). Default: `false` + */ + blue(saturation: number, absolute?: boolean): this; + + private __set_channel_value__( + value: number, + absolute: boolean, + offset: number + ): void; + + /** + * Sets the brightness of the image. + * + * @param value `0`-`1` + * @param absolute Whether to scale the current lightness (`false`) or + * just set the new lightness (`true`). Default: `false` + */ + lightness(value: number, absolute?: boolean): this; + + /** + * Sets the saturation of the image. + * + * @param value `0`-`1` + * @param absolute Whether to scale the current saturation (`false`) or + * just set the new saturation (`true`). Default: `false` + */ + saturation(value: number, absolute?: boolean): this; + + /** + * Composites (overlays) the {@link source} onto this image at the + * specified coordinates. + */ + composite(source: this, x?: number, y?: number): this; + + /** + * Inverts the image's colors. + */ + invert(): this; + + /** + * Inverts the image's value (lightness). + */ + invertValue(): this; + + /** + * Inverts the image's saturation. + */ + invertSaturation(): this; + + /** + * Inverts the image's hue. + */ + invertHue(): this; + + /** + * Shifts the image's hue. + */ + hueShift(degrees: number): this; + + /** + * Gets the average color of the image. + */ + averageColor(): number; + + /** + * Gets the image's dominant color. + * + * @param ignoreBlack Whether to ignore dark colors below the threshold. + * Default: `true` + * @param ignoreWhite Whether to ignore light colors above the threshold. + * Default: `true` + * @param bwThreshold The black/white threshold (`0`-`64`). + * Default: `0xf` (`15`) + */ + dominantColor( + ignoreBlack?: boolean, + ignoreWhite?: boolean, + bwThreshold?: number + ): number; + + /** + * Rotates the image the given amount of degrees. + * + * @param angle The angle to rotate the image for (in degrees) + * @param resize Whether to resize the image so it fits all pixels (`true`) or + * just ignore outlying pixels (`false`). Default: `true` + */ + rotate(angle: number, resize?: boolean): this; + + /** + * Flips / mirrors the image horizontally or vertically. + */ + flip(direction: "horizontal" | "vertical"): this; + + private __apply__(image: this | Frame): this | Frame; + + /** + * Creates a multi-point gradient generator. + * + * @param colors The gradient points to use + * (e.g. `{0: 0xff0000ff, 1: 0x00ff00ff}`). + * @returns The gradient generator. The function argument is the position + * in the gradient (`0`-`1`). + */ + static gradient(colors: { + [position: number]: number; + }): (position: number) => number; + + /** + * Rounds the image's corners. + * + * @param radius Default: `min(width, height) / 4` + */ + roundCorners(radius?: number): this; + + private static __gradient__(startColor: number, endColor: number): number; + + /** + * @param radius Default: `2` + */ + fisheye(radius?: number): this; + + /** + * Encodes the image into a PNG. + * + * @param compression `0`-`9`, where `0` is no compression and `9` is highest + * compression (default: `1`) + * @param metadata + */ + async encode( + compression?: PNGCompressionLevel, + metadata?: PNGMetadata + ): Promise; + async encode(metadata?: PNGMetadata): Promise; + + /** + * Encodes the image into a JPEG. + * + * @param quality `1`-`100`, where `1` is lowest quality (highest compression) + * and `100` is highest quality (lowest compression). Default: `90` + */ + async encodeJPEG(quality?: JPEGQuality): Promise; + + /** + * Encodes the image into a WEBP. + * + * @param quality `0`-`100`, or `null` for lossless. `0` is lowest quality + * (highest compression) and `100` is highest quality (lowest compression). + * Default: `null` + */ + async encodeWEBP(quality?: null | WEBPQuality): Promise; + + /** + * Decodes an image (PNG, JPEG or TIFF). + * + * @param data The binary data to decode + * @returns The decoded image + */ + static async decode(data: Buffer | Uint8Array): Promise; + + /** + * Scale the SVG by the given amount. For use with {@link Image.renderSVG}. + */ + static get SVG_MODE_SCALE(): 1; + + /** + * Scale the SVG to fit the given width. For use with {@link Image.renderSVG}. + */ + static get SVG_MODE_WIDTH(): 2; + + /** + * Scale the SVG to fit the given height. For use with {@link Image.renderSVG}. + */ + static get SVG_MODE_HEIGHT(): 3; + + /** + * Creates a new image from the given SVG. + * + * @param svg + * @param size + * @param mode {@link Image.SVG_MODE_SCALE}, {@link Image.SVG_MODE_WIDTH}, or + * {@link Image.SVG_MODE_HEIGHT}. + * + * @returns New bitmap image with the rendered {@link svg}. + */ + static async renderSVG( + svg: string, + size?: number, + mode?: SVGScaleMode + ): Promise; + + /** + * Creates a new image containing the rendered text. + * + * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use. + * @param scale + * @param text + * @param color + * @param layout + * + * @returns New image with the rendered {@link text}. + */ + static async renderText( + font: Uint8Array, + scale: number, + text: string, + color?: number, + layout?: TextLayout + ): Promise; +} + +export type FrameDisposalModeName = "any" | "keep" | "previous" | "background"; + +export type FrameDisposalModeId = 0 | 1 | 2 | 3; + +/** + * Represents a frame in a GIF. + */ +export class Frame extends Image { + static get DISPOSAL_KEEP(): "keep"; + + static get DISPOSAL_PREVIOUS(): "previous"; + + static get DISPOSAL_BACKGROUND(): "background"; + + private static __convert_disposal_mode__( + mode: FrameDisposalModeName | FrameDisposalModeId + ): FrameDisposalModeId; + + /** + * Creates a new, blank frame. + * + * @param width + * @param height + * @param duration Milliseconds (default: `100`) + * @param xOffset Offset on the X-axis (default: `0`) + * @param yOffset Offset on the y-axis (default: `0`) + * @param disposalMode The frame's disposal mode (default: `'keep'`) + */ + constructor( + width: number, + height: number, + duration: number, + xOffset?: number, + yOffset?: number, + disposalMode?: FrameDisposalModeName | FrameDisposalModeId + ); + + /** + * Milliseconds. + */ + duration: number; + + xOffset: number; + + yOffset: number; + + get disposalMode(): FrameDisposalModeId; + + set disposalMode(disposalMode: FrameDisposalModeName | FrameDisposalModeId); + + toString(): `Frame<${number}x${number}x${number}ms>`; + + /** + * Converts an Image instance to a Frame, cloning it in the process + * @param image The image to create the frame from + * @param duration Milliseconds (default: `100`) + * @param xOffset Offset on the X-axis (default: `0`) + * @param yOffset Offset on the y-axis (default: `0`) + * @param disposalMode The frame's disposal mode (default: `'keep'`) + */ + static from( + image: Image, + duration?: number, + xOffset?: number, + yOffset?: number, + disposalMode?: FrameDisposalModeName | FrameDisposalModeId + ): Frame; + + /** + * @param width + * @param height + * @param mode Default: {@link Frame.DISPOSAL_KEEP} + */ + resize( + width: number, + height: number, + mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string + ): Image; +} + +/** + * Represents a GIF image as an array of frames. + */ +export class GIF extends Array { + /** + * @param frames + * @param loopCount How many times to loop the GIF for (`-1` = unlimited). + */ + constructor(frames: Frame[], loopCount?: number); + + get width(): number; + + get height(): number; + + toString(): `GIF<${number}x${number}x${number}ms>`; + + *[Symbol.iterator](): Generator; + + slice(start: number, end: number): GIF; + + /** + * Milliseconds. + */ + get duration(): number; + + /** + * @param quality GIF quality `0`-`100` (default: `95`) + */ + async encode(quality?: GIFQuality): Promise; + + /** + * @param data + * @param onlyExtractFirstFrame Whether to end GIF decoding after the first + * frame (default: `false`) + */ + static async decode( + data: Buffer | Uint8Array, + onlyExtractFirstFrame?: boolean + ): Promise; + + /** + * @param width + * @param height + * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR} + */ + resize(width: number, height: number, mode?: ResizeMode): void; +} + +export type WrapStyle = "word" | "char"; + +export type VerticalAlign = "left" | "center" | "right"; + +export type HorizontalAlign = "top" | "middle" | "bottom"; + +export class TextLayout { + /** + * @param options Defaults: + * ```js + * { + * maxWidth: Infinity, + * maxHeight: Infinity, + * wrapStyle: 'word', + * verticalAlign: 'left', + * horizontalAlign: 'top', + * wrapHardBreaks: true, + * } + * ``` + */ + constructor(options?: { + /** @default Infinity */ + maxWidth?: number; + + /** @default Infinity */ + maxHeight?: number; + + /** @default 'word' */ + wrapStyle?: WrapStyle; + + /** @default 'left' */ + verticalAlign?: VerticalAlign; + + /** @default 'top' */ + horizontalAlign?: HorizontalAlign; + + /** @default true */ + wrapHardBreaks?: boolean; + }); +} + +export type ImageTypeName = "png" | "jpeg" | "tiff" | "gif"; + +export class ImageType { + static getType(data: Buffer | Uint8Array): ImageTypeName | null; + + static isPNG(view: DataView): boolean; + + static isJPEG(view: DataView): boolean; + + static isTIFF(view: DataView): boolean; + + static isGIF(view: DataView): boolean; +} + +/** + * @param data + * @param onlyExtractFirstFrame Whether to end GIF decoding after the first + * frame (default: `false`) + */ +export function decode( + data: Uint8Array | Buffer, + onlyExtractFirstFrame?: boolean +): Promise; + +export type PNGMetadata = { + title?: string; + author?: string; + description?: string; + copyright?: string; + creationTime?: string | number | Date; + software?: string; + disclaimer?: string; + warning?: string; + source?: string; + comment?: string; +}; + +export type ColorFunction = (x: number, y: number) => number; + +export type ResizeMode = "RESIZE_NEAREST_NEIGHBOR" | -1; + +/** + * - `0` = no compression + * - `9` = highest compression + */ +export type PNGCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + +/** + * {@link Image.SVG_MODE_SCALE}, {@link Image.SVG_MODE_WIDTH}, or + * {@link Image.SVG_MODE_HEIGHT}. + */ +export type SVGScaleMode = 1 | 2 | 3; + +/** + * - `0` = **lowest** quality (smallest file size) + * - `100` = **highest** quality (largest file size) + */ +export type WEBPQuality = + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21 + | 22 + | 23 + | 24 + | 25 + | 26 + | 27 + | 28 + | 29 + | 30 + | 31 + | 32 + | 33 + | 34 + | 35 + | 36 + | 37 + | 38 + | 39 + | 40 + | 41 + | 42 + | 43 + | 44 + | 45 + | 46 + | 47 + | 48 + | 49 + | 50 + | 51 + | 52 + | 53 + | 54 + | 55 + | 56 + | 57 + | 58 + | 59 + | 60 + | 61 + | 62 + | 63 + | 64 + | 65 + | 66 + | 67 + | 68 + | 69 + | 70 + | 71 + | 72 + | 73 + | 74 + | 75 + | 76 + | 77 + | 78 + | 79 + | 80 + | 81 + | 82 + | 83 + | 84 + | 85 + | 86 + | 87 + | 88 + | 89 + | 90 + | 91 + | 92 + | 93 + | 94 + | 95 + | 96 + | 97 + | 98 + | 99 + | 100; + +/** + * - `0` = **lowest** quality (smallest file size) + * - `100` = **highest** quality (largest file size) + */ +export type JPEGQuality = + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21 + | 22 + | 23 + | 24 + | 25 + | 26 + | 27 + | 28 + | 29 + | 30 + | 31 + | 32 + | 33 + | 34 + | 35 + | 36 + | 37 + | 38 + | 39 + | 40 + | 41 + | 42 + | 43 + | 44 + | 45 + | 46 + | 47 + | 48 + | 49 + | 50 + | 51 + | 52 + | 53 + | 54 + | 55 + | 56 + | 57 + | 58 + | 59 + | 60 + | 61 + | 62 + | 63 + | 64 + | 65 + | 66 + | 67 + | 68 + | 69 + | 70 + | 71 + | 72 + | 73 + | 74 + | 75 + | 76 + | 77 + | 78 + | 79 + | 80 + | 81 + | 82 + | 83 + | 84 + | 85 + | 86 + | 87 + | 88 + | 89 + | 90 + | 91 + | 92 + | 93 + | 94 + | 95 + | 96 + | 97 + | 98 + | 99 + | 100; + +/** + * - `0` = **lowest** quality (smallest file size) + * - `100` = **highest** quality (largest file size) + */ +export type GIFQuality = + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21 + | 22 + | 23 + | 24 + | 25 + | 26 + | 27 + | 28 + | 29 + | 30 + | 31 + | 32 + | 33 + | 34 + | 35 + | 36 + | 37 + | 38 + | 39 + | 40 + | 41 + | 42 + | 43 + | 44 + | 45 + | 46 + | 47 + | 48 + | 49 + | 50 + | 51 + | 52 + | 53 + | 54 + | 55 + | 56 + | 57 + | 58 + | 59 + | 60 + | 61 + | 62 + | 63 + | 64 + | 65 + | 66 + | 67 + | 68 + | 69 + | 70 + | 71 + | 72 + | 73 + | 74 + | 75 + | 76 + | 77 + | 78 + | 79 + | 80 + | 81 + | 82 + | 83 + | 84 + | 85 + | 86 + | 87 + | 88 + | 89 + | 90 + | 91 + | 92 + | 93 + | 94 + | 95 + | 96 + | 97 + | 98 + | 99 + | 100; diff --git a/ImageScript.js b/ImageScript.js index e2acb0b..88f1278 100644 --- a/ImageScript.js +++ b/ImageScript.js @@ -1,9 +1,18 @@ const png = require('./utils/png'); -const fontlib = require('./utils/wasm/font'); +const mem = require('./utils/buffer.js'); +const giflib = require('./utils/wasm/gif'); const svglib = require('./utils/wasm/svg'); +const {version} = require('./package.json'); +const fontlib = require('./utils/wasm/font'); const jpeglib = require('./utils/wasm/jpeg'); const tifflib = require('./utils/wasm/tiff'); -const giflib = require('./utils/wasm/gif'); + +const MAGIC_NUMBERS = { + PNG: 0x89504e47, + JPEG: 0xffd8ff, + TIFF: 0x49492a00, + GIF: 0x474946 +}; /** * Represents an image; provides utility functions @@ -49,11 +58,6 @@ class Image { return `Image<${this.width}x${this.height}>`; } - /** @private */ - static new(width, height) { - return new this(width, height); - } - /** * The images width * @returns {number} @@ -71,8 +75,8 @@ class Image { } /** - * Yields an [x,y] array for every pixel in the image - * @yields {[number, number]} The coordinates of the pixel + * Yields an [x, y] array for every pixel in the image + * @yields {number[]} The coordinates of the pixel ([x, y]) * @returns {void} */ * [Symbol.iterator]() { @@ -84,9 +88,8 @@ class Image { } /** - * Yields an [x,y,color] array for every pixel in the image - * @yields {[number, number, number]} The coordinates and color of the pixel - * @returns {void} + * Yields an [x, y, color] array for every pixel in the image + * @yields {number[]} The coordinates and color of the pixel ([x, y, color]) */ * iterateWithColors() { let offset = 0; @@ -177,7 +180,7 @@ class Image { * @param g {number} (0..255) * @param b {number} (0..255) * @param a {number} (0..255) - * @returns {(number)[]} The HSLA values ([H, S, L, A]) + * @returns {number[]} The HSLA values ([H, S, L, A]) */ static rgbaToHSLA(r, g, b, a) { r /= 255; @@ -236,7 +239,7 @@ class Image { */ getPixelAt(x, y) { this.__check_boundaries__(x, y); - return this.__view__.getUint32((~~y - 1) * this.width + (~~x - 1), false); + return this.__view__.getUint32(((~~y - 1) * this.width + (~~x - 1)) * 4, false); } /** @@ -335,7 +338,7 @@ class Image { * @returns {Image} */ clone() { - const image = Image.new(this.width, this.height); + const image = new Image(this.width, this.height); image.bitmap.set(this.bitmap); return image; } @@ -363,8 +366,14 @@ class Image { * @returns {Image} */ scale(factor, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const image = this.__scale__(factor, mode); + return this.__apply__(image); + } + + /** @private */ + __scale__(factor, mode = Image.RESIZE_NEAREST_NEIGHBOR) { if (factor === 1) return this; - return this.resize(this.width * factor, this.height * factor, mode); + return this.__resize__(this.width * factor, this.height * factor, mode); } /** @@ -376,6 +385,54 @@ class Image { * @returns {Image} The resized image */ resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const image = this.__resize__(width, height, mode); + return this.__apply__(image); + } + + /** + * Resizes the image so it is contained in the given bounding box. + * Can return an image with one axis smaller than the given bounding box. + * @param {number} width The width of the bounding box + * @param {number} height The height of the bounding box + * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use + * @returns {Image} The resized image + */ + contain(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const scaleFactor = width / height > this.width / this.height ? height / this.height : width / this.width; + return this.scale(scaleFactor, mode); + } + + /** + * Resizes the image so it is contained in the given bounding box, placing it in the center of the given bounding box. + * Always returns the exact dimensions of the bounding box. + * @param {number} width The width of the bounding box + * @param {number} height The height of the bounding box + * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use + * @returns {Image} The resized image + */ + fit(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const result = new Image(width, height); + this.contain(width, height, mode); + result.composite(this, (width - this.width) / 2, (height - this.height) / 2); + return this.__apply__(result); + } + + /** + * Resizes the image so it covers the given bounding box, cropping the overflowing edges. + * Always returns the exact dimensions of the bounding box. + * @param {number} width The width of the bounding box + * @param {number} height The height of the bounding box + * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use + * @returns {Image} The resized image + */ + cover(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const scaleFactor = width / height > this.width / this.height ? width / this.width : height / this.height; + const result = this.scale(scaleFactor, mode); + return result.crop((result.width - width) / 2, (result.height - height) / 2, width, height); + } + + /** @private */ + __resize__(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { if (width === Image.RESIZE_AUTO && height === Image.RESIZE_AUTO) throw new Error('RESIZE_AUTO can only be used for either width or height, not for both'); else if (width === Image.RESIZE_AUTO) width = this.width / this.height * height; else if (height === Image.RESIZE_AUTO) height = this.height / this.width * width; @@ -387,9 +444,12 @@ class Image { if (height < 1) throw new RangeError('Image has to be at least 1 pixel high'); + let image; if (mode === Image.RESIZE_NEAREST_NEIGHBOR) - return this.__resize_nearest_neighbor__(width, height); + image = this.__resize_nearest_neighbor__(width, height); else throw new Error('Invalid resize mode'); + + return image; } /** @@ -412,9 +472,7 @@ class Image { } } - this.__apply__(image); - - return this; + return image; } /** @@ -429,7 +487,7 @@ class Image { if (width > this.width) width = this.width; if (height > this.height) height = this.height; - return this.__apply__(this.__crop__(x, y, width, height)); + return this.__apply__(this.__crop__(~~x, ~~y, ~~width, ~~height)); } /** @@ -464,8 +522,10 @@ class Image { * @returns {Image} */ drawBox(x, y, width, height, color) { - x -= 1; - y -= 1; + x = ~~(x - 1); + y = ~~(y - 1); + width = ~~width; + height = ~~height; if (typeof color === 'function') { for (let tY = 1; tY <= height; tY++) { @@ -495,12 +555,12 @@ class Image { __fast_box__(x, y, width, height, color) { if (x < 0) { width += x; - x = 1; + x = 0; } if (y < 0) { height += y; - y = 1; + y = 0; } const right = Math.max(Math.min(x + width, this.width), 1); @@ -851,7 +911,7 @@ class Image { ? Math.abs(this.width * cos) + Math.abs(this.height * sin) : this.height; - const out = Image.new(width, height); + const out = new Image(width, height); const out_cx = width / 2 - .5; const out_cy = height / 2 - .5; @@ -942,8 +1002,8 @@ class Image { /** * @private - * @param {Image} image - * @returns {Image} + * @param {Image|Frame} image + * @returns {Image|Frame} */ __apply__(image) { this.__width__ = image.__width__; @@ -952,6 +1012,9 @@ class Image { this.__u32__ = image.__u32__; this.bitmap = image.bitmap; + if (image instanceof Frame) + return Frame.from(this, image.duration, image.xOffset, image.yOffset, image.disposalMode); + return this; } @@ -1071,26 +1134,95 @@ class Image { }; } + fisheye(radius = 2) { + const r = new Image(this.width, this.height); + + const w = this.width; + const h = this.height; + const tu32 = this.__u32__; + const ru32 = r.__u32__; + const iw = 1 / w; + const ih = 1 / h; + + for (const [x, y] of this) { + const xco = x * iw - .5; + const yco = y * ih - .5; + const dfc = Math.sqrt(xco ** 2 + yco ** 2); + const dis = 2 * dfc ** radius; + const nx = ((dis * xco / dfc + 0.5) * w) | 0; + const ny = ((dis * yco / dfc + 0.5) * h) | 0; + + if (nx < 1 || nx > w || ny < 1 || ny > h || isNaN(nx) || isNaN(ny)) + continue; + + ru32[y * w + x] = tu32[w * ny + nx]; + } + + const cO = tu32.length * .5 + w / 2; + ru32[cO] = tu32[cO]; + + return this.__apply__(r); + } + + /** + * @typedef {object} PNGMetadata + * @property {string} [title] The images title + * @property {string} [author] The images author + * @property {string} [description] The images description + * @property {string} [copyright] The images copyright info + * @property {string|number|Date} [creationTime=Date.now()] The images creation timestamp + * @property {string} [software="github.com/matmen/ImageScript vX.X.X"] The software used to create this image + * @property {string} [disclaimer] A disclaimer for the image + * @property {string} [warning] A warning for the image + * @property {string} [source] The images source + * @property {string} [comment] A comment for the image + */ + /** * Encodes the image into a PNG - * @param {number} compression The compression level to use (0-3) + * @param {number} compression The compression level to use (0-9) + * @param {PNGMetadata} [meta={}] Image metadata * @return {Promise} The encoded data */ - async encode(compression = 1) { - return await png.encode(this.bitmap, {width: this.width, height: this.height, level: compression, channels: 4}); + async encode(compression = 1, { + title, + author, + description, + copyright, + creationTime, + software, + disclaimer, + warning, + source, + comment + } = {}) { + return png.encode(this.bitmap, { + width: this.width, + height: this.height, + level: compression, + channels: 4, + text: { + Title: title, + Author: author, + Description: description, + Copyright: copyright, + 'Creation Time': new Date(creationTime === undefined ? Date.now() : creationTime).toUTCString(), + Software: software === undefined ? `github.com/matmen/ImageScript v${version}` : software, + Disclaimer: disclaimer, + Warning: warning, + Source: source, + Comment: comment + } + }); } /** * Encodes the image into a JPEG - * @param {number} [quality=90] The JPEG quality to use + * @param {number} [quality=90] The JPEG quality to use (1-100) * @return {Promise} */ async encodeJPEG(quality = 90) { - quality = Math.max(1, Math.min(100, quality)); - const jpegCanvas = new this.constructor(this.width, this.height); - jpegCanvas.fill(0xff); - jpegCanvas.composite(this); - return jpeglib.encode(this.width, this.height, quality, jpegCanvas.bitmap); + return (await jpeglib.init()).encode(this.bitmap, this.width, this.height, quality); } /** @@ -1101,26 +1233,22 @@ class Image { static async decode(data) { let image; - let view; - if (!ArrayBuffer.isView(data)) { - data = new Uint8Array(data); - view = new DataView(data.buffer); - } else { - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); - view = new DataView(data.buffer, data.byteOffset, data.byteLength); - } + data = mem.view(data); + const view = new DataView(data.buffer, data.byteOffset, data.byteLength); - if (view.getUint32(0, false) === 0x89504e47) { // PNG - const {width, height, pixels} = await png.decode(data); - image = new this(width, height); + if (ImageType.isPNG(view)) { // PNG + const {width, height, pixels} = png.decode(data); + image = new Image(width, height); image.bitmap.set(pixels); - } else if ((view.getUint32(0, false) >>> 8) === 0xffd8ff) { // JPEG - const status = await jpeglib.decode(0, data, 0, 0); - if (status === 1) throw new Error('Failed decoding JPEG image'); - const [pixelType, width, height] = jpeglib.meta(0); - image = new this(width, height); - const buffer = jpeglib.buffer(0); - jpeglib.free(0); + } else if (ImageType.isJPEG(view)) { // JPEG + const framebuffer = (await jpeglib.init()).decode(data); + + const width = framebuffer.width; + const height = framebuffer.height; + const pixelType = framebuffer.format; + + image = new Image(width, height); + const buffer = framebuffer.buffer; if (pixelType === 0) { const view = new DataView(image.bitmap.buffer); @@ -1141,15 +1269,11 @@ class Image { image.bitmap[i + 3] = 0xff; } } - } else if (view.getUint32(0, false) === 0x49492a00) { - const status = await tifflib.decode(0, data); - if (status === 1) throw new Error('Failed decoding TIFF image'); - const meta = tifflib.meta(0); - const buffer = tifflib.buffer(0); - tifflib.free(0); - - image = new this(...meta); - image.bitmap.set(buffer); + } else if (ImageType.isTIFF(view)) { // TIFF + const framebuffer = (await tifflib.init()).decode(data); + image = new Image(framebuffer.width, framebuffer.height); + + image.bitmap.set(framebuffer.buffer); } else throw new Error('Unsupported image type'); return image; @@ -1195,33 +1319,14 @@ class Image { if (mode !== this.SVG_MODE_SCALE && size < 1) throw new RangeError('SVG size must be >= 1') - if (typeof svg !== 'string') - svg = svg.toString(); + if (typeof svg === 'string') svg = new TextEncoder().encode(svg); + const framebuffer = (await svglib.init()).rasterize(svg, mode, size); - const status = await svglib.rgba(0, svg, mode, size, size, size); - if (status === 1) throw new Error('Failed parsing SVG'); - if (status === 2) throw new Error('Failed rendering SVG'); - const meta = svglib.meta(0); - const image = new this(...meta); - image.bitmap.set(svglib.buffer(0)); - svglib.free(0); - return image; - } + const image = new Image(framebuffer.width, framebuffer.height); - /** - * Wrap at individual characters. For use with {@link Image.renderText} - * @return {boolean} - */ - static get WRAP_STYLE_CHAR() { - return true; - } + image.bitmap.set(framebuffer.buffer); - /** - * Wrap at word ends. For use with {@link Image.renderText} - * @return {boolean} - */ - static get WRAP_STYLE_WORD() { - return false; + return image; } /** @@ -1229,23 +1334,39 @@ class Image { * @param {Uint8Array} font TrueType (ttf/ttc) or OpenType (otf) font buffer to use * @param {number} scale Font size to use * @param {string} text Text to render - * @param {number} color Text color to use - * @param {number} wrapWidth Image width before wrapping - * @param {boolean} wrapStyle Whether to break at words ({@link WRAP_STYLE_WORD}) or at characters ({@link WRAP_STYLE_CHAR}) + * @param {number} [color=0xffffffff] Text color to use + * @param {TextLayout} [layout] The text layout to use * @return {Promise} The rendered text */ - static async renderText(font, scale, text, color = 0xffffffff, wrapWidth = Infinity, wrapStyle = this.WRAP_STYLE_WORD) { + static async renderText(font, scale, text, color = 0xffffffff, layout = new TextLayout()) { + const { Font, Layout } = await fontlib.init(); + + font = new Font(scale, font); const [r, g, b, a] = Image.colorToRGBA(color); - await fontlib.load(0, font, scale); - fontlib.render(0, 0, scale, r, g, b, text, wrapWidth === Infinity ? null : wrapWidth, wrapStyle); - const buffer = fontlib.buffer(0); - const [width, height] = fontlib.meta(0); - fontlib.free(0); - const image = new this(width, height); - image.bitmap.set(buffer); - image.opacity(a / 0xff); - return image; + const layoutOptions = new Layout(); + + layoutOptions.reset({ + max_width: layout.maxWidth, + max_height: layout.maxHeight, + wrap_style: layout.wrapStyle, + vertical_align: layout.verticalAlign, + horizontal_align: layout.horizontalAlign, + wrap_hard_breaks: layout.wrapHardBreaks + }); + + layoutOptions.append(font, text, {scale}); + const framebuffer = layoutOptions.rasterize(r, g, b); + const image = new Image(framebuffer.width, framebuffer.height); + + image.bitmap.set(framebuffer.buffer); + + if (image.height > layout.maxHeight) + image.crop(0, 0, image.width, Math.floor(layoutOptions.lines() / image.height * layout.maxHeight) * (image.height / layoutOptions.lines())); + + font.free(); + layoutOptions.free(); + return image.opacity(a / 0xff); } } @@ -1254,20 +1375,75 @@ class Image { * Represents a frame in a GIF * @extends Image */ -class Frame extends Image { + class Frame extends Image { + /** + * GIF frame disposal mode KEEP. For use with {@link Frame} + * @returns {string} + */ + static get DISPOSAL_KEEP() { + return 'keep'; + } + + /** + * GIF frame disposal mode PREVIOUS. For use with {@link Frame} + * @returns {string} + */ + static get DISPOSAL_PREVIOUS() { + return 'previous'; + } + + /** + * GIF frame disposal mode BACKGROUND. For use with {@link Frame} + * @returns {string} + */ + static get DISPOSAL_BACKGROUND() { + return 'background'; + } + + static __convert_disposal_mode__(mode) { + if (typeof mode === 'string') + mode = ['any', 'keep', 'previous', 'background'].indexOf(mode); + if (mode < 0 || mode > 3) + throw new RangeError('Invalid disposal mode'); + + return mode; + } + /** * Creates a new, blank frame * @param {number} width * @param {number} height * @param {number} [duration = 100] The frames duration (in ms) + * @param {number} [xOffset=0] The frames offset on the x-axis + * @param {number} [yOffset=0] The frames offset on the y-axis + * @param {string|number} [disposalMode=Frame.DISPOSAL_KEEP] The frame's disposal mode ({@link Frame.DISPOSAL_KEEP}, {@link Frame.DISPOSAL_PREVIOUS} or {@link Frame.DISPOSAL_BACKGROUND}) * @return {Frame} */ - constructor(width, height, duration = 100) { + constructor(width, height, duration = 100, xOffset = 0, yOffset = 0, disposalMode = Frame.DISPOSAL_KEEP) { if (isNaN(duration) || duration < 0) throw new RangeError('Invalid frame duration'); super(width, height); this.duration = duration; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.disposalMode = disposalMode; + } + + /** + * The Frame's disposal mode + * @returns {number} + */ + get disposalMode() { + return this.__disposalMode__; + } + + /** + * Sets the frame's disposal mode, converting it to the internal numeric value. + * @param {string|number} disposalMode The frame's disposal mode + */ + set disposalMode(disposalMode) { + this.__disposalMode__ = Frame.__convert_disposal_mode__(disposalMode); } toString() { @@ -1278,16 +1454,32 @@ class Frame extends Image { * Converts an Image instance to a Frame, cloning it in the process * @param {Image} image The image to create the frame from * @param {number} [duration = 100] The frames duration (in ms) + * @param {number} [xOffset=0] The frames offset on the x-axis + * @param {number} [yOffset=0] The frames offset on the y-axis + * @param {string|number} [disposalMode=Frame.DISPOSAL_KEEP] The frames disposal mode ({@link Frame.DISPOSAL_KEEP}, {@link Frame.DISPOSAL_PREVIOUS} or {@link Frame.DISPOSAL_BACKGROUND}) * @return {Frame} */ - static from(image, duration) { + static from(image, duration, xOffset, yOffset, disposalMode = Frame.DISPOSAL_KEEP) { if (!(image instanceof Image)) throw new TypeError('Invalid image passed'); - const frame = new Frame(image.width, image.height, duration); + + const frame = new Frame(image.width, image.height, duration, xOffset, yOffset, disposalMode); frame.bitmap.set(image.bitmap); return frame; } + + resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + const originalWidth = this.width; + const originalHeight = this.height; + + const result = super.resize(width, height, mode); + + this.xOffset *= result.width / originalWidth; + this.yOffset *= result.height / originalHeight; + + return result; + } } /** @@ -1298,57 +1490,319 @@ class GIF extends Array { /** * Creates a new GIF image. * @param {Frame[]} frames The frames to create the GIF from - * @param {number} [loopCount=0] How often to loop the GIF for (-1 = unlimited) + * @param {number} [loopCount=-1] How often to loop the GIF for (-1 = unlimited) * @property {number} loopCount How often the GIF will loop for */ constructor(frames, loopCount = -1) { super(...frames); - this.width = frames[0].width; - this.height = frames[0].height; - - for (const frame of this) { + for (const frame of this) if (!(frame instanceof Frame)) throw new TypeError(`Frame ${this.indexOf(frame)} is not an instance of Frame`); - if (frame.width !== this.width) throw new Error('Frames have different widths'); - if (frame.height !== this.height) throw new Error('Frames have different heights'); - } - if (loopCount < -1 || isNaN(loopCount)) throw new RangeError('Invalid loop count'); this.loopCount = loopCount; } + /** + * The GIFs width + * @returns {number} + */ + get width() { + let max = 0; + for (const frame of this) { + let width = frame.width + frame.xOffset; + if (max < width) + max = width; + } + + return max; + } + + /** + * The GIFs height + * @returns {number} + */ + get height() { + let max = 0; + for (const frame of this) { + let height = frame.height + frame.yOffset; + if (max < height) + max = height; + } + + return max; + } + toString() { return `GIF<${this.width}x${this.height}x${this.duration}ms>`; } + /** + * @returns {Generator} + */ + * [Symbol.iterator]() { + for (let i = 0; i < this.length; i++) + yield this[i]; + } + + slice(start, end) { + if (end === Infinity) + end = this.length; + const frames = new Array(end - start); + for (let i = 0; i < frames.length; i++) + frames[i] = this[i + start]; + return new GIF(frames, this.loopCount); + } + /** * The GIFs duration (in ms) * @return {number} */ get duration() { - return [...this].reduce((acc, frame) => acc + frame.duration, 0); + return this.reduce((acc, frame) => acc + frame.duration, 0); } /** * Encodes the image into a GIF - * @param {number} [quality=10] GIF quality ((best) 1..30 (worst)) + * @param {number} [quality=95] GIF quality 0-100 * @return {Promise} The encoded data */ - async encode(quality = 10) { - const encoder = await giflib.GIFEncoder.initialize(this.width, this.height, this.loopCount); + async encode(quality = 95) { + const encoder = new (await giflib.init()).Encoder(this.width, this.height, this.loopCount); + for (const frame of this) { if (!(frame instanceof Frame)) throw new Error('GIF contains invalid frames'); - encoder.add(~~(frame.duration / 10), quality, frame.bitmap); + encoder.add(frame.xOffset, frame.yOffset, ~~(frame.duration / 10), frame.width, frame.height, frame.bitmap, frame.disposalMode, quality / 100 * 29 + 1); } - const encoded = encoder.buffer(); - encoder.free(); - return encoded; + return encoder.u8(); } + + /** + * Decodes a GIF image + * @param {Buffer|Uint8Array} data The binary data to decode + * @param {boolean} [onlyExtractFirstFrame=false] Whether to end GIF decoding after the first frame + * @return {Promise} The decoded GIF + */ + static async decode(data, onlyExtractFirstFrame = false) { + let image; + data = mem.view(data); + const view = new DataView(data.buffer, data.byteOffset, data.byteLength); + + if (ImageType.isGIF(view)) { // GIF + const frames = []; + const decoder = new (await giflib.init()).Decoder(data); + + if (onlyExtractFirstFrame) { + const first = decoder.frames().next().value; + const frame = new Frame(first.width, first.height, 10 * first.delay, first.x, first.y, first.dispose); + + frame.bitmap.set(first.buffer); + + frames.push(frame); + image = new GIF(frames); + } + + const gwidth = decoder.width | 0; + const gheight = decoder.height | 0; + const u32 = new Uint32Array(decoder.width * decoder.height); + const u8 = new Uint8Array(u32.buffer, u32.byteOffset, u32.byteLength); + + for (const frame of decoder.frames()) { + let offset8 = 0 | 0; + let offset32 = 0 | 0; + const fx = frame.x | 0; + const fy = frame.y | 0; + const f8 = frame.buffer; + const mode = frame.dispose; + const width = frame.width | 0; + const height = frame.height | 0; + const f32 = new Uint32Array(f8.buffer, f8.byteOffset, width * height); + const f = frames[frames.push(new Frame(gwidth, gheight, 10 * frame.delay, 0, 0, 3)) - 1]; + + const t8 = f.bitmap; + const t32 = new Uint32Array(t8.buffer); + + t8.set(u8); + + if (2 === mode) { + for (let y = 0 | 0; y < height; y++) { + const y_offset = fx + gwidth * (y + fy) | 0; + + for (let x = 0 | 0; x < width; x++) { + const x_offset = x + y_offset; + + if (0 === f8[3 + offset8]) + t32[x_offset] = u32[x_offset]; + else t32[x_offset] = f32[offset32]; + + offset32++; + offset8 += 4; + } + } + } + + else if (3 === mode) { + for (let y = 0 | 0; y < height; y++) { + const y_offset = fx + gwidth * (y + fy) | 0; + + for (let x = 0 | 0; x < width; x++) { + const x_offset = x + y_offset; + + if (0 === f8[3 + offset8]) + t32[x_offset] = u32[x_offset]; + else t32[x_offset] = f32[offset32]; + + offset32++; + offset8 += 4; + u32[x_offset] = 0; + } + } + } + + else if (0 === mode || 1 === mode) { + t8.set(u8); + for (let y = 0 | 0; y < height; y++) { + const y_offset = fx + gwidth * (y + fy) | 0; + + for (let x = 0 | 0; x < width; x++) { + const x_offset = x + y_offset; + + if (0 === f8[3 + offset8]) + t32[x_offset] = u32[x_offset]; + else t32[x_offset] = f32[offset32]; + + offset32++; + offset8 += 4; + u32[x_offset] = t32[x_offset]; + } + } + } + } + + image = new GIF(frames); + } else throw new Error('Unsupported image type'); + + return image; + } + + resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) { + for (const frame of this) + frame.resize(width, height, mode); + } +} + +class TextLayout { + /** + * Layout options for {@link renderText} + * @param {object} [options] + * @param {number} [options.maxWidth=Infinity] The texts max width + * @param {number} [options.maxHeight=Infinity] The texts max height + * @param {string} [options.wrapStyle='word'] The texts wrap style when reaching the max width (word, char) + * @param {string} [options.verticalAlign='left'] The vertical align mode (left, center, right) + * @param {string} [options.horizontalAlign='top'] The horizontal align mode (top, middle, bottom) + * @param {string} [options.wrapHardBreaks=true] Whether to force wrap at new line characters + */ + constructor(options) { + const {maxWidth, maxHeight, wrapStyle, verticalAlign, horizontalAlign, wrapHardBreaks} = options || {}; + + this.maxWidth = maxWidth || Infinity; + if (isNaN(this.maxWidth) || this.maxWidth < 1) + throw new RangeError('Invalid maxWidth'); + + this.maxHeight = maxHeight || Infinity; + if (isNaN(this.maxHeight) || this.maxHeight < 1) + throw new RangeError('Invalid maxHeight'); + + this.wrapStyle = wrapStyle || 'word'; + if (!['word', 'char'].includes(this.wrapStyle)) + throw new RangeError('Invalid wrapStyle'); + + this.verticalAlign = verticalAlign || 'left'; + if (!['left', 'center', 'right'].includes(this.verticalAlign)) + throw new RangeError('Invalid verticalAlign'); + + this.horizontalAlign = horizontalAlign || 'top'; + if (!['top', 'middle', 'bottom'].includes(this.horizontalAlign)) + throw new RangeError('Invalid horizontalAlign'); + + this.wrapHardBreaks = typeof wrapHardBreaks === 'undefined' ? true : wrapHardBreaks; + if (typeof this.wrapHardBreaks !== 'boolean') + throw new TypeError('Invalid wrapHardBreaks'); + } +} + +class ImageType { + /** + * Gets an images type (png, jpeg, tiff, gif) + * @param {Buffer|Uint8Array} data The image binary to get the type of + * @returns {string|null} The image type (png, jpeg, tiff, gif, null) + */ + static getType(data) { + let view; + if (!ArrayBuffer.isView(data)) { + data = new Uint8Array(data); + view = new DataView(data.buffer); + } else { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + view = new DataView(data.buffer, data.byteOffset, data.byteLength); + } + + if (this.isPNG(view)) return 'png'; + if (this.isJPEG(view)) return 'jpeg'; + if (this.isTIFF(view)) return 'tiff'; + if (this.isGIF(view)) return 'gif'; + return null; + } + + /** + * @param {DataView} view + * @returns {boolean} + */ + static isPNG(view) { + return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.PNG; + } + + /** + * @param {DataView} view + * @returns {boolean} + */ + static isJPEG(view) { + return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.JPEG; + } + + /** + * @param {DataView} view + * @returns {boolean} + */ + static isTIFF(view) { + return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.TIFF; + } + + /** + * @param {DataView} view + * @returns {boolean} + */ + static isGIF(view) { + return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.GIF; + } +} + +/** + * Decodes the given image binary + * @param {Uint8Array|Buffer} data The image data + * @param {boolean} [onlyExtractFirstFrame] Whether to end GIF decoding after the first frame + * @returns {Promise} The decoded image + */ +function decode(data, onlyExtractFirstFrame) { + const type = ImageType.getType(data); + + if (type === 'gif') + return GIF.decode(data, onlyExtractFirstFrame); + return Image.decode(data); } -module.exports = {Image, GIF, Frame}; \ No newline at end of file +module.exports = {Image, GIF, Frame, TextLayout, ImageType, decode}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5d2197d --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +This software is licensed under the following license(s): +- GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 +- MIT License + +== SPDX-License-Identifier: AGPL-3.0-or-later OR MIT == + +You may choose to comply with either one of the above +mentioned licenses, but a license must be chosen. + +The corresponding license files can be found in the projects +root directory, prefixed with LICENSE, suffixed with their +corresponding SPDX identifier. \ No newline at end of file diff --git a/LICENSE.AGPL-3.0 b/LICENSE.AGPL-3.0 new file mode 100644 index 0000000..ce0100f --- /dev/null +++ b/LICENSE.AGPL-3.0 @@ -0,0 +1,619 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE.MIT b/LICENSE.MIT new file mode 100644 index 0000000..8f0286a --- /dev/null +++ b/LICENSE.MIT @@ -0,0 +1,19 @@ +Copyright (c) 2023 Mathis Mensing + +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. \ No newline at end of file diff --git a/README.md b/README.md index 167cc70..aafc8fa 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,45 @@ # ImageScript ##### zero-dependency JavaScript image manipulation [![Discord Server](https://img.shields.io/discord/691713541262147687.svg?label=Discord&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2&style=for-the-badge)](https://discord.gg/8hPrwAH) -[![Documentation](https://img.shields.io/badge/Documentationn-informational?style=for-the-badge)](https://oss-is.dreadful.tech/) +[![Documentation](https://img.shields.io/badge/Documentation-informational?style=for-the-badge)](https://imagescript.matmen.dev/) [![Github](https://img.shields.io/badge/Github-Repository-181717?logo=github&style=for-the-badge)](https://github.com/matmen/ImageScript) -[![deno.land](https://img.shields.io/badge/deno.land-181717?logo=deno&style=for-the-badge)](https://deno.land/x/imagescript) +[![deno.land](https://shields.io/badge/deno.land-gray?logo=deno&style=for-the-badge)](https://deno.land/x/imagescript@1.2.9) [![NPM](https://nodei.co/npm/imagescript.png)](https://www.npmjs.com/package/imagescript) --- -**ImageScript** is a zero-dependency alternative to common JavaScript bitmap image manipulation tools. -It can achieve much more performant results by utilizing lower-level memory access, less memory copying and WebAssembly for compression and encoding. +**ImageScript** is a zero-dependency alternative to common JavaScript bitmap image manipulation tools. It can achieve +much more performant results by utilizing lower-level memory access, less memory copying and WebAssembly / native +binaries for decoding and encoding. --- ### Features -- [Decoding images](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#decode) + +- [Decoding images](https://imagescript.matmen.dev/Image.html#.decode) - PNGs (grayscale, RGB, indexed colors) with and without alpha channels - JPEGs (grayscale, RGB, CMYK) - TIFFs -- [Rendering SVGs](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#rendersvg) -- [Rendering vector fonts](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#rendertext) -- Image manipulation functions ([crop](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#crop), [rotate](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#rotate), [composite](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#composite), ...) -- Color manipulation functions ([invert](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#invert), [hueShift](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#hueshift), ...) -- Color information functions ([averageColor](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#averagecolor), [dominantColor](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#dominantcolor), ...) -- Encoding images as [PNGs](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#encode), [JPEGs](https://oss-is.dreadful.tech/classes/_imagescript_.image.html#encodejpeg) and [GIFs](https://oss-is.dreadful.tech/classes/_imagescript_.gif.html#encode) +- [Decoding GIFs](https://imagescript.matmen.dev/GIF.html#.decode) +- [Rendering SVGs](https://imagescript.matmen.dev/Image.html#.renderSVG) +- [Rendering vector fonts](https://imagescript.matmen.dev/Image.html#.renderText) +- Image manipulation functions ([crop](https://imagescript.matmen.dev/Image.html#crop) + , [rotate](https://imagescript.matmen.dev/Image.html#rotate) + , [composite](https://imagescript.matmen.dev/Image.html#composite), ...) +- Color manipulation functions ([invert](https://imagescript.matmen.dev/Image.html##invert) + , [hueShift](https://imagescript.matmen.dev/Image.html##hueshift), ...) +- Color information functions ([averageColor](https://imagescript.matmen.dev/Image.html##averagecolor) + , [dominantColor](https://imagescript.matmen.dev/Image.html##dominantcolor), ...) +- Encoding images as [PNGs](https://imagescript.matmen.dev/Image.html##encode) + , [JPEGs](https://imagescript.matmen.dev/Image.html##encodejpeg) + and [GIFs](https://imagescript.matmen.dev/GIF.html#encode) --- ### Example -[![Example](./tests/targets/readme.png)](./tests/readme.js) + +[![Example](https://github.com/matmen/ImageScript/raw/master/tests/targets/readme.png)](https://github.com/matmen/ImageScript/blob/master/tests/readme.js) --- -If you have any additional questions, feel free to join the [discord support server](https://discord.gg/8hPrwAH). \ No newline at end of file +If you have any additional questions, feel free to join the [discord support server](https://discord.gg/8hPrwAH). diff --git a/browser/ImageScript.js b/browser/ImageScript.js new file mode 100644 index 0000000..9e91947 --- /dev/null +++ b/browser/ImageScript.js @@ -0,0 +1,2 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ImageScript=e():t.ImageScript=e()}(self,(()=>{return t={223:t=>{const e=new Uint32Array([0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117]);t.exports=function(t){let r=0,i=-1;const n=t.length-4|0;for(;n>r;)i=e[255&(i^t[r++])]^i>>>8,i=e[255&(i^t[r++])]^i>>>8,i=e[255&(i^t[r++])]^i>>>8,i=e[255&(i^t[r++])]^i>>>8;for(;r>>8;return(4294967295^i)>>>0}},248:(t,e,r)=>{const i=r(511),n=r(740),s=r(763),o=r(607),{version:a}=r(330),h=r(816),l=r(751),f=r(706);class c{constructor(t,e){if(e=~~e,(t=~~t)<1)throw new RangeError("Image has to be at least 1 pixel wide");if(e<1)throw new RangeError("Image has to be at least 1 pixel high");this.__width__=t,this.__height__=e,this.__buffer__=new ArrayBuffer(t*e*4),this.__view__=new DataView(this.__buffer__),this.__u32__=new Uint32Array(this.__buffer__),this.bitmap=new Uint8ClampedArray(this.__buffer__)}toString(){return`Image<${this.width}x${this.height}>`}get width(){return this.__width__}get height(){return this.__height__}*[Symbol.iterator](){for(let t=1;t<=this.height;t++)for(let e=1;e<=this.width;e++)yield[e,t]}*iterateWithColors(){let t=0;for(let e=1;e<=this.height;e++)for(let r=1;r<=this.width;r++)yield[r,e,this.__view__.getUint32(t,!1)],t+=4}static rgbaToColor(t,e,r,i){return((255&t)<<24|(255&e)<<16|(255&r)<<8|255&i)>>>0}static rgbToColor(t,e,r){return c.rgbaToColor(t,e,r,255)}static hslaToColor(t,e,r,i){let n,s,o;if(t%=1,e=Math.min(1,Math.max(0,e)),r=Math.min(1,Math.max(0,r)),i=Math.min(1,Math.max(0,i)),0===e)n=s=o=r;else{const i=(t,e,r)=>(r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+(e-t)*(2/3-r)*6:t),a=r<.5?r*(1+e):r+e-r*e,h=2*r-a;n=i(h,a,t+1/3),s=i(h,a,t),o=i(h,a,t-1/3)}return c.rgbaToColor(255*n,255*s,255*o,255*i)}static hslToColor(t,e,r){return c.hslaToColor(t,e,r,1)}static rgbaToHSLA(t,e,r,i){t/=255,e/=255,r/=255;const n=Math.max(t,e,r),s=Math.min(t,e,r);let o,a,h=(n+s)/2;if(n===s)o=a=0;else{const i=n-s;switch(a=h>.5?i/(2-n-s):i/(n+s),n){case t:o=(e-r)/i+(e>24&255,t>>16&255,t>>8&255,255&t]}static colorToRGB(t){return c.colorToRGBA(t).slice(0,3)}getPixelAt(t,e){return this.__check_boundaries__(t,e),this.__view__.getUint32(4*((~~e-1)*this.width+(~~t-1)),!1)}getRGBAAt(t,e){this.__check_boundaries__(t,e);const r=4*((~~e-1)*this.width+(~~t-1));return this.bitmap.subarray(r,r+4)}setPixelAt(t,e,r){return t=~~t,e=~~e,this.__check_boundaries__(t,e),this.__set_pixel__(t,e,r),this}__set_pixel__(t,e,r){this.__view__.setUint32(4*((e-1)*this.width+(t-1)),r,!1)}__check_boundaries__(t,e){if(isNaN(t))throw new TypeError(`Invalid pixel coordinates (x=${t})`);if(isNaN(e))throw new TypeError(`Invalid pixel coordinates (y=${e})`);if(t<1)throw new RangeError(`${c.__out_of_bounds__} (x=${t})<1`);if(t>this.width)throw new RangeError(`${c.__out_of_bounds__} (x=${t})>(width=${this.width})`);if(e<1)throw new RangeError(`${c.__out_of_bounds__} (y=${e})<1`);if(e>this.height)throw new RangeError(`${c.__out_of_bounds__} (y=${e})>(height=${this.height})`)}static get __out_of_bounds__(){return"Tried referencing a pixel outside of the images boundaries:"}fill(t){if("function"!=typeof t)this.__view__.setUint32(0,t,!1),this.__u32__.fill(this.__u32__[0]);else{let e=0;for(let r=1;r<=this.height;r++)for(let i=1;i<=this.width;i++)this.__view__.setUint32(e,t(i,r),!1),e+=4}return this}clone(){const t=new c(this.width,this.height);return t.bitmap.set(this.bitmap),t}static get RESIZE_NEAREST_NEIGHBOR(){return"RESIZE_NEAREST_NEIGHBOR"}static get RESIZE_AUTO(){return-1}scale(t,e=c.RESIZE_NEAREST_NEIGHBOR){const r=this.__scale__(t,e);return this.__apply__(r)}__scale__(t,e=c.RESIZE_NEAREST_NEIGHBOR){return 1===t?this:this.__resize__(this.width*t,this.height*t,e)}resize(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){const i=this.__resize__(t,e,r);return this.__apply__(i)}contain(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){const i=t/e>this.width/this.height?e/this.height:t/this.width;return this.scale(i,r)}fit(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){const i=new c(t,e);return this.contain(t,e,r),i.composite(this,(t-this.width)/2,(e-this.height)/2),this.__apply__(i)}cover(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){const i=t/e>this.width/this.height?t/this.width:e/this.height,n=this.scale(i,r);return n.crop((n.width-t)/2,(n.height-e)/2,t,e)}__resize__(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){if(t===c.RESIZE_AUTO&&e===c.RESIZE_AUTO)throw new Error("RESIZE_AUTO can only be used for either width or height, not for both");if(t===c.RESIZE_AUTO?t=this.width/this.height*e:e===c.RESIZE_AUTO&&(e=this.height/this.width*t),t=Math.floor(t),e=Math.floor(e),t<1)throw new RangeError("Image has to be at least 1 pixel wide");if(e<1)throw new RangeError("Image has to be at least 1 pixel high");let i;if(r!==c.RESIZE_NEAREST_NEIGHBOR)throw new Error("Invalid resize mode");return i=this.__resize_nearest_neighbor__(t,e),i}__resize_nearest_neighbor__(t,e){const r=new this.constructor(t,e);for(let i=0;ithis.width&&(r=this.width),i>this.height&&(i=this.height),this.__apply__(this.__crop__(~~t,~~e,~~r,~~i))}__crop__(t,e,r,i){t=~~t,e=~~e;const n=new this.constructor(r,i);for(let s=0;sthis.width||o>this.height)continue;const a=n(i,s);this.__set_pixel__(r,o,a)}return this}__fast_box__(t,e,r,i,n){t<0&&(r+=t,t=0),e<0&&(i+=e,e=0);const s=Math.max(Math.min(t+r,this.width),1);let o=s;for(;t<=--o;)this.__view__.setUint32(4*(o+e*this.width),n);const a=4*(s+e*this.width),h=4*(t+e*this.width);let l=Math.max(Math.min(e+i,this.height),1);for(;e<--l;)this.bitmap.copyWithin(4*(t+l*this.width),h,a);return this}drawCircle(t,e,r,i){const n=r**2;for(let s=Math.max(1,e-r);s<=Math.min(e+r,this.height);s++)for(let o=Math.max(1,t-r);o<=Math.min(t+r,this.width);o++)(o-t)**2+(s-e)**2r?this.bitmap[a]=0:e&&(this.bitmap[a]*=Math.max(0,Math.min(1,1-o/r*e**.5)))}return this}opacity(t,e=!1){if(isNaN(t)||t<0)throw new RangeError("Invalid opacity value");return this.__set_channel_value__(t,e,3),this}red(t,e=!1){if(isNaN(t)||t<0)throw new RangeError("Invalid saturation value");return this.__set_channel_value__(t,e,0),this}green(t,e=!1){if(isNaN(t)||t<0)throw new RangeError("Invalid saturation value");return this.__set_channel_value__(t,e,1),this}blue(t,e=!1){if(isNaN(t)||t<0)throw new RangeError("Invalid saturation value");return this.__set_channel_value__(t,e,2),this}__set_channel_value__(t,e,r){for(let i=r;i{const[n,s,o,a]=c.rgbaToHSLA(...this.getRGBAAt(r,i));return c.hslaToColor(n,s,t*(e?1:o),a)}))}saturation(t,e=!1){if(isNaN(t)||t<0)throw new RangeError("Invalid saturation value");return this.fill(((r,i)=>{const[n,s,o,a]=c.rgbaToHSLA(...this.getRGBAAt(r,i));return c.hslaToColor(n,t*(e?1:s),o,a)}))}composite(t,e=0,r=0){e=~~e,r=~~r;for(let i=0;i=this.height)break;for(let r=0;r=this.width)break;const o=4*(s+n*this.width),a=t.__view__.getUint32(4*(r+i*t.width),!1),h=this.__view__.getUint32(o,!1);255&~a?255&a?this.__view__.setUint32(o,c.__alpha_blend__(a,h),!1):this.__view__.setUint32(o,h,!1):this.__view__.setUint32(o,a,!1)}}}return this}static __alpha_blend__(t,e){const r=255&t,i=r+1,n=256-r;return(255&i*(t>>>24)+n*(e>>>24)>>8)<<24|(255&i*(t>>16&255)+n*(e>>16&255)>>8)<<16|(255&i*(t>>8&255)+n*(e>>8&255)>>8)<<8|255&Math.max(r,255&e)}invert(){for(const[t,e,r]of this.iterateWithColors())this.__set_pixel__(t,e,4294967295-r&4294967040|255&r);return this}invertValue(){for(const[t,e,r]of this.iterateWithColors()){const[i,n,s,o]=c.rgbaToHSLA(...c.colorToRGBA(r));this.__set_pixel__(t,e,c.hslaToColor(i,n,1-s,o))}return this}invertSaturation(){for(const[t,e,r]of this.iterateWithColors()){const[i,n,s,o]=c.rgbaToHSLA(...c.colorToRGBA(r));this.__set_pixel__(t,e,c.hslaToColor(i,1-n,s,o))}return this}invertHue(){for(const[t,e,r]of this.iterateWithColors()){const[i,n,s,o]=c.rgbaToHSLA(...c.colorToRGBA(r));this.__set_pixel__(t,e,c.hslaToColor(1-i,n,s,o))}return this}hueShift(t){for(const[e,r,i]of this.iterateWithColors()){const[n,s,o,a]=c.rgbaToHSLA(...c.colorToRGBA(i));this.__set_pixel__(e,r,c.hslaToColor(n+t/360,s,o,a))}return this}averageColor(){let t=[0,0,0],e=0;for(let r=0;rt/e)),255)}dominantColor(t=!0,e=!0,r=15){const i=new Array(262143);for(let n=0;n~~(63*t)));if(t&&h63-r)continue;const l=o<<12|a<<6|h;i[l]=(i[l]||0)+1}let n=-1,s=0;if(i.forEach(((t,e)=>{t>>12&63,a=s>>>6&63,h=63&s;return c.hslaToColor(o/63,a/63,h/63,1)}rotate(t,e=!0){if(t%360==0)return this;if(t%180==0)return this.__rotate_180__();const r=Math.PI*(t/180),i=Math.sin(r),n=Math.cos(r),s=e?Math.abs(this.width*i)+Math.abs(this.height*n):this.width,o=e?Math.abs(this.width*n)+Math.abs(this.height*i):this.height,a=new c(s,o),h=s/2-.5,l=o/2-.5,f=this.width/2-.5,_=this.height/2-.5;let u=0;do{let t=0;const e=f-i*(u-l),r=_+n*(u-l);do{const s=e+n*(t-h),o=r+i*(t-h);c.__interpolate__(this,a,t,u,s,o)}while(t++0&&e>0&&tt[0]-e[0])),r=e.map((t=>parseFloat(t[0]))),i=e.map((t=>t[1]));if(0===r.length)throw new RangeError("Invalid gradient point count");if(1===r.length)return()=>i[0];if(2===r.length){const t=this.__gradient__(i[0],i[1]);return e=>e<=r[0]?i[0]:e>=r[1]?i[1]:t((e-r[0])/(r[1]-r[0]))}const n=Math.min(...r),s=Math.max(...r);let o=[];for(let t=0;t{if(t<=n)return o[0].gradient(0);if(t>=s)return o[o.length-1].gradient(1);for(const e of o)if(t>=e.min&&t<=e.max)return e.gradient((t-e.min)/(e.max-e.min));throw new RangeError(`Invalid gradient position: ${t}`)}}roundCorners(t=Math.min(this.width,this.height)/4){const e=t**2;for(let r=1;r<=t;r++){const i=(r-t)**2;for(let n=1;n<=t;n++)i+(n-t)**2>e&&(this.bitmap[4*((n-1)*this.width+r-1)+3]=0)}for(let r=1;r<=t;r++){const i=(r-t)**2;for(let n=this.height-t;n<=this.height;n++)i+(this.height-n-t)**2>e&&(this.bitmap[4*((n-1)*this.width+r-1)+3]=0)}for(let r=this.width-t;r<=this.width;r++){const i=(this.width-r-t)**2;for(let n=1;n<=t;n++)i+(n-t)**2>e&&(this.bitmap[4*((n-1)*this.width+r-1)+3]=0)}for(let r=this.width-t;r<=this.width;r++){const i=(this.width-r-t)**2;for(let n=this.height-t;n<=this.height;n++)i+(this.height-n-t)**2>e&&(this.bitmap[4*((n-1)*this.width+r-1)+3]=0)}return this}static __gradient__(t,e){const r=t>>>24,i=t>>16&255,n=t>>8&255,s=255&t,o=(e>>>24)-r,a=(e>>16&255)-i,h=(e>>8&255)-n,l=(255&e)-s;return t=>(255&r+t*o)<<24|(255&i+t*a)<<16|(255&n+t*h)<<8|255&s+t*l}fisheye(t=2){const e=new c(this.width,this.height),r=this.width,i=this.height,n=this.__u32__,s=e.__u32__,o=1/r,a=1/i;for(const[e,h]of this){const l=e*o-.5,f=h*a-.5,c=Math.sqrt(l**2+f**2),_=2*c**t,u=(_*l/c+.5)*r|0,w=(_*f/c+.5)*i|0;u<1||u>r||w<1||w>i||isNaN(u)||isNaN(w)||(s[h*r+e]=n[r*w+u])}const h=.5*n.length+r/2;return s[h]=n[h],this.__apply__(e)}async encode(t=1,{title:e,author:r,description:n,copyright:s,creationTime:o,software:h,disclaimer:l,warning:f,source:c,comment:_}={}){return i.encode(this.bitmap,{width:this.width,height:this.height,level:t,channels:4,text:{Title:e,Author:r,Description:n,Copyright:s,"Creation Time":new Date(void 0===o?Date.now():o).toUTCString(),Software:void 0===h?`github.com/matmen/ImageScript v${a}`:h,Disclaimer:l,Warning:f,Source:c,Comment:_}})}async encodeJPEG(t=90){return(await l.init()).encode(this.bitmap,this.width,this.height,t)}static async decode(t){let e;t=n.view(t);const r=new DataView(t.buffer,t.byteOffset,t.byteLength);if(g.isPNG(r)){const{width:r,height:n,pixels:s}=i.decode(t);e=new c(r,n),e.bitmap.set(s)}else if(g.isJPEG(r)){const r=(await l.init()).decode(t),i=r.width,n=r.height,s=r.format;e=new c(i,n);const o=r.buffer;if(0===s){const t=new DataView(e.bitmap.buffer);for(let e=0;e 0");if(r!==this.SVG_MODE_SCALE&&e<1)throw new RangeError("SVG size must be >= 1");"string"==typeof t&&(t=(new TextEncoder).encode(t));const i=(await o.init()).rasterize(t,r,e),n=new c(i.width,i.height);return n.bitmap.set(i.buffer),n}static async renderText(t,e,r,i=4294967295,n=new w){const{Font:s,Layout:o}=await h.init();t=new s(e,t);const[a,l,f,_]=c.colorToRGBA(i),u=new o;u.reset({max_width:n.maxWidth,max_height:n.maxHeight,wrap_style:n.wrapStyle,vertical_align:n.verticalAlign,horizontal_align:n.horizontalAlign,wrap_hard_breaks:n.wrapHardBreaks}),u.append(t,r,{scale:e});const g=u.rasterize(a,l,f),d=new c(g.width,g.height);return d.bitmap.set(g.buffer),d.height>n.maxHeight&&d.crop(0,0,d.width,Math.floor(u.lines()/d.height*n.maxHeight)*(d.height/u.lines())),t.free(),u.free(),d.opacity(_/255)}}class _ extends c{static get DISPOSAL_KEEP(){return"keep"}static get DISPOSAL_PREVIOUS(){return"previous"}static get DISPOSAL_BACKGROUND(){return"background"}static __convert_disposal_mode__(t){if("string"==typeof t&&(t=["any","keep","previous","background"].indexOf(t)),t<0||t>3)throw new RangeError("Invalid disposal mode");return t}constructor(t,e,r=100,i=0,n=0,s=_.DISPOSAL_KEEP){if(isNaN(r)||r<0)throw new RangeError("Invalid frame duration");super(t,e),this.duration=r,this.xOffset=i,this.yOffset=n,this.disposalMode=s}get disposalMode(){return this.__disposalMode__}set disposalMode(t){this.__disposalMode__=_.__convert_disposal_mode__(t)}toString(){return`Frame<${this.width}x${this.height}x${this.duration}ms>`}static from(t,e,r,i,n=_.DISPOSAL_KEEP){if(!(t instanceof c))throw new TypeError("Invalid image passed");const s=new _(t.width,t.height,e,r,i,n);return s.bitmap.set(t.bitmap),s}resize(t,e,r=c.RESIZE_NEAREST_NEIGHBOR){const i=this.width,n=this.height,s=super.resize(t,e,r);return this.xOffset*=s.width/i,this.yOffset*=s.height/n,s}}class u extends Array{constructor(t,e=-1){super(...t);for(const t of this)if(!(t instanceof _))throw new TypeError(`Frame ${this.indexOf(t)} is not an instance of Frame`);if(e<-1||isNaN(e))throw new RangeError("Invalid loop count");this.loopCount=e}get width(){let t=0;for(const e of this){let r=e.width+e.xOffset;t`}*[Symbol.iterator](){for(let t=0;tt+e.duration),0)}async encode(t=95){const e=new((await s.init()).Encoder)(this.width,this.height,this.loopCount);for(const r of this){if(!(r instanceof _))throw new Error("GIF contains invalid frames");e.add(r.xOffset,r.yOffset,~~(r.duration/10),r.width,r.height,r.bitmap,r.disposalMode,t/100*29+1)}return e.u8()}static async decode(t,e=!1){let r;t=n.view(t);const i=new DataView(t.buffer,t.byteOffset,t.byteLength);if(!g.isGIF(i))throw new Error("Unsupported image type");{const i=[],n=new((await s.init()).Decoder)(t);if(e){const t=n.frames().next().value,e=new _(t.width,t.height,10*t.delay,t.x,t.y,t.dispose);e.bitmap.set(t.buffer),i.push(e),r=new u(i)}const o=0|n.width,a=0|n.height,h=new Uint32Array(n.width*n.height),l=new Uint8Array(h.buffer,h.byteOffset,h.byteLength);for(const t of n.frames()){let e=0,r=0;const n=0|t.x,s=0|t.y,f=t.buffer,c=t.dispose,u=0|t.width,w=0|t.height,g=new Uint32Array(f.buffer,f.byteOffset,u*w),d=i[i.push(new _(o,a,10*t.delay,0,0,3))-1].bitmap,p=new Uint32Array(d.buffer);if(d.set(l),2===c)for(let t=0;t=4&&2303741511===t.getUint32(0,!1)}static isJPEG(t){return t.byteLength>=4&&t.getUint32(0,!1)>>>8==16767231}static isTIFF(t){return t.byteLength>=4&&1229531648===t.getUint32(0,!1)}static isGIF(t){return t.byteLength>=4&&t.getUint32(0,!1)>>>8==4671814}}t.exports={Image:c,GIF:u,Frame:_,TextLayout:w,ImageType:g,decode:function(t,e){return"gif"===g.getType(t)?u.decode(t,e):c.decode(t)}}},330:t=>{"use strict";t.exports=JSON.parse('{"name":"imagescript","version":"1.2.16","description":"zero-dependency javascript image manipulation","main":"ImageScript.js","types":"ImageScript.d.ts","type":"commonjs","scripts":{"build":"webpack"},"repository":{"type":"git","url":"git+https://github.com/matmen/ImageScript.git"},"keywords":["image","image processing","image manipulation","png","jpeg","jpg","scale","resize","crop","webp","svg","bitmap","gif","picture","thumbnail"],"author":"Mathis Mensing ","license":"(AGPL-3.0-or-later OR MIT)","bugs":{"url":"https://github.com/matmen/ImageScript/issues"},"homepage":"https://github.com/matmen/ImageScript#readme","engines":{"node":">=14.0.0"}}')},511:(t,e,r)=>{const i=r(740),n=r(223),{compress:s,decompress:o}=r(639),a=new Uint8Array([73,72,68,82]),h=new Uint8Array([73,68,65,84]),l=new Uint8Array([73,69,78,68]),f=n(new Uint8Array([73,69,78,68])),c=new Uint8Array([137,80,78,71,13,10,26,10]),_={1:0,2:4,3:2,4:6},u=new TextEncoder;t.exports={encode(t,{text:e,width:r,height:o,channels:w,depth:g=8,level:d=0}){let p=0,m=0;const b=r*w,y=new Uint8Array(o+t.length);for(;pm)break}for(t=o(1===g.length?g[0]:i.from_parts(g),n+n*f);_>1)}else{for(;s>1);for(;s>1)}},filter_4(t,e,r,i,n){let s=0;if(0===r){for(;s{const{version:i}=r(330);let n=null;t.exports={async init(){if(!n){const t="compileStreaming"in WebAssembly;n=await WebAssembly[t?"compileStreaming":"compile"](await fetch(`https://unpkg.com/imagescript@${i}/wasm/any/svg.wasm`).then((e=>t?e:e.arrayBuffer())))}return this.new()},new(){const t=new WebAssembly.Instance(n).exports;class e{static length(){return t.wlen()}static alloc(e){return t.walloc(e)}static free(e,r){return t.wfree(e,r)}static u8(e,r){return new Uint8Array(t.memory.buffer,e,r)}static u32(e,r){return new Uint32Array(t.memory.buffer,e,r)}static copy_and_free(r,i){let n=e.u8(r,i).slice();return t.wfree(r,i),n}}return{rasterize:function(r,i,n){const s=e.alloc(r.length);e.u8(s,r.length).set(r);const o=t.rasterize(s,r.length,i,n);if(0===o)throw new Error("svg: failed to parse");if(1===o)throw new Error("svg: failed to rasterize");const a={width:t.rasterize_width(o),height:t.rasterize_height(o),buffer:e.u8(t.rasterize_buffer(o),e.length()).slice()};return t.rasterize_free(o),a}}}}},639:t=>{var e=Uint8Array,r=Uint16Array,i=Uint32Array,n=new e([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),s=new e([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),o=new e([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),a=function(t,e){for(var n=new r(31),s=0;s<31;++s)n[s]=e+=1<>>1|(21845&d)<<1))>>>2|(13107&c)<<2))>>>4|(3855&c)<<4,g[d]=((65280&c)>>>8|(255&c)<<8)>>>1;var p=function(t,e,i){for(var n=t.length,s=0,o=new r(e);s>>l]=f}else for(a=new r(n),s=0;s>>15-t[s]);return a},m=new e(288);for(d=0;d<144;++d)m[d]=8;for(d=144;d<256;++d)m[d]=9;for(d=256;d<280;++d)m[d]=7;for(d=280;d<288;++d)m[d]=8;var b=new e(32);for(d=0;d<32;++d)b[d]=5;var y=p(m,9,0),v=p(m,9,1),E=p(b,5,0),A=p(b,5,1),x=function(t){for(var e=t[0],r=1;re&&(e=t[r]);return e},S=function(t,e,r){var i=e>>3;return(t[i]|t[i+1]<<8)>>(7&e)&r},I=function(t,e){var r=e>>3;return(t[r]|t[r+1]<<8|t[r+2]<<16)>>(7&e)},U=function(t){return(t>>3)+(7&t&&1)},R=function(t,n,s){(null==n||n<0)&&(n=0),(null==s||s>t.length)&&(s=t.length);var o=new(t instanceof r?r:t instanceof i?i:e)(s-n);return o.set(t.subarray(n,s)),o},T=function(t,e,r){r<<=7&e;var i=e>>3;t[i]|=r,t[i+1]|=r>>>8},M=function(t,e,r){r<<=7&e;var i=e>>3;t[i]|=r,t[i+1]|=r>>>8,t[i+2]|=r>>>16},O=function(t,i){for(var n=[],s=0;sw&&(w=a[s].s);var g=new r(w+1),d=N(n[_-1],g,0);if(d>i){s=0;var p=0,m=d-i,b=1<i))break;p+=b-(1<>>=m;p>0;){var v=a[s].s;g[v]=0&&p;--s){var E=a[s].s;g[E]===i&&(--g[E],++p)}d=i}return[new e(g),d]},N=function(t,e,r){return-1===t.s?Math.max(N(t.l,e,r+1),N(t.r,e,r+1)):e[t.s]=r},G=function(t){for(var e=t.length;e&&!t[--e];);for(var i=new r(++e),n=0,s=t[0],o=1,a=function(t){i[n++]=t},h=1;h<=e;++h)if(t[h]===s&&h!==e)++o;else{if(!s&&o>2){for(;o>138;o-=138)a(32754);o>2&&(a(o>10?o-11<<5|28690:o-3<<5|12305),o=0)}else if(o>3){for(a(s),--o;o>6;o-=6)a(8304);o>2&&(a(o-3<<5|8208),o=0)}for(;o--;)a(s);o=1,s=t[h]}return[i.subarray(0,n),e]},B=function(t,e){for(var r=0,i=0;i>>8,t[n+2]=255^t[n],t[n+3]=255^t[n+1];for(var s=0;s4&&!W[o[$-1]];--$);var F,P,Z,j,J=u+5<<3,K=B(h,m)+B(l,b)+f,q=B(h,d)+B(l,x)+f+14+3*$+B(D,W)+(2*D[16]+3*D[17]+7*D[18]);if(J<=K&&J<=q)return z(e,w,t.subarray(_,_+u));if(T(e,w,1+(q15&&(T(e,w,tt[L]>>>5&127),w+=tt[L]>>>12)}}}else F=y,P=m,Z=E,j=b;for(L=0;L255){et=a[L]>>>18&31,M(e,w,F[et+257]),w+=P[et+257],et>7&&(T(e,w,a[L]>>>23&31),w+=n[et]);var rt=31&a[L];M(e,w,Z[rt]),w+=j[rt],rt>3&&(M(e,w,a[L]>>>5&8191),w+=s[rt])}else M(e,w,F[a[L]]),w+=P[a[L]];return M(e,w,F[256]),w+P[256]},H=new i([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),D=new e(0);function L(t,o){o||(o={});var a=function(){var t=1,e=0;return{p:function(r){for(var i=t,n=e,s=0|r.length,o=0;o!==s;){for(var a=Math.min(o+2655,s);o>16),n=(65535&n)+15*(n>>16)}t=i,e=n},d:function(){return(255&(t%=65521))<<24|t>>>8<<16|(255&(e%=65521))<<8|e>>>8}}}();a.p(t);var h,l,c,_,u,g,d,p,m=(g=2,d=4,function(t,o,a,h,l,c){var _=t.length,u=new e(h+_+5*(1+Math.ceil(_/7e3))+l),g=u.subarray(h,u.length-l),d=0;if(!o||_<8)for(var p=0;p<=_;p+=65535){var m=p+65535;m<_?d=z(g,d,t.subarray(p,m)):(g[p]=c,d=z(g,d,t.subarray(p,_)))}else{for(var b=H[o-1],y=b>>>13,v=8191&b,E=(1<7e3||L>24576)&&P>423){d=C(t,g,0,M,O,N,B,L,W,p-W,d),L=G=B=0,W=p;for(var Z=0;Z<286;++Z)O[Z]=0;for(Z=0;Z<30;++Z)N[Z]=0}var j=2,J=0,K=v,q=$-F&32767;if(P>2&&V===T(p-q))for(var Q=Math.min(y,P)-1,X=Math.min(32767,p),Y=Math.min(258,P);q<=X&&--K&&$!==F;){if(t[p+j]===t[p+j-q]){for(var tt=0;ttj){if(j=tt,J=q,tt>Q)break;var et=Math.min(q,tt-2),rt=0;for(Z=0;Zrt&&(rt=nt,F=it)}}}q+=($=F)-(F=A[$])+32768&32767}if(J){M[L++]=268435456|f[j]<<18|w[J];var st=31&f[j],ot=31&w[J];B+=n[st]+s[ot],++O[257+st],++N[ot],k=p+j,++G}else M[L++]=t[p],++O[t[p]]}}d=C(t,g,c,M,O,N,B,L,W,p-W,d),!c&&7&d&&(d=z(g,d+1,D))}return R(u,0,h+U(d)+l)}(_=t,null==(u=o).level?6:u.level,null==u.mem?Math.ceil(1.5*Math.max(8,Math.min(13,Math.log(_.length)))):12+u.mem,g,d,!p));return h=m,c=0===(l=o.level)?0:l<6?1:9===l?3:2,h[0]=120,h[1]=c<<6|(c?32-2*c:1),function(t,e,r){for(;r;++e)t[e]=r,r>>>=8}(m,m.length-4,a.d()),m}t.exports={compress:function(t,e){return L(t,{level:e})},decompress:function(t,r){return i=t,a=new Uint8Array(r),function(t,r,i){var a=t.length;if(!a||i&&!i.l&&a<5)return r||new e(0);var h=!r||i,f=!i||i.i;i||(i={}),r||(r=new e(3*a));var c=function(t){var i=r.length;if(t>i){var n=new e(Math.max(2*i,t));n.set(r),r=n}},_=i.f||0,w=i.p||0,g=i.b||0,d=i.l,m=i.d,b=i.m,y=i.n,E=8*a;do{if(!d){i.f=_=S(t,w,1);var T=S(t,w+1,3);if(w+=3,!T){var M=t[(W=U(w)+4)-4]|t[W-3]<<8,O=W+M;if(O>a){if(f)throw"unexpected EOF";break}h&&c(g+M),r.set(t.subarray(W,O),g),i.b=g+=M,i.p=w=8*O;continue}if(1===T)d=v,m=A,b=9,y=5;else{if(2!==T)throw"invalid block type";var N=S(t,w,31)+257,G=S(t,w+10,15)+4,B=N+S(t,w+5,31)+1;w+=14;for(var z=new e(B),C=new e(19),H=0;H>>4)<16)z[H++]=W;else{var $=0,F=0;for(16===W?(F=3+S(t,w,3),w+=2,$=z[H-1]):17===W?(F=3+S(t,w,7),w+=3):18===W&&(F=11+S(t,w,127),w+=7);F--;)z[H++]=$}}var P=z.subarray(0,N),Z=z.subarray(N);b=x(P),y=x(Z),d=p(P,b,1),m=p(Z,y,1)}if(w>E){if(f)throw"unexpected EOF";break}}h&&c(g+131072);for(var j=(1<>>4;if((w+=15&$)>E){if(f)throw"unexpected EOF";break}if(!$)throw"invalid length/literal";if(q<256)r[g++]=q;else{if(256===q){K=w,d=null;break}var Q=q-254;if(q>264){var X=n[H=q-257];Q=S(t,w,(1<>>4;if(!Y)throw"invalid distance";if(w+=15&Y,Z=u[tt],tt>3&&(X=s[tt],Z+=I(t,w)&(1<E){if(f)throw"unexpected EOF";break}h&&c(g+131072);for(var et=g+Q;g>>4>7||(t[0]<<8|t[1])%31)throw"invalid zlib data";if(32&t[1])throw"invalid zlib data: preset dictionaries not supported"}(i),i.subarray(2,-4)),a);var i,a}}},706:(t,e,r)=>{const{version:i}=r(330);let n=null;t.exports={async init(){if(!n){const t="compileStreaming"in WebAssembly;n=await WebAssembly[t?"compileStreaming":"compile"](await fetch(`https://unpkg.com/imagescript@${i}/wasm/any/tiff.wasm`).then((e=>t?e:e.arrayBuffer())))}return this.new()},new(){const t=new WebAssembly.Instance(n).exports;class e{static length(){return t.wlen()}static alloc(e){return t.walloc(e)}static free(e,r){return t.wfree(e,r)}static u8(e,r){return new Uint8Array(t.memory.buffer,e,r)}static u32(e,r){return new Uint32Array(t.memory.buffer,e,r)}static copy_and_free(r,i){let n=e.u8(r,i).slice();return t.wfree(r,i),n}}return{decode:function(r){const i=e.alloc(r.length);e.u8(i,r.length).set(r);const n=t.decode(i,r.length);if(0===n)throw new Error("tiff: failed to decode");const s={width:t.decode_width(n),height:t.decode_height(n),buffer:e.u8(t.decode_buffer(n),e.length()).slice()};return t.decode_free(n),s}}}}},740:t=>{function e(t,e=!1){if(t instanceof ArrayBuffer)return new Uint8Array(t);if("undefined"!=typeof SharedArrayBuffer&&e&&t instanceof SharedArrayBuffer)return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(t.buffer,t.byteOffset,t.byteLength);throw new TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'")}t.exports={view:e,from_parts:function(t,r=!1){let i=0,n=0;t.forEach((t=>i+=null==t.byteLength?t.length:t.byteLength));const s=new Uint8Array(r?new SharedArrayBuffer(i):i);return t.forEach((t=>{const r=Array.isArray(t)?t:e(t,!0);s.set(r,n),n+=r.length})),s}}},751:(t,e,r)=>{const{version:i}=r(330);let n=null;t.exports={async init(){if(!n){const t="compileStreaming"in WebAssembly;n=await WebAssembly[t?"compileStreaming":"compile"](await fetch(`https://unpkg.com/imagescript@${i}/wasm/any/jpeg.wasm`).then((e=>t?e:e.arrayBuffer())))}return this.new()},new(){const t=new WebAssembly.Instance(n).exports;class e{static length(){return t.wlen()}static alloc(e){return t.walloc(e)}static free(e,r){return t.wfree(e,r)}static u8(e,r){return new Uint8Array(t.memory.buffer,e,r)}static u32(e,r){return new Uint32Array(t.memory.buffer,e,r)}static copy_and_free(r,i){let n=e.u8(r,i).slice();return t.wfree(r,i),n}}return{encode:function(r,i,n,s){const o=e.alloc(r.length);return e.u8(o,r.length).set(r),e.copy_and_free(t.encode(o,i,n,s),e.length())},decode:function(r,i,n){const s=e.alloc(r.length);e.u8(s,r.length).set(r);const o=t.decode(s,r.length,i,n);if(0===o)throw new Error("jpg: failed to decode");if(1===o)throw new Error("jpg: failed to scale decoder");const a={width:t.decode_width(o),height:t.decode_height(o),format:t.decode_format(o),buffer:e.u8(t.decode_buffer(o),e.length()).slice()};return t.decode_free(o),a}}}}},763:(t,e,r)=>{const{version:i}=r(330);let n=null;t.exports={async init(){if(!n){const t="compileStreaming"in WebAssembly;n=await WebAssembly[t?"compileStreaming":"compile"](await fetch(`https://unpkg.com/imagescript@${i}/wasm/any/gif.wasm`).then((e=>t?e:e.arrayBuffer())))}return this.new()},new(){const t=new Map,e=new TextEncoder,r=new WebAssembly.Instance(n,{env:{push_to_stream(e,r){t.get(e).cb(i.u8(r,i.length()).slice())}}}).exports;class i{static length(){return r.wlen()}static alloc(t){return r.walloc(t)}static free(t,e){return r.wfree(t,e)}static u8(t,e){return new Uint8Array(r.memory.buffer,t,e)}static u32(t,e){return new Uint32Array(r.memory.buffer,t,e)}static copy_and_free(t,e){let n=i.u8(t,e).slice();return r.wfree(t,e),n}}return{Encoder:class{constructor(e,i,n=-1){this.slices=[],t.set(0,this),this.ptr=r.encoder_new(0,e,i,n)}cb(t){this.slices.push(t)}free(){this.ptr=r.encoder_free(this.ptr),t.delete(0)}u8(){this.free();let t=0;const e=new Uint8Array(this.slices.reduce(((t,e)=>t+e.length),0));for(const r of this.slices)e.set(r,t),t+=r.length;return e}add(t,e,n,s,o,a,h,l){const f=i.alloc(a.length);i.u8(f,a.length).set(a),r.encoder_add(this.ptr,f,a.length,t,e,s,o,n,h,l)}set comment(t){const n=e.encode(t),s=i.alloc(n.length);i.u8(s,n.length).set(n),r.encoder_add_comment(this.ptr,s,n.length)}set application(t){const n=e.encode(t),s=i.alloc(n.length);i.u8(s,n.length).set(n),r.encoder_add_application(this.ptr,s,n.length)}},Decoder:class{constructor(t,e=0){const n=i.alloc(t.length);if(i.u8(n,t.length).set(t),this.ptr=r.decoder_new(n,t.length,e),0===this.ptr)throw new Error("gif: failed to parse gif header");this.width=r.decoder_width(this.ptr),this.height=r.decoder_height(this.ptr)}free(){this.ptr=r.decoder_free(this.ptr)}*frames(){let t;for(;t=this.frame();)yield t}frame(){const t=r.decoder_frame(this.ptr);if(1===t)return null;if(0===t)throw this.free(),new Error("gif: failed to decode frame");const e={x:r.decoder_frame_x(t),y:r.decoder_frame_y(t),delay:r.decoder_frame_delay(t),width:r.decoder_frame_width(t),height:r.decoder_frame_height(t),dispose:r.decoder_frame_dispose(t),buffer:i.u8(r.decoder_frame_buffer(t),i.length()).slice()};return r.decoder_frame_free(t),e}}}}}},816:(t,e,r)=>{const{version:i}=r(330);let n=null;t.exports={async init(){if(!n){const t="compileStreaming"in WebAssembly;n=await WebAssembly[t?"compileStreaming":"compile"](await fetch(`https://unpkg.com/imagescript@${i}/wasm/any/font.wasm`).then((e=>t?e:e.arrayBuffer())))}return this.new()},new(){let t=null;const e=new WebAssembly.Instance(n).exports;class r{static length(){return e.wlen()}static alloc(t){return e.walloc(t)}static free(t,r){return e.wfree(t,r)}static u8(t,r){return new Uint8Array(e.memory.buffer,t,r)}static u32(t,r){return new Uint32Array(e.memory.buffer,t,r)}static copy_and_free(t,i){let n=r.u8(t,i).slice();return e.wfree(t,i),n}}const i="Deno"in globalThis?Deno.core.encode:(()=>{const t=new TextEncoder;return e=>t.encode(e)})(),s="Deno"in globalThis?Deno.core.decode:(()=>{const t=new TextDecoder;return e=>t.decode(e)})();return"FinalizationRegistry"in globalThis&&(t=new FinalizationRegistry((([t,r])=>{0===t&&e.font_free(r),1===t&&e.layout_free(r)}))),{Font:class{constructor(i,n){this.scale=i;const s=r.alloc(n.length);if(r.u8(s,n.length).set(n),this.ptr=e.font_new(s,n.length,i),!this.ptr)throw new Error("invalid font");t&&t.register(this,[0,this.ptr],this)}free(){this.ptr=e.font_free(this.ptr),t&&t.unregister(this)}has(t){return e.font_has(this.ptr,String.prototype.charCodeAt.call(t,0))}metrics(t,i=this.scale){const n=e.font_metrics(this.ptr,String.prototype.charCodeAt.call(t,0),i),o=JSON.parse(s(r.u8(e.font_metrics_buffer(n),r.length())));return e.font_metrics_free(n),o}rasterize(t,i=this.scale){const n=e.font_rasterize(this.ptr,String.prototype.charCodeAt.call(t,0),i),o={buffer:r.u8(e.font_rasterize_buffer(n),r.length()).slice(),metrics:JSON.parse(s(r.u8(e.font_rasterize_metrics(n),r.length())))};return e.font_rasterize_free(n),o}},Layout:class{constructor(){this.ptr=e.layout_new(),t&&(this.refs=[]),t&&t.register(this,[1,this.ptr],this)}clear(){e.layout_clear(this.ptr),t&&(this.refs.length=0)}lines(){return e.layout_lines(this.ptr)}free(){t&&(this.refs.length=0),this.ptr=e.layout_free(this.ptr),t&&t.unregister(this)}reset(n={}){n=i(JSON.stringify(n)),t&&(this.refs.length=0);const s=r.alloc(n.length);r.u8(s,n.length).set(n),e.layout_reset(this.ptr,s,n.length)}append(n,s,o){s=i(s);const a=o||{};t&&this.refs.push(n);const h=r.alloc(s.length);r.u8(h,s.length).set(s);const l="r"in a||"g"in a||"b"in a;e.layout_append(this.ptr,n.ptr,h,s.length,null==a.scale?n.scale:a.scale,l,a.r,a.g,a.b)}rasterize(t,i,n){const s=e.layout_rasterize(this.ptr,t,i,n),o={width:e.layout_rasterize_width(s),height:e.layout_rasterize_height(s),buffer:r.u8(e.layout_rasterize_buffer(s),r.length()).slice()};return e.layout_rasterize_free(s),o}}}}}}},e={},function r(i){var n=e[i];if(void 0!==n)return n.exports;var s=e[i]={exports:{}};return t[i](s,s.exports,r),s.exports}(248);var t,e})); +//# sourceMappingURL=ImageScript.js.map \ No newline at end of file diff --git a/browser/ImageScript.js.map b/browser/ImageScript.js.map new file mode 100644 index 0000000..23d53b3 --- /dev/null +++ b/browser/ImageScript.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ImageScript.js","mappings":"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","sources":["webpack://ImageScript/webpack/universalModuleDefinition","webpack://ImageScript/./utils/crc32.js","webpack://ImageScript/./ImageScript.js","webpack://ImageScript/./utils/png.js","webpack://ImageScript/./utils/wasm/svg.js","webpack://ImageScript/./utils/zlib.js","webpack://ImageScript/./utils/wasm/tiff.js","webpack://ImageScript/./utils/buffer.js","webpack://ImageScript/./utils/wasm/jpeg.js","webpack://ImageScript/./utils/wasm/gif.js","webpack://ImageScript/./utils/wasm/font.js","webpack://ImageScript/webpack/bootstrap","webpack://ImageScript/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ImageScript\"] = factory();\n\telse\n\t\troot[\"ImageScript\"] = factory();\n})(self, () => {\nreturn ","const table = new Uint32Array([\n 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,\n 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,\n 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,\n 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,\n 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,\n 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,\n 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,\n 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,\n 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,\n 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,\n 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,\n 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,\n 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,\n 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,\n 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,\n 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,\n 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,\n 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\n 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,\n 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,\n 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,\n 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,\n 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,\n 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,\n 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,\n 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]);\n \n module.exports = function crc32(buffer) {\n let offset = 0 | 0;\n let crc = 0xFFFFFFFF | 0;\n const bl = (buffer.length - 4) | 0;\n \n while (bl > offset) {\n crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8);\n crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8);\n crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8);\n crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8);\n }\n \n while (offset < buffer.length) {\n crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8);\n }\n \n return (crc ^ 0xFFFFFFFF) >>> 0;\n };","const png = require('./utils/png');\nconst mem = require('./utils/buffer.js');\nconst giflib = require('./utils/wasm/gif');\nconst svglib = require('./utils/wasm/svg');\nconst {version} = require('./package.json');\nconst fontlib = require('./utils/wasm/font');\nconst jpeglib = require('./utils/wasm/jpeg');\nconst tifflib = require('./utils/wasm/tiff');\n\nconst MAGIC_NUMBERS = {\n PNG: 0x89504e47,\n JPEG: 0xffd8ff,\n TIFF: 0x49492a00,\n GIF: 0x474946\n};\n\n/**\n * Represents an image; provides utility functions\n */\nclass Image {\n /**\n * Creates a new image with the given dimensions\n * @param {number} width\n * @param {number} height\n * @returns {Image}\n */\n constructor(width, height) {\n width = ~~width;\n height = ~~height;\n\n if (width < 1)\n throw new RangeError('Image has to be at least 1 pixel wide');\n if (height < 1)\n throw new RangeError('Image has to be at least 1 pixel high');\n\n /** @private */\n this.__width__ = width;\n /** @private */\n this.__height__ = height;\n /** @private */\n this.__buffer__ = new ArrayBuffer(width * height * 4);\n /** @private */\n this.__view__ = new DataView(this.__buffer__);\n /** @private */\n this.__u32__ = new Uint32Array(this.__buffer__);\n /**\n * The images RGBA pixel data\n * @type {Uint8ClampedArray}\n */\n this.bitmap = new Uint8ClampedArray(this.__buffer__);\n }\n\n /**\n * @private\n * @returns {string}\n */\n toString() {\n return `Image<${this.width}x${this.height}>`;\n }\n\n /**\n * The images width\n * @returns {number}\n */\n get width() {\n return this.__width__;\n }\n\n /**\n * The images height\n * @returns {number}\n */\n get height() {\n return this.__height__;\n }\n\n /**\n * Yields an [x, y] array for every pixel in the image\n * @yields {number[]} The coordinates of the pixel ([x, y])\n * @returns {void}\n */\n * [Symbol.iterator]() {\n for (let y = 1; y <= this.height; y++) {\n for (let x = 1; x <= this.width; x++) {\n yield [x, y];\n }\n }\n }\n\n /**\n * Yields an [x, y, color] array for every pixel in the image\n * @yields {number[]} The coordinates and color of the pixel ([x, y, color])\n */\n * iterateWithColors() {\n let offset = 0;\n for (let y = 1; y <= this.height; y++) {\n for (let x = 1; x <= this.width; x++) {\n yield [x, y, this.__view__.getUint32(offset, false)];\n offset += 4;\n }\n }\n }\n\n /**\n * Converts RGBA components to an RGBA value\n * @param {number} r red (0..255)\n * @param {number} g green (0..255)\n * @param {number} b blue (0..255)\n * @param {number} a alpha (0..255)\n * @returns {number} RGBA value\n */\n static rgbaToColor(r, g, b, a) {\n return (((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | (a & 0xff)) >>> 0;\n }\n\n /**\n * Converts RGB components to an RGBA value (assuming alpha = 255)\n * @param {number} r red (0..255)\n * @param {number} g green (0..255)\n * @param {number} b blue (0..255)\n * @returns {number} RGBA value\n */\n static rgbToColor(r, g, b) {\n return Image.rgbaToColor(r, g, b, 0xff);\n }\n\n /**\n * Converts HSLA colors to RGBA colors\n * @param {number} h hue (0..1)\n * @param {number} s saturation (0..1)\n * @param {number} l lightness (0..1)\n * @param {number} a opacity (0..1)\n * @returns {number} color\n */\n static hslaToColor(h, s, l, a) {\n h %= 1;\n s = Math.min(1, Math.max(0, s));\n l = Math.min(1, Math.max(0, l));\n a = Math.min(1, Math.max(0, a));\n\n let r, g, b;\n\n if (s === 0) {\n r = g = b = l;\n } else {\n const hue2rgb = (p, q, t) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n\n return Image.rgbaToColor(r * 255, g * 255, b * 255, a * 255);\n }\n\n /**\n * Converts HSL colors to RGBA colors (assuming an opacity of 255)\n * @param {number} h hue (0..1)\n * @param {number} s saturation (0..1)\n * @param {number} l lightness (0..1)\n * @returns {number} color\n */\n static hslToColor(h, s, l) {\n return Image.hslaToColor(h, s, l, 1);\n }\n\n /**\n * Converts an RGBA value to an array of HSLA values\n * @param r {number} (0..255)\n * @param g {number} (0..255)\n * @param b {number} (0..255)\n * @param a {number} (0..255)\n * @returns {number[]} The HSLA values ([H, S, L, A])\n */\n static rgbaToHSLA(r, g, b, a) {\n r /= 255;\n g /= 255;\n b /= 255;\n\n const max = Math.max(r, g, b), min = Math.min(r, g, b);\n let h, s, l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0;\n } else {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r:\n h = (g - b) / d + (g < b ? 6 : 0);\n break;\n case g:\n h = (b - r) / d + 2;\n break;\n case b:\n h = (r - g) / d + 4;\n break;\n }\n\n h /= 6;\n }\n\n return [h, s, l, a / 255];\n }\n\n /**\n * Converts a color value to an array of RGBA values\n * @param {number} color The color value to convert\n * @returns {number[]} The RGBA values ([R, G, B, A])\n */\n static colorToRGBA(color) {\n return [(color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff];\n }\n\n /**\n * Converts a color value to an array of RGB values (ignoring the colors alpha)\n * @param {number} color The color value to convert\n * @returns {number[]} The RGB values ([R, G, B])\n */\n static colorToRGB(color) {\n return Image.colorToRGBA(color).slice(0, 3);\n }\n\n /**\n * Gets the pixel color at the specified position\n * @param {number} x\n * @param {number} y\n * @returns {number} The color value\n */\n getPixelAt(x, y) {\n this.__check_boundaries__(x, y);\n return this.__view__.getUint32(((~~y - 1) * this.width + (~~x - 1)) * 4, false);\n }\n\n /**\n * Gets the pixel color at the specified position\n * @param {number} x\n * @param {number} y\n * @returns {Uint8ClampedArray} The RGBA value\n */\n getRGBAAt(x, y) {\n this.__check_boundaries__(x, y);\n const idx = ((~~y - 1) * this.width + (~~x - 1)) * 4;\n return this.bitmap.subarray(idx, idx + 4);\n }\n\n /**\n * Sets the pixel color for the specified position\n * @param {number} x\n * @param {number} y\n * @param {number} pixelColor\n */\n setPixelAt(x, y, pixelColor) {\n x = ~~x;\n y = ~~y;\n this.__check_boundaries__(x, y);\n this.__set_pixel__(x, y, pixelColor);\n return this;\n }\n\n /**\n * @private\n * @param {number} x\n * @param {number} y\n * @param {number} pixelColor\n */\n __set_pixel__(x, y, pixelColor) {\n this.__view__.setUint32(((y - 1) * this.width + (x - 1)) * 4, pixelColor, false);\n }\n\n /**\n * @private\n * @param {number} x\n * @param {number} y\n */\n __check_boundaries__(x, y) {\n if (isNaN(x)) throw new TypeError(`Invalid pixel coordinates (x=${x})`);\n if (isNaN(y)) throw new TypeError(`Invalid pixel coordinates (y=${y})`);\n if (x < 1)\n throw new RangeError(`${Image.__out_of_bounds__} (x=${x})<1`);\n if (x > this.width)\n throw new RangeError(`${Image.__out_of_bounds__} (x=${x})>(width=${this.width})`);\n if (y < 1)\n throw new RangeError(`${Image.__out_of_bounds__} (y=${y})<1`);\n if (y > this.height)\n throw new RangeError(`${Image.__out_of_bounds__} (y=${y})>(height=${this.height})`);\n }\n\n /**\n * @private\n */\n static get __out_of_bounds__() {\n return 'Tried referencing a pixel outside of the images boundaries:';\n }\n\n /**\n * @callback colorFunction\n * @param {number} x\n * @param {number} y\n * @returns {number} pixel color\n */\n\n /**\n * Fills the image data with the supplied color\n * @param {number|colorFunction} color\n * @returns {Image}\n */\n fill(color) {\n const type = typeof color;\n if (type !== 'function') {\n this.__view__.setUint32(0, color, false);\n this.__u32__.fill(this.__u32__[0]);\n } else {\n let offset = 0;\n for (let y = 1; y <= this.height; y++) {\n for (let x = 1; x <= this.width; x++) {\n this.__view__.setUint32(offset, color(x, y), false);\n offset += 4;\n }\n }\n }\n\n return this;\n }\n\n /**\n * Clones the current image\n * @returns {Image}\n */\n clone() {\n const image = new Image(this.width, this.height);\n image.bitmap.set(this.bitmap);\n return image;\n }\n\n /**\n * Use {@link https://en.wikipedia.org/wiki/Image_scaling#Nearest-neighbor_interpolation Nearest-neighbor} resizing.\n * @returns {string}\n */\n static get RESIZE_NEAREST_NEIGHBOR() {\n return 'RESIZE_NEAREST_NEIGHBOR';\n }\n\n /**\n * Used for automatically preserving an images aspect ratio when resizing.\n * @returns {number}\n */\n static get RESIZE_AUTO() {\n return -1;\n }\n\n /**\n * Resizes the image by the given factor\n * @param {number} factor The factor to resize the image with\n * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use\n * @returns {Image}\n */\n scale(factor, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const image = this.__scale__(factor, mode);\n return this.__apply__(image);\n }\n\n /** @private */\n __scale__(factor, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n if (factor === 1) return this;\n return this.__resize__(this.width * factor, this.height * factor, mode);\n }\n\n /**\n * Resizes the image to the given dimensions.\n * Use {@link Image.RESIZE_AUTO} as either width or height to automatically preserve the aspect ratio.\n * @param {number} width The new width\n * @param {number} height The new height\n * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use\n * @returns {Image} The resized image\n */\n resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const image = this.__resize__(width, height, mode);\n return this.__apply__(image);\n }\n\n /**\n * Resizes the image so it is contained in the given bounding box.\n * Can return an image with one axis smaller than the given bounding box.\n * @param {number} width The width of the bounding box\n * @param {number} height The height of the bounding box\n * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use\n * @returns {Image} The resized image\n */\n contain(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const scaleFactor = width / height > this.width / this.height ? height / this.height : width / this.width;\n return this.scale(scaleFactor, mode);\n }\n\n /**\n * Resizes the image so it is contained in the given bounding box, placing it in the center of the given bounding box.\n * Always returns the exact dimensions of the bounding box.\n * @param {number} width The width of the bounding box\n * @param {number} height The height of the bounding box\n * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use\n * @returns {Image} The resized image\n */\n fit(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const result = new Image(width, height);\n this.contain(width, height, mode);\n result.composite(this, (width - this.width) / 2, (height - this.height) / 2);\n return this.__apply__(result);\n }\n\n /**\n * Resizes the image so it covers the given bounding box, cropping the overflowing edges.\n * Always returns the exact dimensions of the bounding box.\n * @param {number} width The width of the bounding box\n * @param {number} height The height of the bounding box\n * @param {string} [mode=Image.RESIZE_NEAREST_NEIGHBOR] The resizing mode to use\n * @returns {Image} The resized image\n */\n cover(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const scaleFactor = width / height > this.width / this.height ? width / this.width : height / this.height;\n const result = this.scale(scaleFactor, mode);\n return result.crop((result.width - width) / 2, (result.height - height) / 2, width, height);\n }\n\n /** @private */\n __resize__(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n if (width === Image.RESIZE_AUTO && height === Image.RESIZE_AUTO) throw new Error('RESIZE_AUTO can only be used for either width or height, not for both');\n else if (width === Image.RESIZE_AUTO) width = this.width / this.height * height;\n else if (height === Image.RESIZE_AUTO) height = this.height / this.width * width;\n\n width = Math.floor(width);\n height = Math.floor(height);\n if (width < 1)\n throw new RangeError('Image has to be at least 1 pixel wide');\n if (height < 1)\n throw new RangeError('Image has to be at least 1 pixel high');\n\n let image;\n if (mode === Image.RESIZE_NEAREST_NEIGHBOR)\n image = this.__resize_nearest_neighbor__(width, height);\n else throw new Error('Invalid resize mode');\n\n return image;\n }\n\n /**\n * @private\n * @param {number} width The new width\n * @param {number} height The new height\n */\n __resize_nearest_neighbor__(width, height) {\n const image = new this.constructor(width, height);\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const ySrc = Math.floor((y * this.height) / height);\n const xSrc = Math.floor((x * this.width) / width);\n\n const destPos = (y * width + x) * 4;\n const srcPos = (ySrc * this.width + xSrc) * 4;\n\n image.__view__.setUint32(destPos, this.__view__.getUint32(srcPos, false), false);\n }\n }\n\n return image;\n }\n\n /**\n * Crops an image to the specified dimensions\n * @param {number} x The x offset\n * @param {number} y The y offset\n * @param {number} width The new images width\n * @param {number} height The new images height\n * @returns {Image}\n */\n crop(x, y, width, height) {\n if (width > this.width) width = this.width;\n if (height > this.height) height = this.height;\n\n return this.__apply__(this.__crop__(~~x, ~~y, ~~width, ~~height));\n }\n\n /**\n * @param {number} x\n * @param {number} y\n * @param {number} width\n * @param {number} height\n * @returns {Image}\n * @private\n */\n __crop__(x, y, width, height) {\n x = ~~x;\n y = ~~y;\n\n const image = new this.constructor(width, height);\n\n for (let tY = 0; tY < height; tY++) {\n const idx = (tY + y) * this.width + x;\n image.__u32__.set(this.__u32__.subarray(idx, idx + width), tY * width);\n }\n\n return image;\n }\n\n /**\n * Draws a box at the specified coordinates\n * @param {number} x The x offset\n * @param {number} y The y offset\n * @param {number} width The box width\n * @param {number} height The box height\n * @param {number|colorFunction} color The color to fill the box in with\n * @returns {Image}\n */\n drawBox(x, y, width, height, color) {\n x = ~~(x - 1);\n y = ~~(y - 1);\n width = ~~width;\n height = ~~height;\n\n if (typeof color === 'function') {\n for (let tY = 1; tY <= height; tY++) {\n for (let tX = 1; tX <= width; tX++) {\n const nX = tX + x;\n const nY = tY + y;\n if (Math.min(nX, nY) < 1 || nX > this.width || nY > this.height)\n continue;\n\n const tC = color(tX, tY);\n this.__set_pixel__(nX, nY, tC);\n }\n }\n } else return this.__fast_box__(x, y, width, height, color);\n\n return this;\n }\n\n /**\n * @private\n * @param {number} x\n * @param {number} y\n * @param {number} width\n * @param {number} height\n * @param {number} color\n */\n __fast_box__(x, y, width, height, color) {\n if (x < 0) {\n width += x;\n x = 0;\n }\n\n if (y < 0) {\n height += y;\n y = 0;\n }\n\n const right = Math.max(Math.min(x + width, this.width), 1);\n let xPos = right;\n while (x <= --xPos)\n this.__view__.setUint32(4 * (xPos + y * this.width), color);\n const end = 4 * (right + y * this.width);\n const start = 4 * (x + y * this.width);\n\n let bottom = Math.max(Math.min(y + height, this.height), 1);\n while (y < --bottom)\n this.bitmap.copyWithin(4 * (x + bottom * this.width), start, end);\n\n return this;\n }\n\n /**\n * Draws a circle at the specified coordinates with the specified radius\n * @param {number} x The center x position\n * @param {number} y The center y position\n * @param {number} radius The circles radius\n * @param {number|colorFunction} color\n * @returns {Image}\n */\n drawCircle(x, y, radius, color) {\n const radSquared = radius ** 2;\n for (let currentY = Math.max(1, y - radius); currentY <= Math.min(y + radius, this.height); currentY++) {\n for (let currentX = Math.max(1, x - radius); currentX <= Math.min(x + radius, this.width); currentX++) {\n if ((currentX - x) ** 2 + (currentY - y) ** 2 < radSquared)\n this.__set_pixel__(currentX, currentY, typeof color === 'function' ? color(currentX - x + radius, currentY - y + radius) : color);\n }\n }\n\n return this;\n }\n\n /**\n * Crops the image into a circle\n * @param {boolean} [max=false] Whether to use the larger dimension for the size\n * @param {number} [feathering=0] How much feathering to apply to the edges\n * @returns {Image}\n */\n cropCircle(max = false, feathering = 0) {\n const rad = Math[max ? 'max' : 'min'](this.width, this.height) / 2;\n const radSquared = rad ** 2;\n const centerX = this.width / 2;\n const centerY = this.height / 2;\n\n for (const [x, y] of this) {\n const distanceFromCenter = (x - centerX) ** 2 + (y - centerY) ** 2;\n const alphaIdx = ((y - 1) * this.width + (x - 1)) * 4 + 3;\n if (distanceFromCenter > radSquared)\n this.bitmap[alphaIdx] = 0;\n else if (feathering)\n this.bitmap[alphaIdx] *= Math.max(0, Math.min(1, 1 - (distanceFromCenter / radSquared) * feathering ** (1 / 2)));\n }\n\n return this;\n }\n\n /**\n * Sets the images opacity\n * @param {number} opacity The opacity to apply (0..1)\n * @param {boolean} absolute Whether to scale the current opacity (false) or just set the new opacity (true)\n * @returns {Image}\n */\n opacity(opacity, absolute = false) {\n if (isNaN(opacity) || opacity < 0)\n throw new RangeError('Invalid opacity value');\n\n this.__set_channel_value__(opacity, absolute, 3);\n\n return this;\n }\n\n /**\n * Sets the red channels saturation\n * @param {number} saturation The saturation to apply (0..1)\n * @param {boolean} absolute Whether to scale the current saturation (false) or just set the new saturation (true)\n * @returns {Image}\n */\n red(saturation, absolute = false) {\n if (isNaN(saturation) || saturation < 0)\n throw new RangeError('Invalid saturation value');\n\n this.__set_channel_value__(saturation, absolute, 0);\n\n return this;\n }\n\n /**\n * Sets the green channels saturation\n * @param {number} saturation The saturation to apply (0..1)\n * @param {boolean} absolute Whether to scale the current saturation (false) or just set the new saturation (true)\n * @returns {Image}\n */\n green(saturation, absolute = false) {\n if (isNaN(saturation) || saturation < 0)\n throw new RangeError('Invalid saturation value');\n\n this.__set_channel_value__(saturation, absolute, 1);\n\n return this;\n }\n\n /**\n * Sets the blue channels saturation\n * @param {number} saturation The saturation to apply (0..1)\n * @param {boolean} absolute Whether to scale the current saturation (false) or just set the new saturation (true)\n * @returns {Image}\n */\n blue(saturation, absolute = false) {\n if (isNaN(saturation) || saturation < 0)\n throw new RangeError('Invalid saturation value');\n\n this.__set_channel_value__(saturation, absolute, 2);\n\n return this;\n }\n\n /**\n * @private\n * @param {number} value\n * @param {boolean} absolute\n * @param {number} offset\n */\n __set_channel_value__(value, absolute, offset) {\n for (let i = offset; i < this.bitmap.length; i += 4)\n this.bitmap[i] = value * (absolute ? 255 : this.bitmap[i]);\n }\n\n /**\n * Sets the brightness of the image\n * @param {number} value The lightness to apply (0..1)\n * @param {boolean} absolute Whether to scale the current lightness (false) or just set the new lightness (true)\n * @returns {Image}\n */\n lightness(value, absolute = false) {\n if (isNaN(value) || value < 0)\n throw new RangeError('Invalid lightness value');\n\n return this.fill((x, y) => {\n const [h, s, l, a] = Image.rgbaToHSLA(...this.getRGBAAt(x, y));\n return Image.hslaToColor(h, s, value * (absolute ? 1 : l), a);\n });\n }\n\n /**\n * Sets the saturation of the image\n * @param {number} value The saturation to apply (0..1)\n * @param {boolean} absolute Whether to scale the current saturation (false) or just set the new saturation (true)\n * @returns {Image}\n */\n saturation(value, absolute = false) {\n if (isNaN(value) || value < 0)\n throw new RangeError('Invalid saturation value');\n\n return this.fill((x, y) => {\n const [h, s, l, a] = Image.rgbaToHSLA(...this.getRGBAAt(x, y));\n return Image.hslaToColor(h, value * (absolute ? 1 : s), l, a);\n });\n }\n\n /**\n * Composites (overlays) the source onto this image at the specified coordinates\n * @param {Image} source The image to place\n * @param {number} [x=0] The x position to place the image at\n * @param {number} [y=0] The y position to place the image at\n * @returns {Image}\n */\n composite(source, x = 0, y = 0) {\n x = ~~x;\n y = ~~y;\n\n for (let yy = 0; yy < source.height; yy++) {\n let y_offset = y + yy;\n if (y_offset < 0) continue;\n if (y_offset >= this.height) break;\n\n for (let xx = 0; xx < source.width; xx++) {\n let x_offset = x + xx;\n if (x_offset < 0) continue;\n if (x_offset >= this.width) break;\n\n const offset = 4 * (x_offset + y_offset * this.width);\n const fg = source.__view__.getUint32(4 * (xx + yy * source.width), false);\n const bg = this.__view__.getUint32(offset, false);\n\n if ((fg & 0xff) === 0xff) this.__view__.setUint32(offset, fg, false);\n else if ((fg & 0xff) === 0x00) this.__view__.setUint32(offset, bg, false);\n else this.__view__.setUint32(offset, Image.__alpha_blend__(fg, bg), false);\n }\n }\n\n return this;\n }\n\n /**\n * @private\n * @param {number} fg\n * @param {number} bg\n * @returns {number}\n */\n static __alpha_blend__(fg, bg) {\n const fa = fg & 0xff;\n const alpha = fa + 1;\n const inv_alpha = 256 - fa;\n const r = (alpha * (fg >>> 24) + inv_alpha * (bg >>> 24)) >> 8;\n const b = (alpha * (fg >> 8 & 0xff) + inv_alpha * (bg >> 8 & 0xff)) >> 8;\n const g = (alpha * (fg >> 16 & 0xff) + inv_alpha * (bg >> 16 & 0xff)) >> 8;\n return (((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | (Math.max(fa, bg & 0xff) & 0xff));\n }\n\n /**\n * Inverts the images colors\n * @returns {Image}\n */\n invert() {\n for (const [x, y, color] of this.iterateWithColors())\n this.__set_pixel__(x, y, ((0xffffffff - color) & 0xffffff00) | (color & 0xff));\n\n return this;\n }\n\n /**\n * Inverts the images value (lightness)\n * @returns {Image}\n */\n invertValue() {\n for (const [x, y, color] of this.iterateWithColors()) {\n const [h, s, l, a] = Image.rgbaToHSLA(...Image.colorToRGBA(color));\n this.__set_pixel__(x, y, Image.hslaToColor(h, s, 1 - l, a));\n }\n\n return this;\n }\n\n /**\n * Inverts the images saturation\n * @returns {Image}\n */\n invertSaturation() {\n for (const [x, y, color] of this.iterateWithColors()) {\n const [h, s, l, a] = Image.rgbaToHSLA(...Image.colorToRGBA(color));\n this.__set_pixel__(x, y, Image.hslaToColor(h, 1 - s, l, a));\n }\n\n return this;\n }\n\n /**\n * Inverts the images hue\n * @returns {Image}\n */\n invertHue() {\n for (const [x, y, color] of this.iterateWithColors()) {\n const [h, s, l, a] = Image.rgbaToHSLA(...Image.colorToRGBA(color));\n this.__set_pixel__(x, y, Image.hslaToColor(1 - h, s, l, a));\n }\n\n return this;\n }\n\n /**\n * Shifts the images hue\n * @param {number} degrees How many degrees to shift the hue by\n */\n hueShift(degrees) {\n for (const [x, y, color] of this.iterateWithColors()) {\n const [h, s, l, a] = Image.rgbaToHSLA(...Image.colorToRGBA(color));\n this.__set_pixel__(x, y, Image.hslaToColor(h + degrees / 360, s, l, a));\n }\n\n return this;\n }\n\n /**\n * Gets the average color of the image\n * @returns {number}\n */\n averageColor() {\n let colorAvg = [0, 0, 0];\n let divisor = 0;\n for (let idx = 0; idx < this.bitmap.length; idx += 4) {\n const rgba = this.bitmap.subarray(idx, idx + 4);\n for (let i = 0; i < 3; i++)\n colorAvg[i] += rgba[i];\n divisor += rgba[3] / 255;\n }\n\n return Image.rgbaToColor(...colorAvg.map(v => v / divisor), 0xff);\n }\n\n /**\n * Gets the images dominant color\n * @param {boolean} [ignoreBlack=true] Whether to ignore dark colors below the threshold\n * @param {boolean} [ignoreWhite=true] Whether to ignore light colors above the threshold\n * @param {number} [bwThreshold=0xf] The black/white threshold (0-64)\n * @return {number} The images dominant color\n */\n dominantColor(ignoreBlack = true, ignoreWhite = true, bwThreshold = 0xf) {\n const colorCounts = new Array(0x3ffff);\n for (let i = 0; i < this.bitmap.length; i += 4) {\n const color = this.__view__.getUint32(i, false);\n const [h, s, l] = Image.rgbaToHSLA(...Image.colorToRGBA(color)).map(v => (~~(v * 0x3f)));\n if (ignoreBlack && l < bwThreshold) continue;\n if (ignoreWhite && l > 0x3f - bwThreshold) continue;\n const key = h << 12 | s << 6 | l;\n colorCounts[key] = (colorCounts[key] || 0) + 1;\n }\n\n let maxColorCount = -1;\n let mostProminentValue = 0;\n colorCounts.forEach((el, i) => {\n if (el < maxColorCount) return;\n maxColorCount = el;\n mostProminentValue = i;\n });\n\n if (mostProminentValue === -1)\n return this.dominantColor(ignoreBlack, ignoreWhite, bwThreshold - 1);\n\n const h = (mostProminentValue >>> 12) & 0x3f;\n const s = (mostProminentValue >>> 6) & 0x3f;\n const l = mostProminentValue & 0x3f;\n\n return Image.hslaToColor(h / 0x3f, s / 0x3f, l / 0x3f, 1);\n }\n\n /**\n * Rotates the image the given amount of degrees\n * @param {number} angle The angle to rotate the image for (in degrees)\n * @param {boolean} resize Whether to resize the image so it fits all pixels or just ignore outlying pixels\n */\n rotate(angle, resize = true) {\n if (angle % 360 === 0) return this;\n if (angle % 180 === 0) return this.__rotate_180__();\n\n const rad = Math.PI * (angle / 180);\n\n const sin = Math.sin(rad);\n const cos = Math.cos(rad);\n\n const width = resize\n ? Math.abs(this.width * sin) + Math.abs(this.height * cos)\n : this.width;\n const height = resize\n ? Math.abs(this.width * cos) + Math.abs(this.height * sin)\n : this.height;\n\n const out = new Image(width, height);\n\n const out_cx = width / 2 - .5;\n const out_cy = height / 2 - .5;\n const src_cx = this.width / 2 - .5;\n const src_cy = this.height / 2 - .5;\n\n let h = 0;\n do {\n let w = 0;\n const ysin = src_cx - sin * (h - out_cy);\n const ycos = src_cy + cos * (h - out_cy);\n\n do {\n const xf = ysin + cos * (w - out_cx);\n const yf = ycos + sin * (w - out_cx);\n Image.__interpolate__(this, out, w, h, xf, yf);\n } while (w++ < width);\n } while (h++ < height);\n\n return this.__apply__(out);\n }\n\n /**\n * @returns {Image}\n * @private\n */\n __rotate_180__() {\n let offset = 0;\n this.bitmap.reverse();\n while (offset < this.bitmap.length) this.bitmap.subarray(offset, offset += 4).reverse();\n\n return this;\n }\n\n /**\n * @param {Image} src\n * @param {Image} out\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @private\n */\n static __interpolate__(src, out, x0, y0, x1, y1) {\n const x2 = ~~x1;\n const y2 = ~~y1;\n const xq = x1 - x2;\n const yq = y1 - y2;\n const out_slice = out.bitmap.subarray(4 * (x0 + y0 * out.width), -4);\n\n const ref = {\n r: 0,\n g: 0,\n b: 0,\n a: 0,\n };\n\n Image.__pawn__(x2, y2, (1 - xq) * (1 - yq), ref, src);\n Image.__pawn__(1 + x2, y2, xq * (1 - yq), ref, src);\n Image.__pawn__(x2, 1 + y2, (1 - xq) * yq, ref, src);\n Image.__pawn__(1 + x2, 1 + y2, xq * yq, ref, src);\n\n out_slice[3] = ref.a;\n out_slice[0] = ref.r / ref.a;\n out_slice[1] = ref.g / ref.a;\n out_slice[2] = ref.b / ref.a;\n }\n\n /** @private */\n static __pawn__(point0, point1, weight, ref, src) {\n if (\n point0 > 0\n && point1 > 0\n && point0 < src.width\n && point1 < src.height\n ) {\n const offset = 4 * (point0 + point1 * src.width);\n const src_slice = src.bitmap.subarray(offset, offset + 4);\n\n const wa = weight * src_slice[3];\n\n ref.a += wa;\n ref.r += wa * src_slice[0];\n ref.g += wa * src_slice[1];\n ref.b += wa * src_slice[2];\n }\n }\n\n /**\n * @private\n * @param {Image|Frame} image\n * @returns {Image|Frame}\n */\n __apply__(image) {\n this.__width__ = image.__width__;\n this.__height__ = image.__height__;\n this.__view__ = image.__view__;\n this.__u32__ = image.__u32__;\n this.bitmap = image.bitmap;\n\n if (image instanceof Frame)\n return Frame.from(this, image.duration, image.xOffset, image.yOffset, image.disposalMode);\n\n return this;\n }\n\n /**\n * Creates a multi-point gradient generator\n * @param {Object} colors The gradient points to use (e.g. `{0: 0xff0000ff, 1: 0x00ff00ff}`)\n * @return {(function(number): number)} The gradient generator. The function argument is the position in the gradient (0..1).\n */\n static gradient(colors) {\n const entries = Object.entries(colors).sort((a, b) => a[0] - b[0]);\n const positions = entries.map(e => parseFloat(e[0]));\n const values = entries.map(e => e[1]);\n\n if (positions.length === 0) throw new RangeError('Invalid gradient point count');\n else if (positions.length === 1) {\n return () => values[0];\n } else if (positions.length === 2) {\n const gradient = this.__gradient__(values[0], values[1]);\n return position => {\n if (position <= positions[0]) return values[0];\n if (position >= positions[1]) return values[1];\n return gradient((position - positions[0]) / (positions[1] - positions[0]));\n };\n }\n\n const minDef = Math.min(...positions);\n const maxDef = Math.max(...positions);\n let gradients = [];\n\n for (let i = 0; i < positions.length; i++) {\n let minPos = positions[i - 1];\n if (minPos === undefined) continue;\n\n let maxPos = positions[i];\n\n let minVal = values[i - 1];\n if (minVal === undefined) minVal = values[i];\n\n const maxVal = values[i];\n const gradient = this.__gradient__(minVal, maxVal);\n\n gradients.push({min: minPos, max: maxPos, gradient});\n }\n\n return position => {\n if (position <= minDef) return gradients[0].gradient(0);\n if (position >= maxDef) return gradients[gradients.length - 1].gradient(1);\n\n for (const gradient of gradients)\n if (position >= gradient.min && position <= gradient.max)\n return gradient.gradient((position - gradient.min) / (gradient.max - gradient.min));\n throw new RangeError(`Invalid gradient position: ${position}`);\n };\n }\n\n /**\n * Rounds the images corners\n * @param {number} [radius=min(width,height)/4] The radius of the corners\n * @return {Image}\n */\n roundCorners(radius = Math.min(this.width, this.height) / 4) {\n const radSquared = radius ** 2;\n for (let x = 1; x <= radius; x++) {\n const xRad = (x - radius) ** 2;\n for (let y = 1; y <= radius; y++) {\n if (xRad + (y - radius) ** 2 > radSquared)\n this.bitmap[((y - 1) * this.width + x - 1) * 4 + 3] = 0;\n }\n }\n\n for (let x = 1; x <= radius; x++) {\n const xRad = (x - radius) ** 2;\n for (let y = this.height - radius; y <= this.height; y++) {\n if (xRad + ((this.height - y) - radius) ** 2 > radSquared)\n this.bitmap[((y - 1) * this.width + x - 1) * 4 + 3] = 0;\n }\n }\n\n for (let x = this.width - radius; x <= this.width; x++) {\n const xRad = ((this.width - x) - radius) ** 2;\n for (let y = 1; y <= radius; y++) {\n if (xRad + (y - radius) ** 2 > radSquared)\n this.bitmap[((y - 1) * this.width + x - 1) * 4 + 3] = 0;\n }\n }\n\n for (let x = this.width - radius; x <= this.width; x++) {\n const xRad = ((this.width - x) - radius) ** 2;\n for (let y = this.height - radius; y <= this.height; y++) {\n if (xRad + ((this.height - y) - radius) ** 2 > radSquared)\n this.bitmap[((y - 1) * this.width + x - 1) * 4 + 3] = 0;\n }\n }\n\n return this;\n }\n\n /**\n * @private\n */\n static __gradient__(startColor, endColor) {\n const sr = startColor >>> 24;\n const sg = startColor >> 16 & 0xff;\n const sb = startColor >> 8 & 0xff;\n const sa = startColor & 0xff;\n const er = (endColor >>> 24) - sr;\n const eg = (endColor >> 16 & 0xff) - sg;\n const eb = (endColor >> 8 & 0xff) - sb;\n const ea = (endColor & 0xff) - sa;\n\n return position => {\n const r = sr + position * er;\n const g = sg + position * eg;\n const b = sb + position * eb;\n const a = sa + position * ea;\n return (((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | (a & 0xff));\n };\n }\n\n fisheye(radius = 2) {\n const r = new Image(this.width, this.height);\n\n const w = this.width;\n const h = this.height;\n const tu32 = this.__u32__;\n const ru32 = r.__u32__;\n const iw = 1 / w;\n const ih = 1 / h;\n\n for (const [x, y] of this) {\n const xco = x * iw - .5;\n const yco = y * ih - .5;\n const dfc = Math.sqrt(xco ** 2 + yco ** 2);\n const dis = 2 * dfc ** radius;\n const nx = ((dis * xco / dfc + 0.5) * w) | 0;\n const ny = ((dis * yco / dfc + 0.5) * h) | 0;\n\n if (nx < 1 || nx > w || ny < 1 || ny > h || isNaN(nx) || isNaN(ny))\n continue;\n\n ru32[y * w + x] = tu32[w * ny + nx];\n }\n\n const cO = tu32.length * .5 + w / 2;\n ru32[cO] = tu32[cO];\n\n return this.__apply__(r);\n }\n\n /**\n * @typedef {object} PNGMetadata\n * @property {string} [title] The images title\n * @property {string} [author] The images author\n * @property {string} [description] The images description\n * @property {string} [copyright] The images copyright info\n * @property {string|number|Date} [creationTime=Date.now()] The images creation timestamp\n * @property {string} [software=\"github.com/matmen/ImageScript vX.X.X\"] The software used to create this image\n * @property {string} [disclaimer] A disclaimer for the image\n * @property {string} [warning] A warning for the image\n * @property {string} [source] The images source\n * @property {string} [comment] A comment for the image\n */\n\n /**\n * Encodes the image into a PNG\n * @param {number} compression The compression level to use (0-9)\n * @param {PNGMetadata} [meta={}] Image metadata\n * @return {Promise} The encoded data\n */\n async encode(compression = 1, {\n title,\n author,\n description,\n copyright,\n creationTime,\n software,\n disclaimer,\n warning,\n source,\n comment\n } = {}) {\n return png.encode(this.bitmap, {\n width: this.width,\n height: this.height,\n level: compression,\n channels: 4,\n text: {\n Title: title,\n Author: author,\n Description: description,\n Copyright: copyright,\n 'Creation Time': new Date(creationTime === undefined ? Date.now() : creationTime).toUTCString(),\n Software: software === undefined ? `github.com/matmen/ImageScript v${version}` : software,\n Disclaimer: disclaimer,\n Warning: warning,\n Source: source,\n Comment: comment\n }\n });\n }\n\n /**\n * Encodes the image into a JPEG\n * @param {number} [quality=90] The JPEG quality to use (1-100)\n * @return {Promise}\n */\n async encodeJPEG(quality = 90) {\n return (await jpeglib.init()).encode(this.bitmap, this.width, this.height, quality);\n }\n\n /**\n * Decodes an image (PNG, JPEG or TIFF)\n * @param {Buffer|Uint8Array} data The binary data to decode\n * @return {Promise} The decoded image\n */\n static async decode(data) {\n let image;\n\n data = mem.view(data);\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n if (ImageType.isPNG(view)) { // PNG\n const {width, height, pixels} = png.decode(data);\n image = new Image(width, height);\n image.bitmap.set(pixels);\n } else if (ImageType.isJPEG(view)) { // JPEG\n const framebuffer = (await jpeglib.init()).decode(data);\n\n const width = framebuffer.width;\n const height = framebuffer.height;\n const pixelType = framebuffer.format;\n\n image = new Image(width, height);\n const buffer = framebuffer.buffer;\n\n if (pixelType === 0) {\n const view = new DataView(image.bitmap.buffer);\n\n for (let i = 0; i < buffer.length; i++) {\n const pixel = buffer[i];\n view.setUint32(i * 4, pixel << 24 | pixel << 16 | pixel << 8 | 0xff, false);\n }\n } else if (pixelType === 1) {\n image.bitmap.fill(0xff);\n for (let i = 0; i < width * height; i++)\n image.bitmap.set(buffer.subarray(i * 3, i * 3 + 3), i * 4);\n } else if (pixelType === 2) {\n for (let i = 0; i < buffer.length; i += 4) {\n image.bitmap[i] = 0xff * (1 - buffer[i] / 0xff) * (1 - buffer[i + 3] / 0xff);\n image.bitmap[i + 1] = 0xff * (1 - buffer[i + 1] / 0xff) * (1 - buffer[i + 3] / 0xff);\n image.bitmap[i + 2] = 0xff * (1 - buffer[i + 2] / 0xff) * (1 - buffer[i + 3] / 0xff);\n image.bitmap[i + 3] = 0xff;\n }\n }\n } else if (ImageType.isTIFF(view)) { // TIFF\n const framebuffer = (await tifflib.init()).decode(data);\n image = new Image(framebuffer.width, framebuffer.height);\n\n image.bitmap.set(framebuffer.buffer);\n } else throw new Error('Unsupported image type');\n\n return image;\n }\n\n /**\n * Scale the SVG by the given amount. For use with {@link Image.renderSVG}\n * @return {number}\n */\n static get SVG_MODE_SCALE() {\n return 1;\n }\n\n /**\n * Scale the SVG to fit the given width. For use with {@link Image.renderSVG}\n * @return {number}\n */\n static get SVG_MODE_WIDTH() {\n return 2;\n }\n\n /**\n * Scale the SVG to fit the given height. For use with {@link Image.renderSVG}\n * @return {number}\n */\n static get SVG_MODE_HEIGHT() {\n return 3;\n }\n\n /**\n * Creates a new image from the given SVG\n * @param {string} svg The SVG content\n * @param {number} size The size to use\n * @param {number} mode The SVG resizing mode to use (one of {@link SVG_MODE_SCALE}, {@link SVG_MODE_WIDTH}, {@link SVG_MODE_HEIGHT})\n * @return {Promise} The rendered SVG graphic\n */\n static async renderSVG(svg, size = 1, mode = this.SVG_MODE_SCALE) {\n if (![this.SVG_MODE_WIDTH, this.SVG_MODE_HEIGHT, this.SVG_MODE_SCALE].includes(mode))\n throw new Error('Invalid SVG scaling mode');\n\n if (mode === this.SVG_MODE_SCALE && size <= 0)\n throw new RangeError('SVG scale must be > 0');\n if (mode !== this.SVG_MODE_SCALE && size < 1)\n throw new RangeError('SVG size must be >= 1')\n\n if (typeof svg === 'string') svg = new TextEncoder().encode(svg);\n const framebuffer = (await svglib.init()).rasterize(svg, mode, size);\n\n const image = new Image(framebuffer.width, framebuffer.height);\n\n image.bitmap.set(framebuffer.buffer);\n\n return image;\n }\n\n /**\n * Creates a new image containing the rendered text.\n * @param {Uint8Array} font TrueType (ttf/ttc) or OpenType (otf) font buffer to use\n * @param {number} scale Font size to use\n * @param {string} text Text to render\n * @param {number} [color=0xffffffff] Text color to use\n * @param {TextLayout} [layout] The text layout to use\n * @return {Promise} The rendered text\n */\n static async renderText(font, scale, text, color = 0xffffffff, layout = new TextLayout()) {\n const { Font, Layout } = await fontlib.init();\n\n font = new Font(scale, font);\n const [r, g, b, a] = Image.colorToRGBA(color);\n\n const layoutOptions = new Layout();\n\n layoutOptions.reset({\n max_width: layout.maxWidth,\n max_height: layout.maxHeight,\n wrap_style: layout.wrapStyle,\n vertical_align: layout.verticalAlign,\n horizontal_align: layout.horizontalAlign,\n wrap_hard_breaks: layout.wrapHardBreaks\n });\n\n layoutOptions.append(font, text, {scale});\n const framebuffer = layoutOptions.rasterize(r, g, b);\n const image = new Image(framebuffer.width, framebuffer.height);\n\n image.bitmap.set(framebuffer.buffer);\n\n if (image.height > layout.maxHeight)\n image.crop(0, 0, image.width, Math.floor(layoutOptions.lines() / image.height * layout.maxHeight) * (image.height / layoutOptions.lines()));\n\n font.free();\n layoutOptions.free();\n return image.opacity(a / 0xff);\n }\n\n}\n\n/**\n * Represents a frame in a GIF\n * @extends Image\n */\n class Frame extends Image {\n /**\n * GIF frame disposal mode KEEP. For use with {@link Frame}\n * @returns {string}\n */\n static get DISPOSAL_KEEP() {\n return 'keep';\n }\n\n /**\n * GIF frame disposal mode PREVIOUS. For use with {@link Frame}\n * @returns {string}\n */\n static get DISPOSAL_PREVIOUS() {\n return 'previous';\n }\n\n /**\n * GIF frame disposal mode BACKGROUND. For use with {@link Frame}\n * @returns {string}\n */\n static get DISPOSAL_BACKGROUND() {\n return 'background';\n }\n\n static __convert_disposal_mode__(mode) {\n if (typeof mode === 'string')\n mode = ['any', 'keep', 'previous', 'background'].indexOf(mode);\n if (mode < 0 || mode > 3)\n throw new RangeError('Invalid disposal mode');\n\n return mode;\n }\n\n /**\n * Creates a new, blank frame\n * @param {number} width\n * @param {number} height\n * @param {number} [duration = 100] The frames duration (in ms)\n * @param {number} [xOffset=0] The frames offset on the x-axis\n * @param {number} [yOffset=0] The frames offset on the y-axis\n * @param {string|number} [disposalMode=Frame.DISPOSAL_KEEP] The frame's disposal mode ({@link Frame.DISPOSAL_KEEP}, {@link Frame.DISPOSAL_PREVIOUS} or {@link Frame.DISPOSAL_BACKGROUND})\n * @return {Frame}\n */\n constructor(width, height, duration = 100, xOffset = 0, yOffset = 0, disposalMode = Frame.DISPOSAL_KEEP) {\n if (isNaN(duration) || duration < 0)\n throw new RangeError('Invalid frame duration');\n\n super(width, height);\n this.duration = duration;\n this.xOffset = xOffset;\n this.yOffset = yOffset;\n this.disposalMode = disposalMode;\n }\n\n /**\n * The Frame's disposal mode\n * @returns {number}\n */\n get disposalMode() {\n return this.__disposalMode__;\n }\n\n /**\n * Sets the frame's disposal mode, converting it to the internal numeric value.\n * @param {string|number} disposalMode The frame's disposal mode\n */\n set disposalMode(disposalMode) {\n this.__disposalMode__ = Frame.__convert_disposal_mode__(disposalMode);\n }\n\n toString() {\n return `Frame<${this.width}x${this.height}x${this.duration}ms>`;\n }\n\n /**\n * Converts an Image instance to a Frame, cloning it in the process\n * @param {Image} image The image to create the frame from\n * @param {number} [duration = 100] The frames duration (in ms)\n * @param {number} [xOffset=0] The frames offset on the x-axis\n * @param {number} [yOffset=0] The frames offset on the y-axis\n * @param {string|number} [disposalMode=Frame.DISPOSAL_KEEP] The frames disposal mode ({@link Frame.DISPOSAL_KEEP}, {@link Frame.DISPOSAL_PREVIOUS} or {@link Frame.DISPOSAL_BACKGROUND})\n * @return {Frame}\n */\n static from(image, duration, xOffset, yOffset, disposalMode = Frame.DISPOSAL_KEEP) {\n if (!(image instanceof Image))\n throw new TypeError('Invalid image passed');\n\n const frame = new Frame(image.width, image.height, duration, xOffset, yOffset, disposalMode);\n frame.bitmap.set(image.bitmap);\n\n return frame;\n }\n\n resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n const originalWidth = this.width;\n const originalHeight = this.height;\n\n const result = super.resize(width, height, mode);\n\n this.xOffset *= result.width / originalWidth;\n this.yOffset *= result.height / originalHeight;\n\n return result;\n }\n}\n\n/**\n * Represents a GIF image as an array of frames\n * @extends Array\n */\nclass GIF extends Array {\n /**\n * Creates a new GIF image.\n * @param {Frame[]} frames The frames to create the GIF from\n * @param {number} [loopCount=-1] How often to loop the GIF for (-1 = unlimited)\n * @property {number} loopCount How often the GIF will loop for\n */\n constructor(frames, loopCount = -1) {\n super(...frames);\n\n for (const frame of this)\n if (!(frame instanceof Frame))\n throw new TypeError(`Frame ${this.indexOf(frame)} is not an instance of Frame`);\n\n if (loopCount < -1 || isNaN(loopCount))\n throw new RangeError('Invalid loop count');\n\n this.loopCount = loopCount;\n }\n\n /**\n * The GIFs width\n * @returns {number}\n */\n get width() {\n let max = 0;\n for (const frame of this) {\n let width = frame.width + frame.xOffset;\n if (max < width)\n max = width;\n }\n\n return max;\n }\n\n /**\n * The GIFs height\n * @returns {number}\n */\n get height() {\n let max = 0;\n for (const frame of this) {\n let height = frame.height + frame.yOffset;\n if (max < height)\n max = height;\n }\n\n return max;\n }\n\n toString() {\n return `GIF<${this.width}x${this.height}x${this.duration}ms>`;\n }\n\n /**\n * @returns {Generator}\n */\n * [Symbol.iterator]() {\n for (let i = 0; i < this.length; i++)\n yield this[i];\n }\n\n slice(start, end) {\n if (end === Infinity)\n end = this.length;\n const frames = new Array(end - start);\n for (let i = 0; i < frames.length; i++)\n frames[i] = this[i + start];\n return new GIF(frames, this.loopCount);\n }\n\n /**\n * The GIFs duration (in ms)\n * @return {number}\n */\n get duration() {\n return this.reduce((acc, frame) => acc + frame.duration, 0);\n }\n\n /**\n * Encodes the image into a GIF\n * @param {number} [quality=95] GIF quality 0-100\n * @return {Promise} The encoded data\n */\n async encode(quality = 95) {\n const encoder = new (await giflib.init()).Encoder(this.width, this.height, this.loopCount);\n\n for (const frame of this) {\n if (!(frame instanceof Frame)) throw new Error('GIF contains invalid frames');\n encoder.add(frame.xOffset, frame.yOffset, ~~(frame.duration / 10), frame.width, frame.height, frame.bitmap, frame.disposalMode, quality / 100 * 29 + 1);\n }\n\n return encoder.u8();\n }\n\n /**\n * Decodes a GIF image\n * @param {Buffer|Uint8Array} data The binary data to decode\n * @param {boolean} [onlyExtractFirstFrame=false] Whether to end GIF decoding after the first frame\n * @return {Promise} The decoded GIF\n */\n static async decode(data, onlyExtractFirstFrame = false) {\n let image;\n data = mem.view(data);\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n if (ImageType.isGIF(view)) { // GIF\n const frames = [];\n const decoder = new (await giflib.init()).Decoder(data);\n\n if (onlyExtractFirstFrame) {\n const first = decoder.frames().next().value;\n const frame = new Frame(first.width, first.height, 10 * first.delay, first.x, first.y, first.dispose);\n\n frame.bitmap.set(first.buffer);\n\n frames.push(frame);\n image = new GIF(frames);\n }\n\n const gwidth = decoder.width | 0;\n const gheight = decoder.height | 0;\n const u32 = new Uint32Array(decoder.width * decoder.height);\n const u8 = new Uint8Array(u32.buffer, u32.byteOffset, u32.byteLength);\n\n for (const frame of decoder.frames()) {\n let offset8 = 0 | 0;\n let offset32 = 0 | 0;\n const fx = frame.x | 0;\n const fy = frame.y | 0;\n const f8 = frame.buffer;\n const mode = frame.dispose;\n const width = frame.width | 0;\n const height = frame.height | 0;\n const f32 = new Uint32Array(f8.buffer, f8.byteOffset, width * height);\n const f = frames[frames.push(new Frame(gwidth, gheight, 10 * frame.delay, 0, 0, 3)) - 1];\n\n const t8 = f.bitmap;\n const t32 = new Uint32Array(t8.buffer);\n\n t8.set(u8);\n\n if (2 === mode) {\n for (let y = 0 | 0; y < height; y++) {\n const y_offset = fx + gwidth * (y + fy) | 0;\n\n for (let x = 0 | 0; x < width; x++) {\n const x_offset = x + y_offset;\n\n if (0 === f8[3 + offset8])\n t32[x_offset] = u32[x_offset];\n else t32[x_offset] = f32[offset32];\n\n offset32++;\n offset8 += 4;\n }\n }\n }\n\n else if (3 === mode) {\n for (let y = 0 | 0; y < height; y++) {\n const y_offset = fx + gwidth * (y + fy) | 0;\n\n for (let x = 0 | 0; x < width; x++) {\n const x_offset = x + y_offset;\n\n if (0 === f8[3 + offset8])\n t32[x_offset] = u32[x_offset];\n else t32[x_offset] = f32[offset32];\n\n offset32++;\n offset8 += 4;\n u32[x_offset] = 0;\n }\n }\n }\n\n else if (0 === mode || 1 === mode) {\n t8.set(u8);\n for (let y = 0 | 0; y < height; y++) {\n const y_offset = fx + gwidth * (y + fy) | 0;\n\n for (let x = 0 | 0; x < width; x++) {\n const x_offset = x + y_offset;\n\n if (0 === f8[3 + offset8])\n t32[x_offset] = u32[x_offset];\n else t32[x_offset] = f32[offset32];\n\n offset32++;\n offset8 += 4;\n u32[x_offset] = t32[x_offset];\n }\n }\n }\n }\n\n image = new GIF(frames);\n } else throw new Error('Unsupported image type');\n\n return image;\n }\n\n resize(width, height, mode = Image.RESIZE_NEAREST_NEIGHBOR) {\n for (const frame of this)\n frame.resize(width, height, mode);\n }\n}\n\nclass TextLayout {\n /**\n * Layout options for {@link renderText}\n * @param {object} [options]\n * @param {number} [options.maxWidth=Infinity] The texts max width\n * @param {number} [options.maxHeight=Infinity] The texts max height\n * @param {string} [options.wrapStyle='word'] The texts wrap style when reaching the max width (word, char)\n * @param {string} [options.verticalAlign='left'] The vertical align mode (left, center, right)\n * @param {string} [options.horizontalAlign='top'] The horizontal align mode (top, middle, bottom)\n * @param {string} [options.wrapHardBreaks=true] Whether to force wrap at new line characters\n */\n constructor(options) {\n const {maxWidth, maxHeight, wrapStyle, verticalAlign, horizontalAlign, wrapHardBreaks} = options || {};\n\n this.maxWidth = maxWidth || Infinity;\n if (isNaN(this.maxWidth) || this.maxWidth < 1)\n throw new RangeError('Invalid maxWidth');\n\n this.maxHeight = maxHeight || Infinity;\n if (isNaN(this.maxHeight) || this.maxHeight < 1)\n throw new RangeError('Invalid maxHeight');\n\n this.wrapStyle = wrapStyle || 'word';\n if (!['word', 'char'].includes(this.wrapStyle))\n throw new RangeError('Invalid wrapStyle');\n\n this.verticalAlign = verticalAlign || 'left';\n if (!['left', 'center', 'right'].includes(this.verticalAlign))\n throw new RangeError('Invalid verticalAlign');\n\n this.horizontalAlign = horizontalAlign || 'top';\n if (!['top', 'middle', 'bottom'].includes(this.horizontalAlign))\n throw new RangeError('Invalid horizontalAlign');\n\n this.wrapHardBreaks = typeof wrapHardBreaks === 'undefined' ? true : wrapHardBreaks;\n if (typeof this.wrapHardBreaks !== 'boolean')\n throw new TypeError('Invalid wrapHardBreaks');\n }\n}\n\nclass ImageType {\n /**\n * Gets an images type (png, jpeg, tiff, gif)\n * @param {Buffer|Uint8Array} data The image binary to get the type of\n * @returns {string|null} The image type (png, jpeg, tiff, gif, null)\n */\n static getType(data) {\n let view;\n if (!ArrayBuffer.isView(data)) {\n data = new Uint8Array(data);\n view = new DataView(data.buffer);\n } else {\n data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n }\n\n if (this.isPNG(view)) return 'png';\n if (this.isJPEG(view)) return 'jpeg';\n if (this.isTIFF(view)) return 'tiff';\n if (this.isGIF(view)) return 'gif';\n return null;\n }\n\n /**\n * @param {DataView} view\n * @returns {boolean}\n */\n static isPNG(view) {\n return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.PNG;\n }\n\n /**\n * @param {DataView} view\n * @returns {boolean}\n */\n static isJPEG(view) {\n return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.JPEG;\n }\n\n /**\n * @param {DataView} view\n * @returns {boolean}\n */\n static isTIFF(view) {\n return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.TIFF;\n }\n\n /**\n * @param {DataView} view\n * @returns {boolean}\n */\n static isGIF(view) {\n return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.GIF;\n }\n}\n\n/**\n * Decodes the given image binary\n * @param {Uint8Array|Buffer} data The image data\n * @param {boolean} [onlyExtractFirstFrame] Whether to end GIF decoding after the first frame\n * @returns {Promise} The decoded image\n */\nfunction decode(data, onlyExtractFirstFrame) {\n const type = ImageType.getType(data);\n\n if (type === 'gif')\n return GIF.decode(data, onlyExtractFirstFrame);\n return Image.decode(data);\n}\n\nmodule.exports = {Image, GIF, Frame, TextLayout, ImageType, decode};\n","/* global SharedArrayBuffer */\nconst mem = require('./buffer.js');\nconst crc32 = require('./crc32.js');\nconst { compress, decompress } = require('./zlib.js');\n\nconst __IHDR__ = new Uint8Array([73, 72, 68, 82]);\nconst __IDAT__ = new Uint8Array([73, 68, 65, 84]);\nconst __IEND__ = new Uint8Array([73, 69, 78, 68]);\nconst __IEND_CRC__ = crc32(new Uint8Array([73, 69, 78, 68]));\nconst HEAD = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);\n\nconst color_types = {\n GREYSCALE: 0,\n TRUECOLOR: 2,\n INDEXED_COLOR: 3,\n GREYSCALE_ALPHA: 4,\n TRUECOLOR_ALPHA: 6\n};\n\nconst channels_to_color_type = {\n 1: color_types.GREYSCALE,\n 2: color_types.GREYSCALE_ALPHA,\n\n 3: color_types.TRUECOLOR,\n 4: color_types.TRUECOLOR_ALPHA\n};\n\nconst utf8encoder = new TextEncoder; // replace with latin1 encoder or iext\n\nmodule.exports = {\n encode(data, { text, width, height, channels, depth = 8, level = 0 }) {\n let offset = 0;\n let tmp_offset = 0;\n const row_length = width * channels;\n const tmp = new Uint8Array(height + data.length);\n\n while (offset < data.length) {\n tmp[tmp_offset++] = 0;\n tmp.set(data.subarray(offset, (offset += row_length)), tmp_offset);\n\n tmp_offset += row_length;\n }\n\n if (text) {\n let chunks = [];\n for (const key in text) {\n if (!text[key]) continue;\n const kb = utf8encoder.encode(key);\n const tb = utf8encoder.encode(text[key]);\n const chunk = new Uint8Array(1 + 12 + kb.length + tb.length);\n\n const view = new DataView(chunk.buffer);\n\n chunk[4] = 0x74;\n chunk[5] = 0x45;\n chunk[6] = 0x58;\n chunk[7] = 0x74;\n chunk.set(kb, 8);\n chunks.push(chunk);\n chunk.set(tb, 9 + kb.length);\n view.setUint32(0, chunk.length - 12);\n view.setUint32(chunk.length - 4, crc32(chunk.subarray(4, chunk.length - 4)));\n }\n\n text = mem.from_parts(chunks);\n }\n\n offset = text ? text.length : 0;\n const compressed = compress(tmp, level);\n const array = new Uint8Array(49 + offset + HEAD.length + compressed.length);\n\n array[26] = 0;\n array[27] = 0;\n array[28] = 0;\n array[24] = depth;\n array.set(HEAD, 0);\n array.set(__IHDR__, 12);\n array.set(__IDAT__, 37);\n array.set(compressed, 41);\n array[25] = channels_to_color_type[channels];\n if (text) array.set(text, 45 + compressed.length);\n array.set(__IEND__, 49 + offset + compressed.length);\n\n const view = new DataView(array.buffer);\n\n view.setUint32(8, 13);\n view.setUint32(16, width);\n view.setUint32(20, height);\n view.setUint32(33, compressed.length);\n view.setUint32(45 + offset + compressed.length, 0);\n view.setUint32(53 + offset + compressed.length, __IEND_CRC__);\n view.setUint32(29, crc32(new Uint8Array(array.buffer, 12, 17)));\n view.setUint32(41 + compressed.length, crc32(new Uint8Array(array.buffer, 37, 4 + compressed.length)));\n\n return array;\n },\n\n decode(array) {\n let view = new DataView(array.buffer, array.byteOffset, array.byteLength);\n\n const width = view.getUint32(16);\n const height = view.getUint32(20);\n let bit_depth = array[24];\n const color_type = array[25];\n let channels = ({ 3: 1, 0: 1, 4: 2, 2: 3, 6: 4 })[color_type];\n const bytespp = channels * bit_depth / 8;\n\n const row_length = width * bytespp;\n let pixels = new Uint8Array(height * row_length);\n\n let offset = 0;\n let p_offset = 0;\n\n let c_offset = 33;\n const chunks = [];\n\n let palette, alphaPalette;\n\n const maxSearchOffset = array.length - 5;\n\n let type;\n while ((type = view.getUint32(4 + c_offset)) !== 1229278788) { // IEND\n if (type === 1229209940) // IDAT\n chunks.push(array.subarray(8 + c_offset, 8 + c_offset + view.getUint32(c_offset)));\n else if (type === 1347179589) { // PLTE\n if (palette)\n throw new Error('PLTE can only occur once in an image');\n palette = new Uint32Array(view.getUint32(c_offset));\n for (let pxlOffset = 0; pxlOffset < palette.length * 8; pxlOffset += 3)\n palette[pxlOffset / 3] = array[8 + c_offset + pxlOffset] << 24 | array[8 + c_offset + pxlOffset + 1] << 16 | array[8 + c_offset + pxlOffset + 2] << 8 | 0xff;\n } else if (type === 1951551059) { // tRNS\n if (alphaPalette)\n throw new Error('tRNS can only occur once in an image');\n alphaPalette = new Uint8Array(view.getUint32(c_offset));\n for (let i = 0; i < alphaPalette.length; i++)\n alphaPalette[i] = array[8 + c_offset + i];\n }\n\n c_offset += 4 + 4 + 4 + view.getUint32(c_offset);\n if (c_offset > maxSearchOffset) // missing IEND\n break;\n }\n\n array = decompress(chunks.length === 1 ? chunks[0] : mem.from_parts(chunks), height + height * row_length);\n\n while (offset < array.byteLength) {\n const filter = array[offset++];\n const slice = array.subarray(offset, offset += row_length);\n\n if (0 === filter) pixels.set(slice, p_offset);\n else if (1 === filter) this.filter_1(slice, pixels, p_offset, bytespp, row_length);\n else if (2 === filter) this.filter_2(slice, pixels, p_offset, bytespp, row_length);\n else if (3 === filter) this.filter_3(slice, pixels, p_offset, bytespp, row_length);\n else if (4 === filter) this.filter_4(slice, pixels, p_offset, bytespp, row_length);\n\n p_offset += row_length;\n }\n\n if (color_type === 3) {\n if (!palette)\n throw new Error('Indexed color PNG has no PLTE');\n\n if (alphaPalette)\n for (let i = 0; i < alphaPalette.length; i++)\n palette[i] &= 0xffffff00 | alphaPalette[i];\n\n const newPixels = new Uint8Array(width * height * 4);\n const pixelView = new DataView(newPixels.buffer, newPixels.byteOffset, newPixels.byteLength);\n for (let i = 0; i < pixels.length * (8 / bit_depth); i++)\n pixelView.setUint32(i * 4, palette[pixels[~~(i / (8 / bit_depth))] & (2**bit_depth-1)], false);\n channels = 4;\n bit_depth = 8;\n pixels = newPixels;\n }\n\n if (bit_depth !== 8) {\n const newPixels = new Uint8Array(pixels.length / bit_depth * 8);\n for (let i = 0; i < pixels.length; i += 2)\n newPixels[i / 2] = pixels[i];\n pixels = newPixels;\n }\n\n if (channels !== 4) {\n const newPixels = new Uint8Array(width * height * 4);\n const view = new DataView(newPixels.buffer);\n\n if (channels === 1) {\n for (let i = 0; i < width * height; i++) {\n const pixel = pixels[i];\n view.setUint32(i * 4, pixel << 24 | pixel << 16 | pixel << 8 | 0xff, false);\n }\n } else if (channels === 2) {\n for (let i = 0; i < width * height * 2; i += 2) {\n const pixel = pixels[i];\n view.setUint32(i * 2, pixel << 24 | pixel << 16 | pixel << 8 | pixels[i + 1], false);\n }\n } else if (channels === 3) {\n newPixels.fill(0xff);\n for (let i = 0; i < width * height; i++)\n newPixels.set(pixels.subarray(i * 3, i * 3 + 3), i * 4);\n }\n\n pixels = newPixels;\n }\n\n return { width, height, pixels };\n },\n\n filter_1(slice, pixels, p_offset, bytespp, row_length) {\n let i = 0;\n while (i < bytespp) pixels[i + p_offset] = slice[i++];\n while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - bytespp];\n },\n\n filter_2(slice, pixels, p_offset, bytespp, row_length) {\n if (0 === p_offset) pixels.set(slice, p_offset);\n else {\n let i = 0;\n while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length];\n }\n },\n\n filter_3(slice, pixels, p_offset, bytespp, row_length) {\n let i = 0;\n\n if (0 === p_offset) {\n while (i < bytespp) pixels[i] = slice[i++];\n while (i < row_length) pixels[i] = slice[i] + (pixels[i++ - bytespp] >> 1);\n } else {\n while (i < bytespp) pixels[i + p_offset] = slice[i] + (pixels[i++ + p_offset - row_length] >> 1);\n while (i < row_length) pixels[i + p_offset] = slice[i] + (pixels[i + p_offset - bytespp] + pixels[i++ + p_offset - row_length] >> 1);\n }\n },\n\n filter_4(slice, pixels, p_offset, bytespp, row_length) {\n let i = 0;\n\n if (0 === p_offset) {\n while (i < bytespp) pixels[i] = slice[i++];\n while (i < row_length) pixels[i] = slice[i] + pixels[i++ - bytespp];\n } else {\n while (i < bytespp) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length];\n\n while (i < row_length) {\n const a = pixels[i + p_offset - bytespp];\n const b = pixels[i + p_offset - row_length];\n const c = pixels[i + p_offset - bytespp - row_length];\n\n const p = a + b - c;\n const pa = Math.abs(p - a);\n const pb = Math.abs(p - b);\n const pc = Math.abs(p - c);\n\n pixels[i + p_offset] = slice[i++] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c));\n }\n }\n }\n};\n","const { version } = require('../../package.json');\n\nlet mod = null;\nmodule.exports = {\n async init() {\n if (!mod) {\n const streaming = 'compileStreaming' in WebAssembly;\n mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/svg.wasm`).then(x => streaming ? x : x.arrayBuffer()));\n };\n\n return this.new();\n },\n\n new() {\n const wasm = new WebAssembly.Instance(mod).exports;\n\n class mem {\n static length() { return wasm.wlen(); }\n static alloc(size) { return wasm.walloc(size); }\n static free(ptr, size) { return wasm.wfree(ptr, size); }\n static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); }\n static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); }\n\n static copy_and_free(ptr, size) {\n let slice = mem.u8(ptr, size).slice();\n return (wasm.wfree(ptr, size), slice);\n }\n }\n\n function rasterize(buffer, fit, scale) {\n const bptr = mem.alloc(buffer.length);\n mem.u8(bptr, buffer.length).set(buffer);\n const ptr = wasm.rasterize(bptr, buffer.length, fit, scale);\n\n if (0 === ptr) throw new Error('svg: failed to parse');\n if (1 === ptr) throw new Error('svg: failed to rasterize');\n\n const framebuffer = {\n width: wasm.rasterize_width(ptr),\n height: wasm.rasterize_height(ptr),\n buffer: mem.u8(wasm.rasterize_buffer(ptr), mem.length()).slice(),\n }\n\n return (wasm.rasterize_free(ptr), framebuffer);\n }\n\n return { rasterize };\n },\n}\n","// node_modules/fflate/esm/browser.js\n// https://github.com/101arrowz/fflate\n\n// MIT License\n\n// Copyright (c) 2020 Arjun Barrett\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n\n\nvar u8 = Uint8Array;\nvar u16 = Uint16Array;\nvar u32 = Uint32Array;\nvar fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0]);\nvar fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0]);\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\nvar freb = function (eb, start) {\n var b = new u16(31);\n for (var i = 0; i < 31; ++i) {\n b[i] = start += 1 << eb[i - 1];\n }\n var r = new u32(b[30]);\n for (var i = 1; i < 30; ++i) {\n for (var j = b[i]; j < b[i + 1]; ++j) {\n r[j] = j - b[i] << 5 | i;\n }\n }\n return [b, r];\n};\nvar _a = freb(fleb, 2);\nvar fl = _a[0];\nvar revfl = _a[1];\nfl[28] = 258, revfl[258] = 28;\nvar _b = freb(fdeb, 0);\nvar fd = _b[0];\nvar revfd = _b[1];\nvar rev = new u16(32768);\nfor (var i = 0; i < 32768; ++i) {\n x = (i & 43690) >>> 1 | (i & 21845) << 1;\n x = (x & 52428) >>> 2 | (x & 13107) << 2;\n x = (x & 61680) >>> 4 | (x & 3855) << 4;\n rev[i] = ((x & 65280) >>> 8 | (x & 255) << 8) >>> 1;\n}\nvar x;\nvar hMap = function (cd, mb, r) {\n var s = cd.length;\n var i = 0;\n var l = new u16(mb);\n for (; i < s; ++i)\n ++l[cd[i] - 1];\n var le = new u16(mb);\n for (i = 0; i < mb; ++i) {\n le[i] = le[i - 1] + l[i - 1] << 1;\n }\n var co;\n if (r) {\n co = new u16(1 << mb);\n var rvb = 15 - mb;\n for (i = 0; i < s; ++i) {\n if (cd[i]) {\n var sv = i << 4 | cd[i];\n var r_1 = mb - cd[i];\n var v = le[cd[i] - 1]++ << r_1;\n for (var m = v | (1 << r_1) - 1; v <= m; ++v) {\n co[rev[v] >>> rvb] = sv;\n }\n }\n }\n } else {\n co = new u16(s);\n for (i = 0; i < s; ++i) {\n if (cd[i]) {\n co[i] = rev[le[cd[i] - 1]++] >>> 15 - cd[i];\n }\n }\n }\n return co;\n};\nvar flt = new u8(288);\nfor (var i = 0; i < 144; ++i)\n flt[i] = 8;\nfor (var i = 144; i < 256; ++i)\n flt[i] = 9;\nfor (var i = 256; i < 280; ++i)\n flt[i] = 7;\nfor (var i = 280; i < 288; ++i)\n flt[i] = 8;\nvar fdt = new u8(32);\nfor (var i = 0; i < 32; ++i)\n fdt[i] = 5;\nvar flm = hMap(flt, 9, 0);\nvar flrm = hMap(flt, 9, 1);\nvar fdm = hMap(fdt, 5, 0);\nvar fdrm = hMap(fdt, 5, 1);\nvar max = function (a) {\n var m = a[0];\n for (var i = 1; i < a.length; ++i) {\n if (a[i] > m)\n m = a[i];\n }\n return m;\n};\nvar bits = function (d, p, m) {\n var o = p >> 3 | 0;\n return (d[o] | d[o + 1] << 8) >> (p & 7) & m;\n};\nvar bits16 = function (d, p) {\n var o = p >> 3 | 0;\n return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);\n};\nvar shft = function (p) {\n return (p >> 3 | 0) + (p & 7 && 1);\n};\nvar slc = function (v, s, e) {\n if (s == null || s < 0)\n s = 0;\n if (e == null || e > v.length)\n e = v.length;\n var n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s);\n n.set(v.subarray(s, e));\n return n;\n};\nvar inflt = function (dat, buf, st) {\n var sl = dat.length;\n if (!sl || st && !st.l && sl < 5)\n return buf || new u8(0);\n var noBuf = !buf || st;\n var noSt = !st || st.i;\n if (!st)\n st = {};\n if (!buf)\n buf = new u8(sl * 3);\n var cbuf = function (l2) {\n var bl = buf.length;\n if (l2 > bl) {\n var nbuf = new u8(Math.max(bl * 2, l2));\n nbuf.set(buf);\n buf = nbuf;\n }\n };\n var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\n var tbts = sl * 8;\n do {\n if (!lm) {\n st.f = final = bits(dat, pos, 1);\n var type = bits(dat, pos + 1, 3);\n pos += 3;\n if (!type) {\n var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;\n if (t > sl) {\n if (noSt)\n throw \"unexpected EOF\";\n break;\n }\n if (noBuf)\n cbuf(bt + l);\n buf.set(dat.subarray(s, t), bt);\n st.b = bt += l, st.p = pos = t * 8;\n continue;\n } else if (type === 1)\n lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\n else if (type === 2) {\n var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\n var tl = hLit + bits(dat, pos + 5, 31) + 1;\n pos += 14;\n var ldt = new u8(tl);\n var clt = new u8(19);\n for (var i = 0; i < hcLen; ++i) {\n clt[clim[i]] = bits(dat, pos + i * 3, 7);\n }\n pos += hcLen * 3;\n var clb = max(clt), clbmsk = (1 << clb) - 1;\n var clm = hMap(clt, clb, 1);\n for (var i = 0; i < tl;) {\n var r = clm[bits(dat, pos, clbmsk)];\n pos += r & 15;\n var s = r >>> 4;\n if (s < 16) {\n ldt[i++] = s;\n } else {\n var c = 0, n = 0;\n if (s === 16)\n n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\n else if (s === 17)\n n = 3 + bits(dat, pos, 7), pos += 3;\n else if (s === 18)\n n = 11 + bits(dat, pos, 127), pos += 7;\n while (n--)\n ldt[i++] = c;\n }\n }\n var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\n lbt = max(lt);\n dbt = max(dt);\n lm = hMap(lt, lbt, 1);\n dm = hMap(dt, dbt, 1);\n } else\n throw \"invalid block type\";\n if (pos > tbts) {\n if (noSt)\n throw \"unexpected EOF\";\n break;\n }\n }\n if (noBuf)\n cbuf(bt + 131072);\n var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\n var lpos = pos;\n for (; ; lpos = pos) {\n var c = lm[bits16(dat, pos) & lms], sym = c >>> 4;\n pos += c & 15;\n if (pos > tbts) {\n if (noSt)\n throw \"unexpected EOF\";\n break;\n }\n if (!c)\n throw \"invalid length/literal\";\n if (sym < 256)\n buf[bt++] = sym;\n else if (sym === 256) {\n lpos = pos, lm = null;\n break;\n } else {\n var add = sym - 254;\n if (sym > 264) {\n var i = sym - 257, b = fleb[i];\n add = bits(dat, pos, (1 << b) - 1) + fl[i];\n pos += b;\n }\n var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4;\n if (!d)\n throw \"invalid distance\";\n pos += d & 15;\n var dt = fd[dsym];\n if (dsym > 3) {\n var b = fdeb[dsym];\n dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\n }\n if (pos > tbts) {\n if (noSt)\n throw \"unexpected EOF\";\n break;\n }\n if (noBuf)\n cbuf(bt + 131072);\n var end = bt + add;\n for (; bt < end; bt += 4) {\n buf[bt] = buf[bt - dt];\n buf[bt + 1] = buf[bt + 1 - dt];\n buf[bt + 2] = buf[bt + 2 - dt];\n buf[bt + 3] = buf[bt + 3 - dt];\n }\n bt = end;\n }\n }\n st.l = lm, st.p = lpos, st.b = bt;\n if (lm)\n final = 1, st.m = lbt, st.d = dm, st.n = dbt;\n } while (!final);\n return bt === buf.length ? buf : slc(buf, 0, bt);\n};\nvar wbits = function (d, p, v) {\n v <<= p & 7;\n var o = p >> 3 | 0;\n d[o] |= v;\n d[o + 1] |= v >>> 8;\n};\nvar wbits16 = function (d, p, v) {\n v <<= p & 7;\n var o = p >> 3 | 0;\n d[o] |= v;\n d[o + 1] |= v >>> 8;\n d[o + 2] |= v >>> 16;\n};\nvar hTree = function (d, mb) {\n var t = [];\n for (var i = 0; i < d.length; ++i) {\n if (d[i])\n t.push({ s: i, f: d[i] });\n }\n var s = t.length;\n var t2 = t.slice();\n if (!s)\n return [et, 0];\n if (s === 1) {\n var v = new u8(t[0].s + 1);\n v[t[0].s] = 1;\n return [v, 1];\n }\n t.sort(function (a, b) {\n return a.f - b.f;\n });\n t.push({ s: -1, f: 25001 });\n var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;\n t[0] = { s: -1, f: l.f + r.f, l, r };\n while (i1 !== s - 1) {\n l = t[t[i0].f < t[i2].f ? i0++ : i2++];\n r = t[i0 !== i1 && t[i0].f < t[i2].f ? i0++ : i2++];\n t[i1++] = { s: -1, f: l.f + r.f, l, r };\n }\n var maxSym = t2[0].s;\n for (var i = 1; i < s; ++i) {\n if (t2[i].s > maxSym)\n maxSym = t2[i].s;\n }\n var tr = new u16(maxSym + 1);\n var mbt = ln(t[i1 - 1], tr, 0);\n if (mbt > mb) {\n var i = 0, dt = 0;\n var lft = mbt - mb, cst = 1 << lft;\n t2.sort(function (a, b) {\n return tr[b.s] - tr[a.s] || a.f - b.f;\n });\n for (; i < s; ++i) {\n var i2_1 = t2[i].s;\n if (tr[i2_1] > mb) {\n dt += cst - (1 << mbt - tr[i2_1]);\n tr[i2_1] = mb;\n } else\n break;\n }\n dt >>>= lft;\n while (dt > 0) {\n var i2_2 = t2[i].s;\n if (tr[i2_2] < mb)\n dt -= 1 << mb - tr[i2_2]++ - 1;\n else\n ++i;\n }\n for (; i >= 0 && dt; --i) {\n var i2_3 = t2[i].s;\n if (tr[i2_3] === mb) {\n --tr[i2_3];\n ++dt;\n }\n }\n mbt = mb;\n }\n return [new u8(tr), mbt];\n};\nvar ln = function (n, l, d) {\n return n.s === -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;\n};\nvar lc = function (c) {\n var s = c.length;\n while (s && !c[--s])\n ;\n var cl = new u16(++s);\n var cli = 0, cln = c[0], cls = 1;\n var w = function (v) {\n cl[cli++] = v;\n };\n for (var i = 1; i <= s; ++i) {\n if (c[i] === cln && i !== s)\n ++cls;\n else {\n if (!cln && cls > 2) {\n for (; cls > 138; cls -= 138)\n w(32754);\n if (cls > 2) {\n w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);\n cls = 0;\n }\n } else if (cls > 3) {\n w(cln), --cls;\n for (; cls > 6; cls -= 6)\n w(8304);\n if (cls > 2)\n w(cls - 3 << 5 | 8208), cls = 0;\n }\n while (cls--)\n w(cln);\n cls = 1;\n cln = c[i];\n }\n }\n return [cl.subarray(0, cli), s];\n};\nvar clen = function (cf, cl) {\n var l = 0;\n for (var i = 0; i < cl.length; ++i)\n l += cf[i] * cl[i];\n return l;\n};\nvar wfblk = function (out, pos, dat) {\n var s = dat.length;\n var o = shft(pos + 2);\n out[o] = s & 255;\n out[o + 1] = s >>> 8;\n out[o + 2] = out[o] ^ 255;\n out[o + 3] = out[o + 1] ^ 255;\n for (var i = 0; i < s; ++i)\n out[o + i + 4] = dat[i];\n return (o + 4 + s) * 8;\n};\nvar wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) {\n wbits(out, p++, final);\n ++lf[256];\n var _a2 = hTree(lf, 15), dlt = _a2[0], mlb = _a2[1];\n var _b2 = hTree(df, 15), ddt = _b2[0], mdb = _b2[1];\n var _c = lc(dlt), lclt = _c[0], nlc = _c[1];\n var _d = lc(ddt), lcdt = _d[0], ndc = _d[1];\n var lcfreq = new u16(19);\n for (var i = 0; i < lclt.length; ++i)\n lcfreq[lclt[i] & 31]++;\n for (var i = 0; i < lcdt.length; ++i)\n lcfreq[lcdt[i] & 31]++;\n var _e = hTree(lcfreq, 7), lct = _e[0], mlcb = _e[1];\n var nlcc = 19;\n for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)\n ;\n var flen = bl + 5 << 3;\n var ftlen = clen(lf, flt) + clen(df, fdt) + eb;\n var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + (2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]);\n if (flen <= ftlen && flen <= dtlen)\n return wfblk(out, p, dat.subarray(bs, bs + bl));\n var lm, ll, dm, dl;\n wbits(out, p, 1 + (dtlen < ftlen)), p += 2;\n if (dtlen < ftlen) {\n lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;\n var llm = hMap(lct, mlcb, 0);\n wbits(out, p, nlc - 257);\n wbits(out, p + 5, ndc - 1);\n wbits(out, p + 10, nlcc - 4);\n p += 14;\n for (var i = 0; i < nlcc; ++i)\n wbits(out, p + 3 * i, lct[clim[i]]);\n p += 3 * nlcc;\n var lcts = [lclt, lcdt];\n for (var it = 0; it < 2; ++it) {\n var clct = lcts[it];\n for (var i = 0; i < clct.length; ++i) {\n var len = clct[i] & 31;\n wbits(out, p, llm[len]), p += lct[len];\n if (len > 15)\n wbits(out, p, clct[i] >>> 5 & 127), p += clct[i] >>> 12;\n }\n }\n } else {\n lm = flm, ll = flt, dm = fdm, dl = fdt;\n }\n for (var i = 0; i < li; ++i) {\n if (syms[i] > 255) {\n var len = syms[i] >>> 18 & 31;\n wbits16(out, p, lm[len + 257]), p += ll[len + 257];\n if (len > 7)\n wbits(out, p, syms[i] >>> 23 & 31), p += fleb[len];\n var dst = syms[i] & 31;\n wbits16(out, p, dm[dst]), p += dl[dst];\n if (dst > 3)\n wbits16(out, p, syms[i] >>> 5 & 8191), p += fdeb[dst];\n } else {\n wbits16(out, p, lm[syms[i]]), p += ll[syms[i]];\n }\n }\n wbits16(out, p, lm[256]);\n return p + ll[256];\n};\nvar deo = new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);\nvar et = new u8(0);\nvar dflt = function (dat, lvl, plvl, pre, post, lst) {\n var s = dat.length;\n var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);\n var w = o.subarray(pre, o.length - post);\n var pos = 0;\n if (!lvl || s < 8) {\n for (var i = 0; i <= s; i += 65535) {\n var e = i + 65535;\n if (e < s) {\n pos = wfblk(w, pos, dat.subarray(i, e));\n } else {\n w[i] = lst;\n pos = wfblk(w, pos, dat.subarray(i, s));\n }\n }\n } else {\n var opt = deo[lvl - 1];\n var n = opt >>> 13, c = opt & 8191;\n var msk_1 = (1 << plvl) - 1;\n var prev = new u16(32768), head = new u16(msk_1 + 1);\n var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;\n var hsh = function (i2) {\n return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1;\n };\n var syms = new u32(25e3);\n var lf = new u16(288), df = new u16(32);\n var lc_1 = 0, eb = 0, i = 0, li = 0, wi = 0, bs = 0;\n for (; i < s; ++i) {\n var hv = hsh(i);\n var imod = i & 32767, pimod = head[hv];\n prev[imod] = pimod;\n head[hv] = imod;\n if (wi <= i) {\n var rem = s - i;\n if ((lc_1 > 7e3 || li > 24576) && rem > 423) {\n pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);\n li = lc_1 = eb = 0, bs = i;\n for (var j = 0; j < 286; ++j)\n lf[j] = 0;\n for (var j = 0; j < 30; ++j)\n df[j] = 0;\n }\n var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;\n if (rem > 2 && hv === hsh(i - dif)) {\n var maxn = Math.min(n, rem) - 1;\n var maxd = Math.min(32767, i);\n var ml = Math.min(258, rem);\n while (dif <= maxd && --ch_1 && imod !== pimod) {\n if (dat[i + l] === dat[i + l - dif]) {\n var nl = 0;\n for (; nl < ml && dat[i + nl] === dat[i + nl - dif]; ++nl)\n ;\n if (nl > l) {\n l = nl, d = dif;\n if (nl > maxn)\n break;\n var mmd = Math.min(dif, nl - 2);\n var md = 0;\n for (var j = 0; j < mmd; ++j) {\n var ti = i - dif + j + 32768 & 32767;\n var pti = prev[ti];\n var cd = ti - pti + 32768 & 32767;\n if (cd > md)\n md = cd, pimod = ti;\n }\n }\n }\n imod = pimod, pimod = prev[imod];\n dif += imod - pimod + 32768 & 32767;\n }\n }\n if (d) {\n syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];\n var lin = revfl[l] & 31, din = revfd[d] & 31;\n eb += fleb[lin] + fdeb[din];\n ++lf[257 + lin];\n ++df[din];\n wi = i + l;\n ++lc_1;\n } else {\n syms[li++] = dat[i];\n ++lf[dat[i]];\n }\n }\n }\n pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);\n if (!lst && pos & 7)\n pos = wfblk(w, pos + 1, et);\n }\n return slc(o, 0, pre + shft(pos) + post);\n};\nvar adler = function () {\n var a = 1, b = 0;\n return {\n p: function (d) {\n var n = a, m = b;\n var l = d.length | 0;\n for (var i = 0; i !== l;) {\n var e = Math.min(i + 2655, l);\n for (; i < e; ++i)\n m += n += d[i];\n n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16);\n }\n a = n, b = m;\n },\n d: function () {\n a %= 65521, b %= 65521;\n return (a & 255) << 24 | a >>> 8 << 16 | (b & 255) << 8 | b >>> 8;\n }\n };\n};\nvar dopt = function (dat, opt, pre, post, st) {\n return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 12 + opt.mem, pre, post, !st);\n};\nvar wbytes = function (d, b, v) {\n for (; v; ++b)\n d[b] = v, v >>>= 8;\n};\nvar zlh = function (c, o) {\n var lv = o.level, fl2 = lv === 0 ? 0 : lv < 6 ? 1 : lv === 9 ? 3 : 2;\n c[0] = 120, c[1] = fl2 << 6 | (fl2 ? 32 - 2 * fl2 : 1);\n};\nvar zlv = function (d) {\n if ((d[0] & 15) !== 8 || d[0] >>> 4 > 7 || (d[0] << 8 | d[1]) % 31)\n throw \"invalid zlib data\";\n if (d[1] & 32)\n throw \"invalid zlib data: preset dictionaries not supported\";\n};\nfunction zlibSync(data, opts) {\n if (!opts)\n opts = {};\n var a = adler();\n a.p(data);\n var d = dopt(data, opts, 2, 4);\n return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d;\n}\nfunction unzlibSync(data, out) {\n return inflt((zlv(data), data.subarray(2, -4)), out);\n}\n\n// bundle.js\nfunction compress(buf, level) {\n return zlibSync(buf, { level });\n}\n\nfunction decompress(buf, limit) {\n return unzlibSync(buf, new Uint8Array(limit));\n}\n\nmodule.exports = {\n compress,\n decompress\n};\n","const { version } = require('../../package.json');\n\nlet mod = null;\nmodule.exports = {\n\tasync init() {\n\t\tif (!mod) {\n\t\t\tconst streaming = 'compileStreaming' in WebAssembly;\n\t\t\tmod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/tiff.wasm`).then(x => streaming ? x : x.arrayBuffer()));\n\t\t};\n\n\t\treturn this.new();\n\t},\n\n\tnew() {\n\t\tconst wasm = new WebAssembly.Instance(mod).exports;\n\n\t\tclass mem {\n\t\t\tstatic length() { return wasm.wlen(); }\n\t\t\tstatic alloc(size) { return wasm.walloc(size); }\n\t\t\tstatic free(ptr, size) { return wasm.wfree(ptr, size); }\n\t\t\tstatic u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); }\n\t\t\tstatic u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); }\n\n\t\t\tstatic copy_and_free(ptr, size) {\n\t\t\t\tlet slice = mem.u8(ptr, size).slice();\n\t\t\t\treturn (wasm.wfree(ptr, size), slice);\n\t\t\t}\n\t\t}\n\n\t\tfunction decode(buffer) {\n\t\t\tconst bptr = mem.alloc(buffer.length);\n\t\t\tmem.u8(bptr, buffer.length).set(buffer);\n\t\t\tconst ptr = wasm.decode(bptr, buffer.length);\n\t\t\tif (0 === ptr) throw new Error('tiff: failed to decode');\n\n\t\t\tconst framebuffer = {\n\t\t\t\twidth: wasm.decode_width(ptr),\n\t\t\t\theight: wasm.decode_height(ptr),\n\t\t\t\tbuffer: mem.u8(wasm.decode_buffer(ptr), mem.length()).slice(),\n\t\t\t}\n\n\t\t\treturn (wasm.decode_free(ptr), framebuffer);\n\t\t}\n\n\t\treturn { decode };\n\t},\n}\n","function view(buffer, shared = false) {\n if (buffer instanceof ArrayBuffer) return new Uint8Array(buffer);\n if (typeof SharedArrayBuffer !== 'undefined' && shared && buffer instanceof SharedArrayBuffer)\n return new Uint8Array(buffer);\n if (ArrayBuffer.isView(buffer)) return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n throw new TypeError(\"The provided value is not of type '(ArrayBuffer or ArrayBufferView)'\");\n }\n\n function from_parts(buffers, shared = false) {\n let length = 0;\n let offset = 0;\n buffers.forEach(buffer => length += (null == buffer.byteLength ? buffer.length : buffer.byteLength));\n\n const u8 = new Uint8Array(shared ? new SharedArrayBuffer(length) : length);\n\n buffers.forEach(buffer => {\n const ref = Array.isArray(buffer) ? buffer : view(buffer, true);\n\n u8.set(ref, offset);\n offset += ref.length;\n });\n\n return u8;\n }\n\n module.exports = { view, from_parts };\n","const { version } = require('../../package.json');\n\nlet mod = null;\nmodule.exports = {\n async init() {\n if (!mod) {\n const streaming = 'compileStreaming' in WebAssembly;\n mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/jpeg.wasm`).then(x => streaming ? x : x.arrayBuffer()));\n };\n\n return this.new();\n },\n\n new() {\n const wasm = new WebAssembly.Instance(mod).exports;\n\n class mem {\n static length() { return wasm.wlen(); }\n static alloc(size) { return wasm.walloc(size); }\n static free(ptr, size) { return wasm.wfree(ptr, size); }\n static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); }\n static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); }\n\n static copy_and_free(ptr, size) {\n let slice = mem.u8(ptr, size).slice();\n return (wasm.wfree(ptr, size), slice);\n }\n }\n\n function encode(buffer, width, height, quality) {\n const ptr = mem.alloc(buffer.length);\n mem.u8(ptr, buffer.length).set(buffer);\n return mem.copy_and_free(wasm.encode(ptr, width, height, quality), mem.length());\n }\n\n function decode(buffer, width, height) {\n const bptr = mem.alloc(buffer.length);\n mem.u8(bptr, buffer.length).set(buffer);\n const ptr = wasm.decode(bptr, buffer.length, width, height);\n\n if (0 === ptr) throw new Error('jpg: failed to decode');\n if (1 === ptr) throw new Error('jpg: failed to scale decoder');\n\n const framebuffer = {\n width: wasm.decode_width(ptr),\n height: wasm.decode_height(ptr),\n format: wasm.decode_format(ptr),\n buffer: mem.u8(wasm.decode_buffer(ptr), mem.length()).slice(),\n }\n\n return (wasm.decode_free(ptr), framebuffer);\n }\n\n return { encode, decode };\n },\n}","const { version } = require('../../package.json');\n\nlet mod = null;\nmodule.exports = {\n async init() {\n if (!mod) {\n const streaming = 'compileStreaming' in WebAssembly;\n mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/gif.wasm`).then(x => streaming ? x : x.arrayBuffer()));\n };\n\n return this.new();\n },\n\n new() {\n const streams = new Map;\n const utf8encoder = new TextEncoder;\n\n const wasm = new WebAssembly.Instance(mod, {\n env: {\n push_to_stream(id, ptr) {\n streams.get(id).cb(mem.u8(ptr, mem.length()).slice());\n },\n },\n }).exports;\n\n class mem {\n static length() { return wasm.wlen(); }\n static alloc(size) { return wasm.walloc(size); }\n static free(ptr, size) { return wasm.wfree(ptr, size); }\n static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); }\n static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); }\n\n static copy_and_free(ptr, size) {\n let slice = mem.u8(ptr, size).slice();\n return (wasm.wfree(ptr, size), slice);\n }\n }\n\n class Encoder {\n constructor(width, height, loops = -1) {\n this.slices = [];\n streams.set(0, this);\n this.ptr = wasm.encoder_new(0, width, height, loops);\n }\n\n cb(buffer) {\n this.slices.push(buffer);\n }\n\n free() {\n this.ptr = wasm.encoder_free(this.ptr);\n streams.delete(0);\n }\n\n u8() {\n this.free();\n let offset = 0;\n const u8 = new Uint8Array(this.slices.reduce((sum, array) => sum + array.length, 0));\n\n for (const x of this.slices) {\n u8.set(x, offset);\n offset += x.length;\n }\n\n return u8;\n }\n\n add(x, y, delay, width, height, buffer, dispose, quality) {\n const ptr = mem.alloc(buffer.length);\n mem.u8(ptr, buffer.length).set(buffer);\n wasm.encoder_add(this.ptr, ptr, buffer.length, x, y, width, height, delay, dispose, quality);\n }\n\n set comment(comment) {\n const buffer = utf8encoder.encode(comment);\n\n const ptr = mem.alloc(buffer.length);\n mem.u8(ptr, buffer.length).set(buffer);\n wasm.encoder_add_comment(this.ptr, ptr, buffer.length);\n }\n\n set application(application) {\n const buffer = utf8encoder.encode(application);\n\n const ptr = mem.alloc(buffer.length);\n mem.u8(ptr, buffer.length).set(buffer);\n wasm.encoder_add_application(this.ptr, ptr, buffer.length);\n }\n }\n\n class Decoder {\n constructor(buffer, limit = 0) {\n const bptr = mem.alloc(buffer.length);\n mem.u8(bptr, buffer.length).set(buffer);\n this.ptr = wasm.decoder_new(bptr, buffer.length, limit);\n if (0 === this.ptr) throw new Error('gif: failed to parse gif header');\n\n this.width = wasm.decoder_width(this.ptr);\n this.height = wasm.decoder_height(this.ptr);\n }\n\n free() {\n this.ptr = wasm.decoder_free(this.ptr);\n }\n\n *frames() {\n let frame;\n while (frame = this.frame()) yield frame;\n }\n\n frame() {\n const ptr = wasm.decoder_frame(this.ptr);\n\n if (1 === ptr) return null;\n if (0 === ptr) throw (this.free(), new Error('gif: failed to decode frame'));\n\n const framebuffer = {\n x: wasm.decoder_frame_x(ptr),\n y: wasm.decoder_frame_y(ptr),\n delay: wasm.decoder_frame_delay(ptr),\n width: wasm.decoder_frame_width(ptr),\n height: wasm.decoder_frame_height(ptr),\n dispose: wasm.decoder_frame_dispose(ptr),\n buffer: mem.u8(wasm.decoder_frame_buffer(ptr), mem.length()).slice(),\n };\n\n return (wasm.decoder_frame_free(ptr), framebuffer);\n }\n }\n\n return { Encoder, Decoder };\n },\n}\n","const { version } = require('../../package.json');\n\nlet mod = null;\nmodule.exports = {\n async init() {\n if (!mod) {\n const streaming = 'compileStreaming' in WebAssembly;\n mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/font.wasm`).then(x => streaming ? x : x.arrayBuffer()));\n }\n\n return this.new();\n },\n\n new() {\n let registry = null;\n const wasm = new WebAssembly.Instance(mod).exports;\n\n class mem {\n static length() { return wasm.wlen(); }\n static alloc(size) { return wasm.walloc(size); }\n static free(ptr, size) { return wasm.wfree(ptr, size); }\n static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); }\n static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); }\n\n static copy_and_free(ptr, size) {\n let slice = mem.u8(ptr, size).slice();\n return (wasm.wfree(ptr, size), slice);\n }\n }\n const encode_utf8 = 'Deno' in globalThis ? Deno.core.encode : (() => {\n const encoder = new TextEncoder();\n return string => encoder.encode(string);\n })();\n\n const decode_utf8 = 'Deno' in globalThis ? Deno.core.decode : (() => {\n const decoder = new TextDecoder();\n return buffer => decoder.decode(buffer);\n })();\n\n if ('FinalizationRegistry' in globalThis) {\n registry = new FinalizationRegistry(([t, ptr]) => {\n if (t === 0) wasm.font_free(ptr);\n if (t === 1) wasm.layout_free(ptr);\n });\n }\n\n class Font {\n constructor(scale, buffer) {\n this.scale = scale;\n const ptr = mem.alloc(buffer.length);\n mem.u8(ptr, buffer.length).set(buffer);\n this.ptr = wasm.font_new(ptr, buffer.length, scale);\n\n if (!this.ptr) throw new Error('invalid font');\n if (registry) registry.register(this, [0, this.ptr], this);\n }\n\n free() {\n this.ptr = wasm.font_free(this.ptr);\n if (registry) registry.unregister(this);\n }\n\n has(char) {\n return wasm.font_has(this.ptr, String.prototype.charCodeAt.call(char, 0));\n }\n\n metrics(char, scale = this.scale) {\n const ptr = wasm.font_metrics(this.ptr, String.prototype.charCodeAt.call(char, 0), scale);\n const metrics = JSON.parse(decode_utf8(mem.u8(wasm.font_metrics_buffer(ptr), mem.length())));\n\n return (wasm.font_metrics_free(ptr), metrics);\n }\n\n rasterize(char, scale = this.scale) {\n const ptr = wasm.font_rasterize(this.ptr, String.prototype.charCodeAt.call(char, 0), scale);\n\n const glyph = {\n buffer: mem.u8(wasm.font_rasterize_buffer(ptr), mem.length()).slice(),\n metrics: JSON.parse(decode_utf8(mem.u8(wasm.font_rasterize_metrics(ptr), mem.length()))),\n }\n\n return (wasm.font_rasterize_free(ptr), glyph);\n }\n }\n\n class Layout {\n constructor() {\n this.ptr = wasm.layout_new();\n if (registry) this.refs = [];\n if (registry) registry.register(this, [1, this.ptr], this);\n }\n\n clear() {\n wasm.layout_clear(this.ptr);\n if (registry) this.refs.length = 0;\n }\n\n lines() {\n return wasm.layout_lines(this.ptr);\n }\n\n free() {\n if (registry) this.refs.length = 0;\n this.ptr = wasm.layout_free(this.ptr);\n if (registry) registry.unregister(this);\n }\n\n reset(options = {}) {\n options = encode_utf8(JSON.stringify(options));\n\n if (registry) this.refs.length = 0;\n const ptr = mem.alloc(options.length);\n mem.u8(ptr, options.length).set(options);\n wasm.layout_reset(this.ptr, ptr, options.length);\n }\n\n append(font, text, init) {\n text = encode_utf8(text);\n const options = init || {};\n if (registry) this.refs.push(font);\n const ptr = mem.alloc(text.length);\n mem.u8(ptr, text.length).set(text);\n const has_color = ('r' in options) || ('g' in options) || ('b' in options);\n wasm.layout_append(this.ptr, font.ptr, ptr, text.length, options.scale == null ? font.scale : options.scale, has_color, options.r, options.g, options.b);\n }\n\n rasterize(r, g, b) {\n const ptr = wasm.layout_rasterize(this.ptr, r, g, b);\n\n const framebuffer = {\n width: wasm.layout_rasterize_width(ptr),\n height: wasm.layout_rasterize_height(ptr),\n buffer: mem.u8(wasm.layout_rasterize_buffer(ptr), mem.length()).slice(),\n }\n\n return (wasm.layout_rasterize_free(ptr), framebuffer);\n }\n }\n\n return { Font, Layout };\n },\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(248);\n"],"names":["root","factory","exports","module","define","amd","self","table","Uint32Array","buffer","offset","crc","bl","length","png","mem","giflib","svglib","version","fontlib","jpeglib","tifflib","Image","constructor","width","height","RangeError","this","__width__","__height__","__buffer__","ArrayBuffer","__view__","DataView","__u32__","bitmap","Uint8ClampedArray","toString","Symbol","iterator","y","x","iterateWithColors","getUint32","rgbaToColor","r","g","b","a","rgbToColor","hslaToColor","h","s","l","Math","min","max","hue2rgb","p","q","t","hslToColor","rgbaToHSLA","d","colorToRGBA","color","colorToRGB","slice","getPixelAt","__check_boundaries__","getRGBAAt","idx","subarray","setPixelAt","pixelColor","__set_pixel__","setUint32","isNaN","TypeError","__out_of_bounds__","fill","clone","image","set","RESIZE_NEAREST_NEIGHBOR","RESIZE_AUTO","scale","factor","mode","__scale__","__apply__","__resize__","resize","contain","scaleFactor","fit","result","composite","cover","crop","Error","floor","__resize_nearest_neighbor__","ySrc","xSrc","destPos","srcPos","__crop__","tY","drawBox","__fast_box__","tX","nX","nY","tC","right","xPos","end","start","bottom","copyWithin","drawCircle","radius","radSquared","currentY","currentX","cropCircle","feathering","centerX","centerY","distanceFromCenter","alphaIdx","opacity","absolute","__set_channel_value__","red","saturation","green","blue","value","i","lightness","source","yy","y_offset","xx","x_offset","fg","bg","__alpha_blend__","fa","alpha","inv_alpha","invert","invertValue","invertSaturation","invertHue","hueShift","degrees","averageColor","colorAvg","divisor","rgba","map","v","dominantColor","ignoreBlack","ignoreWhite","bwThreshold","colorCounts","Array","key","maxColorCount","mostProminentValue","forEach","el","rotate","angle","__rotate_180__","rad","PI","sin","cos","abs","out","out_cx","out_cy","src_cx","src_cy","w","ysin","ycos","xf","yf","__interpolate__","reverse","src","x0","y0","x1","y1","x2","y2","xq","yq","out_slice","ref","__pawn__","point0","point1","weight","src_slice","wa","Frame","from","duration","xOffset","yOffset","disposalMode","gradient","colors","entries","Object","sort","positions","e","parseFloat","values","__gradient__","position","minDef","maxDef","gradients","minPos","undefined","maxPos","minVal","maxVal","push","roundCorners","xRad","startColor","endColor","sr","sg","sb","sa","er","eg","eb","ea","fisheye","tu32","ru32","iw","ih","xco","yco","dfc","sqrt","dis","nx","ny","cO","encode","compression","title","author","description","copyright","creationTime","software","disclaimer","warning","comment","level","channels","text","Title","Author","Description","Copyright","Date","now","toUTCString","Software","Disclaimer","Warning","Source","Comment","encodeJPEG","quality","init","decode","data","view","byteOffset","byteLength","ImageType","isPNG","pixels","isJPEG","framebuffer","pixelType","format","pixel","isTIFF","SVG_MODE_SCALE","SVG_MODE_WIDTH","SVG_MODE_HEIGHT","renderSVG","svg","size","includes","TextEncoder","rasterize","renderText","font","layout","TextLayout","Font","Layout","layoutOptions","reset","max_width","maxWidth","max_height","maxHeight","wrap_style","wrapStyle","vertical_align","verticalAlign","horizontal_align","horizontalAlign","wrap_hard_breaks","wrapHardBreaks","append","lines","free","DISPOSAL_KEEP","DISPOSAL_PREVIOUS","DISPOSAL_BACKGROUND","__convert_disposal_mode__","indexOf","super","__disposalMode__","frame","originalWidth","originalHeight","GIF","frames","loopCount","Infinity","reduce","acc","encoder","Encoder","add","u8","onlyExtractFirstFrame","isGIF","decoder","Decoder","first","next","delay","dispose","gwidth","gheight","u32","Uint8Array","offset8","offset32","fx","fy","f8","f32","t8","t32","options","getType","isView","crc32","compress","decompress","__IHDR__","__IDAT__","__IEND__","__IEND_CRC__","HEAD","channels_to_color_type","utf8encoder","depth","tmp_offset","row_length","tmp","chunks","kb","tb","chunk","from_parts","compressed","array","bit_depth","color_type","bytespp","p_offset","c_offset","palette","alphaPalette","maxSearchOffset","type","pxlOffset","filter","filter_1","filter_2","filter_3","filter_4","newPixels","pixelView","c","pa","pb","pc","mod","streaming","WebAssembly","fetch","then","arrayBuffer","new","wasm","Instance","wlen","alloc","walloc","ptr","wfree","memory","copy_and_free","bptr","rasterize_width","rasterize_height","rasterize_buffer","rasterize_free","u16","Uint16Array","fleb","fdeb","clim","freb","j","_a","fl","revfl","_b","fd","revfd","rev","hMap","cd","mb","co","le","rvb","sv","r_1","m","flt","fdt","flm","flrm","fdm","fdrm","bits","o","bits16","shft","slc","n","wbits","wbits16","hTree","f","t2","et","i0","i1","i2","maxSym","tr","mbt","ln","dt","lft","cst","i2_1","i2_2","i2_3","lc","cl","cli","cln","cls","clen","cf","wfblk","pos","dat","wblk","final","syms","lf","df","li","bs","_a2","dlt","mlb","_b2","ddt","mdb","_c","lclt","nlc","_d","lcdt","ndc","lcfreq","_e","lct","mlcb","nlcc","lm","ll","dm","dl","flen","ftlen","dtlen","llm","lcts","it","clct","len","dst","deo","zlibSync","opts","adler","lv","fl2","opt","pre","post","st","lvl","plvl","lst","ceil","msk_1","prev","head","bs1_1","bs2_1","hsh","lc_1","wi","hv","imod","pimod","rem","ch_1","dif","maxn","maxd","ml","nl","mmd","md","ti","lin","din","dflt","log","wbytes","buf","limit","sl","noBuf","noSt","cbuf","l2","nbuf","bt","lbt","dbt","tbts","hLit","hcLen","tl","ldt","clt","clb","clbmsk","clm","lt","lms","dms","lpos","sym","dsym","inflt","zlv","decode_width","decode_height","decode_buffer","decode_free","shared","SharedArrayBuffer","buffers","isArray","decode_format","streams","Map","env","push_to_stream","id","get","cb","loops","slices","encoder_new","encoder_free","delete","sum","encoder_add","encoder_add_comment","application","encoder_add_application","decoder_new","decoder_width","decoder_height","decoder_free","decoder_frame","decoder_frame_x","decoder_frame_y","decoder_frame_delay","decoder_frame_width","decoder_frame_height","decoder_frame_dispose","decoder_frame_buffer","decoder_frame_free","registry","encode_utf8","globalThis","Deno","core","string","decode_utf8","TextDecoder","FinalizationRegistry","font_free","layout_free","font_new","register","unregister","has","char","font_has","String","prototype","charCodeAt","call","metrics","font_metrics","JSON","parse","font_metrics_buffer","font_metrics_free","font_rasterize","glyph","font_rasterize_buffer","font_rasterize_metrics","font_rasterize_free","layout_new","refs","clear","layout_clear","layout_lines","stringify","layout_reset","has_color","layout_append","layout_rasterize","layout_rasterize_width","layout_rasterize_height","layout_rasterize_buffer","layout_rasterize_free","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__"],"sourceRoot":""} \ No newline at end of file diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..cd780c2 --- /dev/null +++ b/example/index.html @@ -0,0 +1,26 @@ + + + ImageScript Example + + +

ImageScript example

+

Simple example showing integration of ImageScript into an application (load image, modify, encode, convert to blob, + display)

+

You can find more examples on GitHub

+ImageScript Example Result + + + + diff --git a/package.json b/package.json index 67fbdb8..086d1f9 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "imagescript", - "version": "1.1.14", + "version": "1.2.16", "description": "zero-dependency javascript image manipulation", "main": "ImageScript.js", + "types": "ImageScript.d.ts", + "type": "commonjs", "scripts": { - "test": "node ./tests/run.js", - "coverage": "nyc --reporter=html npm test" + "build": "webpack" }, "repository": { "type": "git", @@ -14,15 +15,27 @@ "keywords": [ "image", "image processing", - "image manipulation" + "image manipulation", + "png", + "jpeg", + "jpg", + "scale", + "resize", + "crop", + "webp", + "svg", + "bitmap", + "gif", + "picture", + "thumbnail" ], - "author": "matmen ", - "license": "GPL-3.0-or-later", + "author": "Mathis Mensing ", + "license": "(AGPL-3.0-or-later OR MIT)", "bugs": { "url": "https://github.com/matmen/ImageScript/issues" }, "homepage": "https://github.com/matmen/ImageScript#readme", "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } } diff --git a/tests/averageColor.js b/tests/averageColor.js deleted file mode 100644 index 6d34582..0000000 --- a/tests/averageColor.js +++ /dev/null @@ -1,8 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); -(async () => { - const binary = await fs.readFile('./tests/targets/readme.png'); - const image = await Image.decode(binary); - const avgColor = image.averageColor(); - if (avgColor !== 0x343c3dff) process.exit(1); -})(); \ No newline at end of file diff --git a/tests/circle.js b/tests/circle.js deleted file mode 100644 index bfd46ca..0000000 --- a/tests/circle.js +++ /dev/null @@ -1,46 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -(async () => { - { - const image = new Image(512, 512); - image.drawCircle(256, 256, 128, 0xffffffff); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/circle.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(512, 512); - image.drawCircle(256, 256, 320, 0x000000ff); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/circle2.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(256, 512); - image.fill(0x000000ff); - image.cropCircle(); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/circle3.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(256, 512); - image.fill(0x000000ff); - image.cropCircle(true, .5); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/circle4.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } -})(); \ No newline at end of file diff --git a/tests/crop.js b/tests/crop.js deleted file mode 100644 index a403668..0000000 --- a/tests/crop.js +++ /dev/null @@ -1,13 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -(async () => { - const image = new Image(512, 512); - image.fill((x, y) => Image.hslToColor((x + y) / (image.width + image.height), 1, .5)); - image.crop(128, 128, 128, 128); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/crop.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); -})(); \ No newline at end of file diff --git a/tests/decode.js b/tests/decode.js deleted file mode 100644 index a20070f..0000000 --- a/tests/decode.js +++ /dev/null @@ -1,29 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); -const ImageTest = require('./image'); - -const panic = message => { - console.error(message); - process.exit(1); -}; - -(async () => { - { - const binary = await fs.readFile('./tests/targets/image.png'); - const image = await Image.decode(binary); - - const target = await ImageTest; - if (!Buffer.from(target.bitmap).equals(Buffer.from(image.bitmap))) process.exit(1); - } - - { - const binary = await fs.readFile('./tests/targets/external.png'); - const image = await Image.decode(binary); - - if ([image.width, image.height].some(v => v !== 638)) - panic('dimensions don\'t match'); - - if (!Buffer.from(image.bitmap.subarray(0, 4)).equals(Buffer.from([70, 65, 62, 255]))) - panic('pixel doesn\'t match'); - } -})(); \ No newline at end of file diff --git a/tests/fill.js b/tests/fill.js deleted file mode 100644 index 57220b1..0000000 --- a/tests/fill.js +++ /dev/null @@ -1,29 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -const panic = message => { - console.error(message); - process.exit(1); -}; - -(async () => { - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/fill-static.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) panic('fill static doesn\'t equal'); - } - - { - const image = new Image(512, 512); - image.fill((x, y) => Image.hslToColor((x + y) / (image.width + image.height), 1, .5)); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/fill-func.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) panic('fill func doesn\'t equal'); - } -})(); \ No newline at end of file diff --git a/tests/font.js b/tests/font.js deleted file mode 100644 index 4151c3d..0000000 --- a/tests/font.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - Fonts sourced from: - https://www.1001fonts.com/carbon-font.html - https://www.1001fonts.com/ethnocentric-font.html - */ - -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -const panic = message => { - console.error(message); - process.exit(1); -}; - -(async () => { - { - const font = await Image.renderText(await fs.readFile('./tests/fonts/carbon phyber.ttf'), 128, 'ThE qUiCk'); - const encoded = await font.encode(); - - const desired = await fs.readFile('./tests/targets/font-1.png'); - if (!desired.equals(Buffer.from(encoded))) panic('font 1 doesn\'t match'); - } - - { - const font = await Image.renderText(await fs.readFile('./tests/fonts/ethnocentric rg.ttf'), 128, 'BrOwN fOx'); - const encoded = await font.encode(); - - const desired = await fs.readFile('./tests/targets/font-2.png'); - if (!desired.equals(Buffer.from(encoded))) panic('font 2 doesn\'t match'); - } -})(); \ No newline at end of file diff --git a/tests/fonts/carbon phyber.ttf b/tests/fonts/carbon phyber.ttf deleted file mode 100644 index 9111530..0000000 Binary files a/tests/fonts/carbon phyber.ttf and /dev/null differ diff --git a/tests/fonts/ethnocentric rg.ttf b/tests/fonts/ethnocentric rg.ttf deleted file mode 100644 index f041b9a..0000000 Binary files a/tests/fonts/ethnocentric rg.ttf and /dev/null differ diff --git a/tests/gif.js b/tests/gif.js deleted file mode 100644 index bbe9d40..0000000 --- a/tests/gif.js +++ /dev/null @@ -1,17 +0,0 @@ -const fs = require('fs').promises; -const {Frame, GIF} = require('../ImageScript'); - -(async () => { - const frames = []; - for (let i = 0; i < 30; i++) { - const frame = new Frame(256, 256); - frame.fill(x => Frame.hslToColor(x / frame.width + i / 30, 1, 0.5)); - frames.push(frame); - } - - const gif = new GIF(frames); - - const encoded = await gif.encode(); - const desired = await fs.readFile('./tests/targets/gif.gif'); - process.exit(desired.equals(encoded) ? 0 : 1); -})(); \ No newline at end of file diff --git a/tests/image.js b/tests/image.js deleted file mode 100644 index 773a9cf..0000000 --- a/tests/image.js +++ /dev/null @@ -1,13 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -module.exports = (async () => { - const image = new Image(128, 128); - image.fill(x => Image.hslToColor(x / image.width, 1, 0.5)); - - const encoded = await image.encode(); - const desired = await fs.readFile('./tests/targets/image.png'); - if (process.argv[1].slice(-8) === 'image.js') process.exit(desired.equals(encoded) ? 0 : 1); - - return image; -})(); \ No newline at end of file diff --git a/tests/invert.js b/tests/invert.js deleted file mode 100644 index 9442cdd..0000000 --- a/tests/invert.js +++ /dev/null @@ -1,59 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -(async () => { - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - image.invert(); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/invert.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - image.invertValue(); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/invert-value.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - image.invertSaturation(); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/invert-saturation.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - image.invertHue(); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/invert-hue.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } - - { - const image = new Image(512, 512); - image.fill(0xff8000ff); - image.hueShift(180); - - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/invert-hueshift.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); - } -})(); \ No newline at end of file diff --git a/tests/jpeg.js b/tests/jpeg.js deleted file mode 100644 index 882823e..0000000 --- a/tests/jpeg.js +++ /dev/null @@ -1,19 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); - -const panic = message => { - console.error(message); - process.exit(1); -}; - -(async () => { - const binary = await fs.readFile('./tests/targets/external.jpg'); - const image = await Image.decode(binary); - - if ([image.width, image.height].some(v => v !== 638)) - panic('dimensions don\'t match'); - if (!Buffer.from(image.bitmap.slice(0, 4)).equals(Buffer.from([70, 65, 61, 255]))) - panic('pixel doesn\'t match'); - - await image.encodeJPEG(100); -})(); \ No newline at end of file diff --git a/tests/misc.js b/tests/misc.js deleted file mode 100644 index 591ad95..0000000 --- a/tests/misc.js +++ /dev/null @@ -1,210 +0,0 @@ -const {Image, Frame, GIF} = require('../ImageScript'); -const panic = msg => { - console.error(msg); - process.exit(1); -} - -try { - new Image(0, 1); - panic('width 0 failed'); -} catch { -} - -try { - new Image(1, 0); - panic('height 0 failed'); -} catch { -} - -if (new Image(1, 1).toString() !== 'Image<1x1>') - panic('toString failed'); - -for (const [x, y] of new Image(1, 1)) - if (x !== 1 || y !== 1) panic('Symbol.iterator failed'); - -for (const [x, y, color] of new Image(1, 1).fill(0xff8000ff).iterateWithColors()) - if (x !== 1 || y !== 1 || color !== 0xff8000ff) panic('iterateWithColors failed'); - -if (Image.rgbToColor(0xff, 0x80, 0x00) !== 0xff8000ff) - panic('rgbToColor failed'); - -if (Image.hslaToColor(0, 0, 1, 0xff) !== 0xffffffff) - panic('hslaToColor for s=0 failed'); - -{ - for (const rgba of [0xff0000ff, 0x00ff00ff, 0x0000ffff, 0x000000ff, 0xffffffff].map(x => Image.colorToRGBA(x))) { - const hsla = Image.rgbaToHSLA(...rgba); - const rgbaBacktransform = Image.colorToRGBA(Image.hslaToColor(...hsla)); - for (let i = 0; i < 4; i++) - if (rgba[i] !== rgbaBacktransform[i]) - panic('rgbaToHSLA failed'); - } -} - -{ - const rgb = Image.colorToRGB(0xff8000ff); - const target = [0xff, 0x80, 0x00]; - for (let i = 0; i < 3; i++) - if (rgb[i] !== target[i]) - panic('colorToRGB failed'); -} - -{ - const image = new Image(1, 1); - image.setPixelAt(1, 1, 0xff8000ff); - - const pixel = image.getPixelAt(1, 1); - if (pixel !== 0xff8000ff) panic('getPixelAt fails'); - - const rgba = image.getRGBAAt(1, 1); - const target = [0xff, 0x80, 0x00, 0xff]; - for (let i = 0; i < 4; i++) - if (rgba[i] !== target[i]) - panic('colorToRGB failed'); -} - -{ - const image = new Image(1, 1); - try { - image.__check_boundaries__('a', 1); - panic('check boundaries for x as NaN failed'); - } catch { - } - try { - image.__check_boundaries__(1, 'a'); - panic('check boundaries for y as NaN failed'); - } catch { - } - try { - image.__check_boundaries__(0, 1); - panic('check boundaries for x as 0 failed'); - } catch { - } - try { - image.__check_boundaries__(1, 0); - panic('check boundaries for y as 0 failed'); - } catch { - } - try { - image.__check_boundaries__(2, 1); - panic('check boundaries for x as 2 failed'); - } catch { - } - try { - image.__check_boundaries__(1, 2); - panic('check boundaries for y as 2 failed'); - } catch { - } -} - -{ - const image = new Image(1, 1); - image.fill(0xff8000ff); - - const clone = image.clone(); - - if (!Buffer.from(clone.bitmap).equals(Buffer.from(image.bitmap))) - panic('clone failed'); -} - -{ - const image = new Image(2, 2); - image.scale(.5); - if (image.width !== 1 || image.height !== 1) - panic('resize failed'); - - image.scale(1); - if (image.width !== 1 || image.height !== 1) - panic('resize failed'); - - try { - image.resize(0, 1); - panic('resize for x = 0 failed'); - } catch { - } - try { - image.resize(1, 0); - panic('resize for y = 0 failed'); - } catch { - } - try { - image.resize(1, 1, 'garbage'); - panic('resize with invalid mode failed'); - } catch { - } - try { - image.resize(Image.RESIZE_AUTO, Image.RESIZE_AUTO); - panic('resize with RESIZE_AUTO for both x and y failed'); - } catch { - } -} - -{ - const image = new Image(1, 1); - image.drawBox(1, 1, 1, 1, 0xff8000ff); - if (image.getPixelAt(1, 1) !== 0xff8000ff) - panic('static drawBox failed'); - - image.drawBox(1, 1, 1, 1, () => 0x00ff00ff); - if (image.getPixelAt(1, 1) !== 0x00ff00ff) - panic('fn drawBox failed'); -} - -{ - const image = new Image(1, 1); - const toFail = ['a', -1]; - const funcs = [image.red, image.green, image.blue, image.opacity, image.lightness, image.saturation]; - for (const func of funcs) - for (const value of toFail) - try { - func.call(image, toFail); - panic(`${func.name} failed with value ${JSON.stringify(value)}`); - } catch { - } - - const toPass = [[1, true], [1, false], [0, true], [0, false]]; - for (const func of funcs) - for (const value of toPass) - func.call(image, ...value); -} - -{ - const image = new Image(512, 256); - const overlay = new Image(1024, 512); - image.composite(overlay, -512, -256); - overlay.fill(0x80); - image.composite(overlay, -512, -256); - overlay.fill(0xff); - image.composite(overlay, -512, -256); -} - -try { - new Frame(1, 1, -1); - panic('frame duration failed'); -} catch { -} - -if (new Frame(1, 2, 3).toString() !== 'Frame<1x2x3ms>') panic('frame toString failed'); - -{ - const image = new Image(512, 512); - Frame.from(image, 10); - try { - Frame.from({}, 10); - panic('frame instanceof image failed'); - } catch { - } -} - -try { - new GIF([{}]); - panic('gif frame instanceof failed'); -} catch { -} - -{ - const frame = new Frame(512, 128, 123); - const gif = new GIF([frame]); - if (gif.toString() !== 'GIF<512x128x123ms>') panic('gif tostring failed'); - if (gif.duration !== 123) panic('gif duration failed'); -} \ No newline at end of file diff --git a/tests/readme.js b/tests/readme.js deleted file mode 100644 index 5ad7df1..0000000 --- a/tests/readme.js +++ /dev/null @@ -1,108 +0,0 @@ -const {Image} = require('..'); -const fs = require('fs').promises; - -(async () => { - const [backgroundSVG, avatarBinary, badges, font] = await Promise.all([ - fs.readFile('./tests/svgs/background.svg').then(b => b.toString()), - fs.readFile('./tests/targets/external.png'), - Promise.all( - [ - 'crown', 'potato', 'mask', 'microbe', 'petri_dish', 'thermometer', 'cigarette' - ].map( - x => fs.readFile(`./tests/svgs/${x}.svg`) - .then(b => b.toString())) - ), - fs.readFile('./tests/fonts/carbon phyber.ttf') - ]); - - const image = new Image(1000, 700); - - const backgroundPattern = await Image.renderSVG(backgroundSVG); - for (let xOffset = 0; xOffset < image.width; xOffset += backgroundPattern.width) { - for (let yOffset = 0; yOffset < image.height; yOffset += backgroundPattern.height) { - image.composite(backgroundPattern, xOffset, yOffset); - } - } - - const avatarBG = new Image(200 + 16, 200 + 16); - const avatarGradient = Image.gradient({0: 0x00ffffff, 1: 0x0080ffff}); - avatarBG.fill((x, y) => avatarGradient((x + y) / (avatarBG.width + avatarBG.height))); - image.composite(avatarBG.cropCircle(), 0.05 * image.width, 0.05 * image.height); - - const avatar = await Image.decode(avatarBinary); - image.composite(avatar.resize(200, 200).cropCircle(), 0.05 * image.width + 8, 0.05 * image.height + 8); - - const username = await Image.renderText(font, 64, 'matmen', 0xffffffff); - image.composite(username, 0.3 * image.width, 0.05 * image.height); - - image.drawBox(0.3 * image.width, 0.05 * image.height + username.height, username.width, 3, 0x808080ff); - - const discriminator = await Image.renderText(font, 48, '#9984', 0xd0d0d0ff); - image.composite(discriminator, 0.3 * image.width, 0.05 * image.height + username.height); - - // Global XP - { - const xpBarBackground = new Image(0.9 * image.width, 0.05 * image.height); - xpBarBackground.fill(0xa0a0a0ff); - image.composite(xpBarBackground.roundCorners(16), 0.05 * image.width, 0.5 * image.height); - - const xpBar = new Image(69 / 420 * xpBarBackground.width, 0.05 * image.height); - const xpGradient = Image.gradient({0: 0x0080ffff, .8: 0x00ffffff, 1: 0x00ff80ff}); - xpBar.fill(x => xpGradient(x / xpBarBackground.width)); - image.composite(xpBar.roundCorners(16), 0.05 * image.width, 0.5 * image.height); - - const xpText = await Image.renderText(font, 32, '69/420', 0xff); - image.composite(xpText, 0.05 * image.width + xpBarBackground.width / 2 - xpText.width / 2, 0.5 * image.height + xpBarBackground.height / 2 - xpText.height / 2); - - const levelText = await Image.renderText(font, 32, 'Level 3', 0xffffffff); - image.composite(levelText, 0.05 * image.width + xpBarBackground.width - levelText.width, 0.5 * image.height - levelText.height); - - const xpKindText = await Image.renderText(font, 32, 'Global XP', 0xffffffff); - image.composite(xpKindText, 0.05 * image.width, 0.5 * image.height - levelText.height); - } - - // Server XP - { - const xpBarBackground = new Image(0.9 * image.width, 0.05 * image.height); - xpBarBackground.fill(0xa0a0a0ff); - image.composite(xpBarBackground.roundCorners(16), 0.05 * image.width, 0.65 * image.height); - - const xpBar = new Image(75 / 100 * xpBarBackground.width, 0.05 * image.height); - const xpGradient = Image.gradient({0: 0x0080ffff, .8: 0x00ffffff, 1: 0x00ff80ff}); - xpBar.fill(x => xpGradient(x / xpBarBackground.width)); - image.composite(xpBar.roundCorners(16), 0.05 * image.width, 0.65 * image.height); - - const xpText = await Image.renderText(font, 32, '75/100', 0xff); - image.composite(xpText, 0.05 * image.width + xpBarBackground.width / 2 - xpText.width / 2, 0.65 * image.height + xpBarBackground.height / 2 - xpText.height / 2); - - const levelText = await Image.renderText(font, 32, 'Level 1', 0xffffffff); - image.composite(levelText, 0.05 * image.width + xpBarBackground.width - levelText.width, 0.65 * image.height - levelText.height); - - const xpKindText = await Image.renderText(font, 32, 'Server XP', 0xffffffff); - image.composite(xpKindText, 0.05 * image.width, 0.65 * image.height - levelText.height); - } - - const badgeBackground = new Image(...Array(2).fill(Math.sqrt(64 ** 2 * 2))); - badgeBackground.fill(0xa0a0a080); - badgeBackground.cropCircle(); - for (let i = 0; i < badges.length; i++) { - image.composite(badgeBackground, 0.05 * image.width + 0.9 * image.width / badges.length * i, 0.8 * image.height); - - const badge = await Image.renderSVG(badges[i], 64, Image.SVG_MODE_WIDTH); - if (i >= 3) - badge.saturation(0); - - image.composite( - badge, - 0.05 * image.width + 0.9 * image.width / badges.length * i + (badgeBackground.width - badge.width) / 2, - 0.8 * image.height + (badgeBackground.height - badge.height) / 2 - ); - } - - image.roundCorners(32); - - const encoded = await image.encode(); - - if (!(await fs.readFile('./tests/targets/readme.png')).equals(Buffer.from(encoded))) - process.exit(1); -})(); \ No newline at end of file diff --git a/tests/resize.js b/tests/resize.js deleted file mode 100644 index f477d3e..0000000 --- a/tests/resize.js +++ /dev/null @@ -1,11 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); -(async () => { - const binary = await fs.readFile('./tests/targets/image.png'); - const image = await Image.decode(binary); - image.resize(image.width / 4, Image.RESIZE_AUTO); - - const encoded = await image.encode(); - const target = await fs.readFile('./tests/targets/resize.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); -})(); \ No newline at end of file diff --git a/tests/rotate.js b/tests/rotate.js deleted file mode 100644 index a8742c0..0000000 --- a/tests/rotate.js +++ /dev/null @@ -1,51 +0,0 @@ -const fs = require('fs').promises; -const {Image} = require('../ImageScript'); -const panic = msg => { - console.error(msg); - process.exit(1); -} - -(async () => { - { - const binary = await fs.readFile('./tests/targets/image.png'); - const image = await Image.decode(binary); - image.rotate(45); - - const encoded = await image.encode(); - - await fs.writeFile('./tests/targets/rotate-45.png', encoded); - const target = await fs.readFile('./tests/targets/rotate-45.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) panic('rotate 45 failed'); - } - - { - const binary = await fs.readFile('./tests/targets/image.png'); - const image = await Image.decode(binary); - image.rotate(45, false); - - const encoded = await image.encode(); - - await fs.writeFile('./tests/targets/rotate-45-noresize.png', encoded); - const target = await fs.readFile('./tests/targets/rotate-45-noresize.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) panic('rotate 45 noresize failed'); - } - - { - const binary = await fs.readFile('./tests/targets/image.png'); - const image = await Image.decode(binary); - image.rotate(180); - - const encoded = await image.encode(); - - await fs.writeFile('./tests/targets/rotate-180.png', encoded); - const target = await fs.readFile('./tests/targets/rotate-180.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) panic('rotate 180 failed'); - } - - { - const image = new Image(512, 512); - image.fill((x) => Image.hslToColor(x / image.width, 1, .5)); - if (!Buffer.from(image.bitmap).equals(Buffer.from(image.rotate(360).bitmap))) - panic('rotate 360 failed'); - } -})(); \ No newline at end of file diff --git a/tests/run.js b/tests/run.js deleted file mode 100644 index 20fb3fa..0000000 --- a/tests/run.js +++ /dev/null @@ -1,37 +0,0 @@ -const fs = require('fs'); -const child_process = require('child_process'); - -(async () => { - for (const file of fs.readdirSync('./tests/')) { - if (file === 'run.js' || file.slice(-3) !== '.js') continue; - - console.log(`running test ${file}`); - const start = Date.now(); - const proc = child_process.exec(`node --unhandled-rejections=strict ./tests/${file}`); - proc.stderr.pipe(process.stderr); - proc.stdout.pipe(process.stdout); - await new Promise(resolve => { - const timeout = setTimeout(() => { - if (proc.connected) { - console.log('script timeout'); - proc.exitCode = 1; - proc.kill('SIGTERM'); - } - }, 1000); - - proc.on('exit', code => { - clearTimeout(timeout); - - if (code) { - console.error(`test ${file} failed in ${Date.now() - start}ms`); - process.exit(1); - } else { - console.log(`test ${file} passed in ${Date.now() - start}ms`); - resolve(); - } - }); - }); - } - - console.log('all tests passed'); -})(); \ No newline at end of file diff --git a/tests/svg.js b/tests/svg.js deleted file mode 100644 index 3cba8ee..0000000 --- a/tests/svg.js +++ /dev/null @@ -1,11 +0,0 @@ -const {Image} = require('../ImageScript'); -const fs = require('fs').promises; - -(async () => { - const svg = await fs.readFile('./tests/svgs/potato.svg'); - const image = await Image.renderSVG(svg.toString(), 256 / 36, Image.SVG_MODE_SCALE); - const encoded = await image.encode(); - - const target = await fs.readFile('./tests/targets/potato.png'); - if (!Buffer.from(target).equals(Buffer.from(encoded))) process.exit(1); -})(); \ No newline at end of file diff --git a/tests/svgs/background.svg b/tests/svgs/background.svg deleted file mode 100644 index d18d80b..0000000 --- a/tests/svgs/background.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/tests/svgs/cigarette.svg b/tests/svgs/cigarette.svg deleted file mode 100644 index db79111..0000000 --- a/tests/svgs/cigarette.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/tests/svgs/crown.svg b/tests/svgs/crown.svg deleted file mode 100644 index edf81f7..0000000 --- a/tests/svgs/crown.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/svgs/mask.svg b/tests/svgs/mask.svg deleted file mode 100644 index d759c04..0000000 --- a/tests/svgs/mask.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/tests/svgs/microbe.svg b/tests/svgs/microbe.svg deleted file mode 100644 index af20b0d..0000000 --- a/tests/svgs/microbe.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/svgs/petri_dish.svg b/tests/svgs/petri_dish.svg deleted file mode 100644 index fbfaa2c..0000000 --- a/tests/svgs/petri_dish.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/svgs/potato.svg b/tests/svgs/potato.svg deleted file mode 100644 index a046ed8..0000000 --- a/tests/svgs/potato.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/tests/svgs/thermometer.svg b/tests/svgs/thermometer.svg deleted file mode 100644 index 9cbcbf3..0000000 --- a/tests/svgs/thermometer.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/tests/targets/circle.png b/tests/targets/circle.png deleted file mode 100644 index eeeba93..0000000 Binary files a/tests/targets/circle.png and /dev/null differ diff --git a/tests/targets/circle2.png b/tests/targets/circle2.png deleted file mode 100644 index 93d3b1e..0000000 Binary files a/tests/targets/circle2.png and /dev/null differ diff --git a/tests/targets/circle3.png b/tests/targets/circle3.png deleted file mode 100644 index a137b4b..0000000 Binary files a/tests/targets/circle3.png and /dev/null differ diff --git a/tests/targets/circle4.png b/tests/targets/circle4.png deleted file mode 100644 index d1ea6b4..0000000 Binary files a/tests/targets/circle4.png and /dev/null differ diff --git a/tests/targets/crop.png b/tests/targets/crop.png deleted file mode 100644 index 9b38bfc..0000000 Binary files a/tests/targets/crop.png and /dev/null differ diff --git a/tests/targets/external.jpg b/tests/targets/external.jpg deleted file mode 100644 index dc35590..0000000 Binary files a/tests/targets/external.jpg and /dev/null differ diff --git a/tests/targets/external.png b/tests/targets/external.png deleted file mode 100644 index d27eba0..0000000 Binary files a/tests/targets/external.png and /dev/null differ diff --git a/tests/targets/fill-func.png b/tests/targets/fill-func.png deleted file mode 100644 index 236d825..0000000 Binary files a/tests/targets/fill-func.png and /dev/null differ diff --git a/tests/targets/fill-static.png b/tests/targets/fill-static.png deleted file mode 100644 index d4d53d4..0000000 Binary files a/tests/targets/fill-static.png and /dev/null differ diff --git a/tests/targets/font-1.png b/tests/targets/font-1.png deleted file mode 100644 index b375fcb..0000000 Binary files a/tests/targets/font-1.png and /dev/null differ diff --git a/tests/targets/font-2.png b/tests/targets/font-2.png deleted file mode 100644 index d63925a..0000000 Binary files a/tests/targets/font-2.png and /dev/null differ diff --git a/tests/targets/gif.gif b/tests/targets/gif.gif deleted file mode 100644 index a86713c..0000000 Binary files a/tests/targets/gif.gif and /dev/null differ diff --git a/tests/targets/image.png b/tests/targets/image.png deleted file mode 100644 index 1b5ffae..0000000 Binary files a/tests/targets/image.png and /dev/null differ diff --git a/tests/targets/invert-hue.png b/tests/targets/invert-hue.png deleted file mode 100644 index 6092478..0000000 Binary files a/tests/targets/invert-hue.png and /dev/null differ diff --git a/tests/targets/invert-hueshift.png b/tests/targets/invert-hueshift.png deleted file mode 100644 index 3e97362..0000000 Binary files a/tests/targets/invert-hueshift.png and /dev/null differ diff --git a/tests/targets/invert-saturation.png b/tests/targets/invert-saturation.png deleted file mode 100644 index b11dfe2..0000000 Binary files a/tests/targets/invert-saturation.png and /dev/null differ diff --git a/tests/targets/invert-value.png b/tests/targets/invert-value.png deleted file mode 100644 index d4d53d4..0000000 Binary files a/tests/targets/invert-value.png and /dev/null differ diff --git a/tests/targets/invert.png b/tests/targets/invert.png deleted file mode 100644 index d4b247e..0000000 Binary files a/tests/targets/invert.png and /dev/null differ diff --git a/tests/targets/issues.png b/tests/targets/issues.png deleted file mode 100644 index edea0ef..0000000 Binary files a/tests/targets/issues.png and /dev/null differ diff --git a/tests/targets/potato.png b/tests/targets/potato.png deleted file mode 100644 index 985b077..0000000 Binary files a/tests/targets/potato.png and /dev/null differ diff --git a/tests/targets/readme.png b/tests/targets/readme.png deleted file mode 100644 index 2261a2d..0000000 Binary files a/tests/targets/readme.png and /dev/null differ diff --git a/tests/targets/resize.png b/tests/targets/resize.png deleted file mode 100644 index 5138335..0000000 Binary files a/tests/targets/resize.png and /dev/null differ diff --git a/tests/targets/rotate-180.png b/tests/targets/rotate-180.png deleted file mode 100644 index 7cd167d..0000000 Binary files a/tests/targets/rotate-180.png and /dev/null differ diff --git a/tests/targets/rotate-45-noresize.png b/tests/targets/rotate-45-noresize.png deleted file mode 100644 index aa00020..0000000 Binary files a/tests/targets/rotate-45-noresize.png and /dev/null differ diff --git a/tests/targets/rotate-45.png b/tests/targets/rotate-45.png deleted file mode 100644 index 9fd95f5..0000000 Binary files a/tests/targets/rotate-45.png and /dev/null differ diff --git a/tests/targets/twemoji.png b/tests/targets/twemoji.png deleted file mode 100644 index 56f5b6a..0000000 Binary files a/tests/targets/twemoji.png and /dev/null differ diff --git a/utils/buffer.js b/utils/buffer.js index 04c0318..14c1cdf 100644 --- a/utils/buffer.js +++ b/utils/buffer.js @@ -1,15 +1,27 @@ -module.exports = class Buffer { - static concat(...arrays) { - const array = new Uint8Array( - arrays.reduce((length, array) => length + array.length, 0) - ); - - let offset = 0; - for (const x of arrays) { - array.set(x, offset); - offset += x.length; - } - - return array; - } -}; \ No newline at end of file +function view(buffer, shared = false) { + if (buffer instanceof ArrayBuffer) return new Uint8Array(buffer); + if (typeof SharedArrayBuffer !== 'undefined' && shared && buffer instanceof SharedArrayBuffer) + return new Uint8Array(buffer); + if (ArrayBuffer.isView(buffer)) return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); + + throw new TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'"); + } + + function from_parts(buffers, shared = false) { + let length = 0; + let offset = 0; + buffers.forEach(buffer => length += (null == buffer.byteLength ? buffer.length : buffer.byteLength)); + + const u8 = new Uint8Array(shared ? new SharedArrayBuffer(length) : length); + + buffers.forEach(buffer => { + const ref = Array.isArray(buffer) ? buffer : view(buffer, true); + + u8.set(ref, offset); + offset += ref.length; + }); + + return u8; + } + + module.exports = { view, from_parts }; diff --git a/utils/crc32.js b/utils/crc32.js index c1da781..5221bd1 100644 --- a/utils/crc32.js +++ b/utils/crc32.js @@ -1,62 +1,49 @@ const table = new Uint32Array([ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, - 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, - 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, - 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, - 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, - 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, - 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, - 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, - 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, - 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, - 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, + 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, + 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, + 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, + 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, + 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, + 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, + 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, + 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, + 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]); - -module.exports = function crc32(buffer) { - let offset = 0; - let crc = 0xFFFFFFFF; - - while (offset < buffer.length - 4) { - crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); - crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); - crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); - crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); + + module.exports = function crc32(buffer) { + let offset = 0 | 0; + let crc = 0xFFFFFFFF | 0; + const bl = (buffer.length - 4) | 0; + + while (bl > offset) { + crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); + crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); + crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); + crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); } - + while (offset < buffer.length) { - crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); + crc = table[(crc ^ buffer[offset++]) & 0xff] ^ (crc >>> 8); } - + return (crc ^ 0xFFFFFFFF) >>> 0; -}; \ No newline at end of file + }; \ No newline at end of file diff --git a/utils/png.js b/utils/png.js index 81773cc..fd406c6 100644 --- a/utils/png.js +++ b/utils/png.js @@ -1,7 +1,7 @@ /* global SharedArrayBuffer */ +const mem = require('./buffer.js'); const crc32 = require('./crc32.js'); -const Buffer = require('./buffer'); -const {compress, decompress} = require('./wasm/zlib.js'); +const { compress, decompress } = require('./zlib.js'); const __IHDR__ = new Uint8Array([73, 72, 68, 82]); const __IDAT__ = new Uint8Array([73, 68, 65, 84]); @@ -10,204 +10,249 @@ const __IEND_CRC__ = crc32(new Uint8Array([73, 69, 78, 68])); const HEAD = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]); const color_types = { - GREYSCALE: 0, - TRUECOLOR: 2, - INDEXED_COLOR: 3, - GREYSCALE_ALPHA: 4, - TRUECOLOR_ALPHA: 6 + GREYSCALE: 0, + TRUECOLOR: 2, + INDEXED_COLOR: 3, + GREYSCALE_ALPHA: 4, + TRUECOLOR_ALPHA: 6 }; const channels_to_color_type = { - 1: color_types.GREYSCALE, - 2: color_types.GREYSCALE_ALPHA, + 1: color_types.GREYSCALE, + 2: color_types.GREYSCALE_ALPHA, - 3: color_types.TRUECOLOR, - 4: color_types.TRUECOLOR_ALPHA + 3: color_types.TRUECOLOR, + 4: color_types.TRUECOLOR_ALPHA }; +const utf8encoder = new TextEncoder; // replace with latin1 encoder or iext + module.exports = { - async encode(data, {width, height, channels, depth = 8, level = 0}) { - let offset = 0; - let tmp_offset = 0; - const row_length = width * channels; - const tmp = new Uint8Array(height + data.length); + encode(data, { text, width, height, channels, depth = 8, level = 0 }) { + let offset = 0; + let tmp_offset = 0; + const row_length = width * channels; + const tmp = new Uint8Array(height + data.length); - while (offset < data.length) { - tmp[tmp_offset++] = 0; - tmp.set(data.subarray(offset, (offset += row_length)), tmp_offset); + while (offset < data.length) { + tmp[tmp_offset++] = 0; + tmp.set(data.subarray(offset, (offset += row_length)), tmp_offset); - tmp_offset += row_length; - } + tmp_offset += row_length; + } - const compressed = await compress(tmp, level); - const array = new Uint8Array(49 + HEAD.length + compressed.length); - - array[26] = 0; - array[27] = 0; - array[28] = 0; - array[24] = depth; - array.set(HEAD, 0); - array.set(__IHDR__, 12); - array.set(__IDAT__, 37); - array.set(compressed, 41); - array.set(__IEND__, 49 + compressed.length); - array[25] = channels_to_color_type[channels]; - - const view = new DataView(array.buffer); - - view.setUint32(8, 13); - view.setUint32(16, width); - view.setUint32(20, height); - view.setUint32(33, compressed.length); - view.setUint32(45 + compressed.length, 0); - view.setUint32(53 + compressed.length, __IEND_CRC__); - view.setUint32(29, crc32(new Uint8Array(array.buffer, 12, 17))); - view.setUint32(41 + compressed.length, crc32(new Uint8Array(array.buffer, 37, 4 + compressed.length))); - - return array; - }, - async decode(array) { - let view = new DataView(array.buffer, array.byteOffset, array.byteLength); - - const width = view.getUint32(16); - const height = view.getUint32(20); - const bpc = array[24]; - const pixel_type = array[25]; - let channels = ({3: 1, 0: 1, 4: 2, 2: 3, 6: 4})[pixel_type]; - const bytespp = channels * bpc / 8; - - const row_length = width * bytespp; - let pixels = new Uint8Array(height * row_length); - - let offset = 0; - let p_offset = 0; - - let c_offset = 33; - const chunks = []; - - let palette; - if (array[25] === 3) - palette = new Uint32Array(2 ** bpc); - - let type; - while (type !== 1229278788) { - type = view.getUint32(4 + c_offset); - - // IDAT - if (type === 1229209940) - chunks.push(array.subarray(8 + c_offset, 8 + c_offset + view.getUint32(c_offset))); - else if (type === 1347179589) { - for (let pxlOffset = 0; pxlOffset < palette.length * 8; pxlOffset += 3) - palette[pxlOffset / 3] = array[8 + c_offset + pxlOffset] << 24 | array[8 + c_offset + pxlOffset + 1] << 16 | array[8 + c_offset + pxlOffset + 2] << 8 | 0xff; - } - - c_offset += 4 + 4 + 4 + view.getUint32(c_offset); - } + if (text) { + let chunks = []; + for (const key in text) { + if (!text[key]) continue; + const kb = utf8encoder.encode(key); + const tb = utf8encoder.encode(text[key]); + const chunk = new Uint8Array(1 + 12 + kb.length + tb.length); + + const view = new DataView(chunk.buffer); + + chunk[4] = 0x74; + chunk[5] = 0x45; + chunk[6] = 0x58; + chunk[7] = 0x74; + chunk.set(kb, 8); + chunks.push(chunk); + chunk.set(tb, 9 + kb.length); + view.setUint32(0, chunk.length - 12); + view.setUint32(chunk.length - 4, crc32(chunk.subarray(4, chunk.length - 4))); + } + + text = mem.from_parts(chunks); + } - array = await decompress(chunks.length === 1 ? chunks[0] : Buffer.concat(...chunks)); + offset = text ? text.length : 0; + const compressed = compress(tmp, level); + const array = new Uint8Array(49 + offset + HEAD.length + compressed.length); + + array[26] = 0; + array[27] = 0; + array[28] = 0; + array[24] = depth; + array.set(HEAD, 0); + array.set(__IHDR__, 12); + array.set(__IDAT__, 37); + array.set(compressed, 41); + array[25] = channels_to_color_type[channels]; + if (text) array.set(text, 45 + compressed.length); + array.set(__IEND__, 49 + offset + compressed.length); + + const view = new DataView(array.buffer); + + view.setUint32(8, 13); + view.setUint32(16, width); + view.setUint32(20, height); + view.setUint32(33, compressed.length); + view.setUint32(45 + offset + compressed.length, 0); + view.setUint32(53 + offset + compressed.length, __IEND_CRC__); + view.setUint32(29, crc32(new Uint8Array(array.buffer, 12, 17))); + view.setUint32(41 + compressed.length, crc32(new Uint8Array(array.buffer, 37, 4 + compressed.length))); + + return array; + }, + + decode(array) { + let view = new DataView(array.buffer, array.byteOffset, array.byteLength); + + const width = view.getUint32(16); + const height = view.getUint32(20); + let bit_depth = array[24]; + const color_type = array[25]; + let channels = ({ 3: 1, 0: 1, 4: 2, 2: 3, 6: 4 })[color_type]; + const bytespp = channels * bit_depth / 8; + + const row_length = width * bytespp; + let pixels = new Uint8Array(height * row_length); + + let offset = 0; + let p_offset = 0; + + let c_offset = 33; + const chunks = []; + + let palette, alphaPalette; + + const maxSearchOffset = array.length - 5; + + let type; + while ((type = view.getUint32(4 + c_offset)) !== 1229278788) { // IEND + if (type === 1229209940) // IDAT + chunks.push(array.subarray(8 + c_offset, 8 + c_offset + view.getUint32(c_offset))); + else if (type === 1347179589) { // PLTE + if (palette) + throw new Error('PLTE can only occur once in an image'); + palette = new Uint32Array(view.getUint32(c_offset)); + for (let pxlOffset = 0; pxlOffset < palette.length * 8; pxlOffset += 3) + palette[pxlOffset / 3] = array[8 + c_offset + pxlOffset] << 24 | array[8 + c_offset + pxlOffset + 1] << 16 | array[8 + c_offset + pxlOffset + 2] << 8 | 0xff; + } else if (type === 1951551059) { // tRNS + if (alphaPalette) + throw new Error('tRNS can only occur once in an image'); + alphaPalette = new Uint8Array(view.getUint32(c_offset)); + for (let i = 0; i < alphaPalette.length; i++) + alphaPalette[i] = array[8 + c_offset + i]; + } + + c_offset += 4 + 4 + 4 + view.getUint32(c_offset); + if (c_offset > maxSearchOffset) // missing IEND + break; + } - while (offset < array.byteLength) { - const filter = array[offset++]; - const slice = array.subarray(offset, offset += row_length); + array = decompress(chunks.length === 1 ? chunks[0] : mem.from_parts(chunks), height + height * row_length); - if (0 === filter) pixels.set(slice, p_offset); - else if (1 === filter) this.filter_1(slice, pixels, p_offset, bytespp, row_length); - else if (2 === filter) this.filter_2(slice, pixels, p_offset, bytespp, row_length); - else if (3 === filter) this.filter_3(slice, pixels, p_offset, bytespp, row_length); - else if (4 === filter) this.filter_4(slice, pixels, p_offset, bytespp, row_length); + while (offset < array.byteLength) { + const filter = array[offset++]; + const slice = array.subarray(offset, offset += row_length); - p_offset += row_length; - } + if (0 === filter) pixels.set(slice, p_offset); + else if (1 === filter) this.filter_1(slice, pixels, p_offset, bytespp, row_length); + else if (2 === filter) this.filter_2(slice, pixels, p_offset, bytespp, row_length); + else if (3 === filter) this.filter_3(slice, pixels, p_offset, bytespp, row_length); + else if (4 === filter) this.filter_4(slice, pixels, p_offset, bytespp, row_length); - if (channels === 1 && palette) { - channels = 4; - const newPixels = new Uint8Array(width * height * 4); - const pixelView = new DataView(newPixels.buffer, newPixels.byteOffset, newPixels.byteLength); - for (let i = 0; i < pixels.length; i++) - pixelView.setUint32(i * 4, palette[pixels[i]], false); - pixels = newPixels; - } + p_offset += row_length; + } - if (bpc !== 8) { - const newPixels = new Uint8Array(pixels.length / bpc * 8); - for (let i = 0; i < pixels.length; i += 2) - newPixels[i / 2] = pixels[i]; - pixels = newPixels; - } + if (color_type === 3) { + if (!palette) + throw new Error('Indexed color PNG has no PLTE'); + + if (alphaPalette) + for (let i = 0; i < alphaPalette.length; i++) + palette[i] &= 0xffffff00 | alphaPalette[i]; + + const newPixels = new Uint8Array(width * height * 4); + const pixelView = new DataView(newPixels.buffer, newPixels.byteOffset, newPixels.byteLength); + for (let i = 0; i < pixels.length * (8 / bit_depth); i++) + pixelView.setUint32(i * 4, palette[pixels[~~(i / (8 / bit_depth))] & (2**bit_depth-1)], false); + channels = 4; + bit_depth = 8; + pixels = newPixels; + } - if (channels !== 4) { - const newPixels = new Uint8Array(width * height * 4); - const view = new DataView(newPixels.buffer); - - if (channels === 1) { - for (let i = 0; i < width * height; i++) { - const pixel = pixels[i]; - view.setUint32(i * 4, pixel << 24 | pixel << 16 | pixel << 8 | 0xff, false); - } - } else if (channels === 2) { - for (let i = 0; i < width * height * 2; i += 2) { - const pixel = pixels[i]; - view.setUint32(i * 2, pixel << 24 | pixel << 16 | pixel << 8 | pixels[i + 1], false); - } - } else if (channels === 3) { - newPixels.fill(0xff); - for (let i = 0; i < width * height; i++) - newPixels.set(pixels.subarray(i * 3, i * 3 + 3), i * 4); - } - - pixels = newPixels; + if (bit_depth !== 8) { + const newPixels = new Uint8Array(pixels.length / bit_depth * 8); + for (let i = 0; i < pixels.length; i += 2) + newPixels[i / 2] = pixels[i]; + pixels = newPixels; + } + + if (channels !== 4) { + const newPixels = new Uint8Array(width * height * 4); + const view = new DataView(newPixels.buffer); + + if (channels === 1) { + for (let i = 0; i < width * height; i++) { + const pixel = pixels[i]; + view.setUint32(i * 4, pixel << 24 | pixel << 16 | pixel << 8 | 0xff, false); + } + } else if (channels === 2) { + for (let i = 0; i < width * height * 2; i += 2) { + const pixel = pixels[i]; + view.setUint32(i * 2, pixel << 24 | pixel << 16 | pixel << 8 | pixels[i + 1], false); } + } else if (channels === 3) { + newPixels.fill(0xff); + for (let i = 0; i < width * height; i++) + newPixels.set(pixels.subarray(i * 3, i * 3 + 3), i * 4); + } - return {width, height, pixels}; - }, + pixels = newPixels; + } - filter_1(slice, pixels, p_offset, bytespp, row_length) { - let i = 0; - while (i < bytespp) pixels[i + p_offset] = slice[i++]; - while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - bytespp]; - }, + return { width, height, pixels }; + }, - filter_2(slice, pixels, p_offset, bytespp, row_length) { - if (0 === p_offset) pixels.set(slice, p_offset); - else { - let i = 0; - while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length]; - } - }, + filter_1(slice, pixels, p_offset, bytespp, row_length) { + let i = 0; + while (i < bytespp) pixels[i + p_offset] = slice[i++]; + while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - bytespp]; + }, - filter_3(slice, pixels, p_offset, bytespp, row_length) { - let i = 0; + filter_2(slice, pixels, p_offset, bytespp, row_length) { + if (0 === p_offset) pixels.set(slice, p_offset); + else { + let i = 0; + while (i < row_length) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length]; + } + }, - if (0 === p_offset) { - while (i < bytespp) pixels[i] = slice[i++]; - while (i < row_length) pixels[i] = slice[i] + (pixels[i++ - bytespp] >> 1); - } else { - while (i < bytespp) pixels[i + p_offset] = slice[i] + (pixels[i++ + p_offset - row_length] >> 1); - while (i < row_length) pixels[i + p_offset] = slice[i] + (pixels[i + p_offset - bytespp] + pixels[i++ + p_offset - row_length] >> 1); - } - }, + filter_3(slice, pixels, p_offset, bytespp, row_length) { + let i = 0; - filter_4(slice, pixels, p_offset, bytespp, row_length) { - let i = 0; + if (0 === p_offset) { + while (i < bytespp) pixels[i] = slice[i++]; + while (i < row_length) pixels[i] = slice[i] + (pixels[i++ - bytespp] >> 1); + } else { + while (i < bytespp) pixels[i + p_offset] = slice[i] + (pixels[i++ + p_offset - row_length] >> 1); + while (i < row_length) pixels[i + p_offset] = slice[i] + (pixels[i + p_offset - bytespp] + pixels[i++ + p_offset - row_length] >> 1); + } + }, - if (0 === p_offset) { - while (i < bytespp) pixels[i] = slice[i++]; - while (i < row_length) pixels[i] = slice[i] + pixels[i++ - bytespp]; - } else { - while (i < bytespp) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length]; + filter_4(slice, pixels, p_offset, bytespp, row_length) { + let i = 0; - while (i < row_length) { - const a = pixels[i + p_offset - bytespp]; - const b = pixels[i + p_offset - row_length]; - const c = pixels[i + p_offset - bytespp - row_length]; + if (0 === p_offset) { + while (i < bytespp) pixels[i] = slice[i++]; + while (i < row_length) pixels[i] = slice[i] + pixels[i++ - bytespp]; + } else { + while (i < bytespp) pixels[i + p_offset] = slice[i] + pixels[i++ + p_offset - row_length]; - const p = a + b - c; - const pa = Math.abs(p - a); - const pb = Math.abs(p - b); - const pc = Math.abs(p - c); + while (i < row_length) { + const a = pixels[i + p_offset - bytespp]; + const b = pixels[i + p_offset - row_length]; + const c = pixels[i + p_offset - bytespp - row_length]; - pixels[i + p_offset] = slice[i++] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c)); - } - } + const p = a + b - c; + const pa = Math.abs(p - a); + const pb = Math.abs(p - b); + const pc = Math.abs(p - c); + + pixels[i + p_offset] = slice[i++] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c)); + } } -}; \ No newline at end of file + } +}; diff --git a/utils/wasm/font.js b/utils/wasm/font.js index fc3c753..8c0813e 100644 --- a/utils/wasm/font.js +++ b/utils/wasm/font.js @@ -1,98 +1,142 @@ -const {join} = require('path'); -const {promises: {readFile}} = require('fs'); +const { version } = require('../../package.json'); -let u8array_ref, i32array_ref, u32array_ref, wasm; +let mod = null; +module.exports = { + async init() { + if (!mod) { + const streaming = 'compileStreaming' in WebAssembly; + mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/font.wasm`).then(x => streaming ? x : x.arrayBuffer())); + } -const utf8encoder = new TextEncoder(); + return this.new(); + }, -function u8array() { - return u8array_ref.buffer === wasm.memory.buffer ? u8array_ref : (u8array_ref = new Uint8Array(wasm.memory.buffer)); -} + new() { + let registry = null; + const wasm = new WebAssembly.Instance(mod).exports; -function i32array() { - return i32array_ref.buffer === wasm.memory.buffer ? i32array_ref : (i32array_ref = new Int32Array(wasm.memory.buffer)); -} + class mem { + static length() { return wasm.wlen(); } + static alloc(size) { return wasm.walloc(size); } + static free(ptr, size) { return wasm.wfree(ptr, size); } + static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); } + static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); } -function u32array() { - return u32array_ref.buffer === wasm.memory.buffer ? u32array_ref : (u32array_ref = new Uint32Array(wasm.memory.buffer)); -} + static copy_and_free(ptr, size) { + let slice = mem.u8(ptr, size).slice(); + return (wasm.wfree(ptr, size), slice); + } + } + const encode_utf8 = 'Deno' in globalThis ? Deno.core.encode : (() => { + const encoder = new TextEncoder(); + return string => encoder.encode(string); + })(); + + const decode_utf8 = 'Deno' in globalThis ? Deno.core.decode : (() => { + const decoder = new TextDecoder(); + return buffer => decoder.decode(buffer); + })(); + + if ('FinalizationRegistry' in globalThis) { + registry = new FinalizationRegistry(([t, ptr]) => { + if (t === 0) wasm.font_free(ptr); + if (t === 1) wasm.layout_free(ptr); + }); + } -function ptr_to_u8array(ptr, len) { - return u8array().subarray(ptr, ptr + len); -} + class Font { + constructor(scale, buffer) { + this.scale = scale; + const ptr = mem.alloc(buffer.length); + mem.u8(ptr, buffer.length).set(buffer); + this.ptr = wasm.font_new(ptr, buffer.length, scale); -function ptr_to_u32array(ptr, len) { - return u32array().subarray(ptr / 4, ptr / 4 + len); -} + if (!this.ptr) throw new Error('invalid font'); + if (registry) registry.register(this, [0, this.ptr], this); + } -function u8array_to_ptr(buffer) { - const ptr = wasm.__wbindgen_malloc(buffer.length); - u8array().set(buffer, ptr); + free() { + this.ptr = wasm.font_free(this.ptr); + if (registry) registry.unregister(this); + } - return ptr; -} + has(char) { + return wasm.font_has(this.ptr, String.prototype.charCodeAt.call(char, 0)); + } -function string_to_ptr(string) { - let offset = 0; - let len = string.length; - let ptr = wasm.__wbindgen_malloc(string.length); + metrics(char, scale = this.scale) { + const ptr = wasm.font_metrics(this.ptr, String.prototype.charCodeAt.call(char, 0), scale); + const metrics = JSON.parse(decode_utf8(mem.u8(wasm.font_metrics_buffer(ptr), mem.length()))); - const u8 = u8array(); - while (len > offset) { - const code = string.charCodeAt(offset); + return (wasm.font_metrics_free(ptr), metrics); + } - if (code > 0x7F) break; - u8[ptr + offset++] = code; - } + rasterize(char, scale = this.scale) { + const ptr = wasm.font_rasterize(this.ptr, String.prototype.charCodeAt.call(char, 0), scale); - if (offset !== len) { - if (offset !== 0) string = string.substring(offset); - ptr = wasm.__wbindgen_realloc(ptr, len, len = offset + string.length * 3); - const ret = utf8encoder.encodeInto(string, u8array().subarray(ptr + offset, ptr + len)); + const glyph = { + buffer: mem.u8(wasm.font_rasterize_buffer(ptr), mem.length()).slice(), + metrics: JSON.parse(decode_utf8(mem.u8(wasm.font_rasterize_metrics(ptr), mem.length()))), + } - offset += ret.written; + return (wasm.font_rasterize_free(ptr), glyph); + } } - return [ptr, offset]; -} - -const nullish = x => x == null; - -module.exports = { - render(ptr, id, scale, r, g, b, text, max_width, wrap_style = false) { - const str = string_to_ptr(text); - wasm.render(ptr, id, scale, r, g, b, str[0], str[1], !nullish(max_width), max_width || 0, wrap_style); - }, - buffer(id) { - wasm.buffer(8, id); - const i32 = i32array(); - const slice = ptr_to_u8array(i32[2], i32[3]).slice(); - wasm.__wbindgen_free(i32[2], i32[3]); - - return slice; - }, - meta(id) { - wasm.meta(8, id); - const i32 = i32array(); - const slice = ptr_to_u32array(i32[2], i32[3]).slice(); - wasm.__wbindgen_free(i32[2], 4 * i32[3]); - - return slice; - }, - async load(id, buffer, scale = 128) { - if (!wasm) { - const module = new WebAssembly.Module(await readFile(join(__dirname, './font.wasm'))); - const instance = new WebAssembly.Instance(module); - - wasm = instance.exports; - u8array_ref = new Uint8Array(wasm.memory.buffer); - i32array_ref = new Int32Array(wasm.memory.buffer); - u32array_ref = new Uint32Array(wasm.memory.buffer); + class Layout { + constructor() { + this.ptr = wasm.layout_new(); + if (registry) this.refs = []; + if (registry) registry.register(this, [1, this.ptr], this); + } + + clear() { + wasm.layout_clear(this.ptr); + if (registry) this.refs.length = 0; + } + + lines() { + return wasm.layout_lines(this.ptr); + } + + free() { + if (registry) this.refs.length = 0; + this.ptr = wasm.layout_free(this.ptr); + if (registry) registry.unregister(this); + } + + reset(options = {}) { + options = encode_utf8(JSON.stringify(options)); + + if (registry) this.refs.length = 0; + const ptr = mem.alloc(options.length); + mem.u8(ptr, options.length).set(options); + wasm.layout_reset(this.ptr, ptr, options.length); + } + + append(font, text, init) { + text = encode_utf8(text); + const options = init || {}; + if (registry) this.refs.push(font); + const ptr = mem.alloc(text.length); + mem.u8(ptr, text.length).set(text); + const has_color = ('r' in options) || ('g' in options) || ('b' in options); + wasm.layout_append(this.ptr, font.ptr, ptr, text.length, options.scale == null ? font.scale : options.scale, has_color, options.r, options.g, options.b); + } + + rasterize(r, g, b) { + const ptr = wasm.layout_rasterize(this.ptr, r, g, b); + + const framebuffer = { + width: wasm.layout_rasterize_width(ptr), + height: wasm.layout_rasterize_height(ptr), + buffer: mem.u8(wasm.layout_rasterize_buffer(ptr), mem.length()).slice(), } - wasm.load(id, u8array_to_ptr(buffer), buffer.length, scale); - }, - free(id) { - wasm.free(id); + return (wasm.layout_rasterize_free(ptr), framebuffer); + } } + + return { Font, Layout }; + }, } \ No newline at end of file diff --git a/utils/wasm/font.wasm b/utils/wasm/font.wasm deleted file mode 100644 index a03a568..0000000 Binary files a/utils/wasm/font.wasm and /dev/null differ diff --git a/utils/wasm/gif.js b/utils/wasm/gif.js index d7dfa9d..dfbdd9d 100644 --- a/utils/wasm/gif.js +++ b/utils/wasm/gif.js @@ -1,105 +1,133 @@ -const {join} = require('path'); -const {promises: {readFile}} = require('fs'); - -let wasm; - -let cachedTextDecoder = new TextDecoder('utf-8', {ignoreBOM: true, fatal: true}); - -cachedTextDecoder.decode(); - -let cachegetUint8Memory0 = null; - -function getUint8Memory0() { - if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { - cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachegetUint8Memory0; -} - -function getStringFromWasm0(ptr, len) { - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); -} - -let cachegetInt32Memory0 = null; - -function getInt32Memory0() { - if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { - cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachegetInt32Memory0; -} - -function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); +const { version } = require('../../package.json'); + +let mod = null; +module.exports = { + async init() { + if (!mod) { + const streaming = 'compileStreaming' in WebAssembly; + mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/gif.wasm`).then(x => streaming ? x : x.arrayBuffer())); + }; + + return this.new(); + }, + + new() { + const streams = new Map; + const utf8encoder = new TextEncoder; + + const wasm = new WebAssembly.Instance(mod, { + env: { + push_to_stream(id, ptr) { + streams.get(id).cb(mem.u8(ptr, mem.length()).slice()); + }, + }, + }).exports; + + class mem { + static length() { return wasm.wlen(); } + static alloc(size) { return wasm.walloc(size); } + static free(ptr, size) { return wasm.wfree(ptr, size); } + static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); } + static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); } + + static copy_and_free(ptr, size) { + let slice = mem.u8(ptr, size).slice(); + return (wasm.wfree(ptr, size), slice); + } + } + + class Encoder { + constructor(width, height, loops = -1) { + this.slices = []; + streams.set(0, this); + this.ptr = wasm.encoder_new(0, width, height, loops); + } + + cb(buffer) { + this.slices.push(buffer); + } + + free() { + this.ptr = wasm.encoder_free(this.ptr); + streams.delete(0); + } + + u8() { + this.free(); + let offset = 0; + const u8 = new Uint8Array(this.slices.reduce((sum, array) => sum + array.length, 0)); + + for (const x of this.slices) { + u8.set(x, offset); + offset += x.length; + } + + return u8; + } + + add(x, y, delay, width, height, buffer, dispose, quality) { + const ptr = mem.alloc(buffer.length); + mem.u8(ptr, buffer.length).set(buffer); + wasm.encoder_add(this.ptr, ptr, buffer.length, x, y, width, height, delay, dispose, quality); + } + + set comment(comment) { + const buffer = utf8encoder.encode(comment); + + const ptr = mem.alloc(buffer.length); + mem.u8(ptr, buffer.length).set(buffer); + wasm.encoder_add_comment(this.ptr, ptr, buffer.length); + } + + set application(application) { + const buffer = utf8encoder.encode(application); + + const ptr = mem.alloc(buffer.length); + mem.u8(ptr, buffer.length).set(buffer); + wasm.encoder_add_application(this.ptr, ptr, buffer.length); + } + } + + class Decoder { + constructor(buffer, limit = 0) { + const bptr = mem.alloc(buffer.length); + mem.u8(bptr, buffer.length).set(buffer); + this.ptr = wasm.decoder_new(bptr, buffer.length, limit); + if (0 === this.ptr) throw new Error('gif: failed to parse gif header'); + + this.width = wasm.decoder_width(this.ptr); + this.height = wasm.decoder_height(this.ptr); + } + + free() { + this.ptr = wasm.decoder_free(this.ptr); + } + + *frames() { + let frame; + while (frame = this.frame()) yield frame; + } + + frame() { + const ptr = wasm.decoder_frame(this.ptr); + + if (1 === ptr) return null; + if (0 === ptr) throw (this.free(), new Error('gif: failed to decode frame')); + + const framebuffer = { + x: wasm.decoder_frame_x(ptr), + y: wasm.decoder_frame_y(ptr), + delay: wasm.decoder_frame_delay(ptr), + width: wasm.decoder_frame_width(ptr), + height: wasm.decoder_frame_height(ptr), + dispose: wasm.decoder_frame_dispose(ptr), + buffer: mem.u8(wasm.decoder_frame_buffer(ptr), mem.length()).slice(), + }; + + return (wasm.decoder_frame_free(ptr), framebuffer); + } + } + + return { Encoder, Decoder }; + }, } - -let WASM_VECTOR_LEN = 0; - -function passArray8ToWasm0(arg, malloc) { - const ptr = malloc(arg.length * 1); - getUint8Memory0().set(arg, ptr / 1); - WASM_VECTOR_LEN = arg.length; - return ptr; -} - -class GIFEncoder { - free() { - wasm.__wbg_gif_encoder_free(this.ptr); - } - - /** - * @param {number} width - * @param {number} height - * @param {number} repeat - */ - static async initialize(width, height, repeat) { - if (!wasm) { - const module = new WebAssembly.Module(await readFile(join(__dirname, './gif.wasm'))); - const instance = new WebAssembly.Instance(module, { - __wbindgen_placeholder__: { - __wbindgen_throw: function (arg0, arg1) { - throw new Error(getStringFromWasm0(arg0, arg1)); - }, - } - }); - wasm = instance.exports; - } - - const ret = wasm.gif_encoder_new(width, height, repeat); - return new GIFEncoder(ret); - } - - constructor(ptr) { - this.ptr = ptr; - } - - /** - * @returns {Uint8Array} - */ - buffer() { - try { - const retptr = wasm.__wbindgen_export_0.value - 16; - wasm.__wbindgen_export_0.value = retptr; - wasm.gif_encoder_buffer(retptr, this.ptr); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1); - return v0; - } finally { - wasm.__wbindgen_export_0.value += 16; - } - } - - /** - * @param {number} delay - * @param {number} quality - * @param {Uint8Array} buffer - */ - add(delay, quality, buffer) { - const ptr0 = passArray8ToWasm0(buffer, wasm.__wbindgen_malloc); - wasm.gif_encoder_add(this.ptr, delay, quality, ptr0, WASM_VECTOR_LEN); - } -} - -module.exports = {GIFEncoder}; \ No newline at end of file diff --git a/utils/wasm/gif.wasm b/utils/wasm/gif.wasm deleted file mode 100644 index 216a447..0000000 Binary files a/utils/wasm/gif.wasm and /dev/null differ diff --git a/utils/wasm/jpeg.js b/utils/wasm/jpeg.js index e905621..1d2032c 100644 --- a/utils/wasm/jpeg.js +++ b/utils/wasm/jpeg.js @@ -1,137 +1,56 @@ -const {join} = require('path'); -const {promises: {readFile}} = require('fs'); +const { version } = require('../../package.json'); -let wasm; - -let cachegetUint8Memory0 = null; -function getUint8Memory0() { - if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { - cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); +let mod = null; +module.exports = { + async init() { + if (!mod) { + const streaming = 'compileStreaming' in WebAssembly; + mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/jpeg.wasm`).then(x => streaming ? x : x.arrayBuffer())); + }; + + return this.new(); + }, + + new() { + const wasm = new WebAssembly.Instance(mod).exports; + + class mem { + static length() { return wasm.wlen(); } + static alloc(size) { return wasm.walloc(size); } + static free(ptr, size) { return wasm.wfree(ptr, size); } + static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); } + static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); } + + static copy_and_free(ptr, size) { + let slice = mem.u8(ptr, size).slice(); + return (wasm.wfree(ptr, size), slice); + } } - return cachegetUint8Memory0; -} - -let WASM_VECTOR_LEN = 0; - -function passArray8ToWasm0(arg, malloc) { - const ptr = malloc(arg.length * 1); - getUint8Memory0().set(arg, ptr / 1); - WASM_VECTOR_LEN = arg.length; - return ptr; -} -let cachegetInt32Memory0 = null; - -function getInt32Memory0() { - if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { - cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); + function encode(buffer, width, height, quality) { + const ptr = mem.alloc(buffer.length); + mem.u8(ptr, buffer.length).set(buffer); + return mem.copy_and_free(wasm.encode(ptr, width, height, quality), mem.length()); } - return cachegetInt32Memory0; -} - -function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); -} -let cachegetUint16Memory0 = null; + function decode(buffer, width, height) { + const bptr = mem.alloc(buffer.length); + mem.u8(bptr, buffer.length).set(buffer); + const ptr = wasm.decode(bptr, buffer.length, width, height); -function getUint16Memory0() { - if (cachegetUint16Memory0 === null || cachegetUint16Memory0.buffer !== wasm.memory.buffer) { - cachegetUint16Memory0 = new Uint16Array(wasm.memory.buffer); - } - return cachegetUint16Memory0; -} + if (0 === ptr) throw new Error('jpg: failed to decode'); + if (1 === ptr) throw new Error('jpg: failed to scale decoder'); -function getArrayU16FromWasm0(ptr, len) { - return getUint16Memory0().subarray(ptr / 2, ptr / 2 + len); -} + const framebuffer = { + width: wasm.decode_width(ptr), + height: wasm.decode_height(ptr), + format: wasm.decode_format(ptr), + buffer: mem.u8(wasm.decode_buffer(ptr), mem.length()).slice(), + } -async function initWASM() { - if (wasm) return; - - const module = new WebAssembly.Module(await readFile(join(__dirname, './jpeg.wasm'))); - const instance = new WebAssembly.Instance(module); - wasm = instance.exports; -} - -module.exports = { - /** - * @param {number} width - * @param {number} height - * @param {number} quality - * @param {Uint8Array|Uint8ClampedArray} buffer - * @returns {Uint8Array} - */ - async encode(width, height, quality, buffer) { - await initWASM(); - - try { - const retptr = wasm.__wbindgen_export_0.value - 16; - wasm.__wbindgen_export_0.value = retptr; - const ptr0 = passArray8ToWasm0(buffer, wasm.__wbindgen_malloc); - wasm.encode(retptr, width, height, quality, ptr0, WASM_VECTOR_LEN); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1); - return v1; - } finally { - wasm.__wbindgen_export_0.value += 16; - } - }, - /** - * @param {number} ptr - * @param {Uint8Array} buffer - * @param {number} width - * @param {number} height - * @returns {number} - */ - async decode(ptr, buffer, width, height) { - await initWASM(); - - const ptr0 = passArray8ToWasm0(buffer, wasm.__wbindgen_malloc); - return wasm.decode(ptr, ptr0, WASM_VECTOR_LEN, width, height); - }, - /** - * @param {number} id - * @returns {Uint16Array} - */ - meta(id) { - try { - const retptr = wasm.__wbindgen_export_0.value - 16; - wasm.__wbindgen_export_0.value = retptr; - wasm.meta(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU16FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 2); - return v0; - } finally { - wasm.__wbindgen_export_0.value += 16; - } - }, - /** - * @param {number} id - * @returns {Uint8Array} - */ - buffer(id) { - try { - const retptr = wasm.__wbindgen_export_0.value - 16; - wasm.__wbindgen_export_0.value = retptr; - wasm.buffer(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1); - return v0; - } finally { - wasm.__wbindgen_export_0.value += 16; - } - }, - /** - * @param {number} id - */ - free(id) { - wasm.free(id); + return (wasm.decode_free(ptr), framebuffer); } + + return { encode, decode }; + }, } \ No newline at end of file diff --git a/utils/wasm/jpeg.wasm b/utils/wasm/jpeg.wasm deleted file mode 100644 index ad99919..0000000 Binary files a/utils/wasm/jpeg.wasm and /dev/null differ diff --git a/utils/wasm/svg.js b/utils/wasm/svg.js index 6966e93..1694649 100644 --- a/utils/wasm/svg.js +++ b/utils/wasm/svg.js @@ -1,159 +1,49 @@ -const {readFile} = require('fs').promises; -const {join} = require('path'); +const { version } = require('../../package.json'); -let wasm; - -let WASM_VECTOR_LEN = 0; - -let cachegetUint8Memory0 = null; - -function getUint8Memory0() { - if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { - cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachegetUint8Memory0; -} - -let cachedTextEncoder = new TextEncoder(); - -const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' - ? function (arg, view) { - return cachedTextEncoder.encodeInto(arg, view); - } - : function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; - }); - -function passStringToWasm0(arg, malloc, realloc) { - - if (realloc === undefined) { - const textEncoder = new TextEncoder(); - const buf = textEncoder.encode(arg); - const ptr = malloc(buf.length); - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); - WASM_VECTOR_LEN = buf.length; - return ptr; - } - - let len = arg.length; - let ptr = malloc(len); - - const mem = getUint8Memory0(); +let mod = null; +module.exports = { + async init() { + if (!mod) { + const streaming = 'compileStreaming' in WebAssembly; + mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/svg.wasm`).then(x => streaming ? x : x.arrayBuffer())); + }; - let offset = 0; + return this.new(); + }, - for (; offset < len; offset++) { - const code = arg.charCodeAt(offset); - if (code > 0x7F) break; - mem[ptr + offset] = code; - } + new() { + const wasm = new WebAssembly.Instance(mod).exports; - if (offset !== len) { - if (offset !== 0) { - arg = arg.slice(offset); - } - ptr = realloc(ptr, len, len = offset + arg.length * 3); - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); - const ret = encodeString(arg, view); + class mem { + static length() { return wasm.wlen(); } + static alloc(size) { return wasm.walloc(size); } + static free(ptr, size) { return wasm.wfree(ptr, size); } + static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); } + static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); } - offset += ret.written; + static copy_and_free(ptr, size) { + let slice = mem.u8(ptr, size).slice(); + return (wasm.wfree(ptr, size), slice); + } } - WASM_VECTOR_LEN = offset; - return ptr; -} + function rasterize(buffer, fit, scale) { + const bptr = mem.alloc(buffer.length); + mem.u8(bptr, buffer.length).set(buffer); + const ptr = wasm.rasterize(bptr, buffer.length, fit, scale); -let cachegetInt32Memory0 = null; + if (0 === ptr) throw new Error('svg: failed to parse'); + if (1 === ptr) throw new Error('svg: failed to rasterize'); -function getInt32Memory0() { - if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { - cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachegetInt32Memory0; -} - -let cachegetUint32Memory0 = null; + const framebuffer = { + width: wasm.rasterize_width(ptr), + height: wasm.rasterize_height(ptr), + buffer: mem.u8(wasm.rasterize_buffer(ptr), mem.length()).slice(), + } -function getUint32Memory0() { - if (cachegetUint32Memory0 === null || cachegetUint32Memory0.buffer !== wasm.memory.buffer) { - cachegetUint32Memory0 = new Uint32Array(wasm.memory.buffer); + return (wasm.rasterize_free(ptr), framebuffer); } - return cachegetUint32Memory0; -} -function getArrayU32FromWasm0(ptr, len) { - return getUint32Memory0().subarray(ptr / 4, ptr / 4 + len); + return { rasterize }; + }, } - -function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr, ptr + len); -} - -module.exports = { - /** - * @param {number} ptr - * @param {string} svg - * @param {number} fit_kind - * @param {number} zoom - * @param {number} width - * @param {number} height - * @returns {number} - */ - async rgba(ptr, svg, fit_kind, zoom, width, height) { - if (!wasm) { - const module = new WebAssembly.Module(await readFile(join(__dirname, './svg.wasm'))); - const instance = new WebAssembly.Instance(module); - wasm = instance.exports; - } - - const ptr0 = passStringToWasm0(svg, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - return wasm.rgba(ptr, ptr0, WASM_VECTOR_LEN, fit_kind, zoom, width, height); - }, - /** - * @param {number} id - * @returns {Uint32Array} - */ - meta(id) { - try { - const retptr = wasm.__wbindgen_export_2.value - 16; - wasm.__wbindgen_export_2.value = retptr; - wasm.meta(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU32FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 4); - return v0; - } finally { - wasm.__wbindgen_export_2.value += 16; - } - }, - /** - * @param {number} id - * @returns {Uint8Array} - */ - buffer(id) { - try { - const retptr = wasm.__wbindgen_export_2.value - 16; - wasm.__wbindgen_export_2.value = retptr; - wasm.buffer(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1); - return v0; - } finally { - wasm.__wbindgen_export_2.value += 16; - } - }, - /** - * @param {number} id - */ - free(id) { - wasm.free(id); - } -}; \ No newline at end of file diff --git a/utils/wasm/svg.wasm b/utils/wasm/svg.wasm deleted file mode 100644 index 988be8c..0000000 Binary files a/utils/wasm/svg.wasm and /dev/null differ diff --git a/utils/wasm/tiff.js b/utils/wasm/tiff.js index 3ffdc59..e4b7446 100644 --- a/utils/wasm/tiff.js +++ b/utils/wasm/tiff.js @@ -1,108 +1,47 @@ -const {readFile} = require('fs').promises; -const {join} = require('path'); +const { version } = require('../../package.json'); -let wasm; - -let cachegetUint8Memory0 = null; - -function getUint8Memory0() { - if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { - cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachegetUint8Memory0; -} - -let WASM_VECTOR_LEN = 0; - -function passArray8ToWasm0(arg, malloc) { - const ptr = malloc(arg.length * 1); - getUint8Memory0().set(arg, ptr / 1); - WASM_VECTOR_LEN = arg.length; - return ptr; -} +let mod = null; +module.exports = { + async init() { + if (!mod) { + const streaming = 'compileStreaming' in WebAssembly; + mod = await WebAssembly[!streaming ? 'compile' : 'compileStreaming'](await fetch(`https://unpkg.com/imagescript@${version}/wasm/any/tiff.wasm`).then(x => streaming ? x : x.arrayBuffer())); + }; -let cachegetInt32Memory0 = null; + return this.new(); + }, -function getInt32Memory0() { - if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { - cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachegetInt32Memory0; -} + new() { + const wasm = new WebAssembly.Instance(mod).exports; -let cachegetUint32Memory0 = null; + class mem { + static length() { return wasm.wlen(); } + static alloc(size) { return wasm.walloc(size); } + static free(ptr, size) { return wasm.wfree(ptr, size); } + static u8(ptr, size) { return new Uint8Array(wasm.memory.buffer, ptr, size); } + static u32(ptr, size) { return new Uint32Array(wasm.memory.buffer, ptr, size); } -function getUint32Memory0() { - if (cachegetUint32Memory0 === null || cachegetUint32Memory0.buffer !== wasm.memory.buffer) { - cachegetUint32Memory0 = new Uint32Array(wasm.memory.buffer); - } - return cachegetUint32Memory0; -} + static copy_and_free(ptr, size) { + let slice = mem.u8(ptr, size).slice(); + return (wasm.wfree(ptr, size), slice); + } + } -function getArrayU32FromWasm0(ptr, len) { - return getUint32Memory0().subarray(ptr / 4, ptr / 4 + len); -} + function decode(buffer) { + const bptr = mem.alloc(buffer.length); + mem.u8(bptr, buffer.length).set(buffer); + const ptr = wasm.decode(bptr, buffer.length); + if (0 === ptr) throw new Error('tiff: failed to decode'); -function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); -} + const framebuffer = { + width: wasm.decode_width(ptr), + height: wasm.decode_height(ptr), + buffer: mem.u8(wasm.decode_buffer(ptr), mem.length()).slice(), + } -module.exports = { - /** - * @param {number} ptr - * @param {Uint8Array} buffer - * @returns {number} - */ - async decode(ptr, buffer) { - if (!wasm) { - const module = new WebAssembly.Module(await readFile(join(__dirname, './tiff.wasm'))); - const instance = new WebAssembly.Instance(module); - wasm = instance.exports; + return (wasm.decode_free(ptr), framebuffer); } - const ptr0 = passArray8ToWasm0(buffer, wasm.__wbindgen_malloc); - return wasm.decode(ptr, ptr0, WASM_VECTOR_LEN); + return { decode }; }, - /** - * @param {number} id - * @returns {Uint32Array} - */ - meta(id) { - try { - const retptr = wasm.__wbindgen_export_1.value - 16; - wasm.__wbindgen_export_1.value = retptr; - wasm.meta(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU32FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 4); - return v0; - } finally { - wasm.__wbindgen_export_1.value += 16; - } - }, - /** - * @param {number} id - * @returns {Uint8Array} - */ - buffer(id) { - try { - const retptr = wasm.__wbindgen_export_1.value - 16; - wasm.__wbindgen_export_1.value = retptr; - wasm.buffer(retptr, id); - const r0 = getInt32Memory0()[retptr / 4]; - const r1 = getInt32Memory0()[retptr / 4 + 1]; - const v0 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1); - return v0; - } finally { - wasm.__wbindgen_export_1.value += 16; - } - }, - /** - * @param {number} id - */ - free(id) { - wasm.free(id); - } -} \ No newline at end of file +} diff --git a/utils/wasm/tiff.wasm b/utils/wasm/tiff.wasm deleted file mode 100644 index d38d869..0000000 Binary files a/utils/wasm/tiff.wasm and /dev/null differ diff --git a/utils/wasm/zlib.js b/utils/wasm/zlib.js deleted file mode 100644 index c763626..0000000 --- a/utils/wasm/zlib.js +++ /dev/null @@ -1,73 +0,0 @@ -const {join} = require('path'); -const {promises: {readFile}} = require('fs'); - -async function load() { - let wasm; - - { - const module = new WebAssembly.Module(await readFile(join(__dirname, './zlib.wasm'))); - const instance = new WebAssembly.Instance(module); - - wasm = instance.exports; - } - - let u8array_ref = new Uint8Array(wasm.memory.buffer); - let i32array_ref = new Int32Array(wasm.memory.buffer); - - function u8array() { - return u8array_ref.buffer === wasm.memory.buffer ? u8array_ref : (u8array_ref = new Uint8Array(wasm.memory.buffer)); - } - - function i32array() { - return i32array_ref.buffer === wasm.memory.buffer ? i32array_ref : (i32array_ref = new Int32Array(wasm.memory.buffer)); - } - - function ptr_to_u8array(ptr, len) { - return u8array().subarray(ptr, ptr + len); - } - - function u8array_to_ptr(buffer) { - const ptr = wasm.__wbindgen_malloc(buffer.length); - u8array().set(buffer, ptr); - return ptr; - } - - return { - compress(buffer, level) { - const ptr = u8array_to_ptr(buffer); - wasm.compress(8, ptr, buffer.length, level); - - const i32 = i32array(); - const slice = ptr_to_u8array(i32[2], i32[3]).slice(); - wasm.__wbindgen_free(i32[2], i32[3]); - return slice; - }, decompress(buffer, limit) { - const ptr = u8array_to_ptr(buffer); - - try { - wasm.decompress(8, ptr, buffer.length, limit); - - const i32 = i32array(); - const slice = ptr_to_u8array(i32[2], i32[3]).slice(); - wasm.__wbindgen_free(i32[2], i32[3]); - return slice; - } catch { - wasm.__wbindgen_free(ptr, buffer.length); - throw new Error('zlib: panic'); - } - } - }; -} - -module.exports = { - async compress(buffer, level) { - const {compress} = module.exports = await load(); - - return compress(buffer, level); - }, - async decompress(buffer, limit) { - const {decompress} = module.exports = await load(); - - return decompress(buffer, limit); - } -}; \ No newline at end of file diff --git a/utils/wasm/zlib.wasm b/utils/wasm/zlib.wasm deleted file mode 100644 index 8332f68..0000000 Binary files a/utils/wasm/zlib.wasm and /dev/null differ diff --git a/utils/zlib.js b/utils/zlib.js new file mode 100644 index 0000000..3367764 --- /dev/null +++ b/utils/zlib.js @@ -0,0 +1,622 @@ +// node_modules/fflate/esm/browser.js +// https://github.com/101arrowz/fflate + +// MIT License + +// Copyright (c) 2020 Arjun Barrett + +// 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. + + +var u8 = Uint8Array; +var u16 = Uint16Array; +var u32 = Uint32Array; +var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0]); +var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0]); +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + var r = new u32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = j - b[i] << 5 | i; + } + } + return [b, r]; +}; +var _a = freb(fleb, 2); +var fl = _a[0]; +var revfl = _a[1]; +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0); +var fd = _b[0]; +var revfd = _b[1]; +var rev = new u16(32768); +for (var i = 0; i < 32768; ++i) { + x = (i & 43690) >>> 1 | (i & 21845) << 1; + x = (x & 52428) >>> 2 | (x & 13107) << 2; + x = (x & 61680) >>> 4 | (x & 3855) << 4; + rev[i] = ((x & 65280) >>> 8 | (x & 255) << 8) >>> 1; +} +var x; +var hMap = function (cd, mb, r) { + var s = cd.length; + var i = 0; + var l = new u16(mb); + for (; i < s; ++i) + ++l[cd[i] - 1]; + var le = new u16(mb); + for (i = 0; i < mb; ++i) { + le[i] = le[i - 1] + l[i - 1] << 1; + } + var co; + if (r) { + co = new u16(1 << mb); + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + if (cd[i]) { + var sv = i << 4 | cd[i]; + var r_1 = mb - cd[i]; + var v = le[cd[i] - 1]++ << r_1; + for (var m = v | (1 << r_1) - 1; v <= m; ++v) { + co[rev[v] >>> rvb] = sv; + } + } + } + } else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >>> 15 - cd[i]; + } + } + } + return co; +}; +var flt = new u8(288); +for (var i = 0; i < 144; ++i) + flt[i] = 8; +for (var i = 144; i < 256; ++i) + flt[i] = 9; +for (var i = 256; i < 280; ++i) + flt[i] = 7; +for (var i = 280; i < 288; ++i) + flt[i] = 8; +var fdt = new u8(32); +for (var i = 0; i < 32; ++i) + fdt[i] = 5; +var flm = hMap(flt, 9, 0); +var flrm = hMap(flt, 9, 1); +var fdm = hMap(fdt, 5, 0); +var fdrm = hMap(fdt, 5, 1); +var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +var bits = function (d, p, m) { + var o = p >> 3 | 0; + return (d[o] | d[o + 1] << 8) >> (p & 7) & m; +}; +var bits16 = function (d, p) { + var o = p >> 3 | 0; + return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7); +}; +var shft = function (p) { + return (p >> 3 | 0) + (p & 7 && 1); +}; +var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + var n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s); + n.set(v.subarray(s, e)); + return n; +}; +var inflt = function (dat, buf, st) { + var sl = dat.length; + if (!sl || st && !st.l && sl < 5) + return buf || new u8(0); + var noBuf = !buf || st; + var noSt = !st || st.i; + if (!st) + st = {}; + if (!buf) + buf = new u8(sl * 3); + var cbuf = function (l2) { + var bl = buf.length; + if (l2 > bl) { + var nbuf = new u8(Math.max(bl * 2, l2)); + nbuf.set(buf); + buf = nbuf; + } + }; + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + var tbts = sl * 8; + do { + if (!lm) { + st.f = final = bits(dat, pos, 1); + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l; + if (t > sl) { + if (noSt) + throw "unexpected EOF"; + break; + } + if (noBuf) + cbuf(bt + l); + buf.set(dat.subarray(s, t), bt); + st.b = bt += l, st.p = pos = t * 8; + continue; + } else if (type === 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type === 2) { + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + var ldt = new u8(tl); + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + var clb = max(clt), clbmsk = (1 << clb) - 1; + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + pos += r & 15; + var s = r >>> 4; + if (s < 16) { + ldt[i++] = s; + } else { + var c = 0, n = 0; + if (s === 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s === 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s === 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + lbt = max(lt); + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } else + throw "invalid block type"; + if (pos > tbts) { + if (noSt) + throw "unexpected EOF"; + break; + } + } + if (noBuf) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (; ; lpos = pos) { + var c = lm[bits16(dat, pos) & lms], sym = c >>> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + throw "unexpected EOF"; + break; + } + if (!c) + throw "invalid length/literal"; + if (sym < 256) + buf[bt++] = sym; + else if (sym === 256) { + lpos = pos, lm = null; + break; + } else { + var add = sym - 254; + if (sym > 264) { + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4; + if (!d) + throw "invalid distance"; + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + throw "unexpected EOF"; + break; + } + if (noBuf) + cbuf(bt + 131072); + var end = bt + add; + for (; bt < end; bt += 4) { + buf[bt] = buf[bt - dt]; + buf[bt + 1] = buf[bt + 1 - dt]; + buf[bt + 2] = buf[bt + 2 - dt]; + buf[bt + 3] = buf[bt + 3 - dt]; + } + bt = end; + } + } + st.l = lm, st.p = lpos, st.b = bt; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + return bt === buf.length ? buf : slc(buf, 0, bt); +}; +var wbits = function (d, p, v) { + v <<= p & 7; + var o = p >> 3 | 0; + d[o] |= v; + d[o + 1] |= v >>> 8; +}; +var wbits16 = function (d, p, v) { + v <<= p & 7; + var o = p >> 3 | 0; + d[o] |= v; + d[o + 1] |= v >>> 8; + d[o + 2] |= v >>> 16; +}; +var hTree = function (d, mb) { + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return [et, 0]; + if (s === 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return [v, 1]; + } + t.sort(function (a, b) { + return a.f - b.f; + }); + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l, r }; + while (i1 !== s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 !== i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l, r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + var tr = new u16(maxSym + 1); + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + var i = 0, dt = 0; + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function (a, b) { + return tr[b.s] - tr[a.s] || a.f - b.f; + }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << mbt - tr[i2_1]); + tr[i2_1] = mb; + } else + break; + } + dt >>>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << mb - tr[i2_2]++ - 1; + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] === mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return [new u8(tr), mbt]; +}; +var ln = function (n, l, d) { + return n.s === -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d; +}; +var lc = function (c) { + var s = c.length; + while (s && !c[--s]) + ; + var cl = new u16(++s); + var cli = 0, cln = c[0], cls = 1; + var w = function (v) { + cl[cli++] = v; + }; + for (var i = 1; i <= s; ++i) { + if (c[i] === cln && i !== s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305); + cls = 0; + } + } else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(cls - 3 << 5 | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return [cl.subarray(0, cli), s]; +}; +var clen = function (cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +var wfblk = function (out, pos, dat) { + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >>> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +var wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a2 = hTree(lf, 15), dlt = _a2[0], mlb = _a2[1]; + var _b2 = hTree(df, 15), ddt = _b2[0], mdb = _b2[1]; + var _c = lc(dlt), lclt = _c[0], nlc = _c[1]; + var _d = lc(ddt), lcdt = _d[0], ndc = _d[1]; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + lcfreq[lclt[i] & 31]++; + for (var i = 0; i < lcdt.length; ++i) + lcfreq[lcdt[i] & 31]++; + var _e = hTree(lcfreq, 7), lct = _e[0], mlcb = _e[1]; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = bl + 5 << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + (2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]); + if (flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, clct[i] >>> 5 & 127), p += clct[i] >>> 12; + } + } + } else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + if (syms[i] > 255) { + var len = syms[i] >>> 18 & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, syms[i] >>> 23 & 31), p += fleb[len]; + var dst = syms[i] & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, syms[i] >>> 5 & 8191), p += fdeb[dst]; + } else { + wbits16(out, p, lm[syms[i]]), p += ll[syms[i]]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +var deo = new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +var et = new u8(0); +var dflt = function (dat, lvl, plvl, pre, post, lst) { + var s = dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post); + var w = o.subarray(pre, o.length - post); + var pos = 0; + if (!lvl || s < 8) { + for (var i = 0; i <= s; i += 65535) { + var e = i + 65535; + if (e < s) { + pos = wfblk(w, pos, dat.subarray(i, e)); + } else { + w[i] = lst; + pos = wfblk(w, pos, dat.subarray(i, s)); + } + } + } else { + var opt = deo[lvl - 1]; + var n = opt >>> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + var prev = new u16(32768), head = new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function (i2) { + return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1; + }; + var syms = new u32(25e3); + var lf = new u16(288), df = new u16(32); + var lc_1 = 0, eb = 0, i = 0, li = 0, wi = 0, bs = 0; + for (; i < s; ++i) { + var hv = hsh(i); + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + if (wi <= i) { + var rem = s - i; + if ((lc_1 > 7e3 || li > 24576) && rem > 423) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv === hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod !== pimod) { + if (dat[i + l] === dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] === dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + if (nl > maxn) + break; + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j + 32768 & 32767; + var pti = prev[ti]; + var cd = ti - pti + 32768 & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + imod = pimod, pimod = prev[imod]; + dif += imod - pimod + 32768 & 32767; + } + } + if (d) { + syms[li++] = 268435456 | revfl[l] << 18 | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst && pos & 7) + pos = wfblk(w, pos + 1, et); + } + return slc(o, 0, pre + shft(pos) + post); +}; +var adler = function () { + var a = 1, b = 0; + return { + p: function (d) { + var n = a, m = b; + var l = d.length | 0; + for (var i = 0; i !== l;) { + var e = Math.min(i + 2655, l); + for (; i < e; ++i) + m += n += d[i]; + n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16); + } + a = n, b = m; + }, + d: function () { + a %= 65521, b %= 65521; + return (a & 255) << 24 | a >>> 8 << 16 | (b & 255) << 8 | b >>> 8; + } + }; +}; +var dopt = function (dat, opt, pre, post, st) { + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 12 + opt.mem, pre, post, !st); +}; +var wbytes = function (d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +var zlh = function (c, o) { + var lv = o.level, fl2 = lv === 0 ? 0 : lv < 6 ? 1 : lv === 9 ? 3 : 2; + c[0] = 120, c[1] = fl2 << 6 | (fl2 ? 32 - 2 * fl2 : 1); +}; +var zlv = function (d) { + if ((d[0] & 15) !== 8 || d[0] >>> 4 > 7 || (d[0] << 8 | d[1]) % 31) + throw "invalid zlib data"; + if (d[1] & 32) + throw "invalid zlib data: preset dictionaries not supported"; +}; +function zlibSync(data, opts) { + if (!opts) + opts = {}; + var a = adler(); + a.p(data); + var d = dopt(data, opts, 2, 4); + return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d; +} +function unzlibSync(data, out) { + return inflt((zlv(data), data.subarray(2, -4)), out); +} + +// bundle.js +function compress(buf, level) { + return zlibSync(buf, { level }); +} + +function decompress(buf, limit) { + return unzlibSync(buf, new Uint8Array(limit)); +} + +module.exports = { + compress, + decompress +}; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..40d4491 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,12 @@ +const path = require('path'); + +module.exports = { + entry: './ImageScript.js', + output: { + library: 'ImageScript', + libraryTarget: 'umd', + path: path.resolve('./browser'), + filename: 'ImageScript.js' + }, + devtool: 'source-map' +};