ag-psd 32.0.0 → 33.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/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/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/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 +78 -0
- package/LICENSE +5 -0
- package/README.md +3 -6
- package/README_PSD.md +242 -81
- package/dist/abr.d.ts +11 -4
- package/dist/abr.js +357 -230
- package/dist/abr.js.map +1 -1
- package/dist/additionalInfo.d.ts +54 -2
- package/dist/additionalInfo.js +487 -306
- 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 +1937 -1115
- package/dist/descriptor.d.ts +14 -8
- package/dist/descriptor.js +202 -186
- package/dist/descriptor.js.map +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.js +4 -2
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.d.ts +15 -3
- package/dist/imageResources.js +503 -142
- package/dist/imageResources.js.map +1 -1
- package/dist/jpeg.js +8 -8
- package/dist/jpeg.js.map +1 -1
- package/dist/psd.d.ts +148 -17
- package/dist/psd.js.map +1 -1
- package/dist/psdReader.d.ts +10 -0
- package/dist/psdReader.js +278 -166
- package/dist/psdReader.js.map +1 -1
- package/dist/psdWriter.d.ts +1 -0
- package/dist/psdWriter.js +77 -62
- package/dist/psdWriter.js.map +1 -1
- package/dist/text.js +17 -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 +357 -230
- package/dist-es/abr.js.map +1 -1
- package/dist-es/additionalInfo.d.ts +54 -2
- package/dist-es/additionalInfo.js +487 -306
- 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 +14 -8
- package/dist-es/descriptor.js +202 -186
- package/dist-es/descriptor.js.map +1 -1
- package/dist-es/helpers.d.ts +1 -1
- package/dist-es/helpers.js +4 -2
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.d.ts +15 -3
- package/dist-es/imageResources.js +503 -142
- package/dist-es/imageResources.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 +148 -17
- package/dist-es/psd.js.map +1 -1
- package/dist-es/psdReader.d.ts +10 -0
- package/dist-es/psdReader.js +278 -166
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/psdWriter.d.ts +1 -0
- package/dist-es/psdWriter.js +77 -62
- package/dist-es/psdWriter.js.map +1 -1
- package/dist-es/text.js +17 -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/src/abr.ts +375 -235
- package/src/additionalInfo.ts +663 -420
- package/src/ase.ts +66 -61
- package/src/descriptor.ts +199 -195
- package/src/helpers.ts +4 -1
- package/src/imageResources.ts +632 -168
- package/src/jpeg.ts +8 -8
- package/src/psd.ts +156 -30
- package/src/psdReader.ts +273 -172
- package/src/psdWriter.ts +95 -58
- package/src/text.ts +17 -6
- package/src/utf8.ts +0 -4
package/src/psdWriter.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { Psd, Layer, LayerAdditionalInfo, ColorMode, SectionDividerType, WriteOptions, Color, GlobalLayerMaskInfo, PixelData, LayerMaskData, Compression, ChannelID, PatternInfo } from './psd';
|
|
2
|
-
import { hasAlpha, createCanvas, writeDataRLE, LayerChannelData, ChannelData, offsetForChannel, createImageData, fromBlendMode, clamp, LayerMaskFlags, MaskParams, ColorSpace, Bounds, largeAdditionalInfoKeys,
|
|
3
|
-
import { ExtendedWriteOptions, infoHandlers } from './additionalInfo';
|
|
2
|
+
import { hasAlpha, createCanvas, writeDataRLE, LayerChannelData, ChannelData, offsetForChannel, createImageData, fromBlendMode, clamp, LayerMaskFlags, MaskParams, ColorSpace, Bounds, largeAdditionalInfoKeys, writeDataZipWithoutPrediction, imageDataToCanvas, denormalizeLabAB } from './helpers';
|
|
3
|
+
import { ExtendedWriteOptions, infoHandlers, infoHandlersMap } from './additionalInfo';
|
|
4
4
|
import { InternalImageResources, resourceHandlers } from './imageResources';
|
|
5
|
+
import { getCompositeImageData, getLayerImageData, getLayerMaskImageData, getLayerRealMaskImageData } from './psdReader';
|
|
5
6
|
|
|
6
7
|
export interface PsdWriter {
|
|
7
8
|
offset: number;
|
|
8
9
|
buffer: ArrayBuffer;
|
|
9
10
|
view: DataView;
|
|
10
11
|
tempBuffer: Uint8Array | undefined;
|
|
12
|
+
log(...args: any[]): void;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export function createWriter(size = 4096): PsdWriter {
|
|
14
16
|
const buffer = new ArrayBuffer(size);
|
|
15
17
|
const view = new DataView(buffer);
|
|
16
18
|
const offset = 0;
|
|
17
|
-
return { buffer, view, offset, tempBuffer: undefined };
|
|
19
|
+
return { buffer, view, offset, tempBuffer: undefined, log: console.log };
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function getWriterBuffer(writer: PsdWriter) {
|
|
@@ -241,6 +243,8 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
241
243
|
if (bitsPerChannel !== 8)
|
|
242
244
|
throw new Error('bitsPerChannel other than 8 are not supported for writing');
|
|
243
245
|
|
|
246
|
+
if (options.log) writer.log = options.log;
|
|
247
|
+
|
|
244
248
|
const layers: Layer[] = [];
|
|
245
249
|
addChildren(layers, psd.children);
|
|
246
250
|
if (!layers.length) layers.push({});
|
|
@@ -250,6 +254,18 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
250
254
|
const imageResources: InternalImageResources = { ...psd.imageResources };
|
|
251
255
|
const opt: ExtendedWriteOptions = { ...options, layerIds: new Set(), layerToId: new Map() };
|
|
252
256
|
|
|
257
|
+
// document is always written in RGB color mode, skip resources specific to original color mode
|
|
258
|
+
if (psd.colorMode !== undefined && psd.colorMode !== ColorMode.RGB) {
|
|
259
|
+
delete imageResources.iccProfile;
|
|
260
|
+
delete imageResources.indexedColorCount;
|
|
261
|
+
delete imageResources.transparencyIndex;
|
|
262
|
+
delete imageResources.alphaChannelDisplayInfo;
|
|
263
|
+
delete imageResources.colorHalftoneScreens;
|
|
264
|
+
delete imageResources.grayscaleHalftoneScreens;
|
|
265
|
+
delete imageResources.colorTransferFunctions;
|
|
266
|
+
delete imageResources.grayscaleTransferFunctions;
|
|
267
|
+
}
|
|
268
|
+
|
|
253
269
|
if (opt.generateThumbnail) {
|
|
254
270
|
imageResources.thumbnail = createThumbnail(psd);
|
|
255
271
|
}
|
|
@@ -260,6 +276,10 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
260
276
|
imageData = psd.canvas.getContext('2d')!.getImageData(0, 0, psd.canvas.width, psd.canvas.height);
|
|
261
277
|
}
|
|
262
278
|
|
|
279
|
+
if (!imageData && psd.rawCompositeData) { // read with `useRawData` option
|
|
280
|
+
imageData = getCompositeImageData(psd);
|
|
281
|
+
}
|
|
282
|
+
|
|
263
283
|
if (imageData && (psd.width !== imageData.width || psd.height !== imageData.height))
|
|
264
284
|
throw new Error('Document canvas must have the same size as document');
|
|
265
285
|
|
|
@@ -277,16 +297,8 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
277
297
|
writeUint16(writer, bitsPerChannel); // bits per channel
|
|
278
298
|
writeUint16(writer, ColorMode.RGB); // we only support saving RGB right now
|
|
279
299
|
|
|
280
|
-
// color mode data
|
|
281
|
-
|
|
282
|
-
if (psd.palette) {
|
|
283
|
-
for (let i = 0; i < 256; i++) writeUint8(writer, psd.palette[i]?.r || 0);
|
|
284
|
-
for (let i = 0; i < 256; i++) writeUint8(writer, psd.palette[i]?.g || 0);
|
|
285
|
-
for (let i = 0; i < 256; i++) writeUint8(writer, psd.palette[i]?.b || 0);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// TODO: other data?
|
|
289
|
-
});
|
|
300
|
+
// color mode data (empty for RGB color mode)
|
|
301
|
+
writeUint32(writer, 0);
|
|
290
302
|
|
|
291
303
|
// image resources
|
|
292
304
|
|
|
@@ -298,10 +310,12 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
298
310
|
const has = handler.has(imageResources);
|
|
299
311
|
const count = has === false ? 0 : (has === true ? 1 : has);
|
|
300
312
|
for (let i = 0; i < count; i++) {
|
|
313
|
+
const id = handler.keyCount > 1 ? handler.key + i : handler.key;
|
|
314
|
+
const name = handler.name ? handler.name(imageResources, i) : '';
|
|
301
315
|
writeSignature(writer, '8BIM');
|
|
302
|
-
writeUint16(writer,
|
|
303
|
-
writePascalString(writer,
|
|
304
|
-
writeSection(writer, 2, () => handler.write(writer, imageResources, i));
|
|
316
|
+
writeUint16(writer, id);
|
|
317
|
+
writePascalString(writer, name, 2);
|
|
318
|
+
writeSection(writer, 2, () => handler.write(writer, imageResources, i, psd));
|
|
305
319
|
}
|
|
306
320
|
}
|
|
307
321
|
});
|
|
@@ -318,19 +332,14 @@ export function writePsd(writer: PsdWriter, psd: Psd, options: WriteOptions = {}
|
|
|
318
332
|
// image data
|
|
319
333
|
writeUint16(writer, Compression.RleCompressed); // Photoshop doesn't support zip compression of composite image data
|
|
320
334
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
writeBytes(writer, (psd as any).imageDataRaw);
|
|
324
|
-
} else {
|
|
325
|
-
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
326
|
-
const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
|
|
335
|
+
const channels = globalAlpha ? [0, 1, 2, 3] : [0, 1, 2];
|
|
336
|
+
const data = getCompositeData(imageData, psd.width, psd.height, globalAlpha);
|
|
327
337
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
338
|
+
// encode directly into the writer buffer
|
|
339
|
+
const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
|
|
340
|
+
ensureSize(writer, writer.offset + maxSize);
|
|
341
|
+
const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
|
|
342
|
+
writer.offset += writeDataRLE(buffer, data, channels, !!options.psb).length;
|
|
334
343
|
}
|
|
335
344
|
|
|
336
345
|
function getCompositeData(imageData: PixelData | undefined, width: number, height: number, globalAlpha: boolean): PixelData {
|
|
@@ -362,7 +371,7 @@ function writeLayerInfo(writer: PsdWriter, layers: Layer[], psd: Psd, globalAlph
|
|
|
362
371
|
writeSection(writer, 4, () => {
|
|
363
372
|
writeInt16(writer, globalAlpha ? -layers.length : layers.length);
|
|
364
373
|
|
|
365
|
-
const layersData = layers.map((l, i) => getChannels(writer
|
|
374
|
+
const layersData = layers.map((l, i) => getChannels(writer, l, i === 0, options));
|
|
366
375
|
|
|
367
376
|
// layer records
|
|
368
377
|
for (const layerData of layersData) {
|
|
@@ -419,7 +428,14 @@ function writeLayerInfo(writer: PsdWriter, layers: Layer[], psd: Psd, globalAlph
|
|
|
419
428
|
}, true, options.psb);
|
|
420
429
|
}
|
|
421
430
|
|
|
422
|
-
|
|
431
|
+
// real mask is only stored separately if layer has both vector and pixel masks, otherwise it's stored as the main mask
|
|
432
|
+
function getMasks(layer: Layer) {
|
|
433
|
+
return layer.mask ? { mask: layer.mask, realMask: layer.realMask } : { mask: layer.realMask, realMask: undefined };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function writeLayerMaskData(writer: PsdWriter, layer: Layer, layerData: LayerChannelData) {
|
|
437
|
+
const { mask, realMask } = getMasks(layer);
|
|
438
|
+
|
|
423
439
|
writeSection(writer, 4, () => {
|
|
424
440
|
if (!mask && !realMask) return;
|
|
425
441
|
|
|
@@ -512,13 +528,13 @@ function writeAdditionalLayerInfo(writer: PsdWriter, target: LayerAdditionalInfo
|
|
|
512
528
|
let key = handler.key;
|
|
513
529
|
|
|
514
530
|
if (key === 'Txt2' && options.invalidateTextLayers) continue;
|
|
515
|
-
if (key === 'vmsk' &&
|
|
531
|
+
if (key === 'vmsk' && infoHandlersMap['vscg'].has(target)) key = 'vsms'; // Photoshop uses 'vsms' for layers with vector stroke
|
|
516
532
|
|
|
517
533
|
if (handler.has(target)) {
|
|
518
534
|
const large = options.psb && largeAdditionalInfoKeys.indexOf(key) !== -1;
|
|
519
535
|
const writeTotalLength = key !== 'Txt2' && key !== 'cinf' && key !== 'extn' && key !== 'CAI ' && key !== 'OCIO';
|
|
520
536
|
const fourBytes = key === 'levl' || key === 'Txt2' || key === 'luni' || key === 'vmsk' || key === 'artb' || key === 'artd' ||
|
|
521
|
-
key === 'vogk' || key === 'SoLd' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
537
|
+
key === 'vogk' || key === 'SoLd' || key === 'SoLE' || key === 'lnk2' || key === 'vscg' || key === 'vsms' || key === 'GdFl' ||
|
|
522
538
|
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';
|
|
523
539
|
|
|
524
540
|
writeSignature(writer, large ? '8B64' : '8BIM');
|
|
@@ -624,7 +640,7 @@ function createThumbnail(psd: Psd) {
|
|
|
624
640
|
return canvas;
|
|
625
641
|
}
|
|
626
642
|
|
|
627
|
-
function getMaskChannels(tempBuffer: Uint8Array, layerData: LayerChannelData,
|
|
643
|
+
function getMaskChannels(tempBuffer: Uint8Array, layerData: LayerChannelData, mask: LayerMaskData, options: WriteOptions, realMask: boolean) {
|
|
628
644
|
let top = (mask.top as any) | 0;
|
|
629
645
|
let left = (mask.left as any) | 0;
|
|
630
646
|
let right = (mask.right as any) | 0;
|
|
@@ -646,10 +662,7 @@ function getMaskChannels(tempBuffer: Uint8Array, layerData: LayerChannelData, la
|
|
|
646
662
|
let buffer: Uint8Array;
|
|
647
663
|
let compression: Compression;
|
|
648
664
|
|
|
649
|
-
if (
|
|
650
|
-
buffer = (layer as any)[realMask ? 'realMaskDataRaw' : 'maskDataRaw'];
|
|
651
|
-
compression = (layer as any)[realMask ? 'realMaskDataRawCompression' : 'maskDataRawCompression'];
|
|
652
|
-
} else if (!imageData) {
|
|
665
|
+
if (!imageData) {
|
|
653
666
|
buffer = new Uint8Array(0);
|
|
654
667
|
compression = Compression.RleCompressed;
|
|
655
668
|
} else if (options.compress) {
|
|
@@ -674,20 +687,47 @@ function bounds(obj: { top?: number; left?: number; bottom?: number; right?: num
|
|
|
674
687
|
} : undefined;
|
|
675
688
|
}
|
|
676
689
|
|
|
677
|
-
function getChannels(
|
|
690
|
+
function getChannels(writer: PsdWriter, layer: Layer, background: boolean, options: WriteOptions): LayerChannelData {
|
|
691
|
+
let source = layer;
|
|
692
|
+
|
|
678
693
|
if (layer.rawData) {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
mask
|
|
684
|
-
|
|
694
|
+
const { colorMode, bitsPerChannel, large } = layer.rawData;
|
|
695
|
+
|
|
696
|
+
if (large === !!options.psb && colorMode === ColorMode.RGB && bitsPerChannel === 8) {
|
|
697
|
+
// same mask mapping as in writeLayerMaskData
|
|
698
|
+
const { mask, realMask } = getMasks(layer);
|
|
699
|
+
return {
|
|
700
|
+
layer,
|
|
701
|
+
channels: layer.rawData.channels.map(c => ({ ...c, length: 2 + (c.data?.byteLength ?? 0) })),
|
|
702
|
+
...bounds(layer)!,
|
|
703
|
+
mask: bounds(mask),
|
|
704
|
+
realMask: bounds(realMask),
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (bitsPerChannel !== 8) throw new Error('Layer raw data with bitsPerChannel other than 8 is not supported for writing');
|
|
709
|
+
|
|
710
|
+
// raw data is in different format than the one we're writing, decode it so it can be re-encoded
|
|
711
|
+
source = {
|
|
712
|
+
...layer,
|
|
713
|
+
rawData: undefined,
|
|
714
|
+
canvas: undefined,
|
|
715
|
+
imageData: getLayerImageData(layer),
|
|
716
|
+
mask: layer.mask && { ...layer.mask, canvas: undefined, imageData: getLayerMaskImageData(layer) },
|
|
717
|
+
realMask: layer.realMask && { ...layer.realMask, canvas: undefined, imageData: getLayerRealMaskImageData(layer) },
|
|
685
718
|
};
|
|
719
|
+
|
|
720
|
+
// temp buffer is sized only for layers with image data, grow it and keep it for following layers
|
|
721
|
+
const size = getLargestLayerSize([{ ...source, children: undefined }], !!options.psb);
|
|
722
|
+
if (writer.tempBuffer!.byteLength < size) writer.tempBuffer = new Uint8Array(size);
|
|
686
723
|
}
|
|
687
724
|
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
725
|
+
const tempBuffer = writer.tempBuffer!;
|
|
726
|
+
const { mask, realMask } = getMasks(source);
|
|
727
|
+
const layerData = getLayerChannels(tempBuffer, source, background, options);
|
|
728
|
+
if (mask) getMaskChannels(tempBuffer, layerData, mask, options, false);
|
|
729
|
+
if (realMask) getMaskChannels(tempBuffer, layerData, realMask, options, true);
|
|
730
|
+
layerData.layer = layer;
|
|
691
731
|
return layerData;
|
|
692
732
|
}
|
|
693
733
|
|
|
@@ -768,20 +808,16 @@ function getLayerChannels(tempBuffer: Uint8Array, layer: Layer, background: bool
|
|
|
768
808
|
ChannelID.Color2,
|
|
769
809
|
];
|
|
770
810
|
|
|
771
|
-
if (!background || options.noBackground || layer.mask || hasAlpha(imageData)
|
|
811
|
+
if (!background || options.noBackground || layer.mask || hasAlpha(imageData)) {
|
|
772
812
|
channelIds.unshift(ChannelID.Transparency);
|
|
773
813
|
}
|
|
774
814
|
|
|
775
815
|
channels = channelIds.map(id => {
|
|
776
|
-
const offset = offsetForChannel(id, false); //
|
|
816
|
+
const offset = offsetForChannel(id, false); // image data is always RGBA
|
|
777
817
|
let data: Uint8Array;
|
|
778
818
|
let compression: Compression;
|
|
779
819
|
|
|
780
|
-
if (
|
|
781
|
-
// console.log('written raw layer image data');
|
|
782
|
-
data = (layer as any).imageDataRaw[id];
|
|
783
|
-
compression = (layer as any).imageDataRawCompression[id];
|
|
784
|
-
} else if (options.compress) {
|
|
820
|
+
if (options.compress) {
|
|
785
821
|
data = writeDataZipWithoutPrediction(imageData, [offset]);
|
|
786
822
|
compression = Compression.ZipWithoutPrediction;
|
|
787
823
|
} else {
|
|
@@ -868,11 +904,12 @@ export function writeColor(writer: PsdWriter, color: Color | undefined) {
|
|
|
868
904
|
writeUint16(writer, Math.round(color.b * 0xffff));
|
|
869
905
|
writeUint16(writer, 0);
|
|
870
906
|
} else if ('c' in color) {
|
|
907
|
+
// 0 = 100% ink
|
|
871
908
|
writeUint16(writer, ColorSpace.CMYK);
|
|
872
|
-
writeUint16(writer, Math.round(color.c * 257));
|
|
873
|
-
writeUint16(writer, Math.round(color.m * 257));
|
|
874
|
-
writeUint16(writer, Math.round(color.y * 257));
|
|
875
|
-
writeUint16(writer, Math.round(color.k * 257));
|
|
909
|
+
writeUint16(writer, 0xffff - Math.round(clamp(color.c, 0, 255) * 257));
|
|
910
|
+
writeUint16(writer, 0xffff - Math.round(clamp(color.m, 0, 255) * 257));
|
|
911
|
+
writeUint16(writer, 0xffff - Math.round(clamp(color.y, 0, 255) * 257));
|
|
912
|
+
writeUint16(writer, 0xffff - Math.round(clamp(color.k, 0, 255) * 257));
|
|
876
913
|
} else {
|
|
877
914
|
writeUint16(writer, ColorSpace.Grayscale);
|
|
878
915
|
writeUint16(writer, Math.round(color.k * 10000 / 255));
|
package/src/text.ts
CHANGED
|
@@ -274,7 +274,16 @@ const styleKeys: (keyof TextStyle)[] = [
|
|
|
274
274
|
'kashida', 'diacriticPos',
|
|
275
275
|
];
|
|
276
276
|
|
|
277
|
-
const antialias: AntiAlias[] = [
|
|
277
|
+
const antialias: (AntiAlias | undefined)[] = [
|
|
278
|
+
'none', // 0
|
|
279
|
+
'crisp', // 1
|
|
280
|
+
'strong', // 2
|
|
281
|
+
'smooth', // 3
|
|
282
|
+
'sharp', // 4
|
|
283
|
+
undefined, // 5 - unknown
|
|
284
|
+
'platformLCD', // 6
|
|
285
|
+
'platform', // 7
|
|
286
|
+
];
|
|
278
287
|
const justification: Justification[] = [
|
|
279
288
|
'left', // 0
|
|
280
289
|
'right', // 1
|
|
@@ -360,8 +369,9 @@ function objectsEqual(a: any, b: any) {
|
|
|
360
369
|
}
|
|
361
370
|
|
|
362
371
|
function findOrAddFont(fonts: Font[], font: Font) {
|
|
372
|
+
// Photoshop writes separate entries for the same font with different synthetic (faux bold/italic) styles
|
|
363
373
|
for (let i = 0; i < fonts.length; i++) {
|
|
364
|
-
if (fonts[i].name === font.name) return i;
|
|
374
|
+
if (fonts[i].name === font.name && (fonts[i].synthetic || 0) === (font.synthetic || 0)) return i;
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
fonts.push(font);
|
|
@@ -578,7 +588,8 @@ export function decodeEngineData(engineData: EngineData) {
|
|
|
578
588
|
}
|
|
579
589
|
|
|
580
590
|
for (let counter = removedCharacters; result.paragraphStyleRuns.length && counter > 0; counter--) {
|
|
581
|
-
|
|
591
|
+
// keep 0 length run if it's for empty last paragraph, otherwise we lose its style
|
|
592
|
+
if (--result.paragraphStyleRuns[result.paragraphStyleRuns.length - 1].length === 0 && result.paragraphStyleRuns.length === 1) {
|
|
582
593
|
result.paragraphStyleRuns.pop();
|
|
583
594
|
}
|
|
584
595
|
}
|
|
@@ -671,14 +682,14 @@ export function encodeEngineData(data: LayerTextData) {
|
|
|
671
682
|
let runLength = Math.min(run.length, leftLength);
|
|
672
683
|
leftLength -= runLength;
|
|
673
684
|
|
|
674
|
-
if (
|
|
675
|
-
|
|
676
|
-
// extend last run if it's only for trailing \r
|
|
685
|
+
// extend last run if it's only for trailing \r (last run has 0 length if it's for empty last paragraph)
|
|
677
686
|
if (leftLength === 1 && run === paragraphRuns[paragraphRuns.length - 1]) {
|
|
678
687
|
runLength++;
|
|
679
688
|
leftLength--;
|
|
680
689
|
}
|
|
681
690
|
|
|
691
|
+
if (!runLength) continue; // ignore 0 size runs
|
|
692
|
+
|
|
682
693
|
paragraphRunLengthArray.push(runLength);
|
|
683
694
|
paragraphRunArray.push({
|
|
684
695
|
ParagraphSheet: {
|
package/src/utf8.ts
CHANGED
|
@@ -113,10 +113,6 @@ export function encodeString(value: string): Uint8Array {
|
|
|
113
113
|
// UTF-8 decoder implementing the WHATWG Encoding Standard's non-fatal error handling,
|
|
114
114
|
// so malformed byte sequences are replaced with U+FFFD instead of throwing, matching TextDecoder.
|
|
115
115
|
export function decodeString(value: Uint8Array): string {
|
|
116
|
-
if (value.byteLength > 1000 && typeof TextDecoder !== 'undefined') {
|
|
117
|
-
return (new TextDecoder()).decode(value);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
116
|
const result: string[] = [];
|
|
121
117
|
|
|
122
118
|
function pushCodePoint(code: number) {
|