ag-psd 32.0.0 → 34.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/03e19709 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +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/7ea06cea +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +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/c0b789d2 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +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/d13d7610 +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/e6745c2b +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
- package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
- package/CHANGELOG.md +100 -0
- package/LICENSE +5 -0
- package/README.md +4 -7
- package/README_PSD.md +261 -84
- package/TODO.md +13 -84
- package/dist/abr.d.ts +11 -4
- package/dist/abr.js +362 -230
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +56 -2
- package/dist/additionalInfo.js +828 -361
- package/dist/additionalInfo.js.map +1 -1
- package/dist/ase.d.ts +6 -1
- package/dist/ase.js +61 -61
- package/dist/ase.js.map +1 -1
- package/dist/bundle.js +3321 -1364
- package/dist/descriptor.d.ts +28 -13
- package/dist/descriptor.js +295 -241
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +7 -1
- package/dist/helpers.js +246 -4
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.d.ts +15 -3
- package/dist/imageResources.js +586 -144
- package/dist/imageResources.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jpeg.js +8 -8
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +292 -19
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.d.ts +10 -0
- package/dist/psdReader.js +424 -216
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +2 -0
- package/dist/psdWriter.js +373 -113
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.d.ts +32 -1
- package/dist/text.js +75 -6
- package/dist/text.js.map +1 -1
- package/dist/utf8.js +0 -3
- package/dist/utf8.js.map +1 -1
- package/dist-es/abr.d.ts +11 -4
- package/dist-es/abr.js +362 -230
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +56 -2
- package/dist-es/additionalInfo.js +828 -361
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/ase.d.ts +6 -1
- package/dist-es/ase.js +61 -61
- package/dist-es/ase.js.map +1 -1
- package/dist-es/descriptor.d.ts +28 -13
- package/dist-es/descriptor.js +295 -241
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +7 -1
- package/dist-es/helpers.js +246 -4
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.d.ts +15 -3
- package/dist-es/imageResources.js +586 -144
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/index.d.ts +1 -0
- package/dist-es/index.js +1 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/jpeg.js +8 -8
- package/dist-es/jpeg.js.map +1 -1
- package/dist-es/psd.d.ts +292 -19
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.d.ts +10 -0
- package/dist-es/psdReader.js +424 -216
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +2 -0
- package/dist-es/psdWriter.js +373 -113
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.d.ts +32 -1
- package/dist-es/text.js +75 -6
- package/dist-es/text.js.map +1 -1
- package/dist-es/utf8.js +0 -3
- package/dist-es/utf8.js.map +1 -1
- package/package.json +2 -2
- package/perf.js +312 -9
- package/src/abr.ts +382 -235
- package/src/additionalInfo.ts +1071 -482
- package/src/ase.ts +66 -61
- package/src/descriptor.ts +291 -242
- package/src/helpers.ts +266 -3
- package/src/imageResources.ts +736 -169
- package/src/index.ts +1 -0
- package/src/jpeg.ts +8 -8
- package/src/psd.ts +271 -32
- package/src/psdReader.ts +440 -221
- package/src/psdWriter.ts +402 -110
- package/src/text.ts +93 -7
- package/src/utf8.ts +0 -4
package/dist/psdWriter.js
CHANGED
|
@@ -30,13 +30,15 @@ exports.writePsd = writePsd;
|
|
|
30
30
|
exports.writeColor = writeColor;
|
|
31
31
|
exports.writePattern = writePattern;
|
|
32
32
|
const helpers_1 = require("./helpers");
|
|
33
|
+
const pako_1 = require("pako");
|
|
33
34
|
const additionalInfo_1 = require("./additionalInfo");
|
|
34
35
|
const imageResources_1 = require("./imageResources");
|
|
36
|
+
const psdReader_1 = require("./psdReader");
|
|
35
37
|
function createWriter(size = 4096) {
|
|
36
38
|
const buffer = new ArrayBuffer(size);
|
|
37
39
|
const view = new DataView(buffer);
|
|
38
40
|
const offset = 0;
|
|
39
|
-
return { buffer, view, offset, tempBuffer: undefined };
|
|
41
|
+
return { buffer, view, offset, tempBuffer: undefined, log: console.log };
|
|
40
42
|
}
|
|
41
43
|
function getWriterBuffer(writer) {
|
|
42
44
|
return writer.buffer.slice(0, writer.offset);
|
|
@@ -201,10 +203,33 @@ function writeSection(writer, round, func, writeTotalLength = false, large = fal
|
|
|
201
203
|
function verifyPixelData(data, name) {
|
|
202
204
|
// check element size instead of instanceof, so arrays from other realms (iframes, workers, vm) are accepted
|
|
203
205
|
const bytesPerElement = data && data.data.BYTES_PER_ELEMENT;
|
|
204
|
-
if (bytesPerElement !== undefined && bytesPerElement !== 1) {
|
|
205
|
-
throw new Error(`${name} has incorrect bitDepth (only
|
|
206
|
+
if (bytesPerElement !== undefined && bytesPerElement !== 1 && bytesPerElement !== 2 && !(data.data instanceof Float32Array)) {
|
|
207
|
+
throw new Error(`${name} has incorrect bitDepth (only Uint8Array, Uint8ClampedArray, Uint16Array and Float32Array data is supported for writing)`);
|
|
206
208
|
}
|
|
207
209
|
}
|
|
210
|
+
// supported bit depths for each color mode
|
|
211
|
+
const writeBitDepths = {
|
|
212
|
+
[0 /* ColorMode.Bitmap */]: [1],
|
|
213
|
+
[1 /* ColorMode.Grayscale */]: [8, 16, 32],
|
|
214
|
+
[2 /* ColorMode.Indexed */]: [8],
|
|
215
|
+
[3 /* ColorMode.RGB */]: [8, 16, 32],
|
|
216
|
+
[4 /* ColorMode.CMYK */]: [8, 16],
|
|
217
|
+
};
|
|
218
|
+
const colorModeNames = {
|
|
219
|
+
[0 /* ColorMode.Bitmap */]: 'Bitmap', [1 /* ColorMode.Grayscale */]: 'Grayscale', [2 /* ColorMode.Indexed */]: 'Indexed', [3 /* ColorMode.RGB */]: 'RGB',
|
|
220
|
+
[4 /* ColorMode.CMYK */]: 'CMYK', [7 /* ColorMode.Multichannel */]: 'Multichannel', [8 /* ColorMode.Duotone */]: 'Duotone', [9 /* ColorMode.Lab */]: 'Lab',
|
|
221
|
+
};
|
|
222
|
+
function colorChannelsCount(colorMode) {
|
|
223
|
+
return colorMode === 3 /* ColorMode.RGB */ ? 3 : (colorMode === 4 /* ColorMode.CMYK */ ? 4 : 1);
|
|
224
|
+
}
|
|
225
|
+
// HDR toning settings that Photoshop stores in color mode data of 32bit documents (default values of new document),
|
|
226
|
+
// Photoshop refuses to open 32bit documents without them
|
|
227
|
+
const hdrToningData = [
|
|
228
|
+
104, 100, 114, 116, 0, 0, 0, 3, 62, 107, 133, 31, 0, 0, 0, 2, 0, 0, 0, 7, 0, 76, 0, 105, 0, 110, 0, 101, 0, 97, 0, 114, 0, 0,
|
|
229
|
+
0, 2, 0, 2, 0, 0, 0, 0, 0, 255, 0, 255, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 65, 128, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 63, 128, 0, 0,
|
|
230
|
+
104, 100, 114, 97, 0, 0, 0, 6, 0, 0, 0, 0, 65, 160, 0, 0, 65, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 0, 0, 0, 0,
|
|
231
|
+
0, 0,
|
|
232
|
+
];
|
|
208
233
|
function verifyBitCount(target) {
|
|
209
234
|
var _a, _b, _c;
|
|
210
235
|
(_a = target.children) === null || _a === void 0 ? void 0 : _a.forEach(verifyBitCount);
|
|
@@ -215,21 +240,37 @@ function verifyBitCount(target) {
|
|
|
215
240
|
verifyPixelData((_c = target.realMask) === null || _c === void 0 ? void 0 : _c.imageData, 'realMask imageData');
|
|
216
241
|
}
|
|
217
242
|
function writePsd(writer, psd, options = {}) {
|
|
218
|
-
var _a;
|
|
243
|
+
var _a, _b, _c, _d;
|
|
219
244
|
if (!(+psd.width > 0 && +psd.height > 0))
|
|
220
245
|
throw new Error('Invalid document size');
|
|
221
246
|
if ((psd.width > 30000 || psd.height > 30000) && !options.psb)
|
|
222
247
|
throw new Error('Document size is too large (max is 30000x30000, use PSB format instead)');
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
const colorMode = (_a = psd.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
|
|
249
|
+
const bitsPerChannel = (_b = psd.bitsPerChannel) !== null && _b !== void 0 ? _b : (colorMode === 0 /* ColorMode.Bitmap */ ? 1 : 8);
|
|
250
|
+
const bitDepths = writeBitDepths[colorMode];
|
|
251
|
+
if (!bitDepths)
|
|
252
|
+
throw new Error(`${(_c = colorModeNames[colorMode]) !== null && _c !== void 0 ? _c : colorMode} color mode is not supported for writing`);
|
|
253
|
+
if (bitDepths.indexOf(bitsPerChannel) === -1)
|
|
254
|
+
throw new Error(`bitsPerChannel ${bitsPerChannel} is not supported for writing in ${colorModeNames[colorMode]} color mode`);
|
|
255
|
+
// Photoshop doesn't support layers in bitmap and indexed color modes
|
|
256
|
+
const layersAllowed = colorMode !== 0 /* ColorMode.Bitmap */ && colorMode !== 2 /* ColorMode.Indexed */;
|
|
257
|
+
if (!layersAllowed && ((_d = psd.children) === null || _d === void 0 ? void 0 : _d.length))
|
|
258
|
+
throw new Error(`Layers are not supported in ${colorModeNames[colorMode]} color mode`);
|
|
259
|
+
if (colorMode === 2 /* ColorMode.Indexed */ && !psd.palette)
|
|
260
|
+
throw new Error('Missing color palette for Indexed color mode');
|
|
261
|
+
if (options.log)
|
|
262
|
+
writer.log = options.log;
|
|
263
|
+
if (options.logMissingFeatures)
|
|
264
|
+
writer.logMissingFeatures = true;
|
|
226
265
|
const layers = [];
|
|
227
266
|
addChildren(layers, psd.children);
|
|
228
|
-
if (!layers.length)
|
|
267
|
+
if (!layers.length && layersAllowed)
|
|
229
268
|
layers.push({});
|
|
230
269
|
verifyBitCount(psd);
|
|
231
270
|
const imageResources = Object.assign({}, psd.imageResources);
|
|
232
|
-
const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map() });
|
|
271
|
+
const opt = Object.assign(Object.assign({}, options), { layerIds: new Set(), layerToId: new Map(), colorMode, bitsPerChannel });
|
|
272
|
+
// 16 and 32 bit documents store layers in Lr16 / Lr32 section of global additional info
|
|
273
|
+
const layersInGlobalInfo = bitsPerChannel === 16 || bitsPerChannel === 32;
|
|
233
274
|
if (opt.generateThumbnail) {
|
|
234
275
|
imageResources.thumbnail = createThumbnail(psd);
|
|
235
276
|
}
|
|
@@ -237,32 +278,38 @@ function writePsd(writer, psd, options = {}) {
|
|
|
237
278
|
if (!imageData && psd.canvas) {
|
|
238
279
|
imageData = psd.canvas.getContext('2d').getImageData(0, 0, psd.canvas.width, psd.canvas.height);
|
|
239
280
|
}
|
|
281
|
+
if (!imageData && psd.rawCompositeData) { // read with `useRawData` option
|
|
282
|
+
imageData = (0, psdReader_1.getCompositeImageData)(psd);
|
|
283
|
+
}
|
|
240
284
|
if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
|
|
241
285
|
throw new Error('Document canvas must have the same size as document');
|
|
242
|
-
const globalAlpha = !!imageData && (0, helpers_1.hasAlpha)(imageData);
|
|
286
|
+
const globalAlpha = !!imageData && layersAllowed && (0, helpers_1.hasAlpha)(imageData);
|
|
243
287
|
// only used for encoding a single layer channel at a time, composite image is encoded directly into the writer buffer
|
|
244
288
|
writer.tempBuffer = new Uint8Array(getLargestLayerSize(psd.children, !!options.psb));
|
|
245
289
|
// header
|
|
246
290
|
writeSignature(writer, '8BPS');
|
|
247
291
|
writeUint16(writer, options.psb ? 2 : 1); // version
|
|
248
292
|
writeZeros(writer, 6);
|
|
249
|
-
writeUint16(writer, globalAlpha ?
|
|
293
|
+
writeUint16(writer, colorChannelsCount(colorMode) + (globalAlpha ? 1 : 0)); // channels
|
|
250
294
|
writeUint32(writer, psd.height);
|
|
251
295
|
writeUint32(writer, psd.width);
|
|
252
296
|
writeUint16(writer, bitsPerChannel); // bits per channel
|
|
253
|
-
writeUint16(writer,
|
|
297
|
+
writeUint16(writer, colorMode);
|
|
254
298
|
// color mode data
|
|
255
299
|
writeSection(writer, 1, () => {
|
|
256
|
-
var _a, _b, _c;
|
|
257
|
-
if (
|
|
300
|
+
var _a, _b, _c, _d, _e, _f;
|
|
301
|
+
if (colorMode === 2 /* ColorMode.Indexed */) {
|
|
302
|
+
const palette = psd.palette;
|
|
258
303
|
for (let i = 0; i < 256; i++)
|
|
259
|
-
writeUint8(writer, ((_a =
|
|
304
|
+
writeUint8(writer, (_b = (_a = palette[i]) === null || _a === void 0 ? void 0 : _a.r) !== null && _b !== void 0 ? _b : 0);
|
|
260
305
|
for (let i = 0; i < 256; i++)
|
|
261
|
-
writeUint8(writer, ((
|
|
306
|
+
writeUint8(writer, (_d = (_c = palette[i]) === null || _c === void 0 ? void 0 : _c.g) !== null && _d !== void 0 ? _d : 0);
|
|
262
307
|
for (let i = 0; i < 256; i++)
|
|
263
|
-
writeUint8(writer, ((
|
|
308
|
+
writeUint8(writer, (_f = (_e = palette[i]) === null || _e === void 0 ? void 0 : _e.b) !== null && _f !== void 0 ? _f : 0);
|
|
309
|
+
}
|
|
310
|
+
else if (bitsPerChannel === 32) {
|
|
311
|
+
writeBytes(writer, new Uint8Array(hdrToningData));
|
|
264
312
|
}
|
|
265
|
-
// TODO: other data?
|
|
266
313
|
});
|
|
267
314
|
// image resources
|
|
268
315
|
imageResources.layersGroup = layers.map(l => l.linkGroup || 0);
|
|
@@ -272,27 +319,37 @@ function writePsd(writer, psd, options = {}) {
|
|
|
272
319
|
const has = handler.has(imageResources);
|
|
273
320
|
const count = has === false ? 0 : (has === true ? 1 : has);
|
|
274
321
|
for (let i = 0; i < count; i++) {
|
|
322
|
+
const id = handler.keyCount > 1 ? handler.key + i : handler.key;
|
|
323
|
+
const name = handler.name ? handler.name(imageResources, i) : '';
|
|
275
324
|
writeSignature(writer, '8BIM');
|
|
276
|
-
writeUint16(writer,
|
|
277
|
-
writePascalString(writer,
|
|
278
|
-
writeSection(writer, 2, () => handler.write(writer, imageResources, i));
|
|
325
|
+
writeUint16(writer, id);
|
|
326
|
+
writePascalString(writer, name, 2);
|
|
327
|
+
writeSection(writer, 2, () => handler.write(writer, imageResources, i, psd));
|
|
279
328
|
}
|
|
280
329
|
}
|
|
281
330
|
});
|
|
282
331
|
// layer and mask info
|
|
283
332
|
writeSection(writer, 2, () => {
|
|
284
|
-
|
|
333
|
+
if (layersInGlobalInfo || !layersAllowed) {
|
|
334
|
+
writeSection(writer, 4, () => { }, true, opt.psb); // empty layer info
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
writeLayerInfo(writer, layers, psd, globalAlpha, opt);
|
|
338
|
+
}
|
|
285
339
|
writeGlobalLayerMaskInfo(writer, psd.globalLayerMaskInfo);
|
|
340
|
+
if (layersInGlobalInfo) {
|
|
341
|
+
if (globalAlpha)
|
|
342
|
+
writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Mt16' : 'Mt32', !!opt.psb, () => { });
|
|
343
|
+
writeGlobalInfoSection(writer, bitsPerChannel === 16 ? 'Lr16' : 'Lr32', !!opt.psb, () => {
|
|
344
|
+
writeLayerInfoData(writer, layers, psd, globalAlpha, opt);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
286
347
|
writeAdditionalLayerInfo(writer, psd, psd, opt);
|
|
287
348
|
}, undefined, !!opt.psb);
|
|
288
349
|
writer.tempBuffer = undefined;
|
|
289
350
|
// image data
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
console.log('writing raw image data');
|
|
293
|
-
writeBytes(writer, psd.imageDataRaw);
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
351
|
+
if (colorMode === 3 /* ColorMode.RGB */ && bitsPerChannel === 8 && (!imageData || is8bit(imageData))) {
|
|
352
|
+
writeUint16(writer, 1 /* Compression.RleCompressed */); // Photoshop doesn't support zip compression of composite image data
|
|
296
353
|
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
297
354
|
const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
|
|
298
355
|
// encode directly into the writer buffer
|
|
@@ -301,6 +358,174 @@ function writePsd(writer, psd, options = {}) {
|
|
|
301
358
|
const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
|
|
302
359
|
writer.offset += (0, helpers_1.writeDataRLE)(buffer, data, channels, !!options.psb).length;
|
|
303
360
|
}
|
|
361
|
+
else {
|
|
362
|
+
writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, !!options.psb);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function writeGlobalInfoSection(writer, key, psb, func) {
|
|
366
|
+
writeSignature(writer, psb ? '8B64' : '8BIM');
|
|
367
|
+
writeSignature(writer, key);
|
|
368
|
+
writeSection(writer, 4, func, false, psb);
|
|
369
|
+
}
|
|
370
|
+
function is8bit(data) {
|
|
371
|
+
return data.data.BYTES_PER_ELEMENT === 1;
|
|
372
|
+
}
|
|
373
|
+
// converts image data (8, 16 or 32 bit RGBA data) to channels of the document color mode and bit depth
|
|
374
|
+
function getPlanarChannels(imageData, colorMode, bitsPerChannel, matte) {
|
|
375
|
+
const { data, width, height } = imageData;
|
|
376
|
+
const size = width * height;
|
|
377
|
+
const srcFloat = data instanceof Float32Array;
|
|
378
|
+
const srcMax = srcFloat ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
|
|
379
|
+
const dstFloat = bitsPerChannel === 32;
|
|
380
|
+
const dstMax = dstFloat ? 1 : (bitsPerChannel === 16 ? 0xffff : 0xff);
|
|
381
|
+
const colorCount = colorChannelsCount(colorMode);
|
|
382
|
+
const create = () => dstFloat ? new Float32Array(size) : (bitsPerChannel === 16 ? new Uint16Array(size) : new Uint8Array(size));
|
|
383
|
+
const colors = [];
|
|
384
|
+
for (let i = 0; i < colorCount; i++)
|
|
385
|
+
colors.push(create());
|
|
386
|
+
const alpha = create();
|
|
387
|
+
// color values are gamma corrected when converting between float (linear) and integer values (same as imageDataToCanvas)
|
|
388
|
+
const toNormalized = (v) => srcFloat ? Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) : v / srcMax;
|
|
389
|
+
const fromNormalized = (v) => dstFloat ? Math.pow(v, 2.2) : Math.round((0, helpers_1.clamp)(v, 0, 1) * dstMax);
|
|
390
|
+
const sameType = srcFloat === dstFloat && srcMax === dstMax;
|
|
391
|
+
const convertColor = (v) => sameType ? (dstFloat ? v : Math.round(v)) : fromNormalized(toNormalized(v));
|
|
392
|
+
const convertAlpha = (v) => sameType ? v : (dstFloat ? v / srcMax : Math.round((0, helpers_1.clamp)(v / srcMax, 0, 1) * dstMax));
|
|
393
|
+
const cmyk = [0, 0, 0, 0];
|
|
394
|
+
for (let i = 0, p = 0; i < size; i++, p += 4) {
|
|
395
|
+
const a = data[p + 3];
|
|
396
|
+
const alphaValue = convertAlpha(a);
|
|
397
|
+
alpha[i] = alphaValue;
|
|
398
|
+
// composite image colors are blended with white (or no ink) for documents with transparency
|
|
399
|
+
const blend = matte && a !== srcMax && a > 0 ? (0, helpers_1.clamp)(a / srcMax, 0, 1) : 1;
|
|
400
|
+
if (colorMode === 4 /* ColorMode.CMYK */) {
|
|
401
|
+
(0, helpers_1.rgbToCmykValues)(toNormalized(data[p]), toNormalized(data[p + 1]), toNormalized(data[p + 2]), cmyk);
|
|
402
|
+
for (let j = 0; j < 4; j++) {
|
|
403
|
+
colors[j][i] = Math.round((1 - (0, helpers_1.clamp)(cmyk[j] * blend, 0, 1)) * dstMax); // stored inverted (0 = 100% ink)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
for (let j = 0; j < colorCount; j++) {
|
|
408
|
+
let value;
|
|
409
|
+
if (colorMode === 3 /* ColorMode.RGB */) {
|
|
410
|
+
value = convertColor(data[p + j]);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
const r = data[p], g = data[p + 1], b = data[p + 2];
|
|
414
|
+
value = convertColor((r === g && g === b) ? r : (0.299 * r + 0.587 * g + 0.114 * b));
|
|
415
|
+
}
|
|
416
|
+
if (blend !== 1)
|
|
417
|
+
value = dstFloat ? value * blend + 1 - blend : Math.round(value * blend + dstMax * (1 - blend));
|
|
418
|
+
colors[j][i] = value;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return { colors, alpha };
|
|
423
|
+
}
|
|
424
|
+
function encodeChannel(values, width, height, options) {
|
|
425
|
+
if (!(values instanceof Uint8Array)) {
|
|
426
|
+
return { data: (0, helpers_1.writeDataZipWithPrediction)(values, width, height), compression: 3 /* Compression.ZipWithPrediction */ };
|
|
427
|
+
}
|
|
428
|
+
else if (options.compress) {
|
|
429
|
+
return { data: (0, pako_1.deflate)(values), compression: 2 /* Compression.ZipWithoutPrediction */ };
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
return { data: (0, helpers_1.writeDataRLEBytes)(values, width, height, !!options.psb), compression: 1 /* Compression.RleCompressed */ };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function writeCompositeImageData(writer, psd, imageData, colorMode, bitsPerChannel, globalAlpha, psb) {
|
|
436
|
+
var _a;
|
|
437
|
+
const { width, height } = psd;
|
|
438
|
+
const data = imageData !== null && imageData !== void 0 ? imageData : { data: new Uint8Array(width * height * 4), width, height };
|
|
439
|
+
const parts = [];
|
|
440
|
+
if (colorMode === 0 /* ColorMode.Bitmap */ || colorMode === 2 /* ColorMode.Indexed */) {
|
|
441
|
+
const values = colorMode === 0 /* ColorMode.Bitmap */ ?
|
|
442
|
+
getBitmapData(data) :
|
|
443
|
+
getIndexedData(data, psd.palette, (_a = psd.imageResources) === null || _a === void 0 ? void 0 : _a.transparencyIndex);
|
|
444
|
+
const rowBytes = colorMode === 0 /* ColorMode.Bitmap */ ? Math.ceil(width / 8) : width;
|
|
445
|
+
if (colorMode === 0 /* ColorMode.Bitmap */) {
|
|
446
|
+
writeUint16(writer, 0 /* Compression.RawData */);
|
|
447
|
+
parts.push(values);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
writeUint16(writer, 1 /* Compression.RleCompressed */);
|
|
451
|
+
parts.push((0, helpers_1.writeDataRLEBytes)(values, rowBytes, height, psb));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
const { colors, alpha } = getPlanarChannels(data, colorMode, bitsPerChannel, globalAlpha);
|
|
456
|
+
const channels = globalAlpha ? [...colors, alpha] : colors;
|
|
457
|
+
if (bitsPerChannel === 8) {
|
|
458
|
+
// row byte counts for all channels are stored before data of all channels
|
|
459
|
+
const encoded = channels.map(c => (0, helpers_1.writeDataRLEBytes)(c, width, height, psb));
|
|
460
|
+
const countsSize = height * (psb ? 4 : 2);
|
|
461
|
+
writeUint16(writer, 1 /* Compression.RleCompressed */);
|
|
462
|
+
for (const e of encoded)
|
|
463
|
+
parts.push(e.subarray(0, countsSize));
|
|
464
|
+
for (const e of encoded)
|
|
465
|
+
parts.push(e.subarray(countsSize));
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
writeUint16(writer, 0 /* Compression.RawData */); // Photoshop writes 16 and 32 bit composite image without compression
|
|
469
|
+
for (const c of channels)
|
|
470
|
+
parts.push((0, helpers_1.planarToBytes)(c));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
for (const part of parts)
|
|
474
|
+
writeBytes(writer, part);
|
|
475
|
+
}
|
|
476
|
+
function getBitmapData({ data, width, height }) {
|
|
477
|
+
const rowBytes = Math.ceil(width / 8);
|
|
478
|
+
const result = new Uint8Array(rowBytes * height);
|
|
479
|
+
const max = data instanceof Float32Array ? 1 : (data instanceof Uint16Array ? 0xffff : 0xff);
|
|
480
|
+
for (let y = 0, p = 0; y < height; y++) {
|
|
481
|
+
for (let x = 0; x < width; x++, p += 4) {
|
|
482
|
+
const a = data[p + 3] / max;
|
|
483
|
+
const value = ((0.299 * data[p] + 0.587 * data[p + 1] + 0.114 * data[p + 2]) / max) * a + (1 - a); // blend with white
|
|
484
|
+
if (value < 0.5)
|
|
485
|
+
result[y * rowBytes + (x >> 3)] |= 0x80 >> (x & 7); // 1 = black
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
function getIndexedData({ data, width, height }, palette, transparencyIndex) {
|
|
491
|
+
const size = width * height;
|
|
492
|
+
const result = new Uint8Array(size);
|
|
493
|
+
const shift = data instanceof Uint16Array ? 8 : 0;
|
|
494
|
+
const cache = new Map();
|
|
495
|
+
for (let i = 0; i < palette.length && i < 256; i++) {
|
|
496
|
+
const key = (palette[i].r << 16) | (palette[i].g << 8) | palette[i].b;
|
|
497
|
+
if (i !== transparencyIndex && !cache.has(key))
|
|
498
|
+
cache.set(key, i);
|
|
499
|
+
}
|
|
500
|
+
for (let i = 0, p = 0; i < size; i++, p += 4) {
|
|
501
|
+
const read = (v) => data instanceof Float32Array ? Math.round(Math.pow((0, helpers_1.clamp)(v, 0, 1), 1 / 2.2) * 255) : (v >>> shift);
|
|
502
|
+
const a = data instanceof Float32Array ? data[p + 3] * 255 : (data[p + 3] >>> shift);
|
|
503
|
+
if (transparencyIndex !== undefined && transparencyIndex >= 0 && a < 128) {
|
|
504
|
+
result[i] = transparencyIndex;
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
const r = read(data[p]), g = read(data[p + 1]), b = read(data[p + 2]);
|
|
508
|
+
const key = (r << 16) | (g << 8) | b;
|
|
509
|
+
let index = cache.get(key);
|
|
510
|
+
if (index === undefined) {
|
|
511
|
+
// use closest color from the palette
|
|
512
|
+
let best = Infinity;
|
|
513
|
+
index = 0;
|
|
514
|
+
for (let j = 0; j < palette.length && j < 256; j++) {
|
|
515
|
+
if (j === transparencyIndex)
|
|
516
|
+
continue;
|
|
517
|
+
const dr = palette[j].r - r, dg = palette[j].g - g, db = palette[j].b - b;
|
|
518
|
+
const distance = dr * dr + dg * dg + db * db;
|
|
519
|
+
if (distance < best) {
|
|
520
|
+
best = distance;
|
|
521
|
+
index = j;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
cache.set(key, index);
|
|
525
|
+
}
|
|
526
|
+
result[i] = index;
|
|
527
|
+
}
|
|
528
|
+
return result;
|
|
304
529
|
}
|
|
305
530
|
function getCompositeData(imageData, width, height, globalAlpha) {
|
|
306
531
|
if (!imageData)
|
|
@@ -326,62 +551,68 @@ function getCompositeData(imageData, width, height, globalAlpha) {
|
|
|
326
551
|
return dst ? { data: dst, width, height } : imageData;
|
|
327
552
|
}
|
|
328
553
|
function writeLayerInfo(writer, layers, psd, globalAlpha, options) {
|
|
329
|
-
writeSection(writer, 4, () =>
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
writeUint32(writer, c.length);
|
|
348
|
-
}
|
|
554
|
+
writeSection(writer, 4, () => writeLayerInfoData(writer, layers, psd, globalAlpha, options), true, options.psb);
|
|
555
|
+
}
|
|
556
|
+
function writeLayerInfoData(writer, layers, psd, globalAlpha, options) {
|
|
557
|
+
var _a;
|
|
558
|
+
writeInt16(writer, globalAlpha ? -layers.length : layers.length);
|
|
559
|
+
const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
|
|
560
|
+
// layer records
|
|
561
|
+
for (const layerData of layersData) {
|
|
562
|
+
const { layer, top, left, bottom, right, channels } = layerData;
|
|
563
|
+
writeInt32(writer, top);
|
|
564
|
+
writeInt32(writer, left);
|
|
565
|
+
writeInt32(writer, bottom);
|
|
566
|
+
writeInt32(writer, right);
|
|
567
|
+
writeUint16(writer, channels.length);
|
|
568
|
+
for (const c of channels) {
|
|
569
|
+
writeInt16(writer, c.id);
|
|
570
|
+
if (options.psb) {
|
|
571
|
+
writeUint64(writer, c.length);
|
|
349
572
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
|
|
353
|
-
writeUint8(writer, layer.clipping ? 1 : 0);
|
|
354
|
-
let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
|
|
355
|
-
if (layer.transparencyProtected)
|
|
356
|
-
flags |= 0x01;
|
|
357
|
-
if (layer.hidden)
|
|
358
|
-
flags |= 0x02;
|
|
359
|
-
if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
|
|
360
|
-
flags |= 0x10; // pixel data irrelevant to appearance of document
|
|
573
|
+
else {
|
|
574
|
+
writeUint32(writer, c.length);
|
|
361
575
|
}
|
|
362
|
-
if (layer.effectsOpen)
|
|
363
|
-
flags |= 0x20;
|
|
364
|
-
writeUint8(writer, flags);
|
|
365
|
-
writeUint8(writer, 0); // filler
|
|
366
|
-
writeSection(writer, 1, () => {
|
|
367
|
-
writeLayerMaskData(writer, layer, layerData);
|
|
368
|
-
writeLayerBlendingRanges(writer, layer);
|
|
369
|
-
writePascalString(writer, (layer.name || '').substring(0, 255), 4);
|
|
370
|
-
writeAdditionalLayerInfo(writer, layer, psd, options);
|
|
371
|
-
});
|
|
372
576
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
577
|
+
writeSignature(writer, '8BIM');
|
|
578
|
+
writeSignature(writer, helpers_1.fromBlendMode[layer.blendMode] || 'norm');
|
|
579
|
+
writeUint8(writer, Math.round((0, helpers_1.clamp)((_a = layer.opacity) !== null && _a !== void 0 ? _a : 1, 0, 1) * 255));
|
|
580
|
+
writeUint8(writer, layer.clipping ? 1 : 0);
|
|
581
|
+
let flags = 0x08; // 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
|
|
582
|
+
if (layer.transparencyProtected)
|
|
583
|
+
flags |= 0x01;
|
|
584
|
+
if (layer.hidden)
|
|
585
|
+
flags |= 0x02;
|
|
586
|
+
if (layer.vectorMask || (layer.sectionDivider && layer.sectionDivider.type !== 0 /* SectionDividerType.Other */) || layer.adjustment) {
|
|
587
|
+
flags |= 0x10; // pixel data irrelevant to appearance of document
|
|
588
|
+
}
|
|
589
|
+
if (layer.effectsOpen)
|
|
590
|
+
flags |= 0x20;
|
|
591
|
+
writeUint8(writer, flags);
|
|
592
|
+
writeUint8(writer, 0); // filler
|
|
593
|
+
writeSection(writer, 1, () => {
|
|
594
|
+
writeLayerMaskData(writer, layer, layerData);
|
|
595
|
+
writeLayerBlendingRanges(writer, layer);
|
|
596
|
+
writePascalString(writer, (layer.name || '').substring(0, 255), 4);
|
|
597
|
+
writeAdditionalLayerInfo(writer, layer, psd, options);
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
// layer channel image data
|
|
601
|
+
for (const layerData of layersData) {
|
|
602
|
+
for (const channel of layerData.channels) {
|
|
603
|
+
writeUint16(writer, channel.compression);
|
|
604
|
+
if (channel.data) {
|
|
605
|
+
writeBytes(writer, channel.data);
|
|
380
606
|
}
|
|
381
607
|
}
|
|
382
|
-
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
// real mask is only stored separately if layer has both vector and pixel masks, otherwise it's stored as the main mask
|
|
611
|
+
function getMasks(layer) {
|
|
612
|
+
return layer.mask ? { mask: layer.mask, realMask: layer.realMask } : { mask: layer.realMask, realMask: undefined };
|
|
383
613
|
}
|
|
384
|
-
function writeLayerMaskData(writer,
|
|
614
|
+
function writeLayerMaskData(writer, layer, layerData) {
|
|
615
|
+
const { mask, realMask } = getMasks(layer);
|
|
385
616
|
writeSection(writer, 4, () => {
|
|
386
617
|
if (!mask && !realMask)
|
|
387
618
|
return;
|
|
@@ -477,13 +708,13 @@ function writeAdditionalLayerInfo(writer, target, psd, options) {
|
|
|
477
708
|
let key = handler.key;
|
|
478
709
|
if (key === 'Txt2' && options.invalidateTextLayers)
|
|
479
710
|
continue;
|
|
480
|
-
if (key === 'vmsk' &&
|
|
481
|
-
key = 'vsms';
|
|
711
|
+
if (key === 'vmsk' && additionalInfo_1.infoHandlersMap['vscg'].has(target))
|
|
712
|
+
key = 'vsms'; // Photoshop uses 'vsms' for layers with vector stroke
|
|
482
713
|
if (handler.has(target)) {
|
|
483
714
|
const large = options.psb && helpers_1.largeAdditionalInfoKeys.indexOf(key) !== -1;
|
|
484
715
|
const writeTotalLength = key !== 'Txt2' && key !== 'cinf' && key !== 'extn' && key !== 'CAI ' && key !== 'OCIO';
|
|
485
716
|
const fourBytes = key === 'levl' || key === 'Txt2' || key === 'luni' || key === 'vmsk' || key === 'artb' || key === 'artd' ||
|
|
486
|
-
key === 'vogk' || key === 'SoLd' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
717
|
+
key === 'vogk' || key === 'SoLd' || key === 'SoLE' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
487
718
|
key === 'lmfx' || key === 'lrFX' || key === 'cinf' || key === 'PlLd' || key === 'Anno' || key === 'CAI ' || key === 'OCIO' || key === 'GenI' || key === 'FEid' || key === 'curv' || key === 'CgEd' || key === 'vibA' || key === 'blwh' || key === 'grdm';
|
|
488
719
|
writeSignature(writer, large ? '8B64' : '8BIM');
|
|
489
720
|
writeSignature(writer, key);
|
|
@@ -576,7 +807,8 @@ function createThumbnail(psd) {
|
|
|
576
807
|
}
|
|
577
808
|
return canvas;
|
|
578
809
|
}
|
|
579
|
-
function getMaskChannels(tempBuffer, layerData,
|
|
810
|
+
function getMaskChannels(tempBuffer, layerData, mask, options, realMask) {
|
|
811
|
+
var _a;
|
|
580
812
|
let top = mask.top | 0;
|
|
581
813
|
let left = mask.left | 0;
|
|
582
814
|
let right = mask.right | 0;
|
|
@@ -593,14 +825,15 @@ function getMaskChannels(tempBuffer, layerData, layer, mask, options, realMask)
|
|
|
593
825
|
bottom = top + height;
|
|
594
826
|
let buffer;
|
|
595
827
|
let compression;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
compression = layer[realMask ? 'realMaskDataRawCompression' : 'maskDataRawCompression'];
|
|
599
|
-
}
|
|
600
|
-
else if (!imageData) {
|
|
828
|
+
const bitsPerChannel = (_a = options.bitsPerChannel) !== null && _a !== void 0 ? _a : 8;
|
|
829
|
+
if (!imageData) {
|
|
601
830
|
buffer = new Uint8Array(0);
|
|
602
831
|
compression = 1 /* Compression.RleCompressed */;
|
|
603
832
|
}
|
|
833
|
+
else if (bitsPerChannel !== 8 || !is8bit(imageData)) {
|
|
834
|
+
const { colors } = getPlanarChannels(imageData, 3 /* ColorMode.RGB */, bitsPerChannel, false);
|
|
835
|
+
({ data: buffer, compression } = encodeChannel(colors[0], width, height, options));
|
|
836
|
+
}
|
|
604
837
|
else if (options.compress) {
|
|
605
838
|
buffer = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [0]);
|
|
606
839
|
compression = 2 /* Compression.ZipWithoutPrediction */;
|
|
@@ -620,15 +853,32 @@ function bounds(obj) {
|
|
|
620
853
|
bottom: obj.bottom || 0,
|
|
621
854
|
} : undefined;
|
|
622
855
|
}
|
|
623
|
-
function getChannels(
|
|
856
|
+
function getChannels(writer, layer, background, options) {
|
|
857
|
+
var _a, _b;
|
|
858
|
+
let source = layer;
|
|
624
859
|
if (layer.rawData) {
|
|
625
|
-
|
|
860
|
+
const { colorMode, bitsPerChannel, large } = layer.rawData;
|
|
861
|
+
const opt = options;
|
|
862
|
+
if (large === !!options.psb && colorMode === ((_a = opt.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */) && bitsPerChannel === ((_b = opt.bitsPerChannel) !== null && _b !== void 0 ? _b : 8)) {
|
|
863
|
+
// same mask mapping as in writeLayerMaskData
|
|
864
|
+
const { mask, realMask } = getMasks(layer);
|
|
865
|
+
return Object.assign(Object.assign({ layer, channels: layer.rawData.channels.map(c => { var _a, _b; return (Object.assign(Object.assign({}, c), { length: 2 + ((_b = (_a = c.data) === null || _a === void 0 ? void 0 : _a.byteLength) !== null && _b !== void 0 ? _b : 0) })); }) }, bounds(layer)), { mask: bounds(mask), realMask: bounds(realMask) });
|
|
866
|
+
}
|
|
867
|
+
// raw data is in different format than the one we're writing, decode it so it can be re-encoded
|
|
868
|
+
source = Object.assign(Object.assign({}, layer), { rawData: undefined, canvas: undefined, imageData: (0, psdReader_1.getLayerImageData)(layer), mask: layer.mask && Object.assign(Object.assign({}, layer.mask), { canvas: undefined, imageData: (0, psdReader_1.getLayerMaskImageData)(layer) }), realMask: layer.realMask && Object.assign(Object.assign({}, layer.realMask), { canvas: undefined, imageData: (0, psdReader_1.getLayerRealMaskImageData)(layer) }) });
|
|
869
|
+
// temp buffer is sized only for layers with image data, grow it and keep it for following layers
|
|
870
|
+
const size = getLargestLayerSize([Object.assign(Object.assign({}, source), { children: undefined })], !!options.psb);
|
|
871
|
+
if (writer.tempBuffer.byteLength < size)
|
|
872
|
+
writer.tempBuffer = new Uint8Array(size);
|
|
626
873
|
}
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (
|
|
631
|
-
getMaskChannels(tempBuffer, layerData,
|
|
874
|
+
const tempBuffer = writer.tempBuffer;
|
|
875
|
+
const { mask, realMask } = getMasks(source);
|
|
876
|
+
const layerData = getLayerChannels(tempBuffer, source, background, options);
|
|
877
|
+
if (mask)
|
|
878
|
+
getMaskChannels(tempBuffer, layerData, mask, options, false);
|
|
879
|
+
if (realMask)
|
|
880
|
+
getMaskChannels(tempBuffer, layerData, realMask, options, true);
|
|
881
|
+
layerData.layer = layer;
|
|
632
882
|
return layerData;
|
|
633
883
|
}
|
|
634
884
|
function getLayerDimentions({ canvas, imageData }) {
|
|
@@ -639,10 +889,8 @@ function getLayerDimentions({ canvas, imageData }) {
|
|
|
639
889
|
return { width, height };
|
|
640
890
|
}
|
|
641
891
|
function cropImageData(data, left, top, width, height) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
const croppedData = (0, helpers_1.createImageData)(width, height);
|
|
892
|
+
const croppedData = is8bit(data) ? (0, helpers_1.createImageData)(width, height) :
|
|
893
|
+
{ width, height, data: new data.data.constructor(width * height * 4) };
|
|
646
894
|
const srcData = data.data;
|
|
647
895
|
const dstData = croppedData.data;
|
|
648
896
|
for (let y = 0; y < height; y++) {
|
|
@@ -658,7 +906,7 @@ function cropImageData(data, left, top, width, height) {
|
|
|
658
906
|
return croppedData;
|
|
659
907
|
}
|
|
660
908
|
function getLayerChannels(tempBuffer, layer, background, options) {
|
|
661
|
-
var _a;
|
|
909
|
+
var _a, _b;
|
|
662
910
|
let top = layer.top | 0;
|
|
663
911
|
let left = layer.left | 0;
|
|
664
912
|
let right = layer.right | 0;
|
|
@@ -671,8 +919,11 @@ function getLayerChannels(tempBuffer, layer, background, options) {
|
|
|
671
919
|
];
|
|
672
920
|
let { width, height } = getLayerDimentions(layer);
|
|
673
921
|
if (!(layer.canvas || layer.imageData) || !width || !height) {
|
|
674
|
-
|
|
675
|
-
|
|
922
|
+
// layer without image data is empty, keep inverted (negative size) bounds from some files as they are
|
|
923
|
+
if (layer.right === undefined || right > left)
|
|
924
|
+
right = left;
|
|
925
|
+
if (layer.bottom === undefined || bottom > top)
|
|
926
|
+
bottom = top;
|
|
676
927
|
return { layer, top, left, right, bottom, channels };
|
|
677
928
|
}
|
|
678
929
|
right = left + width;
|
|
@@ -697,19 +948,27 @@ function getLayerChannels(tempBuffer, layer, background, options) {
|
|
|
697
948
|
1 /* ChannelID.Color1 */,
|
|
698
949
|
2 /* ChannelID.Color2 */,
|
|
699
950
|
];
|
|
700
|
-
if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)
|
|
951
|
+
if (!background || options.noBackground || layer.mask || (0, helpers_1.hasAlpha)(imageData)) {
|
|
701
952
|
channelIds.unshift(-1 /* ChannelID.Transparency */);
|
|
702
953
|
}
|
|
954
|
+
const colorMode = (_a = options.colorMode) !== null && _a !== void 0 ? _a : 3 /* ColorMode.RGB */;
|
|
955
|
+
const bitsPerChannel = (_b = options.bitsPerChannel) !== null && _b !== void 0 ? _b : 8;
|
|
956
|
+
if (colorMode !== 3 /* ColorMode.RGB */ || bitsPerChannel !== 8 || !is8bit(imageData)) {
|
|
957
|
+
const { colors, alpha } = getPlanarChannels(imageData, colorMode, bitsPerChannel, false);
|
|
958
|
+
const ids = channelIds[0] === -1 /* ChannelID.Transparency */ ? [-1 /* ChannelID.Transparency */] : [];
|
|
959
|
+
for (let i = 0; i < colors.length; i++)
|
|
960
|
+
ids.push(i);
|
|
961
|
+
channels = ids.map(id => {
|
|
962
|
+
const { data, compression } = encodeChannel(id === -1 /* ChannelID.Transparency */ ? alpha : colors[id], width, height, options);
|
|
963
|
+
return { id, compression, data, length: 2 + data.length };
|
|
964
|
+
});
|
|
965
|
+
return { layer, top, left, right, bottom, channels };
|
|
966
|
+
}
|
|
703
967
|
channels = channelIds.map(id => {
|
|
704
|
-
const offset = (0, helpers_1.offsetForChannel)(id, false); //
|
|
968
|
+
const offset = (0, helpers_1.offsetForChannel)(id, false); // image data is always RGBA
|
|
705
969
|
let data;
|
|
706
970
|
let compression;
|
|
707
|
-
if (
|
|
708
|
-
// console.log('written raw layer image data');
|
|
709
|
-
data = layer.imageDataRaw[id];
|
|
710
|
-
compression = layer.imageDataRawCompression[id];
|
|
711
|
-
}
|
|
712
|
-
else if (options.compress) {
|
|
971
|
+
if (options.compress) {
|
|
713
972
|
data = (0, helpers_1.writeDataZipWithoutPrediction)(imageData, [offset]);
|
|
714
973
|
compression = 2 /* Compression.ZipWithoutPrediction */;
|
|
715
974
|
}
|
|
@@ -790,11 +1049,12 @@ function writeColor(writer, color) {
|
|
|
790
1049
|
writeUint16(writer, 0);
|
|
791
1050
|
}
|
|
792
1051
|
else if ('c' in color) {
|
|
1052
|
+
// 0 = 100% ink
|
|
793
1053
|
writeUint16(writer, 2 /* ColorSpace.CMYK */);
|
|
794
|
-
writeUint16(writer, Math.round(color.c * 257));
|
|
795
|
-
writeUint16(writer, Math.round(color.m * 257));
|
|
796
|
-
writeUint16(writer, Math.round(color.y * 257));
|
|
797
|
-
writeUint16(writer, Math.round(color.k * 257));
|
|
1054
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.c, 0, 255) * 257));
|
|
1055
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.m, 0, 255) * 257));
|
|
1056
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.y, 0, 255) * 257));
|
|
1057
|
+
writeUint16(writer, 0xffff - Math.round((0, helpers_1.clamp)(color.k, 0, 255) * 257));
|
|
798
1058
|
}
|
|
799
1059
|
else {
|
|
800
1060
|
writeUint16(writer, 8 /* ColorSpace.Grayscale */);
|