imagescript 1.3.0 → 1.3.1

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 (32) hide show
  1. package/ImageScript.d.ts +862 -143
  2. package/ImageScript.js +4 -4
  3. package/package.json +1 -1
  4. package/codecs/tests/gif.js +0 -0
  5. package/codecs/tests/jpeg.js +0 -0
  6. package/codecs/tests/png.js +0 -0
  7. package/codecs/tests/results/gif/1024.nis.gif +0 -0
  8. package/codecs/tests/results/gif/1024.skyra.gif +0 -0
  9. package/codecs/tests/results/gif/256.nis.gif +0 -0
  10. package/codecs/tests/results/gif/256.skyra.gif +0 -0
  11. package/codecs/tests/results/jpeg/256.jpegjs.jpeg +0 -0
  12. package/codecs/tests/results/jpeg/256.nis.jpeg +0 -0
  13. package/codecs/tests/results/jpeg/256.sharp.jpeg +0 -0
  14. package/codecs/tests/results/jpeg/512.jpegjs.jpeg +0 -0
  15. package/codecs/tests/results/jpeg/512.nis.jpeg +0 -0
  16. package/codecs/tests/results/jpeg/512.sharp.jpeg +0 -0
  17. package/codecs/tests/results/jpeg/64.jpegjs.jpeg +0 -0
  18. package/codecs/tests/results/jpeg/64.nis.jpeg +0 -0
  19. package/codecs/tests/results/jpeg/64.sharp.jpeg +0 -0
  20. package/codecs/tests/results/png/256.jis.png +0 -0
  21. package/codecs/tests/results/png/256.nis.png +0 -0
  22. package/codecs/tests/results/png/256.sharp.png +0 -0
  23. package/codecs/tests/results/png/256.upng.png +0 -0
  24. package/codecs/tests/results/png/512.jis.png +0 -0
  25. package/codecs/tests/results/png/512.nis.png +0 -0
  26. package/codecs/tests/results/png/512.sharp.png +0 -0
  27. package/codecs/tests/results/png/512.upng.png +0 -0
  28. package/codecs/tests/results/png/64.jis.png +0 -0
  29. package/codecs/tests/results/png/64.nis.png +0 -0
  30. package/codecs/tests/results/png/64.sharp.png +0 -0
  31. package/codecs/tests/results/png/64.upng.png +0 -0
  32. package/codecs/tests/webp.js +0 -0
package/ImageScript.d.ts CHANGED
@@ -8,16 +8,19 @@ export class Image {
8
8
 
9
9
  constructor(width: number, height: number);
10
10
 
11
- private toString(): string;
11
+ private toString(): `Image<${number}x${number}>`;
12
12
 
13
13
  get width(): number;
14
14
 
15
15
  get height(): number;
16
16
 
17
- * [Symbol.iterator](): void;
18
-
19
- * iterateWithColors(): Generator<[x: number, y: number, color: number], void, unknown>;
17
+ *[Symbol.iterator](): void;
20
18
 
19
+ *iterateWithColors(): Generator<
20
+ [x: number, y: number, color: number],
21
+ void,
22
+ unknown
23
+ >;
21
24
  static rgbaToColor(r: number, g: number, b: number, a: number): number;
22
25
 
23
26
  static rgbToColor(r: number, g: number, b: number): number;
@@ -36,7 +39,7 @@ export class Image {
36
39
 
37
40
  getRGBAAt(x: number, y: number): Uint8ClampedArray;
38
41
 
39
- setPixelAt(x: number, y: number, pixelColor: number): Image;
42
+ setPixelAt(x: number, y: number, pixelColor: number): this;
40
43
 
41
44
  private __set_pixel__(x: number, y: number, pixelColor: number): void;
42
45
 
@@ -44,169 +47,543 @@ export class Image {
44
47
 
45
48
  private static get __out_of_bounds__(): string;
46
49
 
47
- fill(color: number | colorFunction): Image;
50
+ /**
51
+ * Fills the entire image with the supplied color.
52
+ *
53
+ * @param color
54
+ */
55
+ fill(color: number | ColorFunction): this;
48
56
 
49
57
  clone(): Image;
50
58
 
51
- static get RESIZE_NEAREST_NEIGHBOR(): string;
52
-
53
- static get RESIZE_AUTO(): number;
54
-
55
- scale(factor: number, mode?: string): Image;
56
-
57
- private __scale__(factor: number, mode?: string);
58
-
59
- resize(width: number, height: number, mode?: string): Image;
60
-
61
- contain(width: number, height: number, mode?: string): Image;
62
-
63
- fit(width: number, height: number, mode?: string): Image;
64
-
65
- cover(width: number, height: number, mode?: string): Image;
66
-
67
- private __resize__(width: number, height: number, mode?: string): Image;
68
-
69
- private __resize_nearest_neighbor__(width: number, height: number): Image;
70
-
71
- crop(x: number, y: number, width: number, height: number): Image;
72
-
73
- private __crop__(x: number, y: number, width: number, height: number): Image;
74
-
75
- drawBox(x: number, y: number, width: number, height: number, color: number | colorFunction): Image;
76
-
77
- private __fast_box__(x: number, y: number, width: number, height: number, color: number): Image;
78
-
79
- drawCircle(x: number, y: number, radius: number, color: number | colorFunction): Image;
80
-
81
- cropCircle(max?: boolean, feathering?: number): Image;
82
-
83
- opacity(opacity: number, absolute?: boolean): Image;
84
-
85
- red(saturation: number, absolute?: boolean): Image;
86
-
87
- green(saturation: number, absolute?: boolean): Image;
88
-
89
- blue(saturation: number, absolute?: boolean): Image;
90
-
91
- private __set_channel_value__(value: number, absolute: boolean, offset: number): void;
92
-
93
- lightness(value: number, absolute?: boolean): Image;
94
-
95
- saturation(value: number, absolute?: boolean): Image;
96
-
97
- composite(source: Image, x?: number, y?: number): Image;
98
-
99
- invert(): Image;
100
-
101
- invertValue(): Image;
102
-
103
- invertSaturation(): Image;
104
-
105
- invertHue(): Image;
106
-
107
- hueShift(degrees: number): Image;
108
-
59
+ /**
60
+ * Use
61
+ * {@link https://en.wikipedia.org/wiki/Image_scaling#Nearest-neighbor_interpolation Nearest-neighbor}
62
+ * resizing.
63
+ */
64
+ static get RESIZE_NEAREST_NEIGHBOR(): "RESIZE_NEAREST_NEIGHBOR";
65
+
66
+ /**
67
+ * Used for automatically preserving an image's aspect ratio when resizing.
68
+ */
69
+ static get RESIZE_AUTO(): -1;
70
+
71
+ /**
72
+ * Resizes the image by the given factor.
73
+ *
74
+ * @param factor Fraction, where:
75
+ * - `0.5` is "50%" (half)
76
+ * - `1.0` is "100%" (same size)
77
+ * - `2.0` is "200%" (double)
78
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
79
+ */
80
+ scale(factor: number, mode?: ResizeMode): this;
81
+
82
+ private __scale__(factor: number, mode?: ResizeMode);
83
+
84
+ /**
85
+ * Resizes the image to the given dimensions.
86
+ * Use {@link Image.RESIZE_AUTO} as either width or height to automatically
87
+ * preserve the aspect ratio.
88
+ *
89
+ * @param width The new width.
90
+ * @param height The new height.
91
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
92
+ */
93
+ resize(width: number, height: number, mode?: ResizeMode): this;
94
+
95
+ /**
96
+ * Resizes the image so it is contained in the given bounding box.
97
+ * Can return an image with one axis smaller than the given bounding box.
98
+ *
99
+ * @param width The width of the bounding box
100
+ * @param height The height of the bounding box
101
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
102
+ */
103
+ contain(width: number, height: number, mode?: ResizeMode): this;
104
+
105
+ /**
106
+ * Resizes the image so it is contained in the given bounding box, placing it in the center of the given bounding box.
107
+ * Always returns the exact dimensions of the bounding box.
108
+ *
109
+ * @param width The width of the bounding box
110
+ * @param height The height of the bounding box
111
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
112
+ */
113
+ fit(width: number, height: number, mode?: ResizeMode): this;
114
+
115
+ /**
116
+ * Resizes the image so it covers the given bounding box, cropping the overflowing edges.
117
+ * Always returns the exact dimensions of the bounding box.
118
+ *
119
+ * @param width The width of the bounding box
120
+ * @param height The height of the bounding box
121
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
122
+ */
123
+ cover(width: number, height: number, mode?: ResizeMode): this;
124
+
125
+ private __resize__(width: number, height: number, mode?: ResizeMode): this;
126
+
127
+ private __resize_nearest_neighbor__(width: number, height: number): this;
128
+
129
+ crop(x: number, y: number, width: number, height: number): this;
130
+
131
+ private __crop__(x: number, y: number, width: number, height: number): this;
132
+
133
+ /**
134
+ * Draws a box at the specified coordinates.
135
+ */
136
+ drawBox(
137
+ x: number,
138
+ y: number,
139
+ width: number,
140
+ height: number,
141
+ color: number | ColorFunction
142
+ ): this;
143
+
144
+ private __fast_box__(
145
+ x: number,
146
+ y: number,
147
+ width: number,
148
+ height: number,
149
+ color: number
150
+ ): this;
151
+
152
+ /**
153
+ * Draws a circle at the specified coordinates with the specified radius.
154
+ */
155
+ drawCircle(
156
+ x: number,
157
+ y: number,
158
+ radius: number,
159
+ color: number | ColorFunction
160
+ ): this;
161
+
162
+ /**
163
+ * Crops the image into a circle.
164
+ *
165
+ * @param max Whether to use the larger dimension for the size. Default: `false`
166
+ * @param feathering How much feathering to apply to the edges. Default: `0`
167
+ */
168
+ cropCircle(max?: boolean, feathering?: number): this;
169
+
170
+ /**
171
+ * Sets the image's opacity.
172
+ *
173
+ * @param opacity `0`-`1`, where `0` is completely transparent and
174
+ * `1` is completely opaque.
175
+ * @param absolute Whether to scale the current opacity (`false`) or
176
+ * just set the new opacity (`true`). Default: `false`
177
+ */
178
+ opacity(opacity: number, absolute?: boolean): this;
179
+
180
+ /**
181
+ * Set the red channel's saturation value.
182
+ *
183
+ * @param saturation `0`-`1`
184
+ * @param absolute Whether to scale the current saturation (`false`) or
185
+ * just set the new saturation (`true`). Default: `false`
186
+ */
187
+ red(saturation: number, absolute?: boolean): this;
188
+
189
+ /**
190
+ * Set the green channel's saturation value.
191
+ *
192
+ * @param saturation `0`-`1`
193
+ * @param absolute Whether to scale the current saturation (`false`) or
194
+ * just set the new saturation (`true`). Default: `false`
195
+ */
196
+ green(saturation: number, absolute?: boolean): this;
197
+
198
+ /**
199
+ * Set the blue channel's saturation value.
200
+ *
201
+ * @param saturation `0`-`1`
202
+ * @param absolute Whether to scale the current saturation (`false`) or
203
+ * just set the new saturation (`true`). Default: `false`
204
+ */
205
+ blue(saturation: number, absolute?: boolean): this;
206
+
207
+ private __set_channel_value__(
208
+ value: number,
209
+ absolute: boolean,
210
+ offset: number
211
+ ): void;
212
+
213
+ /**
214
+ * Sets the brightness of the image.
215
+ *
216
+ * @param value `0`-`1`
217
+ * @param absolute Whether to scale the current lightness (`false`) or
218
+ * just set the new lightness (`true`). Default: `false`
219
+ */
220
+ lightness(value: number, absolute?: boolean): this;
221
+
222
+ /**
223
+ * Sets the saturation of the image.
224
+ *
225
+ * @param value `0`-`1`
226
+ * @param absolute Whether to scale the current saturation (`false`) or
227
+ * just set the new saturation (`true`). Default: `false`
228
+ */
229
+ saturation(value: number, absolute?: boolean): this;
230
+
231
+ /**
232
+ * Composites (overlays) the {@link source} onto this image at the
233
+ * specified coordinates.
234
+ */
235
+ composite(source: this, x?: number, y?: number): this;
236
+
237
+ /**
238
+ * Inverts the image's colors.
239
+ */
240
+ invert(): this;
241
+
242
+ /**
243
+ * Inverts the image's value (lightness).
244
+ */
245
+ invertValue(): this;
246
+
247
+ /**
248
+ * Inverts the image's saturation.
249
+ */
250
+ invertSaturation(): this;
251
+
252
+ /**
253
+ * Inverts the image's hue.
254
+ */
255
+ invertHue(): this;
256
+
257
+ /**
258
+ * Shifts the image's hue.
259
+ */
260
+ hueShift(degrees: number): this;
261
+
262
+ /**
263
+ * Gets the average color of the image.
264
+ */
109
265
  averageColor(): number;
110
266
 
111
- dominantColor(ignoreBlack?: boolean, ignoreWhite?: boolean, bwThreshold?: number): number;
112
-
113
- rotate(angle: number, resize?: boolean): Image;
114
-
115
- flip(direction: 'horizontal' | 'vertical'): Image;
116
-
117
- private __apply__(image: Image | Frame): Image | Frame;
118
-
119
- static gradient(colors: { [position: number]: number; }): ((position: number) => number);
120
-
121
- roundCorners(radius?: number): Image;
267
+ /**
268
+ * Gets the image's dominant color.
269
+ *
270
+ * @param ignoreBlack Whether to ignore dark colors below the threshold.
271
+ * Default: `true`
272
+ * @param ignoreWhite Whether to ignore light colors above the threshold.
273
+ * Default: `true`
274
+ * @param bwThreshold The black/white threshold (`0`-`64`).
275
+ * Default: `0xf` (`15`)
276
+ */
277
+ dominantColor(
278
+ ignoreBlack?: boolean,
279
+ ignoreWhite?: boolean,
280
+ bwThreshold?: number
281
+ ): number;
282
+
283
+ /**
284
+ * Rotates the image the given amount of degrees.
285
+ *
286
+ * @param angle The angle to rotate the image for (in degrees)
287
+ * @param resize Whether to resize the image so it fits all pixels (`true`) or
288
+ * just ignore outlying pixels (`false`). Default: `true`
289
+ */
290
+ rotate(angle: number, resize?: boolean): this;
291
+
292
+ /**
293
+ * Flips / mirrors the image horizontally or vertically.
294
+ */
295
+ flip(direction: "horizontal" | "vertical"): this;
296
+
297
+ private __apply__(image: this | Frame): this | Frame;
298
+
299
+ /**
300
+ * Creates a multi-point gradient generator.
301
+ *
302
+ * @param colors The gradient points to use
303
+ * (e.g. `{0: 0xff0000ff, 1: 0x00ff00ff}`).
304
+ * @returns The gradient generator. The function argument is the position
305
+ * in the gradient (`0`-`1`).
306
+ */
307
+ static gradient(colors: {
308
+ [position: number]: number;
309
+ }): (position: number) => number;
310
+
311
+ /**
312
+ * Rounds the image's corners.
313
+ *
314
+ * @param radius Default: `min(width, height) / 4`
315
+ */
316
+ roundCorners(radius?: number): this;
122
317
 
123
318
  private static __gradient__(startColor: number, endColor: number): number;
124
319
 
125
- fisheye(radius?: number): Image;
126
-
127
- async encode(compression?: number, metadata?: PNGMetadata): Promise<Uint8Array>;
320
+ /**
321
+ * @param radius Default: `2`
322
+ */
323
+ fisheye(radius?: number): this;
324
+
325
+ /**
326
+ * Encodes the image into a PNG.
327
+ *
328
+ * @param compression `0`-`9`, where `0` is no compression and `9` is highest
329
+ * compression (default: `1`)
330
+ * @param metadata
331
+ */
332
+ async encode(
333
+ compression?: PNGCompressionLevel,
334
+ metadata?: PNGMetadata
335
+ ): Promise<Uint8Array>;
128
336
  async encode(metadata?: PNGMetadata): Promise<Uint8Array>;
129
337
 
130
- async encodeJPEG(quality?: number): Promise<Uint8Array>;
131
-
132
- async encodeWEBP(quality?: null | number): Promise<Uint8Array>;
133
-
134
- static async decode(data: Buffer | Uint8Array): Promise<Image>
135
-
136
- static get SVG_MODE_SCALE(): number;
137
-
138
- static get SVG_MODE_WIDTH(): number;
139
-
140
- static get SVG_MODE_HEIGHT(): number;
338
+ /**
339
+ * Encodes the image into a JPEG.
340
+ *
341
+ * @param quality `1`-`100`, where `1` is lowest quality (highest compression)
342
+ * and `100` is highest quality (lowest compression). Default: `90`
343
+ */
344
+ async encodeJPEG(quality?: JPEGQuality): Promise<Uint8Array>;
345
+
346
+ /**
347
+ * Encodes the image into a WEBP.
348
+ *
349
+ * @param quality `0`-`100`, or `null` for lossless. `0` is lowest quality
350
+ * (highest compression) and `100` is highest quality (lowest compression).
351
+ * Default: `null`
352
+ */
353
+ async encodeWEBP(quality?: null | WEBPQuality): Promise<Uint8Array>;
354
+
355
+ /**
356
+ * Decodes an image (PNG, JPEG or TIFF).
357
+ *
358
+ * @param data The binary data to decode
359
+ * @returns The decoded image
360
+ */
361
+ static async decode(data: Buffer | Uint8Array): Promise<Image>;
362
+
363
+ /**
364
+ * Scale the SVG by the given amount. For use with {@link Image.renderSVG}.
365
+ */
366
+ static get SVG_MODE_SCALE(): 1;
367
+
368
+ /**
369
+ * Scale the SVG to fit the given width. For use with {@link Image.renderSVG}.
370
+ */
371
+ static get SVG_MODE_WIDTH(): 2;
372
+
373
+ /**
374
+ * Scale the SVG to fit the given height. For use with {@link Image.renderSVG}.
375
+ */
376
+ static get SVG_MODE_HEIGHT(): 3;
377
+
378
+ /**
379
+ * Creates a new image from the given SVG.
380
+ *
381
+ * @param svg
382
+ * @param size
383
+ * @param mode {@link Image.SVG_MODE_SCALE}, {@link Image.SVG_MODE_WIDTH}, or
384
+ * {@link Image.SVG_MODE_HEIGHT}.
385
+ *
386
+ * @returns New bitmap image with the rendered {@link svg}.
387
+ */
388
+ static async renderSVG(
389
+ svg: string,
390
+ size?: number,
391
+ mode?: SVGScaleMode
392
+ ): Promise<Image>;
393
+
394
+ /**
395
+ * Creates a new image containing the rendered text.
396
+ *
397
+ * @param font TrueType (ttf/ttc) or OpenType (otf) font buffer to use.
398
+ * @param scale
399
+ * @param text
400
+ * @param color
401
+ * @param layout
402
+ *
403
+ * @returns New image with the rendered {@link text}.
404
+ */
405
+ static async renderText(
406
+ font: Uint8Array,
407
+ scale: number,
408
+ text: string,
409
+ color?: number,
410
+ layout?: TextLayout
411
+ ): Promise<Image>;
412
+ }
141
413
 
142
- static async renderSVG(svg: string, size?: number, mode?: number): Promise<Image>;
414
+ export type FrameDisposalModeName = "any" | "keep" | "previous" | "background";
143
415
 
144
- static async renderText(font: Uint8Array, scale: number, text: string, color?: number, layout?: TextLayout): Promise<Image>;
145
- };
416
+ export type FrameDisposalModeId = 0 | 1 | 2 | 3;
146
417
 
418
+ /**
419
+ * Represents a frame in a GIF.
420
+ */
147
421
  export class Frame extends Image {
148
- static get DISPOSAL_KEEP(): string;
149
-
150
- static get DISPOSAL_PREVIOUS(): string;
151
-
152
- static get DISPOSAL_BACKGROUND(): string
153
-
154
- private static __convert_disposal_mode__(mode: string | number): any;
155
-
156
- constructor(width: number, height: number, duration?: number, xOffset?: number, yOffset?: number, disposalMode?: typeof Frame.DISPOSAL_KEEP | string);
157
-
422
+ static get DISPOSAL_KEEP(): "keep";
423
+
424
+ static get DISPOSAL_PREVIOUS(): "previous";
425
+
426
+ static get DISPOSAL_BACKGROUND(): "background";
427
+
428
+ private static __convert_disposal_mode__(
429
+ mode: FrameDisposalModeName | FrameDisposalModeId
430
+ ): FrameDisposalModeId;
431
+
432
+ /**
433
+ * Creates a new, blank frame.
434
+ *
435
+ * @param width
436
+ * @param height
437
+ * @param duration Milliseconds (default: `100`)
438
+ * @param xOffset Offset on the X-axis (default: `0`)
439
+ * @param yOffset Offset on the y-axis (default: `0`)
440
+ * @param disposalMode The frame's disposal mode (default: `'keep'`)
441
+ */
442
+ constructor(
443
+ width: number,
444
+ height: number,
445
+ duration: number,
446
+ xOffset?: number,
447
+ yOffset?: number,
448
+ disposalMode?: FrameDisposalModeName | FrameDisposalModeId
449
+ );
450
+
451
+ /**
452
+ * Milliseconds.
453
+ */
158
454
  duration: number;
159
455
 
160
456
  xOffset: number;
161
457
 
162
458
  yOffset: number;
163
459
 
164
- get disposalMode(): number;
165
-
166
- set disposalMode(disposalMode: string|number);
167
-
168
- toString(): string;
169
-
170
- static from(image: Image, duration?: number, xOffset?: number, yOffset?: number, disposalMode?: typeof Frame.DISPOSAL_KEEP | string): Frame;
171
-
172
- resize(width: number, height: number, mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string): Image;
173
- };
460
+ get disposalMode(): FrameDisposalModeId;
461
+
462
+ set disposalMode(disposalMode: FrameDisposalModeName | FrameDisposalModeId);
463
+
464
+ toString(): `Frame<${number}x${number}x${number}ms>`;
465
+
466
+ /**
467
+ * Converts an Image instance to a Frame, cloning it in the process
468
+ * @param image The image to create the frame from
469
+ * @param duration Milliseconds (default: `100`)
470
+ * @param xOffset Offset on the X-axis (default: `0`)
471
+ * @param yOffset Offset on the y-axis (default: `0`)
472
+ * @param disposalMode The frame's disposal mode (default: `'keep'`)
473
+ */
474
+ static from(
475
+ image: Image,
476
+ duration?: number,
477
+ xOffset?: number,
478
+ yOffset?: number,
479
+ disposalMode?: FrameDisposalModeName | FrameDisposalModeId
480
+ ): Frame;
481
+
482
+ /**
483
+ * @param width
484
+ * @param height
485
+ * @param mode Default: {@link Frame.DISPOSAL_KEEP}
486
+ */
487
+ resize(
488
+ width: number,
489
+ height: number,
490
+ mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string
491
+ ): Image;
492
+ }
174
493
 
175
- export class GIF extends Array {
494
+ /**
495
+ * Represents a GIF image as an array of frames.
496
+ */
497
+ export class GIF extends Array<Frame> {
498
+ /**
499
+ * @param frames
500
+ * @param loopCount How many times to loop the GIF for (`-1` = unlimited).
501
+ */
176
502
  constructor(frames: Frame[], loopCount?: number);
177
503
 
178
504
  get width(): number;
179
505
 
180
506
  get height(): number;
181
507
 
182
- toString(): string;
508
+ toString(): `GIF<${number}x${number}x${number}ms>`;
183
509
 
184
- * [Symbol.iterator](): Generator<Frame, void, *>
510
+ *[Symbol.iterator](): Generator<Frame, void, *>;
185
511
 
186
512
  slice(start: number, end: number): GIF;
187
513
 
514
+ /**
515
+ * Milliseconds.
516
+ */
188
517
  get duration(): number;
189
518
 
190
- async encode(quality?: number): Promise<Uint8Array>
519
+ /**
520
+ * @param quality GIF quality `0`-`100` (default: `95`)
521
+ */
522
+ async encode(quality?: GIFQuality): Promise<Uint8Array>;
523
+
524
+ /**
525
+ * @param data
526
+ * @param onlyExtractFirstFrame Whether to end GIF decoding after the first
527
+ * frame (default: `false`)
528
+ */
529
+ static async decode(
530
+ data: Buffer | Uint8Array,
531
+ onlyExtractFirstFrame?: boolean
532
+ ): Promise<GIF>;
533
+
534
+ /**
535
+ * @param width
536
+ * @param height
537
+ * @param mode Default: {@link Image.RESIZE_NEAREST_NEIGHBOR}
538
+ */
539
+ resize(width: number, height: number, mode?: ResizeMode): void;
540
+ }
191
541
 
192
- static async decode(data: Buffer | Uint8Array, onlyExtractFirstFrame?: boolean): Promise<GIF>;
542
+ export type WrapStyle = "word" | "char";
193
543
 
194
- resize(width: number, height: number, mode?: typeof Image.RESIZE_NEAREST_NEIGHBOR | string): void;
195
- }
544
+ export type VerticalAlign = "left" | "center" | "right";
545
+
546
+ export type HorizontalAlign = "top" | "middle" | "bottom";
196
547
 
197
548
  export class TextLayout {
549
+ /**
550
+ * @param options Defaults:
551
+ * ```js
552
+ * {
553
+ * maxWidth: Infinity,
554
+ * maxHeight: Infinity,
555
+ * wrapStyle: 'word',
556
+ * verticalAlign: 'left',
557
+ * horizontalAlign: 'top',
558
+ * wrapHardBreaks: true,
559
+ * }
560
+ * ```
561
+ */
198
562
  constructor(options?: {
199
- maxWidth?: number,
200
- maxHeight?: number,
201
- wrapStyle?: string,
202
- verticalAlign?: string,
203
- horizontalAlign?: string,
204
- wrapHardBreaks?: boolean
563
+ /** @default Infinity */
564
+ maxWidth?: number;
565
+
566
+ /** @default Infinity */
567
+ maxHeight?: number;
568
+
569
+ /** @default 'word' */
570
+ wrapStyle?: WrapStyle;
571
+
572
+ /** @default 'left' */
573
+ verticalAlign?: VerticalAlign;
574
+
575
+ /** @default 'top' */
576
+ horizontalAlign?: HorizontalAlign;
577
+
578
+ /** @default true */
579
+ wrapHardBreaks?: boolean;
205
580
  });
206
- };
581
+ }
582
+
583
+ export type ImageTypeName = "png" | "jpeg" | "tiff" | "gif";
207
584
 
208
585
  export class ImageType {
209
- static getType(data: Buffer | Uint8Array): string | null;
586
+ static getType(data: Buffer | Uint8Array): ImageTypeName | null;
210
587
 
211
588
  static isPNG(view: DataView): boolean;
212
589
 
@@ -215,21 +592,363 @@ export class ImageType {
215
592
  static isTIFF(view: DataView): boolean;
216
593
 
217
594
  static isGIF(view: DataView): boolean;
218
- };
595
+ }
219
596
 
220
- export function decode(data: Uint8Array | Buffer, onlyExtractFirstFrame?: boolean): Promise<GIF | Image>;
221
-
222
- type colorFunction = (x: number, y: number) => number;
223
-
224
- type PNGMetadata = {
225
- title?: string,
226
- author?: string,
227
- description?: string,
228
- copyright?: string,
229
- creationTime?: string | number | Date,
230
- software?: string,
231
- disclaimer?: string,
232
- warning?: string,
233
- source?: string,
234
- comment?: string
597
+ /**
598
+ * @param data
599
+ * @param onlyExtractFirstFrame Whether to end GIF decoding after the first
600
+ * frame (default: `false`)
601
+ */
602
+ export function decode(
603
+ data: Uint8Array | Buffer,
604
+ onlyExtractFirstFrame?: boolean
605
+ ): Promise<GIF | Image>;
606
+
607
+ export type PNGMetadata = {
608
+ title?: string;
609
+ author?: string;
610
+ description?: string;
611
+ copyright?: string;
612
+ creationTime?: string | number | Date;
613
+ software?: string;
614
+ disclaimer?: string;
615
+ warning?: string;
616
+ source?: string;
617
+ comment?: string;
235
618
  };
619
+
620
+ export type ColorFunction = (x: number, y: number) => number;
621
+
622
+ export type ResizeMode = "RESIZE_NEAREST_NEIGHBOR" | -1;
623
+
624
+ /**
625
+ * - `0` = no compression
626
+ * - `9` = highest compression
627
+ */
628
+ export type PNGCompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
629
+
630
+ /**
631
+ * {@link Image.SVG_MODE_SCALE}, {@link Image.SVG_MODE_WIDTH}, or
632
+ * {@link Image.SVG_MODE_HEIGHT}.
633
+ */
634
+ export type SVGScaleMode = 1 | 2 | 3;
635
+
636
+ /**
637
+ * - `0` = **lowest** quality (smallest file size)
638
+ * - `100` = **highest** quality (largest file size)
639
+ */
640
+ export type WEBPQuality =
641
+ | 0
642
+ | 1
643
+ | 2
644
+ | 3
645
+ | 4
646
+ | 5
647
+ | 6
648
+ | 7
649
+ | 8
650
+ | 9
651
+ | 10
652
+ | 11
653
+ | 12
654
+ | 13
655
+ | 14
656
+ | 15
657
+ | 16
658
+ | 17
659
+ | 18
660
+ | 19
661
+ | 20
662
+ | 21
663
+ | 22
664
+ | 23
665
+ | 24
666
+ | 25
667
+ | 26
668
+ | 27
669
+ | 28
670
+ | 29
671
+ | 30
672
+ | 31
673
+ | 32
674
+ | 33
675
+ | 34
676
+ | 35
677
+ | 36
678
+ | 37
679
+ | 38
680
+ | 39
681
+ | 40
682
+ | 41
683
+ | 42
684
+ | 43
685
+ | 44
686
+ | 45
687
+ | 46
688
+ | 47
689
+ | 48
690
+ | 49
691
+ | 50
692
+ | 51
693
+ | 52
694
+ | 53
695
+ | 54
696
+ | 55
697
+ | 56
698
+ | 57
699
+ | 58
700
+ | 59
701
+ | 60
702
+ | 61
703
+ | 62
704
+ | 63
705
+ | 64
706
+ | 65
707
+ | 66
708
+ | 67
709
+ | 68
710
+ | 69
711
+ | 70
712
+ | 71
713
+ | 72
714
+ | 73
715
+ | 74
716
+ | 75
717
+ | 76
718
+ | 77
719
+ | 78
720
+ | 79
721
+ | 80
722
+ | 81
723
+ | 82
724
+ | 83
725
+ | 84
726
+ | 85
727
+ | 86
728
+ | 87
729
+ | 88
730
+ | 89
731
+ | 90
732
+ | 91
733
+ | 92
734
+ | 93
735
+ | 94
736
+ | 95
737
+ | 96
738
+ | 97
739
+ | 98
740
+ | 99
741
+ | 100;
742
+
743
+ /**
744
+ * - `0` = **lowest** quality (smallest file size)
745
+ * - `100` = **highest** quality (largest file size)
746
+ */
747
+ export type JPEGQuality =
748
+ | 1
749
+ | 2
750
+ | 3
751
+ | 4
752
+ | 5
753
+ | 6
754
+ | 7
755
+ | 8
756
+ | 9
757
+ | 10
758
+ | 11
759
+ | 12
760
+ | 13
761
+ | 14
762
+ | 15
763
+ | 16
764
+ | 17
765
+ | 18
766
+ | 19
767
+ | 20
768
+ | 21
769
+ | 22
770
+ | 23
771
+ | 24
772
+ | 25
773
+ | 26
774
+ | 27
775
+ | 28
776
+ | 29
777
+ | 30
778
+ | 31
779
+ | 32
780
+ | 33
781
+ | 34
782
+ | 35
783
+ | 36
784
+ | 37
785
+ | 38
786
+ | 39
787
+ | 40
788
+ | 41
789
+ | 42
790
+ | 43
791
+ | 44
792
+ | 45
793
+ | 46
794
+ | 47
795
+ | 48
796
+ | 49
797
+ | 50
798
+ | 51
799
+ | 52
800
+ | 53
801
+ | 54
802
+ | 55
803
+ | 56
804
+ | 57
805
+ | 58
806
+ | 59
807
+ | 60
808
+ | 61
809
+ | 62
810
+ | 63
811
+ | 64
812
+ | 65
813
+ | 66
814
+ | 67
815
+ | 68
816
+ | 69
817
+ | 70
818
+ | 71
819
+ | 72
820
+ | 73
821
+ | 74
822
+ | 75
823
+ | 76
824
+ | 77
825
+ | 78
826
+ | 79
827
+ | 80
828
+ | 81
829
+ | 82
830
+ | 83
831
+ | 84
832
+ | 85
833
+ | 86
834
+ | 87
835
+ | 88
836
+ | 89
837
+ | 90
838
+ | 91
839
+ | 92
840
+ | 93
841
+ | 94
842
+ | 95
843
+ | 96
844
+ | 97
845
+ | 98
846
+ | 99
847
+ | 100;
848
+
849
+ /**
850
+ * - `0` = **lowest** quality (smallest file size)
851
+ * - `100` = **highest** quality (largest file size)
852
+ */
853
+ export type GIFQuality =
854
+ | 0
855
+ | 1
856
+ | 2
857
+ | 3
858
+ | 4
859
+ | 5
860
+ | 6
861
+ | 7
862
+ | 8
863
+ | 9
864
+ | 10
865
+ | 11
866
+ | 12
867
+ | 13
868
+ | 14
869
+ | 15
870
+ | 16
871
+ | 17
872
+ | 18
873
+ | 19
874
+ | 20
875
+ | 21
876
+ | 22
877
+ | 23
878
+ | 24
879
+ | 25
880
+ | 26
881
+ | 27
882
+ | 28
883
+ | 29
884
+ | 30
885
+ | 31
886
+ | 32
887
+ | 33
888
+ | 34
889
+ | 35
890
+ | 36
891
+ | 37
892
+ | 38
893
+ | 39
894
+ | 40
895
+ | 41
896
+ | 42
897
+ | 43
898
+ | 44
899
+ | 45
900
+ | 46
901
+ | 47
902
+ | 48
903
+ | 49
904
+ | 50
905
+ | 51
906
+ | 52
907
+ | 53
908
+ | 54
909
+ | 55
910
+ | 56
911
+ | 57
912
+ | 58
913
+ | 59
914
+ | 60
915
+ | 61
916
+ | 62
917
+ | 63
918
+ | 64
919
+ | 65
920
+ | 66
921
+ | 67
922
+ | 68
923
+ | 69
924
+ | 70
925
+ | 71
926
+ | 72
927
+ | 73
928
+ | 74
929
+ | 75
930
+ | 76
931
+ | 77
932
+ | 78
933
+ | 79
934
+ | 80
935
+ | 81
936
+ | 82
937
+ | 83
938
+ | 84
939
+ | 85
940
+ | 86
941
+ | 87
942
+ | 88
943
+ | 89
944
+ | 90
945
+ | 91
946
+ | 92
947
+ | 93
948
+ | 94
949
+ | 95
950
+ | 96
951
+ | 97
952
+ | 98
953
+ | 99
954
+ | 100;
package/ImageScript.js CHANGED
@@ -1624,7 +1624,7 @@ class ImageType {
1624
1624
  * @returns {boolean}
1625
1625
  */
1626
1626
  static isPNG(view) {
1627
- return view.getUint32(0, false) === MAGIC_NUMBERS.PNG;
1627
+ return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.PNG;
1628
1628
  }
1629
1629
 
1630
1630
  /**
@@ -1632,7 +1632,7 @@ class ImageType {
1632
1632
  * @returns {boolean}
1633
1633
  */
1634
1634
  static isJPEG(view) {
1635
- return (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.JPEG;
1635
+ return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.JPEG;
1636
1636
  }
1637
1637
 
1638
1638
  /**
@@ -1640,7 +1640,7 @@ class ImageType {
1640
1640
  * @returns {boolean}
1641
1641
  */
1642
1642
  static isTIFF(view) {
1643
- return view.getUint32(0, false) === MAGIC_NUMBERS.TIFF;
1643
+ return view.byteLength >= 4 && view.getUint32(0, false) === MAGIC_NUMBERS.TIFF;
1644
1644
  }
1645
1645
 
1646
1646
  /**
@@ -1648,7 +1648,7 @@ class ImageType {
1648
1648
  * @returns {boolean}
1649
1649
  */
1650
1650
  static isGIF(view) {
1651
- return (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.GIF;
1651
+ return view.byteLength >= 4 && (view.getUint32(0, false) >>> 8) === MAGIC_NUMBERS.GIF;
1652
1652
  }
1653
1653
  }
1654
1654
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imagescript",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "zero-dependency javascript image manipulation",
5
5
  "main": "ImageScript.js",
6
6
  "types": "ImageScript.d.ts",
File without changes
File without changes
File without changes
Binary file
Binary file
File without changes