ag-psd 21.0.1 → 22.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.
@@ -2,7 +2,7 @@ import { fromByteArray, toByteArray } from 'base64-js';
2
2
  import { readEffects, writeEffects } from './effectsHelpers';
3
3
  import { clamp, createEnum, layerColors, MOCK_HANDLERS } from './helpers';
4
4
  import { LayerAdditionalInfo, BezierPath, Psd, BrightnessAdjustment, ExposureAdjustment, VibranceAdjustment, ColorBalanceAdjustment, BlackAndWhiteAdjustment, PhotoFilterAdjustment, ChannelMixerChannel, ChannelMixerAdjustment, PosterizeAdjustment, ThresholdAdjustment, GradientMapAdjustment, CMYK, SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment, CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel, PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem, BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer, ReadOptions } from './psd';
5
- import { PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16, readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32, readPascalString, readUnicodeStringWithLength, readAsciiString, readPattern, readLayerInfo, ReadOptionsExt } from './psdReader';
5
+ import { PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16, readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32, readPascalString, readUnicodeStringWithLength, readAsciiString, readPattern, readLayerInfo } from './psdReader';
6
6
  import { PsdWriter, writeZeros, writeSignature, writeBytes, writeUint32, writeUint16, writeFloat64, writeUint8, writeInt16, writeFloat32, writeFixedPointPath32, writeUnicodeString, writeSection, writeUnicodeStringWithPadding, writeColor, writePascalString, writeInt32 } from './psdWriter';
7
7
  import { Annt, BlnM, DescriptorColor, DescriptorUnitsValue, parsePercent, parseUnits, parseUnitsOrNumber, QuiltWarpDescriptor, strokeStyleLineAlignment, strokeStyleLineCapType, strokeStyleLineJoinType, TextDescriptor, textGridding, unitsPercent, unitsValue, WarpDescriptor, warpStyle, writeVersionAndDescriptor, readVersionAndDescriptor, StrokeDescriptor, Ornt, horzVrtcToXY, LmfxDescriptor, Lfx2Descriptor, FrameListDescriptor, TimelineDescriptor, FrameDescriptor, xyToHorzVrtc, serializeEffects, parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList, serializeTrackList, FractionDescriptor, BlrM, BlrQ, SmBQ, SmBM, DspM, UndA, Cnvr, RplS, SphM, Wvtp, ZZTy, Dstr, Chnl, MztT, Lns, blurType, DfsM, ExtT, ExtR, FlCl, CntE, WndM, Drct, IntE, IntC, FlMd, unitsPercentF, frac, ClrS, descBoundsToBounds, boundsToDescBounds } from './descriptor';
8
8
  import { serializeEngineData, parseEngineData } from './engineData';
@@ -14,7 +14,7 @@ export interface ExtendedWriteOptions extends WriteOptions {
14
14
  }
15
15
 
16
16
  type HasMethod = (target: LayerAdditionalInfo) => boolean;
17
- type ReadMethod = (reader: PsdReader, target: LayerAdditionalInfo, left: () => number, psd: Psd, options: ReadOptionsExt) => void;
17
+ type ReadMethod = (reader: PsdReader, target: LayerAdditionalInfo, left: () => number, psd: Psd) => void;
18
18
  type WriteMethod = (writer: PsdWriter, target: LayerAdditionalInfo, psd: Psd, options: ExtendedWriteOptions) => void;
19
19
 
20
20
  export interface InfoHandler {
@@ -513,7 +513,7 @@ addHandler(
513
513
  addHandler(
514
514
  'lmfx',
515
515
  target => target.effects !== undefined && hasMultiEffects(target.effects),
516
- (reader, target, left, _, options) => {
516
+ (reader, target, left) => {
517
517
  const version = readUint32(reader);
518
518
  if (version !== 0) throw new Error('Invalid lmfx version');
519
519
 
@@ -521,7 +521,7 @@ addHandler(
521
521
  // console.log(require('util').inspect(info, false, 99, true));
522
522
 
523
523
  // discard if read in 'lrFX' or 'lfx2' section
524
- target.effects = parseEffects(desc, !!options.logMissingFeatures);
524
+ target.effects = parseEffects(desc, !!reader.logMissingFeatures);
525
525
 
526
526
  skipBytes(reader, left());
527
527
  },
@@ -550,7 +550,18 @@ addHandler(
550
550
  'luni',
551
551
  hasKey('name'),
552
552
  (reader, target, left) => {
553
- target.name = readUnicodeString(reader);
553
+ if (left() > 4) {
554
+ const length = readUint32(reader);
555
+
556
+ if (left() >= (length * 2)) {
557
+ target.name = readUnicodeStringWithLength(reader, length);
558
+ } else {
559
+ if (reader.logDevFeatures) reader.log('name in luni section is too long');
560
+ }
561
+ } else {
562
+ if (reader.logDevFeatures) reader.log('empty luni section');
563
+ }
564
+
554
565
  skipBytes(reader, left());
555
566
  },
556
567
  (writer, target) => {
@@ -722,7 +733,7 @@ addHandler(
722
733
  'shmd',
723
734
  target => target.timestamp !== undefined || target.animationFrames !== undefined ||
724
735
  target.animationFrameFlags !== undefined || target.timeline !== undefined || target.comps !== undefined,
725
- (reader, target, left, _, options) => {
736
+ (reader, target, left) => {
726
737
  const count = readUint32(reader);
727
738
 
728
739
  for (let i = 0; i < count; i++) {
@@ -748,7 +759,7 @@ addHandler(
748
759
  if (f.enab !== undefined) frame.enable = f.enab;
749
760
  if (f.Ofst) frame.offset = horzVrtcToXY(f.Ofst);
750
761
  if (f.FXRf) frame.referencePoint = horzVrtcToXY(f.FXRf);
751
- if (f.Lefx) frame.effects = parseEffects(f.Lefx, !!options.logMissingFeatures);
762
+ if (f.Lefx) frame.effects = parseEffects(f.Lefx, !!reader.logMissingFeatures);
752
763
  if (f.blendOptions && f.blendOptions.Opct) frame.opacity = parsePercent(f.blendOptions.Opct);
753
764
  target.animationFrames.push(frame);
754
765
  }
@@ -779,7 +790,7 @@ addHandler(
779
790
  };
780
791
 
781
792
  if (desc.trackList) {
782
- timeline.tracks = parseTrackList(desc.trackList, !!options.logMissingFeatures);
793
+ timeline.tracks = parseTrackList(desc.trackList, !!reader.logMissingFeatures);
783
794
  }
784
795
 
785
796
  target.timeline = timeline;
@@ -802,7 +813,7 @@ addHandler(
802
813
  if (item.FXRefPoint) t.effectsReferencePoint = { x: item.FXRefPoint.Hrzn, y: item.FXRefPoint.Vrtc };
803
814
  }
804
815
  } else {
805
- options.logMissingFeatures && console.log('Unhandled "shmd" section key', key);
816
+ reader.logMissingFeatures && reader.log('Unhandled "shmd" section key', key);
806
817
  }
807
818
 
808
819
  skipBytes(reader, left());
@@ -3209,7 +3220,7 @@ function getWarpFromPlacedLayer(placed: PlacedLayer): Warp {
3209
3220
  addHandler(
3210
3221
  'SoLd',
3211
3222
  hasKey('placedLayer'),
3212
- (reader, target, left, _, options) => {
3223
+ (reader, target, left) => {
3213
3224
  if (readSignature(reader) !== 'soLD') throw new Error(`Invalid SoLd type`);
3214
3225
  const version = readInt32(reader);
3215
3226
  if (version !== 4 && version !== 5) throw new Error(`Invalid SoLd version`);
@@ -3250,7 +3261,7 @@ addHandler(
3250
3261
  originalCompID: desc.compInfo.originalCompID,
3251
3262
  };
3252
3263
  }
3253
- if (desc.filterFX) target.placedLayer.filter = parseFilterFX(desc.filterFX, options);
3264
+ if (desc.filterFX) target.placedLayer.filter = parseFilterFX(desc.filterFX, reader);
3254
3265
 
3255
3266
  // console.log('filter', require('util').inspect(target.placedLayer.filter, false, 99, true));
3256
3267
 
@@ -3356,8 +3367,8 @@ addHandler(
3356
3367
  addHandler(
3357
3368
  'Lr16',
3358
3369
  () => false,
3359
- (reader, _target, _left, psd, options) => {
3360
- readLayerInfo(reader, psd, options);
3370
+ (reader, _target, _left, psd) => {
3371
+ readLayerInfo(reader, psd);
3361
3372
  },
3362
3373
  (_writer, _target) => {
3363
3374
  },
@@ -3366,8 +3377,8 @@ addHandler(
3366
3377
  addHandler(
3367
3378
  'Lr32',
3368
3379
  () => false,
3369
- (reader, _target, _left, psd, options) => {
3370
- readLayerInfo(reader, psd, options);
3380
+ (reader, _target, _left, psd) => {
3381
+ readLayerInfo(reader, psd);
3371
3382
  },
3372
3383
  (_writer, _target) => {
3373
3384
  },
@@ -3594,7 +3605,7 @@ interface FileOpenDescriptor {
3594
3605
  addHandler(
3595
3606
  'lnk2',
3596
3607
  (target: any) => !!(target as Psd).linkedFiles && (target as Psd).linkedFiles!.length > 0,
3597
- (reader, target, left, _, options) => {
3608
+ (reader, target, left) => {
3598
3609
  const psd = target as Psd;
3599
3610
  psd.linkedFiles = psd.linkedFiles || [];
3600
3611
 
@@ -3649,7 +3660,7 @@ addHandler(
3649
3660
  if (version >= 7) file.assetLockedState = readUint8(reader);
3650
3661
  if (type === 'liFE' && version === 2) file.data = readBytes(reader, fileSize);
3651
3662
 
3652
- if (options.skipLinkedFilesData) file.data = undefined;
3663
+ if (reader.skipLinkedFilesData) file.data = undefined;
3653
3664
 
3654
3665
  psd.linkedFiles.push(file);
3655
3666
  linkedFileDescriptor;
@@ -4836,7 +4847,7 @@ export function hasMultiEffects(effects: LayerEffectsInfo) {
4836
4847
  addHandler(
4837
4848
  'lfx2',
4838
4849
  target => target.effects !== undefined && !hasMultiEffects(target.effects),
4839
- (reader, target, left, _, options) => {
4850
+ (reader, target, left) => {
4840
4851
  const version = readUint32(reader);
4841
4852
  if (version !== 0) throw new Error(`Invalid lfx2 version`);
4842
4853
 
@@ -4845,7 +4856,7 @@ addHandler(
4845
4856
 
4846
4857
  // TODO: don't discard if we got it from lmfx
4847
4858
  // discard if read in 'lrFX' section
4848
- target.effects = parseEffects(desc, !!options.logMissingFeatures);
4859
+ target.effects = parseEffects(desc, !!reader.logMissingFeatures);
4849
4860
 
4850
4861
  skipBytes(reader, left());
4851
4862
  },
package/src/descriptor.ts CHANGED
@@ -1910,6 +1910,7 @@ export const gradientInterpolationMethodType = createEnum<InterpolationMethod>('
1910
1910
  perceptual: 'Perc',
1911
1911
  linear: 'Lnr',
1912
1912
  classic: 'Gcls',
1913
+ smooth: 'Smoo',
1913
1914
  });
1914
1915
 
1915
1916
  export const ClrS = createEnum<'rgb' | 'hsb' | 'lab'>('ClrS', 'rgb', {
@@ -31,7 +31,7 @@ const keysStyleSheet: KeysDict = {
31
31
  '8': { name: 'Tracking' },
32
32
  '9': { name: 'BaselineShift' },
33
33
  // '10': ???
34
- '11': { name: 'Kerning?' }, // different value than EngineData
34
+ '11': { name: 'Kerning?' }, // different value than EngineData (0 - numerical value, 1 - metric, 2 - optical)
35
35
  '12': { name: 'FontCaps' },
36
36
  '13': { name: 'FontBaseline' },
37
37
 
@@ -255,7 +255,7 @@ const keysRoot: KeysDict = {
255
255
  },
256
256
  },
257
257
  '1': {
258
- name: 'Editors?',
258
+ name: 'Editors?', // layer.text.index is specifying the index of the editor related to the layer
259
259
  children: {
260
260
  '0': {
261
261
  name: 'Editor',
@@ -1,5 +1,5 @@
1
1
  import { toByteArray } from 'base64-js';
2
- import { BlendMode, ImageResources, ReadOptions, RenderingIntent } from './psd';
2
+ import { BlendMode, ImageResources, RenderingIntent } from './psd';
3
3
  import {
4
4
  PsdReader, readPascalString, readUnicodeString, readUint32, readUint16, readUint8, readFloat64,
5
5
  readBytes, skipBytes, readFloat32, readInt16, readFixedPoint32, readSignature, checkSignature,
@@ -21,7 +21,7 @@ import {
21
21
  export interface ResourceHandler {
22
22
  key: number;
23
23
  has: (target: ImageResources) => boolean | number;
24
- read: (reader: PsdReader, target: ImageResources, left: () => number, options: ReadOptions) => void;
24
+ read: (reader: PsdReader, target: ImageResources, left: () => number) => void;
25
25
  write: (writer: PsdWriter, target: ImageResources, index: number) => void;
26
26
  }
27
27
 
@@ -31,7 +31,7 @@ export const resourceHandlersMap: { [key: number]: ResourceHandler } = {};
31
31
  function addHandler(
32
32
  key: number,
33
33
  has: (target: ImageResources) => boolean | number,
34
- read: (reader: PsdReader, target: ImageResources, left: () => number, options: ReadOptions) => void,
34
+ read: (reader: PsdReader, target: ImageResources, left: () => number) => void,
35
35
  write: (writer: PsdWriter, target: ImageResources, index: number) => void,
36
36
  ) {
37
37
  const handler: ResourceHandler = { key, has, read, write };
@@ -732,7 +732,7 @@ interface TimelineInformationDescriptor {
732
732
  addHandler(
733
733
  1075, // Timeline Information
734
734
  target => target.timelineInformation !== undefined,
735
- (reader, target, _, options) => {
735
+ (reader, target) => {
736
736
  const desc = readVersionAndDescriptor(reader) as TimelineInformationDescriptor;
737
737
 
738
738
  target.timelineInformation = {
@@ -745,7 +745,7 @@ addHandler(
745
745
  workOutTime: frac(desc.workOutTime),
746
746
  repeats: desc.LCnt,
747
747
  hasMotion: desc.hasMotion,
748
- globalTracks: parseTrackList(desc.globalTrackList, !!options.logMissingFeatures),
748
+ globalTracks: parseTrackList(desc.globalTrackList, !!reader.logMissingFeatures),
749
749
  };
750
750
 
751
751
  if (desc.audioClipGroupList?.audioClipGroupList?.length) {
@@ -874,13 +874,13 @@ addHandler(
874
874
  addHandler(
875
875
  1054, // URL List
876
876
  target => target.urlsList !== undefined,
877
- (reader, target, _, options) => {
877
+ (reader, target) => {
878
878
  const count = readUint32(reader);
879
879
  target.urlsList = [];
880
880
 
881
881
  for (let i = 0; i < count; i++) {
882
882
  const long = readSignature(reader);
883
- if (long !== 'slic' && options.throwForMissingFeatures) throw new Error('Unknown long');
883
+ if (long !== 'slic' && reader.throwForMissingFeatures) throw new Error('Unknown long');
884
884
  const id = readUint32(reader);
885
885
  const url = readUnicodeString(reader);
886
886
  target.urlsList.push({ id, url, ref: 'slice' });
@@ -1180,7 +1180,7 @@ addHandler(
1180
1180
  addHandler(
1181
1181
  1036,
1182
1182
  target => target.thumbnail !== undefined || target.thumbnailRaw !== undefined,
1183
- (reader, target, left, options) => {
1183
+ (reader, target, left) => {
1184
1184
  const format = readUint32(reader); // 1 = kJpegRGB, 0 = kRawRGB
1185
1185
  const width = readUint32(reader);
1186
1186
  const height = readUint32(reader);
@@ -1191,7 +1191,7 @@ addHandler(
1191
1191
  const planes = readUint16(reader); // 1
1192
1192
 
1193
1193
  if (format !== 1 || bitsPerPixel !== 24 || planes !== 1) {
1194
- options.logMissingFeatures && console.log(`Invalid thumbnail data (format: ${format}, bitsPerPixel: ${bitsPerPixel}, planes: ${planes})`);
1194
+ reader.logMissingFeatures && reader.log(`Invalid thumbnail data (format: ${format}, bitsPerPixel: ${bitsPerPixel}, planes: ${planes})`);
1195
1195
  skipBytes(reader, left());
1196
1196
  return;
1197
1197
  }
@@ -1199,7 +1199,7 @@ addHandler(
1199
1199
  const size = left();
1200
1200
  const data = readBytes(reader, size);
1201
1201
 
1202
- if (options.useRawThumbnail) {
1202
+ if (reader.useRawThumbnail) {
1203
1203
  target.thumbnailRaw = { width, height, data };
1204
1204
  } else if (data.byteLength) {
1205
1205
  target.thumbnail = createCanvasFromData(data);
@@ -1362,7 +1362,7 @@ interface AnimationsDescriptor {
1362
1362
  addHandler(
1363
1363
  4000, // Plug-In resource(s)
1364
1364
  target => target.animations !== undefined,
1365
- (reader, target, left, { logMissingFeatures, logDevFeatures }) => {
1365
+ (reader, target, left) => {
1366
1366
  const key = readSignature(reader);
1367
1367
 
1368
1368
  if (key === 'mani') {
@@ -1395,18 +1395,18 @@ addHandler(
1395
1395
  // console.log('#4000 AnDs:result', require('util').inspect(target.animations, false, 99, true));
1396
1396
  } else if (key === 'Roll') {
1397
1397
  const bytes = readBytes(reader, left());
1398
- logDevFeatures && console.log('#4000 Roll', bytes);
1398
+ reader.logDevFeatures && reader.log('#4000 Roll', bytes);
1399
1399
  } else {
1400
- logMissingFeatures && console.log('Unhandled subsection in #4000', key);
1400
+ reader.logMissingFeatures && reader.log('Unhandled subsection in #4000', key);
1401
1401
  }
1402
1402
  });
1403
1403
  }
1404
1404
  });
1405
1405
  } else if (key === 'mopt') {
1406
1406
  const bytes = readBytes(reader, left());
1407
- logDevFeatures && console.log('#4000 mopt', bytes);
1407
+ reader.logDevFeatures && reader.log('#4000 mopt', bytes);
1408
1408
  } else {
1409
- logMissingFeatures && console.log('Unhandled key in #4000:', key);
1409
+ reader.logMissingFeatures && reader.log('Unhandled key in #4000:', key);
1410
1410
  }
1411
1411
  },
1412
1412
  (writer, target) => {
@@ -1462,7 +1462,7 @@ addHandler(
1462
1462
  MOCK_HANDLERS && addHandler(
1463
1463
  4001, // Plug-In resource(s)
1464
1464
  target => (target as any)._ir4001 !== undefined,
1465
- (reader, target, left, { logMissingFeatures, logDevFeatures }) => {
1465
+ (reader, target, left) => {
1466
1466
  if (MOCK_HANDLERS) {
1467
1467
  LOG_MOCK_HANDLERS && console.log('image resource 4001', left());
1468
1468
  (target as any)._ir4001 = readBytes(reader, left());
@@ -1477,12 +1477,12 @@ MOCK_HANDLERS && addHandler(
1477
1477
 
1478
1478
  const length = readUint32(reader);
1479
1479
  const bytes = readBytes(reader, length);
1480
- logDevFeatures && console.log('mfri', bytes);
1480
+ reader.logDevFeatures && reader.log('mfri', bytes);
1481
1481
  } else if (key === 'mset') {
1482
1482
  const desc = readVersionAndDescriptor(reader);
1483
- logDevFeatures && console.log('mset', desc);
1483
+ reader.logDevFeatures && reader.log('mset', desc);
1484
1484
  } else {
1485
- logMissingFeatures && console.log('Unhandled key in #4001', key);
1485
+ reader.logMissingFeatures && reader.log('Unhandled key in #4001', key);
1486
1486
  }
1487
1487
  },
1488
1488
  (writer, target) => {
package/src/psd.ts CHANGED
@@ -205,6 +205,7 @@ export interface LayerEffectGradientOverlay {
205
205
  offset?: { x: number; y: number; };
206
206
  gradient?: EffectSolidGradient | EffectNoiseGradient;
207
207
  interpolationMethod?: InterpolationMethod;
208
+ angle?: number; // degrees
208
209
  }
209
210
 
210
211
  export interface LayerEffectsInfo {
@@ -401,7 +402,7 @@ export interface LayerTextData {
401
402
  antiAlias?: AntiAlias;
402
403
  gridding?: TextGridding;
403
404
  orientation?: Orientation;
404
- index?: number;
405
+ index?: number; // index of Editor in extra editor data related to this layer
405
406
  warp?: Warp;
406
407
  top?: number;
407
408
  left?: number;
@@ -1688,8 +1689,15 @@ export interface ReadOptions {
1688
1689
  /** Loads thumbnail raw data instead of decoding it's content into canvas.
1689
1690
  * `thumnailRaw` field is used instead. */
1690
1691
  useRawThumbnail?: boolean;
1691
- /** Usend only for development. */
1692
+
1693
+ /** Used only for development. */
1692
1694
  logDevFeatures?: boolean;
1695
+ /** Used only for development. */
1696
+ strict?: boolean;
1697
+ /** Used only for development. */
1698
+ debug?: boolean;
1699
+ /** Used only for development. */
1700
+ log?: (...args: any[]) => void;
1693
1701
  }
1694
1702
 
1695
1703
  export interface WriteOptions {