ag-psd 31.0.3 → 32.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.
- package/.v8-cache/v24.7.0-x64-ef5a0af0/00d0e0b4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/0cc76730 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/20729831 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/214a593b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/25f8b84a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/27518289 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/330ef2d9 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/37ff16b8 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/3f72a97c +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/75efccd4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/762f9305 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7bcfc50a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/825e9a05 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87372817 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/891a7c73 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/8b68a3a2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a1d12a93 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/a7e80865 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/ac317c9c +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b8569d6b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/b8b073c4 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/bb489c89 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c46725e1 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c794cb34 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cd4ae980 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/d02dd6f7 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6735171 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f5417276 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f74d3518 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f886deac +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fd0a2987 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/fe349423 +0 -0
- package/CHANGELOG.md +29 -0
- package/dist/abr.js +12 -5
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +2 -0
- package/dist/additionalInfo.js +123 -68
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +1365 -632
- package/dist/descriptor.d.ts +15 -2
- package/dist/descriptor.js +329 -100
- package/dist/descriptor.js.map +1 -1
- package/dist/effectsHelpers.js +12 -12
- package/dist/effectsHelpers.js.map +1 -1
- package/dist/engineData.d.ts +3 -1
- package/dist/engineData.js +34 -13
- package/dist/engineData.js.map +1 -1
- package/dist/engineData2.js +50 -21
- package/dist/engineData2.js.map +1 -1
- package/dist/helpers.d.ts +5 -2
- package/dist/helpers.js +18 -4
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +45 -21
- package/dist/imageResources.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jpeg.js +27 -7
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +6 -1
- package/dist/psdReader.d.ts +2 -2
- package/dist/psdReader.js +457 -270
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +2 -0
- package/dist/psdWriter.js +98 -76
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.js +126 -23
- package/dist/text.js.map +1 -1
- package/dist/utf8.js +36 -15
- package/dist/utf8.js.map +1 -1
- package/dist-es/abr.js +12 -5
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +2 -0
- package/dist-es/additionalInfo.js +123 -68
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/descriptor.d.ts +15 -2
- package/dist-es/descriptor.js +329 -100
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/effectsHelpers.js +12 -12
- package/dist-es/effectsHelpers.js.map +1 -1
- package/dist-es/engineData.d.ts +3 -1
- package/dist-es/engineData.js +34 -13
- package/dist-es/engineData.js.map +1 -1
- package/dist-es/engineData2.js +50 -21
- package/dist-es/engineData2.js.map +1 -1
- package/dist-es/helpers.d.ts +5 -2
- package/dist-es/helpers.js +18 -4
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +45 -21
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/index.js +1 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/jpeg.js +27 -7
- package/dist-es/jpeg.js.map +1 -1
- package/dist-es/psd.d.ts +6 -1
- package/dist-es/psdReader.d.ts +2 -2
- package/dist-es/psdReader.js +457 -270
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +2 -0
- package/dist-es/psdWriter.js +98 -76
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.js +126 -23
- package/dist-es/text.js.map +1 -1
- package/dist-es/utf8.js +36 -15
- package/dist-es/utf8.js.map +1 -1
- package/package.json +1 -1
- package/src/abr.ts +14 -6
- package/src/additionalInfo.ts +127 -66
- package/src/descriptor.ts +347 -107
- package/src/effectsHelpers.ts +9 -9
- package/src/engineData.ts +36 -13
- package/src/engineData2.ts +468 -432
- package/src/helpers.ts +19 -4
- package/src/imageResources.ts +49 -22
- package/src/index.ts +1 -0
- package/src/jpeg.ts +24 -9
- package/src/psd.ts +3 -1
- package/src/psdReader.ts +477 -260
- package/src/psdWriter.ts +100 -83
- package/src/text.ts +122 -12
- package/src/utf8.ts +35 -17
package/dist-es/psdReader.js
CHANGED
|
@@ -125,22 +125,24 @@ function readFixedPoint32(reader) {
|
|
|
125
125
|
function readFixedPointPath32(reader) {
|
|
126
126
|
return readInt32(reader) / (1 << 24);
|
|
127
127
|
}
|
|
128
|
+
// NOTE: returned array may alias the reader's underlying buffer, never write into it
|
|
128
129
|
function readBytes(reader, length) {
|
|
129
|
-
const start = reader.
|
|
130
|
+
const start = reader.offset;
|
|
131
|
+
const viewLength = reader.view.byteLength;
|
|
130
132
|
reader.offset += length;
|
|
131
|
-
if ((start + length) >
|
|
133
|
+
if ((start + length) > viewLength) {
|
|
132
134
|
// fix for broken PSD files that are missing part of file at the end
|
|
133
135
|
warnOrThrow(reader, 'Reading bytes exceeding buffer length');
|
|
134
136
|
if (length > (100 * 1024 * 1024))
|
|
135
137
|
throw new Error('Reading past end of file'); // limit to 100MB
|
|
136
138
|
const result = new Uint8Array(length);
|
|
137
|
-
const len = Math.min(length,
|
|
139
|
+
const len = Math.min(length, viewLength - start);
|
|
138
140
|
if (len > 0)
|
|
139
|
-
result.set(new Uint8Array(reader.view.buffer, start, len));
|
|
141
|
+
result.set(new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, len));
|
|
140
142
|
return result;
|
|
141
143
|
}
|
|
142
144
|
else {
|
|
143
|
-
return new Uint8Array(reader.view.buffer, start, length);
|
|
145
|
+
return new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, length);
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
function readSignature(reader) {
|
|
@@ -165,31 +167,52 @@ function readUnicodeString(reader) {
|
|
|
165
167
|
const length = readUint32(reader);
|
|
166
168
|
return readUnicodeStringWithLength(reader, length);
|
|
167
169
|
}
|
|
168
|
-
|
|
170
|
+
const STRING_CHUNK_SIZE = 0x2000;
|
|
171
|
+
function checkReadBounds(reader, size) {
|
|
172
|
+
if (reader.offset < 0 || (reader.offset + size) > reader.view.byteLength) {
|
|
173
|
+
throw new RangeError('Offset is outside the bounds of the DataView');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function readUtf16String(reader, length, littleEndian) {
|
|
177
|
+
if (!(length > 0))
|
|
178
|
+
return '';
|
|
179
|
+
checkReadBounds(reader, length * 2);
|
|
180
|
+
const view = reader.view;
|
|
181
|
+
const codes = new Uint16Array(Math.min(length, STRING_CHUNK_SIZE));
|
|
182
|
+
let offset = reader.offset;
|
|
169
183
|
let text = '';
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
for (let i = 0; i < length; i += STRING_CHUNK_SIZE) {
|
|
185
|
+
const count = Math.min(STRING_CHUNK_SIZE, length - i);
|
|
186
|
+
for (let j = 0; j < count; j++, offset += 2) {
|
|
187
|
+
codes[j] = view.getUint16(offset, littleEndian);
|
|
174
188
|
}
|
|
189
|
+
text += String.fromCharCode.apply(null, (count === codes.length ? codes : codes.subarray(0, count)));
|
|
175
190
|
}
|
|
191
|
+
reader.offset = offset;
|
|
192
|
+
// remove trailing \0
|
|
193
|
+
if (text.charCodeAt(text.length - 1) === 0)
|
|
194
|
+
text = text.substring(0, text.length - 1);
|
|
176
195
|
return text;
|
|
177
196
|
}
|
|
178
|
-
function
|
|
197
|
+
function bytesToString(bytes) {
|
|
179
198
|
let text = '';
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (value || length > 0) { // remove trailing \0
|
|
183
|
-
text += String.fromCharCode(value);
|
|
184
|
-
}
|
|
199
|
+
for (let i = 0; i < bytes.length; i += STRING_CHUNK_SIZE) {
|
|
200
|
+
text += String.fromCharCode.apply(null, bytes.subarray(i, i + STRING_CHUNK_SIZE));
|
|
185
201
|
}
|
|
186
202
|
return text;
|
|
187
203
|
}
|
|
204
|
+
function readUnicodeStringWithLength(reader, length) {
|
|
205
|
+
return readUtf16String(reader, length, false);
|
|
206
|
+
}
|
|
207
|
+
function readUnicodeStringWithLengthLE(reader, length) {
|
|
208
|
+
return readUtf16String(reader, length, true);
|
|
209
|
+
}
|
|
188
210
|
function readAsciiString(reader, length) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
211
|
+
if (!(length > 0))
|
|
212
|
+
return '';
|
|
213
|
+
checkReadBounds(reader, length);
|
|
214
|
+
const text = bytesToString(new Uint8Array(reader.view.buffer, reader.view.byteOffset + reader.offset, length));
|
|
215
|
+
reader.offset += length;
|
|
193
216
|
return text;
|
|
194
217
|
}
|
|
195
218
|
function skipBytes(reader, count) {
|
|
@@ -203,12 +226,7 @@ function checkSignature(reader, a, b) {
|
|
|
203
226
|
}
|
|
204
227
|
}
|
|
205
228
|
function readShortString(reader, length) {
|
|
206
|
-
|
|
207
|
-
let result = '';
|
|
208
|
-
for (let i = 0; i < buffer.length; i++) {
|
|
209
|
-
result += String.fromCharCode(buffer[i]);
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
229
|
+
return bytesToString(readBytes(reader, length));
|
|
212
230
|
}
|
|
213
231
|
function isValidSignature(sig) {
|
|
214
232
|
return sig === '8BIM' || sig === 'MeSa' || sig === 'AgHg' || sig === 'PHUT' || sig === 'DCSR';
|
|
@@ -229,7 +247,7 @@ function readPsd(reader, readOptions = {}) {
|
|
|
229
247
|
const maxSize = version === 1 ? 30000 : 300000;
|
|
230
248
|
if (width > maxSize || height > maxSize)
|
|
231
249
|
throw new Error(`Invalid size: ${width}x${height}`);
|
|
232
|
-
if (channels >
|
|
250
|
+
if (channels < 1 || channels > 56)
|
|
233
251
|
throw new Error(`Invalid channel count: ${channels}`);
|
|
234
252
|
if (![1, 8, 16, 32].includes(bitsPerChannel))
|
|
235
253
|
throw new Error(`Invalid bitsPerChannel: ${bitsPerChannel}`);
|
|
@@ -331,7 +349,10 @@ function readPsd(reader, readOptions = {}) {
|
|
|
331
349
|
const skipComposite = reader.skipCompositeImageData && (reader.skipLayerImageData || hasChildren);
|
|
332
350
|
if (!skipComposite) {
|
|
333
351
|
if (reader.useRawData) {
|
|
334
|
-
|
|
352
|
+
const rawOffset = Math.min(reader.offset, reader.view.byteLength);
|
|
353
|
+
const rawCompositeData = new Uint8Array(reader.view.buffer, reader.view.byteOffset + rawOffset, reader.view.byteLength - rawOffset);
|
|
354
|
+
psd.rawCompositeData = rawCompositeData;
|
|
355
|
+
psd.rawCompositeDataInfo = { large: reader.large, globalAlpha: reader.globalAlpha };
|
|
335
356
|
}
|
|
336
357
|
else {
|
|
337
358
|
const imageData = readImageData(reader, psd);
|
|
@@ -386,7 +407,9 @@ function readLayerInfo(reader, psd, imageResources) {
|
|
|
386
407
|
stack.push(l);
|
|
387
408
|
}
|
|
388
409
|
else if (type === 3 /* SectionDividerType.BoundingSectionDivider */) {
|
|
389
|
-
|
|
410
|
+
// ignore unmatched section dividers, never pop the root
|
|
411
|
+
if (stack.length > 1)
|
|
412
|
+
stack.pop();
|
|
390
413
|
// this was workaround because I didn't know what `lsdk` section was, now it's probably not needed anymore
|
|
391
414
|
// } else if (l.name === '</Layer group>' && !l.sectionDivider && !l.top && !l.left && !l.bottom && !l.right) {
|
|
392
415
|
// // sometimes layer group terminator doesn't have sectionDivider, so we just guess here (PS bug ?)
|
|
@@ -472,7 +495,7 @@ function readLayerMaskData(reader, layer) {
|
|
|
472
495
|
mask.positionRelativeToLayer = (flags & 1 /* LayerMaskFlags.PositionRelativeToLayer */) !== 0;
|
|
473
496
|
mask.disabled = (flags & 2 /* LayerMaskFlags.LayerMaskDisabled */) !== 0;
|
|
474
497
|
mask.fromVectorData = (flags & 8 /* LayerMaskFlags.LayerMaskFromRenderingOtherData */) !== 0;
|
|
475
|
-
if (
|
|
498
|
+
if (hasRealMaskData(reader, flags, left())) {
|
|
476
499
|
const realMask = {};
|
|
477
500
|
layer.realMask = realMask;
|
|
478
501
|
const realFlags = readUint8(reader);
|
|
@@ -501,6 +524,43 @@ function readLayerMaskData(reader, layer) {
|
|
|
501
524
|
skipBytes(reader, left());
|
|
502
525
|
});
|
|
503
526
|
}
|
|
527
|
+
function maskParamsSize(params) {
|
|
528
|
+
return 1 +
|
|
529
|
+
((params & 1 /* MaskParams.UserMaskDensity */) ? 1 : 0) +
|
|
530
|
+
((params & 2 /* MaskParams.UserMaskFeather */) ? 8 : 0) +
|
|
531
|
+
((params & 4 /* MaskParams.VectorMaskDensity */) ? 1 : 0) +
|
|
532
|
+
((params & 8 /* MaskParams.VectorMaskFeather */) ? 8 : 0);
|
|
533
|
+
}
|
|
534
|
+
// checks if data at offset is mask parameters followed by up to 3 bytes of zero padding, ending exactly at offset + left
|
|
535
|
+
function isMaskParamsLayout(view, offset, left) {
|
|
536
|
+
if (left < 1)
|
|
537
|
+
return false;
|
|
538
|
+
const params = view.getUint8(offset);
|
|
539
|
+
if (params === 0 || (params & ~0x0f))
|
|
540
|
+
return false; // only 4 parameter flags exist
|
|
541
|
+
const size = maskParamsSize(params);
|
|
542
|
+
if (left < size || left - size > 3)
|
|
543
|
+
return false;
|
|
544
|
+
for (let i = size; i < left; i++) {
|
|
545
|
+
if (view.getUint8(offset + i) !== 0)
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
// real mask data (18 bytes) is followed by mask parameters (if flag is set) and padding
|
|
551
|
+
function hasRealMaskData(reader, flags, left) {
|
|
552
|
+
if (left < 18)
|
|
553
|
+
return false;
|
|
554
|
+
if (!(flags & 16 /* LayerMaskFlags.MaskHasParametersAppliedToIt */))
|
|
555
|
+
return true;
|
|
556
|
+
const { view, offset } = reader;
|
|
557
|
+
if (isMaskParamsLayout(view, offset, left))
|
|
558
|
+
return false;
|
|
559
|
+
if (isMaskParamsLayout(view, offset + 18, left - 18))
|
|
560
|
+
return true;
|
|
561
|
+
// unknown layout, assume real mask if there's enough data for it (and mask parameters)
|
|
562
|
+
return left === 18 || left - 18 >= maskParamsSize(view.getUint8(offset + 18));
|
|
563
|
+
}
|
|
504
564
|
function readBlendingRange(reader) {
|
|
505
565
|
return [readUint8(reader), readUint8(reader), readUint8(reader), readUint8(reader)];
|
|
506
566
|
}
|
|
@@ -567,8 +627,12 @@ function getCompositeImageData(psd) {
|
|
|
567
627
|
if (!data)
|
|
568
628
|
return undefined;
|
|
569
629
|
const reader = createReader(data.buffer, data.byteOffset, data.byteLength);
|
|
570
|
-
const
|
|
571
|
-
|
|
630
|
+
const info = psd.rawCompositeDataInfo;
|
|
631
|
+
if (info) {
|
|
632
|
+
reader.large = info.large;
|
|
633
|
+
reader.globalAlpha = info.globalAlpha;
|
|
634
|
+
}
|
|
635
|
+
return readImageData(reader, psd);
|
|
572
636
|
}
|
|
573
637
|
function getCompositeCanvas(psd) {
|
|
574
638
|
return imageDataToCanvasSafe(getCompositeImageData(psd));
|
|
@@ -610,18 +674,18 @@ function decodeLayerPixels(layer, useImageData) {
|
|
|
610
674
|
function decodeLayerImageData(layer, options) {
|
|
611
675
|
var _a, _b, _c;
|
|
612
676
|
let { throwForMissingFeatures, useImageData } = options;
|
|
613
|
-
const imageData = getDataFromLayer(layer, LayerDataType.Layer, throwForMissingFeatures, options.totalMemoryLimit);
|
|
677
|
+
const imageData = getDataFromLayer(layer, LayerDataType.Layer, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
614
678
|
setImageDataOrCanvas(layer, imageData, useImageData);
|
|
615
679
|
if (options.totalMemoryLimit !== undefined)
|
|
616
680
|
options.totalMemoryLimit -= (_a = imageData === null || imageData === void 0 ? void 0 : imageData.data.byteLength) !== null && _a !== void 0 ? _a : 0;
|
|
617
681
|
if (layer.mask) {
|
|
618
|
-
const maskData = getDataFromLayer(layer, LayerDataType.Mask, throwForMissingFeatures, options.totalMemoryLimit);
|
|
682
|
+
const maskData = getDataFromLayer(layer, LayerDataType.Mask, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
619
683
|
setImageDataOrCanvas(layer.mask, maskData, useImageData);
|
|
620
684
|
if (options.totalMemoryLimit !== undefined)
|
|
621
685
|
options.totalMemoryLimit -= (_b = maskData === null || maskData === void 0 ? void 0 : maskData.data.byteLength) !== null && _b !== void 0 ? _b : 0;
|
|
622
686
|
}
|
|
623
687
|
if (layer.realMask) {
|
|
624
|
-
const maskData = getDataFromLayer(layer, LayerDataType.RealMask, throwForMissingFeatures, options.totalMemoryLimit);
|
|
688
|
+
const maskData = getDataFromLayer(layer, LayerDataType.RealMask, throwForMissingFeatures, options.totalMemoryLimit, options);
|
|
625
689
|
setImageDataOrCanvas(layer.realMask, maskData, useImageData);
|
|
626
690
|
if (options.totalMemoryLimit !== undefined)
|
|
627
691
|
options.totalMemoryLimit -= (_c = maskData === null || maskData === void 0 ? void 0 : maskData.data.byteLength) !== null && _c !== void 0 ? _c : 0;
|
|
@@ -634,7 +698,8 @@ var LayerDataType;
|
|
|
634
698
|
LayerDataType[LayerDataType["Mask"] = 1] = "Mask";
|
|
635
699
|
LayerDataType[LayerDataType["RealMask"] = 2] = "RealMask";
|
|
636
700
|
})(LayerDataType || (LayerDataType = {}));
|
|
637
|
-
function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
701
|
+
function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit, logOptions) {
|
|
702
|
+
var _a;
|
|
638
703
|
if (!layer.rawData)
|
|
639
704
|
return undefined;
|
|
640
705
|
const { colorMode, bitsPerChannel, channels, large } = layer.rawData;
|
|
@@ -647,7 +712,7 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
647
712
|
if (layerWidth && layerHeight && read === LayerDataType.Layer) {
|
|
648
713
|
if (cmyk) {
|
|
649
714
|
if (bitsPerChannel !== 8)
|
|
650
|
-
throw new Error('bitsPerChannel
|
|
715
|
+
throw new Error('bitsPerChannel not supported');
|
|
651
716
|
imageData = { width: layerWidth, height: layerHeight, data: new Uint8ClampedArray(layerWidth * layerHeight * 5) };
|
|
652
717
|
}
|
|
653
718
|
else {
|
|
@@ -662,6 +727,11 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
662
727
|
if (!data)
|
|
663
728
|
continue;
|
|
664
729
|
const dataReader = createReader(data.buffer, data.byteOffset, data.byteLength);
|
|
730
|
+
dataReader.debug = !!(logOptions === null || logOptions === void 0 ? void 0 : logOptions.debug);
|
|
731
|
+
if (logOptions === null || logOptions === void 0 ? void 0 : logOptions.log)
|
|
732
|
+
dataReader.log = logOptions.log;
|
|
733
|
+
if (memoryLimit !== undefined)
|
|
734
|
+
dataReader.totalMemoryLimit = Math.max(0, memoryLimit - ((_a = imageData === null || imageData === void 0 ? void 0 : imageData.data.byteLength) !== null && _a !== void 0 ? _a : 0));
|
|
665
735
|
if (id === -2 /* ChannelID.UserMask */ || id === -3 /* ChannelID.RealUserMask */) {
|
|
666
736
|
if (id === -2 /* ChannelID.UserMask */ && read !== LayerDataType.Mask)
|
|
667
737
|
continue;
|
|
@@ -674,6 +744,8 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
674
744
|
const maskHeight = Math.max(0, (mask.bottom || 0) - (mask.top || 0));
|
|
675
745
|
if (maskWidth && maskHeight) {
|
|
676
746
|
maskData = createImageDataBitDepth(maskWidth, maskHeight, bitsPerChannel, 4, memoryLimit);
|
|
747
|
+
if (memoryLimit !== undefined)
|
|
748
|
+
dataReader.totalMemoryLimit = Math.max(0, dataReader.totalMemoryLimit - maskData.data.byteLength);
|
|
677
749
|
readData(dataReader, data.byteLength, maskData, compression, maskWidth, maskHeight, bitsPerChannel, 0, large, 4);
|
|
678
750
|
if (helpers_1.RAW_IMAGE_DATA) { // TODO: use layer.rawData instead
|
|
679
751
|
if (id === -2 /* ChannelID.UserMask */) {
|
|
@@ -705,15 +777,14 @@ function getDataFromLayer(layer, read, throwForMissingFeatures, memoryLimit) {
|
|
|
705
777
|
layer.imageDataRawCompression[id] = compression;
|
|
706
778
|
layer.imageDataRaw[id] = data;
|
|
707
779
|
}
|
|
708
|
-
if (targetData && colorMode === 1 /* ColorMode.Grayscale */) {
|
|
709
|
-
setupGrayscale(targetData);
|
|
710
|
-
}
|
|
711
780
|
}
|
|
712
781
|
if (id === -1 /* ChannelID.Transparency */) {
|
|
713
782
|
initializedAlpha = true;
|
|
714
783
|
}
|
|
715
784
|
}
|
|
716
785
|
if (imageData) {
|
|
786
|
+
if (colorMode === 1 /* ColorMode.Grayscale */)
|
|
787
|
+
setupGrayscale(imageData);
|
|
717
788
|
if (!initializedAlpha)
|
|
718
789
|
resetAlpha(imageData, cmyk);
|
|
719
790
|
if (cmyk) {
|
|
@@ -729,7 +800,7 @@ function readData(reader, length, pixels, compression, width, height, bitDepth,
|
|
|
729
800
|
return;
|
|
730
801
|
if (compression === 0 /* Compression.RawData */) {
|
|
731
802
|
if (length !== (width * height * Math.floor(bitDepth / 8))) {
|
|
732
|
-
reader
|
|
803
|
+
warnOrThrow(reader, `Invalid length (${length}, ${width * height * Math.floor(bitDepth / 8)})`);
|
|
733
804
|
}
|
|
734
805
|
const data = readBytes(reader, length);
|
|
735
806
|
readDataRaw(data, pixels, bitDepth, step, offset);
|
|
@@ -740,11 +811,11 @@ function readData(reader, length, pixels, compression, width, height, bitDepth,
|
|
|
740
811
|
}
|
|
741
812
|
else if (compression === 2 /* Compression.ZipWithoutPrediction */) {
|
|
742
813
|
const data = readBytes(reader, length);
|
|
743
|
-
readDataZip(data, pixels, width, height, bitDepth, step, offset, false);
|
|
814
|
+
readDataZip(data, pixels, width, height, bitDepth, step, offset, false, reader);
|
|
744
815
|
}
|
|
745
816
|
else if (compression === 3 /* Compression.ZipWithPrediction */) {
|
|
746
817
|
const data = readBytes(reader, length);
|
|
747
|
-
readDataZip(data, pixels, width, height, bitDepth, step, offset, true);
|
|
818
|
+
readDataZip(data, pixels, width, height, bitDepth, step, offset, true, reader);
|
|
748
819
|
}
|
|
749
820
|
else {
|
|
750
821
|
throw new Error(`Invalid Compression type: ${compression}`);
|
|
@@ -759,7 +830,7 @@ function readGlobalLayerMaskInfo(reader) {
|
|
|
759
830
|
const colorSpace2 = readUint16(reader);
|
|
760
831
|
const colorSpace3 = readUint16(reader);
|
|
761
832
|
const colorSpace4 = readUint16(reader);
|
|
762
|
-
const opacity = readUint16(reader) /
|
|
833
|
+
const opacity = readUint16(reader) / 100; // 0 - 100
|
|
763
834
|
const kind = readUint8(reader);
|
|
764
835
|
skipBytes(reader, left()); // 3 bytes of padding ?
|
|
765
836
|
return { overlayColorSpace, colorSpace1, colorSpace2, colorSpace3, colorSpace4, opacity, kind };
|
|
@@ -839,11 +910,12 @@ function readImageData(reader, psd) {
|
|
|
839
910
|
var _a;
|
|
840
911
|
const compression = readUint16(reader);
|
|
841
912
|
const bitsPerChannel = (_a = psd.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
913
|
+
const { width, height } = psd;
|
|
842
914
|
if (exports.supportedColorModes.indexOf(psd.colorMode) === -1)
|
|
843
915
|
throw new Error(`Color mode not supported: ${psd.colorMode}`);
|
|
844
916
|
if (compression !== 0 /* Compression.RawData */ && compression !== 1 /* Compression.RleCompressed */)
|
|
845
917
|
throw new Error(`Compression type not supported: ${compression}`);
|
|
846
|
-
const imageData = createImageDataBitDepth(
|
|
918
|
+
const imageData = createImageDataBitDepth(width, height, bitsPerChannel, 4, reader.totalMemoryLimit);
|
|
847
919
|
if (reader.totalMemoryLimit !== undefined)
|
|
848
920
|
reader.totalMemoryLimit -= imageData.data.byteLength;
|
|
849
921
|
(0, helpers_1.resetImageData)(imageData);
|
|
@@ -851,46 +923,26 @@ function readImageData(reader, psd) {
|
|
|
851
923
|
case 0 /* ColorMode.Bitmap */: {
|
|
852
924
|
if (bitsPerChannel !== 1)
|
|
853
925
|
throw new Error('Invalid bitsPerChannel for bitmap color mode');
|
|
926
|
+
const rowBytes = Math.ceil(width / 8);
|
|
854
927
|
let bytes;
|
|
855
928
|
if (compression === 0 /* Compression.RawData */) {
|
|
856
|
-
bytes = readBytes(reader,
|
|
857
|
-
}
|
|
858
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
859
|
-
bytes = new Uint8Array(psd.width * psd.height);
|
|
860
|
-
readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, 8, 1, [0], reader.large);
|
|
929
|
+
bytes = readBytes(reader, rowBytes * height);
|
|
861
930
|
}
|
|
862
931
|
else {
|
|
863
|
-
|
|
932
|
+
bytes = new Uint8Array(rowBytes * height);
|
|
933
|
+
readDataRLE(reader, { data: bytes, width: rowBytes, height }, rowBytes, height, 8, 1, [0], reader.large);
|
|
864
934
|
}
|
|
865
|
-
(0, helpers_1.decodeBitmap)(bytes, imageData.data,
|
|
935
|
+
(0, helpers_1.decodeBitmap)(bytes, imageData.data, width, height);
|
|
866
936
|
break;
|
|
867
937
|
}
|
|
868
938
|
case 3 /* ColorMode.RGB */:
|
|
869
939
|
case 1 /* ColorMode.Grayscale */: {
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
else if (reader.globalAlpha) {
|
|
878
|
-
channels.push(3);
|
|
879
|
-
}
|
|
880
|
-
if (compression === 0 /* Compression.RawData */) {
|
|
881
|
-
for (let i = 0; i < channels.length; i++) {
|
|
882
|
-
const data = readBytes(reader, psd.width * psd.height * Math.floor(bitsPerChannel / 8));
|
|
883
|
-
readDataRaw(data, imageData, bitsPerChannel, 4, channels[i]);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
887
|
-
const start = reader.offset;
|
|
888
|
-
readDataRLE(reader, imageData, psd.width, psd.height, bitsPerChannel, 4, channels, reader.large);
|
|
889
|
-
if (helpers_1.RAW_IMAGE_DATA)
|
|
890
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
891
|
-
}
|
|
892
|
-
else {
|
|
893
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
940
|
+
const colorChannels = psd.colorMode === 1 /* ColorMode.Grayscale */ ? 1 : 3;
|
|
941
|
+
const offsets = compositeChannelOffsets(reader, psd, colorChannels, 3);
|
|
942
|
+
const start = reader.offset;
|
|
943
|
+
readCompositeChannels(reader, compression, imageData, bitsPerChannel, 4, offsets);
|
|
944
|
+
if (helpers_1.RAW_IMAGE_DATA && compression === 1 /* Compression.RleCompressed */) {
|
|
945
|
+
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
894
946
|
}
|
|
895
947
|
if (psd.colorMode === 1 /* ColorMode.Grayscale */) {
|
|
896
948
|
setupGrayscale(imageData);
|
|
@@ -899,57 +951,25 @@ function readImageData(reader, psd) {
|
|
|
899
951
|
}
|
|
900
952
|
case 2 /* ColorMode.Indexed */: {
|
|
901
953
|
if (bitsPerChannel !== 8)
|
|
902
|
-
throw new Error('bitsPerChannel
|
|
903
|
-
if (psd.channels !== 1)
|
|
904
|
-
throw new Error('Invalid channel count');
|
|
954
|
+
throw new Error('bitsPerChannel not supported');
|
|
905
955
|
if (!psd.palette)
|
|
906
956
|
throw new Error('Missing color palette');
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
const indexedImageData = {
|
|
912
|
-
width: imageData.width,
|
|
913
|
-
height: imageData.height,
|
|
914
|
-
data: new Uint8Array(imageData.width * imageData.height),
|
|
915
|
-
};
|
|
916
|
-
readDataRLE(reader, indexedImageData, psd.width, psd.height, bitsPerChannel, 1, [0], reader.large);
|
|
917
|
-
indexedToRgb(indexedImageData, imageData, psd.palette);
|
|
918
|
-
}
|
|
919
|
-
else {
|
|
920
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
921
|
-
}
|
|
957
|
+
const offsets = compositeChannelOffsets(reader, psd, 1, -1);
|
|
958
|
+
const indexedImageData = { width, height, data: new Uint8Array(width * height) };
|
|
959
|
+
readCompositeChannels(reader, compression, indexedImageData, 8, 1, offsets);
|
|
960
|
+
indexedToRgb(indexedImageData, imageData, psd.palette);
|
|
922
961
|
break;
|
|
923
962
|
}
|
|
924
963
|
case 4 /* ColorMode.CMYK */: {
|
|
925
964
|
if (bitsPerChannel !== 8)
|
|
926
|
-
throw new Error('bitsPerChannel
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
if (compression ===
|
|
933
|
-
|
|
934
|
-
// TODO: ...
|
|
935
|
-
// for (let i = 0; i < channels.length; i++) {
|
|
936
|
-
// readDataRaw(reader, imageData, channels[i], psd.width, psd.height);
|
|
937
|
-
// }
|
|
938
|
-
}
|
|
939
|
-
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
940
|
-
const cmykImageData = {
|
|
941
|
-
width: imageData.width,
|
|
942
|
-
height: imageData.height,
|
|
943
|
-
data: new Uint8Array(imageData.width * imageData.height * 5),
|
|
944
|
-
};
|
|
945
|
-
const start = reader.offset;
|
|
946
|
-
readDataRLE(reader, cmykImageData, psd.width, psd.height, bitsPerChannel, 5, channels, reader.large);
|
|
947
|
-
cmykToRgb(cmykImageData, imageData, true);
|
|
948
|
-
if (helpers_1.RAW_IMAGE_DATA)
|
|
949
|
-
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
950
|
-
}
|
|
951
|
-
else {
|
|
952
|
-
throw new Error(`Compression not supported: ${compression}`);
|
|
965
|
+
throw new Error('bitsPerChannel not supported');
|
|
966
|
+
const offsets = compositeChannelOffsets(reader, psd, 4, 4);
|
|
967
|
+
const cmykImageData = { width, height, data: new Uint8Array(width * height * 5) };
|
|
968
|
+
const start = reader.offset;
|
|
969
|
+
readCompositeChannels(reader, compression, cmykImageData, 8, 5, offsets);
|
|
970
|
+
cmykToRgb(cmykImageData, imageData, true);
|
|
971
|
+
if (helpers_1.RAW_IMAGE_DATA && compression === 1 /* Compression.RleCompressed */) {
|
|
972
|
+
psd.imageDataRaw = new Uint8Array(reader.view.buffer, reader.view.byteOffset + start, reader.offset - start);
|
|
953
973
|
}
|
|
954
974
|
break;
|
|
955
975
|
}
|
|
@@ -957,23 +977,98 @@ function readImageData(reader, psd) {
|
|
|
957
977
|
}
|
|
958
978
|
// remove weird white matte
|
|
959
979
|
if (reader.globalAlpha) {
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
980
|
+
removeWhiteMatte(imageData);
|
|
981
|
+
}
|
|
982
|
+
return imageData;
|
|
983
|
+
}
|
|
984
|
+
// returns target offset for each of the composite image channels stored in the file, -1 for channels that are skipped
|
|
985
|
+
function compositeChannelOffsets(reader, psd, colorChannels, alphaOffset) {
|
|
986
|
+
var _a, _b, _c, _d;
|
|
987
|
+
const channelCount = (_a = psd.channels) !== null && _a !== void 0 ? _a : (colorChannels + (reader.globalAlpha ? 1 : 0));
|
|
988
|
+
if (channelCount < colorChannels)
|
|
989
|
+
throw new Error(`Invalid channel count: ${channelCount}`);
|
|
990
|
+
// First extra channel is transparency if document has global alpha (negative layer count). Some non-Photoshop
|
|
991
|
+
// applications write transparency channel without setting global alpha, in that case extra channel is not
|
|
992
|
+
// listed in alpha channel names (Photoshop names all user alpha channels / saved selections).
|
|
993
|
+
const namedChannels = (_d = (_c = (_b = psd.imageResources) === null || _b === void 0 ? void 0 : _b.alphaChannelNames) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
994
|
+
const hasTransparency = reader.globalAlpha || (channelCount - colorChannels) > namedChannels;
|
|
995
|
+
const offsets = [];
|
|
996
|
+
for (let i = 0; i < channelCount; i++) {
|
|
997
|
+
if (i < colorChannels) {
|
|
998
|
+
offsets.push(i);
|
|
999
|
+
}
|
|
1000
|
+
else if (i === colorChannels && hasTransparency && alphaOffset >= 0) {
|
|
1001
|
+
offsets.push(alphaOffset);
|
|
1002
|
+
}
|
|
1003
|
+
else {
|
|
1004
|
+
// TODO: store these channels (alpha channels / saved selections, spot colors) in additional image data
|
|
1005
|
+
offsets.push(-1);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
return offsets;
|
|
1009
|
+
}
|
|
1010
|
+
function readCompositeChannels(reader, compression, pixelData, bitsPerChannel, step, offsets) {
|
|
1011
|
+
if (compression === 0 /* Compression.RawData */) {
|
|
1012
|
+
const channelSize = pixelData.width * pixelData.height * bytesPerValue(bitsPerChannel);
|
|
1013
|
+
for (const offset of offsets) {
|
|
1014
|
+
if (offset < 0) {
|
|
1015
|
+
skipBytes(reader, channelSize);
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
readDataRaw(readBytes(reader, channelSize), pixelData, bitsPerChannel, step, offset);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
else if (compression === 1 /* Compression.RleCompressed */) {
|
|
1023
|
+
readDataRLE(reader, pixelData, pixelData.width, pixelData.height, bitsPerChannel, step, offsets, reader.large);
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
throw new Error(`Compression not supported: ${compression}`);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
// un-premultiplies colors from white matte, used for composite image of documents with global alpha
|
|
1030
|
+
function removeWhiteMatte({ data, width, height }) {
|
|
1031
|
+
const size = width * height * 4;
|
|
1032
|
+
if (data instanceof Float32Array) {
|
|
1033
|
+
for (let i = 0; i < size; i += 4) {
|
|
1034
|
+
const a = data[i + 3];
|
|
1035
|
+
if (a > 0 && a < 1) {
|
|
1036
|
+
const ra = 1 / a;
|
|
1037
|
+
const invA = 1 - ra;
|
|
1038
|
+
for (let j = 0; j < 3; j++) {
|
|
1039
|
+
const v = data[i + j] * ra + invA;
|
|
1040
|
+
data[i + j] = v < 0 ? 0 : v;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
else if (data instanceof Uint16Array) {
|
|
964
1046
|
for (let i = 0; i < size; i += 4) {
|
|
965
|
-
const pa =
|
|
1047
|
+
const pa = data[i + 3];
|
|
1048
|
+
if (pa !== 0 && pa !== 0xffff) {
|
|
1049
|
+
const ra = 0xffff / pa;
|
|
1050
|
+
const invA = 0xffff * (1 - ra);
|
|
1051
|
+
for (let j = 0; j < 3; j++) {
|
|
1052
|
+
const v = Math.round(data[i + j] * ra + invA);
|
|
1053
|
+
data[i + j] = v < 0 ? 0 : (v > 0xffff ? 0xffff : v);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
// Uint8ClampedArray clamps and rounds values on assignment
|
|
1060
|
+
for (let i = 0; i < size; i += 4) {
|
|
1061
|
+
const pa = data[i + 3];
|
|
966
1062
|
if (pa != 0 && pa != 255) {
|
|
967
1063
|
const a = pa / 255;
|
|
968
1064
|
const ra = 1 / a;
|
|
969
1065
|
const invA = 255 * (1 - ra);
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1066
|
+
data[i + 0] = data[i + 0] * ra + invA;
|
|
1067
|
+
data[i + 1] = data[i + 1] * ra + invA;
|
|
1068
|
+
data[i + 2] = data[i + 2] * ra + invA;
|
|
973
1069
|
}
|
|
974
1070
|
}
|
|
975
1071
|
}
|
|
976
|
-
return imageData;
|
|
977
1072
|
}
|
|
978
1073
|
function cmykToRgb(cmyk, rgb, reverseAlpha) {
|
|
979
1074
|
const size = rgb.width * rgb.height * 4;
|
|
@@ -1012,175 +1107,267 @@ function indexedToRgb(indexed, rgb, palette) {
|
|
|
1012
1107
|
dstData[dst + 3] = 255;
|
|
1013
1108
|
}
|
|
1014
1109
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1110
|
+
// number of bytes used to store single channel value, 1-bit data is handled as bytes
|
|
1111
|
+
function bytesPerValue(bitDepth) {
|
|
1112
|
+
switch (bitDepth) {
|
|
1113
|
+
case 1:
|
|
1114
|
+
case 8: return 1;
|
|
1115
|
+
case 16: return 2;
|
|
1116
|
+
case 32: return 4;
|
|
1117
|
+
default: throw new Error(`Invalid bitDepth (${bitDepth})`);
|
|
1018
1118
|
}
|
|
1019
1119
|
}
|
|
1020
|
-
function
|
|
1021
|
-
if (
|
|
1022
|
-
|
|
1120
|
+
function verifyArrayType(data, bytesPerValue) {
|
|
1121
|
+
if (data.BYTES_PER_ELEMENT !== bytesPerValue) {
|
|
1122
|
+
throw new Error('Invalid array types');
|
|
1023
1123
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
|
|
1124
|
+
}
|
|
1125
|
+
// NOTE: `buffer` may alias input file data, it must not be modified here
|
|
1126
|
+
function readDataRaw(buffer, pixelData, bitDepth, step, offset) {
|
|
1127
|
+
const bpv = bytesPerValue(bitDepth);
|
|
1128
|
+
if (!pixelData || offset < 0 || offset >= step)
|
|
1129
|
+
return;
|
|
1130
|
+
const data = pixelData.data;
|
|
1131
|
+
verifyArrayType(data, bpv);
|
|
1132
|
+
const size = Math.min(pixelData.width * pixelData.height, Math.floor(buffer.byteLength / bpv)) | 0;
|
|
1133
|
+
if (bpv === 1) {
|
|
1134
|
+
for (let i = 0, p = offset | 0; i < size; i++, p = (p + step) | 0) {
|
|
1135
|
+
data[p] = buffer[i];
|
|
1039
1136
|
}
|
|
1040
1137
|
}
|
|
1041
|
-
else if (
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
new Uint8Array(result.buffer, result.byteOffset, result.byteLength).set(bytes);
|
|
1045
|
-
return result;
|
|
1046
|
-
}
|
|
1047
|
-
else {
|
|
1048
|
-
return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
|
|
1138
|
+
else if (bpv === 2) {
|
|
1139
|
+
for (let i = 0, j = 0, p = offset | 0; i < size; i++, j += 2, p = (p + step) | 0) {
|
|
1140
|
+
data[p] = (buffer[j] << 8) | buffer[j + 1];
|
|
1049
1141
|
}
|
|
1050
1142
|
}
|
|
1051
1143
|
else {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
function copyChannelToPixelData(pixelData, channel, offset, step) {
|
|
1056
|
-
verifyCompatible(pixelData.data, channel);
|
|
1057
|
-
const size = pixelData.width * pixelData.height;
|
|
1058
|
-
const data = pixelData.data;
|
|
1059
|
-
for (let i = 0, p = offset | 0; i < size; i++, p = (p + step) | 0) {
|
|
1060
|
-
data[p] = channel[i];
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
function readDataRaw(buffer, pixelData, bitDepth, step, offset) {
|
|
1064
|
-
if (bitDepth == 32) {
|
|
1065
|
-
for (let i = 0; i < buffer.byteLength; i += 4) {
|
|
1066
|
-
const a = buffer[i + 0];
|
|
1067
|
-
const b = buffer[i + 1];
|
|
1068
|
-
const c = buffer[i + 2];
|
|
1069
|
-
const d = buffer[i + 3];
|
|
1070
|
-
buffer[i + 0] = d;
|
|
1071
|
-
buffer[i + 1] = c;
|
|
1072
|
-
buffer[i + 2] = b;
|
|
1073
|
-
buffer[i + 3] = a;
|
|
1144
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
1145
|
+
for (let i = 0, j = 0, p = offset | 0; i < size; i++, j += 4, p = (p + step) | 0) {
|
|
1146
|
+
data[p] = view.getFloat32(j, false);
|
|
1074
1147
|
}
|
|
1075
1148
|
}
|
|
1076
|
-
const array = bytesToArray(buffer, bitDepth);
|
|
1077
|
-
if (pixelData && offset < step) {
|
|
1078
|
-
copyChannelToPixelData(pixelData, array, offset, step);
|
|
1079
|
-
}
|
|
1080
1149
|
}
|
|
1081
|
-
function decodePredicted(data, width, height
|
|
1150
|
+
function decodePredicted(data, width, height) {
|
|
1082
1151
|
for (let y = 0; y < height; y++) {
|
|
1083
1152
|
const offset = y * width;
|
|
1084
1153
|
for (let x = 1, o = offset + 1; x < width; x++, o++) {
|
|
1085
|
-
data[o] =
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1154
|
+
data[o] = data[o - 1] + data[o]; // Uint8Array wraps values on assignment
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
const zipOverflow = new Error('Decompressed data exceeds expected size');
|
|
1159
|
+
// inflates data, stopping when output exceeds expected size (protects against zip bombs)
|
|
1160
|
+
function inflateLimited(compressed, expectedSize, reader) {
|
|
1161
|
+
const output = new Uint8Array(expectedSize);
|
|
1162
|
+
let position = 0;
|
|
1163
|
+
let overflow = false;
|
|
1164
|
+
const inflator = new pako_1.Inflate({ chunkSize: Math.max(1024, Math.min(expectedSize, 0x10000)) });
|
|
1165
|
+
inflator.onData = (chunk) => {
|
|
1166
|
+
const data = chunk;
|
|
1167
|
+
const count = Math.min(data.length, expectedSize - position);
|
|
1168
|
+
if (count > 0)
|
|
1169
|
+
output.set(count === data.length ? data : data.subarray(0, count), position);
|
|
1170
|
+
position += count;
|
|
1171
|
+
if (count < data.length) {
|
|
1172
|
+
overflow = true;
|
|
1173
|
+
throw zipOverflow;
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
inflator.onEnd = (status) => {
|
|
1177
|
+
var _a;
|
|
1178
|
+
// default handler collects all the chunks into result, we only need the error status
|
|
1179
|
+
inflator.err = status;
|
|
1180
|
+
inflator.msg = ((_a = inflator.strm) === null || _a === void 0 ? void 0 : _a.msg) || '';
|
|
1181
|
+
};
|
|
1182
|
+
try {
|
|
1183
|
+
inflator.push(compressed, true);
|
|
1184
|
+
}
|
|
1185
|
+
catch (e) {
|
|
1186
|
+
if (e !== zipOverflow)
|
|
1187
|
+
throw e;
|
|
1188
|
+
}
|
|
1189
|
+
if (overflow) {
|
|
1190
|
+
if (reader)
|
|
1191
|
+
warnOrThrow(reader, zipOverflow.message);
|
|
1192
|
+
}
|
|
1193
|
+
else if (inflator.err) {
|
|
1194
|
+
throw new Error(`Invalid zip data: ${inflator.msg}`);
|
|
1195
|
+
}
|
|
1196
|
+
return output;
|
|
1197
|
+
}
|
|
1198
|
+
function readDataZip(compressed, pixelData, width, height, bitDepth, step, offset, prediction, reader) {
|
|
1199
|
+
const bpv = bytesPerValue(bitDepth);
|
|
1200
|
+
if (!pixelData || offset < 0 || offset >= step)
|
|
1201
|
+
return;
|
|
1202
|
+
const data = pixelData.data;
|
|
1203
|
+
verifyArrayType(data, bpv);
|
|
1204
|
+
const expectedSize = width * height * bpv;
|
|
1205
|
+
if (reader)
|
|
1206
|
+
consumeMemory(reader, expectedSize);
|
|
1207
|
+
try {
|
|
1208
|
+
const decompressed = inflateLimited(compressed, expectedSize, reader);
|
|
1209
|
+
if (bpv === 1) {
|
|
1210
|
+
for (let y = 0, i = 0; y < height; y++) {
|
|
1211
|
+
let prev = 0;
|
|
1212
|
+
for (let x = 0, p = offset + y * width * step; x < width; x++, i++, p += step) {
|
|
1213
|
+
let v = decompressed[i];
|
|
1214
|
+
if (prediction)
|
|
1215
|
+
v = prev = (prev + v) & 0xff;
|
|
1216
|
+
data[p] = v;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
else if (bpv === 2) {
|
|
1221
|
+
for (let y = 0, i = 0; y < height; y++) {
|
|
1222
|
+
let prev = 0;
|
|
1223
|
+
for (let x = 0, p = offset + y * width * step; x < width; x++, i += 2, p += step) {
|
|
1224
|
+
let v = (decompressed[i] << 8) | decompressed[i + 1];
|
|
1225
|
+
if (prediction)
|
|
1226
|
+
v = prev = (prev + v) & 0xffff;
|
|
1227
|
+
data[p] = v;
|
|
1115
1228
|
}
|
|
1116
1229
|
}
|
|
1117
1230
|
}
|
|
1118
1231
|
else {
|
|
1119
|
-
|
|
1232
|
+
const dst = new Uint32Array(data.buffer, data.byteOffset, data.length);
|
|
1233
|
+
if (prediction) {
|
|
1234
|
+
// bytes are delta encoded per row and stored in planar order (all 1st bytes, all 2nd bytes, ...)
|
|
1235
|
+
decodePredicted(decompressed, width * 4, height);
|
|
1236
|
+
for (let y = 0, di = offset; y < height; y++) {
|
|
1237
|
+
let a = width * 4 * y;
|
|
1238
|
+
for (let x = 0; x < width; x++, a++, di += step) {
|
|
1239
|
+
const b = a + width;
|
|
1240
|
+
const c = b + width;
|
|
1241
|
+
const d = c + width;
|
|
1242
|
+
dst[di] = ((decompressed[a] << 24) | (decompressed[b] << 16) | (decompressed[c] << 8) | decompressed[d]) >>> 0;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
else {
|
|
1247
|
+
const view = new DataView(decompressed.buffer, decompressed.byteOffset, decompressed.byteLength);
|
|
1248
|
+
for (let i = 0, j = 0, di = offset, size = width * height; i < size; i++, j += 4, di += step) {
|
|
1249
|
+
dst[di] = view.getUint32(j, false);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1120
1252
|
}
|
|
1121
1253
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1254
|
+
finally {
|
|
1255
|
+
if (reader)
|
|
1256
|
+
recoverMemory(reader, expectedSize);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
// decodes single PackBits row, returns number of decoded values
|
|
1260
|
+
function decodeRLERow(src, i, end, dst, p, step, count) {
|
|
1261
|
+
let x = 0;
|
|
1262
|
+
while (i < end && x < count) {
|
|
1263
|
+
const header = src[i++];
|
|
1264
|
+
if (header > 128) {
|
|
1265
|
+
if (i >= end)
|
|
1266
|
+
break;
|
|
1267
|
+
const value = src[i++];
|
|
1268
|
+
let n = 257 - header;
|
|
1269
|
+
if (n > count - x)
|
|
1270
|
+
n = count - x;
|
|
1271
|
+
x += n;
|
|
1272
|
+
for (; n > 0; n--, p += step) {
|
|
1273
|
+
dst[p] = value;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
else if (header < 128) {
|
|
1277
|
+
let n = header + 1;
|
|
1278
|
+
if (n > count - x)
|
|
1279
|
+
n = count - x;
|
|
1280
|
+
if (n > end - i)
|
|
1281
|
+
n = end - i;
|
|
1282
|
+
x += n;
|
|
1283
|
+
for (; n > 0; n--, p += step) {
|
|
1284
|
+
dst[p] = src[i++];
|
|
1132
1285
|
}
|
|
1133
1286
|
}
|
|
1287
|
+
else {
|
|
1288
|
+
// ignore 128
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
return x;
|
|
1292
|
+
}
|
|
1293
|
+
// converts big-endian 16/32-bit values from bytes and writes them to `data` starting at `p` with `step`
|
|
1294
|
+
function scatterValues(bytes, count, bpv, data, p, step) {
|
|
1295
|
+
if (bpv === 2) {
|
|
1296
|
+
for (let x = 0, i = 0; x < count; x++, i += 2, p += step) {
|
|
1297
|
+
data[p] = (bytes[i] << 8) | bytes[i + 1];
|
|
1298
|
+
}
|
|
1134
1299
|
}
|
|
1135
1300
|
else {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
for (let y = 0; y < height; y++, li++) {
|
|
1140
|
-
lengths[li] = readUint16(reader);
|
|
1141
|
-
}
|
|
1301
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1302
|
+
for (let x = 0, i = 0; x < count; x++, i += 4, p += step) {
|
|
1303
|
+
data[p] = view.getFloat32(i, false);
|
|
1142
1304
|
}
|
|
1143
1305
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1306
|
+
}
|
|
1307
|
+
// decodes RLE rows of single channel, each row starts at the beginning of the image row
|
|
1308
|
+
function decodeRLEChannel(src, lengths, li, pos, width, height, data, offset, step, bpv, row) {
|
|
1309
|
+
const srcEnd = src.length;
|
|
1310
|
+
const rowSize = width * bpv;
|
|
1311
|
+
for (let y = 0; y < height; y++, li++) {
|
|
1312
|
+
const rowStart = pos < srcEnd ? pos : srcEnd;
|
|
1313
|
+
pos += lengths[li];
|
|
1314
|
+
const rowEnd = pos < srcEnd ? pos : srcEnd;
|
|
1315
|
+
if (rowStart >= rowEnd)
|
|
1316
|
+
continue;
|
|
1317
|
+
if (bpv === 1) {
|
|
1318
|
+
decodeRLERow(src, rowStart, rowEnd, data, offset + y * width * step, step, width);
|
|
1153
1319
|
}
|
|
1154
1320
|
else {
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1321
|
+
const decoded = decodeRLERow(src, rowStart, rowEnd, row, 0, 1, rowSize);
|
|
1322
|
+
scatterValues(row, Math.floor(decoded / bpv), bpv, data, offset + y * width * step, step);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
function readDataRLE(reader, pixelData, width, height, bitDepth, step, offsets, large) {
|
|
1327
|
+
const data = pixelData && pixelData.data;
|
|
1328
|
+
const rows = offsets.length * height;
|
|
1329
|
+
const lengthSize = large ? 4 : 2;
|
|
1330
|
+
consumeMemory(reader, rows * lengthSize);
|
|
1331
|
+
try {
|
|
1332
|
+
if ((reader.offset + rows * lengthSize) > reader.view.byteLength) {
|
|
1333
|
+
throw new Error('RLE row lengths exceed buffer length');
|
|
1334
|
+
}
|
|
1335
|
+
const lengths = large ? new Uint32Array(rows) : new Uint16Array(rows);
|
|
1336
|
+
let total = 0;
|
|
1337
|
+
if (large) {
|
|
1338
|
+
for (let i = 0; i < rows; i++)
|
|
1339
|
+
total += (lengths[i] = readUint32(reader));
|
|
1340
|
+
}
|
|
1341
|
+
else {
|
|
1342
|
+
for (let i = 0; i < rows; i++)
|
|
1343
|
+
total += (lengths[i] = readUint16(reader));
|
|
1344
|
+
}
|
|
1345
|
+
const start = reader.offset;
|
|
1346
|
+
const srcEnd = reader.view.byteLength;
|
|
1347
|
+
if (total > (srcEnd - start)) {
|
|
1348
|
+
// broken or truncated file, decode only data that is available
|
|
1349
|
+
warnOrThrow(reader, 'RLE data exceeds buffer length');
|
|
1350
|
+
}
|
|
1351
|
+
const bpv = bytesPerValue(bitDepth);
|
|
1352
|
+
if (data)
|
|
1353
|
+
verifyArrayType(data, bpv);
|
|
1354
|
+
const src = new Uint8Array(reader.view.buffer, reader.view.byteOffset, srcEnd);
|
|
1355
|
+
const row = (data && bpv > 1) ? new Uint8Array(width * bpv) : undefined;
|
|
1356
|
+
let pos = start;
|
|
1357
|
+
for (let c = 0, li = 0; c < offsets.length; c++, li += height) {
|
|
1358
|
+
const offset = offsets[c] | 0;
|
|
1359
|
+
const channelStart = pos;
|
|
1360
|
+
for (let y = 0; y < height; y++)
|
|
1361
|
+
pos += lengths[li + y];
|
|
1362
|
+
if (data && offset >= 0 && offset < step) {
|
|
1363
|
+
decodeRLEChannel(src, lengths, li, channelStart, width, height, data, offset, step, bpv, row);
|
|
1180
1364
|
}
|
|
1181
1365
|
}
|
|
1366
|
+
reader.offset = pos;
|
|
1367
|
+
}
|
|
1368
|
+
finally {
|
|
1369
|
+
recoverMemory(reader, rows * lengthSize);
|
|
1182
1370
|
}
|
|
1183
|
-
recoverMemory(reader, lengths.byteLength);
|
|
1184
1371
|
}
|
|
1185
1372
|
function readSection(reader, round, func, skipEmpty = true, eightBytes = false) {
|
|
1186
1373
|
let length = readUint32(reader);
|
|
@@ -1239,8 +1426,8 @@ function readColor(reader) {
|
|
|
1239
1426
|
const l = readInt16(reader) / 10000;
|
|
1240
1427
|
const ta = readInt16(reader);
|
|
1241
1428
|
const tb = readInt16(reader);
|
|
1242
|
-
const a =
|
|
1243
|
-
const b =
|
|
1429
|
+
const a = (0, helpers_1.normalizeLabAB)(ta, 100);
|
|
1430
|
+
const b = (0, helpers_1.normalizeLabAB)(tb, 100);
|
|
1244
1431
|
skipBytes(reader, 2);
|
|
1245
1432
|
return { l, a, b };
|
|
1246
1433
|
}
|