@twin.org/image 0.0.2-next.9 → 0.0.3-next.2

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.
@@ -0,0 +1,740 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ /* eslint-disable no-bitwise */
4
+ /* eslint-disable no-mixed-operators */
5
+ import { GeneralError } from "@twin.org/core";
6
+ /**
7
+ * JPEG Encoder.
8
+ * Based on JPEG encoder ported to JavaScript and optimized by Andreas Ritter.
9
+ */
10
+ export class JpegEncoder {
11
+ /**
12
+ * Runtime name for the class.
13
+ */
14
+ static CLASS_NAME = "JpegEncoder";
15
+ /**
16
+ * @internal
17
+ */
18
+ static _STD_DC_LUMINANCE_NR_CODES = [
19
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
20
+ ];
21
+ /**
22
+ * @internal
23
+ */
24
+ static _STD_DC_LUMINANCE_VALUES = [
25
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
26
+ ];
27
+ /**
28
+ * @internal
29
+ */
30
+ static _STD_AC_LUMINANCE_NR_CODES = [
31
+ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
32
+ ];
33
+ /**
34
+ * @internal
35
+ */
36
+ static _STD_AC_LUMINANCE_VALUES = [
37
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
38
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
39
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
40
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
41
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
42
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
43
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
44
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
45
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
46
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
47
+ 0xf9, 0xfa
48
+ ];
49
+ /**
50
+ * @internal
51
+ */
52
+ static _STD_DC_CHROMINANCE_NR_CODES = [
53
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
54
+ ];
55
+ /**
56
+ * @internal
57
+ */
58
+ static _STD_DC_CHROMINANCE_VALUES = [
59
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
60
+ ];
61
+ /**
62
+ * @internal
63
+ */
64
+ static _STD_AC_CHROMINANCE_NR_CODES = [
65
+ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
66
+ ];
67
+ /**
68
+ * @internal
69
+ */
70
+ static _STD_AC_CHROMINANCE_VALUES = [
71
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
72
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
73
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
74
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
75
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
76
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
77
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
78
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
79
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
80
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
81
+ 0xf9, 0xfa
82
+ ];
83
+ /** @internal */
84
+ static _SIG_ZAG = [
85
+ 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,
86
+ 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
87
+ 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63
88
+ ];
89
+ /**
90
+ * @internal
91
+ */
92
+ _yTable;
93
+ /**
94
+ * @internal
95
+ */
96
+ _uvTable;
97
+ /**
98
+ * @internal
99
+ */
100
+ _fdTblY;
101
+ /**
102
+ * @internal
103
+ */
104
+ _fdTblUV;
105
+ /**
106
+ * @internal
107
+ */
108
+ _ydcHashTable;
109
+ /**
110
+ * @internal
111
+ */
112
+ _uVdcHashTable;
113
+ /**
114
+ * @internal
115
+ */
116
+ _yacHashTable;
117
+ /**
118
+ * @internal
119
+ */
120
+ _uVacHashTable;
121
+ /**
122
+ * @internal
123
+ */
124
+ _bitCode;
125
+ /**
126
+ * @internal
127
+ */
128
+ _category;
129
+ /**
130
+ * @internal
131
+ */
132
+ _outputFDctQuant;
133
+ /**
134
+ * @internal
135
+ */
136
+ _du;
137
+ /**
138
+ * @internal
139
+ */
140
+ _byteOut;
141
+ /**
142
+ * @internal
143
+ */
144
+ _byteNew;
145
+ /**
146
+ * @internal
147
+ */
148
+ _bytePos;
149
+ /**
150
+ * @internal
151
+ */
152
+ _ydu;
153
+ /**
154
+ * @internal
155
+ */
156
+ _udu;
157
+ /**
158
+ * @internal
159
+ */
160
+ _vdu;
161
+ /**
162
+ * @internal
163
+ */
164
+ _rgbYuvTable;
165
+ /**
166
+ * Create a new instance of JpegEncoder.
167
+ */
168
+ constructor() {
169
+ this._yTable = Array.from({ length: 64 });
170
+ this._uvTable = Array.from({ length: 64 });
171
+ this._fdTblY = Array.from({ length: 64 });
172
+ this._fdTblUV = Array.from({ length: 64 });
173
+ this._bitCode = Array.from({ length: 65535 });
174
+ this._category = Array.from({ length: 65535 });
175
+ this._outputFDctQuant = Array.from({ length: 64 });
176
+ this._du = Array.from({ length: 64 });
177
+ this._byteOut = [];
178
+ this._byteNew = 0;
179
+ this._bytePos = 7;
180
+ this._ydu = Array.from({ length: 64 });
181
+ this._udu = Array.from({ length: 64 });
182
+ this._vdu = Array.from({ length: 64 });
183
+ this._rgbYuvTable = Array.from({ length: 2048 });
184
+ this.initHuffmanTbl();
185
+ this.initCategoryNumber();
186
+ this.initRGBYUVTable();
187
+ }
188
+ /**
189
+ * Encode the image with the given quality.
190
+ * @param width The width of the image to encode.
191
+ * @param height The height of the image to encode.
192
+ * @param imageData The data for the image.
193
+ * @param quality The quality to encode the image at.
194
+ * @returns The data for the encoded image.
195
+ */
196
+ encode(width, height, imageData, quality) {
197
+ this.setQuality(quality);
198
+ // Initialize bit writer
199
+ this._byteOut = [];
200
+ this._byteNew = 0;
201
+ this._bytePos = 7;
202
+ // Add JPEG headers
203
+ this.writeWord(0xffd8); // SOI
204
+ this.writeAPP0();
205
+ this.writeDQT();
206
+ this.writeSOF0(width, height);
207
+ this.writeDHT();
208
+ this.writeSOS();
209
+ // Encode 8x8 macro blocks
210
+ let DCY = 0;
211
+ let DCU = 0;
212
+ let DCV = 0;
213
+ this._byteNew = 0;
214
+ this._bytePos = 7;
215
+ const quadWidth = width * 4;
216
+ let x;
217
+ let y = 0;
218
+ let r;
219
+ let g;
220
+ let b;
221
+ let start;
222
+ let p;
223
+ let col;
224
+ let row;
225
+ let pos;
226
+ while (y < height) {
227
+ x = 0;
228
+ while (x < quadWidth) {
229
+ start = quadWidth * y + x;
230
+ p = start;
231
+ col = -1;
232
+ row = 0;
233
+ for (pos = 0; pos < 64; pos++) {
234
+ row = pos >> 3; // /8
235
+ col = (pos & 7) * 4; // %8
236
+ p = start + row * quadWidth + col;
237
+ if (y + row >= height) {
238
+ // padding bottom
239
+ p -= quadWidth * (y + 1 + row - height);
240
+ }
241
+ if (x + col >= quadWidth) {
242
+ // padding right
243
+ p -= x + col - quadWidth + 4;
244
+ }
245
+ r = imageData[p++];
246
+ g = imageData[p++];
247
+ b = imageData[p++];
248
+ // use lookup table (slightly faster)
249
+ this._ydu[pos] =
250
+ ((this._rgbYuvTable[r] +
251
+ this._rgbYuvTable[Math.trunc(g + 256)] +
252
+ this._rgbYuvTable[Math.trunc(b + 512)]) >>
253
+ 16) -
254
+ 128;
255
+ this._udu[pos] =
256
+ ((this._rgbYuvTable[Math.trunc(r + 768)] +
257
+ this._rgbYuvTable[Math.trunc(g + 1024)] +
258
+ this._rgbYuvTable[Math.trunc(b + 1280)]) >>
259
+ 16) -
260
+ 128;
261
+ this._vdu[pos] =
262
+ ((this._rgbYuvTable[Math.trunc(r + 1280)] +
263
+ this._rgbYuvTable[Math.trunc(g + 1536)] +
264
+ this._rgbYuvTable[Math.trunc(b + 1792)]) >>
265
+ 16) -
266
+ 128;
267
+ }
268
+ if (this._ydcHashTable && this._yacHashTable) {
269
+ DCY = this.processDU(this._ydu, this._fdTblY, DCY, this._ydcHashTable, this._yacHashTable);
270
+ }
271
+ if (this._uVdcHashTable && this._uVacHashTable) {
272
+ DCU = this.processDU(this._udu, this._fdTblUV, DCU, this._uVdcHashTable, this._uVacHashTable);
273
+ }
274
+ if (this._uVdcHashTable && this._uVacHashTable) {
275
+ DCV = this.processDU(this._vdu, this._fdTblUV, DCV, this._uVdcHashTable, this._uVacHashTable);
276
+ }
277
+ x += 32;
278
+ }
279
+ y += 8;
280
+ }
281
+ // Do the bit alignment of the EOI marker
282
+ if (this._bytePos >= 0) {
283
+ const fillBits = [];
284
+ fillBits[1] = this._bytePos + 1;
285
+ fillBits[0] = (1 << (this._bytePos + 1)) - 1;
286
+ this.writeBits(fillBits);
287
+ }
288
+ this.writeWord(0xffd9); // EOI
289
+ return new Uint8Array(this._byteOut);
290
+ }
291
+ /**
292
+ * @internal
293
+ */
294
+ setQuality(quality) {
295
+ if (quality <= 0 || quality > 100) {
296
+ throw new GeneralError(JpegEncoder.CLASS_NAME, "invalidQuality", { value: quality });
297
+ }
298
+ let sf = 0;
299
+ if (quality < 50) {
300
+ sf = Math.floor(5000 / quality);
301
+ }
302
+ else {
303
+ sf = Math.floor(200 - quality * 2);
304
+ }
305
+ this.initQuantTables(sf);
306
+ }
307
+ /**
308
+ * @internal
309
+ */
310
+ initQuantTables(sf) {
311
+ const YQT = [
312
+ 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69,
313
+ 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104,
314
+ 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99
315
+ ];
316
+ for (let i = 0; i < 64; i++) {
317
+ let t = Math.floor((YQT[i] * sf + 50) / 100);
318
+ if (t < 1) {
319
+ t = 1;
320
+ }
321
+ else if (t > 255) {
322
+ t = 255;
323
+ }
324
+ this._yTable[JpegEncoder._SIG_ZAG[i]] = t;
325
+ }
326
+ const UVQT = [
327
+ 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99,
328
+ 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
329
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99
330
+ ];
331
+ for (let j = 0; j < 64; j++) {
332
+ let u = Math.floor((UVQT[j] * sf + 50) / 100);
333
+ if (u < 1) {
334
+ u = 1;
335
+ }
336
+ else if (u > 255) {
337
+ u = 255;
338
+ }
339
+ this._uvTable[JpegEncoder._SIG_ZAG[j]] = u;
340
+ }
341
+ const aAsf = [1, 1.387039845, 1.306562965, 1.175875602, 1, 0.785694958, 0.5411961, 0.275899379];
342
+ let k = 0;
343
+ for (let row = 0; row < 8; row++) {
344
+ for (let col = 0; col < 8; col++) {
345
+ this._fdTblY[k] = 1 / (this._yTable[JpegEncoder._SIG_ZAG[k]] * aAsf[row] * aAsf[col] * 8);
346
+ this._fdTblUV[k] = 1 / (this._uvTable[JpegEncoder._SIG_ZAG[k]] * aAsf[row] * aAsf[col] * 8);
347
+ k++;
348
+ }
349
+ }
350
+ }
351
+ /**
352
+ * @internal
353
+ */
354
+ computeHuffmanTbl(nrCodes, stdTable) {
355
+ let codeValue = 0;
356
+ let posInTable = 0;
357
+ const HT = [];
358
+ for (let k = 1; k <= 16; k++) {
359
+ for (let j = 1; j <= nrCodes[k]; j++) {
360
+ HT[stdTable[posInTable]] = [];
361
+ HT[stdTable[posInTable]][0] = codeValue;
362
+ HT[stdTable[posInTable]][1] = k;
363
+ posInTable++;
364
+ codeValue++;
365
+ }
366
+ codeValue *= 2;
367
+ }
368
+ return HT;
369
+ }
370
+ /**
371
+ * @internal
372
+ */
373
+ initHuffmanTbl() {
374
+ this._ydcHashTable = this.computeHuffmanTbl(JpegEncoder._STD_DC_LUMINANCE_NR_CODES, JpegEncoder._STD_DC_LUMINANCE_VALUES);
375
+ this._uVdcHashTable = this.computeHuffmanTbl(JpegEncoder._STD_DC_CHROMINANCE_NR_CODES, JpegEncoder._STD_DC_CHROMINANCE_VALUES);
376
+ this._yacHashTable = this.computeHuffmanTbl(JpegEncoder._STD_AC_LUMINANCE_NR_CODES, JpegEncoder._STD_AC_LUMINANCE_VALUES);
377
+ this._uVacHashTable = this.computeHuffmanTbl(JpegEncoder._STD_AC_CHROMINANCE_NR_CODES, JpegEncoder._STD_AC_CHROMINANCE_VALUES);
378
+ }
379
+ /**
380
+ * @internal
381
+ */
382
+ initCategoryNumber() {
383
+ let nrLower = 1;
384
+ let nrUpper = 2;
385
+ for (let cat = 1; cat <= 15; cat++) {
386
+ // Positive numbers
387
+ for (let nr = nrLower; nr < nrUpper; nr++) {
388
+ this._category[32767 + nr] = cat;
389
+ this._bitCode[32767 + nr] = [];
390
+ this._bitCode[32767 + nr][1] = cat;
391
+ this._bitCode[32767 + nr][0] = nr;
392
+ }
393
+ // Negative numbers
394
+ for (let nrNeg = -(nrUpper - 1); nrNeg <= -nrLower; nrNeg++) {
395
+ this._category[32767 + nrNeg] = cat;
396
+ this._bitCode[32767 + nrNeg] = [];
397
+ this._bitCode[32767 + nrNeg][1] = cat;
398
+ this._bitCode[32767 + nrNeg][0] = nrUpper - 1 + nrNeg;
399
+ }
400
+ nrLower <<= 1;
401
+ nrUpper <<= 1;
402
+ }
403
+ }
404
+ /**
405
+ * @internal
406
+ */
407
+ initRGBYUVTable() {
408
+ for (let i = 0; i < 256; i++) {
409
+ this._rgbYuvTable[i] = 19595 * i;
410
+ this._rgbYuvTable[Math.trunc(i + 256)] = 38470 * i;
411
+ this._rgbYuvTable[Math.trunc(i + 512)] = 7471 * i + 0x8000;
412
+ this._rgbYuvTable[Math.trunc(i + 768)] = -11059 * i;
413
+ this._rgbYuvTable[Math.trunc(i + 1024)] = -21709 * i;
414
+ this._rgbYuvTable[Math.trunc(i + 1280)] = 32768 * i + 0x807fff;
415
+ this._rgbYuvTable[Math.trunc(i + 1536)] = -27439 * i;
416
+ this._rgbYuvTable[Math.trunc(i + 1792)] = -5329 * i;
417
+ }
418
+ }
419
+ /**
420
+ * @internal
421
+ */
422
+ writeBits(bs) {
423
+ const value = bs[0];
424
+ let posVal = bs[1] - 1;
425
+ while (posVal >= 0) {
426
+ if (value & (1 << posVal)) {
427
+ this._byteNew |= 1 << this._bytePos;
428
+ }
429
+ posVal--;
430
+ this._bytePos--;
431
+ if (this._bytePos < 0) {
432
+ if (this._byteNew === 0xff) {
433
+ this.writeByte(0xff);
434
+ this.writeByte(0);
435
+ }
436
+ else {
437
+ this.writeByte(this._byteNew);
438
+ }
439
+ this._bytePos = 7;
440
+ this._byteNew = 0;
441
+ }
442
+ }
443
+ }
444
+ /**
445
+ * @internal
446
+ */
447
+ writeByte(value) {
448
+ this._byteOut.push(value);
449
+ }
450
+ /**
451
+ * @internal
452
+ */
453
+ writeWord(value) {
454
+ this.writeByte((value >> 8) & 0xff);
455
+ this.writeByte(value & 0xff);
456
+ }
457
+ /**
458
+ * @internal
459
+ */
460
+ fDCTQuant(data, fdTbl) {
461
+ let d0;
462
+ let d1;
463
+ let d2;
464
+ let d3;
465
+ let d4;
466
+ let d5;
467
+ let d6;
468
+ let d7;
469
+ /* Pass 1: process rows. */
470
+ let dataOff = 0;
471
+ let i;
472
+ const I8 = 8;
473
+ const I64 = 64;
474
+ for (i = 0; i < I8; ++i) {
475
+ d0 = data[dataOff];
476
+ d1 = data[dataOff + 1];
477
+ d2 = data[dataOff + 2];
478
+ d3 = data[dataOff + 3];
479
+ d4 = data[dataOff + 4];
480
+ d5 = data[dataOff + 5];
481
+ d6 = data[dataOff + 6];
482
+ d7 = data[dataOff + 7];
483
+ const tmp0 = d0 + d7;
484
+ const tmp7 = d0 - d7;
485
+ const tmp1 = d1 + d6;
486
+ const tmp6 = d1 - d6;
487
+ const tmp2 = d2 + d5;
488
+ const tmp5 = d2 - d5;
489
+ const tmp3 = d3 + d4;
490
+ const tmp4 = d3 - d4;
491
+ /* Even part */
492
+ let tmp10 = tmp0 + tmp3; /* phase 2 */
493
+ const tmp13 = tmp0 - tmp3;
494
+ let tmp11 = tmp1 + tmp2;
495
+ let tmp12 = tmp1 - tmp2;
496
+ data[dataOff] = tmp10 + tmp11; /* phase 3 */
497
+ data[dataOff + 4] = tmp10 - tmp11;
498
+ const z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */
499
+ data[dataOff + 2] = tmp13 + z1; /* phase 5 */
500
+ data[dataOff + 6] = tmp13 - z1;
501
+ /* Odd part */
502
+ tmp10 = tmp4 + tmp5; /* phase 2 */
503
+ tmp11 = tmp5 + tmp6;
504
+ tmp12 = tmp6 + tmp7;
505
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
506
+ const z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */
507
+ const z2 = 0.5411961 * tmp10 + z5; /* c2-c6 */
508
+ const z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */
509
+ const z3 = tmp11 * 0.707106781; /* c4 */
510
+ const z11 = tmp7 + z3; /* phase 5 */
511
+ const z13 = tmp7 - z3;
512
+ data[dataOff + 5] = z13 + z2; /* phase 6 */
513
+ data[dataOff + 3] = z13 - z2;
514
+ data[dataOff + 1] = z11 + z4;
515
+ data[dataOff + 7] = z11 - z4;
516
+ dataOff += 8; /* advance pointer to next row */
517
+ }
518
+ /* Pass 2: process columns. */
519
+ dataOff = 0;
520
+ for (i = 0; i < I8; ++i) {
521
+ d0 = data[dataOff];
522
+ d1 = data[dataOff + 8];
523
+ d2 = data[dataOff + 16];
524
+ d3 = data[dataOff + 24];
525
+ d4 = data[dataOff + 32];
526
+ d5 = data[dataOff + 40];
527
+ d6 = data[dataOff + 48];
528
+ d7 = data[dataOff + 56];
529
+ const tmp0p2 = d0 + d7;
530
+ const tmp7p2 = d0 - d7;
531
+ const tmp1p2 = d1 + d6;
532
+ const tmp6p2 = d1 - d6;
533
+ const tmp2p2 = d2 + d5;
534
+ const tmp5p2 = d2 - d5;
535
+ const tmp3p2 = d3 + d4;
536
+ const tmp4p2 = d3 - d4;
537
+ /* Even part */
538
+ let tmp10p2 = tmp0p2 + tmp3p2; /* phase 2 */
539
+ const tmp13p2 = tmp0p2 - tmp3p2;
540
+ let tmp11p2 = tmp1p2 + tmp2p2;
541
+ let tmp12p2 = tmp1p2 - tmp2p2;
542
+ data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */
543
+ data[dataOff + 32] = tmp10p2 - tmp11p2;
544
+ const z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */
545
+ data[dataOff + 16] = tmp13p2 + z1p2; /* phase 5 */
546
+ data[dataOff + 48] = tmp13p2 - z1p2;
547
+ /* Odd part */
548
+ tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */
549
+ tmp11p2 = tmp5p2 + tmp6p2;
550
+ tmp12p2 = tmp6p2 + tmp7p2;
551
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
552
+ const z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */
553
+ const z2p2 = 0.5411961 * tmp10p2 + z5p2; /* c2-c6 */
554
+ const z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */
555
+ const z3p2 = tmp11p2 * 0.707106781; /* c4 */
556
+ const z11p2 = tmp7p2 + z3p2; /* phase 5 */
557
+ const z13p2 = tmp7p2 - z3p2;
558
+ data[dataOff + 40] = z13p2 + z2p2; /* phase 6 */
559
+ data[dataOff + 24] = z13p2 - z2p2;
560
+ data[dataOff + 8] = z11p2 + z4p2;
561
+ data[dataOff + 56] = z11p2 - z4p2;
562
+ dataOff++; /* advance pointer to next column */
563
+ }
564
+ // Quantize/descale the coefficients
565
+ let fDCTQuant;
566
+ for (i = 0; i < I64; ++i) {
567
+ // Apply the quantization and scaling factor & Round to nearest integer
568
+ fDCTQuant = data[i] * fdTbl[i];
569
+ this._outputFDctQuant[i] =
570
+ fDCTQuant > 0 ? Math.trunc(fDCTQuant + 0.5) : Math.trunc(fDCTQuant - 0.5);
571
+ }
572
+ return this._outputFDctQuant;
573
+ }
574
+ /**
575
+ * @internal
576
+ */
577
+ writeAPP0() {
578
+ this.writeWord(0xffe0); // marker
579
+ this.writeWord(16); // length
580
+ this.writeByte(0x4a); // J
581
+ this.writeByte(0x46); // F
582
+ this.writeByte(0x49); // I
583
+ this.writeByte(0x46); // F
584
+ // cspell:disable-next-line
585
+ this.writeByte(0); // = "JFIF",'\0'
586
+ this.writeByte(1); // version hi
587
+ this.writeByte(1); // version lo
588
+ this.writeByte(0); // xy units
589
+ this.writeWord(1); // x density
590
+ this.writeWord(1); // y density
591
+ this.writeByte(0); // thumb n width
592
+ this.writeByte(0); // thumb n height
593
+ }
594
+ /**
595
+ * @internal
596
+ */
597
+ writeSOF0(width, height) {
598
+ this.writeWord(0xffc0); // marker
599
+ this.writeWord(17); // length, true color YUV JPG
600
+ this.writeByte(8); // precision
601
+ this.writeWord(height);
602
+ this.writeWord(width);
603
+ this.writeByte(3); // nr of components
604
+ this.writeByte(1); // IdY
605
+ this.writeByte(0x11); // HVY
606
+ this.writeByte(0); // QTY
607
+ this.writeByte(2); // IdU
608
+ this.writeByte(0x11); // HVU
609
+ this.writeByte(1); // QTU
610
+ this.writeByte(3); // IdV
611
+ this.writeByte(0x11); // HVV
612
+ this.writeByte(1); // QTV
613
+ }
614
+ /**
615
+ * @internal
616
+ */
617
+ writeDQT() {
618
+ this.writeWord(0xffdb); // marker
619
+ this.writeWord(132); // length
620
+ this.writeByte(0);
621
+ for (let i = 0; i < 64; i++) {
622
+ this.writeByte(this._yTable[i]);
623
+ }
624
+ this.writeByte(1);
625
+ for (let j = 0; j < 64; j++) {
626
+ this.writeByte(this._uvTable[j]);
627
+ }
628
+ }
629
+ /**
630
+ * @internal
631
+ */
632
+ writeDHT() {
633
+ this.writeWord(0xffc4); // marker
634
+ this.writeWord(0x01a2); // length
635
+ this.writeByte(0); // HTYDc info
636
+ for (let i = 0; i < 16; i++) {
637
+ this.writeByte(JpegEncoder._STD_DC_LUMINANCE_NR_CODES[i + 1]);
638
+ }
639
+ for (let j = 0; j <= 11; j++) {
640
+ this.writeByte(JpegEncoder._STD_DC_LUMINANCE_VALUES[j]);
641
+ }
642
+ this.writeByte(0x10); // HTYAc info
643
+ for (let k = 0; k < 16; k++) {
644
+ this.writeByte(JpegEncoder._STD_AC_LUMINANCE_NR_CODES[k + 1]);
645
+ }
646
+ for (let l = 0; l <= 161; l++) {
647
+ this.writeByte(JpegEncoder._STD_AC_LUMINANCE_VALUES[l]);
648
+ }
649
+ this.writeByte(1); // HTUDc info
650
+ for (let m = 0; m < 16; m++) {
651
+ this.writeByte(JpegEncoder._STD_DC_CHROMINANCE_NR_CODES[m + 1]);
652
+ }
653
+ for (let n = 0; n <= 11; n++) {
654
+ this.writeByte(JpegEncoder._STD_DC_CHROMINANCE_VALUES[n]);
655
+ }
656
+ this.writeByte(0x11); // HTUAc info
657
+ for (let o = 0; o < 16; o++) {
658
+ this.writeByte(JpegEncoder._STD_AC_CHROMINANCE_NR_CODES[o + 1]);
659
+ }
660
+ for (let p = 0; p <= 161; p++) {
661
+ this.writeByte(JpegEncoder._STD_AC_CHROMINANCE_VALUES[p]);
662
+ }
663
+ }
664
+ /**
665
+ * @internal
666
+ */
667
+ writeSOS() {
668
+ this.writeWord(0xffda); // marker
669
+ this.writeWord(12); // length
670
+ this.writeByte(3); // nr of components
671
+ this.writeByte(1); // IdY
672
+ this.writeByte(0); // HTY
673
+ this.writeByte(2); // IdU
674
+ this.writeByte(0x11); // HTU
675
+ this.writeByte(3); // IdV
676
+ this.writeByte(0x11); // HTV
677
+ this.writeByte(0); // Ss
678
+ this.writeByte(0x3f); // Se
679
+ this.writeByte(0); // Bf
680
+ }
681
+ /**
682
+ * @internal
683
+ */
684
+ processDU(CDU, fdTbl, passedDC, HTDc, HTAc) {
685
+ let DC = passedDC;
686
+ const EOB = HTAc[0x00];
687
+ const m16zeroes = HTAc[0xf0];
688
+ let pos;
689
+ const I16 = 16;
690
+ const I63 = 63;
691
+ const I64 = 64;
692
+ const DU_DCT = this.fDCTQuant(CDU, fdTbl);
693
+ // ZigZag reorder
694
+ for (let j = 0; j < I64; ++j) {
695
+ this._du[JpegEncoder._SIG_ZAG[j]] = DU_DCT[j];
696
+ }
697
+ const diff = this._du[0] - DC;
698
+ DC = this._du[0];
699
+ // Encode DC
700
+ if (diff === 0) {
701
+ this.writeBits(HTDc[0]); // Diff might be 0
702
+ }
703
+ else {
704
+ pos = 32767 + diff;
705
+ this.writeBits(HTDc[this._category[pos]]);
706
+ this.writeBits(this._bitCode[pos]);
707
+ }
708
+ // Encode ACs
709
+ let end0pos = 63; // was const... which is crazy
710
+ for (; end0pos > 0 && this._du[end0pos] === 0; end0pos--) { }
711
+ // end0pos = first element in reverse order !=0
712
+ if (end0pos === 0) {
713
+ this.writeBits(EOB);
714
+ return DC;
715
+ }
716
+ let i = 1;
717
+ let lng;
718
+ while (i <= end0pos) {
719
+ const startPos = i;
720
+ for (; this._du[i] === 0 && i <= end0pos; ++i) { }
721
+ let nrZeroes = i - startPos;
722
+ if (nrZeroes >= I16) {
723
+ lng = nrZeroes >> 4;
724
+ for (let nrMarker = 1; nrMarker <= lng; ++nrMarker) {
725
+ this.writeBits(m16zeroes);
726
+ }
727
+ nrZeroes &= 0xf;
728
+ }
729
+ pos = 32767 + this._du[i];
730
+ this.writeBits(HTAc[(nrZeroes << 4) + this._category[pos]]);
731
+ this.writeBits(this._bitCode[pos]);
732
+ i++;
733
+ }
734
+ if (end0pos !== I63) {
735
+ this.writeBits(EOB);
736
+ }
737
+ return DC;
738
+ }
739
+ }
740
+ //# sourceMappingURL=jpegEncoder.js.map