ag-psd 32.0.0 → 34.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 (117) hide show
  1. package/.v8-cache/v24.7.0-x64-ef5a0af0/03e19709 +0 -0
  2. package/.v8-cache/v24.7.0-x64-ef5a0af0/05135617 +0 -0
  3. package/.v8-cache/v24.7.0-x64-ef5a0af0/1130885f +0 -0
  4. package/.v8-cache/v24.7.0-x64-ef5a0af0/226e2801 +0 -0
  5. package/.v8-cache/v24.7.0-x64-ef5a0af0/2a19133e +0 -0
  6. package/.v8-cache/v24.7.0-x64-ef5a0af0/4511bacf +0 -0
  7. package/.v8-cache/v24.7.0-x64-ef5a0af0/68416cb2 +0 -0
  8. package/.v8-cache/v24.7.0-x64-ef5a0af0/71df9cb3 +0 -0
  9. package/.v8-cache/v24.7.0-x64-ef5a0af0/7ea06cea +0 -0
  10. package/.v8-cache/v24.7.0-x64-ef5a0af0/87cf2209 +0 -0
  11. package/.v8-cache/v24.7.0-x64-ef5a0af0/932f0770 +0 -0
  12. package/.v8-cache/v24.7.0-x64-ef5a0af0/acc36e66 +0 -0
  13. package/.v8-cache/v24.7.0-x64-ef5a0af0/b3c2fab7 +0 -0
  14. package/.v8-cache/v24.7.0-x64-ef5a0af0/c0b789d2 +0 -0
  15. package/.v8-cache/v24.7.0-x64-ef5a0af0/c314aece +0 -0
  16. package/.v8-cache/v24.7.0-x64-ef5a0af0/cfc49f4f +0 -0
  17. package/.v8-cache/v24.7.0-x64-ef5a0af0/cff9434a +0 -0
  18. package/.v8-cache/v24.7.0-x64-ef5a0af0/d13d7610 +0 -0
  19. package/.v8-cache/v24.7.0-x64-ef5a0af0/dc86f000 +0 -0
  20. package/.v8-cache/v24.7.0-x64-ef5a0af0/e03e2acd +0 -0
  21. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6745c2b +0 -0
  22. package/.v8-cache/v24.7.0-x64-ef5a0af0/e6b99945 +0 -0
  23. package/.v8-cache/v24.7.0-x64-ef5a0af0/eeeebdfe +0 -0
  24. package/.v8-cache/v24.7.0-x64-ef5a0af0/f6fd8125 +0 -0
  25. package/CHANGELOG.md +100 -0
  26. package/LICENSE +5 -0
  27. package/README.md +4 -7
  28. package/README_PSD.md +261 -84
  29. package/TODO.md +13 -84
  30. package/dist/abr.d.ts +11 -4
  31. package/dist/abr.js +362 -230
  32. package/dist/abr.js.map +1 -1
  33. package/dist/additionalInfo.d.ts +56 -2
  34. package/dist/additionalInfo.js +828 -361
  35. package/dist/additionalInfo.js.map +1 -1
  36. package/dist/ase.d.ts +6 -1
  37. package/dist/ase.js +61 -61
  38. package/dist/ase.js.map +1 -1
  39. package/dist/bundle.js +3321 -1364
  40. package/dist/descriptor.d.ts +28 -13
  41. package/dist/descriptor.js +295 -241
  42. package/dist/descriptor.js.map +1 -1
  43. package/dist/helpers.d.ts +7 -1
  44. package/dist/helpers.js +246 -4
  45. package/dist/helpers.js.map +1 -1
  46. package/dist/imageResources.d.ts +15 -3
  47. package/dist/imageResources.js +586 -144
  48. package/dist/imageResources.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +1 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/jpeg.js +8 -8
  53. package/dist/jpeg.js.map +1 -1
  54. package/dist/psd.d.ts +292 -19
  55. package/dist/psd.js.map +1 -1
  56. package/dist/psdReader.d.ts +10 -0
  57. package/dist/psdReader.js +424 -216
  58. package/dist/psdReader.js.map +1 -1
  59. package/dist/psdWriter.d.ts +2 -0
  60. package/dist/psdWriter.js +373 -113
  61. package/dist/psdWriter.js.map +1 -1
  62. package/dist/text.d.ts +32 -1
  63. package/dist/text.js +75 -6
  64. package/dist/text.js.map +1 -1
  65. package/dist/utf8.js +0 -3
  66. package/dist/utf8.js.map +1 -1
  67. package/dist-es/abr.d.ts +11 -4
  68. package/dist-es/abr.js +362 -230
  69. package/dist-es/abr.js.map +1 -1
  70. package/dist-es/additionalInfo.d.ts +56 -2
  71. package/dist-es/additionalInfo.js +828 -361
  72. package/dist-es/additionalInfo.js.map +1 -1
  73. package/dist-es/ase.d.ts +6 -1
  74. package/dist-es/ase.js +61 -61
  75. package/dist-es/ase.js.map +1 -1
  76. package/dist-es/descriptor.d.ts +28 -13
  77. package/dist-es/descriptor.js +295 -241
  78. package/dist-es/descriptor.js.map +1 -1
  79. package/dist-es/helpers.d.ts +7 -1
  80. package/dist-es/helpers.js +246 -4
  81. package/dist-es/helpers.js.map +1 -1
  82. package/dist-es/imageResources.d.ts +15 -3
  83. package/dist-es/imageResources.js +586 -144
  84. package/dist-es/imageResources.js.map +1 -1
  85. package/dist-es/index.d.ts +1 -0
  86. package/dist-es/index.js +1 -0
  87. package/dist-es/index.js.map +1 -1
  88. package/dist-es/jpeg.js +8 -8
  89. package/dist-es/jpeg.js.map +1 -1
  90. package/dist-es/psd.d.ts +292 -19
  91. package/dist-es/psd.js.map +1 -1
  92. package/dist-es/psdReader.d.ts +10 -0
  93. package/dist-es/psdReader.js +424 -216
  94. package/dist-es/psdReader.js.map +1 -1
  95. package/dist-es/psdWriter.d.ts +2 -0
  96. package/dist-es/psdWriter.js +373 -113
  97. package/dist-es/psdWriter.js.map +1 -1
  98. package/dist-es/text.d.ts +32 -1
  99. package/dist-es/text.js +75 -6
  100. package/dist-es/text.js.map +1 -1
  101. package/dist-es/utf8.js +0 -3
  102. package/dist-es/utf8.js.map +1 -1
  103. package/package.json +2 -2
  104. package/perf.js +312 -9
  105. package/src/abr.ts +382 -235
  106. package/src/additionalInfo.ts +1071 -482
  107. package/src/ase.ts +66 -61
  108. package/src/descriptor.ts +291 -242
  109. package/src/helpers.ts +266 -3
  110. package/src/imageResources.ts +736 -169
  111. package/src/index.ts +1 -0
  112. package/src/jpeg.ts +8 -8
  113. package/src/psd.ts +271 -32
  114. package/src/psdReader.ts +440 -221
  115. package/src/psdWriter.ts +402 -110
  116. package/src/text.ts +93 -7
  117. package/src/utf8.ts +0 -4
@@ -11,14 +11,12 @@ 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;
16
- exports.setLogErrors = setLogErrors;
14
+ 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 = exports.cameraRawFilterKeyTypes = exports.cameraRawFilterClassID = void 0;
15
+ exports.patternColorHandling = exports.presetKindType = exports.prjM = exports.FlMd = exports.IntC = exports.IntE = exports.Drct = exports.WndM = void 0;
17
16
  exports.readAsciiStringOrClassId = readAsciiStringOrClassId;
18
17
  exports.writeAsciiStringOrClassId = writeAsciiStringOrClassId;
19
18
  exports.readDescriptorStructure = readDescriptorStructure;
20
19
  exports.writeDescriptorStructure = writeDescriptorStructure;
21
- exports.createDescriptorReference = createDescriptorReference;
22
20
  exports.pathSelectionStateToReference = pathSelectionStateToReference;
23
21
  exports.writeClassStructure = writeClassStructure;
24
22
  exports.readVersionAndDescriptor = readVersionAndDescriptor;
@@ -68,10 +66,6 @@ const unitsMap = {
68
66
  'RrCm': 'Centimeters',
69
67
  };
70
68
  const unitsMapRev = revMap(unitsMap);
71
- let logErrors = false;
72
- function setLogErrors(value) {
73
- logErrors = value;
74
- }
75
69
  function makeType(name, classID) {
76
70
  return { name, classID };
77
71
  }
@@ -117,6 +111,7 @@ const fieldToExtType = {
117
111
  psVersion: nullType,
118
112
  docDefaultNewArtboardBackgroundColor: makeType('', 'RGBC'),
119
113
  artboardRect: makeType('', 'classFloatRect'),
114
+ framedGroupRect: makeType('', 'classFloatRect'),
120
115
  keyOriginRRectRadii: makeType('', 'radii'),
121
116
  keyOriginBoxCorners: nullType,
122
117
  rectangleCornerA: makeType('', 'Pnt '),
@@ -167,6 +162,7 @@ const fieldToArrayExtType = {
167
162
  Clrs: makeType('', 'Clrt'),
168
163
  Trns: makeType('', 'TrnS'),
169
164
  keyDescriptorList: nullType,
165
+ keyRootDescriptorList: nullType,
170
166
  solidFillMulti: makeType('', 'SoFi'),
171
167
  gradientFillMulti: makeType('', 'GrFl'),
172
168
  dropShadowMulti: makeType('', 'DrSh'),
@@ -200,17 +196,23 @@ const fieldToArrayExtType = {
200
196
  };
201
197
  const typeToField = {
202
198
  'TEXT': [
203
- 'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
199
+ 'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName', 'exportOption', 'scaleSettings',
200
+ 'BackgroundImagePath', 'ImageSubfolderName', 'SavedIteratedName',
204
201
  'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
205
202
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
206
- 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath',
203
+ 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth', 'comment', 'originalPath', 'Bk ', 'pathUnicodeName',
207
204
  ],
208
205
  'tdta': [
209
206
  'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
210
- 'LqMe',
207
+ 'LqMe', 'bookKey',
211
208
  ],
212
209
  'long': [
213
- 'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
210
+ 'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ', 'bookID',
211
+ 'cropRectBottom', 'cropRectLeft', 'cropRectRight', 'cropRectTop',
212
+ // save for web output settings
213
+ 'Version', 'BackgroundColorBlue', 'BackgroundColorGreen', 'BackgroundColorRed', 'BackgroundColorState', 'AttributeCase', 'Encoding',
214
+ 'DuplicateFileNameBehavior', 'ImageMapLocation', 'ImageMapType', 'Indent', 'LineEndings', 'SpacersEmptyCells',
215
+ 'SpacersHorizontal', 'SpacersVertical', 'StylesFormat', 'TDWidthHeight', 'TagCase', 'ColorPolicy', 'MetadataPolicy',
214
216
  'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'comp', 'compID', 'originalCompID',
215
217
  'curvesPresetKind', 'mixerPresetKind', 'uOrder', 'vOrder', 'PgNm', 'totalPages', 'Crop',
216
218
  'numerator', 'denominator', 'frameCount', 'Annt', 'keyOriginType', 'unitValueQuadVersion',
@@ -222,7 +224,7 @@ const typeToField = {
222
224
  'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
223
225
  'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
224
226
  'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4', 'lastAppliedComp', 'capturedInfo',
225
- 'pixelSourceType',
227
+ 'pixelSourceType', 'framedGroupType',
226
228
  ],
227
229
  'enum': [
228
230
  'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
@@ -232,7 +234,7 @@ const typeToField = {
232
234
  'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
233
235
  'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
234
236
  'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
235
- 'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod',
237
+ 'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ', 'placedLayerOCIOConversion', 'gradientsInterpolationMethod', 'pathSymmetryMode',
236
238
  'interpretAlpha',
237
239
  ],
238
240
  'bool': [
@@ -246,15 +248,15 @@ const typeToField = {
246
248
  'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
247
249
  'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
248
250
  'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
249
- 'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn',
251
+ 'moreAccurate', 'GpuY', 'LIWy', 'Cnty', 'Lnkd', 'showAlteredVideo', 'lightingOn', 'LockPPI',
250
252
  ],
251
253
  'doub': [
252
- 'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
254
+ 'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght', 'Gmm ',
253
255
  'strokeStyleMiterLimit', 'strokeStyleResolution', 'layerTime', 'keyOriginResolution',
254
256
  'xx', 'xy', 'yx', 'yy', 'tx', 'ty', 'FrGA', 'frameRate', 'audioLevel', 'rotation',
255
257
  'X ', 'Y ', 'redFloat', 'greenFloat', 'blueFloat', 'imageResolution',
256
258
  'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3',
257
- 'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity',
259
+ 'stylization', 'cleanliness', 'brushScale', 'microBrush', 'specularity', 'PreferredResolution',
258
260
  ],
259
261
  'UntF': [
260
262
  'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
@@ -263,7 +265,7 @@ const typeToField = {
263
265
  'topRight', 'topLeft', 'bottomLeft', 'bottomRight', 'ClNs', 'Shrp',
264
266
  ],
265
267
  'VlLs': [
266
- 'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
268
+ 'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'keyRootDescriptorList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
267
269
  'LaSt', 'Trnf', 'nonAffineTransform', 'keyDescriptorList', 'guideIndeces', 'gradientFillMulti',
268
270
  'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
269
271
  'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
@@ -282,26 +284,13 @@ const channels = [
282
284
  ];
283
285
  // color classes whose channel values are written as doubles ('GRYC' and 'LABC' are kept for backwards compatibility)
284
286
  const doubleColorClasses = ['Grsc', 'LbCl', 'GRYC', 'LABC'];
285
- // Hidden (non-enumerable) markers used to remember how values were stored in the file, so they can be
286
- // written back the same way. They don't change the shape of the objects returned by the reader.
287
- const osTypeKey = typeof Symbol !== 'undefined' ? Symbol('agPsdOSType') : '__agPsdOSType';
288
- const obArInfoKey = typeof Symbol !== 'undefined' ? Symbol('agPsdObAr') : '__agPsdObAr';
289
- const referenceInfoKey = typeof Symbol !== 'undefined' ? Symbol('agPsdReference') : '__agPsdReference';
290
- function setHidden(target, key, value) {
291
- Object.defineProperty(target, key, { value, enumerable: false, configurable: true, writable: true });
292
- return target;
293
- }
294
- function getHidden(target, key) {
295
- return (target && typeof target === 'object') ? target[key] : undefined;
296
- }
297
- const osTypeFamilies = {
298
- UntF: 'UntF', UnFl: 'UntF',
299
- Objc: 'Objc', GlbO: 'Objc',
300
- type: 'type', GlbC: 'type',
301
- comp: 'comp',
302
- };
303
- // returns the OS type the value was originally read with, if it's compatible with the type we'd write it as
304
287
  // fallback for unknown keys, based on the type of the value
288
+ exports.cameraRawFilterClassID = 'Adobe Camera Raw Filter';
289
+ // types of Camera Raw Filter settings (keys clash with other descriptors so they're typed by class)
290
+ exports.cameraRawFilterKeyTypes = {
291
+ CrVe: 'TEXT', PrVN: 'long', PrVe: 'long', WBal: 'enum', Ex12: 'doub', ShpR: 'doub',
292
+ 'Crv ': 'VlLs', CrvR: 'VlLs', CrvG: 'VlLs', CrvB: 'VlLs',
293
+ };
305
294
  function guessOSType(value) {
306
295
  if (typeof value === 'boolean')
307
296
  return 'bool';
@@ -309,26 +298,33 @@ function guessOSType(value) {
309
298
  return 'doub';
310
299
  if (Array.isArray(value))
311
300
  return 'VlLs';
312
- if (value && typeof value === 'object' && typeof value._classID === 'string')
313
- return 'Objc';
301
+ if (value && typeof value === 'object') {
302
+ if (typeof value._classID === 'string')
303
+ return 'Objc';
304
+ if (typeof value.classID === 'string')
305
+ return 'type'; // class read from 'type' or 'GlbC'
306
+ if (typeof value.low === 'number' && typeof value.high === 'number')
307
+ return 'comp';
308
+ if (typeof value.units === 'string' && typeof value.value === 'number')
309
+ return 'UntF';
310
+ }
314
311
  return undefined;
315
312
  }
316
- function getRecordedOSType(value, type) {
317
- const recorded = getHidden(value, osTypeKey);
318
- if (!recorded)
319
- return type;
320
- if (!type || recorded === 'comp' || recorded === 'type' || recorded === 'GlbC')
321
- return recorded;
322
- return osTypeFamilies[recorded] === osTypeFamilies[type] ? recorded : type;
323
- }
324
313
  const fieldToArrayType = {
325
314
  'Mnm ': 'long',
326
315
  'Mxm ': 'long',
316
+ HtmlFileNameComponents: 'long', // save for web output settings
317
+ SavingFileNameComponents: 'long',
318
+ SliceFileNameComponents: 'long',
319
+ Inpt: 'long', // levels filter
320
+ Otpt: 'long', // levels filter
327
321
  FrLs: 'long',
328
322
  strokeStyleLineDashSet: 'UntF',
329
323
  Trnf: 'doub',
330
324
  nonAffineTransform: 'doub',
331
325
  keyDescriptorList: 'Objc',
326
+ keyRootDescriptorList: 'Objc',
327
+ pathList: 'Objc',
332
328
  gradientFillMulti: 'Objc',
333
329
  solidFillMulti: 'Objc',
334
330
  frameFXMulti: 'Objc',
@@ -419,6 +415,15 @@ function getTypeByKey(key, value, root, parent) {
419
415
  else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'HsbP') {
420
416
  return 'enum';
421
417
  }
418
+ else if ((key === 'Inpt' || key === 'Otpt') && parent._classID === 'LvlA') {
419
+ return 'VlLs';
420
+ }
421
+ else if (key === 'Intr' && typeof value === 'boolean') {
422
+ return 'bool'; // interpolation in print style
423
+ }
424
+ else if (key === 'PgPs') {
425
+ return 'enum';
426
+ }
422
427
  else if (key === 'LghD' && parent._classID === 'oilPaint') {
423
428
  return 'long';
424
429
  }
@@ -431,7 +436,7 @@ function readAsciiStringOrClassId(reader) {
431
436
  return (0, psdReader_1.readAsciiString)(reader, length || 4);
432
437
  }
433
438
  function writeAsciiStringOrClassId(writer, value) {
434
- if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list') {
439
+ if (value.length === 4 && value !== 'warp' && value !== 'time' && value !== 'hold' && value !== 'list' && value !== 'json') {
435
440
  // write classId
436
441
  (0, psdWriter_1.writeInt32)(writer, 0);
437
442
  (0, psdWriter_1.writeSignature)(writer, value);
@@ -459,12 +464,21 @@ function readDescriptorStructure(reader, includeClass) {
459
464
  }
460
465
  return object;
461
466
  }
467
+ exports.outputSettingsRoot = 'outputSettings';
462
468
  function writeDescriptorStructure(writer, name, classId, value, root) {
463
- if (logErrors && !classId)
464
- console.log('Missing classId for: ', name, classId, value);
469
+ var _a;
470
+ if (writer.logMissingFeatures && !classId)
471
+ writer.log('Missing classId for: ', name, classId, value);
465
472
  // write class structure
466
473
  (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, name);
467
- writeAsciiStringOrClassId(writer, classId);
474
+ if (root === exports.outputSettingsRoot && classId === 'null') {
475
+ // Photoshop writes 'null' class id as 4 character string in save for web output settings
476
+ (0, psdWriter_1.writeInt32)(writer, 4);
477
+ (0, psdWriter_1.writeSignature)(writer, classId);
478
+ }
479
+ else {
480
+ writeAsciiStringOrClassId(writer, classId);
481
+ }
468
482
  const allKeys = Object.keys(value);
469
483
  const keys = allKeys.filter(key => key !== '_name' && key !== '_classID' && value[key] !== undefined);
470
484
  (0, psdWriter_1.writeUint32)(writer, keys.length);
@@ -472,6 +486,10 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
472
486
  let type = getTypeByKey(key, value[key], root, value);
473
487
  let childRoot = root;
474
488
  let extType = fieldToExtType[key];
489
+ if (classId === exports.cameraRawFilterClassID) {
490
+ type = (_a = exports.cameraRawFilterKeyTypes[key]) !== null && _a !== void 0 ? _a : 'long'; // other settings are integer levels
491
+ childRoot = exports.cameraRawFilterClassID; // lists (curves) contain integer levels
492
+ }
475
493
  if (key === 'bounds' && root === 'text') {
476
494
  extType = makeType('', 'bounds');
477
495
  }
@@ -568,25 +586,30 @@ function writeDescriptorStructure(writer, name, classId, value, root) {
568
586
  extType = makeType('', 'patternLayer');
569
587
  }
570
588
  else {
571
- logErrors && console.log('Invalid strokeStyleContent value', value[key]);
589
+ writer.logMissingFeatures && writer.log('Invalid strokeStyleContent value', value[key]);
572
590
  }
573
591
  }
574
592
  else if (key === 'bounds' && root === 'quiltWarp') {
575
593
  extType = makeType('', 'classFloatRect');
576
594
  }
595
+ // guess color class from its fields (colors created by serializeColor always have _classID set)
577
596
  if (extType && extType.classID === 'RGBC') {
578
597
  if ('H ' in value[key])
579
598
  extType = { classID: 'HSBC', name: '' };
580
- // TODO: other color spaces
599
+ else if ('Cyn ' in value[key])
600
+ extType = { classID: 'CMYC', name: '' };
601
+ else if ('Lmnc' in value[key])
602
+ extType = { classID: 'LbCl', name: '' };
603
+ else if ('Gry ' in value[key])
604
+ extType = { classID: 'Grsc', name: '' };
581
605
  }
582
- type = getRecordedOSType(value[key], type);
583
606
  if (!type)
584
607
  type = guessOSType(value[key]);
585
608
  writeAsciiStringOrClassId(writer, key);
586
609
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
587
610
  writeOSType(writer, type || 'long', value[key], key, extType, childRoot);
588
- if (logErrors && !type)
589
- console.log(`Missing descriptor field type for: '${key}' in`, value);
611
+ if (writer.logMissingFeatures && !type)
612
+ writer.log(`Missing descriptor field type for: '${key}' in`, value);
590
613
  }
591
614
  }
592
615
  function readOSType(reader, type, includeClass) {
@@ -594,9 +617,8 @@ function readOSType(reader, type, includeClass) {
594
617
  case 'obj ': // Reference
595
618
  return readReferenceStructure(reader);
596
619
  case 'Objc': // Descriptor
597
- return readDescriptorStructure(reader, includeClass);
598
620
  case 'GlbO': // GlobalObject same as Descriptor
599
- return setHidden(readDescriptorStructure(reader, includeClass), osTypeKey, type);
621
+ return readDescriptorStructure(reader, includeClass);
600
622
  case 'VlLs': { // List
601
623
  const length = (0, psdReader_1.readInt32)(reader);
602
624
  const items = [];
@@ -621,7 +643,7 @@ function readOSType(reader, type, includeClass) {
621
643
  const value = (0, psdReader_1.readFloat32)(reader);
622
644
  if (!unitsMap[units])
623
645
  throw new Error(`Invalid units: ${units}`);
624
- return setHidden({ units: unitsMap[units], value }, osTypeKey, type);
646
+ return { units: unitsMap[units], value };
625
647
  }
626
648
  case 'TEXT': // String
627
649
  return (0, psdReader_1.readUnicodeString)(reader);
@@ -635,13 +657,13 @@ function readOSType(reader, type, includeClass) {
635
657
  case 'comp': { // Large Integer
636
658
  const low = (0, psdReader_1.readUint32)(reader);
637
659
  const high = (0, psdReader_1.readUint32)(reader);
638
- return setHidden({ low, high }, osTypeKey, type);
660
+ return { low, high };
639
661
  }
640
662
  case 'bool': // Boolean
641
663
  return !!(0, psdReader_1.readUint8)(reader);
642
664
  case 'type': // Class
643
665
  case 'GlbC': // Class
644
- return setHidden(readClassStructure(reader), osTypeKey, type);
666
+ return readClassStructure(reader);
645
667
  case 'alis': { // Alias
646
668
  const length = (0, psdReader_1.readInt32)(reader);
647
669
  return (0, psdReader_1.readAsciiString)(reader, length);
@@ -653,21 +675,21 @@ function readOSType(reader, type, includeClass) {
653
675
  case 'ObAr': { // Object array
654
676
  (0, psdReader_1.readInt32)(reader); // version: 16
655
677
  (0, psdReader_1.readUnicodeString)(reader); // name: ''
656
- const classID = readAsciiStringOrClassId(reader); // 'rationalPoint'
678
+ readAsciiStringOrClassId(reader); // classID: 'rationalPoint'
657
679
  const length = (0, psdReader_1.readInt32)(reader);
658
680
  const items = [];
659
681
  for (let i = 0; i < length; i++) {
660
682
  const type1 = readAsciiStringOrClassId(reader); // type Hrzn | Vrtc
661
- const valueType = (0, psdReader_1.readSignature)(reader); // UnFl
662
- const units = (0, psdReader_1.readSignature)(reader); // units ? '#Pxl'
683
+ (0, psdReader_1.readSignature)(reader); // UnFl
684
+ (0, psdReader_1.readSignature)(reader); // units ? '#Pxl'
663
685
  const valuesCount = (0, psdReader_1.readInt32)(reader);
664
686
  const values = [];
665
687
  for (let j = 0; j < valuesCount; j++) {
666
688
  values.push((0, psdReader_1.readFloat64)(reader));
667
689
  }
668
- items.push(setHidden({ type: type1, values }, obArInfoKey, { valueType, units }));
690
+ items.push({ type: type1, values });
669
691
  }
670
- return setHidden(items, obArInfoKey, { classID });
692
+ return items;
671
693
  }
672
694
  case 'Pth ': { // File path
673
695
  /*const length =*/ (0, psdReader_1.readInt32)(reader); // total size of all fields below
@@ -687,7 +709,7 @@ const ObArTypes = {
687
709
  quiltSliceY: 'UntF',
688
710
  };
689
711
  function writeOSType(writer, type, value, key, extType, root) {
690
- var _a, _b, _c, _d, _e;
712
+ var _a;
691
713
  switch (type) {
692
714
  case 'obj ': // Reference
693
715
  writeReferenceStructure(writer, key, value);
@@ -708,11 +730,11 @@ function writeOSType(writer, type, value, key, extType, root) {
708
730
  throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
709
731
  (0, psdWriter_1.writeInt32)(writer, value.length);
710
732
  for (let i = 0; i < value.length; i++) {
711
- const type = (_a = getRecordedOSType(value[i], fieldToArrayType[key])) !== null && _a !== void 0 ? _a : guessOSType(value[i]);
733
+ const type = root === exports.cameraRawFilterClassID ? 'long' : ((_a = fieldToArrayType[key]) !== null && _a !== void 0 ? _a : guessOSType(value[i]));
712
734
  (0, psdWriter_1.writeSignature)(writer, type || 'long');
713
735
  writeOSType(writer, type || 'long', value[i], `${key}[]`, fieldToArrayExtType[key], root);
714
- if (logErrors && !type)
715
- console.log(`Missing descriptor array type for: '${key}' in`, value);
736
+ if (writer.logMissingFeatures && !type)
737
+ writer.log(`Missing descriptor array type for: '${key}' in`, value);
716
738
  }
717
739
  break;
718
740
  case 'doub': // Double
@@ -782,16 +804,15 @@ function writeOSType(writer, type, value, key, extType, root) {
782
804
  case 'ObAr': { // Object array
783
805
  (0, psdWriter_1.writeInt32)(writer, 16); // version
784
806
  (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, ''); // name
785
- const type = (_c = (_b = getHidden(value, obArInfoKey)) === null || _b === void 0 ? void 0 : _b.classID) !== null && _c !== void 0 ? _c : ObArTypes[key];
807
+ const type = ObArTypes[key];
786
808
  if (!type)
787
809
  throw new Error(`Not implemented ObArType for: ${key}`);
788
810
  writeAsciiStringOrClassId(writer, type);
789
811
  (0, psdWriter_1.writeInt32)(writer, value.length);
790
812
  for (let i = 0; i < value.length; i++) {
791
- const info = getHidden(value[i], obArInfoKey);
792
813
  writeAsciiStringOrClassId(writer, value[i].type); // Hrzn | Vrtc
793
- (0, psdWriter_1.writeSignature)(writer, (_d = info === null || info === void 0 ? void 0 : info.valueType) !== null && _d !== void 0 ? _d : 'UnFl');
794
- (0, psdWriter_1.writeSignature)(writer, (_e = info === null || info === void 0 ? void 0 : info.units) !== null && _e !== void 0 ? _e : '#Pxl');
814
+ (0, psdWriter_1.writeSignature)(writer, 'UnFl');
815
+ (0, psdWriter_1.writeSignature)(writer, '#Pxl');
795
816
  (0, psdWriter_1.writeInt32)(writer, value[i].values.length);
796
817
  for (let j = 0; j < value[i].values.length; j++) {
797
818
  (0, psdWriter_1.writeFloat64)(writer, value[i].values[j]);
@@ -800,83 +821,60 @@ function writeOSType(writer, type, value, key, extType, root) {
800
821
  break;
801
822
  }
802
823
  case 'Pth ': { // File path
803
- const length = 4 + 4 + 4 + value.path.length * 2;
824
+ const path = value.path + '\0'; // Photoshop stores trailing null character (stripped when reading)
825
+ const length = 4 + 4 + 4 + path.length * 2;
804
826
  (0, psdWriter_1.writeInt32)(writer, length);
805
827
  (0, psdWriter_1.writeSignature)(writer, value.sig);
806
828
  (0, psdWriter_1.writeInt32LE)(writer, length);
807
- (0, psdWriter_1.writeInt32LE)(writer, value.path.length);
808
- (0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer, value.path);
829
+ (0, psdWriter_1.writeInt32LE)(writer, path.length);
830
+ (0, psdWriter_1.writeUnicodeStringWithoutLengthLE)(writer, path);
809
831
  break;
810
832
  }
811
833
  default:
812
834
  throw new Error(`Not implemented descriptor OSType: ${type}`);
813
835
  }
814
836
  }
815
- function referenceItemToValue(item) {
816
- switch (item.type) {
817
- case 'prop': return item.keyID;
818
- case 'Clss': return { name: item.name || '', classID: item.classID };
819
- case 'Enmr': return `${item.typeID}.${item.enumValue}`;
820
- default: return item.value;
821
- }
822
- }
823
- function referenceItemMatches(item, value) {
824
- if (!item)
825
- return false;
826
- const expected = referenceItemToValue(item);
827
- if (expected && typeof expected === 'object') {
828
- return !!value && typeof value === 'object' && value.name === expected.name && value.classID === expected.classID;
829
- }
830
- return expected === value;
831
- }
832
- // Attaches information about how each item of reference should be written (class IDs, reference types),
833
- // the public value of the array stays the same (array of strings/numbers/class objects)
834
- function createDescriptorReference(items) {
835
- return setHidden(items.map(referenceItemToValue), referenceInfoKey, items);
837
+ const referenceTypes = ['prop', 'Clss', 'Enmr', 'rele', 'Idnt', 'indx', 'name'];
838
+ function isReferenceItem(value) {
839
+ return !!value && typeof value === 'object' && referenceTypes.indexOf(value.type) !== -1;
836
840
  }
837
841
  function readReferenceStructure(reader) {
838
842
  const itemsCount = (0, psdReader_1.readInt32)(reader);
839
- const infos = [];
843
+ const items = [];
840
844
  for (let i = 0; i < itemsCount; i++) {
841
845
  const type = (0, psdReader_1.readSignature)(reader);
842
846
  switch (type) {
843
- case 'prop': { // Property
844
- const { name, classID } = readClassStructure(reader);
845
- const keyID = readAsciiStringOrClassId(reader);
846
- infos.push({ type, name, classID, keyID });
847
+ case 'prop': // Property
848
+ readClassStructure(reader);
849
+ items.push(readAsciiStringOrClassId(reader));
847
850
  break;
848
- }
849
- case 'Clss': { // Class
850
- const { name, classID } = readClassStructure(reader);
851
- infos.push({ type, name, classID });
851
+ case 'Clss': // Class
852
+ items.push(readClassStructure(reader));
852
853
  break;
853
- }
854
854
  case 'Enmr': { // Enumerated Reference
855
- const { name, classID } = readClassStructure(reader);
855
+ readClassStructure(reader);
856
856
  const typeID = readAsciiStringOrClassId(reader);
857
857
  const enumValue = readAsciiStringOrClassId(reader);
858
- infos.push({ type, name, classID, typeID, enumValue });
858
+ items.push(`${typeID}.${enumValue}`);
859
859
  break;
860
860
  }
861
- case 'rele': { // Offset
862
- const { name, classID } = readClassStructure(reader);
863
- infos.push({ type, name, classID, value: (0, psdReader_1.readUint32)(reader) });
861
+ case 'rele': // Offset
862
+ readClassStructure(reader);
863
+ items.push((0, psdReader_1.readUint32)(reader));
864
864
  break;
865
- }
866
865
  case 'Idnt': // Identifier
867
866
  case 'indx': // Index
868
- infos.push({ type, value: (0, psdReader_1.readInt32)(reader) });
867
+ items.push((0, psdReader_1.readInt32)(reader));
869
868
  break;
870
- case 'name': { // Name
871
- const { name, classID } = readClassStructure(reader);
872
- infos.push({ type, name, classID, value: (0, psdReader_1.readUnicodeString)(reader) });
869
+ case 'name': // Name
870
+ readClassStructure(reader);
871
+ items.push((0, psdReader_1.readUnicodeString)(reader));
873
872
  break;
874
- }
875
873
  default:
876
874
  throw new Error(`Invalid descriptor reference type: ${type}`);
877
875
  }
878
876
  }
879
- return createDescriptorReference(infos);
877
+ return items;
880
878
  }
881
879
  function guessReferenceItem(value) {
882
880
  if (typeof value === 'string') {
@@ -884,17 +882,17 @@ function guessReferenceItem(value) {
884
882
  // (values like 'My.Path' or 'Logo.v2' can't be typeID/enum value, so they are written as name references)
885
883
  const match = /^([a-z ]{4}|[a-z]{5,})\.([a-z ]+)$/i.exec(value);
886
884
  if (match) {
887
- return { type: 'Enmr', name: '', classID: match[1], typeID: match[1], enumValue: match[2] };
885
+ return { type: 'Enmr', _name: '', _classID: match[1], typeID: match[1], enumValue: match[2] };
888
886
  }
889
887
  else {
890
- return { type: 'name', name: '', classID: 'Lyr ', value };
888
+ return { type: 'name', _name: '', _classID: 'Lyr ', value };
891
889
  }
892
890
  }
893
891
  else if (typeof value === 'number') {
894
892
  return { type: 'Idnt', value };
895
893
  }
896
894
  else if (value && typeof value === 'object' && typeof value.classID === 'string') {
897
- return { type: 'Clss', name: value.name || '', classID: value.classID };
895
+ return { type: 'Clss', _name: value.name || '', _classID: value.classID };
898
896
  }
899
897
  else {
900
898
  throw new Error(`Invalid descriptor reference value: ${JSON.stringify(value)}`);
@@ -903,41 +901,35 @@ function guessReferenceItem(value) {
903
901
  // path selection state (image resource 1088) is a reference to paths, enumerated references there use 'Path' class
904
902
  // (name references use 'Lyr ' class, they reference layer of the vector mask)
905
903
  function pathSelectionStateToReference(items) {
906
- const infos = getHidden(items, referenceInfoKey);
907
- return createDescriptorReference(items.map((value, i) => {
908
- if (referenceItemMatches(infos === null || infos === void 0 ? void 0 : infos[i], value))
909
- return infos[i]; // keep information read from the file
904
+ return items.map(value => {
910
905
  const item = guessReferenceItem(value);
911
906
  if (item.type === 'Enmr')
912
- item.classID = 'Path';
907
+ item._classID = 'Path';
913
908
  return item;
914
- }));
909
+ });
915
910
  }
916
911
  function writeReferenceStructure(writer, _key, items) {
917
912
  if (!Array.isArray(items))
918
913
  throw new Error(`Invalid reference value: ${JSON.stringify(items)}, key: ${_key}`);
919
- const infos = getHidden(items, referenceInfoKey);
920
914
  (0, psdWriter_1.writeInt32)(writer, items.length);
921
- for (let i = 0; i < items.length; i++) {
922
- const value = items[i];
923
- const recorded = infos === null || infos === void 0 ? void 0 : infos[i];
924
- const item = referenceItemMatches(recorded, value) ? recorded : guessReferenceItem(value);
915
+ for (const value of items) {
916
+ const item = isReferenceItem(value) ? value : guessReferenceItem(value);
925
917
  (0, psdWriter_1.writeSignature)(writer, item.type);
926
918
  switch (item.type) {
927
919
  case 'prop': // Property
928
- writeClassStructure(writer, item.name || '', item.classID);
920
+ writeClassStructure(writer, item._name || '', item._classID);
929
921
  writeAsciiStringOrClassId(writer, item.keyID);
930
922
  break;
931
923
  case 'Clss': // Class
932
- writeClassStructure(writer, item.name || '', item.classID);
924
+ writeClassStructure(writer, item._name || '', item._classID);
933
925
  break;
934
926
  case 'Enmr': // Enumerated Reference
935
- writeClassStructure(writer, item.name || '', item.classID);
927
+ writeClassStructure(writer, item._name || '', item._classID);
936
928
  writeAsciiStringOrClassId(writer, item.typeID);
937
929
  writeAsciiStringOrClassId(writer, item.enumValue);
938
930
  break;
939
931
  case 'rele': // Offset
940
- writeClassStructure(writer, item.name || '', item.classID);
932
+ writeClassStructure(writer, item._name || '', item._classID);
941
933
  (0, psdWriter_1.writeUint32)(writer, item.value);
942
934
  break;
943
935
  case 'Idnt': // Identifier
@@ -945,7 +937,7 @@ function writeReferenceStructure(writer, _key, items) {
945
937
  (0, psdWriter_1.writeInt32)(writer, item.value);
946
938
  break;
947
939
  case 'name': // Name
948
- writeClassStructure(writer, item.name || '', item.classID);
940
+ writeClassStructure(writer, item._name || '', item._classID);
949
941
  (0, psdWriter_1.writeUnicodeStringWithPadding)(writer, `${item.value}`);
950
942
  break;
951
943
  default:
@@ -1004,7 +996,7 @@ function parseFxObject(fx) {
1004
996
  fillType: exports.FrFl.decode(fx.PntT),
1005
997
  blendMode: exports.BlnM.decode(fx['Md ']),
1006
998
  opacity: parsePercent(fx.Opct),
1007
- size: parseUnits(fx['Sz ']),
999
+ size: parseUnitsOrNumber(fx['Sz ']), // stored as number (pixels) in old versions
1008
1000
  };
1009
1001
  if (fx.present !== undefined)
1010
1002
  stroke.present = fx.present;
@@ -1042,7 +1034,7 @@ function serializeFxObject(stroke) {
1042
1034
  FrFX.overprint = !!stroke.overprint;
1043
1035
  return FrFX;
1044
1036
  }
1045
- function serializeEffects(e, log, multi) {
1037
+ function serializeEffects(e, writer, multi) {
1046
1038
  var _a, _b, _c;
1047
1039
  const info = multi ? {
1048
1040
  'Scl ': unitsPercentF((_a = e.scale) !== null && _a !== void 0 ? _a : 1),
@@ -1059,33 +1051,33 @@ function serializeEffects(e, log, multi) {
1059
1051
  const useMulti = (arr) => !!arr && arr.length > 1 && multi;
1060
1052
  const useSingle = (arr) => !!arr && arr.length >= 1 && (!multi || arr.length === 1);
1061
1053
  if (useSingle(e.dropShadow))
1062
- info.DrSh = serializeEffectObject(e.dropShadow[0], 'dropShadow', log);
1054
+ info.DrSh = serializeEffectObject(e.dropShadow[0], 'dropShadow', writer);
1063
1055
  if (useMulti(e.dropShadow))
1064
- info.dropShadowMulti = e.dropShadow.map(i => serializeEffectObject(i, 'dropShadow', log));
1056
+ info.dropShadowMulti = e.dropShadow.map(i => serializeEffectObject(i, 'dropShadow', writer));
1065
1057
  if (useSingle(e.innerShadow))
1066
- info.IrSh = serializeEffectObject(e.innerShadow[0], 'innerShadow', log);
1058
+ info.IrSh = serializeEffectObject(e.innerShadow[0], 'innerShadow', writer);
1067
1059
  if (useMulti(e.innerShadow))
1068
- info.innerShadowMulti = e.innerShadow.map(i => serializeEffectObject(i, 'innerShadow', log));
1060
+ info.innerShadowMulti = e.innerShadow.map(i => serializeEffectObject(i, 'innerShadow', writer));
1069
1061
  if (e.outerGlow)
1070
- info.OrGl = serializeEffectObject(e.outerGlow, 'outerGlow', log);
1062
+ info.OrGl = serializeEffectObject(e.outerGlow, 'outerGlow', writer);
1071
1063
  if (useMulti(e.solidFill))
1072
- info.solidFillMulti = e.solidFill.map(i => serializeEffectObject(i, 'solidFill', log));
1064
+ info.solidFillMulti = e.solidFill.map(i => serializeEffectObject(i, 'solidFill', writer));
1073
1065
  if (useMulti(e.gradientOverlay))
1074
- info.gradientFillMulti = e.gradientOverlay.map(i => serializeEffectObject(i, 'gradientOverlay', log));
1066
+ info.gradientFillMulti = e.gradientOverlay.map(i => serializeEffectObject(i, 'gradientOverlay', writer));
1075
1067
  if (useMulti(e.stroke))
1076
1068
  info.frameFXMulti = e.stroke.map(i => serializeFxObject(i));
1077
1069
  if (e.innerGlow)
1078
- info.IrGl = serializeEffectObject(e.innerGlow, 'innerGlow', log);
1070
+ info.IrGl = serializeEffectObject(e.innerGlow, 'innerGlow', writer);
1079
1071
  if (e.bevel)
1080
- info.ebbl = serializeEffectObject(e.bevel, 'bevel', log);
1072
+ info.ebbl = serializeEffectObject(e.bevel, 'bevel', writer);
1081
1073
  if (useSingle(e.solidFill))
1082
- info.SoFi = serializeEffectObject(e.solidFill[0], 'solidFill', log);
1074
+ info.SoFi = serializeEffectObject(e.solidFill[0], 'solidFill', writer);
1083
1075
  if (e.patternOverlay)
1084
- info.patternFill = serializeEffectObject(e.patternOverlay, 'patternOverlay', log);
1076
+ info.patternFill = serializeEffectObject(e.patternOverlay, 'patternOverlay', writer);
1085
1077
  if (useSingle(e.gradientOverlay))
1086
- info.GrFl = serializeEffectObject(e.gradientOverlay[0], 'gradientOverlay', log);
1078
+ info.GrFl = serializeEffectObject(e.gradientOverlay[0], 'gradientOverlay', writer);
1087
1079
  if (e.satin)
1088
- info.ChFX = serializeEffectObject(e.satin, 'satin', log);
1080
+ info.ChFX = serializeEffectObject(e.satin, 'satin', writer);
1089
1081
  if (useSingle(e.stroke))
1090
1082
  info.FrFX = serializeFxObject((_c = e.stroke) === null || _c === void 0 ? void 0 : _c[0]);
1091
1083
  if (multi) {
@@ -1107,48 +1099,48 @@ function serializeEffects(e, log, multi) {
1107
1099
  }
1108
1100
  return info;
1109
1101
  }
1110
- function parseEffects(info, log) {
1102
+ function parseEffects(info, reader) {
1111
1103
  const effects = {};
1112
- 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"]);
1104
+ 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"]);
1113
1105
  if (!masterFXSwitch)
1114
1106
  effects.disabled = true;
1115
- if (info['Scl '])
1116
- effects.scale = parsePercent(info['Scl ']);
1107
+ if (scale)
1108
+ effects.scale = parsePercent(scale);
1117
1109
  if (DrSh)
1118
- effects.dropShadow = [parseEffectObject(DrSh, log)];
1110
+ effects.dropShadow = [parseEffectObject(DrSh, reader)];
1119
1111
  if (dropShadowMulti)
1120
- effects.dropShadow = dropShadowMulti.map(i => parseEffectObject(i, log));
1112
+ effects.dropShadow = dropShadowMulti.map(i => parseEffectObject(i, reader));
1121
1113
  if (IrSh)
1122
- effects.innerShadow = [parseEffectObject(IrSh, log)];
1114
+ effects.innerShadow = [parseEffectObject(IrSh, reader)];
1123
1115
  if (innerShadowMulti)
1124
- effects.innerShadow = innerShadowMulti.map(i => parseEffectObject(i, log));
1116
+ effects.innerShadow = innerShadowMulti.map(i => parseEffectObject(i, reader));
1125
1117
  if (OrGl)
1126
- effects.outerGlow = parseEffectObject(OrGl, log);
1118
+ effects.outerGlow = parseEffectObject(OrGl, reader);
1127
1119
  if (IrGl)
1128
- effects.innerGlow = parseEffectObject(IrGl, log);
1120
+ effects.innerGlow = parseEffectObject(IrGl, reader);
1129
1121
  if (ebbl)
1130
- effects.bevel = parseEffectObject(ebbl, log);
1122
+ effects.bevel = parseEffectObject(ebbl, reader, 'bevel');
1131
1123
  if (SoFi)
1132
- effects.solidFill = [parseEffectObject(SoFi, log)];
1124
+ effects.solidFill = [parseEffectObject(SoFi, reader)];
1133
1125
  if (solidFillMulti)
1134
- effects.solidFill = solidFillMulti.map(i => parseEffectObject(i, log));
1126
+ effects.solidFill = solidFillMulti.map(i => parseEffectObject(i, reader));
1135
1127
  if (patternFill)
1136
- effects.patternOverlay = parseEffectObject(patternFill, log);
1128
+ effects.patternOverlay = parseEffectObject(patternFill, reader);
1137
1129
  if (GrFl)
1138
- effects.gradientOverlay = [parseEffectObject(GrFl, log)];
1130
+ effects.gradientOverlay = [parseEffectObject(GrFl, reader)];
1139
1131
  if (gradientFillMulti)
1140
- effects.gradientOverlay = gradientFillMulti.map(i => parseEffectObject(i, log));
1132
+ effects.gradientOverlay = gradientFillMulti.map(i => parseEffectObject(i, reader));
1141
1133
  if (ChFX)
1142
- effects.satin = parseEffectObject(ChFX, log);
1134
+ effects.satin = parseEffectObject(ChFX, reader);
1143
1135
  if (FrFX)
1144
1136
  effects.stroke = [parseFxObject(FrFX)];
1145
1137
  if (frameFXMulti)
1146
1138
  effects.stroke = frameFXMulti.map(i => parseFxObject(i));
1147
- if (log && Object.keys(rest).length > 1)
1148
- console.log('Unhandled effect keys:', rest);
1139
+ if (reader.logMissingFeatures && Object.keys(rest).length)
1140
+ reader.log('Unhandled effect keys:', rest);
1149
1141
  return effects;
1150
1142
  }
1151
- function parseKeyList(keyList, logMissingFeatures) {
1143
+ function parseKeyList(keyList, reader) {
1152
1144
  const keys = [];
1153
1145
  for (let j = 0; j < keyList.length; j++) {
1154
1146
  const key = keyList[j];
@@ -1171,7 +1163,7 @@ function parseKeyList(keyList, logMissingFeatures) {
1171
1163
  case 'keyType.sheetStyle': {
1172
1164
  const key = { interpolation, time, selected, type: 'style' };
1173
1165
  if (animKey.sheetStyle.Lefx)
1174
- key.style = parseEffects(animKey.sheetStyle.Lefx, logMissingFeatures);
1166
+ key.style = parseEffects(animKey.sheetStyle.Lefx, reader);
1175
1167
  keys.push(key);
1176
1168
  break;
1177
1169
  }
@@ -1187,7 +1179,7 @@ function parseKeyList(keyList, logMissingFeatures) {
1187
1179
  }
1188
1180
  return keys;
1189
1181
  }
1190
- function serializeKeyList(keys) {
1182
+ function serializeKeyList(keys, writer) {
1191
1183
  const keyList = [];
1192
1184
  for (let j = 0; j < keys.length; j++) {
1193
1185
  const key = keys[j];
@@ -1207,7 +1199,7 @@ function serializeKeyList(keys) {
1207
1199
  case 'style':
1208
1200
  animKey = { Type: 'keyType.sheetStyle', sheetStyle: { Vrsn: 1, blendOptions: {} } };
1209
1201
  if (key.style)
1210
- animKey.sheetStyle = { Vrsn: 1, Lefx: serializeEffects(key.style, false, false), blendOptions: {} };
1202
+ animKey.sheetStyle = { Vrsn: 1, Lefx: serializeEffects(key.style, writer, false), blendOptions: {} };
1211
1203
  break;
1212
1204
  case 'globalLighting': {
1213
1205
  animKey = { Type: 'keyType.globalLighting', gblA: key.globalAngle, globalAltitude: key.globalAltitude };
@@ -1219,41 +1211,41 @@ function serializeKeyList(keys) {
1219
1211
  }
1220
1212
  return keyList;
1221
1213
  }
1222
- function parseTrackList(trackList, logMissingFeatures) {
1214
+ function parseTrackList(trackList, reader) {
1223
1215
  const tracks = [];
1224
1216
  for (let i = 0; i < trackList.length; i++) {
1225
1217
  const tr = trackList[i];
1226
1218
  const track = {
1227
1219
  type: exports.stdTrackID.decode(tr.trackID),
1228
1220
  enabled: tr.enab,
1229
- keys: parseKeyList(tr.keyList, logMissingFeatures),
1221
+ keys: parseKeyList(tr.keyList, reader),
1230
1222
  };
1231
1223
  if (tr.effectParams) {
1232
1224
  track.effectParams = {
1233
1225
  fillCanvas: tr.effectParams.fillCanvas,
1234
1226
  zoomOrigin: tr.effectParams.zoomOrigin,
1235
- keys: parseKeyList(tr.effectParams.keyList, logMissingFeatures),
1227
+ keys: parseKeyList(tr.effectParams.keyList, reader),
1236
1228
  };
1237
1229
  }
1238
1230
  tracks.push(track);
1239
1231
  }
1240
1232
  return tracks;
1241
1233
  }
1242
- function serializeTrackList(tracks) {
1234
+ function serializeTrackList(tracks, writer) {
1243
1235
  const trackList = [];
1244
1236
  for (let i = 0; i < tracks.length; i++) {
1245
1237
  const t = tracks[i];
1246
1238
  trackList.push(Object.assign(Object.assign({ trackID: exports.stdTrackID.encode(t.type), Vrsn: 1, enab: !!t.enabled, Effc: !!t.effectParams }, (t.effectParams ? {
1247
1239
  effectParams: {
1248
- keyList: serializeKeyList(t.effectParams.keys),
1240
+ keyList: serializeKeyList(t.effectParams.keys, writer),
1249
1241
  fillCanvas: t.effectParams.fillCanvas,
1250
1242
  zoomOrigin: t.effectParams.zoomOrigin,
1251
1243
  }
1252
- } : {})), { keyList: serializeKeyList(t.keys) }));
1244
+ } : {})), { keyList: serializeKeyList(t.keys, writer) }));
1253
1245
  }
1254
1246
  return trackList;
1255
1247
  }
1256
- function parseEffectObject(obj, reportErrors) {
1248
+ function parseEffectObject(obj, reader, objName) {
1257
1249
  const result = {};
1258
1250
  for (const key of Object.keys(obj)) {
1259
1251
  const val = obj[key];
@@ -1318,7 +1310,8 @@ function parseEffectObject(obj, reportErrors) {
1318
1310
  case 'Type':
1319
1311
  result.type = exports.GrdT.decode(val);
1320
1312
  break;
1321
- case 'gs99':
1313
+ case 'gs99': // gradient overlay
1314
+ case 'gradientsInterpolationMethod': // glows
1322
1315
  result.interpolationMethod = exports.gradientInterpolationMethodType.decode(val);
1323
1316
  break;
1324
1317
  case 'Opct':
@@ -1370,18 +1363,26 @@ function parseEffectObject(obj, reportErrors) {
1370
1363
  result.pattern = { name: val['Nm '], id: val.Idnt };
1371
1364
  break;
1372
1365
  case 'phase':
1373
- result.phase = { x: val.Hrzn, y: val.Vrtc };
1366
+ result.phase = parsePhase(val);
1374
1367
  break;
1375
1368
  case 'Ofst':
1376
1369
  result.offset = { x: parsePercent(val.Hrzn), y: parsePercent(val.Vrtc) };
1377
1370
  break;
1378
1371
  case 'MpgS':
1379
- case 'TrnS':
1380
- result.contour = {
1372
+ case 'TrnS': {
1373
+ const contour = {
1381
1374
  name: val['Nm '],
1382
1375
  curve: val['Crv '].map(p => ({ x: p.Hrzn, y: p.Vrtc })),
1383
1376
  };
1377
+ // bevel can have both: gloss contour (TrnS) and contour of the shape (MpgS)
1378
+ if (objName === 'bevel' && key === 'MpgS') {
1379
+ result.shapeContour = contour;
1380
+ }
1381
+ else {
1382
+ result.contour = contour;
1383
+ }
1384
1384
  break;
1385
+ }
1385
1386
  case 'Grad':
1386
1387
  result.gradient = parseGradient(val);
1387
1388
  break;
@@ -1397,12 +1398,12 @@ function parseEffectObject(obj, reportErrors) {
1397
1398
  case '_classID':
1398
1399
  break;
1399
1400
  default:
1400
- reportErrors && console.log(`Invalid effect key: '${key}', value:`, val);
1401
+ reader.logMissingFeatures && reader.log(`Invalid effect key: '${key}', value:`, val);
1401
1402
  }
1402
1403
  }
1403
1404
  return result;
1404
1405
  }
1405
- function serializeEffectObject(obj, objName, reportErrors) {
1406
+ function serializeEffectObject(obj, objName, writer) {
1406
1407
  const result = {
1407
1408
  enab: false,
1408
1409
  };
@@ -1476,7 +1477,7 @@ function serializeEffectObject(obj, objName, reportErrors) {
1476
1477
  result.Type = exports.GrdT.encode(val);
1477
1478
  break;
1478
1479
  case 'interpolationMethod':
1479
- result.gs99 = exports.gradientInterpolationMethodType.encode(val);
1480
+ result[(objName === 'outerGlow' || objName === 'innerGlow') ? 'gradientsInterpolationMethod' : 'gs99'] = exports.gradientInterpolationMethodType.encode(val);
1480
1481
  break;
1481
1482
  case 'opacity':
1482
1483
  result.Opct = unitsPercent(val);
@@ -1532,15 +1533,14 @@ function serializeEffectObject(obj, objName, reportErrors) {
1532
1533
  result.phase = { Hrzn: val.x, Vrtc: val.y };
1533
1534
  break;
1534
1535
  case 'offset':
1535
- result.Ofst = { Hrzn: unitsPercent(val.x), Vrtc: unitsPercent(val.y) };
1536
+ result.Ofst = { Hrzn: unitsPercentF(val.x), Vrtc: unitsPercentF(val.y) };
1536
1537
  break;
1537
- case 'contour': {
1538
- result[objName === 'satin' ? 'MpgS' : 'TrnS'] = {
1539
- 'Nm ': val.name,
1540
- 'Crv ': val.curve.map(p => ({ Hrzn: p.x, Vrtc: p.y })),
1541
- };
1538
+ case 'contour':
1539
+ result[objName === 'satin' ? 'MpgS' : 'TrnS'] = serializeContour(val);
1540
+ break;
1541
+ case 'shapeContour':
1542
+ result.MpgS = serializeContour(val);
1542
1543
  break;
1543
- }
1544
1544
  case 'gradient':
1545
1545
  result.Grad = serializeGradient(val);
1546
1546
  break;
@@ -1553,11 +1553,17 @@ function serializeEffectObject(obj, objName, reportErrors) {
1553
1553
  result[key] = val;
1554
1554
  break;
1555
1555
  default:
1556
- reportErrors && console.log(`Invalid effect key: '${key}', value:`, val);
1556
+ writer.logMissingFeatures && writer.log(`Invalid effect key: '${key}', value:`, val);
1557
1557
  }
1558
1558
  }
1559
1559
  return result;
1560
1560
  }
1561
+ function serializeContour(contour) {
1562
+ return {
1563
+ 'Nm ': contour.name,
1564
+ 'Crv ': contour.curve.map(p => ({ Hrzn: p.x, Vrtc: p.y })),
1565
+ };
1566
+ }
1561
1567
  function parseGradient(grad) {
1562
1568
  if (grad.GrdF === 'GrdF.CstS') {
1563
1569
  // stop locations are always in 0..4096 range, independent of smoothness (Intr)
@@ -1566,11 +1572,22 @@ function parseGradient(grad) {
1566
1572
  type: 'solid',
1567
1573
  name: grad['Nm '],
1568
1574
  smoothness: grad.Intr / 4096,
1569
- colorStops: grad.Clrs.map(s => ({
1570
- color: parseColor(s['Clr ']),
1571
- location: s.Lctn / samples,
1572
- midpoint: s.Mdpn / 100,
1573
- })),
1575
+ colorStops: grad.Clrs.map(s => {
1576
+ const stop = {
1577
+ color: s['Clr '] ? parseColor(s['Clr ']) : { r: 0, g: 0, b: 0 },
1578
+ location: s.Lctn / samples,
1579
+ midpoint: s.Mdpn / 100,
1580
+ };
1581
+ if (s.Type) {
1582
+ try {
1583
+ const type = exports.Clry.decode(s.Type);
1584
+ if (type !== 'user')
1585
+ stop.type = type;
1586
+ }
1587
+ catch (_a) { } // unknown stop type, read as user color
1588
+ }
1589
+ return stop;
1590
+ }),
1574
1591
  opacityStops: grad.Trns.map(s => ({
1575
1592
  opacity: parsePercent(s.Opct),
1576
1593
  location: s.Lctn / samples,
@@ -1602,18 +1619,18 @@ function serializeGradient(grad) {
1602
1619
  GrdF: 'GrdF.CstS',
1603
1620
  Intr: Math.round(((_a = grad.smoothness) !== null && _a !== void 0 ? _a : 1) * 4096),
1604
1621
  Clrs: grad.colorStops.map(s => {
1605
- var _a;
1622
+ var _a, _b;
1606
1623
  return ({
1607
1624
  'Clr ': serializeColor(s.color),
1608
- Type: 'Clry.UsrS',
1625
+ Type: exports.Clry.encode((_a = s.type) !== null && _a !== void 0 ? _a : 'user'),
1609
1626
  Lctn: Math.round(s.location * samples),
1610
- Mdpn: Math.round(((_a = s.midpoint) !== null && _a !== void 0 ? _a : 0.5) * 100),
1627
+ Mdpn: Math.round(((_b = s.midpoint) !== null && _b !== void 0 ? _b : 0.5) * 100),
1611
1628
  });
1612
1629
  }),
1613
1630
  Trns: grad.opacityStops.map(s => {
1614
1631
  var _a;
1615
1632
  return ({
1616
- Opct: unitsPercent(s.opacity),
1633
+ Opct: unitsPercentF(s.opacity),
1617
1634
  Lctn: Math.round(s.location * samples),
1618
1635
  Mdpn: Math.round(((_a = s.midpoint) !== null && _a !== void 0 ? _a : 0.5) * 100),
1619
1636
  });
@@ -1657,6 +1674,13 @@ function parseGradientContent(descriptor) {
1657
1674
  }
1658
1675
  return result;
1659
1676
  }
1677
+ // phase is usually stored as plain numbers, but some files store it as unit values
1678
+ function parsePhase({ Hrzn, Vrtc }) {
1679
+ return {
1680
+ x: typeof Hrzn === 'number' ? Hrzn : Hrzn.value,
1681
+ y: typeof Vrtc === 'number' ? Vrtc : Vrtc.value,
1682
+ };
1683
+ }
1660
1684
  function parsePatternContent(descriptor) {
1661
1685
  const result = {
1662
1686
  name: descriptor.Ptrn['Nm '],
@@ -1665,7 +1689,11 @@ function parsePatternContent(descriptor) {
1665
1689
  if (descriptor.Lnkd !== undefined)
1666
1690
  result.linked = descriptor.Lnkd;
1667
1691
  if (descriptor.phase !== undefined)
1668
- result.phase = { x: descriptor.phase.Hrzn, y: descriptor.phase.Vrtc };
1692
+ result.phase = parsePhase(descriptor.phase);
1693
+ if (descriptor['Scl '] !== undefined)
1694
+ result.scale = parsePercent(descriptor['Scl ']);
1695
+ if (descriptor.Angl !== undefined)
1696
+ result.angle = parseAngle(descriptor.Angl);
1669
1697
  return result;
1670
1698
  }
1671
1699
  function parseVectorContent(descriptor) {
@@ -1696,11 +1724,11 @@ function serializeGradientContent(content) {
1696
1724
  if (content.align !== undefined)
1697
1725
  result.Algn = content.align;
1698
1726
  if (content.scale !== undefined)
1699
- result['Scl '] = unitsPercent(content.scale);
1727
+ result['Scl '] = unitsPercentF(content.scale);
1700
1728
  if (content.offset) {
1701
1729
  result.Ofst = {
1702
- Hrzn: unitsPercent(content.offset.x),
1703
- Vrtc: unitsPercent(content.offset.y),
1730
+ Hrzn: unitsPercentF(content.offset.x),
1731
+ Vrtc: unitsPercentF(content.offset.y),
1704
1732
  };
1705
1733
  }
1706
1734
  result.Grad = serializeGradient(content);
@@ -1717,6 +1745,10 @@ function serializePatternContent(content) {
1717
1745
  result.Lnkd = !!content.linked;
1718
1746
  if (content.phase !== undefined)
1719
1747
  result.phase = { Hrzn: content.phase.x, Vrtc: content.phase.y };
1748
+ if (content.scale !== undefined)
1749
+ result['Scl '] = unitsPercentF(content.scale);
1750
+ if (content.angle !== undefined)
1751
+ result.Angl = unitsAngle(content.angle);
1720
1752
  return result;
1721
1753
  }
1722
1754
  function serializeVectorContent(content) {
@@ -1732,9 +1764,9 @@ function serializeVectorContent(content) {
1732
1764
  }
1733
1765
  // Descriptor color values: HSB saturation/brightness 0..100, CMYK 0..100, Gray 0..100, Lab L 0..100, a/b -128..127
1734
1766
  // 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)
1735
- const colorSourceKey = typeof Symbol !== 'undefined' ? Symbol('agPsdColorSource') : '__agPsdColorSource';
1736
1767
  const colorConversions = {
1737
1768
  // key: [descriptor -> color, color -> descriptor]
1769
+ 'H ': [x => x / 360, x => x * 360], // angle
1738
1770
  Strt: [x => x / 100, x => x * 100],
1739
1771
  Brgh: [x => x / 100, x => x * 100],
1740
1772
  'Cyn ': [x => x * 255 / 100, x => x * 100 / 255],
@@ -1762,22 +1794,33 @@ function colorToDescriptorValue(key, value) {
1762
1794
  }
1763
1795
  return result;
1764
1796
  }
1765
- function shallowEqual(a, b) {
1766
- const keys = Object.keys(a);
1767
- if (keys.length !== Object.keys(b).length)
1768
- return false;
1769
- return keys.every(key => a[key] === b[key]);
1797
+ function isBookColor(color) {
1798
+ return color._classID === 'BkCl' || 'Bk ' in color || 'bookID' in color;
1770
1799
  }
1771
1800
  function parseColor(color) {
1772
- let result;
1801
+ var _a, _b, _c;
1802
+ const result = parseColorValues(color);
1803
+ if (isBookColor(color)) {
1804
+ const book = color;
1805
+ const key = book.bookKey;
1806
+ result.book = {
1807
+ book: (_a = book['Bk ']) !== null && _a !== void 0 ? _a : '',
1808
+ name: (_b = book['Nm ']) !== null && _b !== void 0 ? _b : '',
1809
+ bookID: (_c = book.bookID) !== null && _c !== void 0 ? _c : 0,
1810
+ bookKey: typeof key === 'string' ? key : (key ? String.fromCharCode(...Array.from(key)) : ''),
1811
+ };
1812
+ }
1813
+ return result;
1814
+ }
1815
+ function parseColorValues(color) {
1773
1816
  if ('H ' in color) {
1774
- result = { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
1817
+ return { h: parsePercentOrAngle(color['H ']), s: color.Strt / 100, b: color.Brgh / 100 };
1775
1818
  }
1776
1819
  else if ('Rd ' in color) {
1777
1820
  return { r: color['Rd '], g: color['Grn '], b: color['Bl '] };
1778
1821
  }
1779
1822
  else if ('Cyn ' in color) {
1780
- result = {
1823
+ return {
1781
1824
  c: color['Cyn '] * 255 / 100,
1782
1825
  m: color.Mgnt * 255 / 100,
1783
1826
  y: color['Ylw '] * 255 / 100,
@@ -1785,19 +1828,31 @@ function parseColor(color) {
1785
1828
  };
1786
1829
  }
1787
1830
  else if ('Gry ' in color) {
1788
- result = { k: color['Gry '] * 255 / 100 };
1831
+ return { k: color['Gry '] * 255 / 100 };
1789
1832
  }
1790
1833
  else if ('Lmnc' in color) {
1791
- result = { l: color.Lmnc / 100, a: (0, helpers_1.normalizeLabAB)(color['A ']), b: (0, helpers_1.normalizeLabAB)(color['B ']) };
1834
+ return { l: color.Lmnc / 100, a: (0, helpers_1.normalizeLabAB)(color['A ']), b: (0, helpers_1.normalizeLabAB)(color['B ']) };
1792
1835
  }
1793
1836
  else if ('redFloat' in color) {
1794
1837
  return { fr: color.redFloat, fg: color.greenFloat, fb: color.blueFloat };
1795
1838
  }
1839
+ else if (isBookColor(color)) {
1840
+ return { r: 0, g: 0, b: 0 }; // book (Pantone) color without color values
1841
+ }
1796
1842
  else {
1797
1843
  throw new Error('Unsupported color descriptor');
1798
1844
  }
1799
- // remember original descriptor values, so unmodified colors can be written back without conversion errors
1800
- return setHidden(result, colorSourceKey, { color: Object.assign({}, result), descriptor: color });
1845
+ }
1846
+ function serializeColor(color) {
1847
+ const result = serializeColorValues(color);
1848
+ if (color === null || color === void 0 ? void 0 : color.book) {
1849
+ const { book, name, bookID, bookKey } = color.book;
1850
+ const key = new Uint8Array(bookKey.length);
1851
+ for (let i = 0; i < key.length; i++)
1852
+ key[i] = bookKey.charCodeAt(i) & 0xff;
1853
+ Object.assign(result, { 'Bk ': book, 'Nm ': name, bookID, bookKey: key });
1854
+ }
1855
+ return result;
1801
1856
  }
1802
1857
  function serializeColorValues(color) {
1803
1858
  if (!color) {
@@ -1812,7 +1867,7 @@ function serializeColorValues(color) {
1812
1867
  else if ('h' in color) {
1813
1868
  return {
1814
1869
  _name: '', _classID: 'HSBC',
1815
- 'H ': unitsAngle((color.h || 0) * 360),
1870
+ 'H ': unitsAngle(colorToDescriptorValue('H ', color.h || 0)),
1816
1871
  Strt: colorToDescriptorValue('Strt', color.s || 0),
1817
1872
  Brgh: colorToDescriptorValue('Brgh', color.b || 0),
1818
1873
  };
@@ -1841,19 +1896,6 @@ function serializeColorValues(color) {
1841
1896
  throw new Error('Invalid color value');
1842
1897
  }
1843
1898
  }
1844
- function serializeColor(color) {
1845
- const result = serializeColorValues(color);
1846
- const source = getHidden(color, colorSourceKey);
1847
- if (source && shallowEqual(source.color, color)) {
1848
- // color was not modified since it was read, use exact original values
1849
- for (const key of Object.keys(result)) {
1850
- if (colorConversions[key] && typeof source.descriptor[key] === 'number') {
1851
- result[key] = source.descriptor[key];
1852
- }
1853
- }
1854
- }
1855
- return result;
1856
- }
1857
1899
  function parseAngle(x) {
1858
1900
  if (x === undefined)
1859
1901
  return 0;
@@ -1879,7 +1921,8 @@ function parsePercentOrAngle(x) {
1879
1921
  }
1880
1922
  function parseUnits({ units, value }) {
1881
1923
  if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
1882
- units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density') {
1924
+ units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
1925
+ units !== 'Distance') {
1883
1926
  throw new Error(`Invalid units: ${JSON.stringify({ units, value })}`);
1884
1927
  }
1885
1928
  return { value, units };
@@ -1912,7 +1955,8 @@ function unitsValue(x, key) {
1912
1955
  if (typeof value !== 'number')
1913
1956
  throw new Error(`Invalid value in ${JSON.stringify(x)} (key: ${key})`);
1914
1957
  if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
1915
- units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density') {
1958
+ units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density' &&
1959
+ units !== 'Distance') {
1916
1960
  throw new Error(`Invalid units in ${JSON.stringify(x)} (key: ${key})`);
1917
1961
  }
1918
1962
  return { units, value };
@@ -2040,6 +2084,11 @@ exports.gradientInterpolationMethodType = (0, helpers_1.createEnum)('gradientInt
2040
2084
  smooth: 'Smoo',
2041
2085
  // TODO: stripes
2042
2086
  });
2087
+ exports.Clry = (0, helpers_1.createEnum)('Clry', 'user', {
2088
+ user: 'UsrS',
2089
+ foreground: 'FrgC',
2090
+ background: 'BckC',
2091
+ });
2043
2092
  exports.ClrS = (0, helpers_1.createEnum)('ClrS', 'rgb', {
2044
2093
  rgb: 'RGBC',
2045
2094
  hsb: 'HSBl',
@@ -2231,4 +2280,9 @@ exports.presetKindType = (0, helpers_1.createEnum)('presetKindType', 'custom', {
2231
2280
  custom: 'presetKindCustom',
2232
2281
  default: 'presetKindDefault',
2233
2282
  });
2283
+ exports.patternColorHandling = (0, helpers_1.createEnum)('', 'convert', {
2284
+ 'convert': 'conv',
2285
+ 'avoid conversion': 'avod',
2286
+ 'luminance only': 'lumi',
2287
+ });
2234
2288
  //# sourceMappingURL=descriptor.js.map