@napi-rs/canvas 0.1.83 → 0.1.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -619,6 +619,121 @@ export interface AvifConfig {
619
619
  /** set to '4:2:0' to use chroma subsampling, default '4:4:4' */
620
620
  chromaSubsampling?: ChromaSubsampling
621
621
  }
622
+
623
+ /** GIF encoding configuration for single-frame encoding */
624
+ export interface GifConfig {
625
+ /**
626
+ * Quality for NeuQuant color quantization (1-30, lower = slower but better quality)
627
+ * @default 10
628
+ */
629
+ quality?: number
630
+ }
631
+
632
+ /** Configuration for the GIF encoder (animated GIFs) */
633
+ export interface GifEncoderConfig {
634
+ /**
635
+ * Loop count: 0 = infinite loop, positive number = finite loops
636
+ * @default 0 (infinite)
637
+ */
638
+ repeat?: number
639
+ /**
640
+ * Quality for NeuQuant color quantization (1-30, lower = slower but better quality)
641
+ * @default 10
642
+ */
643
+ quality?: number
644
+ }
645
+
646
+ /** Configuration for individual GIF frames */
647
+ export interface GifFrameConfig {
648
+ /**
649
+ * Frame delay in milliseconds
650
+ * @default 100
651
+ */
652
+ delay?: number
653
+ /** Disposal method for this frame */
654
+ disposal?: GifDisposal
655
+ /** Transparent color index (0-255), if the frame has transparency */
656
+ transparent?: number
657
+ /** X offset of this frame within the canvas */
658
+ left?: number
659
+ /** Y offset of this frame within the canvas */
660
+ top?: number
661
+ }
662
+
663
+ /** GIF frame disposal method */
664
+ export enum GifDisposal {
665
+ /** Keep the frame visible (default) */
666
+ Keep = 0,
667
+ /** Clear the frame area to the background color */
668
+ Background = 1,
669
+ /** Restore to the previous frame */
670
+ Previous = 2,
671
+ }
672
+
673
+ /**
674
+ * GIF Encoder for creating animated GIFs.
675
+ * Implements `Disposable` interface for use with the `using` keyword (ES2024).
676
+ *
677
+ * @example
678
+ * ```typescript
679
+ * // Basic usage
680
+ * const encoder = new GifEncoder(100, 100, { repeat: 0, quality: 10 });
681
+ * encoder.addFrame(rgbaData, 100, 100, { delay: 100 });
682
+ * encoder.addFrame(rgbaData2, 100, 100, { delay: 100 });
683
+ * const buffer = encoder.finish();
684
+ *
685
+ * // With `using` keyword (automatic cleanup)
686
+ * {
687
+ * using encoder = new GifEncoder(100, 100);
688
+ * encoder.addFrame(frame1, 100, 100, { delay: 100 });
689
+ * const buffer = encoder.finish();
690
+ * } // encoder automatically disposed
691
+ * ```
692
+ */
693
+ export class GifEncoder implements Disposable {
694
+ /**
695
+ * Create a new GIF encoder with the specified dimensions
696
+ * @param width - Width of the GIF canvas in pixels
697
+ * @param height - Height of the GIF canvas in pixels
698
+ * @param config - Optional encoder configuration
699
+ */
700
+ constructor(width: number, height: number, config?: GifEncoderConfig)
701
+
702
+ /** Width of the GIF canvas */
703
+ readonly width: number
704
+ /** Height of the GIF canvas */
705
+ readonly height: number
706
+ /** Number of frames added so far */
707
+ readonly frameCount: number
708
+
709
+ /**
710
+ * Add a frame from RGBA pixel data
711
+ * @param data - RGBA pixel data (must be width * height * 4 bytes)
712
+ * @param width - Width of the frame in pixels
713
+ * @param height - Height of the frame in pixels
714
+ * @param config - Optional frame configuration
715
+ */
716
+ addFrame(data: Uint8Array, width: number, height: number, config?: GifFrameConfig): void
717
+
718
+ /**
719
+ * Finish encoding and return the GIF data.
720
+ * Clears all accumulated frames after encoding.
721
+ * @throws Error if no frames have been added
722
+ */
723
+ finish(): Buffer
724
+
725
+ /**
726
+ * Dispose of the encoder, clearing all accumulated frames without encoding.
727
+ * Called automatically when using the `using` keyword.
728
+ */
729
+ dispose(): void
730
+
731
+ /**
732
+ * Symbol.dispose implementation for ES2024 Explicit Resource Management.
733
+ * Allows using `using encoder = new GifEncoder(...)` syntax.
734
+ */
735
+ [Symbol.dispose](): void
736
+ }
622
737
  /**
623
738
  * https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling
624
739
  * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts
@@ -676,24 +791,29 @@ export class Canvas {
676
791
  encodeSync(format: 'webp' | 'jpeg', quality?: number): Buffer
677
792
  encodeSync(format: 'png'): Buffer
678
793
  encodeSync(format: 'avif', cfg?: AvifConfig): Buffer
794
+ encodeSync(format: 'gif', quality?: number): Buffer
679
795
  encode(format: 'webp' | 'jpeg', quality?: number): Promise<Buffer>
680
796
  encode(format: 'png'): Promise<Buffer>
681
797
  encode(format: 'avif', cfg?: AvifConfig): Promise<Buffer>
798
+ encode(format: 'gif', quality?: number): Promise<Buffer>
682
799
  encodeStream(format: 'webp' | 'jpeg', quality?: number): ReadableStream<Buffer>
683
800
  encodeStream(format: 'png'): ReadableStream<Buffer>
684
801
  toBuffer(mime: 'image/png'): Buffer
685
802
  toBuffer(mime: 'image/jpeg' | 'image/webp', quality?: number): Buffer
686
803
  toBuffer(mime: 'image/avif', cfg?: AvifConfig): Buffer
804
+ toBuffer(mime: 'image/gif', quality?: number): Buffer
687
805
  // raw pixels
688
806
  data(): Buffer
689
807
  toDataURL(mime?: 'image/png'): string
690
808
  toDataURL(mime: 'image/jpeg' | 'image/webp', quality?: number): string
691
- toDataURL(mime?: 'image/jpeg' | 'image/webp' | 'image/png', quality?: number): string
809
+ toDataURL(mime: 'image/gif', quality?: number): string
810
+ toDataURL(mime?: 'image/jpeg' | 'image/webp' | 'image/png' | 'image/gif', quality?: number): string
692
811
  toDataURL(mime?: 'image/avif', cfg?: AvifConfig): string
693
812
 
694
813
  toDataURLAsync(mime?: 'image/png'): Promise<string>
695
814
  toDataURLAsync(mime: 'image/jpeg' | 'image/webp', quality?: number): Promise<string>
696
- toDataURLAsync(mime?: 'image/jpeg' | 'image/webp' | 'image/png', quality?: number): Promise<string>
815
+ toDataURLAsync(mime: 'image/gif', quality?: number): Promise<string>
816
+ toDataURLAsync(mime?: 'image/jpeg' | 'image/webp' | 'image/png' | 'image/gif', quality?: number): Promise<string>
697
817
  toDataURLAsync(mime?: 'image/avif', cfg?: AvifConfig): Promise<string>
698
818
 
699
819
  toBlob(callback: (blob: Blob | null) => void, mime?: string, quality?: number): void
package/index.js CHANGED
@@ -17,12 +17,21 @@ const {
17
17
  StrokeCap,
18
18
  convertSVGTextToPath,
19
19
  PdfDocument,
20
+ GifEncoder,
21
+ GifDisposal,
20
22
  } = require('./js-binding')
21
23
 
22
24
  const { DOMPoint, DOMMatrix, DOMRect } = require('./geometry')
23
25
 
24
26
  const loadImage = require('./load-image')
25
27
 
28
+ // Add Symbol.dispose support for GifEncoder (ECMAScript 2024 Explicit Resource Management)
29
+ if (GifEncoder && typeof Symbol.dispose !== 'undefined') {
30
+ GifEncoder.prototype[Symbol.dispose] = function () {
31
+ this.dispose()
32
+ }
33
+ }
34
+
26
35
  const SvgExportFlag = {
27
36
  ConvertTextToPaths: 0x01,
28
37
  NoPrettyXML: 0x02,
@@ -178,4 +187,7 @@ module.exports = {
178
187
  CanvasElement,
179
188
  SVGCanvas,
180
189
  PDFDocument: PdfDocument,
190
+ // GIF encoding
191
+ GifEncoder,
192
+ GifDisposal,
181
193
  }
package/js-binding.js CHANGED
@@ -460,3 +460,5 @@ module.exports.PathOp = nativeBinding.PathOp
460
460
  module.exports.StrokeCap = nativeBinding.StrokeCap
461
461
  module.exports.StrokeJoin = nativeBinding.StrokeJoin
462
462
  module.exports.SvgExportFlag = nativeBinding.SvgExportFlag
463
+ module.exports.GifEncoder = nativeBinding.GifEncoder
464
+ module.exports.GifDisposal = nativeBinding.GifDisposal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@napi-rs/canvas",
3
- "version": "0.1.83",
3
+ "version": "0.1.84",
4
4
  "description": "Canvas for Node.js with skia backend",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -77,7 +77,7 @@
77
77
  "@jimp/png": "^0.22.12",
78
78
  "@napi-rs/cli": "^3.1.1",
79
79
  "@octokit/rest": "^22.0.0",
80
- "@oxc-node/core": "^0.0.34",
80
+ "@oxc-node/core": "^0.0.35",
81
81
  "@taplo/cli": "^0.7.0",
82
82
  "@types/lodash": "^4.17.17",
83
83
  "@types/node": "^24.0.0",
@@ -102,7 +102,7 @@
102
102
  "semver": "^7.7.2",
103
103
  "skia-canvas": "^3.0.0",
104
104
  "table": "^6.9.0",
105
- "tinybench": "^5.0.0",
105
+ "tinybench": "^6.0.0",
106
106
  "typescript": "^5.8.3"
107
107
  },
108
108
  "lint-staged": {
@@ -142,15 +142,15 @@
142
142
  },
143
143
  "packageManager": "yarn@4.12.0",
144
144
  "optionalDependencies": {
145
- "@napi-rs/canvas-linux-x64-gnu": "0.1.83",
146
- "@napi-rs/canvas-darwin-x64": "0.1.83",
147
- "@napi-rs/canvas-win32-x64-msvc": "0.1.83",
148
- "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.83",
149
- "@napi-rs/canvas-linux-x64-musl": "0.1.83",
150
- "@napi-rs/canvas-linux-arm64-gnu": "0.1.83",
151
- "@napi-rs/canvas-linux-arm64-musl": "0.1.83",
152
- "@napi-rs/canvas-darwin-arm64": "0.1.83",
153
- "@napi-rs/canvas-android-arm64": "0.1.83",
154
- "@napi-rs/canvas-linux-riscv64-gnu": "0.1.83"
145
+ "@napi-rs/canvas-linux-x64-gnu": "0.1.84",
146
+ "@napi-rs/canvas-darwin-x64": "0.1.84",
147
+ "@napi-rs/canvas-win32-x64-msvc": "0.1.84",
148
+ "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.84",
149
+ "@napi-rs/canvas-linux-x64-musl": "0.1.84",
150
+ "@napi-rs/canvas-linux-arm64-gnu": "0.1.84",
151
+ "@napi-rs/canvas-linux-arm64-musl": "0.1.84",
152
+ "@napi-rs/canvas-darwin-arm64": "0.1.84",
153
+ "@napi-rs/canvas-android-arm64": "0.1.84",
154
+ "@napi-rs/canvas-linux-riscv64-gnu": "0.1.84"
155
155
  }
156
156
  }