imagescript 1.3.1 → 3.0.0

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 (117) hide show
  1. package/LICENSE +4 -1
  2. package/README.md +64 -26
  3. package/THIRD_PARTY_NOTICES.md +74 -0
  4. package/dist/codecs/crc.d.ts +9 -0
  5. package/dist/codecs/crc.js +29 -0
  6. package/dist/codecs/exif.d.ts +11 -0
  7. package/dist/codecs/exif.js +27 -0
  8. package/dist/codecs/gif.d.ts +44 -0
  9. package/dist/codecs/gif.js +401 -0
  10. package/dist/codecs/jpeg.d.ts +35 -0
  11. package/dist/codecs/jpeg.js +980 -0
  12. package/dist/codecs/png.d.ts +44 -0
  13. package/dist/codecs/png.js +442 -0
  14. package/dist/codecs/quantize.d.ts +25 -0
  15. package/dist/codecs/quantize.js +302 -0
  16. package/dist/codecs/tiff.d.ts +6 -0
  17. package/dist/codecs/tiff.js +546 -0
  18. package/dist/codecs/zlib.d.ts +22 -0
  19. package/dist/codecs/zlib.js +607 -0
  20. package/dist/frame.d.ts +57 -0
  21. package/dist/frame.js +65 -0
  22. package/dist/gif.d.ts +44 -0
  23. package/dist/gif.js +93 -0
  24. package/dist/image-type.d.ts +20 -0
  25. package/dist/image-type.js +49 -0
  26. package/dist/image.d.ts +521 -0
  27. package/dist/image.js +1118 -0
  28. package/dist/index.d.ts +19 -0
  29. package/dist/index.js +13 -0
  30. package/dist/package.json +1 -0
  31. package/dist/render/font.d.ts +63 -0
  32. package/dist/render/font.js +857 -0
  33. package/dist/render/svg.d.ts +11 -0
  34. package/dist/render/svg.js +1717 -0
  35. package/dist/render/text.d.ts +61 -0
  36. package/dist/render/text.js +317 -0
  37. package/dist/text-layout.d.ts +46 -0
  38. package/dist/text-layout.js +35 -0
  39. package/dist/util/blur.d.ts +13 -0
  40. package/dist/util/blur.js +146 -0
  41. package/dist/util/mem.d.ts +10 -0
  42. package/dist/util/mem.js +23 -0
  43. package/dist/util/resample.d.ts +12 -0
  44. package/dist/util/resample.js +99 -0
  45. package/dist/util/utf8.d.ts +5 -0
  46. package/dist/util/utf8.js +55 -0
  47. package/dist/version.d.ts +1 -0
  48. package/dist/version.js +1 -0
  49. package/licenses/Apache-2.0.txt +202 -0
  50. package/licenses/README.ijg +260 -0
  51. package/package.json +31 -7
  52. package/ImageScript.d.ts +0 -954
  53. package/ImageScript.js +0 -1669
  54. package/bench/_.mjs +0 -166
  55. package/bench/all.mjs +0 -4
  56. package/bench/blur.mjs +0 -59
  57. package/bench/flip.mjs +0 -63
  58. package/bench/overlay.mjs +0 -35
  59. package/bench/package.json +0 -7
  60. package/bench/readme.md +0 -64
  61. package/bench/resize.mjs +0 -52
  62. package/codecs/LICENSE +0 -21
  63. package/codecs/lib.d.ts +0 -50
  64. package/codecs/lib.js +0 -6
  65. package/codecs/lib.mjs +0 -1
  66. package/codecs/node/bin/arm64-darwin.node +0 -0
  67. package/codecs/node/bin/arm64-linux.node +0 -0
  68. package/codecs/node/bin/x64-darwin.node +0 -0
  69. package/codecs/node/bin/x64-linux.node +0 -0
  70. package/codecs/node/bin/x64-win32.node +0 -0
  71. package/codecs/node/index.js +0 -3
  72. package/codecs/node/index.mjs +0 -6
  73. package/codecs/package.json +0 -14
  74. package/codecs/readme.md +0 -38
  75. package/codecs/wasm/bin/codecs.wasm +0 -0
  76. package/codecs/wasm/bin/simd.wasm +0 -0
  77. package/codecs/wasm/bundle/browser.js +0 -1
  78. package/codecs/wasm/index.js +0 -1
  79. package/codecs/wasm/index.mjs +0 -1
  80. package/png/README.md +0 -1
  81. package/png/node.js +0 -1137
  82. package/png/src/crc.mjs +0 -49
  83. package/png/src/mem.mjs +0 -24
  84. package/png/src/png.mjs +0 -254
  85. package/png/src/zlib.mjs +0 -618
  86. package/tsconfig.json +0 -21
  87. package/utils/mem.js +0 -26
  88. package/v2/codecs/magic.js +0 -25
  89. package/v2/framebuffer.d.ts +0 -67
  90. package/v2/framebuffer.js +0 -2352
  91. package/v2/framebuffer.mjs +0 -126
  92. package/v2/framebuffer.rs +0 -1264
  93. package/v2/index.d.ts +0 -84
  94. package/v2/index.js +0 -261
  95. package/v2/ops/blur.mjs +0 -303
  96. package/v2/ops/color.mjs +0 -277
  97. package/v2/ops/crop.mjs +0 -64
  98. package/v2/ops/fill.mjs +0 -33
  99. package/v2/ops/flip.mjs +0 -33
  100. package/v2/ops/index.mjs +0 -9
  101. package/v2/ops/iterator.mjs +0 -34
  102. package/v2/ops/overlay.mjs +0 -63
  103. package/v2/ops/resize.mjs +0 -166
  104. package/v2/ops/rotate.mjs +0 -117
  105. package/v2/util/mem.mjs +0 -24
  106. package/wasm/any/font.wasm +0 -0
  107. package/wasm/any/gif.wasm +0 -0
  108. package/wasm/any/jpeg.wasm +0 -0
  109. package/wasm/any/png.wasm +0 -0
  110. package/wasm/any/svg.wasm +0 -0
  111. package/wasm/any/tiff.wasm +0 -0
  112. package/wasm/node/font.js +0 -142
  113. package/wasm/node/gif.js +0 -76
  114. package/wasm/node/jpeg.js +0 -92
  115. package/wasm/node/png.js +0 -49
  116. package/wasm/node/svg.js +0 -56
  117. package/wasm/node/tiff.js +0 -47
@@ -0,0 +1,546 @@
1
+ import { decompressAsync } from "./zlib.js";
2
+ import * as jpeg from "./jpeg.js";
3
+ const TYPE_SIZES = { 1: 1, 2: 1, 3: 2, 4: 4, 5: 8, 6: 1, 7: 1, 8: 2, 9: 4, 10: 8, 11: 4, 12: 8, 13: 4, 16: 8, 17: 8, 18: 8 };
4
+ const TAGS = {
5
+ ImageWidth: 256,
6
+ ImageLength: 257,
7
+ BitsPerSample: 258,
8
+ Compression: 259,
9
+ Photometric: 262,
10
+ FillOrder: 266,
11
+ Orientation: 274,
12
+ StripOffsets: 273,
13
+ SamplesPerPixel: 277,
14
+ RowsPerStrip: 278,
15
+ StripByteCounts: 279,
16
+ PlanarConfiguration: 284,
17
+ Predictor: 317,
18
+ ColorMap: 320,
19
+ TileWidth: 322,
20
+ TileLength: 323,
21
+ TileOffsets: 324,
22
+ TileByteCounts: 325,
23
+ ExtraSamples: 338,
24
+ SampleFormat: 339,
25
+ JPEGTables: 347,
26
+ YCbCrCoefficients: 529,
27
+ YCbCrSubSampling: 530,
28
+ ReferenceBlackWhite: 532
29
+ };
30
+ const COMPRESSION_NAMES = { 2: 'CCITT RLE', 3: 'CCITT fax 3', 4: 'CCITT fax 4', 6: 'old-style JPEG', 32809: 'ThunderScan', 34676: 'SGI LogLuv', 34677: 'SGI LogL' };
31
+ export async function decode(data) {
32
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
33
+ let little;
34
+ if (data[0] === 0x49 && data[1] === 0x49)
35
+ little = true;
36
+ else if (data[0] === 0x4d && data[1] === 0x4d)
37
+ little = false;
38
+ else
39
+ throw new Error('TIFF: invalid byte order');
40
+ const u16 = (offset) => view.getUint16(offset, little);
41
+ const u32 = (offset) => view.getUint32(offset, little);
42
+ const u64 = (offset) => {
43
+ const lo = view.getUint32(offset + (little ? 0 : 4), little);
44
+ const hi = view.getUint32(offset + (little ? 4 : 0), little);
45
+ return hi * 0x100000000 + lo;
46
+ };
47
+ const version = u16(2);
48
+ if (version !== 42 && version !== 43)
49
+ throw new Error('TIFF: invalid version');
50
+ const big = version === 43;
51
+ const ifdOffset = big ? u64(8) : u32(4);
52
+ if (ifdOffset + 2 > data.length)
53
+ throw new Error('TIFF: invalid IFD offset');
54
+ const tags = new Map();
55
+ const entryCount = big ? u64(ifdOffset) : u16(ifdOffset);
56
+ const entrySize = big ? 20 : 12;
57
+ const inlineSize = big ? 8 : 4;
58
+ for (let i = 0; i < entryCount; i++) {
59
+ const entry = ifdOffset + (big ? 8 : 2) + i * entrySize;
60
+ if (entry + entrySize > data.length)
61
+ break;
62
+ const tag = u16(entry);
63
+ const type = u16(entry + 2);
64
+ const count = big ? u64(entry + 4) : u32(entry + 4);
65
+ const size = TYPE_SIZES[type];
66
+ if (!size)
67
+ continue;
68
+ const valueField = entry + (big ? 12 : 8);
69
+ const offset = size * count <= inlineSize ? valueField : big ? u64(valueField) : u32(valueField);
70
+ if (offset + size * count > data.length)
71
+ continue;
72
+ tags.set(tag, { type, count, offset });
73
+ }
74
+ const read = (type, offset) => {
75
+ switch (type) {
76
+ case 1:
77
+ case 2:
78
+ case 7: return data[offset];
79
+ case 6: return view.getInt8(offset);
80
+ case 3: return u16(offset);
81
+ case 8: return view.getInt16(offset, little);
82
+ case 4:
83
+ case 13: return u32(offset);
84
+ case 9: return view.getInt32(offset, little);
85
+ case 5: return u32(offset) / u32(offset + 4);
86
+ case 10: return view.getInt32(offset, little) / view.getInt32(offset + 4, little);
87
+ case 11: return view.getFloat32(offset, little);
88
+ case 12: return view.getFloat64(offset, little);
89
+ case 16:
90
+ case 18: return u64(offset);
91
+ case 17: return Number(view.getBigInt64(offset, little));
92
+ default: return 0;
93
+ }
94
+ };
95
+ function values(tag, fallback) {
96
+ const entry = tags.get(tag);
97
+ if (!entry)
98
+ return fallback;
99
+ const result = new Array(entry.count);
100
+ const size = TYPE_SIZES[entry.type];
101
+ for (let i = 0; i < entry.count; i++)
102
+ result[i] = read(entry.type, entry.offset + i * size);
103
+ return result;
104
+ }
105
+ function value(tag, fallback) {
106
+ const v = values(tag);
107
+ return v && v.length ? v[0] : fallback;
108
+ }
109
+ const orientationTag = value(TAGS.Orientation, 1);
110
+ const orientation = orientationTag >= 1 && orientationTag <= 8 ? orientationTag : 1;
111
+ const width = value(TAGS.ImageWidth);
112
+ const height = value(TAGS.ImageLength);
113
+ if (!width || !height)
114
+ throw new Error('TIFF: invalid dimensions');
115
+ const samplesPerPixel = value(TAGS.SamplesPerPixel, 1);
116
+ const bitsPerSample = values(TAGS.BitsPerSample, [1]);
117
+ const bps = bitsPerSample[0];
118
+ if (bitsPerSample.some(b => b !== bps))
119
+ throw new Error('TIFF: mixed bit depths are not supported');
120
+ const compression = value(TAGS.Compression, 1);
121
+ const photometric = value(TAGS.Photometric, samplesPerPixel >= 3 ? 2 : 1);
122
+ const planar = value(TAGS.PlanarConfiguration, 1) === 2 && samplesPerPixel > 1;
123
+ const predictor = value(TAGS.Predictor, 1);
124
+ const sampleFormat = value(TAGS.SampleFormat, 1);
125
+ const fillOrder = value(TAGS.FillOrder, 1);
126
+ const extraSamples = values(TAGS.ExtraSamples, []);
127
+ if (COMPRESSION_NAMES[compression])
128
+ throw new Error(`TIFF: ${COMPRESSION_NAMES[compression]} compression is not supported`);
129
+ if (![1, 5, 7, 8, 32773, 32946].includes(compression))
130
+ throw new Error(`TIFF: compression ${compression} is not supported`);
131
+ if (![0, 1, 2, 3, 5, 6].includes(photometric))
132
+ throw new Error(`TIFF: photometric interpretation ${photometric} is not supported`);
133
+ if (sampleFormat === 3 ? bps !== 32 && bps !== 64 : bps < 1 || bps > 32)
134
+ throw new Error(`TIFF: ${bps}-bit samples are not supported`);
135
+ const colorChannels = { 0: 1, 1: 1, 2: 3, 3: 1, 5: 4, 6: 3 }[photometric];
136
+ if (samplesPerPixel < colorChannels)
137
+ throw new Error('TIFF: not enough samples per pixel');
138
+ const alphaType = samplesPerPixel > colorChannels ? extraSamples[0] || 0 : 0;
139
+ const alphaChannel = alphaType === 1 || alphaType === 2 ? colorChannels : -1;
140
+ const tiled = tags.has(TAGS.TileWidth) && tags.has(TAGS.TileLength);
141
+ const segmentWidth = tiled ? value(TAGS.TileWidth) : width;
142
+ const segmentHeight = tiled ? value(TAGS.TileLength) : Math.min(height, value(TAGS.RowsPerStrip, height));
143
+ const offsets = values(TAGS.TileOffsets) || values(TAGS.StripOffsets);
144
+ const byteCounts = values(TAGS.TileByteCounts) || values(TAGS.StripByteCounts);
145
+ if (!offsets || !segmentWidth || !segmentHeight)
146
+ throw new Error('TIFF: missing image data');
147
+ const segmentsAcross = Math.ceil(width / segmentWidth);
148
+ const segmentsDown = Math.ceil(height / segmentHeight);
149
+ const segmentsPerPlane = segmentsAcross * segmentsDown;
150
+ const segment = (index) => {
151
+ const offset = offsets[index];
152
+ const count = byteCounts ? byteCounts[index] : data.length - offset;
153
+ if (offset === undefined || offset >= data.length)
154
+ throw new Error('TIFF: missing image data');
155
+ return data.subarray(offset, Math.min(data.length, offset + count));
156
+ };
157
+ const pixels = new Uint8Array(width * height * 4);
158
+ if (compression === 7) {
159
+ const tables = tags.has(TAGS.JPEGTables) ? data.subarray(tags.get(TAGS.JPEGTables).offset, tags.get(TAGS.JPEGTables).offset + tags.get(TAGS.JPEGTables).count) : null;
160
+ const transform = photometric === 6 ? 'ycc' : photometric === 2 ? 'rgb' : photometric === 5 ? 'cmyk' : null;
161
+ for (let s = 0; s < segmentsPerPlane; s++) {
162
+ let stream = segment(s);
163
+ if (tables) {
164
+ const joined = new Uint8Array(tables.length - 2 + stream.length - 2);
165
+ joined.set(tables.subarray(0, tables.length - 2));
166
+ joined.set(stream.subarray(2), tables.length - 2);
167
+ stream = joined;
168
+ }
169
+ const decoded = jpeg.decode(stream, { transform });
170
+ blitRGBA(decoded.pixels, decoded.width, decoded.height, pixels, width, height, (s % segmentsAcross) * segmentWidth, (s / segmentsAcross | 0) * segmentHeight);
171
+ }
172
+ return { width, height, pixels, orientation };
173
+ }
174
+ const samplesPerRow = planar ? 1 : samplesPerPixel;
175
+ const planes = planar ? samplesPerPixel : 1;
176
+ const subsampling = photometric === 6 ? values(TAGS.YCbCrSubSampling, [2, 2]) : [1, 1];
177
+ const subsampled = photometric === 6 && (subsampling[0] !== 1 || subsampling[1] !== 1);
178
+ if (subsampled) {
179
+ if (tiled || planar || bps !== 8)
180
+ throw new Error('TIFF: subsampled YCbCr is only supported for 8-bit strips');
181
+ const [h, v] = subsampling;
182
+ const unitsPerRow = Math.ceil(width / h);
183
+ const unitRowBytes = unitsPerRow * (h * v + 2);
184
+ const units = new Uint8Array(Math.ceil(height / v) * unitRowBytes);
185
+ let written = 0;
186
+ for (let s = 0; s < segmentsPerPlane && written < units.length; s++) {
187
+ const expected = Math.min(units.length - written, Math.ceil(segmentHeight / v) * unitRowBytes);
188
+ const raw = await decompressSegment(segment(s), compression, expected);
189
+ units.set(raw.subarray(0, expected), written);
190
+ written += expected;
191
+ }
192
+ ycbcrUnitsToRGBA(units, width, height, h, v, ycbcrConversion(values), pixels);
193
+ return { width, height, pixels, orientation };
194
+ }
195
+ const rowBytes = Math.ceil(width * samplesPerRow * bps / 8);
196
+ const planeBytes = rowBytes * height;
197
+ const raw = new Uint8Array(planeBytes * planes);
198
+ const segmentRowBytes = Math.ceil(segmentWidth * samplesPerRow * bps / 8);
199
+ for (let plane = 0; plane < planes; plane++) {
200
+ for (let s = 0; s < segmentsPerPlane; s++) {
201
+ const sx = (s % segmentsAcross) * segmentWidth;
202
+ const sy = (s / segmentsAcross | 0) * segmentHeight;
203
+ const rows = tiled ? segmentHeight : Math.min(segmentHeight, height - sy);
204
+ const expected = rows * segmentRowBytes;
205
+ const bytes = await decompressSegment(segment(plane * segmentsPerPlane + s), compression, expected);
206
+ if (fillOrder === 2)
207
+ reverseBits(bytes);
208
+ if (predictor === 2)
209
+ undoHorizontalPredictor(bytes, segmentRowBytes, rows, samplesPerRow, bps, little);
210
+ else if (predictor === 3)
211
+ undoFloatingPointPredictor(bytes, segmentRowBytes, rows, samplesPerRow, bps);
212
+ const visibleRows = Math.min(rows, height - sy);
213
+ const startBit = sx * samplesPerRow * bps;
214
+ const copyBits = Math.min(segmentWidth, width - sx) * samplesPerRow * bps;
215
+ for (let row = 0; row < visibleRows; row++) {
216
+ const target = plane * planeBytes + (sy + row) * rowBytes;
217
+ if (startBit % 8 === 0) {
218
+ const start = target + startBit / 8;
219
+ raw.set(bytes.subarray(row * segmentRowBytes, row * segmentRowBytes + Math.ceil(copyBits / 8)).subarray(0, rowBytes - startBit / 8), start);
220
+ }
221
+ else
222
+ copyBitsUnaligned(bytes, row * segmentRowBytes * 8, raw, target * 8 + startBit, copyBits);
223
+ }
224
+ }
225
+ }
226
+ const sampleLittle = predictor === 3 ? true : little;
227
+ const readSample = sampleReader(raw, bps, sampleFormat, sampleLittle, sampleFormat === 3 ? floatRange(raw, bps, sampleLittle) : null);
228
+ const sampleAt = planar
229
+ ? (x, y, s) => readSample(s * planeBytes + y * rowBytes, x)
230
+ : (x, y, s) => readSample(y * rowBytes, x * samplesPerPixel + s);
231
+ const colormap = photometric === 3 ? values(TAGS.ColorMap, []) : [];
232
+ if (photometric === 3 && colormap.length < 3 << bps)
233
+ throw new Error('TIFF: missing color map');
234
+ const ycc = photometric === 6 ? ycbcrConversion(values) : null;
235
+ for (let y = 0, o = 0; y < height; y++) {
236
+ for (let x = 0; x < width; x++, o += 4) {
237
+ if (photometric === 3) {
238
+ const index = sampleAt(x, y, 0).raw;
239
+ const entries = 1 << bps;
240
+ pixels[o] = colormap[index] >> 8;
241
+ pixels[o + 1] = colormap[entries + index] >> 8;
242
+ pixels[o + 2] = colormap[2 * entries + index] >> 8;
243
+ }
244
+ else if (photometric <= 1) {
245
+ const v = sampleAt(x, y, 0).value;
246
+ pixels[o] = pixels[o + 1] = pixels[o + 2] = photometric === 0 ? 255 - v : v;
247
+ }
248
+ else if (photometric === 2) {
249
+ pixels[o] = sampleAt(x, y, 0).value;
250
+ pixels[o + 1] = sampleAt(x, y, 1).value;
251
+ pixels[o + 2] = sampleAt(x, y, 2).value;
252
+ }
253
+ else if (photometric === 5) {
254
+ const k = sampleAt(x, y, 3).value;
255
+ pixels[o] = cmykToRGB(sampleAt(x, y, 0).value, k);
256
+ pixels[o + 1] = cmykToRGB(sampleAt(x, y, 1).value, k);
257
+ pixels[o + 2] = cmykToRGB(sampleAt(x, y, 2).value, k);
258
+ }
259
+ else
260
+ ycc(sampleAt(x, y, 0).value, sampleAt(x, y, 1).value, sampleAt(x, y, 2).value, pixels, o);
261
+ if (alphaChannel === -1)
262
+ pixels[o + 3] = 0xff;
263
+ else {
264
+ const alpha = pixels[o + 3] = sampleAt(x, y, alphaChannel).value;
265
+ if (alphaType === 1) {
266
+ for (let c = 0; c < 3; c++)
267
+ pixels[o + c] = alpha ? Math.min(255, Math.round(pixels[o + c] * 255 / alpha)) : 0;
268
+ }
269
+ }
270
+ }
271
+ }
272
+ return { width, height, pixels, orientation };
273
+ }
274
+ function sampleReader(raw, bps, sampleFormat, little, range) {
275
+ const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
276
+ const result = { raw: 0, value: 0 };
277
+ if (sampleFormat === 3) {
278
+ const [min, max] = range || [0, 1];
279
+ const scale = 255 / (max - min || 1);
280
+ return (rowOffset, n) => {
281
+ const v = bps === 32 ? view.getFloat32(rowOffset + n * 4, little) : view.getFloat64(rowOffset + n * 8, little);
282
+ result.raw = v;
283
+ result.value = v === v ? Math.min(255, Math.max(0, Math.round((v - min) * scale))) : 0;
284
+ return result;
285
+ };
286
+ }
287
+ const signed = sampleFormat === 2;
288
+ const max = 2 ** bps - 1;
289
+ if (bps === 8) {
290
+ return (rowOffset, n) => {
291
+ result.raw = raw[rowOffset + n];
292
+ result.value = signed ? result.raw ^ 0x80 : result.raw;
293
+ return result;
294
+ };
295
+ }
296
+ if (bps === 16) {
297
+ return (rowOffset, n) => {
298
+ result.raw = view.getUint16(rowOffset + n * 2, little);
299
+ result.value = (signed ? result.raw ^ 0x8000 : result.raw) >> 8;
300
+ return result;
301
+ };
302
+ }
303
+ if (bps === 32) {
304
+ return (rowOffset, n) => {
305
+ result.raw = view.getUint32(rowOffset + n * 4, little);
306
+ result.value = (signed ? (result.raw ^ 0x80000000) >>> 0 : result.raw) >>> 24;
307
+ return result;
308
+ };
309
+ }
310
+ return (rowOffset, n) => {
311
+ let bit = rowOffset * 8 + n * bps;
312
+ let v = 0;
313
+ for (let remaining = bps; remaining > 0;) {
314
+ const byte = raw[bit >> 3];
315
+ const available = 8 - (bit & 7);
316
+ const take = Math.min(available, remaining);
317
+ v = v * (1 << take) + (byte >> available - take & (1 << take) - 1);
318
+ bit += take;
319
+ remaining -= take;
320
+ }
321
+ if (signed)
322
+ v = (v + 2 ** (bps - 1)) % 2 ** bps;
323
+ result.raw = v;
324
+ result.value = bps === 1 ? v * 255 : Math.round(v * 255 / max);
325
+ return result;
326
+ };
327
+ }
328
+ function floatRange(raw, bps, little) {
329
+ const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
330
+ const size = bps / 8;
331
+ let min = Infinity, max = -Infinity;
332
+ for (let o = 0; o + size <= raw.length; o += size) {
333
+ const v = size === 4 ? view.getFloat32(o, little) : view.getFloat64(o, little);
334
+ if (v < min)
335
+ min = v;
336
+ if (v > max)
337
+ max = v;
338
+ }
339
+ if (min >= 0 && max <= 1)
340
+ return [0, 1];
341
+ if (min >= 0 && max <= 255)
342
+ return [0, 255];
343
+ return [min, max];
344
+ }
345
+ async function decompressSegment(bytes, compression, expected) {
346
+ let out;
347
+ if (compression === 5)
348
+ out = lzw(bytes, expected);
349
+ else if (compression === 8 || compression === 32946)
350
+ out = await decompressAsync(bytes, expected);
351
+ else if (compression === 32773)
352
+ out = packBits(bytes, expected);
353
+ else
354
+ out = bytes.slice(0, expected);
355
+ if (out.length >= expected)
356
+ return out.length === expected ? out : out.slice(0, expected);
357
+ const padded = new Uint8Array(expected);
358
+ padded.set(out);
359
+ return padded;
360
+ }
361
+ function lzw(input, expected) {
362
+ const out = new Uint8Array(expected);
363
+ const compat = input[0] === 0 && (input[1] & 1) === 1;
364
+ const prefix = new Uint16Array(4096);
365
+ const suffix = new Uint8Array(4096);
366
+ const first = new Uint8Array(4096);
367
+ const lengths = new Uint16Array(4096);
368
+ for (let i = 0; i < 256; i++) {
369
+ suffix[i] = first[i] = i;
370
+ lengths[i] = 1;
371
+ }
372
+ let codeSize = 9, next = 258, previous = -1;
373
+ let buffer = 0, bits = 0, position = 0, written = 0;
374
+ while (written < expected) {
375
+ while (bits < codeSize) {
376
+ if (position >= input.length)
377
+ return out.subarray(0, written);
378
+ buffer = compat ? buffer | input[position++] << bits : (buffer << 8 | input[position++]) & 0xffffff;
379
+ bits += 8;
380
+ }
381
+ let code;
382
+ if (compat) {
383
+ code = buffer & (1 << codeSize) - 1;
384
+ buffer >>>= codeSize;
385
+ }
386
+ else
387
+ code = buffer >> bits - codeSize & (1 << codeSize) - 1;
388
+ bits -= codeSize;
389
+ if (code === 256) {
390
+ codeSize = 9;
391
+ next = 258;
392
+ previous = -1;
393
+ continue;
394
+ }
395
+ if (code === 257)
396
+ break;
397
+ let entry;
398
+ if (previous === -1) {
399
+ if (code > 255)
400
+ break;
401
+ entry = code;
402
+ }
403
+ else if (code < next)
404
+ entry = code;
405
+ else if (code === next)
406
+ entry = previous;
407
+ else
408
+ break;
409
+ const length = lengths[entry];
410
+ let c = entry;
411
+ for (let i = written + length - 1; i >= written; i--) {
412
+ if (i < expected)
413
+ out[i] = suffix[c];
414
+ c = prefix[c];
415
+ }
416
+ written += length;
417
+ if (code === next && written < expected)
418
+ out[written] = first[previous];
419
+ if (code === next)
420
+ written++;
421
+ if (previous !== -1 && next < 4096) {
422
+ prefix[next] = previous;
423
+ suffix[next] = first[code === next ? previous : code];
424
+ first[next] = first[previous];
425
+ lengths[next] = lengths[previous] + 1;
426
+ next++;
427
+ }
428
+ if (next + (compat ? 0 : 1) >= 1 << codeSize && codeSize < 12)
429
+ codeSize++;
430
+ previous = code;
431
+ }
432
+ return out.subarray(0, Math.min(written, expected));
433
+ }
434
+ function packBits(input, expected) {
435
+ const out = new Uint8Array(expected);
436
+ let i = 0, o = 0;
437
+ while (i < input.length && o < expected) {
438
+ const n = input[i++];
439
+ if (n < 128) {
440
+ const count = Math.min(n + 1, expected - o, input.length - i);
441
+ out.set(input.subarray(i, i + count), o);
442
+ i += n + 1;
443
+ o += count;
444
+ }
445
+ else if (n > 128) {
446
+ const count = Math.min(257 - n, expected - o);
447
+ out.fill(input[i++], o, o + count);
448
+ o += count;
449
+ }
450
+ }
451
+ return out.subarray(0, o);
452
+ }
453
+ function reverseBits(bytes) {
454
+ for (let i = 0; i < bytes.length; i++) {
455
+ let b = bytes[i];
456
+ b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
457
+ b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
458
+ bytes[i] = (b & 0xaa) >> 1 | (b & 0x55) << 1;
459
+ }
460
+ }
461
+ function undoHorizontalPredictor(bytes, rowBytes, rows, samplesPerPixel, bps, little) {
462
+ if (bps === 8) {
463
+ for (let r = 0; r < rows; r++)
464
+ for (let i = r * rowBytes + samplesPerPixel, end = (r + 1) * rowBytes; i < end; i++)
465
+ bytes[i] = bytes[i] + bytes[i - samplesPerPixel];
466
+ }
467
+ else if (bps === 16 || bps === 32) {
468
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
469
+ const size = bps / 8;
470
+ const get = size === 2 ? (o) => view.getUint16(o, little) : (o) => view.getUint32(o, little);
471
+ const set = size === 2 ? (o, v) => view.setUint16(o, v, little) : (o, v) => view.setUint32(o, v >>> 0, little);
472
+ const stride = samplesPerPixel * size;
473
+ for (let r = 0; r < rows; r++)
474
+ for (let o = r * rowBytes + stride, end = r * rowBytes + Math.floor(rowBytes / size) * size; o < end; o += size)
475
+ set(o, get(o) + get(o - stride));
476
+ }
477
+ else
478
+ throw new Error(`TIFF: horizontal predictor with ${bps}-bit samples is not supported`);
479
+ }
480
+ function undoFloatingPointPredictor(bytes, rowBytes, rows, samplesPerPixel, bps) {
481
+ const size = bps / 8;
482
+ const count = rowBytes / size;
483
+ const tmp = new Uint8Array(rowBytes);
484
+ for (let r = 0; r < rows; r++) {
485
+ const row = bytes.subarray(r * rowBytes, (r + 1) * rowBytes);
486
+ for (let i = samplesPerPixel; i < rowBytes; i++)
487
+ row[i] = row[i] + row[i - samplesPerPixel];
488
+ tmp.set(row);
489
+ for (let n = 0; n < count; n++)
490
+ for (let b = 0; b < size; b++)
491
+ row[n * size + b] = tmp[(size - b - 1) * count + n];
492
+ }
493
+ }
494
+ function copyBitsUnaligned(src, srcBit, dst, dstBit, count) {
495
+ for (let i = 0; i < count; i++, srcBit++, dstBit++) {
496
+ const bit = src[srcBit >> 3] >> 7 - (srcBit & 7) & 1;
497
+ if (bit)
498
+ dst[dstBit >> 3] |= 0x80 >> (dstBit & 7);
499
+ else
500
+ dst[dstBit >> 3] &= ~(0x80 >> (dstBit & 7));
501
+ }
502
+ }
503
+ function blitRGBA(src, sw, sh, dst, dw, dh, x0, y0) {
504
+ const w = Math.min(sw, dw - x0);
505
+ for (let y = 0; y < sh && y0 + y < dh; y++)
506
+ dst.set(src.subarray(y * sw * 4, (y * sw + w) * 4), ((y0 + y) * dw + x0) * 4);
507
+ }
508
+ function ycbcrConversion(values) {
509
+ const [lr, lg, lb] = values(TAGS.YCbCrCoefficients, [0.299, 0.587, 0.114]);
510
+ const reference = values(TAGS.ReferenceBlackWhite, [0, 255, 128, 255, 128, 255]);
511
+ const scale = (v, black, white, center) => (v - black) * (center ? 127 : 255) / (white - black || 1);
512
+ return (Y, Cb, Cr, out, o) => {
513
+ const y = scale(Y, reference[0], reference[1], false);
514
+ const cb = scale(Cb, reference[2], reference[3], true);
515
+ const cr = scale(Cr, reference[4], reference[5], true);
516
+ const r = y + cr * (2 - 2 * lr);
517
+ const b = y + cb * (2 - 2 * lb);
518
+ const g = (y - lb * b - lr * r) / lg;
519
+ out[o] = Math.min(255, Math.max(0, Math.round(r)));
520
+ out[o + 1] = Math.min(255, Math.max(0, Math.round(g)));
521
+ out[o + 2] = Math.min(255, Math.max(0, Math.round(b)));
522
+ };
523
+ }
524
+ function ycbcrUnitsToRGBA(units, width, height, h, v, convert, pixels) {
525
+ const unitsPerRow = Math.ceil(width / h);
526
+ const unitSize = h * v + 2;
527
+ for (let uy = 0; uy < Math.ceil(height / v); uy++)
528
+ for (let ux = 0; ux < unitsPerRow; ux++) {
529
+ const u = (uy * unitsPerRow + ux) * unitSize;
530
+ const cb = units[u + h * v], cr = units[u + h * v + 1];
531
+ for (let j = 0; j < v; j++)
532
+ for (let i = 0; i < h; i++) {
533
+ const x = ux * h + i, y = uy * v + j;
534
+ if (x >= width || y >= height)
535
+ continue;
536
+ const o = (y * width + x) * 4;
537
+ convert(units[u + j * h + i], cb, cr, pixels, o);
538
+ pixels[o + 3] = 0xff;
539
+ }
540
+ }
541
+ }
542
+ function cmykToRGB(c, k) {
543
+ const t = (255 - c) * k + 128;
544
+ const v = 255 - (c + ((t >> 8) + t >> 8));
545
+ return v < 0 ? 0 : v;
546
+ }
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * zlib deflate/inflate, derived from fflate (https://github.com/101arrowz/fflate)
3
+ * Copyright (c) 2020 Arjun Barrett, MIT License (see THIRD_PARTY_NOTICES.md)
4
+ */
5
+ /**
6
+ * Compresses data into a zlib stream
7
+ * @param level compression level 0-9
8
+ */
9
+ export declare function compress(data: Uint8Array, level: number): Uint8Array;
10
+ /**
11
+ * Decompresses a zlib stream into at most limit bytes
12
+ */
13
+ export declare function decompress(data: Uint8Array, limit: number): Uint8Array;
14
+ /**
15
+ * Compresses data into a zlib stream, with the runtime's native zlib when available
16
+ * @param level compression level 0-9
17
+ */
18
+ export declare function compressAsync(data: Uint8Array, level: number): Promise<Uint8Array>;
19
+ /**
20
+ * Decompresses a zlib stream into at most limit bytes, using the runtime's native zlib when available
21
+ */
22
+ export declare function decompressAsync(data: Uint8Array, limit: number): Promise<Uint8Array>;