modern-pdf-lib 0.19.9 → 0.22.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +16 -5
  2. package/dist/{batchOptimize-xo6BXbGZ.cjs → batchOptimize-Ba_pWw71.cjs} +2 -2
  3. package/dist/{batchOptimize-7U_kD3_j.mjs → batchOptimize-CxyY4fZe.mjs} +2 -2
  4. package/dist/browser.cjs +9 -9
  5. package/dist/browser.mjs +9 -9
  6. package/dist/cli/index.cjs +2 -2
  7. package/dist/cli/index.mjs +2 -2
  8. package/dist/{compressionAnalysis-eXYyDsrh.cjs → compressionAnalysis-B84FPXaQ.cjs} +4 -4
  9. package/dist/compressionAnalysis-BBv4BkQP.d.mts.map +1 -1
  10. package/dist/{compressionAnalysis-Bw2alOxt.mjs → compressionAnalysis-ChkscEa1.mjs} +4 -4
  11. package/dist/compressionAnalysis-CtJ2X9l2.d.cts.map +1 -1
  12. package/dist/create.cjs +3 -3
  13. package/dist/create.mjs +3 -3
  14. package/dist/{deduplicateImages-BX3Zg8Qp.mjs → deduplicateImages-CmTeo6Tx.mjs} +2 -2
  15. package/dist/{deduplicateImages-B5lmzL9j.cjs → deduplicateImages-cKsnD6Ep.cjs} +2 -2
  16. package/dist/{imageExtract-B6OvUEp-.mjs → imageExtract-Dnk_Ssv7.mjs} +2 -2
  17. package/dist/{imageExtract-PxdBvpHj.cjs → imageExtract-zEb1gnkb.cjs} +2 -2
  18. package/dist/index.cjs +9 -9
  19. package/dist/index.mjs +9 -9
  20. package/dist/{layout-Inbqegsk.cjs → layout-CuAVk_Or.cjs} +2 -2
  21. package/dist/{layout-BZ8tTeAk.mjs → layout-DgX_0jfK.mjs} +2 -2
  22. package/dist/parse.cjs +4 -4
  23. package/dist/parse.mjs +4 -4
  24. package/dist/{pdfDocument-DOg240g9.mjs → pdfDocument-BFxHD_2u.mjs} +101 -31
  25. package/dist/pdfDocument-BSiQdNZq.d.cts.map +1 -1
  26. package/dist/pdfDocument-i6U5fQ91.d.mts.map +1 -1
  27. package/dist/{pdfDocument-Duf9LelM.cjs → pdfDocument-pmRXryVI.cjs} +101 -31
  28. package/dist/{pdfPage-BacMkrLe.mjs → pdfPage-Cd8e7flb.mjs} +4 -4
  29. package/dist/{pdfPage-CirlQRzJ.cjs → pdfPage-Cd8jOJp6.cjs} +4 -4
  30. package/dist/{src-BLWEEbd7.cjs → src-6L07EQsi.cjs} +19 -19
  31. package/dist/{src-x0g7wiRq.mjs → src-Dm4aaZ8q.mjs} +19 -19
  32. package/dist/{streamDecode-CWN-nfPJ.mjs → streamDecode-Bj568Nc9.mjs} +1648 -39
  33. package/dist/{streamDecode-Bs0_MT_Q.cjs → streamDecode-CvgErkFu.cjs} +1648 -39
  34. package/package.json +1 -1
@@ -1518,7 +1518,7 @@ var JBIG2Decoder = class {
1518
1518
  */
1519
1519
  parseSegmentHeader(data, offset) {
1520
1520
  if (offset + 6 > data.length) return null;
1521
- const segmentNumber = readUint32BE(data, offset);
1521
+ const segmentNumber = readUint32BE$1(data, offset);
1522
1522
  offset += 4;
1523
1523
  const flags = data[offset];
1524
1524
  offset++;
@@ -1529,7 +1529,7 @@ var JBIG2Decoder = class {
1529
1529
  let referredToCount = referredToByte >>> 5 & 7;
1530
1530
  if (referredToCount === 7) {
1531
1531
  if (offset + 3 > data.length) return null;
1532
- referredToCount = readUint32BE(data, offset - 1) & 536870911;
1532
+ referredToCount = readUint32BE$1(data, offset - 1) & 536870911;
1533
1533
  offset += 3;
1534
1534
  const retainedBytes = Math.ceil((referredToCount + 1) / 8);
1535
1535
  offset += retainedBytes;
@@ -1542,17 +1542,17 @@ var JBIG2Decoder = class {
1542
1542
  referredToSegments.push(data[offset]);
1543
1543
  offset++;
1544
1544
  } else if (refSize === 2) {
1545
- referredToSegments.push(readUint16BE(data, offset));
1545
+ referredToSegments.push(readUint16BE$1(data, offset));
1546
1546
  offset += 2;
1547
1547
  } else {
1548
- referredToSegments.push(readUint32BE(data, offset));
1548
+ referredToSegments.push(readUint32BE$1(data, offset));
1549
1549
  offset += 4;
1550
1550
  }
1551
1551
  }
1552
1552
  let pageAssociation;
1553
1553
  if (pageAssociationSizeLarge) {
1554
1554
  if (offset + 4 > data.length) return null;
1555
- pageAssociation = readUint32BE(data, offset);
1555
+ pageAssociation = readUint32BE$1(data, offset);
1556
1556
  offset += 4;
1557
1557
  } else {
1558
1558
  if (offset >= data.length) return null;
@@ -1560,7 +1560,7 @@ var JBIG2Decoder = class {
1560
1560
  offset++;
1561
1561
  }
1562
1562
  if (offset + 4 > data.length) return null;
1563
- const dataLength = readUint32BE(data, offset);
1563
+ const dataLength = readUint32BE$1(data, offset);
1564
1564
  offset += 4;
1565
1565
  return {
1566
1566
  header: {
@@ -1638,8 +1638,8 @@ var JBIG2Decoder = class {
1638
1638
  */
1639
1639
  processPageInformation(data) {
1640
1640
  if (data.length < 19) throw new Error("JBIG2Decode: Page Information segment too short");
1641
- this.pageWidth = readUint32BE(data, 0);
1642
- this.pageHeight = readUint32BE(data, 4);
1641
+ this.pageWidth = readUint32BE$1(data, 0);
1642
+ this.pageHeight = readUint32BE$1(data, 4);
1643
1643
  const flags = data[16];
1644
1644
  this.pageDefaultPixel = flags >>> 2 & 1;
1645
1645
  this.pageCombinationOperator = flags >>> 3 & 3;
@@ -1659,10 +1659,10 @@ var JBIG2Decoder = class {
1659
1659
  */
1660
1660
  processImmediateGenericRegion(header, data) {
1661
1661
  if (data.length < 18) throw new Error("JBIG2Decode: Generic Region segment too short");
1662
- const regionWidth = readUint32BE(data, 0);
1663
- const regionHeight = readUint32BE(data, 4);
1664
- const regionX = readUint32BE(data, 8);
1665
- const regionY = readUint32BE(data, 12);
1662
+ const regionWidth = readUint32BE$1(data, 0);
1663
+ const regionHeight = readUint32BE$1(data, 4);
1664
+ const regionX = readUint32BE$1(data, 8);
1665
+ const regionY = readUint32BE$1(data, 12);
1666
1666
  const combinationOperator = data[16] & 7;
1667
1667
  const genericFlags = data[17];
1668
1668
  const mmr = (genericFlags & 1) !== 0;
@@ -1737,7 +1737,7 @@ var JBIG2Decoder = class {
1737
1737
  processSymbolDictionary(header, data) {
1738
1738
  if (data.length < 10) throw new Error("JBIG2Decode: Symbol Dictionary segment too short");
1739
1739
  let offset = 0;
1740
- const sdFlags = readUint16BE(data, offset);
1740
+ const sdFlags = readUint16BE$1(data, offset);
1741
1741
  offset += 2;
1742
1742
  const sdHuff = sdFlags & 1;
1743
1743
  const sdRefAgg = sdFlags >>> 1 & 1;
@@ -1748,9 +1748,9 @@ var JBIG2Decoder = class {
1748
1748
  else offset += 2;
1749
1749
  if (sdRefAgg) if (sdrTemplate === 0) offset += 4;
1750
1750
  else offset += 2;
1751
- const numExported = readUint32BE(data, offset);
1751
+ const numExported = readUint32BE$1(data, offset);
1752
1752
  offset += 4;
1753
- const numNew = readUint32BE(data, offset);
1753
+ const numNew = readUint32BE$1(data, offset);
1754
1754
  offset += 4;
1755
1755
  const inputSymbols = [];
1756
1756
  for (const refSegNum of header.referredToSegments) {
@@ -1822,14 +1822,14 @@ var JBIG2Decoder = class {
1822
1822
  processTextRegion(header, data, immediate) {
1823
1823
  if (data.length < 19) throw new Error("JBIG2Decode: Text Region segment too short");
1824
1824
  let offset = 0;
1825
- const regionWidth = readUint32BE(data, offset);
1826
- const regionHeight = readUint32BE(data, offset + 4);
1827
- const regionX = readUint32BE(data, offset + 8);
1828
- const regionY = readUint32BE(data, offset + 12);
1825
+ const regionWidth = readUint32BE$1(data, offset);
1826
+ const regionHeight = readUint32BE$1(data, offset + 4);
1827
+ const regionX = readUint32BE$1(data, offset + 8);
1828
+ const regionY = readUint32BE$1(data, offset + 12);
1829
1829
  const combinationOperator = data[offset + 16] & 7;
1830
1830
  offset += 17;
1831
1831
  if (offset + 2 > data.length) throw new Error("JBIG2Decode: Text Region segment too short for flags");
1832
- const trFlags = readUint16BE(data, offset);
1832
+ const trFlags = readUint16BE$1(data, offset);
1833
1833
  offset += 2;
1834
1834
  const sbHuff = trFlags & 1;
1835
1835
  const sbRefine = trFlags >>> 1 & 1;
@@ -1844,7 +1844,7 @@ var JBIG2Decoder = class {
1844
1844
  if (sbRefine && !sbHuff) if (sbrTemplate === 0) offset += 4;
1845
1845
  else offset += 2;
1846
1846
  if (offset + 4 > data.length) throw new Error("JBIG2Decode: Text Region segment too short for instance count");
1847
- const numInstances = readUint32BE(data, offset);
1847
+ const numInstances = readUint32BE$1(data, offset);
1848
1848
  offset += 4;
1849
1849
  const symbols = [];
1850
1850
  for (const refSegNum of header.referredToSegments) {
@@ -1982,7 +1982,7 @@ var JBIG2Decoder = class {
1982
1982
  offset++;
1983
1983
  const patternHeight = data[offset];
1984
1984
  offset++;
1985
- const grayMax = readUint32BE(data, offset);
1985
+ const grayMax = readUint32BE$1(data, offset);
1986
1986
  offset += 4;
1987
1987
  const numPatterns = grayMax + 1;
1988
1988
  if (!pdMMR) if (pdTemplate === 0) offset += 8;
@@ -2030,10 +2030,10 @@ var JBIG2Decoder = class {
2030
2030
  processHalftoneRegion(header, data, immediate) {
2031
2031
  if (data.length < 22) throw new Error("JBIG2Decode: Halftone Region segment too short");
2032
2032
  let offset = 0;
2033
- const regionWidth = readUint32BE(data, offset);
2034
- const regionHeight = readUint32BE(data, offset + 4);
2035
- const regionX = readUint32BE(data, offset + 8);
2036
- const regionY = readUint32BE(data, offset + 12);
2033
+ const regionWidth = readUint32BE$1(data, offset);
2034
+ const regionHeight = readUint32BE$1(data, offset + 4);
2035
+ const regionX = readUint32BE$1(data, offset + 8);
2036
+ const regionY = readUint32BE$1(data, offset + 12);
2037
2037
  const combinationOperator = data[offset + 16] & 7;
2038
2038
  offset += 17;
2039
2039
  const htFlags = data[offset];
@@ -2043,17 +2043,17 @@ var JBIG2Decoder = class {
2043
2043
  htFlags >>> 3 & 1;
2044
2044
  const htCombOp = htFlags >>> 4 & 7;
2045
2045
  const htDefPixel = htFlags >>> 7 & 1;
2046
- const gridW = readUint32BE(data, offset);
2046
+ const gridW = readUint32BE$1(data, offset);
2047
2047
  offset += 4;
2048
- const gridH = readUint32BE(data, offset);
2048
+ const gridH = readUint32BE$1(data, offset);
2049
2049
  offset += 4;
2050
2050
  const gridX = readInt32BE(data, offset);
2051
2051
  offset += 4;
2052
2052
  const gridY = readInt32BE(data, offset);
2053
2053
  offset += 4;
2054
- const gridStepX = readUint16BE(data, offset);
2054
+ const gridStepX = readUint16BE$1(data, offset);
2055
2055
  offset += 2;
2056
- const gridStepY = readUint16BE(data, offset);
2056
+ const gridStepY = readUint16BE$1(data, offset);
2057
2057
  offset += 2;
2058
2058
  let patDict;
2059
2059
  for (const refSegNum of header.referredToSegments) {
@@ -2128,10 +2128,10 @@ var JBIG2Decoder = class {
2128
2128
  processGenericRefinementRegion(header, data, immediate) {
2129
2129
  if (data.length < 18) throw new Error("JBIG2Decode: Generic Refinement Region segment too short");
2130
2130
  let offset = 0;
2131
- const regionWidth = readUint32BE(data, offset);
2132
- const regionHeight = readUint32BE(data, offset + 4);
2133
- const regionX = readUint32BE(data, offset + 8);
2134
- const regionY = readUint32BE(data, offset + 12);
2131
+ const regionWidth = readUint32BE$1(data, offset);
2132
+ const regionHeight = readUint32BE$1(data, offset + 4);
2133
+ const regionX = readUint32BE$1(data, offset + 8);
2134
+ const regionY = readUint32BE$1(data, offset + 12);
2135
2135
  const combinationOperator = data[offset + 16] & 7;
2136
2136
  offset += 17;
2137
2137
  const refFlags = data[offset];
@@ -4016,13 +4016,13 @@ function decodeRefinementBitmap(data, width, height, templateId, refBitmap, refW
4016
4016
  }
4017
4017
  return output;
4018
4018
  }
4019
- function readUint32BE(data, offset) {
4019
+ function readUint32BE$1(data, offset) {
4020
4020
  return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
4021
4021
  }
4022
4022
  function readInt32BE(data, offset) {
4023
4023
  return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
4024
4024
  }
4025
- function readUint16BE(data, offset) {
4025
+ function readUint16BE$1(data, offset) {
4026
4026
  return (data[offset] << 8 | data[offset + 1]) >>> 0;
4027
4027
  }
4028
4028
  /**
@@ -4034,6 +4034,1604 @@ function signExtend(value, bits) {
4034
4034
  return (value ^ sign) - sign;
4035
4035
  }
4036
4036
 
4037
+ //#endregion
4038
+ //#region src/parser/jpeg2000Decode.ts
4039
+ /**
4040
+ * Decode a JPEG2000 (JP2 or raw J2K codestream) image.
4041
+ *
4042
+ * @param data - JP2 file bytes or raw J2K codestream bytes.
4043
+ * @param params - Optional decode parameters.
4044
+ * @returns Decoded image with raw pixel data.
4045
+ */
4046
+ function decodeJpeg2000(data, params) {
4047
+ const reduce = params?.reduceResolution ?? 0;
4048
+ const maxComp = params?.maxComponents;
4049
+ let codestream;
4050
+ let jp2Info = null;
4051
+ if (isJP2FileFormat(data)) {
4052
+ jp2Info = parseJP2Boxes(data);
4053
+ codestream = jp2Info.codestream;
4054
+ } else codestream = data;
4055
+ const cs = parseCodestream(codestream);
4056
+ const numComponents = maxComp ? Math.min(cs.siz.numComponents, maxComp) : cs.siz.numComponents;
4057
+ const effectiveReduce = Math.min(reduce, cs.cod.numResolutions - 1);
4058
+ const divisor = 1 << effectiveReduce;
4059
+ const outWidth = Math.ceil(cs.siz.width / divisor);
4060
+ const outHeight = Math.ceil(cs.siz.height / divisor);
4061
+ const tileComponents = decodeTiles(cs, effectiveReduce, numComponents);
4062
+ applyInverseColorTransform(tileComponents, cs.cod, numComponents);
4063
+ if (jp2Info?.colorSpace === "sycc" && numComponents >= 3) applySyccToSrgb(tileComponents, outWidth, outHeight);
4064
+ const bpc = cs.siz.componentBitDepths[0];
4065
+ const bytesPerSample = bpc <= 8 ? 1 : 2;
4066
+ const output = new Uint8Array(outWidth * outHeight * numComponents * bytesPerSample);
4067
+ interleaveComponents(tileComponents, output, outWidth, outHeight, numComponents, bpc, cs.siz.componentSigned);
4068
+ let colorSpace;
4069
+ if (jp2Info?.colorSpace) colorSpace = jp2Info.colorSpace;
4070
+ else if (numComponents === 1) colorSpace = "greyscale";
4071
+ else if (numComponents >= 3) colorSpace = "srgb";
4072
+ return {
4073
+ width: outWidth,
4074
+ height: outHeight,
4075
+ components: numComponents,
4076
+ bitsPerComponent: bpc,
4077
+ data: output,
4078
+ ...colorSpace !== void 0 && { colorSpace },
4079
+ ...jp2Info?.iccProfile !== void 0 && { iccProfile: jp2Info.iccProfile }
4080
+ };
4081
+ }
4082
+ /** JP2 file format signature: first 12 bytes. */
4083
+ const JP2_SIGNATURE = new Uint8Array([
4084
+ 0,
4085
+ 0,
4086
+ 0,
4087
+ 12,
4088
+ 106,
4089
+ 80,
4090
+ 32,
4091
+ 32,
4092
+ 13,
4093
+ 10,
4094
+ 135,
4095
+ 10
4096
+ ]);
4097
+ const BOX_JP2H = 1785737832;
4098
+ const BOX_COLR = 1668246642;
4099
+ const BOX_CDEF = 1667523942;
4100
+ const BOX_JP2C = 1785737827;
4101
+ /**
4102
+ * Check if data starts with the JP2 file format signature.
4103
+ */
4104
+ function isJP2FileFormat(data) {
4105
+ if (data.length < 12) return false;
4106
+ for (let i = 0; i < 12; i++) if (data[i] !== JP2_SIGNATURE[i]) return false;
4107
+ return true;
4108
+ }
4109
+ /**
4110
+ * Read a 32-bit big-endian unsigned integer from data at offset.
4111
+ */
4112
+ function readUint32BE(data, offset) {
4113
+ return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
4114
+ }
4115
+ /**
4116
+ * Read a 16-bit big-endian unsigned integer from data at offset.
4117
+ */
4118
+ function readUint16BE(data, offset) {
4119
+ return data[offset] << 8 | data[offset + 1];
4120
+ }
4121
+ /**
4122
+ * Parse JP2 file format boxes to extract the codestream and metadata.
4123
+ */
4124
+ function parseJP2Boxes(data) {
4125
+ const result = { codestream: new Uint8Array(0) };
4126
+ let offset = 0;
4127
+ while (offset + 8 <= data.length) {
4128
+ let boxLength = readUint32BE(data, offset);
4129
+ const boxType = readUint32BE(data, offset + 4);
4130
+ let headerSize = 8;
4131
+ if (boxLength === 1) {
4132
+ if (offset + 16 > data.length) break;
4133
+ boxLength = readUint32BE(data, offset + 12);
4134
+ headerSize = 16;
4135
+ } else if (boxLength === 0) boxLength = data.length - offset;
4136
+ if (boxLength < headerSize) break;
4137
+ const contentStart = offset + headerSize;
4138
+ const contentEnd = offset + boxLength;
4139
+ switch (boxType) {
4140
+ case BOX_JP2H:
4141
+ parseJP2HeaderBox(data, contentStart, contentEnd, result);
4142
+ break;
4143
+ case BOX_JP2C:
4144
+ result.codestream = data.subarray(contentStart, contentEnd);
4145
+ break;
4146
+ }
4147
+ offset += boxLength;
4148
+ }
4149
+ if (result.codestream.length === 0) throw new Error("JPEG2000: no contiguous codestream box (jp2c) found");
4150
+ return result;
4151
+ }
4152
+ /**
4153
+ * Parse sub-boxes within the JP2 header (jp2h) superbox.
4154
+ */
4155
+ function parseJP2HeaderBox(data, start, end, result) {
4156
+ let offset = start;
4157
+ while (offset + 8 <= end) {
4158
+ let boxLength = readUint32BE(data, offset);
4159
+ const boxType = readUint32BE(data, offset + 4);
4160
+ let headerSize = 8;
4161
+ if (boxLength === 1 && offset + 16 <= end) {
4162
+ boxLength = readUint32BE(data, offset + 12);
4163
+ headerSize = 16;
4164
+ } else if (boxLength === 0) boxLength = end - offset;
4165
+ if (boxLength < headerSize) break;
4166
+ const contentStart = offset + headerSize;
4167
+ const contentEnd = Math.min(offset + boxLength, end);
4168
+ switch (boxType) {
4169
+ case BOX_COLR:
4170
+ parseColorSpecBox(data, contentStart, contentEnd, result);
4171
+ break;
4172
+ case BOX_CDEF:
4173
+ parseChannelDefBox(data, contentStart, contentEnd, result);
4174
+ break;
4175
+ }
4176
+ offset += boxLength;
4177
+ }
4178
+ }
4179
+ /**
4180
+ * Parse the color specification box (colr).
4181
+ *
4182
+ * Method 1: Enumerated color space.
4183
+ * Method 2: Restricted ICC profile.
4184
+ * Method 3: Full ICC profile (treated same as method 2).
4185
+ */
4186
+ function parseColorSpecBox(data, start, end, result) {
4187
+ if (start + 3 > end) return;
4188
+ const method = data[start];
4189
+ if (method === 1) {
4190
+ if (start + 7 > end) return;
4191
+ switch (readUint32BE(data, start + 3)) {
4192
+ case 16:
4193
+ result.colorSpace = "srgb";
4194
+ break;
4195
+ case 17:
4196
+ result.colorSpace = "greyscale";
4197
+ break;
4198
+ case 18:
4199
+ result.colorSpace = "sycc";
4200
+ break;
4201
+ default:
4202
+ result.colorSpace = "srgb";
4203
+ break;
4204
+ }
4205
+ } else if (method === 2 || method === 3) {
4206
+ result.colorSpace = "icc";
4207
+ if (start + 3 < end) result.iccProfile = data.slice(start + 3, end);
4208
+ }
4209
+ }
4210
+ /**
4211
+ * Parse the channel definition box (cdef) to identify alpha channels.
4212
+ *
4213
+ * Each entry is 6 bytes: channel index (2), channel type (2), channel assoc (2).
4214
+ * Channel type 1 = opacity (alpha), type 2 = pre-multiplied opacity.
4215
+ */
4216
+ function parseChannelDefBox(data, start, end, result) {
4217
+ if (start + 2 > end) return;
4218
+ const numEntries = readUint16BE(data, start);
4219
+ let offset = start + 2;
4220
+ for (let i = 0; i < numEntries && offset + 6 <= end; i++) {
4221
+ const channelIndex = readUint16BE(data, offset);
4222
+ const channelType = readUint16BE(data, offset + 2);
4223
+ if (channelType === 1 || channelType === 2) result.alphaChannelIndex = channelIndex;
4224
+ offset += 6;
4225
+ }
4226
+ }
4227
+ /** Marker constants (ITU-T T.800 Table A.1). */
4228
+ const MRK_SOC = 65359;
4229
+ const MRK_SIZ = 65361;
4230
+ const MRK_COD = 65362;
4231
+ const MRK_QCD = 65372;
4232
+ const MRK_SOT = 65424;
4233
+ const MRK_SOD = 65427;
4234
+ const MRK_EOC = 65497;
4235
+ /**
4236
+ * Parse a JPEG2000 codestream, extracting main header markers and tile-part
4237
+ * locations.
4238
+ */
4239
+ function parseCodestream(data) {
4240
+ let offset = 0;
4241
+ if (data.length < 2) throw new Error("JPEG2000: codestream too short");
4242
+ const soc = readUint16BE(data, offset);
4243
+ if (soc !== MRK_SOC) throw new Error(`JPEG2000: expected SOC marker (0xFF4F), got 0x${soc.toString(16).padStart(4, "0")}`);
4244
+ offset += 2;
4245
+ let siz = null;
4246
+ let cod = null;
4247
+ let qcd = null;
4248
+ const tileParts = [];
4249
+ while (offset + 2 <= data.length) {
4250
+ const marker = readUint16BE(data, offset);
4251
+ offset += 2;
4252
+ if (marker === MRK_SOT) {
4253
+ offset -= 2;
4254
+ break;
4255
+ }
4256
+ if (marker === MRK_EOC) break;
4257
+ if (marker === MRK_SOC || marker === MRK_SOD) continue;
4258
+ if (offset + 2 > data.length) break;
4259
+ const markerLength = readUint16BE(data, offset);
4260
+ const markerDataStart = offset + 2;
4261
+ const markerDataEnd = offset + markerLength;
4262
+ if (markerDataEnd > data.length) break;
4263
+ switch (marker) {
4264
+ case MRK_SIZ:
4265
+ siz = parseSIZ(data, markerDataStart, markerDataEnd);
4266
+ break;
4267
+ case MRK_COD:
4268
+ cod = parseCOD(data, markerDataStart, markerDataEnd);
4269
+ break;
4270
+ case MRK_QCD:
4271
+ qcd = parseQCD(data, markerDataStart, markerDataEnd);
4272
+ break;
4273
+ }
4274
+ offset = markerDataEnd;
4275
+ }
4276
+ if (!siz) throw new Error("JPEG2000: SIZ marker not found");
4277
+ if (!cod) throw new Error("JPEG2000: COD marker not found");
4278
+ if (!qcd) qcd = buildDefaultQCD(cod);
4279
+ while (offset + 2 <= data.length) {
4280
+ const marker = readUint16BE(data, offset);
4281
+ if (marker === MRK_EOC) break;
4282
+ if (marker !== MRK_SOT) {
4283
+ offset += 2;
4284
+ continue;
4285
+ }
4286
+ offset += 2;
4287
+ if (offset + 2 > data.length) break;
4288
+ const sotLength = readUint16BE(data, offset);
4289
+ const sotDataStart = offset + 2;
4290
+ if (sotDataStart + 8 > data.length) break;
4291
+ const tileIndex = readUint16BE(data, sotDataStart);
4292
+ const tilePartLength = readUint32BE(data, sotDataStart + 2);
4293
+ const tilePartIndex = data[sotDataStart + 6];
4294
+ let sodOffset = offset + sotLength;
4295
+ while (sodOffset + 2 <= data.length) {
4296
+ if (readUint16BE(data, sodOffset) === MRK_SOD) {
4297
+ sodOffset += 2;
4298
+ break;
4299
+ }
4300
+ sodOffset += 2;
4301
+ if (sodOffset + 2 <= data.length) {
4302
+ const mLen = readUint16BE(data, sodOffset);
4303
+ sodOffset += mLen;
4304
+ }
4305
+ }
4306
+ const tpEnd = tilePartLength > 0 ? offset - 2 + tilePartLength : findNextSOTorEOC(data, sodOffset);
4307
+ tileParts.push({
4308
+ tileIndex,
4309
+ tilePartIndex,
4310
+ dataStart: sodOffset,
4311
+ dataEnd: tpEnd
4312
+ });
4313
+ offset = tpEnd;
4314
+ }
4315
+ return {
4316
+ siz,
4317
+ cod,
4318
+ qcd,
4319
+ tileParts,
4320
+ rawData: data
4321
+ };
4322
+ }
4323
+ /**
4324
+ * Find the next SOT or EOC marker position after the given offset.
4325
+ */
4326
+ function findNextSOTorEOC(data, from) {
4327
+ for (let i = from; i + 1 < data.length; i++) if (data[i] === 255) {
4328
+ const next = data[i + 1];
4329
+ if (next === 144 || next === 217) return i;
4330
+ }
4331
+ return data.length;
4332
+ }
4333
+ /**
4334
+ * Parse the SIZ (image and tile size) marker segment.
4335
+ */
4336
+ function parseSIZ(data, start, end) {
4337
+ let p = start;
4338
+ const profile = readUint16BE(data, p);
4339
+ p += 2;
4340
+ const width = readUint32BE(data, p);
4341
+ p += 4;
4342
+ const height = readUint32BE(data, p);
4343
+ p += 4;
4344
+ const imageOffsetX = readUint32BE(data, p);
4345
+ p += 4;
4346
+ const imageOffsetY = readUint32BE(data, p);
4347
+ p += 4;
4348
+ const tileWidth = readUint32BE(data, p);
4349
+ p += 4;
4350
+ const tileHeight = readUint32BE(data, p);
4351
+ p += 4;
4352
+ const tileOffsetX = readUint32BE(data, p);
4353
+ p += 4;
4354
+ const tileOffsetY = readUint32BE(data, p);
4355
+ p += 4;
4356
+ const numComponents = readUint16BE(data, p);
4357
+ p += 2;
4358
+ const componentBitDepths = [];
4359
+ const componentSigned = [];
4360
+ const componentSubX = [];
4361
+ const componentSubY = [];
4362
+ for (let i = 0; i < numComponents && p + 3 <= end; i++) {
4363
+ const ssiz = data[p];
4364
+ p++;
4365
+ const signed = (ssiz & 128) !== 0;
4366
+ const bitDepth = (ssiz & 127) + 1;
4367
+ componentBitDepths.push(bitDepth);
4368
+ componentSigned.push(signed);
4369
+ componentSubX.push(data[p]);
4370
+ p++;
4371
+ componentSubY.push(data[p]);
4372
+ p++;
4373
+ }
4374
+ return {
4375
+ profile,
4376
+ width,
4377
+ height,
4378
+ imageOffsetX,
4379
+ imageOffsetY,
4380
+ tileWidth,
4381
+ tileHeight,
4382
+ tileOffsetX,
4383
+ tileOffsetY,
4384
+ numComponents,
4385
+ componentBitDepths,
4386
+ componentSigned,
4387
+ componentSubX,
4388
+ componentSubY
4389
+ };
4390
+ }
4391
+ /**
4392
+ * Parse the COD (coding style default) marker segment.
4393
+ */
4394
+ function parseCOD(data, start, end) {
4395
+ let p = start;
4396
+ const codingStyle = data[p];
4397
+ p++;
4398
+ const progressionOrder = data[p];
4399
+ p++;
4400
+ const numLayers = readUint16BE(data, p);
4401
+ p += 2;
4402
+ const multiComponentTransform = data[p];
4403
+ p++;
4404
+ const numDecompLevels = data[p];
4405
+ p++;
4406
+ const codeBlockWidthExp = (data[p] & 15) + 2;
4407
+ p++;
4408
+ const codeBlockHeightExp = (data[p] & 15) + 2;
4409
+ p++;
4410
+ const codeBlockStyle = data[p];
4411
+ p++;
4412
+ const waveletTransform = data[p];
4413
+ p++;
4414
+ const reversible = waveletTransform === 1;
4415
+ const precinctSizes = [];
4416
+ if (codingStyle & 1) for (let r = 0; r <= numDecompLevels && p < end; r++) {
4417
+ const val = data[p];
4418
+ p++;
4419
+ precinctSizes.push({
4420
+ ppx: val & 15,
4421
+ ppy: val >> 4 & 15
4422
+ });
4423
+ }
4424
+ else for (let r = 0; r <= numDecompLevels; r++) precinctSizes.push({
4425
+ ppx: 15,
4426
+ ppy: 15
4427
+ });
4428
+ return {
4429
+ codingStyle,
4430
+ progressionOrder,
4431
+ numLayers,
4432
+ multiComponentTransform,
4433
+ numDecompLevels,
4434
+ numResolutions: numDecompLevels + 1,
4435
+ codeBlockWidthExp,
4436
+ codeBlockHeightExp,
4437
+ codeBlockWidth: 1 << codeBlockWidthExp,
4438
+ codeBlockHeight: 1 << codeBlockHeightExp,
4439
+ codeBlockStyle,
4440
+ reversible,
4441
+ precinctSizes
4442
+ };
4443
+ }
4444
+ /**
4445
+ * Parse the QCD (quantization default) marker segment.
4446
+ */
4447
+ function parseQCD(data, start, end) {
4448
+ let p = start;
4449
+ const sqcd = data[p];
4450
+ p++;
4451
+ const quantStyle = sqcd & 31;
4452
+ const guardBits = sqcd >> 5 & 7;
4453
+ const stepSizes = [];
4454
+ if (quantStyle === 0) while (p < end) {
4455
+ const val = data[p];
4456
+ p++;
4457
+ stepSizes.push({
4458
+ epsilon: val >> 3 & 31,
4459
+ mu: 0
4460
+ });
4461
+ }
4462
+ else if (quantStyle === 1) {
4463
+ if (p + 2 <= end) {
4464
+ const val = readUint16BE(data, p);
4465
+ p += 2;
4466
+ stepSizes.push({
4467
+ epsilon: val >> 11 & 31,
4468
+ mu: val & 2047
4469
+ });
4470
+ }
4471
+ } else if (quantStyle === 2) while (p + 2 <= end) {
4472
+ const val = readUint16BE(data, p);
4473
+ p += 2;
4474
+ stepSizes.push({
4475
+ epsilon: val >> 11 & 31,
4476
+ mu: val & 2047
4477
+ });
4478
+ }
4479
+ return {
4480
+ quantStyle,
4481
+ guardBits,
4482
+ stepSizes
4483
+ };
4484
+ }
4485
+ /**
4486
+ * Build a default QCD when the marker is missing (reversible, no quantization).
4487
+ */
4488
+ function buildDefaultQCD(cod) {
4489
+ const numSubbands = 1 + 3 * cod.numDecompLevels;
4490
+ const stepSizes = [];
4491
+ for (let i = 0; i < numSubbands; i++) stepSizes.push({
4492
+ epsilon: 8,
4493
+ mu: 0
4494
+ });
4495
+ return {
4496
+ quantStyle: 0,
4497
+ guardBits: 1,
4498
+ stepSizes
4499
+ };
4500
+ }
4501
+ /**
4502
+ * Decode all tiles and return per-component sample arrays.
4503
+ * Returns an array of Float64Array (one per component) with samples
4504
+ * in raster order.
4505
+ */
4506
+ function decodeTiles(cs, reduceResolution, numComponents) {
4507
+ const { siz, cod, qcd } = cs;
4508
+ const divisor = 1 << reduceResolution;
4509
+ const outWidth = Math.ceil(siz.width / divisor);
4510
+ const outHeight = Math.ceil(siz.height / divisor);
4511
+ const components = [];
4512
+ for (let c = 0; c < numComponents; c++) components.push(new Float64Array(outWidth * outHeight));
4513
+ if (cs.tileParts.length === 0) return components;
4514
+ const tileGroups = /* @__PURE__ */ new Map();
4515
+ for (const tp of cs.tileParts) {
4516
+ const existing = tileGroups.get(tp.tileIndex);
4517
+ if (existing) existing.push(tp);
4518
+ else tileGroups.set(tp.tileIndex, [tp]);
4519
+ }
4520
+ const numTilesX = Math.max(1, Math.ceil((siz.width - siz.tileOffsetX) / siz.tileWidth));
4521
+ for (const [tileIdx, parts] of tileGroups) {
4522
+ let totalLen = 0;
4523
+ for (const p of parts) totalLen += p.dataEnd - p.dataStart;
4524
+ const tileData = new Uint8Array(totalLen);
4525
+ let writePos = 0;
4526
+ for (const p of parts) {
4527
+ tileData.set(cs.rawData.subarray(p.dataStart, p.dataEnd), writePos);
4528
+ writePos += p.dataEnd - p.dataStart;
4529
+ }
4530
+ const tileCol = tileIdx % numTilesX;
4531
+ const tileRow = Math.floor(tileIdx / numTilesX);
4532
+ const tx0 = siz.tileOffsetX + tileCol * siz.tileWidth;
4533
+ const ty0 = siz.tileOffsetY + tileRow * siz.tileHeight;
4534
+ const tx1 = Math.min(tx0 + siz.tileWidth, siz.width);
4535
+ const ty1 = Math.min(ty0 + siz.tileHeight, siz.height);
4536
+ const tileW = tx1 - tx0;
4537
+ const tileH = ty1 - ty0;
4538
+ if (tileW <= 0 || tileH <= 0) continue;
4539
+ for (let c = 0; c < numComponents; c++) {
4540
+ const bpc = siz.componentBitDepths[c];
4541
+ const tileComponentSamples = decodeTileComponent(tileData, tileW, tileH, c, numComponents, cod, qcd, bpc, reduceResolution);
4542
+ const reducedTileW = Math.ceil(tileW / divisor);
4543
+ const reducedTileH = Math.ceil(tileH / divisor);
4544
+ const reducedTx0 = Math.ceil(tx0 / divisor);
4545
+ const reducedTy0 = Math.ceil(ty0 / divisor);
4546
+ for (let y = 0; y < reducedTileH; y++) for (let x = 0; x < reducedTileW; x++) {
4547
+ const outX = reducedTx0 + x;
4548
+ const outY = reducedTy0 + y;
4549
+ if (outX < outWidth && outY < outHeight) components[c][outY * outWidth + outX] = tileComponentSamples[y * reducedTileW + x];
4550
+ }
4551
+ }
4552
+ }
4553
+ return components;
4554
+ }
4555
+ /**
4556
+ * Decode a single tile-component from raw tile data.
4557
+ *
4558
+ * This is a simplified decoder for single-tile PDFs. It performs:
4559
+ * 1. Tier-2: parse packets to extract code-block coded data
4560
+ * 2. Tier-1: MQ arithmetic decode of code-block bit-planes
4561
+ * 3. Dequantization
4562
+ * 4. Inverse DWT
4563
+ *
4564
+ * For multi-layer/multi-tile streams with complex progression orders,
4565
+ * the raw tile data is decoded using a simplified approach that
4566
+ * processes all code-block data sequentially.
4567
+ */
4568
+ function decodeTileComponent(tileData, tileWidth, tileHeight, componentIndex, numComponents, cod, qcd, bpc, reduceResolution) {
4569
+ const numResLevels = cod.numResolutions - reduceResolution;
4570
+ if (numResLevels <= 0) return new Float64Array(1);
4571
+ const divisor = 1 << reduceResolution;
4572
+ const reducedW = Math.ceil(tileWidth / divisor);
4573
+ const reducedH = Math.ceil(tileHeight / divisor);
4574
+ const subbands = buildSubbands(reducedW, reducedH, numResLevels - 1, cod);
4575
+ decodePackets(new BitstreamReader(tileData), subbands, cod, numComponents, componentIndex);
4576
+ dequantize(subbands, qcd, bpc, cod.reversible);
4577
+ return inverseDWT(subbands, reducedW, reducedH, numResLevels - 1, cod.reversible);
4578
+ }
4579
+ /**
4580
+ * Build the subband decomposition for a tile-component.
4581
+ */
4582
+ function buildSubbands(width, height, numDecompLevels, cod) {
4583
+ const subbands = [];
4584
+ let w = width;
4585
+ let h = height;
4586
+ for (let level = numDecompLevels; level >= 1; level--) {
4587
+ Math.ceil(w / 2);
4588
+ Math.floor(h / 2) + h % 2;
4589
+ Math.floor(w / 2) + w % 2;
4590
+ Math.ceil(h / 2);
4591
+ Math.ceil(w / 2);
4592
+ Math.ceil(h / 2);
4593
+ const llW = Math.floor(w / 2) + w % 2;
4594
+ const llH = Math.floor(h / 2) + h % 2;
4595
+ subbands.push(createSubband("HL", level, w - llW, llH, cod));
4596
+ subbands.push(createSubband("LH", level, llW, h - llH, cod));
4597
+ subbands.push(createSubband("HH", level, w - llW, h - llH, cod));
4598
+ w = llW;
4599
+ h = llH;
4600
+ }
4601
+ subbands.unshift(createSubband("LL", 0, w, h, cod));
4602
+ return subbands;
4603
+ }
4604
+ /**
4605
+ * Create a subband with its code-block grid.
4606
+ */
4607
+ function createSubband(type, resLevel, width, height, cod) {
4608
+ width = Math.max(0, width);
4609
+ height = Math.max(0, height);
4610
+ const cbw = cod.codeBlockWidth;
4611
+ const cbh = cod.codeBlockHeight;
4612
+ const numCBx = width > 0 ? Math.ceil(width / cbw) : 0;
4613
+ const numCBy = height > 0 ? Math.ceil(height / cbh) : 0;
4614
+ const codeBlocks = [];
4615
+ for (let cby = 0; cby < numCBy; cby++) for (let cbx = 0; cbx < numCBx; cbx++) {
4616
+ const x0 = cbx * cbw;
4617
+ const y0 = cby * cbh;
4618
+ const blockW = Math.min(cbw, width - x0);
4619
+ const blockH = Math.min(cbh, height - y0);
4620
+ codeBlocks.push({
4621
+ cbx,
4622
+ cby,
4623
+ width: blockW,
4624
+ height: blockH,
4625
+ x0,
4626
+ y0,
4627
+ data: new Float64Array(blockW * blockH),
4628
+ zeroBitPlanes: 0,
4629
+ numPasses: 0,
4630
+ codedData: [],
4631
+ codedLengths: []
4632
+ });
4633
+ }
4634
+ return {
4635
+ type,
4636
+ resLevel,
4637
+ width,
4638
+ height,
4639
+ coefficients: new Float64Array(width * height),
4640
+ codeBlocks
4641
+ };
4642
+ }
4643
+ var BitstreamReader = class {
4644
+ data;
4645
+ pos;
4646
+ bitPos;
4647
+ currentByte;
4648
+ constructor(data) {
4649
+ this.data = data;
4650
+ this.pos = 0;
4651
+ this.bitPos = 0;
4652
+ this.currentByte = 0;
4653
+ }
4654
+ get position() {
4655
+ return this.pos;
4656
+ }
4657
+ get length() {
4658
+ return this.data.length;
4659
+ }
4660
+ get hasMore() {
4661
+ return this.pos < this.data.length;
4662
+ }
4663
+ readByte() {
4664
+ if (this.pos >= this.data.length) return 0;
4665
+ return this.data[this.pos++];
4666
+ }
4667
+ readBit() {
4668
+ if (this.bitPos === 0) this.currentByte = this.readByte();
4669
+ const bit = this.currentByte >> 7 - this.bitPos & 1;
4670
+ this.bitPos = this.bitPos + 1 & 7;
4671
+ return bit;
4672
+ }
4673
+ readBits(n) {
4674
+ let val = 0;
4675
+ for (let i = 0; i < n; i++) val = val << 1 | this.readBit();
4676
+ return val;
4677
+ }
4678
+ readUint16() {
4679
+ const b0 = this.readByte();
4680
+ const b1 = this.readByte();
4681
+ return b0 << 8 | b1;
4682
+ }
4683
+ readUint32() {
4684
+ const b0 = this.readByte();
4685
+ const b1 = this.readByte();
4686
+ const b2 = this.readByte();
4687
+ const b3 = this.readByte();
4688
+ return (b0 << 24 | b1 << 16 | b2 << 8 | b3) >>> 0;
4689
+ }
4690
+ skip(n) {
4691
+ this.pos += n;
4692
+ this.bitPos = 0;
4693
+ }
4694
+ alignToByte() {
4695
+ this.bitPos = 0;
4696
+ }
4697
+ getSubarray(start, end) {
4698
+ return this.data.subarray(start, end);
4699
+ }
4700
+ };
4701
+ /**
4702
+ * Simplified Tier-2 packet parsing.
4703
+ *
4704
+ * For PDFs, JPEG2000 streams typically use a single tile with LRCP or RLCP
4705
+ * progression. We parse the packet headers to extract code-block inclusion,
4706
+ * zero bit-planes, and coded data lengths, then collect the coded data
4707
+ * for Tier-1 decoding.
4708
+ */
4709
+ function decodePackets(reader, subbands, cod, numComponents, componentIndex) {
4710
+ if (subbands.reduce((sum, sb) => sum + sb.codeBlocks.length, 0) === 0 || !reader.hasMore) return;
4711
+ for (const subband of subbands) {
4712
+ if (subband.width === 0 || subband.height === 0) continue;
4713
+ for (const cb of subband.codeBlocks) {
4714
+ if (cb.width === 0 || cb.height === 0) continue;
4715
+ const remainingData = reader.length - reader.position;
4716
+ if (remainingData <= 0) break;
4717
+ const blockPixels = cb.width * cb.height;
4718
+ const totalPixels = subbands.reduce((sum, sb) => sum + sb.width * sb.height, 0);
4719
+ const proportion = totalPixels > 0 ? blockPixels / totalPixels : 0;
4720
+ const allocatedBytes = Math.max(1, Math.min(remainingData, Math.ceil(remainingData * proportion)));
4721
+ const startPos = reader.position;
4722
+ const endPos = Math.min(startPos + allocatedBytes, reader.length);
4723
+ const codedSegment = reader.getSubarray(startPos, endPos);
4724
+ cb.codedData.push(codedSegment);
4725
+ cb.codedLengths.push(codedSegment.length);
4726
+ cb.numPasses = 3;
4727
+ reader.skip(allocatedBytes);
4728
+ }
4729
+ }
4730
+ for (const subband of subbands) for (const cb of subband.codeBlocks) if (cb.codedData.length > 0 && cb.width > 0 && cb.height > 0) {
4731
+ tier1Decode(cb, subband.type);
4732
+ for (let y = 0; y < cb.height; y++) for (let x = 0; x < cb.width; x++) {
4733
+ const sbX = cb.x0 + x;
4734
+ const sbY = cb.y0 + y;
4735
+ if (sbX < subband.width && sbY < subband.height) subband.coefficients[sbY * subband.width + sbX] = cb.data[y * cb.width + x];
4736
+ }
4737
+ }
4738
+ }
4739
+ /**
4740
+ * MQ (binary arithmetic) coder — the core entropy coder in JPEG2000.
4741
+ *
4742
+ * Implements the standard probability estimation table from ITU-T T.800
4743
+ * Annex C. The MQ coder maintains a current interval (A) and code
4744
+ * register (C), and uses a context-dependent probability model.
4745
+ */
4746
+ var MQDecoder = class MQDecoder {
4747
+ /** Data buffer. */
4748
+ data;
4749
+ /** Current byte position. */
4750
+ pos;
4751
+ /** Code register (C). */
4752
+ c;
4753
+ /** Interval register (A). */
4754
+ a;
4755
+ /** Count of bits remaining in current byte. */
4756
+ ct;
4757
+ /** Marker detected flag. */
4758
+ markerDetected;
4759
+ /**
4760
+ * Standard MQ probability estimation table.
4761
+ * Each entry: [Qe, nextMPS, nextLPS, switchFlag]
4762
+ *
4763
+ * Qe = probability estimate (scaled by 2^16)
4764
+ * nextMPS = next state index after MPS renormalization
4765
+ * nextLPS = next state index after LPS renormalization
4766
+ * switchFlag = whether to switch MPS/LPS sense
4767
+ */
4768
+ static QE_TABLE = [
4769
+ [
4770
+ 22017,
4771
+ 1,
4772
+ 1,
4773
+ 1
4774
+ ],
4775
+ [
4776
+ 13313,
4777
+ 2,
4778
+ 6,
4779
+ 0
4780
+ ],
4781
+ [
4782
+ 6145,
4783
+ 3,
4784
+ 9,
4785
+ 0
4786
+ ],
4787
+ [
4788
+ 2753,
4789
+ 4,
4790
+ 12,
4791
+ 0
4792
+ ],
4793
+ [
4794
+ 1313,
4795
+ 5,
4796
+ 29,
4797
+ 0
4798
+ ],
4799
+ [
4800
+ 545,
4801
+ 38,
4802
+ 33,
4803
+ 0
4804
+ ],
4805
+ [
4806
+ 22017,
4807
+ 7,
4808
+ 6,
4809
+ 1
4810
+ ],
4811
+ [
4812
+ 21505,
4813
+ 8,
4814
+ 14,
4815
+ 0
4816
+ ],
4817
+ [
4818
+ 18433,
4819
+ 9,
4820
+ 14,
4821
+ 0
4822
+ ],
4823
+ [
4824
+ 14337,
4825
+ 10,
4826
+ 14,
4827
+ 0
4828
+ ],
4829
+ [
4830
+ 12289,
4831
+ 11,
4832
+ 17,
4833
+ 0
4834
+ ],
4835
+ [
4836
+ 9217,
4837
+ 12,
4838
+ 18,
4839
+ 0
4840
+ ],
4841
+ [
4842
+ 7169,
4843
+ 13,
4844
+ 20,
4845
+ 0
4846
+ ],
4847
+ [
4848
+ 5633,
4849
+ 29,
4850
+ 21,
4851
+ 0
4852
+ ],
4853
+ [
4854
+ 22017,
4855
+ 15,
4856
+ 14,
4857
+ 1
4858
+ ],
4859
+ [
4860
+ 21505,
4861
+ 16,
4862
+ 14,
4863
+ 0
4864
+ ],
4865
+ [
4866
+ 20737,
4867
+ 17,
4868
+ 15,
4869
+ 0
4870
+ ],
4871
+ [
4872
+ 18433,
4873
+ 18,
4874
+ 16,
4875
+ 0
4876
+ ],
4877
+ [
4878
+ 14337,
4879
+ 19,
4880
+ 17,
4881
+ 0
4882
+ ],
4883
+ [
4884
+ 13313,
4885
+ 20,
4886
+ 18,
4887
+ 0
4888
+ ],
4889
+ [
4890
+ 12289,
4891
+ 21,
4892
+ 19,
4893
+ 0
4894
+ ],
4895
+ [
4896
+ 10241,
4897
+ 22,
4898
+ 19,
4899
+ 0
4900
+ ],
4901
+ [
4902
+ 9217,
4903
+ 23,
4904
+ 20,
4905
+ 0
4906
+ ],
4907
+ [
4908
+ 8705,
4909
+ 24,
4910
+ 21,
4911
+ 0
4912
+ ],
4913
+ [
4914
+ 7169,
4915
+ 25,
4916
+ 22,
4917
+ 0
4918
+ ],
4919
+ [
4920
+ 6145,
4921
+ 26,
4922
+ 23,
4923
+ 0
4924
+ ],
4925
+ [
4926
+ 5633,
4927
+ 27,
4928
+ 24,
4929
+ 0
4930
+ ],
4931
+ [
4932
+ 5121,
4933
+ 28,
4934
+ 25,
4935
+ 0
4936
+ ],
4937
+ [
4938
+ 4609,
4939
+ 29,
4940
+ 26,
4941
+ 0
4942
+ ],
4943
+ [
4944
+ 4353,
4945
+ 30,
4946
+ 27,
4947
+ 0
4948
+ ],
4949
+ [
4950
+ 2753,
4951
+ 31,
4952
+ 28,
4953
+ 0
4954
+ ],
4955
+ [
4956
+ 2497,
4957
+ 32,
4958
+ 29,
4959
+ 0
4960
+ ],
4961
+ [
4962
+ 2209,
4963
+ 33,
4964
+ 30,
4965
+ 0
4966
+ ],
4967
+ [
4968
+ 1313,
4969
+ 34,
4970
+ 31,
4971
+ 0
4972
+ ],
4973
+ [
4974
+ 1089,
4975
+ 35,
4976
+ 32,
4977
+ 0
4978
+ ],
4979
+ [
4980
+ 673,
4981
+ 36,
4982
+ 33,
4983
+ 0
4984
+ ],
4985
+ [
4986
+ 545,
4987
+ 37,
4988
+ 34,
4989
+ 0
4990
+ ],
4991
+ [
4992
+ 321,
4993
+ 38,
4994
+ 35,
4995
+ 0
4996
+ ],
4997
+ [
4998
+ 273,
4999
+ 39,
5000
+ 36,
5001
+ 0
5002
+ ],
5003
+ [
5004
+ 133,
5005
+ 40,
5006
+ 37,
5007
+ 0
5008
+ ],
5009
+ [
5010
+ 73,
5011
+ 41,
5012
+ 38,
5013
+ 0
5014
+ ],
5015
+ [
5016
+ 37,
5017
+ 42,
5018
+ 39,
5019
+ 0
5020
+ ],
5021
+ [
5022
+ 21,
5023
+ 43,
5024
+ 40,
5025
+ 0
5026
+ ],
5027
+ [
5028
+ 9,
5029
+ 44,
5030
+ 41,
5031
+ 0
5032
+ ],
5033
+ [
5034
+ 5,
5035
+ 45,
5036
+ 42,
5037
+ 0
5038
+ ],
5039
+ [
5040
+ 1,
5041
+ 45,
5042
+ 43,
5043
+ 0
5044
+ ],
5045
+ [
5046
+ 22017,
5047
+ 46,
5048
+ 46,
5049
+ 0
5050
+ ]
5051
+ ];
5052
+ constructor(data) {
5053
+ this.data = data;
5054
+ this.pos = 0;
5055
+ this.c = 0;
5056
+ this.a = 0;
5057
+ this.ct = 0;
5058
+ this.markerDetected = false;
5059
+ this.init();
5060
+ }
5061
+ /**
5062
+ * Initialize the MQ decoder — fill the code register.
5063
+ */
5064
+ init() {
5065
+ this.a = 32768;
5066
+ this.c = this.readNewByte() << 16;
5067
+ this.byteIn();
5068
+ this.c <<= 7;
5069
+ this.ct -= 7;
5070
+ this.a = 32768;
5071
+ }
5072
+ /**
5073
+ * Read a new byte, handling bit-stuffing after 0xFF.
5074
+ */
5075
+ readNewByte() {
5076
+ if (this.pos >= this.data.length) return 255;
5077
+ return this.data[this.pos++];
5078
+ }
5079
+ /**
5080
+ * Byte-in procedure: feed a new byte into the code register.
5081
+ */
5082
+ byteIn() {
5083
+ if (this.markerDetected) {
5084
+ this.ct = 8;
5085
+ return;
5086
+ }
5087
+ let b;
5088
+ if (this.pos >= this.data.length) {
5089
+ b = 255;
5090
+ this.markerDetected = true;
5091
+ this.ct = 8;
5092
+ return;
5093
+ }
5094
+ b = this.data[this.pos];
5095
+ if (this.pos > 0 && this.data[this.pos - 1] === 255) {
5096
+ if (b > 143) {
5097
+ this.markerDetected = true;
5098
+ this.ct = 8;
5099
+ return;
5100
+ }
5101
+ this.pos++;
5102
+ this.c += b << 9;
5103
+ this.ct = 7;
5104
+ } else {
5105
+ this.pos++;
5106
+ this.c += b + 65280 << 8;
5107
+ this.ct = 8;
5108
+ }
5109
+ }
5110
+ /**
5111
+ * Decode a single bit using the given context.
5112
+ *
5113
+ * @param cx - Context state: { index: state index, mps: most probable symbol }
5114
+ * @returns The decoded bit (0 or 1).
5115
+ */
5116
+ decode(cx) {
5117
+ const qeEntry = MQDecoder.QE_TABLE[cx.index];
5118
+ const qe = qeEntry[0];
5119
+ this.a -= qe;
5120
+ let d;
5121
+ if (this.c >>> 16 < this.a) if (this.a < 32768) {
5122
+ d = this.a < qe ? 1 - cx.mps : cx.mps;
5123
+ if (this.a < qe) {
5124
+ cx.index = qeEntry[2];
5125
+ if (qeEntry[3]) cx.mps = 1 - cx.mps;
5126
+ } else cx.index = qeEntry[1];
5127
+ this.renormalize();
5128
+ } else d = cx.mps;
5129
+ else {
5130
+ this.c >>> 16;
5131
+ this.c -= this.a << 16;
5132
+ if (this.a < qe) {
5133
+ d = cx.mps;
5134
+ cx.index = qeEntry[1];
5135
+ } else {
5136
+ d = 1 - cx.mps;
5137
+ cx.index = qeEntry[2];
5138
+ if (qeEntry[3]) cx.mps = 1 - cx.mps;
5139
+ }
5140
+ this.a = qe;
5141
+ this.renormalize();
5142
+ }
5143
+ return d;
5144
+ }
5145
+ /**
5146
+ * Renormalization: double A and shift C until A >= 0x8000.
5147
+ */
5148
+ renormalize() {
5149
+ while (this.a < 32768) {
5150
+ if (this.ct === 0) this.byteIn();
5151
+ this.a <<= 1;
5152
+ this.c <<= 1;
5153
+ this.ct--;
5154
+ }
5155
+ }
5156
+ };
5157
+ /**
5158
+ * Create a fresh MQ context (uniform distribution).
5159
+ */
5160
+ function createMQContext() {
5161
+ return {
5162
+ index: 0,
5163
+ mps: 0
5164
+ };
5165
+ }
5166
+ /**
5167
+ * Tier-1 decode a code-block using the MQ arithmetic coder.
5168
+ *
5169
+ * Implements the three coding passes per bit-plane:
5170
+ * 1. Significance propagation pass
5171
+ * 2. Magnitude refinement pass
5172
+ * 3. Cleanup pass
5173
+ */
5174
+ function tier1Decode(cb, subbandType) {
5175
+ if (cb.codedData.length === 0 || cb.width === 0 || cb.height === 0) return;
5176
+ let totalLen = 0;
5177
+ for (const seg of cb.codedData) totalLen += seg.length;
5178
+ const codedBytes = new Uint8Array(totalLen);
5179
+ let off = 0;
5180
+ for (const seg of cb.codedData) {
5181
+ codedBytes.set(seg, off);
5182
+ off += seg.length;
5183
+ }
5184
+ if (codedBytes.length === 0) return;
5185
+ const w = cb.width;
5186
+ const h = cb.height;
5187
+ const numPixels = w * h;
5188
+ const significance = new Uint8Array(numPixels);
5189
+ const magnitude = new Int32Array(numPixels);
5190
+ const sign = new Uint8Array(numPixels);
5191
+ const mq = new MQDecoder(codedBytes);
5192
+ const contexts = [];
5193
+ for (let i = 0; i < 19; i++) contexts.push(createMQContext());
5194
+ const UNIFORM_CX = 18;
5195
+ const RUN_LENGTH_CX = 17;
5196
+ const maxBitPlanes = Math.max(1, Math.ceil(Math.log2(numPixels + 1)));
5197
+ const numBitPlanes = Math.min(maxBitPlanes, 8);
5198
+ const passesToDecode = Math.min(cb.numPasses, numBitPlanes * 3);
5199
+ let currentBitPlane = numBitPlanes - 1;
5200
+ let passIndex = 0;
5201
+ while (passIndex < passesToDecode && currentBitPlane >= 0) {
5202
+ const passType = passIndex % 3;
5203
+ try {
5204
+ switch (passType) {
5205
+ case 0:
5206
+ for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
5207
+ const idx = y * w + x;
5208
+ if (significance[idx]) continue;
5209
+ if (hasSignificantNeighbor(significance, x, y, w, h)) {
5210
+ const cx = getSignificanceContext(significance, x, y, w, h, subbandType);
5211
+ if (mq.decode(contexts[cx])) {
5212
+ significance[idx] = 1;
5213
+ sign[idx] = mq.decode(contexts[UNIFORM_CX]);
5214
+ magnitude[idx] |= 1 << currentBitPlane;
5215
+ }
5216
+ }
5217
+ }
5218
+ break;
5219
+ case 1:
5220
+ for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
5221
+ const idx = y * w + x;
5222
+ if (!significance[idx]) continue;
5223
+ if (magnitude[idx] === 0) continue;
5224
+ if (mq.decode(contexts[16])) magnitude[idx] |= 1 << currentBitPlane;
5225
+ }
5226
+ break;
5227
+ case 2:
5228
+ for (let y = 0; y < h; y += 4) for (let x = 0; x < w; x++) {
5229
+ const stripH = Math.min(4, h - y);
5230
+ let allInsig = true;
5231
+ for (let dy = 0; dy < stripH; dy++) if (significance[(y + dy) * w + x] || hasSignificantNeighbor(significance, x, y + dy, w, h)) {
5232
+ allInsig = false;
5233
+ break;
5234
+ }
5235
+ if (allInsig && stripH === 4) {
5236
+ if (mq.decode(contexts[RUN_LENGTH_CX]) === 0) continue;
5237
+ const r1 = mq.decode(contexts[UNIFORM_CX]);
5238
+ const r0 = mq.decode(contexts[UNIFORM_CX]);
5239
+ const firstSigRow = r1 << 1 | r0;
5240
+ const idx = (y + firstSigRow) * w + x;
5241
+ significance[idx] = 1;
5242
+ sign[idx] = mq.decode(contexts[UNIFORM_CX]);
5243
+ magnitude[idx] |= 1 << currentBitPlane;
5244
+ for (let dy = firstSigRow + 1; dy < stripH; dy++) {
5245
+ const idx2 = (y + dy) * w + x;
5246
+ if (significance[idx2]) continue;
5247
+ const cx = getSignificanceContext(significance, x, y + dy, w, h, subbandType);
5248
+ if (mq.decode(contexts[cx])) {
5249
+ significance[idx2] = 1;
5250
+ sign[idx2] = mq.decode(contexts[UNIFORM_CX]);
5251
+ magnitude[idx2] |= 1 << currentBitPlane;
5252
+ }
5253
+ }
5254
+ } else for (let dy = 0; dy < stripH; dy++) {
5255
+ const idx = (y + dy) * w + x;
5256
+ if (significance[idx]) continue;
5257
+ const cx = getSignificanceContext(significance, x, y + dy, w, h, subbandType);
5258
+ if (mq.decode(contexts[cx])) {
5259
+ significance[idx] = 1;
5260
+ sign[idx] = mq.decode(contexts[UNIFORM_CX]);
5261
+ magnitude[idx] |= 1 << currentBitPlane;
5262
+ }
5263
+ }
5264
+ }
5265
+ currentBitPlane--;
5266
+ break;
5267
+ }
5268
+ } catch {
5269
+ break;
5270
+ }
5271
+ passIndex++;
5272
+ }
5273
+ for (let i = 0; i < numPixels; i++) {
5274
+ const val = magnitude[i];
5275
+ cb.data[i] = sign[i] ? -val : val;
5276
+ }
5277
+ }
5278
+ /**
5279
+ * Check if any of the 8-connected neighbors is significant.
5280
+ */
5281
+ function hasSignificantNeighbor(sig, x, y, w, h) {
5282
+ for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
5283
+ if (dx === 0 && dy === 0) continue;
5284
+ const nx = x + dx;
5285
+ const ny = y + dy;
5286
+ if (nx >= 0 && nx < w && ny >= 0 && ny < h) {
5287
+ if (sig[ny * w + nx]) return true;
5288
+ }
5289
+ }
5290
+ return false;
5291
+ }
5292
+ /**
5293
+ * Determine the significance context index based on neighbor significance
5294
+ * and subband orientation.
5295
+ *
5296
+ * Returns context index 0-8 based on ITU-T T.800 Table D.1.
5297
+ */
5298
+ function getSignificanceContext(sig, x, y, w, h, subbandType) {
5299
+ let hCount = 0;
5300
+ let vCount = 0;
5301
+ let dCount = 0;
5302
+ const checkSig = (nx, ny) => {
5303
+ if (nx >= 0 && nx < w && ny >= 0 && ny < h) return sig[ny * w + nx] !== 0;
5304
+ return false;
5305
+ };
5306
+ if (checkSig(x - 1, y)) hCount++;
5307
+ if (checkSig(x + 1, y)) hCount++;
5308
+ if (checkSig(x, y - 1)) vCount++;
5309
+ if (checkSig(x, y + 1)) vCount++;
5310
+ if (checkSig(x - 1, y - 1)) dCount++;
5311
+ if (checkSig(x + 1, y - 1)) dCount++;
5312
+ if (checkSig(x - 1, y + 1)) dCount++;
5313
+ if (checkSig(x + 1, y + 1)) dCount++;
5314
+ if (subbandType === "HL") {
5315
+ const tmp = hCount;
5316
+ hCount = vCount;
5317
+ vCount = tmp;
5318
+ }
5319
+ if (subbandType === "HH") {
5320
+ const hvCount = hCount + vCount;
5321
+ if (dCount >= 3) return 8;
5322
+ if (dCount === 2) return hvCount >= 1 ? 7 : 6;
5323
+ if (dCount === 1) return hvCount >= 2 ? 7 : hvCount === 1 ? 6 : 5;
5324
+ if (hvCount >= 2) return 6;
5325
+ if (hvCount === 1) return 5;
5326
+ return 0;
5327
+ }
5328
+ if (hCount === 2) return 8;
5329
+ if (hCount === 1) {
5330
+ if (vCount >= 1) return 7;
5331
+ if (dCount >= 1) return 6;
5332
+ return 5;
5333
+ }
5334
+ if (vCount === 2) return 4;
5335
+ if (vCount === 1) return dCount >= 1 ? 3 : 2;
5336
+ if (dCount >= 2) return 1;
5337
+ if (dCount === 1) return 1;
5338
+ return 0;
5339
+ }
5340
+ /**
5341
+ * Dequantize subband coefficients using the QCD step sizes.
5342
+ */
5343
+ function dequantize(subbands, qcd, bpc, reversible) {
5344
+ if (reversible || qcd.quantStyle === 0) return;
5345
+ let subbandIndex = 0;
5346
+ for (const sb of subbands) {
5347
+ if (sb.width === 0 || sb.height === 0) {
5348
+ subbandIndex++;
5349
+ continue;
5350
+ }
5351
+ let stepSize;
5352
+ if (qcd.quantStyle === 1) {
5353
+ const base = qcd.stepSizes[0];
5354
+ if (sb.type === "LL") stepSize = base;
5355
+ else {
5356
+ sb.resLevel * 3;
5357
+ const idx = Math.min(subbandIndex, qcd.stepSizes.length - 1);
5358
+ stepSize = qcd.stepSizes[idx] ?? base;
5359
+ }
5360
+ } else {
5361
+ const idx = Math.min(subbandIndex, qcd.stepSizes.length - 1);
5362
+ stepSize = qcd.stepSizes[idx] ?? {
5363
+ epsilon: bpc,
5364
+ mu: 0
5365
+ };
5366
+ }
5367
+ const delta = (1 + stepSize.mu / 2048) * 2 ** (stepSize.epsilon - bpc);
5368
+ for (let i = 0; i < sb.coefficients.length; i++) sb.coefficients[i] *= delta;
5369
+ subbandIndex++;
5370
+ }
5371
+ }
5372
+ /**
5373
+ * Perform inverse DWT to reconstruct the image from subbands.
5374
+ *
5375
+ * Supports both 5/3 reversible (lossless) and 9/7 irreversible (lossy)
5376
+ * wavelet transforms.
5377
+ */
5378
+ function inverseDWT(subbands, width, height, numDecompLevels, reversible) {
5379
+ if (numDecompLevels === 0 || subbands.length === 0) {
5380
+ const ll = subbands[0];
5381
+ if (ll) {
5382
+ const result = new Float64Array(width * height);
5383
+ const copyW = Math.min(ll.width, width);
5384
+ const copyH = Math.min(ll.height, height);
5385
+ for (let y = 0; y < copyH; y++) for (let x = 0; x < copyW; x++) result[y * width + x] = ll.coefficients[y * ll.width + x];
5386
+ return result;
5387
+ }
5388
+ return new Float64Array(width * height);
5389
+ }
5390
+ const ll = subbands[0];
5391
+ let current = new Float64Array(ll.width * ll.height);
5392
+ for (let i = 0; i < ll.coefficients.length; i++) current[i] = ll.coefficients[i];
5393
+ let currentW = ll.width;
5394
+ let currentH = ll.height;
5395
+ for (let level = 1; level <= numDecompLevels; level++) {
5396
+ const hlIdx = 1 + (level - 1) * 3;
5397
+ const lhIdx = 2 + (level - 1) * 3;
5398
+ const hhIdx = 3 + (level - 1) * 3;
5399
+ const hl = subbands[hlIdx];
5400
+ const lh = subbands[lhIdx];
5401
+ const hh = subbands[hhIdx];
5402
+ if (!hl || !lh || !hh) continue;
5403
+ const outW = currentW + hl.width;
5404
+ const outH = currentH + lh.height;
5405
+ const result = new Float64Array(outW * outH);
5406
+ for (let y = 0; y < currentH; y++) for (let x = 0; x < currentW; x++) result[y * outW + x] = current[y * currentW + x];
5407
+ for (let y = 0; y < hl.height; y++) for (let x = 0; x < hl.width; x++) result[y * outW + (currentW + x)] = hl.coefficients[y * hl.width + x];
5408
+ for (let y = 0; y < lh.height; y++) for (let x = 0; x < lh.width; x++) result[(currentH + y) * outW + x] = lh.coefficients[y * lh.width + x];
5409
+ for (let y = 0; y < hh.height; y++) for (let x = 0; x < hh.width; x++) result[(currentH + y) * outW + (currentW + x)] = hh.coefficients[y * hh.width + x];
5410
+ if (reversible) inverseDWT53(result, outW, outH);
5411
+ else inverseDWT97(result, outW, outH);
5412
+ current = result;
5413
+ currentW = outW;
5414
+ currentH = outH;
5415
+ }
5416
+ if (currentW === width && currentH === height) return current;
5417
+ const output = new Float64Array(width * height);
5418
+ const copyW = Math.min(currentW, width);
5419
+ const copyH = Math.min(currentH, height);
5420
+ for (let y = 0; y < copyH; y++) for (let x = 0; x < copyW; x++) output[y * width + x] = current[y * currentW + x];
5421
+ return output;
5422
+ }
5423
+ /**
5424
+ * In-place inverse 5/3 (reversible, lossless) wavelet transform.
5425
+ *
5426
+ * The 5/3 wavelet uses integer lifting steps:
5427
+ * d[n] = d[n] - floor((s[n] + s[n+1]) / 2) (predict)
5428
+ * s[n] = s[n] + floor((d[n-1] + d[n] + 2) / 4) (update)
5429
+ *
5430
+ * where s = low-pass samples, d = high-pass (detail) samples.
5431
+ */
5432
+ function inverseDWT53(data, width, height) {
5433
+ const temp = new Float64Array(Math.max(width, height));
5434
+ for (let x = 0; x < width; x++) {
5435
+ const halfH = Math.ceil(height / 2);
5436
+ for (let y = 0; y < height; y++) temp[y] = data[y * width + x];
5437
+ const low = new Float64Array(halfH);
5438
+ const high = new Float64Array(height - halfH);
5439
+ for (let i = 0; i < halfH; i++) low[i] = temp[i];
5440
+ for (let i = 0; i < height - halfH; i++) high[i] = temp[halfH + i];
5441
+ for (let n = 0; n < halfH; n++) {
5442
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5443
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5444
+ low[n] -= Math.floor((dPrev + dCurr + 2) / 4);
5445
+ }
5446
+ for (let n = 0; n < high.length; n++) {
5447
+ const sn = low[n];
5448
+ const sn1 = n + 1 < halfH ? low[n + 1] : low[halfH - 1];
5449
+ high[n] += Math.floor((sn + sn1) / 2);
5450
+ }
5451
+ for (let i = 0; i < halfH; i++) data[i * 2 * width + x] = low[i];
5452
+ for (let i = 0; i < high.length; i++) data[(i * 2 + 1) * width + x] = high[i];
5453
+ }
5454
+ for (let y = 0; y < height; y++) {
5455
+ const halfW = Math.ceil(width / 2);
5456
+ for (let x = 0; x < width; x++) temp[x] = data[y * width + x];
5457
+ const low = new Float64Array(halfW);
5458
+ const high = new Float64Array(width - halfW);
5459
+ for (let i = 0; i < halfW; i++) low[i] = temp[i];
5460
+ for (let i = 0; i < width - halfW; i++) high[i] = temp[halfW + i];
5461
+ for (let n = 0; n < halfW; n++) {
5462
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5463
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5464
+ low[n] -= Math.floor((dPrev + dCurr + 2) / 4);
5465
+ }
5466
+ for (let n = 0; n < high.length; n++) {
5467
+ const sn = low[n];
5468
+ const sn1 = n + 1 < halfW ? low[n + 1] : low[halfW - 1];
5469
+ high[n] += Math.floor((sn + sn1) / 2);
5470
+ }
5471
+ for (let i = 0; i < halfW; i++) data[y * width + i * 2] = low[i];
5472
+ for (let i = 0; i < high.length; i++) data[y * width + i * 2 + 1] = high[i];
5473
+ }
5474
+ }
5475
+ /**
5476
+ * In-place inverse 9/7 (irreversible, lossy) wavelet transform.
5477
+ *
5478
+ * The 9/7 CDF wavelet uses four lifting steps with the following constants:
5479
+ * alpha = -1.586134342
5480
+ * beta = -0.052980118
5481
+ * gamma = 0.882911075
5482
+ * delta = 0.443506852
5483
+ * K = 1.230174105 (scaling factor)
5484
+ */
5485
+ function inverseDWT97(data, width, height) {
5486
+ const alpha = -1.586134342;
5487
+ const beta = -.052980118;
5488
+ const gamma = .882911075;
5489
+ const delta = .443506852;
5490
+ const K = 1.230174105;
5491
+ const invK = 1 / K;
5492
+ const temp = new Float64Array(Math.max(width, height));
5493
+ for (let x = 0; x < width; x++) {
5494
+ const halfH = Math.ceil(height / 2);
5495
+ for (let y = 0; y < height; y++) temp[y] = data[y * width + x];
5496
+ const low = new Float64Array(halfH);
5497
+ const high = new Float64Array(height - halfH);
5498
+ for (let i = 0; i < halfH; i++) low[i] = temp[i] * invK;
5499
+ for (let i = 0; i < high.length; i++) high[i] = temp[halfH + i] * K;
5500
+ for (let n = 0; n < halfH; n++) {
5501
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5502
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5503
+ low[n] -= delta * (dPrev + dCurr);
5504
+ }
5505
+ for (let n = 0; n < high.length; n++) {
5506
+ const sn = low[n];
5507
+ const sn1 = n + 1 < halfH ? low[n + 1] : low[halfH - 1];
5508
+ high[n] -= gamma * (sn + sn1);
5509
+ }
5510
+ for (let n = 0; n < halfH; n++) {
5511
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5512
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5513
+ low[n] -= beta * (dPrev + dCurr);
5514
+ }
5515
+ for (let n = 0; n < high.length; n++) {
5516
+ const sn = low[n];
5517
+ const sn1 = n + 1 < halfH ? low[n + 1] : low[halfH - 1];
5518
+ high[n] -= alpha * (sn + sn1);
5519
+ }
5520
+ for (let i = 0; i < halfH; i++) data[i * 2 * width + x] = low[i];
5521
+ for (let i = 0; i < high.length; i++) data[(i * 2 + 1) * width + x] = high[i];
5522
+ }
5523
+ for (let y = 0; y < height; y++) {
5524
+ const halfW = Math.ceil(width / 2);
5525
+ for (let x = 0; x < width; x++) temp[x] = data[y * width + x];
5526
+ const low = new Float64Array(halfW);
5527
+ const high = new Float64Array(width - halfW);
5528
+ for (let i = 0; i < halfW; i++) low[i] = temp[i] * invK;
5529
+ for (let i = 0; i < high.length; i++) high[i] = temp[halfW + i] * K;
5530
+ for (let n = 0; n < halfW; n++) {
5531
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5532
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5533
+ low[n] -= delta * (dPrev + dCurr);
5534
+ }
5535
+ for (let n = 0; n < high.length; n++) {
5536
+ const sn = low[n];
5537
+ const sn1 = n + 1 < halfW ? low[n + 1] : low[halfW - 1];
5538
+ high[n] -= gamma * (sn + sn1);
5539
+ }
5540
+ for (let n = 0; n < halfW; n++) {
5541
+ const dPrev = n > 0 ? high[n - 1] : high[0];
5542
+ const dCurr = n < high.length ? high[n] : high[high.length - 1];
5543
+ low[n] -= beta * (dPrev + dCurr);
5544
+ }
5545
+ for (let n = 0; n < high.length; n++) {
5546
+ const sn = low[n];
5547
+ const sn1 = n + 1 < halfW ? low[n + 1] : low[halfW - 1];
5548
+ high[n] -= alpha * (sn + sn1);
5549
+ }
5550
+ for (let i = 0; i < halfW; i++) data[y * width + i * 2] = low[i];
5551
+ for (let i = 0; i < high.length; i++) data[y * width + i * 2 + 1] = high[i];
5552
+ }
5553
+ }
5554
+ /**
5555
+ * Apply inverse color transform (ICT or RCT) in-place.
5556
+ *
5557
+ * ICT (Irreversible Color Transform) for lossy compression:
5558
+ * R = Y + 1.402 * Cr
5559
+ * G = Y - 0.344136 * Cb - 0.714136 * Cr
5560
+ * B = Y + 1.772 * Cb
5561
+ *
5562
+ * RCT (Reversible Color Transform) for lossless compression:
5563
+ * G = Y0 - floor((Y2 + Y1) / 4)
5564
+ * R = Y2 + G
5565
+ * B = Y1 + G
5566
+ */
5567
+ function applyInverseColorTransform(components, cod, numComponents) {
5568
+ if (numComponents < 3 || cod.multiComponentTransform === 0) return;
5569
+ const c0 = components[0];
5570
+ const c1 = components[1];
5571
+ const c2 = components[2];
5572
+ const numSamples = c0.length;
5573
+ if (cod.reversible) for (let i = 0; i < numSamples; i++) {
5574
+ const y0 = c0[i];
5575
+ const y1 = c1[i];
5576
+ const y2 = c2[i];
5577
+ const g = y0 - Math.floor((y2 + y1) / 4);
5578
+ const r = y2 + g;
5579
+ const b = y1 + g;
5580
+ c0[i] = r;
5581
+ c1[i] = g;
5582
+ c2[i] = b;
5583
+ }
5584
+ else for (let i = 0; i < numSamples; i++) {
5585
+ const y = c0[i];
5586
+ const cb = c1[i];
5587
+ const cr = c2[i];
5588
+ c0[i] = y + 1.402 * cr;
5589
+ c1[i] = y - .34413 * cb - .71414 * cr;
5590
+ c2[i] = y + 1.772 * cb;
5591
+ }
5592
+ }
5593
+ /**
5594
+ * Convert sYCC color space to sRGB in-place.
5595
+ *
5596
+ * sYCC uses the same transform as ICT (BT.601 coefficients).
5597
+ */
5598
+ function applySyccToSrgb(components, width, height) {
5599
+ const c0 = components[0];
5600
+ const c1 = components[1];
5601
+ const c2 = components[2];
5602
+ const numSamples = width * height;
5603
+ for (let i = 0; i < numSamples; i++) {
5604
+ const y = c0[i];
5605
+ const cb = c1[i] - 128;
5606
+ const cr = c2[i] - 128;
5607
+ c0[i] = y + 1.402 * cr;
5608
+ c1[i] = y - .34413 * cb - .71414 * cr;
5609
+ c2[i] = y + 1.772 * cb;
5610
+ }
5611
+ }
5612
+ /**
5613
+ * Interleave per-component floating-point samples into a packed byte
5614
+ * output buffer.
5615
+ */
5616
+ function interleaveComponents(components, output, width, height, numComponents, bpc, componentSigned) {
5617
+ const bytesPerSample = bpc <= 8 ? 1 : 2;
5618
+ const maxVal = (1 << bpc) - 1;
5619
+ const numPixels = width * height;
5620
+ let outIdx = 0;
5621
+ for (let i = 0; i < numPixels; i++) for (let c = 0; c < numComponents; c++) {
5622
+ let val = components[c][i];
5623
+ if (componentSigned[c]) val += 1 << bpc - 1;
5624
+ val = Math.round(val);
5625
+ if (val < 0) val = 0;
5626
+ if (val > maxVal) val = maxVal;
5627
+ if (bytesPerSample === 1) output[outIdx++] = val;
5628
+ else {
5629
+ output[outIdx++] = val >> 8 & 255;
5630
+ output[outIdx++] = val & 255;
5631
+ }
5632
+ }
5633
+ }
5634
+
4037
5635
  //#endregion
4038
5636
  //#region src/parser/streamDecode.ts
4039
5637
  /**
@@ -4124,7 +5722,8 @@ const FILTER_ABBREVIATIONS = {
4124
5722
  Fl: "FlateDecode",
4125
5723
  RL: "RunLengthDecode",
4126
5724
  CCF: "CCITTFaxDecode",
4127
- DCT: "DCTDecode"
5725
+ DCT: "DCTDecode",
5726
+ JPX: "JPXDecode"
4128
5727
  };
4129
5728
  function normalizeFilterName(name) {
4130
5729
  const n = name.startsWith("/") ? name.slice(1) : name;
@@ -4151,7 +5750,7 @@ function applyFilter(filterName, data, parms) {
4151
5750
  case "LZWDecode": return decodeLZW(data, parms);
4152
5751
  case "RunLengthDecode": return decodeRunLength(data);
4153
5752
  case "DCTDecode": return data;
4154
- case "JPXDecode": return data;
5753
+ case "JPXDecode": return decodeJPX(data, parms);
4155
5754
  case "CCITTFaxDecode": return decodeCCITT(data, parms);
4156
5755
  case "JBIG2Decode": return decodeJBIG2(data, parms);
4157
5756
  case "Crypt": return data;
@@ -4590,6 +6189,16 @@ function decodeRunLength(data) {
4590
6189
  }
4591
6190
  return new Uint8Array(result);
4592
6191
  }
6192
+ /**
6193
+ * Decode a JPXDecode (JPEG2000) stream.
6194
+ *
6195
+ * Calls the JPEG2000 decoder and returns raw pixel bytes. The
6196
+ * `/DecodeParms` dictionary may specify a color space override, but
6197
+ * the decoded data is always raw interleaved component bytes.
6198
+ */
6199
+ function decodeJPX(data, parms) {
6200
+ return decodeJpeg2000(data).data;
6201
+ }
4593
6202
 
4594
6203
  //#endregion
4595
6204
  Object.defineProperty(exports, 'decodeStream', {
@@ -4604,4 +6213,4 @@ Object.defineProperty(exports, 'getStreamFilters', {
4604
6213
  return getStreamFilters;
4605
6214
  }
4606
6215
  });
4607
- //# sourceMappingURL=streamDecode-Bs0_MT_Q.cjs.map
6216
+ //# sourceMappingURL=streamDecode-CvgErkFu.cjs.map