UNPKG

69.7 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.JpxImage = void 0;
28
29var _util = require("../shared/util.js");
30
31var _core_utils = require("./core_utils.js");
32
33var _arithmetic_decoder = require("./arithmetic_decoder.js");
34
35class JpxError extends _util.BaseException {
36 constructor(msg) {
37 super(`JPX error: ${msg}`, "JpxError");
38 }
39
40}
41
42const SubbandsGainLog2 = {
43 LL: 0,
44 LH: 1,
45 HL: 1,
46 HH: 2
47};
48
49class JpxImage {
50 constructor() {
51 this.failOnCorruptedImage = false;
52 }
53
54 parse(data) {
55 const head = (0, _core_utils.readUint16)(data, 0);
56
57 if (head === 0xff4f) {
58 this.parseCodestream(data, 0, data.length);
59 return;
60 }
61
62 const length = data.length;
63 let position = 0;
64
65 while (position < length) {
66 let headerSize = 8;
67 let lbox = (0, _core_utils.readUint32)(data, position);
68 const tbox = (0, _core_utils.readUint32)(data, position + 4);
69 position += headerSize;
70
71 if (lbox === 1) {
72 lbox = (0, _core_utils.readUint32)(data, position) * 4294967296 + (0, _core_utils.readUint32)(data, position + 4);
73 position += 8;
74 headerSize += 8;
75 }
76
77 if (lbox === 0) {
78 lbox = length - position + headerSize;
79 }
80
81 if (lbox < headerSize) {
82 throw new JpxError("Invalid box field size");
83 }
84
85 const dataLength = lbox - headerSize;
86 let jumpDataLength = true;
87
88 switch (tbox) {
89 case 0x6a703268:
90 jumpDataLength = false;
91 break;
92
93 case 0x636f6c72:
94 const method = data[position];
95
96 if (method === 1) {
97 const colorspace = (0, _core_utils.readUint32)(data, position + 3);
98
99 switch (colorspace) {
100 case 16:
101 case 17:
102 case 18:
103 break;
104
105 default:
106 (0, _util.warn)("Unknown colorspace " + colorspace);
107 break;
108 }
109 } else if (method === 2) {
110 (0, _util.info)("ICC profile not supported");
111 }
112
113 break;
114
115 case 0x6a703263:
116 this.parseCodestream(data, position, position + dataLength);
117 break;
118
119 case 0x6a502020:
120 if ((0, _core_utils.readUint32)(data, position) !== 0x0d0a870a) {
121 (0, _util.warn)("Invalid JP2 signature");
122 }
123
124 break;
125
126 case 0x6a501a1a:
127 case 0x66747970:
128 case 0x72726571:
129 case 0x72657320:
130 case 0x69686472:
131 break;
132
133 default:
134 const headerType = String.fromCharCode(tbox >> 24 & 0xff, tbox >> 16 & 0xff, tbox >> 8 & 0xff, tbox & 0xff);
135 (0, _util.warn)(`Unsupported header type ${tbox} (${headerType}).`);
136 break;
137 }
138
139 if (jumpDataLength) {
140 position += dataLength;
141 }
142 }
143 }
144
145 parseImageProperties(stream) {
146 let newByte = stream.getByte();
147
148 while (newByte >= 0) {
149 const oldByte = newByte;
150 newByte = stream.getByte();
151 const code = oldByte << 8 | newByte;
152
153 if (code === 0xff51) {
154 stream.skip(4);
155 const Xsiz = stream.getInt32() >>> 0;
156 const Ysiz = stream.getInt32() >>> 0;
157 const XOsiz = stream.getInt32() >>> 0;
158 const YOsiz = stream.getInt32() >>> 0;
159 stream.skip(16);
160 const Csiz = stream.getUint16();
161 this.width = Xsiz - XOsiz;
162 this.height = Ysiz - YOsiz;
163 this.componentsCount = Csiz;
164 this.bitsPerComponent = 8;
165 return;
166 }
167 }
168
169 throw new JpxError("No size marker found in JPX stream");
170 }
171
172 parseCodestream(data, start, end) {
173 const context = {};
174 let doNotRecover = false;
175
176 try {
177 let position = start;
178
179 while (position + 1 < end) {
180 const code = (0, _core_utils.readUint16)(data, position);
181 position += 2;
182 let length = 0,
183 j,
184 sqcd,
185 spqcds,
186 spqcdSize,
187 scalarExpounded,
188 tile;
189
190 switch (code) {
191 case 0xff4f:
192 context.mainHeader = true;
193 break;
194
195 case 0xffd9:
196 break;
197
198 case 0xff51:
199 length = (0, _core_utils.readUint16)(data, position);
200 const siz = {};
201 siz.Xsiz = (0, _core_utils.readUint32)(data, position + 4);
202 siz.Ysiz = (0, _core_utils.readUint32)(data, position + 8);
203 siz.XOsiz = (0, _core_utils.readUint32)(data, position + 12);
204 siz.YOsiz = (0, _core_utils.readUint32)(data, position + 16);
205 siz.XTsiz = (0, _core_utils.readUint32)(data, position + 20);
206 siz.YTsiz = (0, _core_utils.readUint32)(data, position + 24);
207 siz.XTOsiz = (0, _core_utils.readUint32)(data, position + 28);
208 siz.YTOsiz = (0, _core_utils.readUint32)(data, position + 32);
209 const componentsCount = (0, _core_utils.readUint16)(data, position + 36);
210 siz.Csiz = componentsCount;
211 const components = [];
212 j = position + 38;
213
214 for (let i = 0; i < componentsCount; i++) {
215 const component = {
216 precision: (data[j] & 0x7f) + 1,
217 isSigned: !!(data[j] & 0x80),
218 XRsiz: data[j + 1],
219 YRsiz: data[j + 2]
220 };
221 j += 3;
222 calculateComponentDimensions(component, siz);
223 components.push(component);
224 }
225
226 context.SIZ = siz;
227 context.components = components;
228 calculateTileGrids(context, components);
229 context.QCC = [];
230 context.COC = [];
231 break;
232
233 case 0xff5c:
234 length = (0, _core_utils.readUint16)(data, position);
235 const qcd = {};
236 j = position + 2;
237 sqcd = data[j++];
238
239 switch (sqcd & 0x1f) {
240 case 0:
241 spqcdSize = 8;
242 scalarExpounded = true;
243 break;
244
245 case 1:
246 spqcdSize = 16;
247 scalarExpounded = false;
248 break;
249
250 case 2:
251 spqcdSize = 16;
252 scalarExpounded = true;
253 break;
254
255 default:
256 throw new Error("Invalid SQcd value " + sqcd);
257 }
258
259 qcd.noQuantization = spqcdSize === 8;
260 qcd.scalarExpounded = scalarExpounded;
261 qcd.guardBits = sqcd >> 5;
262 spqcds = [];
263
264 while (j < length + position) {
265 const spqcd = {};
266
267 if (spqcdSize === 8) {
268 spqcd.epsilon = data[j++] >> 3;
269 spqcd.mu = 0;
270 } else {
271 spqcd.epsilon = data[j] >> 3;
272 spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1];
273 j += 2;
274 }
275
276 spqcds.push(spqcd);
277 }
278
279 qcd.SPqcds = spqcds;
280
281 if (context.mainHeader) {
282 context.QCD = qcd;
283 } else {
284 context.currentTile.QCD = qcd;
285 context.currentTile.QCC = [];
286 }
287
288 break;
289
290 case 0xff5d:
291 length = (0, _core_utils.readUint16)(data, position);
292 const qcc = {};
293 j = position + 2;
294 let cqcc;
295
296 if (context.SIZ.Csiz < 257) {
297 cqcc = data[j++];
298 } else {
299 cqcc = (0, _core_utils.readUint16)(data, j);
300 j += 2;
301 }
302
303 sqcd = data[j++];
304
305 switch (sqcd & 0x1f) {
306 case 0:
307 spqcdSize = 8;
308 scalarExpounded = true;
309 break;
310
311 case 1:
312 spqcdSize = 16;
313 scalarExpounded = false;
314 break;
315
316 case 2:
317 spqcdSize = 16;
318 scalarExpounded = true;
319 break;
320
321 default:
322 throw new Error("Invalid SQcd value " + sqcd);
323 }
324
325 qcc.noQuantization = spqcdSize === 8;
326 qcc.scalarExpounded = scalarExpounded;
327 qcc.guardBits = sqcd >> 5;
328 spqcds = [];
329
330 while (j < length + position) {
331 const spqcd = {};
332
333 if (spqcdSize === 8) {
334 spqcd.epsilon = data[j++] >> 3;
335 spqcd.mu = 0;
336 } else {
337 spqcd.epsilon = data[j] >> 3;
338 spqcd.mu = (data[j] & 0x7) << 8 | data[j + 1];
339 j += 2;
340 }
341
342 spqcds.push(spqcd);
343 }
344
345 qcc.SPqcds = spqcds;
346
347 if (context.mainHeader) {
348 context.QCC[cqcc] = qcc;
349 } else {
350 context.currentTile.QCC[cqcc] = qcc;
351 }
352
353 break;
354
355 case 0xff52:
356 length = (0, _core_utils.readUint16)(data, position);
357 const cod = {};
358 j = position + 2;
359 const scod = data[j++];
360 cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
361 cod.sopMarkerUsed = !!(scod & 2);
362 cod.ephMarkerUsed = !!(scod & 4);
363 cod.progressionOrder = data[j++];
364 cod.layersCount = (0, _core_utils.readUint16)(data, j);
365 j += 2;
366 cod.multipleComponentTransform = data[j++];
367 cod.decompositionLevelsCount = data[j++];
368 cod.xcb = (data[j++] & 0xf) + 2;
369 cod.ycb = (data[j++] & 0xf) + 2;
370 const blockStyle = data[j++];
371 cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
372 cod.resetContextProbabilities = !!(blockStyle & 2);
373 cod.terminationOnEachCodingPass = !!(blockStyle & 4);
374 cod.verticallyStripe = !!(blockStyle & 8);
375 cod.predictableTermination = !!(blockStyle & 16);
376 cod.segmentationSymbolUsed = !!(blockStyle & 32);
377 cod.reversibleTransformation = data[j++];
378
379 if (cod.entropyCoderWithCustomPrecincts) {
380 const precinctsSizes = [];
381
382 while (j < length + position) {
383 const precinctsSize = data[j++];
384 precinctsSizes.push({
385 PPx: precinctsSize & 0xf,
386 PPy: precinctsSize >> 4
387 });
388 }
389
390 cod.precinctsSizes = precinctsSizes;
391 }
392
393 const unsupported = [];
394
395 if (cod.selectiveArithmeticCodingBypass) {
396 unsupported.push("selectiveArithmeticCodingBypass");
397 }
398
399 if (cod.terminationOnEachCodingPass) {
400 unsupported.push("terminationOnEachCodingPass");
401 }
402
403 if (cod.verticallyStripe) {
404 unsupported.push("verticallyStripe");
405 }
406
407 if (cod.predictableTermination) {
408 unsupported.push("predictableTermination");
409 }
410
411 if (unsupported.length > 0) {
412 doNotRecover = true;
413 (0, _util.warn)(`JPX: Unsupported COD options (${unsupported.join(", ")}).`);
414 }
415
416 if (context.mainHeader) {
417 context.COD = cod;
418 } else {
419 context.currentTile.COD = cod;
420 context.currentTile.COC = [];
421 }
422
423 break;
424
425 case 0xff90:
426 length = (0, _core_utils.readUint16)(data, position);
427 tile = {};
428 tile.index = (0, _core_utils.readUint16)(data, position + 2);
429 tile.length = (0, _core_utils.readUint32)(data, position + 4);
430 tile.dataEnd = tile.length + position - 2;
431 tile.partIndex = data[position + 8];
432 tile.partsCount = data[position + 9];
433 context.mainHeader = false;
434
435 if (tile.partIndex === 0) {
436 tile.COD = context.COD;
437 tile.COC = context.COC.slice(0);
438 tile.QCD = context.QCD;
439 tile.QCC = context.QCC.slice(0);
440 }
441
442 context.currentTile = tile;
443 break;
444
445 case 0xff93:
446 tile = context.currentTile;
447
448 if (tile.partIndex === 0) {
449 initializeTile(context, tile.index);
450 buildPackets(context);
451 }
452
453 length = tile.dataEnd - position;
454 parseTilePackets(context, data, position, length);
455 break;
456
457 case 0xff53:
458 (0, _util.warn)("JPX: Codestream code 0xFF53 (COC) is not implemented.");
459
460 case 0xff55:
461 case 0xff57:
462 case 0xff58:
463 case 0xff64:
464 length = (0, _core_utils.readUint16)(data, position);
465 break;
466
467 default:
468 throw new Error("Unknown codestream code: " + code.toString(16));
469 }
470
471 position += length;
472 }
473 } catch (e) {
474 if (doNotRecover || this.failOnCorruptedImage) {
475 throw new JpxError(e.message);
476 } else {
477 (0, _util.warn)(`JPX: Trying to recover from: "${e.message}".`);
478 }
479 }
480
481 this.tiles = transformComponents(context);
482 this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
483 this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
484 this.componentsCount = context.SIZ.Csiz;
485 }
486
487}
488
489exports.JpxImage = JpxImage;
490
491function calculateComponentDimensions(component, siz) {
492 component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
493 component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
494 component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
495 component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
496 component.width = component.x1 - component.x0;
497 component.height = component.y1 - component.y0;
498}
499
500function calculateTileGrids(context, components) {
501 const siz = context.SIZ;
502 const tiles = [];
503 let tile;
504 const numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);
505 const numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);
506
507 for (let q = 0; q < numYtiles; q++) {
508 for (let p = 0; p < numXtiles; p++) {
509 tile = {};
510 tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);
511 tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);
512 tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);
513 tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
514 tile.width = tile.tx1 - tile.tx0;
515 tile.height = tile.ty1 - tile.ty0;
516 tile.components = [];
517 tiles.push(tile);
518 }
519 }
520
521 context.tiles = tiles;
522 const componentsCount = siz.Csiz;
523
524 for (let i = 0, ii = componentsCount; i < ii; i++) {
525 const component = components[i];
526
527 for (let j = 0, jj = tiles.length; j < jj; j++) {
528 const tileComponent = {};
529 tile = tiles[j];
530 tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
531 tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
532 tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
533 tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
534 tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
535 tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
536 tile.components[i] = tileComponent;
537 }
538 }
539}
540
541function getBlocksDimensions(context, component, r) {
542 const codOrCoc = component.codingStyleParameters;
543 const result = {};
544
545 if (!codOrCoc.entropyCoderWithCustomPrecincts) {
546 result.PPx = 15;
547 result.PPy = 15;
548 } else {
549 result.PPx = codOrCoc.precinctsSizes[r].PPx;
550 result.PPy = codOrCoc.precinctsSizes[r].PPy;
551 }
552
553 result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : Math.min(codOrCoc.xcb, result.PPx);
554 result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : Math.min(codOrCoc.ycb, result.PPy);
555 return result;
556}
557
558function buildPrecincts(context, resolution, dimensions) {
559 const precinctWidth = 1 << dimensions.PPx;
560 const precinctHeight = 1 << dimensions.PPy;
561 const isZeroRes = resolution.resLevel === 0;
562 const precinctWidthInSubband = 1 << dimensions.PPx + (isZeroRes ? 0 : -1);
563 const precinctHeightInSubband = 1 << dimensions.PPy + (isZeroRes ? 0 : -1);
564 const numprecinctswide = resolution.trx1 > resolution.trx0 ? Math.ceil(resolution.trx1 / precinctWidth) - Math.floor(resolution.trx0 / precinctWidth) : 0;
565 const numprecinctshigh = resolution.try1 > resolution.try0 ? Math.ceil(resolution.try1 / precinctHeight) - Math.floor(resolution.try0 / precinctHeight) : 0;
566 const numprecincts = numprecinctswide * numprecinctshigh;
567 resolution.precinctParameters = {
568 precinctWidth,
569 precinctHeight,
570 numprecinctswide,
571 numprecinctshigh,
572 numprecincts,
573 precinctWidthInSubband,
574 precinctHeightInSubband
575 };
576}
577
578function buildCodeblocks(context, subband, dimensions) {
579 const xcb_ = dimensions.xcb_;
580 const ycb_ = dimensions.ycb_;
581 const codeblockWidth = 1 << xcb_;
582 const codeblockHeight = 1 << ycb_;
583 const cbx0 = subband.tbx0 >> xcb_;
584 const cby0 = subband.tby0 >> ycb_;
585 const cbx1 = subband.tbx1 + codeblockWidth - 1 >> xcb_;
586 const cby1 = subband.tby1 + codeblockHeight - 1 >> ycb_;
587 const precinctParameters = subband.resolution.precinctParameters;
588 const codeblocks = [];
589 const precincts = [];
590 let i, j, codeblock, precinctNumber;
591
592 for (j = cby0; j < cby1; j++) {
593 for (i = cbx0; i < cbx1; i++) {
594 codeblock = {
595 cbx: i,
596 cby: j,
597 tbx0: codeblockWidth * i,
598 tby0: codeblockHeight * j,
599 tbx1: codeblockWidth * (i + 1),
600 tby1: codeblockHeight * (j + 1)
601 };
602 codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
603 codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
604 codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
605 codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
606 const pi = Math.floor((codeblock.tbx0_ - subband.tbx0) / precinctParameters.precinctWidthInSubband);
607 const pj = Math.floor((codeblock.tby0_ - subband.tby0) / precinctParameters.precinctHeightInSubband);
608 precinctNumber = pi + pj * precinctParameters.numprecinctswide;
609 codeblock.precinctNumber = precinctNumber;
610 codeblock.subbandType = subband.type;
611 codeblock.Lblock = 3;
612
613 if (codeblock.tbx1_ <= codeblock.tbx0_ || codeblock.tby1_ <= codeblock.tby0_) {
614 continue;
615 }
616
617 codeblocks.push(codeblock);
618 let precinct = precincts[precinctNumber];
619
620 if (precinct !== undefined) {
621 if (i < precinct.cbxMin) {
622 precinct.cbxMin = i;
623 } else if (i > precinct.cbxMax) {
624 precinct.cbxMax = i;
625 }
626
627 if (j < precinct.cbyMin) {
628 precinct.cbxMin = j;
629 } else if (j > precinct.cbyMax) {
630 precinct.cbyMax = j;
631 }
632 } else {
633 precincts[precinctNumber] = precinct = {
634 cbxMin: i,
635 cbyMin: j,
636 cbxMax: i,
637 cbyMax: j
638 };
639 }
640
641 codeblock.precinct = precinct;
642 }
643 }
644
645 subband.codeblockParameters = {
646 codeblockWidth: xcb_,
647 codeblockHeight: ycb_,
648 numcodeblockwide: cbx1 - cbx0 + 1,
649 numcodeblockhigh: cby1 - cby0 + 1
650 };
651 subband.codeblocks = codeblocks;
652 subband.precincts = precincts;
653}
654
655function createPacket(resolution, precinctNumber, layerNumber) {
656 const precinctCodeblocks = [];
657 const subbands = resolution.subbands;
658
659 for (let i = 0, ii = subbands.length; i < ii; i++) {
660 const subband = subbands[i];
661 const codeblocks = subband.codeblocks;
662
663 for (let j = 0, jj = codeblocks.length; j < jj; j++) {
664 const codeblock = codeblocks[j];
665
666 if (codeblock.precinctNumber !== precinctNumber) {
667 continue;
668 }
669
670 precinctCodeblocks.push(codeblock);
671 }
672 }
673
674 return {
675 layerNumber,
676 codeblocks: precinctCodeblocks
677 };
678}
679
680function LayerResolutionComponentPositionIterator(context) {
681 const siz = context.SIZ;
682 const tileIndex = context.currentTile.index;
683 const tile = context.tiles[tileIndex];
684 const layersCount = tile.codingStyleDefaultParameters.layersCount;
685 const componentsCount = siz.Csiz;
686 let maxDecompositionLevelsCount = 0;
687
688 for (let q = 0; q < componentsCount; q++) {
689 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount);
690 }
691
692 let l = 0,
693 r = 0,
694 i = 0,
695 k = 0;
696
697 this.nextPacket = function JpxImage_nextPacket() {
698 for (; l < layersCount; l++) {
699 for (; r <= maxDecompositionLevelsCount; r++) {
700 for (; i < componentsCount; i++) {
701 const component = tile.components[i];
702
703 if (r > component.codingStyleParameters.decompositionLevelsCount) {
704 continue;
705 }
706
707 const resolution = component.resolutions[r];
708 const numprecincts = resolution.precinctParameters.numprecincts;
709
710 for (; k < numprecincts;) {
711 const packet = createPacket(resolution, k, l);
712 k++;
713 return packet;
714 }
715
716 k = 0;
717 }
718
719 i = 0;
720 }
721
722 r = 0;
723 }
724
725 throw new JpxError("Out of packets");
726 };
727}
728
729function ResolutionLayerComponentPositionIterator(context) {
730 const siz = context.SIZ;
731 const tileIndex = context.currentTile.index;
732 const tile = context.tiles[tileIndex];
733 const layersCount = tile.codingStyleDefaultParameters.layersCount;
734 const componentsCount = siz.Csiz;
735 let maxDecompositionLevelsCount = 0;
736
737 for (let q = 0; q < componentsCount; q++) {
738 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, tile.components[q].codingStyleParameters.decompositionLevelsCount);
739 }
740
741 let r = 0,
742 l = 0,
743 i = 0,
744 k = 0;
745
746 this.nextPacket = function JpxImage_nextPacket() {
747 for (; r <= maxDecompositionLevelsCount; r++) {
748 for (; l < layersCount; l++) {
749 for (; i < componentsCount; i++) {
750 const component = tile.components[i];
751
752 if (r > component.codingStyleParameters.decompositionLevelsCount) {
753 continue;
754 }
755
756 const resolution = component.resolutions[r];
757 const numprecincts = resolution.precinctParameters.numprecincts;
758
759 for (; k < numprecincts;) {
760 const packet = createPacket(resolution, k, l);
761 k++;
762 return packet;
763 }
764
765 k = 0;
766 }
767
768 i = 0;
769 }
770
771 l = 0;
772 }
773
774 throw new JpxError("Out of packets");
775 };
776}
777
778function ResolutionPositionComponentLayerIterator(context) {
779 const siz = context.SIZ;
780 const tileIndex = context.currentTile.index;
781 const tile = context.tiles[tileIndex];
782 const layersCount = tile.codingStyleDefaultParameters.layersCount;
783 const componentsCount = siz.Csiz;
784 let l, r, c, p;
785 let maxDecompositionLevelsCount = 0;
786
787 for (c = 0; c < componentsCount; c++) {
788 const component = tile.components[c];
789 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount, component.codingStyleParameters.decompositionLevelsCount);
790 }
791
792 const maxNumPrecinctsInLevel = new Int32Array(maxDecompositionLevelsCount + 1);
793
794 for (r = 0; r <= maxDecompositionLevelsCount; ++r) {
795 let maxNumPrecincts = 0;
796
797 for (c = 0; c < componentsCount; ++c) {
798 const resolutions = tile.components[c].resolutions;
799
800 if (r < resolutions.length) {
801 maxNumPrecincts = Math.max(maxNumPrecincts, resolutions[r].precinctParameters.numprecincts);
802 }
803 }
804
805 maxNumPrecinctsInLevel[r] = maxNumPrecincts;
806 }
807
808 l = 0;
809 r = 0;
810 c = 0;
811 p = 0;
812
813 this.nextPacket = function JpxImage_nextPacket() {
814 for (; r <= maxDecompositionLevelsCount; r++) {
815 for (; p < maxNumPrecinctsInLevel[r]; p++) {
816 for (; c < componentsCount; c++) {
817 const component = tile.components[c];
818
819 if (r > component.codingStyleParameters.decompositionLevelsCount) {
820 continue;
821 }
822
823 const resolution = component.resolutions[r];
824 const numprecincts = resolution.precinctParameters.numprecincts;
825
826 if (p >= numprecincts) {
827 continue;
828 }
829
830 for (; l < layersCount;) {
831 const packet = createPacket(resolution, p, l);
832 l++;
833 return packet;
834 }
835
836 l = 0;
837 }
838
839 c = 0;
840 }
841
842 p = 0;
843 }
844
845 throw new JpxError("Out of packets");
846 };
847}
848
849function PositionComponentResolutionLayerIterator(context) {
850 const siz = context.SIZ;
851 const tileIndex = context.currentTile.index;
852 const tile = context.tiles[tileIndex];
853 const layersCount = tile.codingStyleDefaultParameters.layersCount;
854 const componentsCount = siz.Csiz;
855 const precinctsSizes = getPrecinctSizesInImageScale(tile);
856 const precinctsIterationSizes = precinctsSizes;
857 let l = 0,
858 r = 0,
859 c = 0,
860 px = 0,
861 py = 0;
862
863 this.nextPacket = function JpxImage_nextPacket() {
864 for (; py < precinctsIterationSizes.maxNumHigh; py++) {
865 for (; px < precinctsIterationSizes.maxNumWide; px++) {
866 for (; c < componentsCount; c++) {
867 const component = tile.components[c];
868 const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount;
869
870 for (; r <= decompositionLevelsCount; r++) {
871 const resolution = component.resolutions[r];
872 const sizeInImageScale = precinctsSizes.components[c].resolutions[r];
873 const k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution);
874
875 if (k === null) {
876 continue;
877 }
878
879 for (; l < layersCount;) {
880 const packet = createPacket(resolution, k, l);
881 l++;
882 return packet;
883 }
884
885 l = 0;
886 }
887
888 r = 0;
889 }
890
891 c = 0;
892 }
893
894 px = 0;
895 }
896
897 throw new JpxError("Out of packets");
898 };
899}
900
901function ComponentPositionResolutionLayerIterator(context) {
902 const siz = context.SIZ;
903 const tileIndex = context.currentTile.index;
904 const tile = context.tiles[tileIndex];
905 const layersCount = tile.codingStyleDefaultParameters.layersCount;
906 const componentsCount = siz.Csiz;
907 const precinctsSizes = getPrecinctSizesInImageScale(tile);
908 let l = 0,
909 r = 0,
910 c = 0,
911 px = 0,
912 py = 0;
913
914 this.nextPacket = function JpxImage_nextPacket() {
915 for (; c < componentsCount; ++c) {
916 const component = tile.components[c];
917 const precinctsIterationSizes = precinctsSizes.components[c];
918 const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount;
919
920 for (; py < precinctsIterationSizes.maxNumHigh; py++) {
921 for (; px < precinctsIterationSizes.maxNumWide; px++) {
922 for (; r <= decompositionLevelsCount; r++) {
923 const resolution = component.resolutions[r];
924 const sizeInImageScale = precinctsIterationSizes.resolutions[r];
925 const k = getPrecinctIndexIfExist(px, py, sizeInImageScale, precinctsIterationSizes, resolution);
926
927 if (k === null) {
928 continue;
929 }
930
931 for (; l < layersCount;) {
932 const packet = createPacket(resolution, k, l);
933 l++;
934 return packet;
935 }
936
937 l = 0;
938 }
939
940 r = 0;
941 }
942
943 px = 0;
944 }
945
946 py = 0;
947 }
948
949 throw new JpxError("Out of packets");
950 };
951}
952
953function getPrecinctIndexIfExist(pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) {
954 const posX = pxIndex * precinctIterationSizes.minWidth;
955 const posY = pyIndex * precinctIterationSizes.minHeight;
956
957 if (posX % sizeInImageScale.width !== 0 || posY % sizeInImageScale.height !== 0) {
958 return null;
959 }
960
961 const startPrecinctRowIndex = posY / sizeInImageScale.width * resolution.precinctParameters.numprecinctswide;
962 return posX / sizeInImageScale.height + startPrecinctRowIndex;
963}
964
965function getPrecinctSizesInImageScale(tile) {
966 const componentsCount = tile.components.length;
967 let minWidth = Number.MAX_VALUE;
968 let minHeight = Number.MAX_VALUE;
969 let maxNumWide = 0;
970 let maxNumHigh = 0;
971 const sizePerComponent = new Array(componentsCount);
972
973 for (let c = 0; c < componentsCount; c++) {
974 const component = tile.components[c];
975 const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount;
976 const sizePerResolution = new Array(decompositionLevelsCount + 1);
977 let minWidthCurrentComponent = Number.MAX_VALUE;
978 let minHeightCurrentComponent = Number.MAX_VALUE;
979 let maxNumWideCurrentComponent = 0;
980 let maxNumHighCurrentComponent = 0;
981 let scale = 1;
982
983 for (let r = decompositionLevelsCount; r >= 0; --r) {
984 const resolution = component.resolutions[r];
985 const widthCurrentResolution = scale * resolution.precinctParameters.precinctWidth;
986 const heightCurrentResolution = scale * resolution.precinctParameters.precinctHeight;
987 minWidthCurrentComponent = Math.min(minWidthCurrentComponent, widthCurrentResolution);
988 minHeightCurrentComponent = Math.min(minHeightCurrentComponent, heightCurrentResolution);
989 maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent, resolution.precinctParameters.numprecinctswide);
990 maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent, resolution.precinctParameters.numprecinctshigh);
991 sizePerResolution[r] = {
992 width: widthCurrentResolution,
993 height: heightCurrentResolution
994 };
995 scale <<= 1;
996 }
997
998 minWidth = Math.min(minWidth, minWidthCurrentComponent);
999 minHeight = Math.min(minHeight, minHeightCurrentComponent);
1000 maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent);
1001 maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent);
1002 sizePerComponent[c] = {
1003 resolutions: sizePerResolution,
1004 minWidth: minWidthCurrentComponent,
1005 minHeight: minHeightCurrentComponent,
1006 maxNumWide: maxNumWideCurrentComponent,
1007 maxNumHigh: maxNumHighCurrentComponent
1008 };
1009 }
1010
1011 return {
1012 components: sizePerComponent,
1013 minWidth,
1014 minHeight,
1015 maxNumWide,
1016 maxNumHigh
1017 };
1018}
1019
1020function buildPackets(context) {
1021 const siz = context.SIZ;
1022 const tileIndex = context.currentTile.index;
1023 const tile = context.tiles[tileIndex];
1024 const componentsCount = siz.Csiz;
1025
1026 for (let c = 0; c < componentsCount; c++) {
1027 const component = tile.components[c];
1028 const decompositionLevelsCount = component.codingStyleParameters.decompositionLevelsCount;
1029 const resolutions = [];
1030 const subbands = [];
1031
1032 for (let r = 0; r <= decompositionLevelsCount; r++) {
1033 const blocksDimensions = getBlocksDimensions(context, component, r);
1034 const resolution = {};
1035 const scale = 1 << decompositionLevelsCount - r;
1036 resolution.trx0 = Math.ceil(component.tcx0 / scale);
1037 resolution.try0 = Math.ceil(component.tcy0 / scale);
1038 resolution.trx1 = Math.ceil(component.tcx1 / scale);
1039 resolution.try1 = Math.ceil(component.tcy1 / scale);
1040 resolution.resLevel = r;
1041 buildPrecincts(context, resolution, blocksDimensions);
1042 resolutions.push(resolution);
1043 let subband;
1044
1045 if (r === 0) {
1046 subband = {};
1047 subband.type = "LL";
1048 subband.tbx0 = Math.ceil(component.tcx0 / scale);
1049 subband.tby0 = Math.ceil(component.tcy0 / scale);
1050 subband.tbx1 = Math.ceil(component.tcx1 / scale);
1051 subband.tby1 = Math.ceil(component.tcy1 / scale);
1052 subband.resolution = resolution;
1053 buildCodeblocks(context, subband, blocksDimensions);
1054 subbands.push(subband);
1055 resolution.subbands = [subband];
1056 } else {
1057 const bscale = 1 << decompositionLevelsCount - r + 1;
1058 const resolutionSubbands = [];
1059 subband = {};
1060 subband.type = "HL";
1061 subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
1062 subband.tby0 = Math.ceil(component.tcy0 / bscale);
1063 subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
1064 subband.tby1 = Math.ceil(component.tcy1 / bscale);
1065 subband.resolution = resolution;
1066 buildCodeblocks(context, subband, blocksDimensions);
1067 subbands.push(subband);
1068 resolutionSubbands.push(subband);
1069 subband = {};
1070 subband.type = "LH";
1071 subband.tbx0 = Math.ceil(component.tcx0 / bscale);
1072 subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
1073 subband.tbx1 = Math.ceil(component.tcx1 / bscale);
1074 subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
1075 subband.resolution = resolution;
1076 buildCodeblocks(context, subband, blocksDimensions);
1077 subbands.push(subband);
1078 resolutionSubbands.push(subband);
1079 subband = {};
1080 subband.type = "HH";
1081 subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
1082 subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
1083 subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
1084 subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
1085 subband.resolution = resolution;
1086 buildCodeblocks(context, subband, blocksDimensions);
1087 subbands.push(subband);
1088 resolutionSubbands.push(subband);
1089 resolution.subbands = resolutionSubbands;
1090 }
1091 }
1092
1093 component.resolutions = resolutions;
1094 component.subbands = subbands;
1095 }
1096
1097 const progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
1098
1099 switch (progressionOrder) {
1100 case 0:
1101 tile.packetsIterator = new LayerResolutionComponentPositionIterator(context);
1102 break;
1103
1104 case 1:
1105 tile.packetsIterator = new ResolutionLayerComponentPositionIterator(context);
1106 break;
1107
1108 case 2:
1109 tile.packetsIterator = new ResolutionPositionComponentLayerIterator(context);
1110 break;
1111
1112 case 3:
1113 tile.packetsIterator = new PositionComponentResolutionLayerIterator(context);
1114 break;
1115
1116 case 4:
1117 tile.packetsIterator = new ComponentPositionResolutionLayerIterator(context);
1118 break;
1119
1120 default:
1121 throw new JpxError(`Unsupported progression order ${progressionOrder}`);
1122 }
1123}
1124
1125function parseTilePackets(context, data, offset, dataLength) {
1126 let position = 0;
1127 let buffer,
1128 bufferSize = 0,
1129 skipNextBit = false;
1130
1131 function readBits(count) {
1132 while (bufferSize < count) {
1133 const b = data[offset + position];
1134 position++;
1135
1136 if (skipNextBit) {
1137 buffer = buffer << 7 | b;
1138 bufferSize += 7;
1139 skipNextBit = false;
1140 } else {
1141 buffer = buffer << 8 | b;
1142 bufferSize += 8;
1143 }
1144
1145 if (b === 0xff) {
1146 skipNextBit = true;
1147 }
1148 }
1149
1150 bufferSize -= count;
1151 return buffer >>> bufferSize & (1 << count) - 1;
1152 }
1153
1154 function skipMarkerIfEqual(value) {
1155 if (data[offset + position - 1] === 0xff && data[offset + position] === value) {
1156 skipBytes(1);
1157 return true;
1158 } else if (data[offset + position] === 0xff && data[offset + position + 1] === value) {
1159 skipBytes(2);
1160 return true;
1161 }
1162
1163 return false;
1164 }
1165
1166 function skipBytes(count) {
1167 position += count;
1168 }
1169
1170 function alignToByte() {
1171 bufferSize = 0;
1172
1173 if (skipNextBit) {
1174 position++;
1175 skipNextBit = false;
1176 }
1177 }
1178
1179 function readCodingpasses() {
1180 if (readBits(1) === 0) {
1181 return 1;
1182 }
1183
1184 if (readBits(1) === 0) {
1185 return 2;
1186 }
1187
1188 let value = readBits(2);
1189
1190 if (value < 3) {
1191 return value + 3;
1192 }
1193
1194 value = readBits(5);
1195
1196 if (value < 31) {
1197 return value + 6;
1198 }
1199
1200 value = readBits(7);
1201 return value + 37;
1202 }
1203
1204 const tileIndex = context.currentTile.index;
1205 const tile = context.tiles[tileIndex];
1206 const sopMarkerUsed = context.COD.sopMarkerUsed;
1207 const ephMarkerUsed = context.COD.ephMarkerUsed;
1208 const packetsIterator = tile.packetsIterator;
1209
1210 while (position < dataLength) {
1211 alignToByte();
1212
1213 if (sopMarkerUsed && skipMarkerIfEqual(0x91)) {
1214 skipBytes(4);
1215 }
1216
1217 const packet = packetsIterator.nextPacket();
1218
1219 if (!readBits(1)) {
1220 continue;
1221 }
1222
1223 const layerNumber = packet.layerNumber,
1224 queue = [];
1225 let codeblock;
1226
1227 for (let i = 0, ii = packet.codeblocks.length; i < ii; i++) {
1228 codeblock = packet.codeblocks[i];
1229 let precinct = codeblock.precinct;
1230 const codeblockColumn = codeblock.cbx - precinct.cbxMin;
1231 const codeblockRow = codeblock.cby - precinct.cbyMin;
1232 let codeblockIncluded = false;
1233 let firstTimeInclusion = false;
1234 let valueReady, zeroBitPlanesTree;
1235
1236 if (codeblock.included !== undefined) {
1237 codeblockIncluded = !!readBits(1);
1238 } else {
1239 precinct = codeblock.precinct;
1240 let inclusionTree;
1241
1242 if (precinct.inclusionTree !== undefined) {
1243 inclusionTree = precinct.inclusionTree;
1244 } else {
1245 const width = precinct.cbxMax - precinct.cbxMin + 1;
1246 const height = precinct.cbyMax - precinct.cbyMin + 1;
1247 inclusionTree = new InclusionTree(width, height, layerNumber);
1248 zeroBitPlanesTree = new TagTree(width, height);
1249 precinct.inclusionTree = inclusionTree;
1250 precinct.zeroBitPlanesTree = zeroBitPlanesTree;
1251
1252 for (let l = 0; l < layerNumber; l++) {
1253 if (readBits(1) !== 0) {
1254 throw new JpxError("Invalid tag tree");
1255 }
1256 }
1257 }
1258
1259 if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
1260 while (true) {
1261 if (readBits(1)) {
1262 valueReady = !inclusionTree.nextLevel();
1263
1264 if (valueReady) {
1265 codeblock.included = true;
1266 codeblockIncluded = firstTimeInclusion = true;
1267 break;
1268 }
1269 } else {
1270 inclusionTree.incrementValue(layerNumber);
1271 break;
1272 }
1273 }
1274 }
1275 }
1276
1277 if (!codeblockIncluded) {
1278 continue;
1279 }
1280
1281 if (firstTimeInclusion) {
1282 zeroBitPlanesTree = precinct.zeroBitPlanesTree;
1283 zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
1284
1285 while (true) {
1286 if (readBits(1)) {
1287 valueReady = !zeroBitPlanesTree.nextLevel();
1288
1289 if (valueReady) {
1290 break;
1291 }
1292 } else {
1293 zeroBitPlanesTree.incrementValue();
1294 }
1295 }
1296
1297 codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
1298 }
1299
1300 const codingpasses = readCodingpasses();
1301
1302 while (readBits(1)) {
1303 codeblock.Lblock++;
1304 }
1305
1306 const codingpassesLog2 = (0, _core_utils.log2)(codingpasses);
1307 const bits = (codingpasses < 1 << codingpassesLog2 ? codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
1308 const codedDataLength = readBits(bits);
1309 queue.push({
1310 codeblock,
1311 codingpasses,
1312 dataLength: codedDataLength
1313 });
1314 }
1315
1316 alignToByte();
1317
1318 if (ephMarkerUsed) {
1319 skipMarkerIfEqual(0x92);
1320 }
1321
1322 while (queue.length > 0) {
1323 const packetItem = queue.shift();
1324 codeblock = packetItem.codeblock;
1325
1326 if (codeblock.data === undefined) {
1327 codeblock.data = [];
1328 }
1329
1330 codeblock.data.push({
1331 data,
1332 start: offset + position,
1333 end: offset + position + packetItem.dataLength,
1334 codingpasses: packetItem.codingpasses
1335 });
1336 position += packetItem.dataLength;
1337 }
1338 }
1339
1340 return position;
1341}
1342
1343function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities) {
1344 const x0 = subband.tbx0;
1345 const y0 = subband.tby0;
1346 const width = subband.tbx1 - subband.tbx0;
1347 const codeblocks = subband.codeblocks;
1348 const right = subband.type.charAt(0) === "H" ? 1 : 0;
1349 const bottom = subband.type.charAt(1) === "H" ? levelWidth : 0;
1350
1351 for (let i = 0, ii = codeblocks.length; i < ii; ++i) {
1352 const codeblock = codeblocks[i];
1353 const blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
1354 const blockHeight = codeblock.tby1_ - codeblock.tby0_;
1355
1356 if (blockWidth === 0 || blockHeight === 0) {
1357 continue;
1358 }
1359
1360 if (codeblock.data === undefined) {
1361 continue;
1362 }
1363
1364 const bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType, codeblock.zeroBitPlanes, mb);
1365 let currentCodingpassType = 2;
1366 const data = codeblock.data;
1367 let totalLength = 0,
1368 codingpasses = 0;
1369 let j, jj, dataItem;
1370
1371 for (j = 0, jj = data.length; j < jj; j++) {
1372 dataItem = data[j];
1373 totalLength += dataItem.end - dataItem.start;
1374 codingpasses += dataItem.codingpasses;
1375 }
1376
1377 const encodedData = new Uint8Array(totalLength);
1378 let position = 0;
1379
1380 for (j = 0, jj = data.length; j < jj; j++) {
1381 dataItem = data[j];
1382 const chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
1383 encodedData.set(chunk, position);
1384 position += chunk.length;
1385 }
1386
1387 const decoder = new _arithmetic_decoder.ArithmeticDecoder(encodedData, 0, totalLength);
1388 bitModel.setDecoder(decoder);
1389
1390 for (j = 0; j < codingpasses; j++) {
1391 switch (currentCodingpassType) {
1392 case 0:
1393 bitModel.runSignificancePropagationPass();
1394 break;
1395
1396 case 1:
1397 bitModel.runMagnitudeRefinementPass();
1398 break;
1399
1400 case 2:
1401 bitModel.runCleanupPass();
1402
1403 if (segmentationSymbolUsed) {
1404 bitModel.checkSegmentationSymbol();
1405 }
1406
1407 break;
1408 }
1409
1410 if (resetContextProbabilities) {
1411 bitModel.reset();
1412 }
1413
1414 currentCodingpassType = (currentCodingpassType + 1) % 3;
1415 }
1416
1417 let offset = codeblock.tbx0_ - x0 + (codeblock.tby0_ - y0) * width;
1418 const sign = bitModel.coefficentsSign;
1419 const magnitude = bitModel.coefficentsMagnitude;
1420 const bitsDecoded = bitModel.bitsDecoded;
1421 const magnitudeCorrection = reversible ? 0 : 0.5;
1422 let k, n, nb;
1423 position = 0;
1424 const interleave = subband.type !== "LL";
1425
1426 for (j = 0; j < blockHeight; j++) {
1427 const row = offset / width | 0;
1428 const levelOffset = 2 * row * (levelWidth - width) + right + bottom;
1429
1430 for (k = 0; k < blockWidth; k++) {
1431 n = magnitude[position];
1432
1433 if (n !== 0) {
1434 n = (n + magnitudeCorrection) * delta;
1435
1436 if (sign[position] !== 0) {
1437 n = -n;
1438 }
1439
1440 nb = bitsDecoded[position];
1441 const pos = interleave ? levelOffset + (offset << 1) : offset;
1442
1443 if (reversible && nb >= mb) {
1444 coefficients[pos] = n;
1445 } else {
1446 coefficients[pos] = n * (1 << mb - nb);
1447 }
1448 }
1449
1450 offset++;
1451 position++;
1452 }
1453
1454 offset += width - blockWidth;
1455 }
1456 }
1457}
1458
1459function transformTile(context, tile, c) {
1460 const component = tile.components[c];
1461 const codingStyleParameters = component.codingStyleParameters;
1462 const quantizationParameters = component.quantizationParameters;
1463 const decompositionLevelsCount = codingStyleParameters.decompositionLevelsCount;
1464 const spqcds = quantizationParameters.SPqcds;
1465 const scalarExpounded = quantizationParameters.scalarExpounded;
1466 const guardBits = quantizationParameters.guardBits;
1467 const segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
1468 const resetContextProbabilities = codingStyleParameters.resetContextProbabilities;
1469 const precision = context.components[c].precision;
1470 const reversible = codingStyleParameters.reversibleTransformation;
1471 const transform = reversible ? new ReversibleTransform() : new IrreversibleTransform();
1472 const subbandCoefficients = [];
1473 let b = 0;
1474
1475 for (let i = 0; i <= decompositionLevelsCount; i++) {
1476 const resolution = component.resolutions[i];
1477 const width = resolution.trx1 - resolution.trx0;
1478 const height = resolution.try1 - resolution.try0;
1479 const coefficients = new Float32Array(width * height);
1480
1481 for (let j = 0, jj = resolution.subbands.length; j < jj; j++) {
1482 let mu, epsilon;
1483
1484 if (!scalarExpounded) {
1485 mu = spqcds[0].mu;
1486 epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
1487 } else {
1488 mu = spqcds[b].mu;
1489 epsilon = spqcds[b].epsilon;
1490 b++;
1491 }
1492
1493 const subband = resolution.subbands[j];
1494 const gainLog2 = SubbandsGainLog2[subband.type];
1495 const delta = reversible ? 1 : 2 ** (precision + gainLog2 - epsilon) * (1 + mu / 2048);
1496 const mb = guardBits + epsilon - 1;
1497 copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities);
1498 }
1499
1500 subbandCoefficients.push({
1501 width,
1502 height,
1503 items: coefficients
1504 });
1505 }
1506
1507 const result = transform.calculate(subbandCoefficients, component.tcx0, component.tcy0);
1508 return {
1509 left: component.tcx0,
1510 top: component.tcy0,
1511 width: result.width,
1512 height: result.height,
1513 items: result.items
1514 };
1515}
1516
1517function transformComponents(context) {
1518 const siz = context.SIZ;
1519 const components = context.components;
1520 const componentsCount = siz.Csiz;
1521 const resultImages = [];
1522
1523 for (let i = 0, ii = context.tiles.length; i < ii; i++) {
1524 const tile = context.tiles[i];
1525 const transformedTiles = [];
1526
1527 for (let c = 0; c < componentsCount; c++) {
1528 transformedTiles[c] = transformTile(context, tile, c);
1529 }
1530
1531 const tile0 = transformedTiles[0];
1532 const out = new Uint8ClampedArray(tile0.items.length * componentsCount);
1533 const result = {
1534 left: tile0.left,
1535 top: tile0.top,
1536 width: tile0.width,
1537 height: tile0.height,
1538 items: out
1539 };
1540 let shift, offset;
1541 let pos = 0,
1542 j,
1543 jj,
1544 y0,
1545 y1,
1546 y2;
1547
1548 if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
1549 const fourComponents = componentsCount === 4;
1550 const y0items = transformedTiles[0].items;
1551 const y1items = transformedTiles[1].items;
1552 const y2items = transformedTiles[2].items;
1553 const y3items = fourComponents ? transformedTiles[3].items : null;
1554 shift = components[0].precision - 8;
1555 offset = (128 << shift) + 0.5;
1556 const component0 = tile.components[0];
1557 const alpha01 = componentsCount - 3;
1558 jj = y0items.length;
1559
1560 if (!component0.codingStyleParameters.reversibleTransformation) {
1561 for (j = 0; j < jj; j++, pos += alpha01) {
1562 y0 = y0items[j] + offset;
1563 y1 = y1items[j];
1564 y2 = y2items[j];
1565 out[pos++] = y0 + 1.402 * y2 >> shift;
1566 out[pos++] = y0 - 0.34413 * y1 - 0.71414 * y2 >> shift;
1567 out[pos++] = y0 + 1.772 * y1 >> shift;
1568 }
1569 } else {
1570 for (j = 0; j < jj; j++, pos += alpha01) {
1571 y0 = y0items[j] + offset;
1572 y1 = y1items[j];
1573 y2 = y2items[j];
1574 const g = y0 - (y2 + y1 >> 2);
1575 out[pos++] = g + y2 >> shift;
1576 out[pos++] = g >> shift;
1577 out[pos++] = g + y1 >> shift;
1578 }
1579 }
1580
1581 if (fourComponents) {
1582 for (j = 0, pos = 3; j < jj; j++, pos += 4) {
1583 out[pos] = y3items[j] + offset >> shift;
1584 }
1585 }
1586 } else {
1587 for (let c = 0; c < componentsCount; c++) {
1588 const items = transformedTiles[c].items;
1589 shift = components[c].precision - 8;
1590 offset = (128 << shift) + 0.5;
1591
1592 for (pos = c, j = 0, jj = items.length; j < jj; j++) {
1593 out[pos] = items[j] + offset >> shift;
1594 pos += componentsCount;
1595 }
1596 }
1597 }
1598
1599 resultImages.push(result);
1600 }
1601
1602 return resultImages;
1603}
1604
1605function initializeTile(context, tileIndex) {
1606 const siz = context.SIZ;
1607 const componentsCount = siz.Csiz;
1608 const tile = context.tiles[tileIndex];
1609
1610 for (let c = 0; c < componentsCount; c++) {
1611 const component = tile.components[c];
1612 const qcdOrQcc = context.currentTile.QCC[c] !== undefined ? context.currentTile.QCC[c] : context.currentTile.QCD;
1613 component.quantizationParameters = qcdOrQcc;
1614 const codOrCoc = context.currentTile.COC[c] !== undefined ? context.currentTile.COC[c] : context.currentTile.COD;
1615 component.codingStyleParameters = codOrCoc;
1616 }
1617
1618 tile.codingStyleDefaultParameters = context.currentTile.COD;
1619}
1620
1621class TagTree {
1622 constructor(width, height) {
1623 const levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1;
1624 this.levels = [];
1625
1626 for (let i = 0; i < levelsLength; i++) {
1627 const level = {
1628 width,
1629 height,
1630 items: []
1631 };
1632 this.levels.push(level);
1633 width = Math.ceil(width / 2);
1634 height = Math.ceil(height / 2);
1635 }
1636 }
1637
1638 reset(i, j) {
1639 let currentLevel = 0,
1640 value = 0,
1641 level;
1642
1643 while (currentLevel < this.levels.length) {
1644 level = this.levels[currentLevel];
1645 const index = i + j * level.width;
1646
1647 if (level.items[index] !== undefined) {
1648 value = level.items[index];
1649 break;
1650 }
1651
1652 level.index = index;
1653 i >>= 1;
1654 j >>= 1;
1655 currentLevel++;
1656 }
1657
1658 currentLevel--;
1659 level = this.levels[currentLevel];
1660 level.items[level.index] = value;
1661 this.currentLevel = currentLevel;
1662 delete this.value;
1663 }
1664
1665 incrementValue() {
1666 const level = this.levels[this.currentLevel];
1667 level.items[level.index]++;
1668 }
1669
1670 nextLevel() {
1671 let currentLevel = this.currentLevel;
1672 let level = this.levels[currentLevel];
1673 const value = level.items[level.index];
1674 currentLevel--;
1675
1676 if (currentLevel < 0) {
1677 this.value = value;
1678 return false;
1679 }
1680
1681 this.currentLevel = currentLevel;
1682 level = this.levels[currentLevel];
1683 level.items[level.index] = value;
1684 return true;
1685 }
1686
1687}
1688
1689class InclusionTree {
1690 constructor(width, height, defaultValue) {
1691 const levelsLength = (0, _core_utils.log2)(Math.max(width, height)) + 1;
1692 this.levels = [];
1693
1694 for (let i = 0; i < levelsLength; i++) {
1695 const items = new Uint8Array(width * height);
1696
1697 for (let j = 0, jj = items.length; j < jj; j++) {
1698 items[j] = defaultValue;
1699 }
1700
1701 const level = {
1702 width,
1703 height,
1704 items
1705 };
1706 this.levels.push(level);
1707 width = Math.ceil(width / 2);
1708 height = Math.ceil(height / 2);
1709 }
1710 }
1711
1712 reset(i, j, stopValue) {
1713 let currentLevel = 0;
1714
1715 while (currentLevel < this.levels.length) {
1716 const level = this.levels[currentLevel];
1717 const index = i + j * level.width;
1718 level.index = index;
1719 const value = level.items[index];
1720
1721 if (value === 0xff) {
1722 break;
1723 }
1724
1725 if (value > stopValue) {
1726 this.currentLevel = currentLevel;
1727 this.propagateValues();
1728 return false;
1729 }
1730
1731 i >>= 1;
1732 j >>= 1;
1733 currentLevel++;
1734 }
1735
1736 this.currentLevel = currentLevel - 1;
1737 return true;
1738 }
1739
1740 incrementValue(stopValue) {
1741 const level = this.levels[this.currentLevel];
1742 level.items[level.index] = stopValue + 1;
1743 this.propagateValues();
1744 }
1745
1746 propagateValues() {
1747 let levelIndex = this.currentLevel;
1748 let level = this.levels[levelIndex];
1749 const currentValue = level.items[level.index];
1750
1751 while (--levelIndex >= 0) {
1752 level = this.levels[levelIndex];
1753 level.items[level.index] = currentValue;
1754 }
1755 }
1756
1757 nextLevel() {
1758 let currentLevel = this.currentLevel;
1759 let level = this.levels[currentLevel];
1760 const value = level.items[level.index];
1761 level.items[level.index] = 0xff;
1762 currentLevel--;
1763
1764 if (currentLevel < 0) {
1765 return false;
1766 }
1767
1768 this.currentLevel = currentLevel;
1769 level = this.levels[currentLevel];
1770 level.items[level.index] = value;
1771 return true;
1772 }
1773
1774}
1775
1776const BitModel = function BitModelClosure() {
1777 const UNIFORM_CONTEXT = 17;
1778 const RUNLENGTH_CONTEXT = 18;
1779 const LLAndLHContextsLabel = new Uint8Array([0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8]);
1780 const HLContextLabel = new Uint8Array([0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8]);
1781 const HHContextLabel = new Uint8Array([0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8]);
1782
1783 class BitModel {
1784 constructor(width, height, subband, zeroBitPlanes, mb) {
1785 this.width = width;
1786 this.height = height;
1787 let contextLabelTable;
1788
1789 if (subband === "HH") {
1790 contextLabelTable = HHContextLabel;
1791 } else if (subband === "HL") {
1792 contextLabelTable = HLContextLabel;
1793 } else {
1794 contextLabelTable = LLAndLHContextsLabel;
1795 }
1796
1797 this.contextLabelTable = contextLabelTable;
1798 const coefficientCount = width * height;
1799 this.neighborsSignificance = new Uint8Array(coefficientCount);
1800 this.coefficentsSign = new Uint8Array(coefficientCount);
1801 let coefficentsMagnitude;
1802
1803 if (mb > 14) {
1804 coefficentsMagnitude = new Uint32Array(coefficientCount);
1805 } else if (mb > 6) {
1806 coefficentsMagnitude = new Uint16Array(coefficientCount);
1807 } else {
1808 coefficentsMagnitude = new Uint8Array(coefficientCount);
1809 }
1810
1811 this.coefficentsMagnitude = coefficentsMagnitude;
1812 this.processingFlags = new Uint8Array(coefficientCount);
1813 const bitsDecoded = new Uint8Array(coefficientCount);
1814
1815 if (zeroBitPlanes !== 0) {
1816 for (let i = 0; i < coefficientCount; i++) {
1817 bitsDecoded[i] = zeroBitPlanes;
1818 }
1819 }
1820
1821 this.bitsDecoded = bitsDecoded;
1822 this.reset();
1823 }
1824
1825 setDecoder(decoder) {
1826 this.decoder = decoder;
1827 }
1828
1829 reset() {
1830 this.contexts = new Int8Array(19);
1831 this.contexts[0] = 4 << 1 | 0;
1832 this.contexts[UNIFORM_CONTEXT] = 46 << 1 | 0;
1833 this.contexts[RUNLENGTH_CONTEXT] = 3 << 1 | 0;
1834 }
1835
1836 setNeighborsSignificance(row, column, index) {
1837 const neighborsSignificance = this.neighborsSignificance;
1838 const width = this.width,
1839 height = this.height;
1840 const left = column > 0;
1841 const right = column + 1 < width;
1842 let i;
1843
1844 if (row > 0) {
1845 i = index - width;
1846
1847 if (left) {
1848 neighborsSignificance[i - 1] += 0x10;
1849 }
1850
1851 if (right) {
1852 neighborsSignificance[i + 1] += 0x10;
1853 }
1854
1855 neighborsSignificance[i] += 0x04;
1856 }
1857
1858 if (row + 1 < height) {
1859 i = index + width;
1860
1861 if (left) {
1862 neighborsSignificance[i - 1] += 0x10;
1863 }
1864
1865 if (right) {
1866 neighborsSignificance[i + 1] += 0x10;
1867 }
1868
1869 neighborsSignificance[i] += 0x04;
1870 }
1871
1872 if (left) {
1873 neighborsSignificance[index - 1] += 0x01;
1874 }
1875
1876 if (right) {
1877 neighborsSignificance[index + 1] += 0x01;
1878 }
1879
1880 neighborsSignificance[index] |= 0x80;
1881 }
1882
1883 runSignificancePropagationPass() {
1884 const decoder = this.decoder;
1885 const width = this.width,
1886 height = this.height;
1887 const coefficentsMagnitude = this.coefficentsMagnitude;
1888 const coefficentsSign = this.coefficentsSign;
1889 const neighborsSignificance = this.neighborsSignificance;
1890 const processingFlags = this.processingFlags;
1891 const contexts = this.contexts;
1892 const labels = this.contextLabelTable;
1893 const bitsDecoded = this.bitsDecoded;
1894 const processedInverseMask = ~1;
1895 const processedMask = 1;
1896 const firstMagnitudeBitMask = 2;
1897
1898 for (let i0 = 0; i0 < height; i0 += 4) {
1899 for (let j = 0; j < width; j++) {
1900 let index = i0 * width + j;
1901
1902 for (let i1 = 0; i1 < 4; i1++, index += width) {
1903 const i = i0 + i1;
1904
1905 if (i >= height) {
1906 break;
1907 }
1908
1909 processingFlags[index] &= processedInverseMask;
1910
1911 if (coefficentsMagnitude[index] || !neighborsSignificance[index]) {
1912 continue;
1913 }
1914
1915 const contextLabel = labels[neighborsSignificance[index]];
1916 const decision = decoder.readBit(contexts, contextLabel);
1917
1918 if (decision) {
1919 const sign = this.decodeSignBit(i, j, index);
1920 coefficentsSign[index] = sign;
1921 coefficentsMagnitude[index] = 1;
1922 this.setNeighborsSignificance(i, j, index);
1923 processingFlags[index] |= firstMagnitudeBitMask;
1924 }
1925
1926 bitsDecoded[index]++;
1927 processingFlags[index] |= processedMask;
1928 }
1929 }
1930 }
1931 }
1932
1933 decodeSignBit(row, column, index) {
1934 const width = this.width,
1935 height = this.height;
1936 const coefficentsMagnitude = this.coefficentsMagnitude;
1937 const coefficentsSign = this.coefficentsSign;
1938 let contribution, sign0, sign1, significance1;
1939 let contextLabel, decoded;
1940 significance1 = column > 0 && coefficentsMagnitude[index - 1] !== 0;
1941
1942 if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {
1943 sign1 = coefficentsSign[index + 1];
1944
1945 if (significance1) {
1946 sign0 = coefficentsSign[index - 1];
1947 contribution = 1 - sign1 - sign0;
1948 } else {
1949 contribution = 1 - sign1 - sign1;
1950 }
1951 } else if (significance1) {
1952 sign0 = coefficentsSign[index - 1];
1953 contribution = 1 - sign0 - sign0;
1954 } else {
1955 contribution = 0;
1956 }
1957
1958 const horizontalContribution = 3 * contribution;
1959 significance1 = row > 0 && coefficentsMagnitude[index - width] !== 0;
1960
1961 if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {
1962 sign1 = coefficentsSign[index + width];
1963
1964 if (significance1) {
1965 sign0 = coefficentsSign[index - width];
1966 contribution = 1 - sign1 - sign0 + horizontalContribution;
1967 } else {
1968 contribution = 1 - sign1 - sign1 + horizontalContribution;
1969 }
1970 } else if (significance1) {
1971 sign0 = coefficentsSign[index - width];
1972 contribution = 1 - sign0 - sign0 + horizontalContribution;
1973 } else {
1974 contribution = horizontalContribution;
1975 }
1976
1977 if (contribution >= 0) {
1978 contextLabel = 9 + contribution;
1979 decoded = this.decoder.readBit(this.contexts, contextLabel);
1980 } else {
1981 contextLabel = 9 - contribution;
1982 decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;
1983 }
1984
1985 return decoded;
1986 }
1987
1988 runMagnitudeRefinementPass() {
1989 const decoder = this.decoder;
1990 const width = this.width,
1991 height = this.height;
1992 const coefficentsMagnitude = this.coefficentsMagnitude;
1993 const neighborsSignificance = this.neighborsSignificance;
1994 const contexts = this.contexts;
1995 const bitsDecoded = this.bitsDecoded;
1996 const processingFlags = this.processingFlags;
1997 const processedMask = 1;
1998 const firstMagnitudeBitMask = 2;
1999 const length = width * height;
2000 const width4 = width * 4;
2001
2002 for (let index0 = 0, indexNext; index0 < length; index0 = indexNext) {
2003 indexNext = Math.min(length, index0 + width4);
2004
2005 for (let j = 0; j < width; j++) {
2006 for (let index = index0 + j; index < indexNext; index += width) {
2007 if (!coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) {
2008 continue;
2009 }
2010
2011 let contextLabel = 16;
2012
2013 if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {
2014 processingFlags[index] ^= firstMagnitudeBitMask;
2015 const significance = neighborsSignificance[index] & 127;
2016 contextLabel = significance === 0 ? 15 : 14;
2017 }
2018
2019 const bit = decoder.readBit(contexts, contextLabel);
2020 coefficentsMagnitude[index] = coefficentsMagnitude[index] << 1 | bit;
2021 bitsDecoded[index]++;
2022 processingFlags[index] |= processedMask;
2023 }
2024 }
2025 }
2026 }
2027
2028 runCleanupPass() {
2029 const decoder = this.decoder;
2030 const width = this.width,
2031 height = this.height;
2032 const neighborsSignificance = this.neighborsSignificance;
2033 const coefficentsMagnitude = this.coefficentsMagnitude;
2034 const coefficentsSign = this.coefficentsSign;
2035 const contexts = this.contexts;
2036 const labels = this.contextLabelTable;
2037 const bitsDecoded = this.bitsDecoded;
2038 const processingFlags = this.processingFlags;
2039 const processedMask = 1;
2040 const firstMagnitudeBitMask = 2;
2041 const oneRowDown = width;
2042 const twoRowsDown = width * 2;
2043 const threeRowsDown = width * 3;
2044 let iNext;
2045
2046 for (let i0 = 0; i0 < height; i0 = iNext) {
2047 iNext = Math.min(i0 + 4, height);
2048 const indexBase = i0 * width;
2049 const checkAllEmpty = i0 + 3 < height;
2050
2051 for (let j = 0; j < width; j++) {
2052 const index0 = indexBase + j;
2053 const allEmpty = checkAllEmpty && processingFlags[index0] === 0 && processingFlags[index0 + oneRowDown] === 0 && processingFlags[index0 + twoRowsDown] === 0 && processingFlags[index0 + threeRowsDown] === 0 && neighborsSignificance[index0] === 0 && neighborsSignificance[index0 + oneRowDown] === 0 && neighborsSignificance[index0 + twoRowsDown] === 0 && neighborsSignificance[index0 + threeRowsDown] === 0;
2054 let i1 = 0,
2055 index = index0;
2056 let i = i0,
2057 sign;
2058
2059 if (allEmpty) {
2060 const hasSignificantCoefficent = decoder.readBit(contexts, RUNLENGTH_CONTEXT);
2061
2062 if (!hasSignificantCoefficent) {
2063 bitsDecoded[index0]++;
2064 bitsDecoded[index0 + oneRowDown]++;
2065 bitsDecoded[index0 + twoRowsDown]++;
2066 bitsDecoded[index0 + threeRowsDown]++;
2067 continue;
2068 }
2069
2070 i1 = decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT);
2071
2072 if (i1 !== 0) {
2073 i = i0 + i1;
2074 index += i1 * width;
2075 }
2076
2077 sign = this.decodeSignBit(i, j, index);
2078 coefficentsSign[index] = sign;
2079 coefficentsMagnitude[index] = 1;
2080 this.setNeighborsSignificance(i, j, index);
2081 processingFlags[index] |= firstMagnitudeBitMask;
2082 index = index0;
2083
2084 for (let i2 = i0; i2 <= i; i2++, index += width) {
2085 bitsDecoded[index]++;
2086 }
2087
2088 i1++;
2089 }
2090
2091 for (i = i0 + i1; i < iNext; i++, index += width) {
2092 if (coefficentsMagnitude[index] || (processingFlags[index] & processedMask) !== 0) {
2093 continue;
2094 }
2095
2096 const contextLabel = labels[neighborsSignificance[index]];
2097 const decision = decoder.readBit(contexts, contextLabel);
2098
2099 if (decision === 1) {
2100 sign = this.decodeSignBit(i, j, index);
2101 coefficentsSign[index] = sign;
2102 coefficentsMagnitude[index] = 1;
2103 this.setNeighborsSignificance(i, j, index);
2104 processingFlags[index] |= firstMagnitudeBitMask;
2105 }
2106
2107 bitsDecoded[index]++;
2108 }
2109 }
2110 }
2111 }
2112
2113 checkSegmentationSymbol() {
2114 const decoder = this.decoder;
2115 const contexts = this.contexts;
2116 const symbol = decoder.readBit(contexts, UNIFORM_CONTEXT) << 3 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 2 | decoder.readBit(contexts, UNIFORM_CONTEXT) << 1 | decoder.readBit(contexts, UNIFORM_CONTEXT);
2117
2118 if (symbol !== 0xa) {
2119 throw new JpxError("Invalid segmentation symbol");
2120 }
2121 }
2122
2123 }
2124
2125 return BitModel;
2126}();
2127
2128class Transform {
2129 constructor() {
2130 if (this.constructor === Transform) {
2131 (0, _util.unreachable)("Cannot initialize Transform.");
2132 }
2133 }
2134
2135 calculate(subbands, u0, v0) {
2136 let ll = subbands[0];
2137
2138 for (let i = 1, ii = subbands.length; i < ii; i++) {
2139 ll = this.iterate(ll, subbands[i], u0, v0);
2140 }
2141
2142 return ll;
2143 }
2144
2145 extend(buffer, offset, size) {
2146 let i1 = offset - 1,
2147 j1 = offset + 1;
2148 let i2 = offset + size - 2,
2149 j2 = offset + size;
2150 buffer[i1--] = buffer[j1++];
2151 buffer[j2++] = buffer[i2--];
2152 buffer[i1--] = buffer[j1++];
2153 buffer[j2++] = buffer[i2--];
2154 buffer[i1--] = buffer[j1++];
2155 buffer[j2++] = buffer[i2--];
2156 buffer[i1] = buffer[j1];
2157 buffer[j2] = buffer[i2];
2158 }
2159
2160 filter(x, offset, length) {
2161 (0, _util.unreachable)("Abstract method `filter` called");
2162 }
2163
2164 iterate(ll, hl_lh_hh, u0, v0) {
2165 const llWidth = ll.width,
2166 llHeight = ll.height;
2167 let llItems = ll.items;
2168 const width = hl_lh_hh.width;
2169 const height = hl_lh_hh.height;
2170 const items = hl_lh_hh.items;
2171 let i, j, k, l, u, v;
2172
2173 for (k = 0, i = 0; i < llHeight; i++) {
2174 l = i * 2 * width;
2175
2176 for (j = 0; j < llWidth; j++, k++, l += 2) {
2177 items[l] = llItems[k];
2178 }
2179 }
2180
2181 llItems = ll.items = null;
2182 const bufferPadding = 4;
2183 const rowBuffer = new Float32Array(width + 2 * bufferPadding);
2184
2185 if (width === 1) {
2186 if ((u0 & 1) !== 0) {
2187 for (v = 0, k = 0; v < height; v++, k += width) {
2188 items[k] *= 0.5;
2189 }
2190 }
2191 } else {
2192 for (v = 0, k = 0; v < height; v++, k += width) {
2193 rowBuffer.set(items.subarray(k, k + width), bufferPadding);
2194 this.extend(rowBuffer, bufferPadding, width);
2195 this.filter(rowBuffer, bufferPadding, width);
2196 items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k);
2197 }
2198 }
2199
2200 let numBuffers = 16;
2201 const colBuffers = [];
2202
2203 for (i = 0; i < numBuffers; i++) {
2204 colBuffers.push(new Float32Array(height + 2 * bufferPadding));
2205 }
2206
2207 let b,
2208 currentBuffer = 0;
2209 ll = bufferPadding + height;
2210
2211 if (height === 1) {
2212 if ((v0 & 1) !== 0) {
2213 for (u = 0; u < width; u++) {
2214 items[u] *= 0.5;
2215 }
2216 }
2217 } else {
2218 for (u = 0; u < width; u++) {
2219 if (currentBuffer === 0) {
2220 numBuffers = Math.min(width - u, numBuffers);
2221
2222 for (k = u, l = bufferPadding; l < ll; k += width, l++) {
2223 for (b = 0; b < numBuffers; b++) {
2224 colBuffers[b][l] = items[k + b];
2225 }
2226 }
2227
2228 currentBuffer = numBuffers;
2229 }
2230
2231 currentBuffer--;
2232 const buffer = colBuffers[currentBuffer];
2233 this.extend(buffer, bufferPadding, height);
2234 this.filter(buffer, bufferPadding, height);
2235
2236 if (currentBuffer === 0) {
2237 k = u - numBuffers + 1;
2238
2239 for (l = bufferPadding; l < ll; k += width, l++) {
2240 for (b = 0; b < numBuffers; b++) {
2241 items[k + b] = colBuffers[b][l];
2242 }
2243 }
2244 }
2245 }
2246 }
2247
2248 return {
2249 width,
2250 height,
2251 items
2252 };
2253 }
2254
2255}
2256
2257class IrreversibleTransform extends Transform {
2258 filter(x, offset, length) {
2259 const len = length >> 1;
2260 offset |= 0;
2261 let j, n, current, next;
2262 const alpha = -1.586134342059924;
2263 const beta = -0.052980118572961;
2264 const gamma = 0.882911075530934;
2265 const delta = 0.443506852043971;
2266 const K = 1.230174104914001;
2267 const K_ = 1 / K;
2268 j = offset - 3;
2269
2270 for (n = len + 4; n--; j += 2) {
2271 x[j] *= K_;
2272 }
2273
2274 j = offset - 2;
2275 current = delta * x[j - 1];
2276
2277 for (n = len + 3; n--; j += 2) {
2278 next = delta * x[j + 1];
2279 x[j] = K * x[j] - current - next;
2280
2281 if (n--) {
2282 j += 2;
2283 current = delta * x[j + 1];
2284 x[j] = K * x[j] - current - next;
2285 } else {
2286 break;
2287 }
2288 }
2289
2290 j = offset - 1;
2291 current = gamma * x[j - 1];
2292
2293 for (n = len + 2; n--; j += 2) {
2294 next = gamma * x[j + 1];
2295 x[j] -= current + next;
2296
2297 if (n--) {
2298 j += 2;
2299 current = gamma * x[j + 1];
2300 x[j] -= current + next;
2301 } else {
2302 break;
2303 }
2304 }
2305
2306 j = offset;
2307 current = beta * x[j - 1];
2308
2309 for (n = len + 1; n--; j += 2) {
2310 next = beta * x[j + 1];
2311 x[j] -= current + next;
2312
2313 if (n--) {
2314 j += 2;
2315 current = beta * x[j + 1];
2316 x[j] -= current + next;
2317 } else {
2318 break;
2319 }
2320 }
2321
2322 if (len !== 0) {
2323 j = offset + 1;
2324 current = alpha * x[j - 1];
2325
2326 for (n = len; n--; j += 2) {
2327 next = alpha * x[j + 1];
2328 x[j] -= current + next;
2329
2330 if (n--) {
2331 j += 2;
2332 current = alpha * x[j + 1];
2333 x[j] -= current + next;
2334 } else {
2335 break;
2336 }
2337 }
2338 }
2339 }
2340
2341}
2342
2343class ReversibleTransform extends Transform {
2344 filter(x, offset, length) {
2345 const len = length >> 1;
2346 offset |= 0;
2347 let j, n;
2348
2349 for (j = offset, n = len + 1; n--; j += 2) {
2350 x[j] -= x[j - 1] + x[j + 1] + 2 >> 2;
2351 }
2352
2353 for (j = offset + 1, n = len; n--; j += 2) {
2354 x[j] += x[j - 1] + x[j + 1] >> 1;
2355 }
2356 }
2357
2358}
\No newline at end of file