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.
Files changed (103) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  22. package/CHANGELOG.md +78 -0
  23. package/LICENSE +5 -0
  24. package/README.md +3 -6
  25. package/README_PSD.md +242 -81
  26. package/dist/abr.d.ts +11 -4
  27. package/dist/abr.js +357 -230
  28. package/dist/abr.js.map +1 -1
  29. package/dist/additionalInfo.d.ts +54 -2
  30. package/dist/additionalInfo.js +487 -306
  31. package/dist/additionalInfo.js.map +1 -1
  32. package/dist/ase.d.ts +6 -1
  33. package/dist/ase.js +61 -61
  34. package/dist/ase.js.map +1 -1
  35. package/dist/bundle.js +1937 -1115
  36. package/dist/descriptor.d.ts +14 -8
  37. package/dist/descriptor.js +202 -186
  38. package/dist/descriptor.js.map +1 -1
  39. package/dist/helpers.d.ts +1 -1
  40. package/dist/helpers.js +4 -2
  41. package/dist/helpers.js.map +1 -1
  42. package/dist/imageResources.d.ts +15 -3
  43. package/dist/imageResources.js +503 -142
  44. package/dist/imageResources.js.map +1 -1
  45. package/dist/jpeg.js +8 -8
  46. package/dist/jpeg.js.map +1 -1
  47. package/dist/psd.d.ts +148 -17
  48. package/dist/psd.js.map +1 -1
  49. package/dist/psdReader.d.ts +10 -0
  50. package/dist/psdReader.js +278 -166
  51. package/dist/psdReader.js.map +1 -1
  52. package/dist/psdWriter.d.ts +1 -0
  53. package/dist/psdWriter.js +77 -62
  54. package/dist/psdWriter.js.map +1 -1
  55. package/dist/text.js +17 -6
  56. package/dist/text.js.map +1 -1
  57. package/dist/utf8.js +0 -3
  58. package/dist/utf8.js.map +1 -1
  59. package/dist-es/abr.d.ts +11 -4
  60. package/dist-es/abr.js +357 -230
  61. package/dist-es/abr.js.map +1 -1
  62. package/dist-es/additionalInfo.d.ts +54 -2
  63. package/dist-es/additionalInfo.js +487 -306
  64. package/dist-es/additionalInfo.js.map +1 -1
  65. package/dist-es/ase.d.ts +6 -1
  66. package/dist-es/ase.js +61 -61
  67. package/dist-es/ase.js.map +1 -1
  68. package/dist-es/descriptor.d.ts +14 -8
  69. package/dist-es/descriptor.js +202 -186
  70. package/dist-es/descriptor.js.map +1 -1
  71. package/dist-es/helpers.d.ts +1 -1
  72. package/dist-es/helpers.js +4 -2
  73. package/dist-es/helpers.js.map +1 -1
  74. package/dist-es/imageResources.d.ts +15 -3
  75. package/dist-es/imageResources.js +503 -142
  76. package/dist-es/imageResources.js.map +1 -1
  77. package/dist-es/jpeg.js +8 -8
  78. package/dist-es/jpeg.js.map +1 -1
  79. package/dist-es/psd.d.ts +148 -17
  80. package/dist-es/psd.js.map +1 -1
  81. package/dist-es/psdReader.d.ts +10 -0
  82. package/dist-es/psdReader.js +278 -166
  83. package/dist-es/psdReader.js.map +1 -1
  84. package/dist-es/psdWriter.d.ts +1 -0
  85. package/dist-es/psdWriter.js +77 -62
  86. package/dist-es/psdWriter.js.map +1 -1
  87. package/dist-es/text.js +17 -6
  88. package/dist-es/text.js.map +1 -1
  89. package/dist-es/utf8.js +0 -3
  90. package/dist-es/utf8.js.map +1 -1
  91. package/package.json +2 -2
  92. package/src/abr.ts +375 -235
  93. package/src/additionalInfo.ts +663 -420
  94. package/src/ase.ts +66 -61
  95. package/src/descriptor.ts +199 -195
  96. package/src/helpers.ts +4 -1
  97. package/src/imageResources.ts +632 -168
  98. package/src/jpeg.ts +8 -8
  99. package/src/psd.ts +156 -30
  100. package/src/psdReader.ts +273 -172
  101. package/src/psdWriter.ts +95 -58
  102. package/src/text.ts +17 -6
  103. 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, RAW_IMAGE_DATA, writeDataZipWithoutPrediction, imageDataToCanvas, denormalizeLabAB } from './helpers';
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
- writeSection(writer, 1, () => {
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, handler.key);
303
- writePascalString(writer, '', 2);
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
- if (RAW_IMAGE_DATA && (psd as any).imageDataRaw) {
322
- console.log('writing raw image data');
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
- // encode directly into the writer buffer
329
- const maxSize = channels.length * getRLEChannelBound(data.width, data.height, !!options.psb);
330
- ensureSize(writer, writer.offset + maxSize);
331
- const buffer = new Uint8Array(writer.buffer, writer.offset, maxSize);
332
- writer.offset += writeDataRLE(buffer, data, channels, !!options.psb).length;
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.tempBuffer!, l, i === 0, options));
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
- function writeLayerMaskData(writer: PsdWriter, { mask, realMask }: Layer, layerData: LayerChannelData) {
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' && options.psb) key = 'vsms';
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, layer: Layer, mask: LayerMaskData, options: WriteOptions, realMask: boolean) {
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 (RAW_IMAGE_DATA && (layer as any)[realMask ? 'realMaskDataRaw' : 'maskDataRaw']) {
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(tempBuffer: Uint8Array, layer: Layer, background: boolean, options: WriteOptions): LayerChannelData {
690
+ function getChannels(writer: PsdWriter, layer: Layer, background: boolean, options: WriteOptions): LayerChannelData {
691
+ let source = layer;
692
+
678
693
  if (layer.rawData) {
679
- return {
680
- layer,
681
- channels: layer.rawData.channels.map(c => ({ ...c, length: 2 + (c.data?.byteLength ?? 0) })),
682
- ...bounds(layer)!,
683
- mask: bounds(layer.mask),
684
- realMask: bounds(layer.realMask),
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 layerData = getLayerChannels(tempBuffer, layer, background, options);
689
- if (layer.mask) getMaskChannels(tempBuffer, layerData, layer, layer.mask, options, false);
690
- if (layer.realMask) getMaskChannels(tempBuffer, layerData, layer, layer.realMask, options, true);
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) || (RAW_IMAGE_DATA && (layer as any).imageDataRaw?.['-1'])) {
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); // TODO: psd.colorMode === ColorMode.CMYK);
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 (RAW_IMAGE_DATA && (layer as any).imageDataRaw) {
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[] = ['none', 'crisp', 'strong', 'smooth', 'sharp'];
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
- if (--result.paragraphStyleRuns[result.paragraphStyleRuns.length - 1].length === 0) {
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 (!runLength) continue; // ignore 0 size runs
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) {