@twin.org/image 0.0.2-next.8 → 0.0.3-next.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.
@@ -1,1898 +0,0 @@
1
- 'use strict';
2
-
3
- var core = require('@twin.org/core');
4
-
5
- // Copyright 2024 IOTA Stiftung.
6
- // SPDX-License-Identifier: Apache-2.0.
7
- /* eslint-disable no-bitwise */
8
- /**
9
- * Class to represent a color.
10
- */
11
- class Color {
12
- /**
13
- * Runtime name for the class.
14
- * @internal
15
- */
16
- static _CLASS_NAME = "Color";
17
- /**
18
- * @internal
19
- */
20
- _alpha;
21
- /**
22
- * @internal
23
- */
24
- _red;
25
- /**
26
- * @internal
27
- */
28
- _green;
29
- /**
30
- * @internal
31
- */
32
- _blue;
33
- /**
34
- * Create a new instance of color.
35
- * @param alpha The alpha element of the color.
36
- * @param red The red element of the color.
37
- * @param green The green element of the color.
38
- * @param blue The blue element of the color.
39
- */
40
- constructor(alpha, red, green, blue) {
41
- core.Guards.number(Color._CLASS_NAME, "alpha", alpha);
42
- core.Guards.number(Color._CLASS_NAME, "red", red);
43
- core.Guards.number(Color._CLASS_NAME, "green", green);
44
- core.Guards.number(Color._CLASS_NAME, "blue", blue);
45
- if (alpha < 0 || alpha > 255) {
46
- throw new core.GeneralError(Color._CLASS_NAME, "range", {
47
- prop: "alpha",
48
- value: alpha
49
- });
50
- }
51
- if (red < 0 || red > 255) {
52
- throw new core.GeneralError(Color._CLASS_NAME, "range", {
53
- prop: "red",
54
- value: red
55
- });
56
- }
57
- if (green < 0 || green > 255) {
58
- throw new core.GeneralError(Color._CLASS_NAME, "range", {
59
- prop: "green",
60
- value: green
61
- });
62
- }
63
- if (blue < 0 || blue > 255) {
64
- throw new core.GeneralError(Color._CLASS_NAME, "range", {
65
- prop: "blue",
66
- value: blue
67
- });
68
- }
69
- this._alpha = alpha;
70
- this._red = red;
71
- this._green = green;
72
- this._blue = blue;
73
- }
74
- /**
75
- * Construct a color from a hex string.
76
- * @param hex The hex string to parse.
77
- * @returns The color.
78
- * @throws Error if the format is incorrect.
79
- */
80
- static fromHex(hex) {
81
- core.Guards.stringValue(Color._CLASS_NAME, "hex", hex);
82
- let alpha;
83
- let red;
84
- let green;
85
- let blue;
86
- if (/^#[\dA-Fa-f]{3}$/.test(hex)) {
87
- // #RGB
88
- alpha = "0xFF";
89
- red = hex.slice(1, 2).repeat(2);
90
- green = hex.slice(2, 3).repeat(2);
91
- blue = hex.slice(3, 4).repeat(2);
92
- }
93
- else if (/^#[\dA-Fa-f]{4}$/.test(hex)) {
94
- // #ARGB
95
- alpha = hex.slice(1, 2).repeat(2);
96
- red = hex.slice(2, 3).repeat(2);
97
- green = hex.slice(3, 4).repeat(2);
98
- blue = hex.slice(4, 5).repeat(2);
99
- }
100
- else if (/^#[\dA-Fa-f]{6}$/.test(hex)) {
101
- // #RRGGBB
102
- alpha = "0xFF";
103
- red = hex.slice(1, 3);
104
- green = hex.slice(3, 5);
105
- blue = hex.slice(5, 7);
106
- }
107
- else if (/^#[\dA-Fa-f]{8}$/.test(hex)) {
108
- // #AARRGGBB
109
- alpha = hex.slice(1, 3);
110
- red = hex.slice(3, 5);
111
- green = hex.slice(5, 7);
112
- blue = hex.slice(7, 9);
113
- }
114
- else {
115
- throw new core.GeneralError(Color._CLASS_NAME, "hex");
116
- }
117
- return new Color(Number.parseInt(alpha, 16), Number.parseInt(red, 16), Number.parseInt(green, 16), Number.parseInt(blue, 16));
118
- }
119
- /**
120
- * Coerce an unknown type to a color.
121
- * @param value The value to try and convert.
122
- * @returns The color if one can be created.
123
- */
124
- static coerce(value) {
125
- if (core.Is.object(value) &&
126
- core.Is.number(value._alpha) &&
127
- core.Is.number(value._red) &&
128
- core.Is.number(value._green) &&
129
- core.Is.number(value._blue)) {
130
- return new Color(value._alpha, value._red, value._green, value._blue);
131
- }
132
- else if (core.Is.stringValue(value) && value.startsWith("#")) {
133
- try {
134
- return Color.fromHex(value);
135
- }
136
- catch { }
137
- }
138
- }
139
- /**
140
- * Get the alpha element.
141
- * @returns The alpha element.
142
- */
143
- alpha() {
144
- return this._alpha;
145
- }
146
- /**
147
- * Get the red element.
148
- * @returns The red element.
149
- */
150
- red() {
151
- return this._red;
152
- }
153
- /**
154
- * Get the green element.
155
- * @returns The green element.
156
- */
157
- green() {
158
- return this._green;
159
- }
160
- /**
161
- * Get the blue element.
162
- * @returns The blue element.
163
- */
164
- blue() {
165
- return this._blue;
166
- }
167
- /**
168
- * Get color as argb.
169
- * @returns The color as argb.
170
- */
171
- argb() {
172
- return ((this._alpha << 24) | (this._red << 16) | (this._green << 8) | this._blue) >>> 0;
173
- }
174
- /**
175
- * Get color as rgba.
176
- * @returns The color as rgba.
177
- */
178
- rgba() {
179
- return ((this._red << 24) | (this._green << 16) | (this._blue << 8) | this._alpha) >>> 0;
180
- }
181
- /**
182
- * Get color as rgb text.
183
- * @returns The color as rgb.
184
- */
185
- rgbText() {
186
- return `rgb(${this._red},${this._green},${this._blue})`;
187
- }
188
- /**
189
- * Get color as rgba text.
190
- * @returns The color as rgba.
191
- */
192
- rgbaText() {
193
- return `rgba(${this._red},${this._green},${this._blue},${Math.round((this._alpha / 255) * 100) / 100})`;
194
- }
195
- /**
196
- * Get color as hex no alpha.
197
- * @returns The color as hex with no alpha component.
198
- */
199
- hex() {
200
- const red = `00${this._red.toString(16)}`.slice(-2);
201
- const green = `00${this._green.toString(16)}`.slice(-2);
202
- const blue = `00${this._blue.toString(16)}`.slice(-2);
203
- return `#${red}${green}${blue}`.toUpperCase();
204
- }
205
- /**
206
- * Get color as hex with alpha.
207
- * @returns The color as hex with with alpha component.
208
- */
209
- hexWithAlpha() {
210
- const alpha = `00${this._alpha.toString(16)}`.slice(-2);
211
- const red = `00${this._red.toString(16)}`.slice(-2);
212
- const green = `00${this._green.toString(16)}`.slice(-2);
213
- const blue = `00${this._blue.toString(16)}`.slice(-2);
214
- return `#${alpha}${red}${green}${blue}`.toUpperCase();
215
- }
216
- }
217
-
218
- // Copyright 2024 IOTA Stiftung.
219
- // SPDX-License-Identifier: Apache-2.0.
220
- /* eslint-disable no-bitwise */
221
- /* eslint-disable no-mixed-operators */
222
- /**
223
- * JPEG Encoder.
224
- * Based on JPEG encoder ported to JavaScript and optimized by Andreas Ritter.
225
- */
226
- class JpegEncoder {
227
- /**
228
- * Runtime name for the class.
229
- * @internal
230
- */
231
- static _CLASS_NAME = "JpegEncoder";
232
- /**
233
- * @internal
234
- */
235
- static _STD_DC_LUMINANCE_NR_CODES = [
236
- 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
237
- ];
238
- /**
239
- * @internal
240
- */
241
- static _STD_DC_LUMINANCE_VALUES = [
242
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
243
- ];
244
- /**
245
- * @internal
246
- */
247
- static _STD_AC_LUMINANCE_NR_CODES = [
248
- 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
249
- ];
250
- /**
251
- * @internal
252
- */
253
- static _STD_AC_LUMINANCE_VALUES = [
254
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
255
- 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
256
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
257
- 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
258
- 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
259
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
260
- 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
261
- 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
262
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
263
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
264
- 0xf9, 0xfa
265
- ];
266
- /**
267
- * @internal
268
- */
269
- static _STD_DC_CHROMINANCE_NR_CODES = [
270
- 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
271
- ];
272
- /**
273
- * @internal
274
- */
275
- static _STD_DC_CHROMINANCE_VALUES = [
276
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
277
- ];
278
- /**
279
- * @internal
280
- */
281
- static _STD_AC_CHROMINANCE_NR_CODES = [
282
- 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
283
- ];
284
- /**
285
- * @internal
286
- */
287
- static _STD_AC_CHROMINANCE_VALUES = [
288
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
289
- 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
290
- 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
291
- 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
292
- 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
293
- 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
294
- 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
295
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
296
- 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
297
- 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
298
- 0xf9, 0xfa
299
- ];
300
- /** @internal */
301
- static _SIG_ZAG = [
302
- 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11,
303
- 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
304
- 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63
305
- ];
306
- /**
307
- * @internal
308
- */
309
- _yTable;
310
- /**
311
- * @internal
312
- */
313
- _uvTable;
314
- /**
315
- * @internal
316
- */
317
- _fdTblY;
318
- /**
319
- * @internal
320
- */
321
- _fdTblUV;
322
- /**
323
- * @internal
324
- */
325
- _ydcHashTable;
326
- /**
327
- * @internal
328
- */
329
- _uVdcHashTable;
330
- /**
331
- * @internal
332
- */
333
- _yacHashTable;
334
- /**
335
- * @internal
336
- */
337
- _uVacHashTable;
338
- /**
339
- * @internal
340
- */
341
- _bitCode;
342
- /**
343
- * @internal
344
- */
345
- _category;
346
- /**
347
- * @internal
348
- */
349
- _outputFDctQuant;
350
- /**
351
- * @internal
352
- */
353
- _du;
354
- /**
355
- * @internal
356
- */
357
- _byteOut;
358
- /**
359
- * @internal
360
- */
361
- _byteNew;
362
- /**
363
- * @internal
364
- */
365
- _bytePos;
366
- /**
367
- * @internal
368
- */
369
- _ydu;
370
- /**
371
- * @internal
372
- */
373
- _udu;
374
- /**
375
- * @internal
376
- */
377
- _vdu;
378
- /**
379
- * @internal
380
- */
381
- _rgbYuvTable;
382
- /**
383
- * Create a new instance of JpegEncoder.
384
- */
385
- constructor() {
386
- this._yTable = Array.from({ length: 64 });
387
- this._uvTable = Array.from({ length: 64 });
388
- this._fdTblY = Array.from({ length: 64 });
389
- this._fdTblUV = Array.from({ length: 64 });
390
- this._bitCode = Array.from({ length: 65535 });
391
- this._category = Array.from({ length: 65535 });
392
- this._outputFDctQuant = Array.from({ length: 64 });
393
- this._du = Array.from({ length: 64 });
394
- this._byteOut = [];
395
- this._byteNew = 0;
396
- this._bytePos = 7;
397
- this._ydu = Array.from({ length: 64 });
398
- this._udu = Array.from({ length: 64 });
399
- this._vdu = Array.from({ length: 64 });
400
- this._rgbYuvTable = Array.from({ length: 2048 });
401
- this.initHuffmanTbl();
402
- this.initCategoryNumber();
403
- this.initRGBYUVTable();
404
- }
405
- /**
406
- * Encode the image with the given quality.
407
- * @param width The width of the image to encode.
408
- * @param height The height of the image to encode.
409
- * @param imageData The data for the image.
410
- * @param quality The quality to encode the image at.
411
- * @returns The data for the encoded image.
412
- */
413
- encode(width, height, imageData, quality) {
414
- this.setQuality(quality);
415
- // Initialize bit writer
416
- this._byteOut = [];
417
- this._byteNew = 0;
418
- this._bytePos = 7;
419
- // Add JPEG headers
420
- this.writeWord(0xffd8); // SOI
421
- this.writeAPP0();
422
- this.writeDQT();
423
- this.writeSOF0(width, height);
424
- this.writeDHT();
425
- this.writeSOS();
426
- // Encode 8x8 macro blocks
427
- let DCY = 0;
428
- let DCU = 0;
429
- let DCV = 0;
430
- this._byteNew = 0;
431
- this._bytePos = 7;
432
- const quadWidth = width * 4;
433
- let x;
434
- let y = 0;
435
- let r;
436
- let g;
437
- let b;
438
- let start;
439
- let p;
440
- let col;
441
- let row;
442
- let pos;
443
- while (y < height) {
444
- x = 0;
445
- while (x < quadWidth) {
446
- start = quadWidth * y + x;
447
- p = start;
448
- col = -1;
449
- row = 0;
450
- for (pos = 0; pos < 64; pos++) {
451
- row = pos >> 3; // /8
452
- col = (pos & 7) * 4; // %8
453
- p = start + row * quadWidth + col;
454
- if (y + row >= height) {
455
- // padding bottom
456
- p -= quadWidth * (y + 1 + row - height);
457
- }
458
- if (x + col >= quadWidth) {
459
- // padding right
460
- p -= x + col - quadWidth + 4;
461
- }
462
- r = imageData[p++];
463
- g = imageData[p++];
464
- b = imageData[p++];
465
- // use lookup table (slightly faster)
466
- this._ydu[pos] =
467
- ((this._rgbYuvTable[r] +
468
- this._rgbYuvTable[Math.trunc(g + 256)] +
469
- this._rgbYuvTable[Math.trunc(b + 512)]) >>
470
- 16) -
471
- 128;
472
- this._udu[pos] =
473
- ((this._rgbYuvTable[Math.trunc(r + 768)] +
474
- this._rgbYuvTable[Math.trunc(g + 1024)] +
475
- this._rgbYuvTable[Math.trunc(b + 1280)]) >>
476
- 16) -
477
- 128;
478
- this._vdu[pos] =
479
- ((this._rgbYuvTable[Math.trunc(r + 1280)] +
480
- this._rgbYuvTable[Math.trunc(g + 1536)] +
481
- this._rgbYuvTable[Math.trunc(b + 1792)]) >>
482
- 16) -
483
- 128;
484
- }
485
- if (this._ydcHashTable && this._yacHashTable) {
486
- DCY = this.processDU(this._ydu, this._fdTblY, DCY, this._ydcHashTable, this._yacHashTable);
487
- }
488
- if (this._uVdcHashTable && this._uVacHashTable) {
489
- DCU = this.processDU(this._udu, this._fdTblUV, DCU, this._uVdcHashTable, this._uVacHashTable);
490
- }
491
- if (this._uVdcHashTable && this._uVacHashTable) {
492
- DCV = this.processDU(this._vdu, this._fdTblUV, DCV, this._uVdcHashTable, this._uVacHashTable);
493
- }
494
- x += 32;
495
- }
496
- y += 8;
497
- }
498
- // Do the bit alignment of the EOI marker
499
- if (this._bytePos >= 0) {
500
- const fillBits = [];
501
- fillBits[1] = this._bytePos + 1;
502
- fillBits[0] = (1 << (this._bytePos + 1)) - 1;
503
- this.writeBits(fillBits);
504
- }
505
- this.writeWord(0xffd9); // EOI
506
- return new Uint8Array(this._byteOut);
507
- }
508
- /**
509
- * @internal
510
- */
511
- setQuality(quality) {
512
- if (quality <= 0 || quality > 100) {
513
- throw new core.GeneralError(JpegEncoder._CLASS_NAME, "invalidQuality", { value: quality });
514
- }
515
- let sf = 0;
516
- if (quality < 50) {
517
- sf = Math.floor(5000 / quality);
518
- }
519
- else {
520
- sf = Math.floor(200 - quality * 2);
521
- }
522
- this.initQuantTables(sf);
523
- }
524
- /**
525
- * @internal
526
- */
527
- initQuantTables(sf) {
528
- const YQT = [
529
- 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69,
530
- 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104,
531
- 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99
532
- ];
533
- for (let i = 0; i < 64; i++) {
534
- let t = Math.floor((YQT[i] * sf + 50) / 100);
535
- if (t < 1) {
536
- t = 1;
537
- }
538
- else if (t > 255) {
539
- t = 255;
540
- }
541
- this._yTable[JpegEncoder._SIG_ZAG[i]] = t;
542
- }
543
- const UVQT = [
544
- 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99,
545
- 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
546
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99
547
- ];
548
- for (let j = 0; j < 64; j++) {
549
- let u = Math.floor((UVQT[j] * sf + 50) / 100);
550
- if (u < 1) {
551
- u = 1;
552
- }
553
- else if (u > 255) {
554
- u = 255;
555
- }
556
- this._uvTable[JpegEncoder._SIG_ZAG[j]] = u;
557
- }
558
- const aAsf = [1, 1.387039845, 1.306562965, 1.175875602, 1, 0.785694958, 0.5411961, 0.275899379];
559
- let k = 0;
560
- for (let row = 0; row < 8; row++) {
561
- for (let col = 0; col < 8; col++) {
562
- this._fdTblY[k] = 1 / (this._yTable[JpegEncoder._SIG_ZAG[k]] * aAsf[row] * aAsf[col] * 8);
563
- this._fdTblUV[k] = 1 / (this._uvTable[JpegEncoder._SIG_ZAG[k]] * aAsf[row] * aAsf[col] * 8);
564
- k++;
565
- }
566
- }
567
- }
568
- /**
569
- * @internal
570
- */
571
- computeHuffmanTbl(nrCodes, stdTable) {
572
- let codeValue = 0;
573
- let posInTable = 0;
574
- const HT = [];
575
- for (let k = 1; k <= 16; k++) {
576
- for (let j = 1; j <= nrCodes[k]; j++) {
577
- HT[stdTable[posInTable]] = [];
578
- HT[stdTable[posInTable]][0] = codeValue;
579
- HT[stdTable[posInTable]][1] = k;
580
- posInTable++;
581
- codeValue++;
582
- }
583
- codeValue *= 2;
584
- }
585
- return HT;
586
- }
587
- /**
588
- * @internal
589
- */
590
- initHuffmanTbl() {
591
- this._ydcHashTable = this.computeHuffmanTbl(JpegEncoder._STD_DC_LUMINANCE_NR_CODES, JpegEncoder._STD_DC_LUMINANCE_VALUES);
592
- this._uVdcHashTable = this.computeHuffmanTbl(JpegEncoder._STD_DC_CHROMINANCE_NR_CODES, JpegEncoder._STD_DC_CHROMINANCE_VALUES);
593
- this._yacHashTable = this.computeHuffmanTbl(JpegEncoder._STD_AC_LUMINANCE_NR_CODES, JpegEncoder._STD_AC_LUMINANCE_VALUES);
594
- this._uVacHashTable = this.computeHuffmanTbl(JpegEncoder._STD_AC_CHROMINANCE_NR_CODES, JpegEncoder._STD_AC_CHROMINANCE_VALUES);
595
- }
596
- /**
597
- * @internal
598
- */
599
- initCategoryNumber() {
600
- let nrLower = 1;
601
- let nrUpper = 2;
602
- for (let cat = 1; cat <= 15; cat++) {
603
- // Positive numbers
604
- for (let nr = nrLower; nr < nrUpper; nr++) {
605
- this._category[32767 + nr] = cat;
606
- this._bitCode[32767 + nr] = [];
607
- this._bitCode[32767 + nr][1] = cat;
608
- this._bitCode[32767 + nr][0] = nr;
609
- }
610
- // Negative numbers
611
- for (let nrNeg = -(nrUpper - 1); nrNeg <= -nrLower; nrNeg++) {
612
- this._category[32767 + nrNeg] = cat;
613
- this._bitCode[32767 + nrNeg] = [];
614
- this._bitCode[32767 + nrNeg][1] = cat;
615
- this._bitCode[32767 + nrNeg][0] = nrUpper - 1 + nrNeg;
616
- }
617
- nrLower <<= 1;
618
- nrUpper <<= 1;
619
- }
620
- }
621
- /**
622
- * @internal
623
- */
624
- initRGBYUVTable() {
625
- for (let i = 0; i < 256; i++) {
626
- this._rgbYuvTable[i] = 19595 * i;
627
- this._rgbYuvTable[Math.trunc(i + 256)] = 38470 * i;
628
- this._rgbYuvTable[Math.trunc(i + 512)] = 7471 * i + 0x8000;
629
- this._rgbYuvTable[Math.trunc(i + 768)] = -11059 * i;
630
- this._rgbYuvTable[Math.trunc(i + 1024)] = -21709 * i;
631
- this._rgbYuvTable[Math.trunc(i + 1280)] = 32768 * i + 0x807fff;
632
- this._rgbYuvTable[Math.trunc(i + 1536)] = -27439 * i;
633
- this._rgbYuvTable[Math.trunc(i + 1792)] = -5329 * i;
634
- }
635
- }
636
- /**
637
- * @internal
638
- */
639
- writeBits(bs) {
640
- const value = bs[0];
641
- let posVal = bs[1] - 1;
642
- while (posVal >= 0) {
643
- if (value & (1 << posVal)) {
644
- this._byteNew |= 1 << this._bytePos;
645
- }
646
- posVal--;
647
- this._bytePos--;
648
- if (this._bytePos < 0) {
649
- if (this._byteNew === 0xff) {
650
- this.writeByte(0xff);
651
- this.writeByte(0);
652
- }
653
- else {
654
- this.writeByte(this._byteNew);
655
- }
656
- this._bytePos = 7;
657
- this._byteNew = 0;
658
- }
659
- }
660
- }
661
- /**
662
- * @internal
663
- */
664
- writeByte(value) {
665
- this._byteOut.push(value);
666
- }
667
- /**
668
- * @internal
669
- */
670
- writeWord(value) {
671
- this.writeByte((value >> 8) & 0xff);
672
- this.writeByte(value & 0xff);
673
- }
674
- /**
675
- * @internal
676
- */
677
- fDCTQuant(data, fdTbl) {
678
- let d0;
679
- let d1;
680
- let d2;
681
- let d3;
682
- let d4;
683
- let d5;
684
- let d6;
685
- let d7;
686
- /* Pass 1: process rows. */
687
- let dataOff = 0;
688
- let i;
689
- const I8 = 8;
690
- const I64 = 64;
691
- for (i = 0; i < I8; ++i) {
692
- d0 = data[dataOff];
693
- d1 = data[dataOff + 1];
694
- d2 = data[dataOff + 2];
695
- d3 = data[dataOff + 3];
696
- d4 = data[dataOff + 4];
697
- d5 = data[dataOff + 5];
698
- d6 = data[dataOff + 6];
699
- d7 = data[dataOff + 7];
700
- const tmp0 = d0 + d7;
701
- const tmp7 = d0 - d7;
702
- const tmp1 = d1 + d6;
703
- const tmp6 = d1 - d6;
704
- const tmp2 = d2 + d5;
705
- const tmp5 = d2 - d5;
706
- const tmp3 = d3 + d4;
707
- const tmp4 = d3 - d4;
708
- /* Even part */
709
- let tmp10 = tmp0 + tmp3; /* phase 2 */
710
- const tmp13 = tmp0 - tmp3;
711
- let tmp11 = tmp1 + tmp2;
712
- let tmp12 = tmp1 - tmp2;
713
- data[dataOff] = tmp10 + tmp11; /* phase 3 */
714
- data[dataOff + 4] = tmp10 - tmp11;
715
- const z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */
716
- data[dataOff + 2] = tmp13 + z1; /* phase 5 */
717
- data[dataOff + 6] = tmp13 - z1;
718
- /* Odd part */
719
- tmp10 = tmp4 + tmp5; /* phase 2 */
720
- tmp11 = tmp5 + tmp6;
721
- tmp12 = tmp6 + tmp7;
722
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
723
- const z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */
724
- const z2 = 0.5411961 * tmp10 + z5; /* c2-c6 */
725
- const z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */
726
- const z3 = tmp11 * 0.707106781; /* c4 */
727
- const z11 = tmp7 + z3; /* phase 5 */
728
- const z13 = tmp7 - z3;
729
- data[dataOff + 5] = z13 + z2; /* phase 6 */
730
- data[dataOff + 3] = z13 - z2;
731
- data[dataOff + 1] = z11 + z4;
732
- data[dataOff + 7] = z11 - z4;
733
- dataOff += 8; /* advance pointer to next row */
734
- }
735
- /* Pass 2: process columns. */
736
- dataOff = 0;
737
- for (i = 0; i < I8; ++i) {
738
- d0 = data[dataOff];
739
- d1 = data[dataOff + 8];
740
- d2 = data[dataOff + 16];
741
- d3 = data[dataOff + 24];
742
- d4 = data[dataOff + 32];
743
- d5 = data[dataOff + 40];
744
- d6 = data[dataOff + 48];
745
- d7 = data[dataOff + 56];
746
- const tmp0p2 = d0 + d7;
747
- const tmp7p2 = d0 - d7;
748
- const tmp1p2 = d1 + d6;
749
- const tmp6p2 = d1 - d6;
750
- const tmp2p2 = d2 + d5;
751
- const tmp5p2 = d2 - d5;
752
- const tmp3p2 = d3 + d4;
753
- const tmp4p2 = d3 - d4;
754
- /* Even part */
755
- let tmp10p2 = tmp0p2 + tmp3p2; /* phase 2 */
756
- const tmp13p2 = tmp0p2 - tmp3p2;
757
- let tmp11p2 = tmp1p2 + tmp2p2;
758
- let tmp12p2 = tmp1p2 - tmp2p2;
759
- data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */
760
- data[dataOff + 32] = tmp10p2 - tmp11p2;
761
- const z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */
762
- data[dataOff + 16] = tmp13p2 + z1p2; /* phase 5 */
763
- data[dataOff + 48] = tmp13p2 - z1p2;
764
- /* Odd part */
765
- tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */
766
- tmp11p2 = tmp5p2 + tmp6p2;
767
- tmp12p2 = tmp6p2 + tmp7p2;
768
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
769
- const z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */
770
- const z2p2 = 0.5411961 * tmp10p2 + z5p2; /* c2-c6 */
771
- const z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */
772
- const z3p2 = tmp11p2 * 0.707106781; /* c4 */
773
- const z11p2 = tmp7p2 + z3p2; /* phase 5 */
774
- const z13p2 = tmp7p2 - z3p2;
775
- data[dataOff + 40] = z13p2 + z2p2; /* phase 6 */
776
- data[dataOff + 24] = z13p2 - z2p2;
777
- data[dataOff + 8] = z11p2 + z4p2;
778
- data[dataOff + 56] = z11p2 - z4p2;
779
- dataOff++; /* advance pointer to next column */
780
- }
781
- // Quantize/descale the coefficients
782
- let fDCTQuant;
783
- for (i = 0; i < I64; ++i) {
784
- // Apply the quantization and scaling factor & Round to nearest integer
785
- fDCTQuant = data[i] * fdTbl[i];
786
- this._outputFDctQuant[i] =
787
- fDCTQuant > 0 ? Math.trunc(fDCTQuant + 0.5) : Math.trunc(fDCTQuant - 0.5);
788
- }
789
- return this._outputFDctQuant;
790
- }
791
- /**
792
- * @internal
793
- */
794
- writeAPP0() {
795
- this.writeWord(0xffe0); // marker
796
- this.writeWord(16); // length
797
- this.writeByte(0x4a); // J
798
- this.writeByte(0x46); // F
799
- this.writeByte(0x49); // I
800
- this.writeByte(0x46); // F
801
- // cspell:disable-next-line
802
- this.writeByte(0); // = "JFIF",'\0'
803
- this.writeByte(1); // version hi
804
- this.writeByte(1); // version lo
805
- this.writeByte(0); // xy units
806
- this.writeWord(1); // x density
807
- this.writeWord(1); // y density
808
- this.writeByte(0); // thumb n width
809
- this.writeByte(0); // thumb n height
810
- }
811
- /**
812
- * @internal
813
- */
814
- writeSOF0(width, height) {
815
- this.writeWord(0xffc0); // marker
816
- this.writeWord(17); // length, true color YUV JPG
817
- this.writeByte(8); // precision
818
- this.writeWord(height);
819
- this.writeWord(width);
820
- this.writeByte(3); // nr of components
821
- this.writeByte(1); // IdY
822
- this.writeByte(0x11); // HVY
823
- this.writeByte(0); // QTY
824
- this.writeByte(2); // IdU
825
- this.writeByte(0x11); // HVU
826
- this.writeByte(1); // QTU
827
- this.writeByte(3); // IdV
828
- this.writeByte(0x11); // HVV
829
- this.writeByte(1); // QTV
830
- }
831
- /**
832
- * @internal
833
- */
834
- writeDQT() {
835
- this.writeWord(0xffdb); // marker
836
- this.writeWord(132); // length
837
- this.writeByte(0);
838
- for (let i = 0; i < 64; i++) {
839
- this.writeByte(this._yTable[i]);
840
- }
841
- this.writeByte(1);
842
- for (let j = 0; j < 64; j++) {
843
- this.writeByte(this._uvTable[j]);
844
- }
845
- }
846
- /**
847
- * @internal
848
- */
849
- writeDHT() {
850
- this.writeWord(0xffc4); // marker
851
- this.writeWord(0x01a2); // length
852
- this.writeByte(0); // HTYDc info
853
- for (let i = 0; i < 16; i++) {
854
- this.writeByte(JpegEncoder._STD_DC_LUMINANCE_NR_CODES[i + 1]);
855
- }
856
- for (let j = 0; j <= 11; j++) {
857
- this.writeByte(JpegEncoder._STD_DC_LUMINANCE_VALUES[j]);
858
- }
859
- this.writeByte(0x10); // HTYAc info
860
- for (let k = 0; k < 16; k++) {
861
- this.writeByte(JpegEncoder._STD_AC_LUMINANCE_NR_CODES[k + 1]);
862
- }
863
- for (let l = 0; l <= 161; l++) {
864
- this.writeByte(JpegEncoder._STD_AC_LUMINANCE_VALUES[l]);
865
- }
866
- this.writeByte(1); // HTUDc info
867
- for (let m = 0; m < 16; m++) {
868
- this.writeByte(JpegEncoder._STD_DC_CHROMINANCE_NR_CODES[m + 1]);
869
- }
870
- for (let n = 0; n <= 11; n++) {
871
- this.writeByte(JpegEncoder._STD_DC_CHROMINANCE_VALUES[n]);
872
- }
873
- this.writeByte(0x11); // HTUAc info
874
- for (let o = 0; o < 16; o++) {
875
- this.writeByte(JpegEncoder._STD_AC_CHROMINANCE_NR_CODES[o + 1]);
876
- }
877
- for (let p = 0; p <= 161; p++) {
878
- this.writeByte(JpegEncoder._STD_AC_CHROMINANCE_VALUES[p]);
879
- }
880
- }
881
- /**
882
- * @internal
883
- */
884
- writeSOS() {
885
- this.writeWord(0xffda); // marker
886
- this.writeWord(12); // length
887
- this.writeByte(3); // nr of components
888
- this.writeByte(1); // IdY
889
- this.writeByte(0); // HTY
890
- this.writeByte(2); // IdU
891
- this.writeByte(0x11); // HTU
892
- this.writeByte(3); // IdV
893
- this.writeByte(0x11); // HTV
894
- this.writeByte(0); // Ss
895
- this.writeByte(0x3f); // Se
896
- this.writeByte(0); // Bf
897
- }
898
- /**
899
- * @internal
900
- */
901
- processDU(CDU, fdTbl, passedDC, HTDc, HTAc) {
902
- let DC = passedDC;
903
- const EOB = HTAc[0x00];
904
- const m16zeroes = HTAc[0xf0];
905
- let pos;
906
- const I16 = 16;
907
- const I63 = 63;
908
- const I64 = 64;
909
- const DU_DCT = this.fDCTQuant(CDU, fdTbl);
910
- // ZigZag reorder
911
- for (let j = 0; j < I64; ++j) {
912
- this._du[JpegEncoder._SIG_ZAG[j]] = DU_DCT[j];
913
- }
914
- const diff = this._du[0] - DC;
915
- DC = this._du[0];
916
- // Encode DC
917
- if (diff === 0) {
918
- this.writeBits(HTDc[0]); // Diff might be 0
919
- }
920
- else {
921
- pos = 32767 + diff;
922
- this.writeBits(HTDc[this._category[pos]]);
923
- this.writeBits(this._bitCode[pos]);
924
- }
925
- // Encode ACs
926
- let end0pos = 63; // was const... which is crazy
927
- for (; end0pos > 0 && this._du[end0pos] === 0; end0pos--) { }
928
- // end0pos = first element in reverse order !=0
929
- if (end0pos === 0) {
930
- this.writeBits(EOB);
931
- return DC;
932
- }
933
- let i = 1;
934
- let lng;
935
- while (i <= end0pos) {
936
- const startPos = i;
937
- for (; this._du[i] === 0 && i <= end0pos; ++i) { }
938
- let nrZeroes = i - startPos;
939
- if (nrZeroes >= I16) {
940
- lng = nrZeroes >> 4;
941
- for (let nrMarker = 1; nrMarker <= lng; ++nrMarker) {
942
- this.writeBits(m16zeroes);
943
- }
944
- nrZeroes &= 0xf;
945
- }
946
- pos = 32767 + this._du[i];
947
- this.writeBits(HTAc[(nrZeroes << 4) + this._category[pos]]);
948
- this.writeBits(this._bitCode[pos]);
949
- i++;
950
- }
951
- if (end0pos !== I63) {
952
- this.writeBits(EOB);
953
- }
954
- return DC;
955
- }
956
- }
957
-
958
- // Copyright 2024 IOTA Stiftung.
959
- // SPDX-License-Identifier: Apache-2.0.
960
- /* eslint-disable no-bitwise */
961
- /* eslint-disable no-mixed-operators */
962
- /* eslint-disable no-continue */
963
- /**
964
- * PNG Encoder.
965
- * Based on https://github.com/photopea/UPNG.js.
966
- */
967
- class PngEncoder {
968
- /**
969
- * Encode the image frames to png.
970
- * @param buffers The frame buffers to encode.
971
- * @param w The image width.
972
- * @param h The image height.
973
- * @returns The data for the image.
974
- */
975
- async encode(buffers, w, h) {
976
- const ps = 0;
977
- const forbidPlte = false;
978
- const data = new Uint8Array(buffers[0].byteLength * buffers.length + 100);
979
- const wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
980
- for (let i = 0; i < 8; i++) {
981
- data[i] = wr[i];
982
- }
983
- let offset = 8;
984
- const nImg = await this.compressPNG(buffers, w, h, ps, forbidPlte);
985
- this.writeUint(data, offset, 13);
986
- offset += 4;
987
- // cspell:disable-next-line
988
- this.writeASCII(data, offset, "IHDR");
989
- offset += 4;
990
- this.writeUint(data, offset, w);
991
- offset += 4;
992
- this.writeUint(data, offset, h);
993
- offset += 4;
994
- data[offset] = nImg.depth;
995
- offset++;
996
- data[offset] = nImg.cType;
997
- offset++;
998
- data[offset] = 0; // compress
999
- offset++;
1000
- data[offset] = 0; // filter
1001
- offset++;
1002
- data[offset] = 0; // interlace
1003
- offset++;
1004
- this.writeUint(data, offset, this.crc(data, offset - 17, 17));
1005
- offset += 4; // crc
1006
- // 9 bytes to say, that it is sRGB
1007
- this.writeUint(data, offset, 1);
1008
- offset += 4;
1009
- this.writeASCII(data, offset, "sRGB");
1010
- offset += 4;
1011
- data[offset] = 1;
1012
- offset++;
1013
- this.writeUint(data, offset, this.crc(data, offset - 5, 5));
1014
- offset += 4; // crc
1015
- const anim = buffers.length > 1;
1016
- if (anim) {
1017
- this.writeUint(data, offset, 8);
1018
- offset += 4;
1019
- this.writeASCII(data, offset, "acTL");
1020
- offset += 4;
1021
- this.writeUint(data, offset, buffers.length);
1022
- offset += 4;
1023
- this.writeUint(data, offset, 0);
1024
- offset += 4;
1025
- this.writeUint(data, offset, this.crc(data, offset - 12, 12));
1026
- offset += 4; // crc
1027
- }
1028
- if (nImg.cType === 3) {
1029
- const dl = nImg.plte.length;
1030
- this.writeUint(data, offset, dl * 3);
1031
- offset += 4;
1032
- this.writeASCII(data, offset, "PLTE");
1033
- offset += 4;
1034
- for (let i = 0; i < dl; i++) {
1035
- const ti = i * 3;
1036
- const c = nImg.plte[i];
1037
- const r = c & 255;
1038
- const g = (c >> 8) & 255;
1039
- const b = (c >> 16) & 255;
1040
- data[offset + ti + 0] = r;
1041
- data[offset + ti + 1] = g;
1042
- data[offset + ti + 2] = b;
1043
- }
1044
- offset += dl * 3;
1045
- this.writeUint(data, offset, this.crc(data, offset - dl * 3 - 4, dl * 3 + 4));
1046
- offset += 4; // crc
1047
- if (nImg.gotAlpha) {
1048
- this.writeUint(data, offset, dl);
1049
- offset += 4;
1050
- this.writeASCII(data, offset, "tRNS");
1051
- offset += 4;
1052
- for (let i = 0; i < dl; i++) {
1053
- data[offset + i] = (nImg.plte[i] >> 24) & 255;
1054
- }
1055
- offset += dl;
1056
- this.writeUint(data, offset, this.crc(data, offset - dl - 4, dl + 4));
1057
- offset += 4; // crc
1058
- }
1059
- }
1060
- let fi = 0;
1061
- for (let j = 0; j < nImg.frames.length; j++) {
1062
- const fr = nImg.frames[j];
1063
- if (anim) {
1064
- this.writeUint(data, offset, 26);
1065
- offset += 4;
1066
- this.writeASCII(data, offset, "fcTL");
1067
- offset += 4;
1068
- this.writeUint(data, offset, fi++);
1069
- offset += 4;
1070
- this.writeUint(data, offset, fr.rect.width);
1071
- offset += 4;
1072
- this.writeUint(data, offset, fr.rect.height);
1073
- offset += 4;
1074
- this.writeUint(data, offset, fr.rect.x);
1075
- offset += 4;
1076
- this.writeUint(data, offset, fr.rect.y);
1077
- offset += 4;
1078
- this.writeUshort(data, offset, 0);
1079
- offset += 2;
1080
- this.writeUshort(data, offset, 1000);
1081
- offset += 2;
1082
- data[offset] = fr.dispose;
1083
- offset++; // dispose
1084
- data[offset] = fr.blend;
1085
- offset++; // blend
1086
- this.writeUint(data, offset, this.crc(data, offset - 30, 30));
1087
- offset += 4; // crc
1088
- }
1089
- const imgD = fr.cImg;
1090
- const dl = imgD?.length ?? 0;
1091
- this.writeUint(data, offset, dl + (j === 0 ? 0 : 4));
1092
- offset += 4;
1093
- const iOff = offset;
1094
- // cspell:disable-next-line
1095
- this.writeASCII(data, offset, j === 0 ? "IDAT" : "fdAT");
1096
- offset += 4;
1097
- if (j !== 0) {
1098
- this.writeUint(data, offset, fi++);
1099
- offset += 4;
1100
- }
1101
- if (imgD) {
1102
- for (let i = 0; i < dl; i++) {
1103
- data[offset + i] = imgD[i];
1104
- }
1105
- }
1106
- offset += dl;
1107
- this.writeUint(data, offset, this.crc(data, iOff, offset - iOff));
1108
- offset += 4; // crc
1109
- }
1110
- this.writeUint(data, offset, 0);
1111
- offset += 4;
1112
- // cspell:disable-next-line
1113
- this.writeASCII(data, offset, "IEND");
1114
- offset += 4;
1115
- this.writeUint(data, offset, this.crc(data, offset - 4, 4));
1116
- offset += 4; // crc
1117
- return new Uint8Array(data.buffer.slice(0, offset));
1118
- }
1119
- /**
1120
- * @internal
1121
- */
1122
- async compressPNG(buffers, w, h, ps, forbidPlte) {
1123
- const out = this.compress(buffers, w, h, ps, 0, forbidPlte);
1124
- for (let i = 0; i < buffers.length; i++) {
1125
- const frm = out.frames[i];
1126
- const nw = frm.rect.width;
1127
- const nh = frm.rect.height;
1128
- const bpl = frm.bpl;
1129
- const bpp = frm.bpp;
1130
- const fData = new Uint8Array(nw * bpl + nh);
1131
- frm.cImg = await this.filterZero(frm.img, nh, bpp, bpl, fData);
1132
- }
1133
- return out;
1134
- }
1135
- /**
1136
- * @internal
1137
- */
1138
- compress(inBuffers, w, h, inPs, forGIF, forbidPlte) {
1139
- let cType = 6;
1140
- let depth = 8;
1141
- let bpp = 4;
1142
- let alphaAnd = 255;
1143
- let ps = inPs;
1144
- let buffers = inBuffers;
1145
- for (let j = 0; j < buffers.length; j++) {
1146
- // when not quantized, other frames can contain colors, that are not in an initial frame
1147
- const img = new Uint8Array(buffers[j]);
1148
- const iLen = img.length;
1149
- for (let i = 0; i < iLen; i += 4) {
1150
- alphaAnd &= img[i + 3];
1151
- }
1152
- }
1153
- let gotAlpha = alphaAnd !== 255;
1154
- const cMap = {};
1155
- const pLte = [];
1156
- if (buffers.length !== 0) {
1157
- cMap[0] = 0;
1158
- pLte.push(0);
1159
- if (ps !== 0) {
1160
- ps--;
1161
- }
1162
- }
1163
- if (ps !== 0) {
1164
- const qRes = this.quantize(buffers, ps, forGIF);
1165
- buffers = qRes.buffers;
1166
- for (let i = 0; i < qRes.plte.length; i++) {
1167
- const c = qRes.plte[i].est?.rgba ?? 0;
1168
- if (!cMap[c]) {
1169
- cMap[c] = pLte.length;
1170
- pLte.push(c);
1171
- }
1172
- }
1173
- }
1174
- else {
1175
- // what if ps==0, but there are <=256 colors? we still need to detect, if the palette could be used
1176
- for (let j = 0; j < buffers.length; j++) {
1177
- // when not quantized, other frames can contain colors, that are not in an initial frame
1178
- const img32 = new Uint32Array(buffers[j]);
1179
- const iLen = img32.length;
1180
- for (let i = 0; i < iLen; i++) {
1181
- const c = img32[i];
1182
- if ((i < w || (c !== img32[i - 1] && c !== img32[i - w])) && !cMap[c]) {
1183
- cMap[c] = pLte.length;
1184
- pLte.push(c);
1185
- if (pLte.length >= 300) {
1186
- break;
1187
- }
1188
- }
1189
- }
1190
- }
1191
- }
1192
- const brute = gotAlpha ? forGIF : false; // brute : frames can only be copied, not "blended"
1193
- const cc = pLte.length;
1194
- if (cc <= 256 && !forbidPlte) {
1195
- if (cc <= 2) {
1196
- depth = 1;
1197
- }
1198
- else if (cc <= 4) {
1199
- depth = 2;
1200
- }
1201
- else if (cc <= 16) {
1202
- depth = 4;
1203
- }
1204
- else {
1205
- depth = 8;
1206
- }
1207
- if (forGIF) {
1208
- depth = 8;
1209
- }
1210
- gotAlpha = true;
1211
- }
1212
- const frames = [];
1213
- for (let j = 0; j < buffers.length; j++) {
1214
- let cImg = new Uint8Array(buffers[j]);
1215
- let cImg32 = new Uint32Array(cImg.buffer);
1216
- let nx = 0;
1217
- let ny = 0;
1218
- let nw = w;
1219
- let nh = h;
1220
- let blend = 0;
1221
- if (j !== 0 && !brute) {
1222
- const tLim = forGIF || j === 1 || frames[frames.length - 2].dispose === 2 ? 1 : 2;
1223
- let tStp = 0;
1224
- let tArea = 1e9;
1225
- for (let it = 0; it < tLim; it++) {
1226
- const p32 = new Uint32Array(buffers[j - 1 - it]);
1227
- let mix = w;
1228
- let miy = h;
1229
- let max = -1;
1230
- let may = -1;
1231
- for (let y = 0; y < h; y++) {
1232
- for (let x = 0; x < w; x++) {
1233
- const i = y * w + x;
1234
- if (cImg32[i] !== p32[i]) {
1235
- if (x < mix) {
1236
- mix = x;
1237
- }
1238
- if (x > max) {
1239
- max = x;
1240
- }
1241
- if (y < miy) {
1242
- miy = y;
1243
- }
1244
- if (y > may) {
1245
- may = y;
1246
- }
1247
- }
1248
- }
1249
- }
1250
- const sArea = max === -1 ? 1 : (max - mix + 1) * (may - miy + 1);
1251
- if (sArea < tArea) {
1252
- tArea = sArea;
1253
- tStp = it;
1254
- if (max === -1) {
1255
- nx = 0;
1256
- ny = 0;
1257
- nw = 1;
1258
- nh = 1;
1259
- }
1260
- else {
1261
- nx = mix;
1262
- ny = miy;
1263
- nw = max - mix + 1;
1264
- nh = may - miy + 1;
1265
- }
1266
- }
1267
- }
1268
- const pImg = new Uint8Array(buffers[j - 1 - tStp]);
1269
- if (tStp === 1) {
1270
- frames[frames.length - 1].dispose = 2;
1271
- }
1272
- const nImg = new Uint8Array(nw * nh * 4);
1273
- this.copyTile(pImg, w, h, nImg, nw, nh, -nx, -ny, 0);
1274
- if (this.copyTile(cImg, w, h, nImg, nw, nh, -nx, -ny, 3)) {
1275
- this.copyTile(cImg, w, h, nImg, nw, nh, -nx, -ny, 2);
1276
- blend = 1;
1277
- }
1278
- else {
1279
- this.copyTile(cImg, w, h, nImg, nw, nh, -nx, -ny, 0);
1280
- blend = 0;
1281
- }
1282
- cImg = nImg;
1283
- cImg32 = new Uint32Array(cImg.buffer);
1284
- }
1285
- let bpl = 4 * nw;
1286
- if (cc <= 256 && !forbidPlte) {
1287
- bpl = Math.ceil((depth * nw) / 8);
1288
- const nImg = new Uint8Array(bpl * nh);
1289
- for (let y = 0; y < nh; y++) {
1290
- const i = y * bpl;
1291
- const ii = y * nw;
1292
- if (depth === 8) {
1293
- for (let x = 0; x < nw; x++) {
1294
- nImg[i + x] = cMap[cImg32[ii + x]];
1295
- }
1296
- }
1297
- else if (depth === 4) {
1298
- for (let x = 0; x < nw; x++) {
1299
- nImg[i + (x >> 1)] |= cMap[cImg32[ii + x]] << (4 - (x & 1) * 4);
1300
- }
1301
- }
1302
- else if (depth === 2) {
1303
- for (let x = 0; x < nw; x++) {
1304
- nImg[i + (x >> 2)] |= cMap[cImg32[ii + x]] << (6 - (x & 3) * 2);
1305
- }
1306
- }
1307
- else if (depth === 1) {
1308
- for (let x = 0; x < nw; x++) {
1309
- nImg[i + (x >> 3)] |= cMap[cImg32[ii + x]] << (7 - (x & 7) * 1);
1310
- }
1311
- }
1312
- }
1313
- cImg = nImg;
1314
- cType = 3;
1315
- bpp = 1;
1316
- }
1317
- else if (!gotAlpha && buffers.length === 1) {
1318
- // some next "reduced" frames may contain alpha for blending
1319
- const nImg = new Uint8Array(nw * nh * 3);
1320
- const area = nw * nh;
1321
- for (let i = 0; i < area; i++) {
1322
- const ti = i * 3;
1323
- const qi = i * 4;
1324
- nImg[ti] = cImg[qi];
1325
- nImg[ti + 1] = cImg[qi + 1];
1326
- nImg[ti + 2] = cImg[qi + 2];
1327
- }
1328
- cImg = nImg;
1329
- cType = 2;
1330
- bpp = 3;
1331
- bpl = 3 * nw;
1332
- }
1333
- frames.push({
1334
- rect: {
1335
- x: nx,
1336
- y: ny,
1337
- width: nw,
1338
- height: nh
1339
- },
1340
- img: cImg,
1341
- bpl,
1342
- bpp,
1343
- blend,
1344
- dispose: brute ? 1 : 0
1345
- });
1346
- }
1347
- return { cType, depth, plte: pLte, gotAlpha, frames };
1348
- }
1349
- /**
1350
- * @internal
1351
- */
1352
- async filterZero(img, h, bpp, bpl, data) {
1353
- const fls = [];
1354
- for (let t = 0; t < 5; t++) {
1355
- if (h * bpl > 500000 && (t === 2 || t === 3 || t === 4)) {
1356
- continue;
1357
- }
1358
- for (let y = 0; y < h; y++) {
1359
- this.filterLine(data, img, y, bpl, bpp, t);
1360
- }
1361
- const deflated = await core.Compression.compress(data, "deflate");
1362
- fls.push(deflated);
1363
- if (bpp === 1) {
1364
- break;
1365
- }
1366
- }
1367
- let ti = 0;
1368
- let tSize = 1e9;
1369
- for (let i = 0; i < fls.length; i++) {
1370
- if (fls[i].length < tSize) {
1371
- ti = i;
1372
- tSize = fls[i].length;
1373
- }
1374
- }
1375
- return fls[ti];
1376
- }
1377
- /**
1378
- * @internal
1379
- */
1380
- filterLine(data, img, y, bpl, bpp, type) {
1381
- const i = y * bpl;
1382
- let di = i + y;
1383
- data[di] = type;
1384
- di++;
1385
- if (type === 0) {
1386
- for (let x = 0; x < bpl; x++) {
1387
- data[di + x] = img[i + x];
1388
- }
1389
- }
1390
- else if (type === 1) {
1391
- for (let x = 0; x < bpp; x++) {
1392
- data[di + x] = img[i + x];
1393
- }
1394
- for (let x = bpp; x < bpl; x++) {
1395
- data[di + x] = (img[i + x] - img[i + x - bpp] + 256) & 255;
1396
- }
1397
- }
1398
- else if (y === 0) {
1399
- for (let x = 0; x < bpp; x++) {
1400
- data[di + x] = img[i + x];
1401
- }
1402
- if (type === 2) {
1403
- for (let x = bpp; x < bpl; x++) {
1404
- data[di + x] = img[i + x];
1405
- }
1406
- }
1407
- if (type === 3) {
1408
- for (let x = bpp; x < bpl; x++) {
1409
- data[di + x] = (img[i + x] - (img[i + x - bpp] >> 1) + 256) & 255;
1410
- }
1411
- }
1412
- if (type === 4) {
1413
- for (let x = bpp; x < bpl; x++) {
1414
- data[di + x] = (img[i + x] - this.paeth(img[i + x - bpp], 0, 0) + 256) & 255;
1415
- }
1416
- }
1417
- }
1418
- else {
1419
- if (type === 2) {
1420
- for (let x = 0; x < bpl; x++) {
1421
- data[di + x] = (img[i + x] + 256 - img[i + x - bpl]) & 255;
1422
- }
1423
- }
1424
- if (type === 3) {
1425
- for (let x = 0; x < bpp; x++) {
1426
- data[di + x] = (img[i + x] + 256 - (img[i + x - bpl] >> 1)) & 255;
1427
- }
1428
- for (let x = bpp; x < bpl; x++) {
1429
- data[di + x] = (img[i + x] + 256 - ((img[i + x - bpl] + img[i + x - bpp]) >> 1)) & 255;
1430
- }
1431
- }
1432
- if (type === 4) {
1433
- for (let x = 0; x < bpp; x++) {
1434
- data[di + x] = (img[i + x] + 256 - this.paeth(0, img[i + x - bpl], 0)) & 255;
1435
- }
1436
- for (let x = bpp; x < bpl; x++) {
1437
- data[di + x] =
1438
- (img[i + x] +
1439
- 256 -
1440
- this.paeth(img[i + x - bpp], img[i + x - bpl], img[i + x - bpp - bpl])) &
1441
- 255;
1442
- }
1443
- }
1444
- }
1445
- }
1446
- /**
1447
- * @internal
1448
- */
1449
- paeth(a, b, c) {
1450
- const p = a + b - c;
1451
- const pa = Math.abs(p - a);
1452
- const pb = Math.abs(p - b);
1453
- const pc = Math.abs(p - c);
1454
- if (pa <= pb && pa <= pc) {
1455
- return a;
1456
- }
1457
- if (pb <= pc) {
1458
- return b;
1459
- }
1460
- return c;
1461
- }
1462
- /**
1463
- * @internal
1464
- */
1465
- writeASCII(data, p, s) {
1466
- for (let i = 0; i < s.length; i++) {
1467
- data[p + i] = s.charCodeAt(i);
1468
- }
1469
- }
1470
- /**
1471
- * @internal
1472
- */
1473
- writeUint(buff, p, n) {
1474
- buff[p] = (n >> 24) & 255;
1475
- buff[p + 1] = (n >> 16) & 255;
1476
- buff[p + 2] = (n >> 8) & 255;
1477
- buff[p + 3] = n & 255;
1478
- }
1479
- /**
1480
- * @internal
1481
- */
1482
- writeUshort(buff, p, n) {
1483
- buff[p] = (n >> 8) & 255;
1484
- buff[p + 1] = n & 255;
1485
- }
1486
- /**
1487
- * @internal
1488
- */
1489
- copyTile(sb, sw, sh, tb, tw, th, xOffset, yOffset, mode) {
1490
- const w = Math.min(sw, tw);
1491
- const h = Math.min(sh, th);
1492
- let si = 0;
1493
- let ti = 0;
1494
- for (let y = 0; y < h; y++) {
1495
- for (let x = 0; x < w; x++) {
1496
- if (xOffset >= 0 && yOffset >= 0) {
1497
- si = (y * sw + x) << 2;
1498
- ti = ((yOffset + y) * tw + xOffset + x) << 2;
1499
- }
1500
- else {
1501
- si = ((-yOffset + y) * sw - xOffset + x) << 2;
1502
- ti = (y * tw + x) << 2;
1503
- }
1504
- if (mode === 0) {
1505
- tb[ti] = sb[si];
1506
- tb[ti + 1] = sb[si + 1];
1507
- tb[ti + 2] = sb[si + 2];
1508
- tb[ti + 3] = sb[si + 3];
1509
- }
1510
- else if (mode === 1) {
1511
- const fa = sb[si + 3] * (1 / 255);
1512
- const fr = sb[si] * fa;
1513
- const fg = sb[si + 1] * fa;
1514
- const fb = sb[si + 2] * fa;
1515
- const ba = tb[ti + 3] * (1 / 255);
1516
- const br = tb[ti] * ba;
1517
- const bg = tb[ti + 1] * ba;
1518
- const bb = tb[ti + 2] * ba;
1519
- const ifa = 1 - fa;
1520
- const oa = fa + ba * ifa;
1521
- const ioa = oa === 0 ? 0 : 1 / oa;
1522
- tb[ti + 3] = 255 * oa;
1523
- tb[ti + 0] = (fr + br * ifa) * ioa;
1524
- tb[ti + 1] = (fg + bg * ifa) * ioa;
1525
- tb[ti + 2] = (fb + bb * ifa) * ioa;
1526
- }
1527
- else if (mode === 2) {
1528
- // copy only differences, otherwise zero
1529
- const fa = sb[si + 3];
1530
- const fr = sb[si];
1531
- const fg = sb[si + 1];
1532
- const fb = sb[si + 2];
1533
- const ba = tb[ti + 3];
1534
- const br = tb[ti];
1535
- const bg = tb[ti + 1];
1536
- const bb = tb[ti + 2];
1537
- if (fa === ba && fr === br && fg === bg && fb === bb) {
1538
- tb[ti] = 0;
1539
- tb[ti + 1] = 0;
1540
- tb[ti + 2] = 0;
1541
- tb[ti + 3] = 0;
1542
- }
1543
- else {
1544
- tb[ti] = fr;
1545
- tb[ti + 1] = fg;
1546
- tb[ti + 2] = fb;
1547
- tb[ti + 3] = fa;
1548
- }
1549
- }
1550
- else if (mode === 3) {
1551
- // check if can be blended
1552
- const fa = sb[si + 3];
1553
- const fr = sb[si];
1554
- const fg = sb[si + 1];
1555
- const fb = sb[si + 2];
1556
- const ba = tb[ti + 3];
1557
- const br = tb[ti];
1558
- const bg = tb[ti + 1];
1559
- const bb = tb[ti + 2];
1560
- if (fa === ba && fr === br && fg === bg && fb === bb) {
1561
- continue;
1562
- }
1563
- if (fa < 220 && ba > 20) {
1564
- return false;
1565
- }
1566
- }
1567
- }
1568
- }
1569
- return true;
1570
- }
1571
- /**
1572
- * @internal
1573
- */
1574
- crc(b, o, l) {
1575
- return this.crcUpdate(0xffffffff, b, o, l) ^ 0xffffffff;
1576
- }
1577
- /**
1578
- * @internal
1579
- */
1580
- crcUpdate(c, buf, off, len) {
1581
- let localC = c;
1582
- const crcTable = this.crcTable();
1583
- for (let i = 0; i < len; i++) {
1584
- localC = crcTable[(localC ^ buf[off + i]) & 0xff] ^ (localC >>> 8);
1585
- }
1586
- return localC;
1587
- }
1588
- /**
1589
- * @internal
1590
- */
1591
- crcTable() {
1592
- const tab = new Uint32Array(256);
1593
- for (let n = 0; n < 256; n++) {
1594
- let c = n;
1595
- for (let k = 0; k < 8; k++) {
1596
- if (c & 1) {
1597
- c = 0xedb88320 ^ (c >>> 1);
1598
- }
1599
- else {
1600
- c >>>= 1;
1601
- }
1602
- }
1603
- tab[n] = c;
1604
- }
1605
- return tab;
1606
- }
1607
- /**
1608
- * @internal
1609
- */
1610
- quantize(buffers, ps, roundAlpha) {
1611
- const imgs = [];
1612
- let total = 0;
1613
- for (let i = 0; i < buffers.length; i++) {
1614
- imgs.push(this.alphaMul(new Uint8Array(buffers[i]), roundAlpha));
1615
- total += buffers[i].byteLength;
1616
- }
1617
- const nImg = new Uint8Array(total);
1618
- const nImg32 = new Uint32Array(nImg.buffer);
1619
- let nOff = 0;
1620
- for (let i = 0; i < imgs.length; i++) {
1621
- const img = imgs[i];
1622
- const il = img.length;
1623
- for (let j = 0; j < il; j++) {
1624
- nImg[nOff + j] = img[j];
1625
- }
1626
- nOff += il;
1627
- }
1628
- const root = {
1629
- i0: 0,
1630
- i1: nImg.length,
1631
- bst: null,
1632
- est: null,
1633
- tDst: 0,
1634
- left: null,
1635
- right: null
1636
- };
1637
- root.bst = this.quantizeStats(nImg, root.i0, root.i1);
1638
- root.est = this.quantizeEStats(root.bst);
1639
- const leafs = [root];
1640
- while (leafs.length < ps) {
1641
- let maxL = 0;
1642
- let mi = 0;
1643
- for (let i = 0; i < leafs.length; i++) {
1644
- const est = leafs[i].est;
1645
- if (est && est.L > maxL) {
1646
- maxL = est.L;
1647
- mi = i;
1648
- }
1649
- }
1650
- if (maxL < 1e-3) {
1651
- break;
1652
- }
1653
- const node = leafs[mi];
1654
- const s0 = this.quantizeSplitPixels(nImg, nImg32, node.i0, node.i1, node.est?.e ?? [], node.est?.eMq255 ?? 0);
1655
- const ln = {
1656
- i0: node.i0,
1657
- i1: s0,
1658
- bst: null,
1659
- est: null,
1660
- tDst: 0,
1661
- left: null,
1662
- right: null
1663
- };
1664
- ln.bst = this.quantizeStats(nImg, ln.i0, ln.i1);
1665
- ln.est = this.quantizeEStats(ln.bst);
1666
- const rn = {
1667
- i0: s0,
1668
- i1: node.i1,
1669
- bst: null,
1670
- est: null,
1671
- tDst: 0,
1672
- left: null,
1673
- right: null
1674
- };
1675
- rn.bst = {
1676
- R: [],
1677
- m: [],
1678
- N: (node.bst?.N ?? 0) - ln.bst.N
1679
- };
1680
- for (let i = 0; i < 16; i++) {
1681
- rn.bst.R[i] = (node.bst?.R[i] ?? 0) - ln.bst.R[i];
1682
- }
1683
- for (let i = 0; i < 4; i++) {
1684
- rn.bst.m[i] = (node.bst?.m[i] ?? 0) - ln.bst.m[i];
1685
- }
1686
- rn.est = this.quantizeEStats(rn.bst);
1687
- node.left = ln;
1688
- node.right = rn;
1689
- leafs[mi] = ln;
1690
- leafs.push(rn);
1691
- }
1692
- leafs.sort((a, b) => (b.bst?.N ?? 0) - (a.bst?.N ?? 0));
1693
- const outBuffers = [];
1694
- for (let ii = 0; ii < imgs.length; ii++) {
1695
- const sb = new Uint8Array(imgs[ii]);
1696
- const tb = new Uint32Array(imgs[ii]);
1697
- const len = sb.length;
1698
- for (let i = 0; i < len; i += 4) {
1699
- const r = sb[i] * (1 / 255);
1700
- const g = sb[i + 1] * (1 / 255);
1701
- const b = sb[i + 2] * (1 / 255);
1702
- const a = sb[i + 3] * (1 / 255);
1703
- let nd = root;
1704
- while (nd?.left) {
1705
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1706
- nd = this.quantizePlaneDst(nd.est, r, g, b, a) <= 0 ? nd.left : nd.right;
1707
- }
1708
- tb[i >> 2] = nd?.est?.rgba ?? 0;
1709
- }
1710
- outBuffers[ii] = tb.buffer;
1711
- }
1712
- return { buffers: outBuffers, plte: leafs };
1713
- }
1714
- /**
1715
- * @internal
1716
- */
1717
- quantizeStats(nImg, i0, i1) {
1718
- const R = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1719
- const m = [0, 0, 0, 0];
1720
- const N = (i1 - i0) >> 2;
1721
- for (let i = i0; i < i1; i += 4) {
1722
- const r = nImg[i] * (1 / 255);
1723
- const g = nImg[i + 1] * (1 / 255);
1724
- const b = nImg[i + 2] * (1 / 255);
1725
- const a = nImg[i + 3] * (1 / 255);
1726
- m[0] += r;
1727
- m[1] += g;
1728
- m[2] += b;
1729
- m[3] += a;
1730
- R[0] += r * r;
1731
- R[1] += r * g;
1732
- R[2] += r * b;
1733
- R[3] += r * a;
1734
- R[5] += g * g;
1735
- R[6] += g * b;
1736
- R[7] += g * a;
1737
- R[10] += b * b;
1738
- R[11] += b * a;
1739
- R[15] += a * a;
1740
- }
1741
- R[4] = R[1];
1742
- R[8] = R[2];
1743
- R[12] = R[3];
1744
- R[9] = R[6];
1745
- R[13] = R[7];
1746
- R[14] = R[11];
1747
- return { R, m, N };
1748
- }
1749
- /**
1750
- * @internal
1751
- */
1752
- quantizeEStats(stats) {
1753
- const R = stats.R;
1754
- const m = stats.m;
1755
- const N = stats.N;
1756
- const m0 = m[0];
1757
- const m1 = m[1];
1758
- const m2 = m[2];
1759
- const m3 = m[3];
1760
- const iN = N === 0 ? 0 : 1 / N;
1761
- const rj = [
1762
- R[0] - m0 * m0 * iN,
1763
- R[1] - m0 * m1 * iN,
1764
- R[2] - m0 * m2 * iN,
1765
- R[3] - m0 * m3 * iN,
1766
- R[4] - m1 * m0 * iN,
1767
- R[5] - m1 * m1 * iN,
1768
- R[6] - m1 * m2 * iN,
1769
- R[7] - m1 * m3 * iN,
1770
- R[8] - m2 * m0 * iN,
1771
- R[9] - m2 * m1 * iN,
1772
- R[10] - m2 * m2 * iN,
1773
- R[11] - m2 * m3 * iN,
1774
- R[12] - m3 * m0 * iN,
1775
- R[13] - m3 * m1 * iN,
1776
- R[14] - m3 * m2 * iN,
1777
- R[15] - m3 * m3 * iN
1778
- ];
1779
- const A = rj;
1780
- let b = [0.5, 0.5, 0.5, 0.5];
1781
- let mi = 0;
1782
- let tmi = 0;
1783
- if (N !== 0) {
1784
- for (let i = 0; i < 10; i++) {
1785
- b = this.m4MultiplyVec(A, b);
1786
- tmi = Math.sqrt(this.m4Dot(b, b));
1787
- b = this.m4Sml(1 / tmi, b);
1788
- if (Math.abs(tmi - mi) < 1e-9) {
1789
- break;
1790
- }
1791
- mi = tmi;
1792
- }
1793
- }
1794
- const q = [m0 * iN, m1 * iN, m2 * iN, m3 * iN];
1795
- const eMq255 = this.m4Dot(this.m4Sml(255, q), b);
1796
- const ia = q[3] < 0.001 ? 0 : 1 / q[3];
1797
- return {
1798
- Cov: rj,
1799
- q,
1800
- e: b,
1801
- L: mi,
1802
- eMq255,
1803
- eMq: this.m4Dot(b, q),
1804
- rgba: ((Math.round(255 * q[3]) << 24) |
1805
- (Math.round(255 * q[2] * ia) << 16) |
1806
- (Math.round(255 * q[1] * ia) << 8) |
1807
- (Math.round(255 * q[0] * ia) << 0)) >>>
1808
- 0
1809
- };
1810
- }
1811
- /**
1812
- * @internal
1813
- */
1814
- quantizePlaneDst(est, r, g, b, a) {
1815
- const e = est.e;
1816
- return e[0] * r + e[1] * g + e[2] * b + e[3] * a - est.eMq;
1817
- }
1818
- /**
1819
- * @internal
1820
- */
1821
- quantizeSplitPixels(nImg, nImg32, i0in, i1in, e, eMq) {
1822
- let i1 = i1in - 4;
1823
- let i0 = i0in;
1824
- while (i0 < i1) {
1825
- while (this.quantizeVecDot(nImg, i0, e) <= eMq) {
1826
- i0 += 4;
1827
- }
1828
- while (this.quantizeVecDot(nImg, i1, e) > eMq) {
1829
- i1 -= 4;
1830
- }
1831
- if (i0 >= i1) {
1832
- break;
1833
- }
1834
- const t = nImg32[i0 >> 2];
1835
- nImg32[i0 >> 2] = nImg32[i1 >> 2];
1836
- nImg32[i1 >> 2] = t;
1837
- i0 += 4;
1838
- i1 -= 4;
1839
- }
1840
- while (this.quantizeVecDot(nImg, i0, e) > eMq) {
1841
- i0 -= 4;
1842
- }
1843
- return i0 + 4;
1844
- }
1845
- /**
1846
- * @internal
1847
- */
1848
- quantizeVecDot(nImg, i, e) {
1849
- return nImg[i] * e[0] + nImg[i + 1] * e[1] + nImg[i + 2] * e[2] + nImg[i + 3] * e[3];
1850
- }
1851
- /**
1852
- * @internal
1853
- */
1854
- m4MultiplyVec(m, v) {
1855
- return [
1856
- m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3],
1857
- m[4] * v[0] + m[5] * v[1] + m[6] * v[2] + m[7] * v[3],
1858
- m[8] * v[0] + m[9] * v[1] + m[10] * v[2] + m[11] * v[3],
1859
- m[12] * v[0] + m[13] * v[1] + m[14] * v[2] + m[15] * v[3]
1860
- ];
1861
- }
1862
- /**
1863
- * @internal
1864
- */
1865
- m4Dot(x, y) {
1866
- return x[0] * y[0] + x[1] * y[1] + x[2] * y[2] + x[3] * y[3];
1867
- }
1868
- /**
1869
- * @internal
1870
- */
1871
- m4Sml(a, y) {
1872
- return [a * y[0], a * y[1], a * y[2], a * y[3]];
1873
- }
1874
- /**
1875
- * @internal
1876
- */
1877
- alphaMul(img, roundA) {
1878
- const nImg = new Uint8Array(img.length);
1879
- const area = img.length >> 2;
1880
- for (let i = 0; i < area; i++) {
1881
- const qi = i << 2;
1882
- let ia = img[qi + 3];
1883
- if (roundA) {
1884
- ia = ia < 128 ? 0 : 255;
1885
- }
1886
- const a = ia * (1 / 255);
1887
- nImg[qi + 0] = img[qi + 0] * a;
1888
- nImg[qi + 1] = img[qi + 1] * a;
1889
- nImg[qi + 2] = img[qi + 2] * a;
1890
- nImg[qi + 3] = ia;
1891
- }
1892
- return nImg;
1893
- }
1894
- }
1895
-
1896
- exports.Color = Color;
1897
- exports.JpegEncoder = JpegEncoder;
1898
- exports.PngEncoder = PngEncoder;