ag-psd 31.0.3 → 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 (159) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/00d0e0b4 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/0cc76730 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/20729831 +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/214a593b +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/25f8b84a +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/27518289 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/330ef2d9 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/37ff16b8 +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/3f72a97c +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/75efccd4 +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/762f9305 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/7bcfc50a +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  22. package/.v8-cache/v24.7.0-x64-ef5a0af0/825e9a05 +0 -0
  23. package/.v8-cache/v24.7.0-x64-ef5a0af0/87372817 +0 -0
  24. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  25. package/.v8-cache/v24.7.0-x64-ef5a0af0/891a7c73 +0 -0
  26. package/.v8-cache/v24.7.0-x64-ef5a0af0/8b68a3a2 +0 -0
  27. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  28. package/.v8-cache/v24.7.0-x64-ef5a0af0/a1d12a93 +0 -0
  29. package/.v8-cache/v24.7.0-x64-ef5a0af0/a7e80865 +0 -0
  30. package/.v8-cache/v24.7.0-x64-ef5a0af0/ac317c9c +0 -0
  31. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  32. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  33. package/.v8-cache/v24.7.0-x64-ef5a0af0/b8569d6b +0 -0
  34. package/.v8-cache/v24.7.0-x64-ef5a0af0/b8b073c4 +0 -0
  35. package/.v8-cache/v24.7.0-x64-ef5a0af0/bb489c89 +0 -0
  36. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  37. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  38. package/.v8-cache/v24.7.0-x64-ef5a0af0/c46725e1 +0 -0
  39. package/.v8-cache/v24.7.0-x64-ef5a0af0/c794cb34 +0 -0
  40. package/.v8-cache/v24.7.0-x64-ef5a0af0/cd4ae980 +0 -0
  41. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  42. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  43. package/.v8-cache/v24.7.0-x64-ef5a0af0/d02dd6f7 +0 -0
  44. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  45. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  46. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6735171 +0 -0
  47. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  48. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  49. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  50. package/.v8-cache/v24.7.0-x64-ef5a0af0/f5417276 +0 -0
  51. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  52. package/.v8-cache/v24.7.0-x64-ef5a0af0/f74d3518 +0 -0
  53. package/.v8-cache/v24.7.0-x64-ef5a0af0/f886deac +0 -0
  54. package/.v8-cache/v24.7.0-x64-ef5a0af0/fd0a2987 +0 -0
  55. package/.v8-cache/v24.7.0-x64-ef5a0af0/fe349423 +0 -0
  56. package/CHANGELOG.md +107 -0
  57. package/LICENSE +5 -0
  58. package/README.md +3 -6
  59. package/README_PSD.md +242 -81
  60. package/dist/abr.d.ts +11 -4
  61. package/dist/abr.js +363 -229
  62. package/dist/abr.js.map +1 -1
  63. package/dist/additionalInfo.d.ts +56 -2
  64. package/dist/additionalInfo.js +600 -364
  65. package/dist/additionalInfo.js.map +1 -1
  66. package/dist/ase.d.ts +6 -1
  67. package/dist/ase.js +61 -61
  68. package/dist/ase.js.map +1 -1
  69. package/dist/bundle.js +3096 -1541
  70. package/dist/descriptor.d.ts +25 -6
  71. package/dist/descriptor.js +380 -135
  72. package/dist/descriptor.js.map +1 -1
  73. package/dist/effectsHelpers.js +12 -12
  74. package/dist/effectsHelpers.js.map +1 -1
  75. package/dist/engineData.d.ts +3 -1
  76. package/dist/engineData.js +34 -13
  77. package/dist/engineData.js.map +1 -1
  78. package/dist/engineData2.js +50 -21
  79. package/dist/engineData2.js.map +1 -1
  80. package/dist/helpers.d.ts +6 -3
  81. package/dist/helpers.js +22 -6
  82. package/dist/helpers.js.map +1 -1
  83. package/dist/imageResources.d.ts +15 -3
  84. package/dist/imageResources.js +529 -144
  85. package/dist/imageResources.js.map +1 -1
  86. package/dist/index.js +1 -0
  87. package/dist/index.js.map +1 -1
  88. package/dist/jpeg.js +30 -10
  89. package/dist/jpeg.js.map +1 -1
  90. package/dist/psd.d.ts +154 -18
  91. package/dist/psd.js.map +1 -1
  92. package/dist/psdReader.d.ts +12 -2
  93. package/dist/psdReader.js +720 -421
  94. package/dist/psdReader.js.map +1 -1
  95. package/dist/psdWriter.d.ts +3 -0
  96. package/dist/psdWriter.js +167 -130
  97. package/dist/psdWriter.js.map +1 -1
  98. package/dist/text.js +143 -29
  99. package/dist/text.js.map +1 -1
  100. package/dist/utf8.js +36 -18
  101. package/dist/utf8.js.map +1 -1
  102. package/dist-es/abr.d.ts +11 -4
  103. package/dist-es/abr.js +363 -229
  104. package/dist-es/abr.js.map +1 -1
  105. package/dist-es/additionalInfo.d.ts +56 -2
  106. package/dist-es/additionalInfo.js +600 -364
  107. package/dist-es/additionalInfo.js.map +1 -1
  108. package/dist-es/ase.d.ts +6 -1
  109. package/dist-es/ase.js +61 -61
  110. package/dist-es/ase.js.map +1 -1
  111. package/dist-es/descriptor.d.ts +25 -6
  112. package/dist-es/descriptor.js +380 -135
  113. package/dist-es/descriptor.js.map +1 -1
  114. package/dist-es/effectsHelpers.js +12 -12
  115. package/dist-es/effectsHelpers.js.map +1 -1
  116. package/dist-es/engineData.d.ts +3 -1
  117. package/dist-es/engineData.js +34 -13
  118. package/dist-es/engineData.js.map +1 -1
  119. package/dist-es/engineData2.js +50 -21
  120. package/dist-es/engineData2.js.map +1 -1
  121. package/dist-es/helpers.d.ts +6 -3
  122. package/dist-es/helpers.js +22 -6
  123. package/dist-es/helpers.js.map +1 -1
  124. package/dist-es/imageResources.d.ts +15 -3
  125. package/dist-es/imageResources.js +529 -144
  126. package/dist-es/imageResources.js.map +1 -1
  127. package/dist-es/index.js +1 -0
  128. package/dist-es/index.js.map +1 -1
  129. package/dist-es/jpeg.js +30 -10
  130. package/dist-es/jpeg.js.map +1 -1
  131. package/dist-es/psd.d.ts +154 -18
  132. package/dist-es/psd.js.map +1 -1
  133. package/dist-es/psdReader.d.ts +12 -2
  134. package/dist-es/psdReader.js +720 -421
  135. package/dist-es/psdReader.js.map +1 -1
  136. package/dist-es/psdWriter.d.ts +3 -0
  137. package/dist-es/psdWriter.js +167 -130
  138. package/dist-es/psdWriter.js.map +1 -1
  139. package/dist-es/text.js +143 -29
  140. package/dist-es/text.js.map +1 -1
  141. package/dist-es/utf8.js +36 -18
  142. package/dist-es/utf8.js.map +1 -1
  143. package/package.json +2 -2
  144. package/src/abr.ts +380 -232
  145. package/src/additionalInfo.ts +781 -477
  146. package/src/ase.ts +66 -61
  147. package/src/descriptor.ts +386 -142
  148. package/src/effectsHelpers.ts +9 -9
  149. package/src/engineData.ts +36 -13
  150. package/src/engineData2.ts +468 -432
  151. package/src/helpers.ts +23 -5
  152. package/src/imageResources.ts +658 -167
  153. package/src/index.ts +1 -0
  154. package/src/jpeg.ts +27 -12
  155. package/src/psd.ts +158 -30
  156. package/src/psdReader.ts +732 -414
  157. package/src/psdWriter.ts +186 -132
  158. package/src/text.ts +139 -18
  159. package/src/utf8.ts +35 -21
@@ -11,12 +11,15 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.IntC = exports.IntE = exports.Drct = exports.WndM = exports.CntE = exports.FlCl = exports.ExtR = exports.ExtT = exports.DfsM = exports.blurType = exports.Lns = exports.MztT = exports.Chnl = exports.Dstr = exports.ZZTy = exports.Wvtp = exports.SphM = exports.RplS = exports.Cnvr = exports.UndA = exports.DspM = exports.SmBQ = exports.SmBM = exports.BlrQ = exports.BlrM = exports.strokeStyleLineAlignment = exports.strokeStyleLineJoinType = exports.strokeStyleLineCapType = exports.ESliceBGColorType = exports.ESliceOrigin = exports.ESliceVertAlign = exports.ESliceHorzAlign = exports.ESliceType = exports.FrFl = exports.FStl = exports.ClrS = exports.gradientInterpolationMethodType = exports.stdTrackID = exports.animInterpStyleEnum = exports.GrdT = exports.IGSr = exports.BETE = exports.BESs = exports.bvlT = exports.BESl = exports.BlnM = exports.warpStyle = exports.Annt = exports.Ornt = exports.textGridding = void 0;
15
- exports.presetKindType = exports.prjM = exports.FlMd = void 0;
14
+ exports.Drct = exports.WndM = exports.CntE = exports.FlCl = exports.ExtR = exports.ExtT = exports.DfsM = exports.blurType = exports.Lns = exports.MztT = exports.Chnl = exports.Dstr = exports.ZZTy = exports.Wvtp = exports.SphM = exports.RplS = exports.Cnvr = exports.UndA = exports.DspM = exports.SmBQ = exports.SmBM = exports.BlrQ = exports.BlrM = exports.strokeStyleLineAlignment = exports.strokeStyleLineJoinType = exports.strokeStyleLineCapType = exports.ESliceBGColorType = exports.ESliceOrigin = exports.ESliceVertAlign = exports.ESliceHorzAlign = exports.ESliceType = exports.FrFl = exports.FStl = exports.ClrS = exports.Clry = exports.gradientInterpolationMethodType = exports.stdTrackID = exports.animInterpStyleEnum = exports.GrdT = exports.IGSr = exports.BETE = exports.BESs = exports.bvlT = exports.BESl = exports.BlnM = exports.warpStyle = exports.Annt = exports.Ornt = exports.textGridding = exports.outputSettingsRoot = void 0;
15
+ exports.presetKindType = exports.prjM = exports.FlMd = exports.IntC = exports.IntE = void 0;
16
16
  exports.setLogErrors = setLogErrors;
17
17
  exports.readAsciiStringOrClassId = readAsciiStringOrClassId;
18
+ exports.writeAsciiStringOrClassId = writeAsciiStringOrClassId;
18
19
  exports.readDescriptorStructure = readDescriptorStructure;
19
20
  exports.writeDescriptorStructure = writeDescriptorStructure;
21
+ exports.pathSelectionStateToReference = pathSelectionStateToReference;
22
+ exports.writeClassStructure = writeClassStructure;
20
23
  exports.readVersionAndDescriptor = readVersionAndDescriptor;
21
24
  exports.writeVersionAndDescriptor = writeVersionAndDescriptor;
22
25
  exports.horzVrtcToXY = horzVrtcToXY;
@@ -155,12 +158,15 @@ const fieldToExtType = {
155
158
  origFXRefPoint: nullType,
156
159
  FXRefPoint: nullType,
157
160
  ClMg: makeType('', 'ClMg'),
161
+ interpretation: makeType('', 'footageInterpretation'),
162
+ bgColor: makeType('', 'NativeQuad'),
158
163
  };
159
164
  const fieldToArrayExtType = {
160
165
  'Crv ': makeType('', 'CrPt'),
161
166
  Clrs: makeType('', 'Clrt'),
162
167
  Trns: makeType('', 'TrnS'),
163
168
  keyDescriptorList: nullType,
169
+ keyRootDescriptorList: nullType,
164
170
  solidFillMulti: makeType('', 'SoFi'),
165
171
  gradientFillMulti: makeType('', 'GrFl'),
166
172
  dropShadowMulti: makeType('', 'DrSh'),
@@ -188,20 +194,29 @@ const fieldToArrayExtType = {
188
194
  layerSettings: nullType,
189
195
  list: nullType,
190
196
  Adjs: makeType('', 'CrvA'),
197
+ vertices: makeType('', 'Pnt '),
198
+ warpedVertices: makeType('', 'Pnt '),
199
+ quads: makeType('', 'quadIndices'),
191
200
  };
192
201
  const typeToField = {
193
202
  'TEXT': [
194
- 'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
203
+ 'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName', 'exportOption', 'scaleSettings',
204
+ 'BackgroundImagePath', 'ImageSubfolderName',
195
205
  'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
196
206
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
197
- 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath',
207
+ 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath', 'Bk ', 'pathUnicodeName',
198
208
  ],
199
209
  'tdta': [
200
210
  'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
201
- 'LqMe',
211
+ 'LqMe', 'bookKey',
202
212
  ],
203
213
  'long': [
204
- 'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
214
+ 'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ', 'bookID',
215
+ 'cropRectBottom', 'cropRectLeft', 'cropRectRight', 'cropRectTop',
216
+ // save for web output settings
217
+ 'Version', 'BackgroundColorBlue', 'BackgroundColorGreen', 'BackgroundColorRed', 'BackgroundColorState', 'AttributeCase', 'Encoding',
218
+ 'DuplicateFileNameBehavior', 'ImageMapLocation', 'ImageMapType', 'Indent', 'LineEndings', 'SpacersEmptyCells',
219
+ 'SpacersHorizontal', 'SpacersVertical', 'StylesFormat', 'TDWidthHeight', 'TagCase', 'ColorPolicy', 'MetadataPolicy',
205
220
  'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'comp', 'compID', 'originalCompID',
206
221
  'curvesPresetKind', 'mixerPresetKind', 'uOrder', 'vOrder', 'PgNm', 'totalPages', 'Crop',
207
222
  'numerator', 'denominator', 'frameCount', 'Annt', 'keyOriginType', 'unitValueQuadVersion',
@@ -213,6 +228,7 @@ const typeToField = {
213
228
  'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
214
229
  'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
215
230
  'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
231
+ 'pixelSourceType',
216
232
  ],
217
233
  'enum': [
218
234
  'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
@@ -222,7 +238,8 @@ const typeToField = {
222
238
  'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
223
239
  'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
224
240
  'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
225
- 'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
241
+ 'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod', 'pathSymmetryMode',
242
+ 'interpretAlpha',
226
243
  ],
227
244
  'bool': [
228
245
  'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
@@ -235,14 +252,15 @@ const typeToField = {
235
252
  'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
236
253
  'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
237
254
  'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
238
- 'moreAccurate', 'GpuY', 'LIWy', 'Cnty',
255
+ 'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn',
239
256
  ],
240
257
  'doub': [
241
- 'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
258
+ 'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght', 'Gmm ',
242
259
  'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
243
260
  'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
244
261
  'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
245
- 'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3'
262
+ 'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3',
263
+ 'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity',
246
264
  ],
247
265
  'UntF': [
248
266
  'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
@@ -251,29 +269,60 @@ const typeToField = {
251
269
  'topRight', 'topLeft', 'bottomLeft', 'bottomRight', 'ClNs', 'Shrp',
252
270
  ],
253
271
  'VlLs': [
254
- 'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
272
+ 'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'keyRootDescriptorList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
255
273
  'LaSt', 'Trnf', 'nonAffineTransform', 'keyDescriptorList', 'guideIndeces', 'gradientFillMulti',
256
274
  'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
257
275
  'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
258
276
  'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
259
277
  'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList', 'ShrP',
260
278
  'channelDenoise', 'Mtrx', 'layerSettings', 'list', 'compList', 'Adjs',
279
+ 'vertices', 'warpedVertices', 'quads', 'indices', 'Mpng',
261
280
  ],
262
281
  'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
263
282
  'obj ': ['null', 'Chnl'],
264
283
  'Pth ': ['DspF'],
284
+ 'alis': ['alis'],
265
285
  };
266
286
  const channels = [
267
287
  'Rd ', 'Grn ', 'Bl ', 'Yllw', 'Ylw ', 'Cyn ', 'Mgnt', 'Blck', 'Gry ', 'Lmnc', 'A ', 'B ',
268
288
  ];
289
+ // color classes whose channel values are written as doubles ('GRYC' and 'LABC' are kept for backwards compatibility)
290
+ const doubleColorClasses = ['Grsc', 'LbCl', 'GRYC', 'LABC'];
291
+ // fallback for unknown keys, based on the type of the value
292
+ function guessOSType(value) {
293
+ if (typeof value === 'boolean')
294
+ return 'bool';
295
+ if (typeof value === 'number' && !Number.isInteger(value))
296
+ return 'doub';
297
+ if (Array.isArray(value))
298
+ return 'VlLs';
299
+ if (value && typeof value === 'object') {
300
+ if (typeof value._classID === 'string')
301
+ return 'Objc';
302
+ if (typeof value.classID === 'string')
303
+ return 'type'; // class read from 'type' or 'GlbC'
304
+ if (typeof value.low === 'number' && typeof value.high === 'number')
305
+ return 'comp';
306
+ if (typeof value.units === 'string' && typeof value.value === 'number')
307
+ return 'UntF';
308
+ }
309
+ return undefined;
310
+ }
269
311
  const fieldToArrayType = {
270
312
  'Mnm ': 'long',
271
313
  'Mxm ': 'long',
314
+ HtmlFileNameComponents: 'long', // save for web output settings
315
+ SavingFileNameComponents: 'long',
316
+ SliceFileNameComponents: 'long',
317
+ Inpt: 'long', // levels filter
318
+ Otpt: 'long', // levels filter
272
319
  FrLs: 'long',
273
320
  strokeStyleLineDashSet: 'UntF',
274
321
  Trnf: 'doub',
275
322
  nonAffineTransform: 'doub',
276
323
  keyDescriptorList: 'Objc',
324
+ keyRootDescriptorList: 'Objc',
325
+ pathList: 'Objc',
277
326
  gradientFillMulti: 'Objc',
278
327
  solidFillMulti: 'Objc',
279
328
  frameFXMulti: 'Objc',
@@ -305,6 +354,8 @@ const fieldToArrayType = {
305
354
  Mtrx: 'long',
306
355
  compList: 'long',
307
356
  Chnl: 'enum',
357
+ indices: 'long',
358
+ Mpng: 'long',
308
359
  };
309
360
  const fieldToType = {};
310
361
  for (const type of Object.keys(typeToField)) {
@@ -319,6 +370,7 @@ for (const field of Object.keys(fieldToExtType)) {
319
370
  for (const field of Object.keys(fieldToArrayExtType)) {
320
371
  fieldToArrayType[field] = 'Objc';
321
372
  }
373
+ const pixelSourceOriginRoot = 'PixelSource.origin';
322
374
  function getTypeByKey(key, value, root, parent) {
323
375
  if (key === 'presetKind') {
324
376
  return typeof value === 'string' ? 'enum' : 'long';
@@ -338,7 +390,7 @@ function getTypeByKey(key, value, root, parent) {
338
390
  else if (key === 'AntA') {
339
391
  return typeof value === 'string' ? 'enum' : 'bool';
340
392
  }
341
- else if ((key === 'Hrzn' || key === 'Vrtc') && (parent.Type === 'keyType.Pstn' || parent._classID === 'Ofst')) {
393
+ else if ((key === 'Hrzn' || key === 'Vrtc') && (parent.Type === 'keyType.Pstn' || parent._classID === 'Ofst' || root === pixelSourceOriginRoot)) {
342
394
  return 'long';
343
395
  }
344
396
  else if (key === 'Hrzn' || key === 'Vrtc' || key === 'Top ' || key === 'Left' || key === 'Btom' || key === 'Rght') {
@@ -355,6 +407,24 @@ function getTypeByKey(key, value, root, parent) {
355
407
  else if (key === 'Trnf') {
356
408
  return Array.isArray(value) ? 'VlLs' : 'Objc';
357
409
  }
410
+ else if (key === 'alpha' && root === 'slices') {
411
+ return 'long';
412
+ }
413
+ else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'HsbP') {
414
+ return 'enum';
415
+ }
416
+ else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'LvlA') {
417
+ return 'VlLs';
418
+ }
419
+ else if (key === 'Intr' && typeof value === 'boolean') {
420
+ return 'bool'; // interpolation in print style
421
+ }
422
+ else if (key === 'PgPs') {
423
+ return 'enum';
424
+ }
425
+ else if (key === 'LghD' && parent._classID === 'oilPaint') {
426
+ return 'long';
427
+ }
358
428
  else {
359
429
  return fieldToType[key];
360
430
  }
@@ -364,7 +434,7 @@ function readAsciiStringOrClassId(reader) {
364
434
  return (0, psdReader_1.readAsciiString)(reader, length || 4);
365
435
  }
366
436
  function writeAsciiStringOrClassId(writer, value) {
367
- if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list') {
437
+ if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list' && value !== 'json') {
368
438
  // write classId
369
439
  (0, psdWriter_1.writeInt32)(writer, 0);
370
440
  (0, psdWriter_1.writeSignature)(writer, value);
@@ -392,29 +462,36 @@ function readDescriptorStructure(reader, includeClass) {
392
462
  }
393
463
  return object;
394
464
  }
465
+ exports.outputSettingsRoot = 'outputSettings';
395
466
  function writeDescriptorStructure(writer, name, classId, value, root) {
396
467
  if (logErrors && !classId)
397
468
  console.log('Missing classId for: ', name, classId, value);
398
469
  // write class structure
399
470
  (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
400
- writeAsciiStringOrClassId(writer, classId);
401
- const keys = Object.keys(value);
402
- let keyCount = keys.length;
403
- if ('_name' in value)
404
- keyCount--;
405
- if ('_classID' in value)
406
- keyCount--;
407
- (0, psdWriter_1.writeUint32)(writer, keyCount);
471
+ if (root === exports.outputSettingsRoot && classId === 'null') {
472
+ // Photoshop writes 'null' class id as 4 character string in save for web output settings
473
+ (0, psdWriter_1.writeInt32)(writer, 4);
474
+ (0, psdWriter_1.writeSignature)(writer, classId);
475
+ }
476
+ else {
477
+ writeAsciiStringOrClassId(writer, classId);
478
+ }
479
+ const allKeys = Object.keys(value);
480
+ const keys = allKeys.filter(key => key !== '_name' && key !== '_classID' && value[key] !== undefined);
481
+ (0, psdWriter_1.writeUint32)(writer, keys.length);
408
482
  for (const key of keys) {
409
- if (key === '_name' || key === '_classID')
410
- continue;
411
483
  let type = getTypeByKey(key, value[key], root, value);
484
+ let childRoot = root;
412
485
  let extType = fieldToExtType[key];
413
486
  if (key === 'bounds' && root === 'text') {
414
487
  extType = makeType('', 'bounds');
415
488
  }
416
489
  else if (key === 'origin') {
417
490
  type = root === 'slices' ? 'enum' : 'Objc';
491
+ if (classId === 'PixelSource') {
492
+ extType = nullType; // stored as 'null' class with integer Hrzn/Vrtc
493
+ childRoot = pixelSourceOriginRoot;
494
+ }
418
495
  }
419
496
  else if ((key === 'Cyn ' || key === 'Mgnt' || key === 'Ylw ' || key === 'Blck') && value._classID === 'CMYC') {
420
497
  type = 'doub';
@@ -482,10 +559,14 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
482
559
  extType = nullType;
483
560
  }
484
561
  else if (channels.indexOf(key) !== -1) {
485
- type = (classId === 'RGBC' && root !== 'artd') ? 'doub' : 'long';
562
+ type = ((classId === 'RGBC' && root !== 'artd') || doubleColorClasses.indexOf(classId) !== -1) ? 'doub' : 'long';
486
563
  }
487
564
  else if (key === 'profile') {
488
- type = classId === 'printOutput' ? 'TEXT' : 'tdta';
565
+ type = (classId === 'printOutput' || classId === 'proofSetup') ? 'TEXT' : 'tdta';
566
+ }
567
+ else if (key === 'alis' && typeof value[key] === 'string') {
568
+ // 'alis' is read as a binary string (one char per byte), strings with wider chars can only be stored as TEXT
569
+ type = /[^\x00-\xff]/.test(value[key]) ? 'TEXT' : 'alis';
489
570
  }
490
571
  else if (key === 'strokeStyleContent') {
491
572
  if (value[key]['Clr ']) {
@@ -504,14 +585,22 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
504
585
  else if (key === 'bounds' && root === 'quiltWarp') {
505
586
  extType = makeType('', 'classFloatRect');
506
587
  }
588
+ // guess color class from its fields (colors created by serializeColor always have _classID set)
507
589
  if (extType && extType.classID === 'RGBC') {
508
590
  if ('H ' in value[key])
509
591
  extType = { classID: 'HSBC', name: '' };
510
- // TODO: other color spaces
592
+ else if ('Cyn ' in value[key])
593
+ extType = { classID: 'CMYC', name: '' };
594
+ else if ('Lmnc' in value[key])
595
+ extType = { classID: 'LbCl', name: '' };
596
+ else if ('Gry ' in value[key])
597
+ extType = { classID: 'Grsc', name: '' };
511
598
  }
599
+ if (!type)
600
+ type = guessOSType(value[key]);
512
601
  writeAsciiStringOrClassId(writer, key);
513
602
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
514
- writeOSType(writer, type || 'long', value[key], key, extType, root);
603
+ writeOSType(writer, type || 'long', value[key], key, extType, childRoot);
515
604
  if (logErrors && !type)
516
605
  console.log(`Missing descriptor field type for: '${key}' in`, value);
517
606
  }
@@ -579,7 +668,7 @@ function readOSType(reader, type, includeClass) {
579
668
  case 'ObAr': { // Object array
580
669
  (0, psdReader_1.readInt32)(reader); // version: 16
581
670
  (0, psdReader_1.readUnicodeString)(reader); // name: ''
582
- readAsciiStringOrClassId(reader); // 'rationalPoint'
671
+ readAsciiStringOrClassId(reader); // classID: 'rationalPoint'
583
672
  const length = (0, psdReader_1.readInt32)(reader);
584
673
  const items = [];
585
674
  for (let i = 0; i < length; i++) {
@@ -613,6 +702,7 @@ const ObArTypes = {
613
702
  quiltSliceY: 'UntF',
614
703
  };
615
704
  function writeOSType(writer, type, value, key, extType, root) {
705
+ var _a;
616
706
  switch (type) {
617
707
  case 'obj ': // Reference
618
708
  writeReferenceStructure(writer, key, value);
@@ -621,9 +711,9 @@ function writeOSType(writer, type, value, key, extType, root) {
621
711
  case 'GlbO': { // GlobalObject same as Descriptor
622
712
  if (typeof value !== 'object')
623
713
  throw new Error(`Invalid struct value: ${JSON.stringify(value)}, key: ${key}`);
624
- if (!extType)
714
+ if (!extType && !value._classID)
625
715
  throw new Error(`Missing ext type for: '${key}' (${JSON.stringify(value)})`);
626
- const name = value._name || extType.name;
716
+ const name = value._name || (extType === null || extType === void 0 ? void 0 : extType.name) || '';
627
717
  const classID = value._classID || extType.classID;
628
718
  writeDescriptorStructure(writer, name, classID, value, root);
629
719
  break;
@@ -633,7 +723,7 @@ function writeOSType(writer, type, value, key, extType, root) {
633
723
  throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
634
724
  (0, psdWriter_1.writeInt32)(writer, value.length);
635
725
  for (let i = 0; i < value.length; i++) {
636
- const type = fieldToArrayType[key];
726
+ const type = (_a = fieldToArrayType[key]) !== null && _a !== void 0 ? _a : guessOSType(value[i]);
637
727
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
638
728
  writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
639
729
  if (logErrors && !type)
@@ -671,20 +761,35 @@ function writeOSType(writer, type, value, key, extType, root) {
671
761
  case 'long': // Integer
672
762
  if (typeof value !== 'number')
673
763
  throw new Error(`Invalid integer value: ${JSON.stringify(value)}, key: ${key}`);
674
- (0, psdWriter_1.writeInt32)(writer, value);
764
+ (0, psdWriter_1.writeInt32)(writer, Math.round(value)); // round instead of truncating fractional values
765
+ break;
766
+ case 'comp': // Large Integer
767
+ if (!value || typeof value !== 'object')
768
+ throw new Error(`Invalid large integer value: ${JSON.stringify(value)}, key: ${key}`);
769
+ (0, psdWriter_1.writeUint32)(writer, value.low >>> 0);
770
+ (0, psdWriter_1.writeUint32)(writer, value.high >>> 0);
675
771
  break;
676
- // case 'comp': // Large Integer
677
- // writeLargeInteger(reader);
678
772
  case 'bool': // Boolean
679
773
  if (typeof value !== 'boolean')
680
774
  throw new Error(`Invalid boolean value: ${JSON.stringify(value)}, key: ${key}`);
681
775
  (0, psdWriter_1.writeUint8)(writer, value ? 1 : 0);
682
776
  break;
683
- // case 'type': // Class
684
- // case 'GlbC': // Class
685
- // writeClassStructure(reader);
686
- // case 'alis': // Alias
687
- // writeAliasStructure(reader);
777
+ case 'type': // Class
778
+ case 'GlbC': // Class
779
+ if (!value || typeof value !== 'object')
780
+ throw new Error(`Invalid class value: ${JSON.stringify(value)}, key: ${key}`);
781
+ (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, value.name || '');
782
+ writeAsciiStringOrClassId(writer, value.classID);
783
+ break;
784
+ case 'alis': { // Alias (read as a binary string, one char per byte)
785
+ if (typeof value !== 'string')
786
+ throw new Error(`Invalid alias value: ${JSON.stringify(value)}, key: ${key}`);
787
+ (0, psdWriter_1.writeInt32)(writer, value.length);
788
+ for (let i = 0; i < value.length; i++) {
789
+ (0, psdWriter_1.writeUint8)(writer, value.charCodeAt(i) & 0xff);
790
+ }
791
+ break;
792
+ }
688
793
  case 'tdta': // Raw Data
689
794
  (0, psdWriter_1.writeInt32)(writer, value.byteLength);
690
795
  (0, psdWriter_1.writeBytes)(writer, value);
@@ -709,97 +814,127 @@ function writeOSType(writer, type, value, key, extType, root) {
709
814
  break;
710
815
  }
711
816
  case 'Pth ': { // File path
712
- const length = 4 + 4 + 4 + value.path.length * 2;
817
+ const path = value.path + '\0'; // Photoshop stores trailing null character (stripped when reading)
818
+ const length = 4 + 4 + 4 + path.length * 2;
713
819
  (0, psdWriter_1.writeInt32)(writer, length);
714
820
  (0, psdWriter_1.writeSignature)(writer, value.sig);
715
821
  (0, psdWriter_1.writeInt32LE)(writer, length);
716
- (0, psdWriter_1.writeInt32LE)(writer, value.path.length);
717
- (0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer, value.path);
822
+ (0, psdWriter_1.writeInt32LE)(writer, path.length);
823
+ (0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer, path);
718
824
  break;
719
825
  }
720
826
  default:
721
827
  throw new Error(`Not implemented descriptor OSType: ${type}`);
722
828
  }
723
829
  }
830
+ const referenceTypes = ['prop', 'Clss', 'Enmr', 'rele', 'Idnt', 'indx', 'name'];
831
+ function isReferenceItem(value) {
832
+ return !!value && typeof value === 'object' && referenceTypes.indexOf(value.type) !== -1;
833
+ }
724
834
  function readReferenceStructure(reader) {
725
835
  const itemsCount = (0, psdReader_1.readInt32)(reader);
726
836
  const items = [];
727
837
  for (let i = 0; i < itemsCount; i++) {
728
838
  const type = (0, psdReader_1.readSignature)(reader);
729
839
  switch (type) {
730
- case 'prop': { // Property
840
+ case 'prop': // Property
731
841
  readClassStructure(reader);
732
- const keyID = readAsciiStringOrClassId(reader);
733
- items.push(keyID);
842
+ items.push(readAsciiStringOrClassId(reader));
734
843
  break;
735
- }
736
844
  case 'Clss': // Class
737
845
  items.push(readClassStructure(reader));
738
846
  break;
739
847
  case 'Enmr': { // Enumerated Reference
740
848
  readClassStructure(reader);
741
849
  const typeID = readAsciiStringOrClassId(reader);
742
- const value = readAsciiStringOrClassId(reader);
743
- items.push(`${typeID}.${value}`);
850
+ const enumValue = readAsciiStringOrClassId(reader);
851
+ items.push(`${typeID}.${enumValue}`);
744
852
  break;
745
853
  }
746
- case 'rele': { // Offset
747
- // const { name, classID } =
854
+ case 'rele': // Offset
748
855
  readClassStructure(reader);
749
856
  items.push((0, psdReader_1.readUint32)(reader));
750
857
  break;
751
- }
752
858
  case 'Idnt': // Identifier
753
- items.push((0, psdReader_1.readInt32)(reader));
754
- break;
755
859
  case 'indx': // Index
756
860
  items.push((0, psdReader_1.readInt32)(reader));
757
861
  break;
758
- case 'name': { // Name
862
+ case 'name': // Name
759
863
  readClassStructure(reader);
760
864
  items.push((0, psdReader_1.readUnicodeString)(reader));
761
865
  break;
762
- }
763
866
  default:
764
867
  throw new Error(`Invalid descriptor reference type: ${type}`);
765
868
  }
766
869
  }
767
870
  return items;
768
871
  }
872
+ function guessReferenceItem(value) {
873
+ if (typeof value === 'string') {
874
+ // enumerated references are read as `${typeID}.${enumValue}` where typeID is a 4 character ID or a string ID
875
+ // (values like 'My.Path' or 'Logo.v2' can't be typeID/enum value, so they are written as name references)
876
+ const match = /^([a-z ]{4}|[a-z]{5,})\.([a-z ]+)$/i.exec(value);
877
+ if (match) {
878
+ return { type: 'Enmr', _name: '', _classID: match[1], typeID: match[1], enumValue: match[2] };
879
+ }
880
+ else {
881
+ return { type: 'name', _name: '', _classID: 'Lyr ', value };
882
+ }
883
+ }
884
+ else if (typeof value === 'number') {
885
+ return { type: 'Idnt', value };
886
+ }
887
+ else if (value && typeof value === 'object' && typeof value.classID === 'string') {
888
+ return { type: 'Clss', _name: value.name || '', _classID: value.classID };
889
+ }
890
+ else {
891
+ throw new Error(`Invalid descriptor reference value: ${JSON.stringify(value)}`);
892
+ }
893
+ }
894
+ // path selection state (image resource 1088) is a reference to paths, enumerated references there use 'Path' class
895
+ // (name references use 'Lyr ' class, they reference layer of the vector mask)
896
+ function pathSelectionStateToReference(items) {
897
+ return items.map(value => {
898
+ const item = guessReferenceItem(value);
899
+ if (item.type === 'Enmr')
900
+ item._classID = 'Path';
901
+ return item;
902
+ });
903
+ }
769
904
  function writeReferenceStructure(writer, _key, items) {
905
+ if (!Array.isArray(items))
906
+ throw new Error(`Invalid reference value: ${JSON.stringify(items)}, key: ${_key}`);
770
907
  (0, psdWriter_1.writeInt32)(writer, items.length);
771
- for (let i = 0; i < items.length; i++) {
772
- const value = items[i];
773
- let type = 'unknown';
774
- if (typeof value === 'string') {
775
- if (/^[a-z ]+\.[a-z ]+$/i.test(value)) {
776
- type = 'Enmr';
777
- }
778
- else {
779
- type = 'name';
780
- }
781
- }
782
- (0, psdWriter_1.writeSignature)(writer, type);
783
- switch (type) {
784
- // case 'prop': // Property
785
- // case 'Clss': // Class
786
- case 'Enmr': { // Enumerated Reference
787
- const [typeID, enumValue] = value.split('.');
788
- writeClassStructure(writer, '\0', typeID);
789
- writeAsciiStringOrClassId(writer, typeID);
790
- writeAsciiStringOrClassId(writer, enumValue);
908
+ for (const value of items) {
909
+ const item = isReferenceItem(value) ? value : guessReferenceItem(value);
910
+ (0, psdWriter_1.writeSignature)(writer, item.type);
911
+ switch (item.type) {
912
+ case 'prop': // Property
913
+ writeClassStructure(writer, item._name || '', item._classID);
914
+ writeAsciiStringOrClassId(writer, item.keyID);
791
915
  break;
792
- }
793
- // case 'rele': // Offset
794
- // case 'Idnt': // Identifier
795
- // case 'indx': // Index
796
- case 'name': { // Name
797
- writeClassStructure(writer, '\0', 'Lyr ');
798
- (0, psdWriter_1.writeUnicodeString)(writer, value + '\0');
916
+ case 'Clss': // Class
917
+ writeClassStructure(writer, item._name || '', item._classID);
918
+ break;
919
+ case 'Enmr': // Enumerated Reference
920
+ writeClassStructure(writer, item._name || '', item._classID);
921
+ writeAsciiStringOrClassId(writer, item.typeID);
922
+ writeAsciiStringOrClassId(writer, item.enumValue);
923
+ break;
924
+ case 'rele': // Offset
925
+ writeClassStructure(writer, item._name || '', item._classID);
926
+ (0, psdWriter_1.writeUint32)(writer, item.value);
927
+ break;
928
+ case 'Idnt': // Identifier
929
+ case 'indx': // Index
930
+ (0, psdWriter_1.writeInt32)(writer, item.value);
931
+ break;
932
+ case 'name': // Name
933
+ writeClassStructure(writer, item._name || '', item._classID);
934
+ (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, `${item.value}`);
799
935
  break;
800
- }
801
936
  default:
802
- throw new Error(`Invalid descriptor reference type: ${type}`);
937
+ throw new Error(`Invalid descriptor reference type: ${item.type}`);
803
938
  }
804
939
  }
805
940
  return items;
@@ -810,7 +945,7 @@ function readClassStructure(reader) {
810
945
  return { name, classID };
811
946
  }
812
947
  function writeClassStructure(writer, name, classID) {
813
- (0, psdWriter_1.writeUnicodeString)(writer, name);
948
+ (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
814
949
  writeAsciiStringOrClassId(writer, classID);
815
950
  }
816
951
  function readVersionAndDescriptor(reader, includeClass = false) {
@@ -854,7 +989,7 @@ function parseFxObject(fx) {
854
989
  fillType: exports.FrFl.decode(fx.PntT),
855
990
  blendMode: exports.BlnM.decode(fx['Md ']),
856
991
  opacity: parsePercent(fx.Opct),
857
- size: parseUnits(fx['Sz ']),
992
+ size: parseUnitsOrNumber(fx['Sz ']), // stored as number (pixels) in old versions
858
993
  };
859
994
  if (fx.present !== undefined)
860
995
  stroke.present = fx.present;
@@ -942,9 +1077,11 @@ function serializeEffects(e, log, multi) {
942
1077
  info.numModifyingFX = 0;
943
1078
  for (const key of Object.keys(e)) {
944
1079
  const value = e[key];
1080
+ if (value == null || typeof value !== 'object')
1081
+ continue;
945
1082
  if (Array.isArray(value)) {
946
1083
  for (const effect of value) {
947
- if (effect.enabled)
1084
+ if (effect === null || effect === void 0 ? void 0 : effect.enabled)
948
1085
  info.numModifyingFX++;
949
1086
  }
950
1087
  }
@@ -957,11 +1094,11 @@ function serializeEffects(e, log, multi) {
957
1094
  }
958
1095
  function parseEffects(info, log) {
959
1096
  const effects = {};
960
- const { masterFXSwitch, DrSh, dropShadowMulti, IrSh, innerShadowMulti, OrGl, IrGl, ebbl, SoFi, solidFillMulti, patternFill, GrFl, gradientFillMulti, ChFX, FrFX, frameFXMulti, numModifyingFX } = info, rest = __rest(info, ["masterFXSwitch", "DrSh", "dropShadowMulti", "IrSh", "innerShadowMulti", "OrGl", "IrGl", "ebbl", "SoFi", "solidFillMulti", "patternFill", "GrFl", "gradientFillMulti", "ChFX", "FrFX", "frameFXMulti", "numModifyingFX"]);
1097
+ const _a = info, { _name, _classID, 'Scl ': scale, masterFXSwitch, DrSh, dropShadowMulti, IrSh, innerShadowMulti, OrGl, IrGl, ebbl, SoFi, solidFillMulti, patternFill, GrFl, gradientFillMulti, ChFX, FrFX, frameFXMulti, numModifyingFX } = _a, rest = __rest(_a, ["_name", "_classID", 'Scl ', "masterFXSwitch", "DrSh", "dropShadowMulti", "IrSh", "innerShadowMulti", "OrGl", "IrGl", "ebbl", "SoFi", "solidFillMulti", "patternFill", "GrFl", "gradientFillMulti", "ChFX", "FrFX", "frameFXMulti", "numModifyingFX"]);
961
1098
  if (!masterFXSwitch)
962
1099
  effects.disabled = true;
963
- if (info['Scl '])
964
- effects.scale = parsePercent(info['Scl ']);
1100
+ if (scale)
1101
+ effects.scale = parsePercent(scale);
965
1102
  if (DrSh)
966
1103
  effects.dropShadow = [parseEffectObject(DrSh, log)];
967
1104
  if (dropShadowMulti)
@@ -975,7 +1112,7 @@ function parseEffects(info, log) {
975
1112
  if (IrGl)
976
1113
  effects.innerGlow = parseEffectObject(IrGl, log);
977
1114
  if (ebbl)
978
- effects.bevel = parseEffectObject(ebbl, log);
1115
+ effects.bevel = parseEffectObject(ebbl, log, 'bevel');
979
1116
  if (SoFi)
980
1117
  effects.solidFill = [parseEffectObject(SoFi, log)];
981
1118
  if (solidFillMulti)
@@ -992,7 +1129,7 @@ function parseEffects(info, log) {
992
1129
  effects.stroke = [parseFxObject(FrFX)];
993
1130
  if (frameFXMulti)
994
1131
  effects.stroke = frameFXMulti.map(i => parseFxObject(i));
995
- if (log && Object.keys(rest).length > 1)
1132
+ if (log && Object.keys(rest).length)
996
1133
  console.log('Unhandled effect keys:', rest);
997
1134
  return effects;
998
1135
  }
@@ -1093,7 +1230,7 @@ function serializeTrackList(tracks) {
1093
1230
  const t = tracks[i];
1094
1231
  trackList.push(Object.assign(Object.assign({ trackID: exports.stdTrackID.encode(t.type), Vrsn: 1, enab: !!t.enabled, Effc: !!t.effectParams }, (t.effectParams ? {
1095
1232
  effectParams: {
1096
- keyList: serializeKeyList(t.keys),
1233
+ keyList: serializeKeyList(t.effectParams.keys),
1097
1234
  fillCanvas: t.effectParams.fillCanvas,
1098
1235
  zoomOrigin: t.effectParams.zoomOrigin,
1099
1236
  }
@@ -1101,7 +1238,7 @@ function serializeTrackList(tracks) {
1101
1238
  }
1102
1239
  return trackList;
1103
1240
  }
1104
- function parseEffectObject(obj, reportErrors) {
1241
+ function parseEffectObject(obj, reportErrors, objName) {
1105
1242
  const result = {};
1106
1243
  for (const key of Object.keys(obj)) {
1107
1244
  const val = obj[key];
@@ -1166,7 +1303,8 @@ function parseEffectObject(obj, reportErrors) {
1166
1303
  case 'Type':
1167
1304
  result.type = exports.GrdT.decode(val);
1168
1305
  break;
1169
- case 'gs99':
1306
+ case 'gs99': // gradient overlay
1307
+ case 'gradientsInterpolationMethod': // glows
1170
1308
  result.interpolationMethod = exports.gradientInterpolationMethodType.decode(val);
1171
1309
  break;
1172
1310
  case 'Opct':
@@ -1218,18 +1356,26 @@ function parseEffectObject(obj, reportErrors) {
1218
1356
  result.pattern = { name: val['Nm '], id: val.Idnt };
1219
1357
  break;
1220
1358
  case 'phase':
1221
- result.phase = { x: val.Hrzn, y: val.Vrtc };
1359
+ result.phase = parsePhase(val);
1222
1360
  break;
1223
1361
  case 'Ofst':
1224
1362
  result.offset = { x: parsePercent(val.Hrzn), y: parsePercent(val.Vrtc) };
1225
1363
  break;
1226
1364
  case 'MpgS':
1227
- case 'TrnS':
1228
- result.contour = {
1365
+ case 'TrnS': {
1366
+ const contour = {
1229
1367
  name: val['Nm '],
1230
1368
  curve: val['Crv '].map(p => ({ x: p.Hrzn, y: p.Vrtc })),
1231
1369
  };
1370
+ // bevel can have both: gloss contour (TrnS) and contour of the shape (MpgS)
1371
+ if (objName === 'bevel' && key === 'MpgS') {
1372
+ result.shapeContour = contour;
1373
+ }
1374
+ else {
1375
+ result.contour = contour;
1376
+ }
1232
1377
  break;
1378
+ }
1233
1379
  case 'Grad':
1234
1380
  result.gradient = parseGradient(val);
1235
1381
  break;
@@ -1324,7 +1470,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
1324
1470
  result.Type = exports.GrdT.encode(val);
1325
1471
  break;
1326
1472
  case 'interpolationMethod':
1327
- result.gs99 = exports.gradientInterpolationMethodType.encode(val);
1473
+ result[(objName === 'outerGlow' || objName === 'innerGlow') ? 'gradientsInterpolationMethod' : 'gs99'] = exports.gradientInterpolationMethodType.encode(val);
1328
1474
  break;
1329
1475
  case 'opacity':
1330
1476
  result.Opct = unitsPercent(val);
@@ -1336,7 +1482,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
1336
1482
  result.sdwO = unitsPercent(val);
1337
1483
  break;
1338
1484
  case 'angle':
1339
- if (objName === 'gradientOverlay' || objName === 'patternFill') {
1485
+ if (objName === 'gradientOverlay' || objName === 'patternOverlay') {
1340
1486
  result.Angl = unitsAngle(val);
1341
1487
  }
1342
1488
  else {
@@ -1380,15 +1526,14 @@ function serializeEffectObject(obj, objName, reportErrors) {
1380
1526
  result.phase = { Hrzn: val.x, Vrtc: val.y };
1381
1527
  break;
1382
1528
  case 'offset':
1383
- result.Ofst = { Hrzn: unitsPercent(val.x), Vrtc: unitsPercent(val.y) };
1529
+ result.Ofst = { Hrzn: unitsPercentF(val.x), Vrtc: unitsPercentF(val.y) };
1384
1530
  break;
1385
- case 'contour': {
1386
- result[objName === 'satin' ? 'MpgS' : 'TrnS'] = {
1387
- 'Nm ': val.name,
1388
- 'Crv ': val.curve.map(p => ({ Hrzn: p.x, Vrtc: p.y })),
1389
- };
1531
+ case 'contour':
1532
+ result[objName === 'satin' ? 'MpgS' : 'TrnS'] = serializeContour(val);
1533
+ break;
1534
+ case 'shapeContour':
1535
+ result.MpgS = serializeContour(val);
1390
1536
  break;
1391
- }
1392
1537
  case 'gradient':
1393
1538
  result.Grad = serializeGradient(val);
1394
1539
  break;
@@ -1406,18 +1551,36 @@ function serializeEffectObject(obj, objName, reportErrors) {
1406
1551
  }
1407
1552
  return result;
1408
1553
  }
1554
+ function serializeContour(contour) {
1555
+ return {
1556
+ 'Nm ': contour.name,
1557
+ 'Crv ': contour.curve.map(p => ({ Hrzn: p.x, Vrtc: p.y })),
1558
+ };
1559
+ }
1409
1560
  function parseGradient(grad) {
1410
1561
  if (grad.GrdF === 'GrdF.CstS') {
1411
- const samples = grad.Intr || 4096;
1562
+ // stop locations are always in 0..4096 range, independent of smoothness (Intr)
1563
+ const samples = 4096;
1412
1564
  return {
1413
1565
  type: 'solid',
1414
1566
  name: grad['Nm '],
1415
1567
  smoothness: grad.Intr / 4096,
1416
- colorStops: grad.Clrs.map(s => ({
1417
- color: parseColor(s['Clr ']),
1418
- location: s.Lctn / samples,
1419
- midpoint: s.Mdpn / 100,
1420
- })),
1568
+ colorStops: grad.Clrs.map(s => {
1569
+ const stop = {
1570
+ color: s['Clr '] ? parseColor(s['Clr ']) : { r: 0, g: 0, b: 0 },
1571
+ location: s.Lctn / samples,
1572
+ midpoint: s.Mdpn / 100,
1573
+ };
1574
+ if (s.Type) {
1575
+ try {
1576
+ const type = exports.Clry.decode(s.Type);
1577
+ if (type !== 'user')
1578
+ stop.type = type;
1579
+ }
1580
+ catch (_a) { } // unknown stop type, read as user color
1581
+ }
1582
+ return stop;
1583
+ }),
1421
1584
  opacityStops: grad.Trns.map(s => ({
1422
1585
  opacity: parsePercent(s.Opct),
1423
1586
  location: s.Lctn / samples,
@@ -1442,24 +1605,25 @@ function parseGradient(grad) {
1442
1605
  function serializeGradient(grad) {
1443
1606
  var _a, _b;
1444
1607
  if (grad.type === 'solid') {
1445
- const samples = Math.round(((_a = grad.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096);
1608
+ // stop locations are always in 0..4096 range, independent of smoothness (Intr)
1609
+ const samples = 4096;
1446
1610
  return {
1447
1611
  'Nm ': grad.name || '',
1448
1612
  GrdF: 'GrdF.CstS',
1449
- Intr: samples,
1613
+ Intr: Math.round(((_a = grad.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096),
1450
1614
  Clrs: grad.colorStops.map(s => {
1451
- var _a;
1615
+ var _a, _b;
1452
1616
  return ({
1453
1617
  'Clr ': serializeColor(s.color),
1454
- Type: 'Clry.UsrS',
1618
+ Type: exports.Clry.encode((_a = s.type) !== null && _a !== void 0 ? _a : 'user'),
1455
1619
  Lctn: Math.round(s.location * samples),
1456
- Mdpn: Math.round(((_a = s.midpoint) !== null && _a !== void 0 ? _a : 0.5) * 100),
1620
+ Mdpn: Math.round(((_b = s.midpoint) !== null && _b !== void 0 ? _b : 0.5) * 100),
1457
1621
  });
1458
1622
  }),
1459
1623
  Trns: grad.opacityStops.map(s => {
1460
1624
  var _a;
1461
1625
  return ({
1462
- Opct: unitsPercent(s.opacity),
1626
+ Opct: unitsPercentF(s.opacity),
1463
1627
  Lctn: Math.round(s.location * samples),
1464
1628
  Mdpn: Math.round(((_a = s.midpoint) !== null && _a !== void 0 ? _a : 0.5) * 100),
1465
1629
  });
@@ -1475,8 +1639,8 @@ function serializeGradient(grad) {
1475
1639
  ClrS: exports.ClrS.encode(grad.colorModel),
1476
1640
  RndS: grad.randomSeed || 0,
1477
1641
  Smth: Math.round(((_b = grad.roughness) !== null && _b !== void 0 ? _b : 1) * 4096),
1478
- 'Mnm ': (grad.min || [0, 0, 0, 0]).map(x => x * 100),
1479
- 'Mxm ': (grad.max || [1, 1, 1, 1]).map(x => x * 100),
1642
+ 'Mnm ': (grad.min || [0, 0, 0, 0]).map(x => Math.round(x * 100)),
1643
+ 'Mxm ': (grad.max || [1, 1, 1, 1]).map(x => Math.round(x * 100)),
1480
1644
  };
1481
1645
  }
1482
1646
  }
@@ -1503,6 +1667,13 @@ function parseGradientContent(descriptor) {
1503
1667
  }
1504
1668
  return result;
1505
1669
  }
1670
+ // phase is usually stored as plain numbers, but some files store it as unit values
1671
+ function parsePhase({ Hrzn, Vrtc }) {
1672
+ return {
1673
+ x: typeof Hrzn === 'number' ? Hrzn : Hrzn.value,
1674
+ y: typeof Vrtc === 'number' ? Vrtc : Vrtc.value,
1675
+ };
1676
+ }
1506
1677
  function parsePatternContent(descriptor) {
1507
1678
  const result = {
1508
1679
  name: descriptor.Ptrn['Nm '],
@@ -1511,7 +1682,11 @@ function parsePatternContent(descriptor) {
1511
1682
  if (descriptor.Lnkd !== undefined)
1512
1683
  result.linked = descriptor.Lnkd;
1513
1684
  if (descriptor.phase !== undefined)
1514
- result.phase = { x: descriptor.phase.Hrzn, y: descriptor.phase.Vrtc };
1685
+ result.phase = parsePhase(descriptor.phase);
1686
+ if (descriptor['Scl '] !== undefined)
1687
+ result.scale = parsePercent(descriptor['Scl ']);
1688
+ if (descriptor.Angl !== undefined)
1689
+ result.angle = parseAngle(descriptor.Angl);
1515
1690
  return result;
1516
1691
  }
1517
1692
  function parseVectorContent(descriptor) {
@@ -1542,11 +1717,11 @@ function serializeGradientContent(content) {
1542
1717
  if (content.align !== undefined)
1543
1718
  result.Algn = content.align;
1544
1719
  if (content.scale !== undefined)
1545
- result['Scl '] = unitsPercent(content.scale);
1720
+ result['Scl '] = unitsPercentF(content.scale);
1546
1721
  if (content.offset) {
1547
1722
  result.Ofst = {
1548
- Hrzn: unitsPercent(content.offset.x),
1549
- Vrtc: unitsPercent(content.offset.y),
1723
+ Hrzn: unitsPercentF(content.offset.x),
1724
+ Vrtc: unitsPercentF(content.offset.y),
1550
1725
  };
1551
1726
  }
1552
1727
  result.Grad = serializeGradient(content);
@@ -1563,6 +1738,10 @@ function serializePatternContent(content) {
1563
1738
  result.Lnkd = !!content.linked;
1564
1739
  if (content.phase !== undefined)
1565
1740
  result.phase = { Hrzn: content.phase.x, Vrtc: content.phase.y };
1741
+ if (content.scale !== undefined)
1742
+ result['Scl '] = unitsPercentF(content.scale);
1743
+ if (content.angle !== undefined)
1744
+ result.Angl = unitsAngle(content.angle);
1566
1745
  return result;
1567
1746
  }
1568
1747
  function serializeVectorContent(content) {
@@ -1576,25 +1755,68 @@ function serializeVectorContent(content) {
1576
1755
  return { key: 'GdFl', descriptor: serializeGradientContent(content) };
1577
1756
  }
1578
1757
  }
1758
+ // Descriptor color values: HSB saturation/brightness 0..100, CMYK 0..100, Gray 0..100, Lab L 0..100, a/b -128..127
1759
+ // Color values (see psd.ts): HSB 0..1, CMYK 0..255, Gray 0..255, Lab L 0..1, a/b -1..1 (same as readColor/writeColor)
1760
+ const colorConversions = {
1761
+ // key: [descriptor -> color, color -> descriptor]
1762
+ 'H ': [x => x / 360, x => x * 360], // angle
1763
+ Strt: [x => x / 100, x => x * 100],
1764
+ Brgh: [x => x / 100, x => x * 100],
1765
+ 'Cyn ': [x => x * 255 / 100, x => x * 100 / 255],
1766
+ Mgnt: [x => x * 255 / 100, x => x * 100 / 255],
1767
+ 'Ylw ': [x => x * 255 / 100, x => x * 100 / 255],
1768
+ Blck: [x => x * 255 / 100, x => x * 100 / 255],
1769
+ 'Gry ': [x => x * 255 / 100, x => x * 100 / 255],
1770
+ Lmnc: [x => x / 100, x => x * 100],
1771
+ 'A ': [helpers_1.normalizeLabAB, helpers_1.denormalizeLabAB],
1772
+ 'B ': [helpers_1.normalizeLabAB, helpers_1.denormalizeLabAB],
1773
+ };
1774
+ function colorToDescriptorValue(key, value) {
1775
+ const conversion = colorConversions[key];
1776
+ if (!conversion)
1777
+ return value;
1778
+ const [from, to] = conversion;
1779
+ const result = to(value);
1780
+ if (!isFinite(result))
1781
+ return result;
1782
+ // prefer shortest number that converts back to the same value (avoids values like 30.200000000000003)
1783
+ for (let precision = 1; precision < 17; precision++) {
1784
+ const candidate = +result.toPrecision(precision);
1785
+ if (from(candidate) === value)
1786
+ return candidate;
1787
+ }
1788
+ return result;
1789
+ }
1790
+ function isBookColor(color) {
1791
+ return color._classID === 'BkCl' || 'Bk ' in color || 'bookID' in color;
1792
+ }
1579
1793
  function parseColor(color) {
1580
1794
  if ('H ' in color) {
1581
- return { h: parsePercentOrAngle(color['H ']), s: color.Strt, b: color.Brgh };
1795
+ return { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
1582
1796
  }
1583
1797
  else if ('Rd ' in color) {
1584
1798
  return { r: color['Rd '], g: color['Grn '], b: color['Bl '] };
1585
1799
  }
1586
1800
  else if ('Cyn ' in color) {
1587
- return { c: color['Cyn '], m: color.Mgnt, y: color['Ylw '], k: color.Blck };
1801
+ return {
1802
+ c: color['Cyn '] * 255 / 100,
1803
+ m: color.Mgnt * 255 / 100,
1804
+ y: color['Ylw '] * 255 / 100,
1805
+ k: color.Blck * 255 / 100,
1806
+ };
1588
1807
  }
1589
1808
  else if ('Gry ' in color) {
1590
- return { k: color['Gry '] };
1809
+ return { k: color['Gry '] * 255 / 100 };
1591
1810
  }
1592
1811
  else if ('Lmnc' in color) {
1593
- return { l: color.Lmnc, a: color['A '], b: color['B '] };
1812
+ return { l: color.Lmnc / 100, a: (0, helpers_1.normalizeLabAB)(color['A ']), b: (0, helpers_1.normalizeLabAB)(color['B ']) };
1594
1813
  }
1595
1814
  else if ('redFloat' in color) {
1596
1815
  return { fr: color.redFloat, fg: color.greenFloat, fb: color.blueFloat };
1597
1816
  }
1817
+ else if (isBookColor(color)) {
1818
+ return { r: 0, g: 0, b: 0 }; // book (Pantone) colors are not supported
1819
+ }
1598
1820
  else {
1599
1821
  throw new Error('Unsupported color descriptor');
1600
1822
  }
@@ -1610,16 +1832,32 @@ function serializeColor(color) {
1610
1832
  return { _name: '', _classID: 'RGBC', redFloat: color.fr, greenFloat: color.fg, blueFloat: color.fb };
1611
1833
  }
1612
1834
  else if ('h' in color) {
1613
- return { _name: '', _classID: 'HSBC', 'H ': unitsAngle(color.h * 360), Strt: color.s || 0, Brgh: color.b || 0 };
1835
+ return {
1836
+ _name: '', _classID: 'HSBC',
1837
+ 'H ': unitsAngle(colorToDescriptorValue('H ', color.h || 0)),
1838
+ Strt: colorToDescriptorValue('Strt', color.s || 0),
1839
+ Brgh: colorToDescriptorValue('Brgh', color.b || 0),
1840
+ };
1614
1841
  }
1615
1842
  else if ('c' in color) {
1616
- return { _name: '', _classID: 'CMYC', 'Cyn ': color.c || 0, Mgnt: color.m || 0, 'Ylw ': color.y || 0, Blck: color.k || 0 };
1843
+ return {
1844
+ _name: '', _classID: 'CMYC',
1845
+ 'Cyn ': colorToDescriptorValue('Cyn ', color.c || 0),
1846
+ Mgnt: colorToDescriptorValue('Mgnt', color.m || 0),
1847
+ 'Ylw ': colorToDescriptorValue('Ylw ', color.y || 0),
1848
+ Blck: colorToDescriptorValue('Blck', color.k || 0),
1849
+ };
1617
1850
  }
1618
1851
  else if ('l' in color) {
1619
- return { _name: '', _classID: 'LABC', Lmnc: color.l || 0, 'A ': color.a || 0, 'B ': color.b || 0 };
1852
+ return {
1853
+ _name: '', _classID: 'LbCl',
1854
+ Lmnc: colorToDescriptorValue('Lmnc', color.l || 0),
1855
+ 'A ': colorToDescriptorValue('A ', color.a || 0),
1856
+ 'B ': colorToDescriptorValue('B ', color.b || 0),
1857
+ };
1620
1858
  }
1621
1859
  else if ('k' in color) {
1622
- return { _name: '', _classID: 'GRYC', 'Gry ': color.k };
1860
+ return { _name: '', _classID: 'Grsc', 'Gry ': colorToDescriptorValue('Gry ', color.k || 0) };
1623
1861
  }
1624
1862
  else {
1625
1863
  throw new Error('Invalid color value');
@@ -1650,7 +1888,8 @@ function parsePercentOrAngle(x) {
1650
1888
  }
1651
1889
  function parseUnits({ units, value }) {
1652
1890
  if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
1653
- units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density') {
1891
+ units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
1892
+ units !== 'Distance') {
1654
1893
  throw new Error(`Invalid units: ${JSON.stringify({ units, value })}`);
1655
1894
  }
1656
1895
  return { value, units };
@@ -1683,7 +1922,8 @@ function unitsValue(x, key) {
1683
1922
  if (typeof value !== 'number')
1684
1923
  throw new Error(`Invalid value in ${JSON.stringify(x)} (key: ${key})`);
1685
1924
  if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
1686
- units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density') {
1925
+ units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
1926
+ units !== 'Distance') {
1687
1927
  throw new Error(`Invalid units in ${JSON.stringify(x)} (key: ${key})`);
1688
1928
  }
1689
1929
  return { units, value };
@@ -1811,6 +2051,11 @@ exports.gradientInterpolationMethodType = (0, helpers_1.createEnum)('gradientInt
1811
2051
  smooth: 'Smoo',
1812
2052
  // TODO: stripes
1813
2053
  });
2054
+ exports.Clry = (0, helpers_1.createEnum)('Clry', 'user', {
2055
+ user: 'UsrS',
2056
+ foreground: 'FrgC',
2057
+ background: 'BckC',
2058
+ });
1814
2059
  exports.ClrS = (0, helpers_1.createEnum)('ClrS', 'rgb', {
1815
2060
  rgb: 'RGBC',
1816
2061
  hsb: 'HSBl',