imagescript 3.2.1 → 3.4.0

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.
Files changed (101) hide show
  1. package/README.md +35 -10
  2. package/THIRD_PARTY_NOTICES.md +298 -2
  3. package/dist/animation.d.ts +25 -8
  4. package/dist/animation.js +44 -13
  5. package/dist/codecs/av1/cdef.js +197 -0
  6. package/dist/codecs/av1/data.js +141 -0
  7. package/dist/codecs/av1/decode.js +1769 -0
  8. package/dist/codecs/av1/filmgrain.js +219 -0
  9. package/dist/codecs/av1/frame.js +114 -0
  10. package/dist/codecs/av1/ipred.js +491 -0
  11. package/dist/codecs/av1/itx.js +950 -0
  12. package/dist/codecs/av1/loopfilter.js +149 -0
  13. package/dist/codecs/av1/msac.js +161 -0
  14. package/dist/codecs/av1/obu.js +516 -0
  15. package/dist/codecs/av1/postfilter.js +28 -0
  16. package/dist/codecs/av1/restoration.js +193 -0
  17. package/dist/codecs/av1/tables.js +160 -0
  18. package/dist/codecs/avif.js +581 -0
  19. package/dist/codecs/bmp.js +317 -0
  20. package/dist/codecs/crc.js +5 -0
  21. package/dist/codecs/gif.js +10 -35
  22. package/dist/codecs/hdr.d.ts +25 -0
  23. package/dist/codecs/hdr.js +201 -0
  24. package/dist/codecs/ico.js +48 -0
  25. package/dist/codecs/jpeg.js +11 -28
  26. package/dist/codecs/jxl/bits.js +126 -0
  27. package/dist/codecs/jxl/blend.js +117 -0
  28. package/dist/codecs/jxl/color.js +116 -0
  29. package/dist/codecs/jxl/dct.js +404 -0
  30. package/dist/codecs/jxl/entropy.js +556 -0
  31. package/dist/codecs/jxl/features.js +325 -0
  32. package/dist/codecs/jxl/filters.js +119 -0
  33. package/dist/codecs/jxl/frame-header.js +195 -0
  34. package/dist/codecs/jxl/frame.js +319 -0
  35. package/dist/codecs/jxl/headers.js +249 -0
  36. package/dist/codecs/jxl/idct.js +484 -0
  37. package/dist/codecs/jxl/modular.js +688 -0
  38. package/dist/codecs/jxl/quant.js +219 -0
  39. package/dist/codecs/jxl/upsample.js +52 -0
  40. package/dist/codecs/jxl/vardct.js +472 -0
  41. package/dist/codecs/jxl.js +89 -0
  42. package/dist/codecs/netpbm.js +239 -0
  43. package/dist/codecs/png.js +22 -10
  44. package/dist/codecs/qoi.js +150 -0
  45. package/dist/codecs/tga.js +3 -1
  46. package/dist/codecs/tiff.js +7 -2
  47. package/dist/codecs/vp8-enc-dsp.js +932 -0
  48. package/dist/codecs/vp8-enc-tables.js +78 -0
  49. package/dist/codecs/vp8-enc.js +1930 -0
  50. package/dist/codecs/vp8.js +3 -1
  51. package/dist/codecs/vp8l.js +126 -58
  52. package/dist/codecs/webp.js +47 -11
  53. package/dist/codecs/zlib.js +81 -69
  54. package/dist/frame.d.ts +1 -0
  55. package/dist/frame.js +4 -2
  56. package/dist/gif.d.ts +1 -0
  57. package/dist/gif.js +2 -2
  58. package/dist/image-type.d.ts +15 -1
  59. package/dist/image-type.js +45 -2
  60. package/dist/image.d.ts +89 -13
  61. package/dist/image.js +266 -113
  62. package/dist/index.d.ts +3 -2
  63. package/dist/index.js +4 -4
  64. package/dist/render/bidi.js +350 -0
  65. package/dist/render/buffer.js +362 -0
  66. package/dist/render/color.js +164 -0
  67. package/dist/render/colr.js +523 -0
  68. package/dist/render/font.js +173 -241
  69. package/dist/render/hinting.js +38 -22
  70. package/dist/render/layout.js +1553 -0
  71. package/dist/render/linebreak.js +210 -0
  72. package/dist/render/segment.js +106 -0
  73. package/dist/render/shape.js +984 -0
  74. package/dist/render/shapers/arabic.js +284 -0
  75. package/dist/render/shapers/hangul.js +142 -0
  76. package/dist/render/shapers/hebrew.js +49 -0
  77. package/dist/render/shapers/index.js +52 -0
  78. package/dist/render/shapers/indic.js +579 -0
  79. package/dist/render/shapers/khmer.js +104 -0
  80. package/dist/render/shapers/machine.js +129 -0
  81. package/dist/render/shapers/myanmar.js +121 -0
  82. package/dist/render/shapers/syllabic.js +100 -0
  83. package/dist/render/shapers/thai.js +125 -0
  84. package/dist/render/shapers/use.js +235 -0
  85. package/dist/render/svg.js +102 -23
  86. package/dist/render/text.js +373 -103
  87. package/dist/render/unicode-data.js +63 -0
  88. package/dist/render/unicode.js +50 -0
  89. package/dist/text-layout.d.ts +4 -1
  90. package/dist/text-layout.js +2 -2
  91. package/dist/util/alpha.js +43 -0
  92. package/dist/util/blur.js +20 -33
  93. package/dist/util/bytes.js +40 -0
  94. package/dist/util/limits.js +34 -0
  95. package/dist/util/options.js +7 -0
  96. package/dist/util/resample.js +126 -7
  97. package/dist/util/rotate.js +43 -0
  98. package/dist/version.js +1 -1
  99. package/licenses/HarfBuzz.txt +42 -0
  100. package/licenses/Unicode-3.0.txt +39 -0
  101. package/package.json +25 -2
package/dist/gif.js CHANGED
@@ -13,10 +13,10 @@ export class GIF extends Animation {
13
13
  return this.encodeGIF(qualityOrOptions);
14
14
  }
15
15
  static async decode(input, onlyFirstFrameOrOptions = false) {
16
- const onlyExtractFirstFrame = isOptions(onlyFirstFrameOrOptions) ? onlyFirstFrameOrOptions.onlyFirstFrame ?? false : onlyFirstFrameOrOptions;
16
+ const { onlyFirstFrame = false, maxPixels } = isOptions(onlyFirstFrameOrOptions) ? onlyFirstFrameOrOptions : { onlyFirstFrame: onlyFirstFrameOrOptions };
17
17
  const data = view(input);
18
18
  if (!ImageType.isGIF(new DataView(data.buffer, data.byteOffset, data.byteLength)))
19
19
  throw new Error('Unsupported image type');
20
- return Animation.__fromGIF__(data, onlyExtractFirstFrame, GIF);
20
+ return Animation.__fromGIF__(data, onlyFirstFrame, GIF, maxPixels);
21
21
  }
22
22
  }
@@ -1,6 +1,6 @@
1
1
  import { BinaryData } from './util/mem.js';
2
2
  /** Image formats recognized by {@link ImageType.getType} */
3
- export type ImageTypeName = 'png' | 'jpeg' | 'tiff' | 'gif' | 'webp' | 'tga';
3
+ export type ImageTypeName = 'png' | 'jpeg' | 'tiff' | 'gif' | 'webp' | 'avif' | 'jxl' | 'bmp' | 'ico' | 'cur' | 'qoi' | 'pnm' | 'hdr' | 'tga';
4
4
  /** Detects image formats by their magic numbers */
5
5
  export declare class ImageType {
6
6
  private constructor();
@@ -20,6 +20,20 @@ export declare class ImageType {
20
20
  static isGIF(data: BinaryData): boolean;
21
21
  /** Whether the data starts like a WebP */
22
22
  static isWebP(data: BinaryData): boolean;
23
+ /** Whether the data starts like an AVIF (the avif or avis brand) */
24
+ static isAVIF(data: BinaryData): boolean;
25
+ /** Whether the data starts like a JPEG XL (a codestream or the container) */
26
+ static isJXL(data: BinaryData): boolean;
27
+ /** Whether the data starts like a BMP */
28
+ static isBMP(data: BinaryData): boolean;
29
+ /** Whether the data is a Windows icon or cursor (ICO or CUR) */
30
+ static isICO(data: BinaryData): boolean;
31
+ /** Whether the data starts like a QOI */
32
+ static isQOI(data: BinaryData): boolean;
33
+ /** Whether the data starts like a Netpbm image (PBM, PGM, PPM, PAM or PFM) */
34
+ static isPNM(data: BinaryData): boolean;
35
+ /** Whether the data starts like a Radiance HDR */
36
+ static isHDR(data: BinaryData): boolean;
23
37
  /** Whether the data looks like a TGA (which has no magic number: its header has to be consistent) */
24
38
  static isTGA(data: BinaryData): boolean;
25
39
  }
@@ -1,5 +1,12 @@
1
1
  import { view as bytes } from "./util/mem.js";
2
2
  import { isTGA } from "./codecs/tga.js";
3
+ import { isBMP } from "./codecs/bmp.js";
4
+ import { iconType } from "./codecs/ico.js";
5
+ import { isQOI } from "./codecs/qoi.js";
6
+ import { isNetpbm } from "./codecs/netpbm.js";
7
+ import { isHDR } from "./codecs/hdr.js";
8
+ import { isAVIF } from "./codecs/avif.js";
9
+ import { isJXL } from "./codecs/jxl.js";
3
10
  const MAGIC_NUMBERS = {
4
11
  PNG: 0x89504e47,
5
12
  JPEG: 0xffd8ff,
@@ -17,6 +24,7 @@ function dataView(data) {
17
24
  const u8 = bytes(data);
18
25
  return new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
19
26
  }
27
+ const u8 = (view) => new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
20
28
  export class ImageType {
21
29
  constructor() { }
22
30
  static getType(data) {
@@ -31,6 +39,21 @@ export class ImageType {
31
39
  return 'gif';
32
40
  if (this.isWebP(view))
33
41
  return 'webp';
42
+ if (this.isAVIF(view))
43
+ return 'avif';
44
+ if (this.isJXL(view))
45
+ return 'jxl';
46
+ if (this.isBMP(view))
47
+ return 'bmp';
48
+ const icon = iconType(u8(view));
49
+ if (icon)
50
+ return icon;
51
+ if (this.isQOI(view))
52
+ return 'qoi';
53
+ if (this.isPNM(view))
54
+ return 'pnm';
55
+ if (this.isHDR(view))
56
+ return 'hdr';
34
57
  if (this.isTGA(view))
35
58
  return 'tga';
36
59
  return null;
@@ -58,8 +81,28 @@ export class ImageType {
58
81
  const view = dataView(data);
59
82
  return view.byteLength >= 12 && view.getUint32(0, false) === MAGIC_NUMBERS.RIFF && view.getUint32(8, false) === MAGIC_NUMBERS.WEBP;
60
83
  }
84
+ static isAVIF(data) {
85
+ return isAVIF(u8(dataView(data)));
86
+ }
87
+ static isJXL(data) {
88
+ return isJXL(u8(dataView(data)));
89
+ }
90
+ static isBMP(data) {
91
+ return isBMP(u8(dataView(data)));
92
+ }
93
+ static isICO(data) {
94
+ return iconType(u8(dataView(data))) !== null;
95
+ }
96
+ static isQOI(data) {
97
+ return isQOI(u8(dataView(data)));
98
+ }
99
+ static isPNM(data) {
100
+ return isNetpbm(u8(dataView(data)));
101
+ }
102
+ static isHDR(data) {
103
+ return isHDR(u8(dataView(data)));
104
+ }
61
105
  static isTGA(data) {
62
- const view = dataView(data);
63
- return isTGA(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
106
+ return isTGA(u8(dataView(data)));
64
107
  }
65
108
  }
package/dist/image.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ToneMapping } from './codecs/hdr.js';
1
2
  import { BinaryData } from './util/mem.js';
2
3
  import { TextLayout } from './text-layout.js';
3
4
  import { Metadata } from './metadata.js';
@@ -26,6 +27,15 @@ export interface CompositeOptions {
26
27
  export interface ResizeOptions {
27
28
  /** The resizing mode. Default: {@link Image.RESIZE_BILINEAR} */
28
29
  mode?: ResizeMode;
30
+ /**
31
+ * Whether to round to 8 bits between the two passes, so two channels share the multiplications of both: about
32
+ * 15-25% faster for opaque images, with 10-25% of the channel values a step off the precise result (instead of
33
+ * about 1%, never more than 1). Transparent images are premultiplied to 8 bits like browsers do, which makes them
34
+ * about twice as fast: what shows once they're composited differs by up to about 2 steps, pixels that are almost
35
+ * transparent keep less of their color. Only affects {@link Image.RESIZE_BILINEAR} and {@link Image.RESIZE_AREA},
36
+ * down to about a third of the size. Default: `true`
37
+ */
38
+ fast?: boolean;
29
39
  }
30
40
  /**
31
41
  * Options of {@link Image.opacity}, {@link Image.red}, {@link Image.green}, {@link Image.blue}, {@link Image.lightness}
@@ -56,7 +66,23 @@ export interface JPEGEncodeOptions {
56
66
  /** Metadata to include, see {@link Metadata} */
57
67
  metadata?: Metadata;
58
68
  }
59
- /** Options of {@link Image.encodeWebP} and {@link Image.encodeTGA} */
69
+ /** Options of {@link Image.encodeWebP} */
70
+ export interface WebPEncodeOptions {
71
+ /**
72
+ * Lossy compression (0-100, like libwebp's quality: 75 is its default): the image is encoded like cwebp encodes it
73
+ * with its default settings, much smaller than lossless. Without it the image is encoded losslessly
74
+ */
75
+ quality?: number;
76
+ /**
77
+ * How much effort lossy compression takes (0-6, libwebp's method): higher is smaller but slower. 0-2 pick the
78
+ * predictions by how close they are, 3 and up also by how many bits they take, 5 and 6 also optimize the
79
+ * quantized values. Default: `4` (like cwebp)
80
+ */
81
+ effort?: number;
82
+ /** Metadata to include, see {@link Metadata} */
83
+ metadata?: Metadata;
84
+ }
85
+ /** Options of {@link Image.encodeTGA} */
60
86
  export interface EncodeOptions {
61
87
  /** Metadata to include, see {@link Metadata} */
62
88
  metadata?: Metadata;
@@ -92,6 +118,19 @@ export interface TextOptions extends TextStyle {
92
118
  export interface DecodeOptions {
93
119
  /** Whether to rotate/mirror JPEGs, TIFFs, PNGs and WebPs as their orientation tag (Exif or XMP) says. Default: `true` */
94
120
  applyOrientation?: boolean;
121
+ /**
122
+ * The most pixels to decode: larger images throw a RangeError before anything that size is allocated, so small
123
+ * files declaring huge images (decompression bombs) can't exhaust the memory. Default: `268402689` (16383², like
124
+ * sharp), `Infinity` for no limit
125
+ */
126
+ maxPixels?: number;
127
+ /**
128
+ * How Radiance HDRs, PFMs and HDR (PQ or HLG) AVIFs and JPEG XLs, whose light can be brighter than (SDR) white,
129
+ * become 8 bit sRGB: `'reinhard'` compresses the brightest parts like Reinhard's tone mapping operator does (the
130
+ * brightest pixel becomes white, images no brighter than white stay as they are), `'clamp'` clamps everything
131
+ * brighter than white. Default: `'reinhard'`
132
+ */
133
+ toneMapping?: ToneMapping;
95
134
  }
96
135
  /** Text style options of {@link Image.renderText} */
97
136
  export interface TextStyle {
@@ -126,6 +165,13 @@ export interface DominantColorOptions {
126
165
  export interface RotateOptions {
127
166
  /** Whether to resize the image so it fits all pixels or just ignore outlying pixels. Default: `true` */
128
167
  resize?: boolean;
168
+ /**
169
+ * Whether to sample with 8-bit weights on 8-bit premultiplied pixels (like {@link ResizeOptions.fast}), about twice
170
+ * as fast: opaque pixels stay within a step of the precise result, what shows of translucent ones (also the
171
+ * faded edges) within about 2.5 steps (pixels that are almost transparent keep less of their color). Only affects
172
+ * angles that aren't multiples of 90°. Default: `true`
173
+ */
174
+ fast?: boolean;
129
175
  }
130
176
  /** Options of {@link Image.trim} */
131
177
  export interface TrimOptions {
@@ -165,9 +211,7 @@ export declare class Image {
165
211
  get bitmap(): Uint8ClampedArray;
166
212
  /** Replaces the pixel data, the array has to hold width * height * 4 bytes */
167
213
  set bitmap(bitmap: Uint8ClampedArray | Uint8Array);
168
- /**
169
- * @private
170
- */
214
+ /** A short description for debugging, e.g. `Image<64x64>` */
171
215
  toString(): string;
172
216
  /**
173
217
  * The images width
@@ -669,7 +713,16 @@ export declare class Image {
669
713
  * Encodes the image into a PNG, an alias of {@link Image.encode}
670
714
  */
671
715
  encodePNG(options?: PNGEncodeOptions): Promise<Uint8Array>;
716
+ /**
717
+ * Encodes the image into a PNG, an alias of {@link Image.encode}
718
+ * @param compression The compression level (0-9). Default: `1`
719
+ * @param metadata Metadata to include, see {@link Metadata}
720
+ */
672
721
  encodePNG(compression?: number, metadata?: Metadata): Promise<Uint8Array>;
722
+ /**
723
+ * Encodes the image into a PNG, an alias of {@link Image.encode}
724
+ * @param metadata Metadata to include, see {@link Metadata}
725
+ */
673
726
  encodePNG(metadata?: Metadata): Promise<Uint8Array>;
674
727
  /**
675
728
  * Encodes the image into a JPEG
@@ -682,18 +735,35 @@ export declare class Image {
682
735
  */
683
736
  encodeJPEG(quality?: number): Promise<Uint8Array>;
684
737
  /**
685
- * Encodes the image as lossless WebP (usually 20-30% smaller than PNG, but slower to encode)
686
- * @param options See {@link EncodeOptions}
738
+ * Encodes the image as WebP: lossless (usually 20-30% smaller than PNG, but slower to encode), or lossy with a
739
+ * quality
740
+ * @param options See {@link WebPEncodeOptions}
687
741
  */
688
- encodeWebP({ metadata }?: EncodeOptions): Promise<Uint8Array>;
742
+ encodeWebP({ quality, effort, metadata }?: WebPEncodeOptions): Promise<Uint8Array>;
689
743
  /**
690
744
  * Encodes the image as run length encoded TGA (32 bit, or 24 bit if the image is opaque)
691
745
  * @param options See {@link EncodeOptions}
692
746
  */
693
747
  encodeTGA({ metadata }?: EncodeOptions): Promise<Uint8Array>;
694
748
  /**
695
- * Decodes an image (PNG, JPEG, TIFF, WebP or TGA). For APNGs this is the default image; animated WebPs and GIFs
696
- * have no single image, decode those with {@link Animation.decode}
749
+ * Encodes the image as BMP: with a palette if it is opaque and has at most 256 colors, else with 24 bit pixels, or
750
+ * 32 bit ones if it has transparency
751
+ */
752
+ encodeBMP(): Promise<Uint8Array>;
753
+ /**
754
+ * Encodes the image as QOI (3 channels if the image is opaque)
755
+ */
756
+ encodeQOI(): Promise<Uint8Array>;
757
+ /**
758
+ * Encodes the image as the smallest fitting Netpbm format: PBM for black and white images, PGM for greyscale ones,
759
+ * PPM for others, PAM if the image has transparency
760
+ */
761
+ encodePNM(): Promise<Uint8Array>;
762
+ /**
763
+ * Decodes an image (PNG, JPEG, TIFF, WebP, BMP, ICO, CUR, QOI, PBM, PGM, PPM, PAM, PFM, Radiance HDR, TGA, AVIF or
764
+ * JPEG XL). For APNGs this is the default image; animated WebPs and GIFs have no single image, decode those with
765
+ * {@link Animation.decode}; for icons and cursors it's their largest image, for AVIF image sequences and JPEG XL
766
+ * animations their first frame
697
767
  * @param input The binary data to decode
698
768
  * @param options See {@link DecodeOptions}. JPEGs, TIFFs and PNGs are rotated/mirrored as their orientation tag
699
769
  * (Exif, for PNGs also XMP) says by default: photos taken with a rotated camera are stored sideways
@@ -731,17 +801,23 @@ export declare class Image {
731
801
  static renderSVG(svg: string | BinaryData, size?: number, mode?: SVGScaleMode): Promise<Image>;
732
802
  /**
733
803
  * Creates a new image containing the rendered text.
734
- * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use
804
+ * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use, or several by priority: every character
805
+ * comes from the first font that has it (e.g. `[text, emoji]`), the first one sets the line height. Color
806
+ * glyphs (COLR layers and paints, CBDT and sbix bitmaps, as in emoji fonts) keep their colors. Text in any script
807
+ * is shaped like browsers do (right to left and bidirectional text, Arabic joining, Indic conjuncts, marks)
735
808
  * @param size Font size in pixels (per em)
736
809
  * @param text Text to render
737
810
  * @param options Color, layout and style, see {@link TextOptions}; the image grows by the outline width on every
738
811
  * side
739
812
  * @return The rendered text
740
813
  */
741
- static renderText(font: BinaryData, size: number, text: string, options?: TextOptions): Promise<Image>;
814
+ static renderText(font: BinaryData | BinaryData[], size: number, text: string, options?: TextOptions): Promise<Image>;
742
815
  /**
743
816
  * Creates a new image containing the rendered text.
744
- * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use
817
+ * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use, or several by priority: every character
818
+ * comes from the first font that has it (e.g. `[text, emoji]`), the first one sets the line height. Color
819
+ * glyphs (COLR layers and paints, CBDT and sbix bitmaps, as in emoji fonts) keep their colors. Text in any script
820
+ * is shaped like browsers do (right to left and bidirectional text, Arabic joining, Indic conjuncts, marks)
745
821
  * @param size Font size in pixels (per em)
746
822
  * @param text Text to render
747
823
  * @param [color=0xffffffff] Text color to use
@@ -749,5 +825,5 @@ export declare class Image {
749
825
  * @param style Outline, see {@link TextStyle}; the image grows by the outline width on every side
750
826
  * @return The rendered text
751
827
  */
752
- static renderText(font: BinaryData, size: number, text: string, color?: Color, layout?: TextLayout, style?: TextStyle): Promise<Image>;
828
+ static renderText(font: BinaryData | BinaryData[], size: number, text: string, color?: Color, layout?: TextLayout, style?: TextStyle): Promise<Image>;
753
829
  }