ag-psd 16.0.0 → 17.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.
@@ -12,7 +12,11 @@ import {
12
12
  } from './psdWriter';
13
13
  import { createCanvasFromData, createEnum, MOCK_HANDLERS } from './helpers';
14
14
  import { decodeString, encodeString } from './utf8';
15
- import { ESliceBGColorType, ESliceHorzAlign, ESliceOrigin, ESliceType, ESliceVertAlign, FractionDescriptor, parseTrackList, readVersionAndDescriptor, serializeTrackList, TimelineTrackDescriptor, TimeScopeDescriptor, writeVersionAndDescriptor } from './descriptor';
15
+ import {
16
+ ESliceBGColorType, ESliceHorzAlign, ESliceOrigin, ESliceType, ESliceVertAlign, frac,
17
+ FractionDescriptor, parseTrackList, readVersionAndDescriptor, serializeTrackList, TimelineTrackDescriptor,
18
+ TimeScopeDescriptor, writeVersionAndDescriptor
19
+ } from './descriptor';
16
20
 
17
21
  export interface ResourceHandler {
18
22
  key: number;
@@ -660,16 +664,15 @@ addHandler(
660
664
  target => target.timelineInformation !== undefined,
661
665
  (reader, target, _, options) => {
662
666
  const desc = readVersionAndDescriptor(reader) as TimelineInformationDescriptor;
663
- // console.log('1075', require('util').inspect(desc, false, 99, true));
664
667
 
665
668
  target.timelineInformation = {
666
669
  enabled: desc.enab,
667
- frameStep: desc.frameStep,
670
+ frameStep: frac(desc.frameStep),
668
671
  frameRate: desc.frameRate,
669
- time: desc.time,
670
- duration: desc.duration,
671
- workInTime: desc.workInTime,
672
- workOutTime: desc.workOutTime,
672
+ time: frac(desc.time),
673
+ duration: frac(desc.duration),
674
+ workInTime: frac(desc.workInTime),
675
+ workOutTime: frac(desc.workOutTime),
673
676
  repeats: desc.LCnt,
674
677
  hasMotion: desc.hasMotion,
675
678
  globalTracks: parseTrackList(desc.globalTrackList, !!options.logMissingFeatures),
@@ -681,10 +684,10 @@ addHandler(
681
684
  muted: g.muted,
682
685
  audioClips: g.audioClipList.map(({ clipID, timeScope, muted, audioLevel, frameReader }) => ({
683
686
  id: clipID,
684
- start: timeScope.Strt,
685
- duration: timeScope.duration,
686
- inTime: timeScope.inTime,
687
- outTime: timeScope.outTime,
687
+ start: frac(timeScope.Strt),
688
+ duration: frac(timeScope.duration),
689
+ inTime: frac(timeScope.inTime),
690
+ outTime: frac(timeScope.outTime),
688
691
  muted: muted,
689
692
  audioLevel: audioLevel,
690
693
  frameReader: {
@@ -745,7 +748,6 @@ addHandler(
745
748
  hasMotion: timeline.hasMotion,
746
749
  };
747
750
 
748
- // console.log('WRITE:1075', require('util').inspect(desc, false, 99, true));
749
751
  writeVersionAndDescriptor(writer, '', 'null', desc, 'anim');
750
752
  },
751
753
  );
@@ -767,7 +769,6 @@ addHandler(
767
769
  target => target.sheetDisclosure !== undefined,
768
770
  (reader, target) => {
769
771
  const desc = readVersionAndDescriptor(reader) as SheetDisclosureDescriptor;
770
- // console.log('1076', require('util').inspect(desc, false, 99, true));
771
772
 
772
773
  target.sheetDisclosure = {};
773
774
 
@@ -930,7 +931,6 @@ addHandler(
930
931
  bounds: { top, left, bottom, right },
931
932
  backgroundColorType, backgroundColor: { r, g, b, a },
932
933
  });
933
- // console.log(require('util').inspect(slices[slices.length - 1], false, 99, true));
934
934
  }
935
935
  const desc = readVersionAndDescriptor(reader) as SlicesDesc;
936
936
  desc.slices.forEach(d => {
@@ -942,12 +942,8 @@ addHandler(
942
942
  slice.rightOutset = d.rightOutset;
943
943
  }
944
944
  });
945
-
946
- // console.log(require('util').inspect(desc, false, 99, true));
947
- // console.log(require('util').inspect(target.slices, false, 99, true));
948
945
  } else if (version == 7 || version == 8) {
949
946
  const desc = readVersionAndDescriptor(reader) as SlicesDesc7;
950
- // console.log(require('util').inspect(desc, false, 99, true));
951
947
 
952
948
  if (!target.slices) target.slices = [];
953
949
  target.slices.push({
@@ -1247,7 +1243,6 @@ addHandler(
1247
1243
  target => target.pathSelectionState !== undefined,
1248
1244
  (reader, target, _left) => {
1249
1245
  const desc: Descriptor1088 = readVersionAndDescriptor(reader);
1250
- // console.log(require('util').inspect(desc, false, 99, true));
1251
1246
  target.pathSelectionState = desc['null'];
1252
1247
  },
1253
1248
  (writer, target) => {
package/src/psd.ts CHANGED
@@ -674,43 +674,458 @@ export interface LinkedFile {
674
674
  assetLockedState?: number;
675
675
  }
676
676
 
677
- export interface PlacedLayerPuppetFilter {
678
- rigidType: boolean;
679
- bounds: { x: number; y: number; }[];
680
- puppetShapeList: {
677
+ type FilterVariant = {
678
+ type: 'average' | 'blur' | 'blur more';
679
+ } | {
680
+ type: 'box blur';
681
+ filter: {
682
+ radius: UnitsValue;
683
+ };
684
+ } | {
685
+ type: 'gaussian blur';
686
+ filter: {
687
+ radius: UnitsValue;
688
+ };
689
+ } | {
690
+ type: 'motion blur';
691
+ filter: {
692
+ angle: number; // in degrees
693
+ distance: UnitsValue;
694
+ };
695
+ } | {
696
+ type: 'radial blur';
697
+ filter: {
698
+ amount: number;
699
+ method: 'spin' | 'zoom';
700
+ quality: 'draft' | 'good' | 'best';
701
+ };
702
+ } | {
703
+ type: 'shape blur';
704
+ filter: {
705
+ radius: UnitsValue;
706
+ customShape: { name: string; id: string };
707
+ };
708
+ } | {
709
+ type: 'smart blur';
710
+ filter: {
711
+ radius: number;
712
+ threshold: number;
713
+ quality: 'low' | 'medium' | 'high';
714
+ mode: 'normal' | 'edge only' | 'overlay edge';
715
+ };
716
+ } | {
717
+ type: 'surface blur';
718
+ filter: {
719
+ radius: UnitsValue;
720
+ threshold: number;
721
+ };
722
+ } | {
723
+ type: 'displace';
724
+ filter: {
725
+ horizontalScale: number;
726
+ verticalScale: number;
727
+ displacementMap: 'stretch to fit' | 'tile';
728
+ undefinedAreas: 'wrap around' | 'repeat edge pixels';
729
+ displacementFile: {
730
+ signature: string;
731
+ path: string;
732
+ };
733
+ };
734
+ } | {
735
+ type: 'pinch';
736
+ filter: {
737
+ amount: number;
738
+ };
739
+ } | {
740
+ type: 'polar coordinates';
741
+ filter: {
742
+ conversion: 'rectangular to polar' | 'polar to rectangular';
743
+ };
744
+ } | {
745
+ type: 'ripple';
746
+ filter: {
747
+ amount: number;
748
+ size: 'small' | 'medium' | 'large';
749
+ };
750
+ } | {
751
+ type: 'shear';
752
+ filter: {
753
+ shearPoints: { x: number; y: number }[];
754
+ shearStart: number;
755
+ shearEnd: number;
756
+ undefinedAreas: 'wrap around' | 'repeat edge pixels';
757
+ };
758
+ } | {
759
+ type: 'spherize';
760
+ filter: {
761
+ amount: number;
762
+ mode: 'normal' | 'horizontal only' | 'vertical only';
763
+ };
764
+ } | {
765
+ type: 'twirl';
766
+ filter: {
767
+ angle: number; // degrees
768
+ };
769
+ } | {
770
+ type: 'wave';
771
+ filter: {
772
+ numberOfGenerators: number;
773
+ type: 'sine' | 'triangle' | 'square';
774
+ wavelength: { min: number; max: number };
775
+ amplitude: { min: number; max: number };
776
+ scale: { x: number; y: number };
777
+ randomSeed: number;
778
+ undefinedAreas: 'wrap around' | 'repeat edge pixels';
779
+ };
780
+ } | {
781
+ type: 'zigzag';
782
+ filter: {
783
+ amount: number;
784
+ ridges: number;
785
+ style: 'around center' | 'out from center' | 'pond ripples';
786
+ };
787
+ } | {
788
+ type: 'add noise';
789
+ filter: {
790
+ amount: number; // 0..1
791
+ distribution: 'uniform' | 'gaussian';
792
+ monochromatic: boolean;
793
+ randomSeed: number;
794
+ };
795
+ } | {
796
+ type: 'despeckle';
797
+ } | {
798
+ type: 'dust and scratches';
799
+ filter: {
800
+ radius: number; // pixels
801
+ threshold: number; // levels
802
+ };
803
+ } | {
804
+ type: 'median';
805
+ filter: {
806
+ radius: UnitsValue;
807
+ };
808
+ } | {
809
+ type: 'reduce noise';
810
+ filter: {
811
+ preset: string;
812
+ removeJpegArtifact: boolean;
813
+ reduceColorNoise: number; // 0..1
814
+ sharpenDetails: number; // 0..1
815
+ channelDenoise: {
816
+ channels: ('red' | 'green' | 'blue' | 'composite')[];
817
+ amount: number;
818
+ preserveDetails?: number; // percent
819
+ }[];
820
+ };
821
+ } | {
822
+ type: 'color halftone';
823
+ filter: {
824
+ radius: number; // pixels
825
+ angle1: number; // degrees
826
+ angle2: number; // degrees
827
+ angle3: number; // degrees
828
+ angle4: number; // degrees
829
+ };
830
+ } | {
831
+ type: 'crystallize';
832
+ filter: {
833
+ cellSize: number;
834
+ randomSeed: number;
835
+ };
836
+ } | {
837
+ type: 'facet' | 'fragment';
838
+ } | {
839
+ type: 'mezzotint';
840
+ filter: {
841
+ type: 'fine dots' | 'medium dots' | 'grainy dots' | 'coarse dots' | 'short lines' | 'medium lines' | 'long lines' | 'short strokes' | 'medium strokes' | 'long strokes';
842
+ randomSeed: number;
843
+ };
844
+ } | {
845
+ type: 'mosaic';
846
+ filter: {
847
+ cellSize: UnitsValue;
848
+ };
849
+ } | {
850
+ type: 'pointillize';
851
+ filter: {
852
+ cellSize: number;
853
+ randomSeed: number;
854
+ };
855
+ } | {
856
+ type: 'clouds';
857
+ filter: {
858
+ randomSeed: number;
859
+ };
860
+ } | {
861
+ type: 'difference clouds';
862
+ filter: {
863
+ randomSeed: number;
864
+ };
865
+ } | {
866
+ type: 'fibers';
867
+ filter: {
868
+ variance: number;
869
+ strength: number;
870
+ randomSeed: number;
871
+ };
872
+ } | {
873
+ type: 'lens flare';
874
+ filter: {
875
+ brightness: number; // percent
876
+ position: { x: number; y: number; };
877
+ lensType: '50-300mm zoom' | '32mm prime' | '105mm prime' | 'movie prime';
878
+ };
879
+ } /*| {
880
+ type: 'lighting effects';
881
+ filter: {
882
+ lights: Light3D;
883
+ cameraPosition: Position3D;
884
+ gloss: number;
885
+ metallic: number;
886
+ exposure: number;
887
+ ambience: number;
888
+ ambientColor: Color;
889
+ // TODO: BmpA, BmpC / Hotspot / color ?
890
+ width: number;
891
+ height: number;
892
+ };
893
+ }*/ | {
894
+ type: 'sharpen' | 'sharpen edges' | 'sharpen more';
895
+ } | {
896
+ type: 'smart sharpen';
897
+ filter: {
898
+ amount: number; // 0..1
899
+ radius: UnitsValue;
900
+ threshold: number;
901
+ angle: number; // degrees
902
+ moreAccurate: boolean;
903
+ blur: 'gaussian blur' | 'lens blur' | 'motion blur';
904
+ preset: string;
905
+ shadow: {
906
+ fadeAmount: number; // 0..1
907
+ tonalWidth: number; // 0..1
908
+ radius: number; // px
909
+ };
910
+ highlight: {
911
+ fadeAmount: number; // 0..1
912
+ tonalWidth: number; // 0..1
913
+ radius: number; // px
914
+ };
915
+ };
916
+ } | {
917
+ type: 'unsharp mask';
918
+ filter: {
919
+ amount: number; // 0..1
920
+ radius: UnitsValue;
921
+ threshold: number; // levels
922
+ };
923
+ } | {
924
+ type: 'diffuse';
925
+ filter: {
926
+ mode: 'normal' | 'darken only' | 'lighten only' | 'anisotropic';
927
+ randomSeed: number;
928
+ };
929
+ } | {
930
+ type: 'emboss';
931
+ filter: {
932
+ angle: number; // degrees
933
+ height: number; // pixels
934
+ amount: number; // percent
935
+ };
936
+ } | {
937
+ type: 'extrude';
938
+ filter: {
939
+ type: 'blocks' | 'pyramids';
940
+ size: number; // pixels
941
+ depth: number;
942
+ depthMode: 'random' | 'level-based';
943
+ randomSeed: number;
944
+ solidFrontFaces: boolean;
945
+ maskIncompleteBlocks: boolean;
946
+ };
947
+ } | {
948
+ type: 'find edges' | 'solarize';
949
+ } | {
950
+ type: 'tiles';
951
+ filter: {
952
+ numberOfTiles: number;
953
+ maximumOffset: number; // percent
954
+ fillEmptyAreaWith: 'background color' | 'foreground color' | 'inverse image' | 'unaltered image';
955
+ randomSeed: number;
956
+ };
957
+ } | {
958
+ type: 'trace contour';
959
+ filter: {
960
+ level: number;
961
+ edge: 'lower' | 'upper';
962
+ };
963
+ } | {
964
+ type: 'wind';
965
+ filter: {
966
+ method: 'wind' | 'blast' | 'stagger';
967
+ direction: 'left' | 'right';
968
+ };
969
+ } | {
970
+ type: 'de-interlace';
971
+ filter: {
972
+ eliminate: 'odd lines' | 'even lines';
973
+ newFieldsBy: 'duplication' | 'interpolation';
974
+ };
975
+ } | {
976
+ type: 'ntsc colors';
977
+ } | {
978
+ type: 'custom';
979
+ filter: {
980
+ scale: number;
981
+ offset: number;
982
+ matrix: number[];
983
+ };
984
+ } | {
985
+ type: 'high pass' | 'maximum' | 'minimum';
986
+ filter: {
987
+ radius: UnitsValue;
988
+ };
989
+ } | {
990
+ type: 'offset';
991
+ filter: {
992
+ horizontal: number; // pixels
993
+ vertical: number; // pixels
994
+ undefinedAreas: 'set to transparent' | 'repeat edge pixels' | 'wrap around';
995
+ };
996
+ } | {
997
+ type: 'puppet';
998
+ filter: {
681
999
  rigidType: boolean;
682
- // VrsM: number;
683
- // VrsN: number;
684
- originalVertexArray: { x: number; y: number; }[];
685
- deformedVertexArray: { x: number; y: number; }[];
686
- indexArray: number[];
687
- pinOffsets: { x: number; y: number; }[];
688
- posFinalPins: { x: number; y: number; }[];
689
- pinVertexIndices: number[];
690
- selectedPin: number[];
691
- pinPosition: { x: number; y: number; }[];
692
- pinRotation: number[]; // in degrees
693
- pinOverlay: boolean[];
694
- pinDepth: number[];
695
- meshQuality: number;
696
- meshExpansion: number;
697
- meshRigidity: number;
698
- imageResolution: number;
699
- meshBoundaryPath: {
700
- pathComponents: {
701
- shapeOperation: string;
702
- paths: {
703
- closed: boolean;
704
- points: {
705
- anchor: { x: UnitsValue; y: UnitsValue; };
706
- forward: { x: UnitsValue; y: UnitsValue; };
707
- backward: { x: UnitsValue; y: UnitsValue; };
708
- smooth: boolean;
1000
+ bounds: { x: number; y: number; }[];
1001
+ puppetShapeList: {
1002
+ rigidType: boolean;
1003
+ // VrsM: number;
1004
+ // VrsN: number;
1005
+ originalVertexArray: { x: number; y: number; }[];
1006
+ deformedVertexArray: { x: number; y: number; }[];
1007
+ indexArray: number[];
1008
+ pinOffsets: { x: number; y: number; }[];
1009
+ posFinalPins: { x: number; y: number; }[];
1010
+ pinVertexIndices: number[];
1011
+ selectedPin: number[];
1012
+ pinPosition: { x: number; y: number; }[];
1013
+ pinRotation: number[]; // in degrees
1014
+ pinOverlay: boolean[];
1015
+ pinDepth: number[];
1016
+ meshQuality: number;
1017
+ meshExpansion: number;
1018
+ meshRigidity: number;
1019
+ imageResolution: number;
1020
+ meshBoundaryPath: {
1021
+ pathComponents: {
1022
+ shapeOperation: string;
1023
+ paths: {
1024
+ closed: boolean;
1025
+ points: {
1026
+ anchor: { x: UnitsValue; y: UnitsValue; };
1027
+ forward: { x: UnitsValue; y: UnitsValue; };
1028
+ backward: { x: UnitsValue; y: UnitsValue; };
1029
+ smooth: boolean;
1030
+ }[];
709
1031
  }[];
710
1032
  }[];
711
- }[];
712
- };
713
- }[];
1033
+ };
1034
+ }[];
1035
+ };
1036
+ } | {
1037
+ type: 'oil paint plugin';
1038
+ filter: {
1039
+ name: string;
1040
+ gpu: boolean;
1041
+ lighting: boolean;
1042
+ // FPth ???
1043
+ parameters: {
1044
+ name: string;
1045
+ value: number;
1046
+ }[];
1047
+ };
1048
+ } /*| {
1049
+ type: 'lens correction';
1050
+ filter: {
1051
+ profile: string;
1052
+
1053
+ };
1054
+ }*//* | {
1055
+ type: 'adaptive wide angle';
1056
+ filter: {
1057
+ correction: 'fisheye' | 'perspective' | 'auto' | 'full spherical';
1058
+ focalLength: number;
1059
+ cropFactor: number;
1060
+ imageScale: number;
1061
+ imageX: number;
1062
+ imageY: number;
1063
+ };
1064
+ }*//* | {
1065
+ type: 'filter gallery';
1066
+ filter: {
1067
+ filter: 'colored pencil';
1068
+ pencilWidth: number;
1069
+ strokePressure: number;
1070
+ paperBrightness: number;
1071
+ } | ...;
1072
+ }*/ | {
1073
+ type: 'hsb/hsl';
1074
+ filter: {
1075
+ inputMode: 'rgb' | 'hsb' | 'hsl';
1076
+ rowOrder: 'rgb' | 'hsb' | 'hsl';
1077
+ };
1078
+ } | {
1079
+ type: 'oil paint';
1080
+ filter: {
1081
+ lightingOn: boolean;
1082
+ stylization: number;
1083
+ cleanliness: number;
1084
+ brushScale: number;
1085
+ microBrush: number;
1086
+ lightDirection: number; // degrees
1087
+ specularity: number;
1088
+ };
1089
+ } | {
1090
+ type: 'liquify';
1091
+ filter: {
1092
+ liquifyMesh: Uint8Array;
1093
+ };
1094
+ };
1095
+
1096
+ /*
1097
+ export interface Position3D {
1098
+ x: number;
1099
+ y: number;
1100
+ z: number;
1101
+ angleX: number;
1102
+ angleY: number;
1103
+ angleZ: number;
1104
+ }
1105
+
1106
+ export interface Light3D {
1107
+ name: string;
1108
+ type: 'point' | 'spot' | 'infinite';
1109
+ red: number; // 0..1
1110
+ green: number; // 0..1
1111
+ blue: number; // 0..1
1112
+ // TODO: hots
1113
+ falloff: number;
1114
+ shadow: number;
1115
+ // TODO: attn
1116
+ // TODO: attt atta, attb, attc, orad, irad, mult, Type
1117
+ // ...
1118
+ }
1119
+ */
1120
+
1121
+ export type Filter = FilterVariant & {
1122
+ name: string;
1123
+ opacity: number;
1124
+ blendMode: BlendMode;
1125
+ enabled: boolean;
1126
+ hasOptions: boolean;
1127
+ foregroundColor: Color;
1128
+ backgroundColor: Color;
714
1129
  }
715
1130
 
716
1131
  export interface PlacedLayerFilter {
@@ -719,17 +1134,7 @@ export interface PlacedLayerFilter {
719
1134
  maskEnabled: boolean;
720
1135
  maskLinked: boolean;
721
1136
  maskExtendWithWhite: boolean;
722
- list: {
723
- id: number;
724
- name: string;
725
- opacity: number;
726
- blendMode: BlendMode;
727
- enabled: boolean;
728
- hasOptions: boolean;
729
- foregroundColor: Color;
730
- backgroundColor: Color;
731
- filter: PlacedLayerPuppetFilter | {};
732
- }[];
1137
+ list: Filter[];
733
1138
  }
734
1139
 
735
1140
  export type PlacedLayerType = 'unknown' | 'vector' | 'raster' | 'image stack';
@@ -953,7 +1358,22 @@ export interface LayerAdditionalInfo {
953
1358
  unifyLayerVisibility?: boolean;
954
1359
  };
955
1360
  timeline?: Timeline;
956
- filterEffects?: any;
1361
+ filterEffectsMasks?: {
1362
+ id: string;
1363
+ top: number;
1364
+ left: number;
1365
+ bottom: number;
1366
+ right: number;
1367
+ depth: number;
1368
+ channels: ({
1369
+ compressionMode: number;
1370
+ data: Uint8Array;
1371
+ } | undefined)[];
1372
+ extra?: {
1373
+ compressionMode: number;
1374
+ data: Uint8Array;
1375
+ };
1376
+ }[];
957
1377
 
958
1378
  // Base64 encoded raw EngineData, currently just kept in original state to support
959
1379
  // loading and modifying PSD file without breaking text layers.
@@ -1165,6 +1585,7 @@ export interface Layer extends LayerAdditionalInfo {
1165
1585
  blendMode?: BlendMode;
1166
1586
  opacity?: number;
1167
1587
  transparencyProtected?: boolean;
1588
+ effectsOpen?: boolean; // effects/filters panel is expanded
1168
1589
  hidden?: boolean;
1169
1590
  clipping?: boolean;
1170
1591
  canvas?: HTMLCanvasElement;
package/src/psdReader.ts CHANGED
@@ -67,6 +67,11 @@ export function readUint16(reader: PsdReader) {
67
67
  return reader.view.getUint16(reader.offset - 2, false);
68
68
  }
69
69
 
70
+ export function readUint16LE(reader: PsdReader) {
71
+ reader.offset += 2;
72
+ return reader.view.getUint16(reader.offset - 2, true);
73
+ }
74
+
70
75
  export function readInt32(reader: PsdReader) {
71
76
  reader.offset += 4;
72
77
  return reader.view.getInt32(reader.offset - 4, false);
@@ -153,6 +158,20 @@ export function readUnicodeStringWithLength(reader: PsdReader, length: number) {
153
158
  return text;
154
159
  }
155
160
 
161
+ export function readUnicodeStringWithLengthLE(reader: PsdReader, length: number) {
162
+ let text = '';
163
+
164
+ while (length--) {
165
+ const value = readUint16LE(reader);
166
+
167
+ if (value || length > 0) { // remove trailing \0
168
+ text += String.fromCharCode(value);
169
+ }
170
+ }
171
+
172
+ return text;
173
+ }
174
+
156
175
  export function readAsciiString(reader: PsdReader, length: number) {
157
176
  let text = '';
158
177
 
@@ -379,15 +398,15 @@ function readLayerRecord(reader: PsdReader, psd: Psd, options: ReadOptionsExt) {
379
398
  const channels: ChannelInfo[] = [];
380
399
 
381
400
  for (let i = 0; i < channelCount; i++) {
382
- let channelID = readInt16(reader) as ChannelID;
383
- let channelLength = readUint32(reader);
401
+ let id = readInt16(reader) as ChannelID;
402
+ let length = readUint32(reader);
384
403
 
385
404
  if (options.large) {
386
- if (channelLength !== 0) throw new Error('Sizes larger than 4GB are not supported');
387
- channelLength = readUint32(reader);
405
+ if (length !== 0) throw new Error('Sizes larger than 4GB are not supported');
406
+ length = readUint32(reader);
388
407
  }
389
408
 
390
- channels.push({ id: channelID, length: channelLength });
409
+ channels.push({ id, length });
391
410
  }
392
411
 
393
412
  checkSignature(reader, '8BIM');
@@ -401,11 +420,11 @@ function readLayerRecord(reader: PsdReader, psd: Psd, options: ReadOptionsExt) {
401
420
  const flags = readUint8(reader);
402
421
  layer.transparencyProtected = (flags & 0x01) !== 0;
403
422
  layer.hidden = (flags & 0x02) !== 0;
423
+ if (flags & 0x20) layer.effectsOpen = true;
404
424
  // 0x04 - obsolete
405
425
  // 0x08 - 1 for Photoshop 5.0 and later, tells if bit 4 has useful information
406
426
  // 0x10 - pixel data irrelevant to appearance of document
407
- // 0x20 - ???
408
- // if (flags & 0x20) (layer as any)._2 = true; // TEMP !!!!
427
+ // 0x20 - effects/filters panel is expanded
409
428
 
410
429
  skipBytes(reader, 1);
411
430