ag-psd 16.0.0 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/descriptor.ts CHANGED
@@ -11,11 +11,12 @@ import {
11
11
  } from './psd';
12
12
  import {
13
13
  PsdReader, readSignature, readUnicodeString, readUint32, readUint8, readFloat64,
14
- readBytes, readAsciiString, readInt32, readFloat32, readInt32LE, readUnicodeStringWithLength
14
+ readBytes, readAsciiString, readInt32, readFloat32, readInt32LE, readUnicodeStringWithLengthLE
15
15
  } from './psdReader';
16
16
  import {
17
17
  PsdWriter, writeSignature, writeBytes, writeUint32, writeFloat64, writeUint8,
18
- writeUnicodeStringWithPadding, writeInt32, writeFloat32, writeUnicodeString
18
+ writeUnicodeStringWithPadding, writeInt32, writeFloat32, writeUnicodeString, writeInt32LE,
19
+ writeUnicodeStringWithoutLengthLE
19
20
  } from './psdWriter';
20
21
 
21
22
  interface Dict { [key: string]: string; }
@@ -125,11 +126,15 @@ const fieldToExtType: ExtTypeDict = {
125
126
  Anch: makeType('', 'Pnt '),
126
127
  'Fwd ': makeType('', 'Pnt '),
127
128
  'Bwd ': makeType('', 'Pnt '),
129
+ FlrC: makeType('', 'Pnt '),
128
130
  meshBoundaryPath: makeType('', 'pathClass'),
129
131
  filterFX: makeType('', 'filterFXStyle'),
130
132
  Fltr: makeType('', 'rigidTransform'),
131
133
  FrgC: makeType('', 'RGBC'),
132
134
  BckC: makeType('', 'RGBC'),
135
+ sdwM: makeType('Parameters', 'adaptCorrectTones'),
136
+ hglM: makeType('Parameters', 'adaptCorrectTones'),
137
+ customShape: makeType('', 'customShape'),
133
138
  };
134
139
 
135
140
  const fieldToArrayExtType: ExtTypeDict = {
@@ -159,6 +164,8 @@ const fieldToArrayExtType: ExtTypeDict = {
159
164
  pathComponents: makeType('', 'PaCm'),
160
165
  filterFXList: makeType('', 'filterFX'),
161
166
  puppetShapeList: makeType('', 'puppetShape'),
167
+ channelDenoise: makeType('', 'channelDenoiseParams'),
168
+ ShrP: makeType('', 'Pnt '),
162
169
  };
163
170
 
164
171
  const typeToField: { [key: string]: string[]; } = {
@@ -166,9 +173,12 @@ const typeToField: { [key: string]: string[]; } = {
166
173
  'Txt ', 'printerName', 'Nm ', 'Idnt', 'blackAndWhitePresetFileName', 'LUT3DFileName',
167
174
  'presetFileName', 'curvesPresetFileName', 'mixerPresetFileName', 'placed', 'description', 'reason',
168
175
  'artboardPresetName', 'json', 'clipID', 'relPath', 'fullPath', 'mediaDescriptor', 'Msge',
169
- 'altTag', 'url', 'cellText',
176
+ 'altTag', 'url', 'cellText', 'preset', 'KnNm', 'FPth',
177
+ ],
178
+ 'tdta': [
179
+ 'EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray',
180
+ 'LqMe',
170
181
  ],
171
- 'tdta': ['EngineData', 'LUT3DFileData', 'indexArray', 'originalVertexArray', 'deformedVertexArray'],
172
182
  'long': [
173
183
  'TextIndex', 'RndS', 'Mdpn', 'Smth', 'Lctn', 'strokeStyleVersion', 'LaID', 'Vrsn', 'Cnt ',
174
184
  'Brgh', 'Cntr', 'means', 'vibrance', 'Strt', 'bwPresetKind', 'presetKind', 'comp', 'compID', 'originalCompID',
@@ -179,16 +189,19 @@ const typeToField: { [key: string]: string[]; } = {
179
189
  'numBefore', 'numAfter', 'Spcn', 'minOpacity', 'maxOpacity', 'BlnM', 'sheetID', 'gblA', 'globalAltitude',
180
190
  'descVersion', 'frameReaderType', 'LyrI', 'zoomOrigin', 'fontSize', 'Rds ', 'sliceID',
181
191
  'topOutset', 'leftOutset', 'bottomOutset', 'rightOutset', 'filterID', 'meshQuality',
182
- 'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN',
192
+ 'meshExpansion', 'meshRigidity', 'VrsM', 'VrsN', 'NmbG', 'WLMn', 'WLMx', 'AmMn', 'AmMx', 'SclH', 'SclV',
193
+ 'Lvl ', 'TlNm', 'TlOf', 'FlRs', 'Thsh', 'ShrS', 'ShrE', 'FlRs', 'Vrnc', 'Strg', 'ExtS', 'ExtD',
194
+ 'HrzS', 'VrtS', 'NmbR', 'EdgF', 'Ang1', 'Ang2', 'Ang3', 'Ang4',
183
195
  ],
184
196
  'enum': [
185
- 'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS',
186
- 'sdwM', 'hglM', 'bvlT', 'bvlS', 'bvlD', 'Md ', 'glwS', 'GrdF', 'GlwT',
197
+ 'textGridding', 'Ornt', 'warpStyle', 'warpRotate', 'Inte', 'Bltn', 'ClrS', 'BlrQ',
198
+ 'bvlT', 'bvlS', 'bvlD', 'Md ', 'glwS', 'GrdF', 'GlwT', 'RplS', 'BlrM', 'SmBM',
187
199
  'strokeStyleLineCapType', 'strokeStyleLineJoinType', 'strokeStyleLineAlignment',
188
200
  'strokeStyleBlendMode', 'PntT', 'Styl', 'lookupType', 'LUTFormat', 'dataOrder',
189
201
  'tableOrder', 'enableCompCore', 'enableCompCoreGPU', 'compCoreSupport', 'compCoreGPUSupport', 'Engn',
190
202
  'enableCompCoreThreads', 'gs99', 'FrDs', 'trackID', 'animInterpStyle', 'horzAlign',
191
- 'vertAlign', 'bgColorType', 'shapeOperation',
203
+ 'vertAlign', 'bgColorType', 'shapeOperation', 'UndA', 'Wvtp', 'Drct', 'WndM', 'Edg ', 'FlCl', 'IntE',
204
+ 'IntC', 'Cnvr', 'Fl ', 'Dstr', 'MztT', 'Lns ', 'ExtT', 'DspM', 'ExtR', 'ZZTy', 'SphM', 'SmBQ',
192
205
  ],
193
206
  'bool': [
194
207
  'PstS', 'printSixteenBit', 'masterFXSwitch', 'enab', 'uglg', 'antialiasGloss',
@@ -200,7 +213,8 @@ const typeToField: { [key: string]: string[]; } = {
200
213
  'present', 'showInDialog', 'overprint', 'sheetDisclosed', 'lightsDisclosed', 'meshesDisclosed',
201
214
  'materialsDisclosed', 'hasMotion', 'muted', 'Effc', 'selected', 'autoScope', 'fillCanvas',
202
215
  'cellTextIsHTML', 'Smoo', 'Clsp', 'validAtPosition', 'rigidType', 'hasoptions', 'filterMaskEnable',
203
- 'filterMaskLinked', 'filterMaskExtendWithWhite',
216
+ 'filterMaskLinked', 'filterMaskExtendWithWhite', 'removeJPEGArtifact', 'Mnch', 'ExtF', 'ExtM',
217
+ 'moreAccurate', 'GpuY', 'LIWy',
204
218
  ],
205
219
  'doub': [
206
220
  'warpValue', 'warpPerspective', 'warpPerspectiveOther', 'Intr', 'Wdth', 'Hght',
@@ -210,10 +224,10 @@ const typeToField: { [key: string]: string[]; } = {
210
224
  'PuX0', 'PuX1', 'PuX2', 'PuX3', 'PuY0', 'PuY1', 'PuY2', 'PuY3'
211
225
  ],
212
226
  'UntF': [
213
- 'Scl ', 'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
227
+ 'sdwO', 'hglO', 'lagl', 'Lald', 'srgR', 'blur', 'Sftn', 'Opct', 'Dstn', 'Angl',
214
228
  'Ckmt', 'Nose', 'Inpr', 'ShdN', 'strokeStyleLineWidth', 'strokeStyleLineDashOffset',
215
229
  'strokeStyleOpacity', 'H ', 'Top ', 'Left', 'Btom', 'Rght', 'Rslt',
216
- 'topRight', 'topLeft', 'bottomLeft', 'bottomRight',
230
+ 'topRight', 'topLeft', 'bottomLeft', 'bottomRight', 'ClNs', 'Shrp',
217
231
  ],
218
232
  'VlLs': [
219
233
  'Crv ', 'Clrs', 'Mnm ', 'Mxm ', 'Trns', 'pathList', 'strokeStyleLineDashSet', 'FrLs', 'slices',
@@ -221,10 +235,12 @@ const typeToField: { [key: string]: string[]; } = {
221
235
  'solidFillMulti', 'frameFXMulti', 'innerShadowMulti', 'dropShadowMulti', 'FrIn', 'FSts', 'FsFr',
222
236
  'sheetTimelineOptions', 'audioClipList', 'trackList', 'globalTrackList', 'keyList', 'audioClipList',
223
237
  'warpValues', 'selectedPin', 'Pts ', 'SbpL', 'pathComponents', 'pinOffsets', 'posFinalPins',
224
- 'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList',
238
+ 'pinVertexIndices', 'PinP', 'PnRt', 'PnOv', 'PnDp', 'filterFXList', 'puppetShapeList', 'ShrP',
239
+ 'channelDenoise', 'Mtrx',
225
240
  ],
226
241
  'ObAr': ['meshPoints', 'quiltSliceX', 'quiltSliceY'],
227
- 'obj ': ['null'],
242
+ 'obj ': ['null', 'Chnl'],
243
+ 'Pth ': ['DspF'],
228
244
  };
229
245
 
230
246
  const channels = [
@@ -265,6 +281,9 @@ const fieldToArrayType: Dict = {
265
281
  PnDp: 'doub',
266
282
  filterFXList: 'Objc',
267
283
  puppetShapeList: 'Objc',
284
+ ShrP: 'Objc',
285
+ channelDenoise: 'Objc',
286
+ Mtrx: 'long',
268
287
  };
269
288
 
270
289
  const fieldToType: Dict = {};
@@ -331,11 +350,13 @@ function writeAsciiStringOrClassId(writer: PsdWriter, value: string) {
331
350
  }
332
351
 
333
352
  export function readDescriptorStructure(reader: PsdReader) {
334
- const object: any = {};
335
- // object.__struct =
353
+ // const struct =
336
354
  readClassStructure(reader);
355
+ // const object: any = { _name: struct.name, _classID: struct.classID };
356
+ const object: any = {};
357
+ // console.log('>> ', struct);
337
358
  const itemsCount = readUint32(reader);
338
- // console.log('//', object.__struct);
359
+
339
360
  for (let i = 0; i < itemsCount; i++) {
340
361
  const key = readAsciiStringOrClassId(reader);
341
362
  const type = readSignature(reader);
@@ -356,25 +377,57 @@ export function writeDescriptorStructure(writer: PsdWriter, name: string, classI
356
377
  writeAsciiStringOrClassId(writer, classId);
357
378
 
358
379
  const keys = Object.keys(value);
359
- writeUint32(writer, keys.length);
380
+ let keyCount = keys.length;
381
+ if ('_name' in value) keyCount--;
382
+ if ('_classID' in value) keyCount--;
383
+
384
+ writeUint32(writer, keyCount);
360
385
 
361
386
  for (const key of keys) {
387
+ if (key === '_name' || key === '_classID') continue;
388
+
362
389
  let type = getTypeByKey(key, value[key], root, value);
363
390
  let extType = fieldToExtType[key];
364
391
 
365
392
  if (key === 'origin') {
366
393
  type = root === 'slices' ? 'enum' : 'Objc';
394
+ } else if ((key === 'Cyn ' || key === 'Mgnt' || key === 'Ylw ' || key === 'Blck') && value._classID === 'CMYC') {
395
+ type = 'doub';
396
+ } else if (/^PN[a-z][a-z]$/.test(key)) {
397
+ type = 'TEXT';
398
+ } else if (/^PT[a-z][a-z]$/.test(key)) {
399
+ type = 'long';
400
+ } else if (/^PF[a-z][a-z]$/.test(key)) {
401
+ type = 'doub';
402
+ } else if (key === 'ClSz' || key === 'Rds ' || key === 'Amnt') {
403
+ type = typeof value[key] === 'number' ? 'long' : 'UntF';
404
+ } else if ((key === 'sdwM' || key === 'hglM') && typeof value[key] === 'string') {
405
+ type = 'enum';
406
+ } else if (key === 'blur' && typeof value[key] === 'string') {
407
+ type = 'enum';
408
+ } else if (key === 'Angl' && typeof value[key] === 'number') {
409
+ type = 'doub'; // ???
367
410
  } else if (key === 'bounds' && root === 'slices') {
368
411
  type = 'Objc';
369
412
  extType = makeType('', 'Rct1');
370
- } else if (key === 'Scl ' && 'Hrzn' in value[key]) {
371
- type = 'Objc';
372
- extType = nullType;
413
+ } else if (key === 'Scl ') {
414
+ if (typeof value[key] === 'object' && 'Hrzn' in value[key]) {
415
+ type = 'Objc';
416
+ extType = nullType;
417
+ } else if (typeof value[key] === 'number') {
418
+ type = 'long';
419
+ } else {
420
+ type = 'UntF';
421
+ }
373
422
  } else if (key === 'audioClipGroupList' && keys.length === 1) {
374
423
  type = 'VlLs';
375
424
  } else if ((key === 'Strt' || key === 'Brgh') && 'H ' in value) {
376
425
  type = 'doub';
377
- } else if (key === 'Strt') {
426
+ } else if (key === 'Wdth' && typeof value[key] === 'object') {
427
+ type = 'UntF';
428
+ } else if (key === 'Ofst' && typeof value[key] === 'number') {
429
+ type = 'long';
430
+ } else if (key === 'Strt' && typeof value[key] === 'object') {
378
431
  type = 'Objc';
379
432
  extType = nullType;
380
433
  } else if (channels.indexOf(key) !== -1) {
@@ -491,11 +544,11 @@ function readOSType(reader: PsdReader, type: string) {
491
544
  return items;
492
545
  }
493
546
  case 'Pth ': { // File path
494
- /*const length =*/ readInt32(reader);
547
+ /*const length =*/ readInt32(reader); // total size of all fields below
495
548
  const sig = readSignature(reader);
496
- /*const pathSize =*/ readInt32LE(reader);
549
+ /*const pathSize =*/ readInt32LE(reader); // the same as length
497
550
  const charsCount = readInt32LE(reader);
498
- const path = readUnicodeStringWithLength(reader, charsCount);
551
+ const path = readUnicodeStringWithLengthLE(reader, charsCount);
499
552
  return { sig, path };
500
553
  }
501
554
  default:
@@ -515,11 +568,16 @@ function writeOSType(writer: PsdWriter, type: string, value: any, key: string, e
515
568
  writeReferenceStructure(writer, key, value);
516
569
  break;
517
570
  case 'Objc': // Descriptor
518
- case 'GlbO': // GlobalObject same as Descriptor
571
+ case 'GlbO': { // GlobalObject same as Descriptor
572
+ if (typeof value !== 'object') throw new Error(`Invalid struct value: ${JSON.stringify(value)}, key: ${key}`);
519
573
  if (!extType) throw new Error(`Missing ext type for: '${key}' (${JSON.stringify(value)})`);
520
- writeDescriptorStructure(writer, extType.name, extType.classID, value, root);
574
+ const name = value._name || extType.name;
575
+ const classID = value._classID || extType.classID;
576
+ writeDescriptorStructure(writer, name, classID, value, root);
521
577
  break;
578
+ }
522
579
  case 'VlLs': // List
580
+ if (!Array.isArray(value)) throw new Error(`Invalid list value: ${JSON.stringify(value)}, key: ${key}`);
523
581
  writeInt32(writer, value.length);
524
582
 
525
583
  for (let i = 0; i < value.length; i++) {
@@ -530,6 +588,7 @@ function writeOSType(writer: PsdWriter, type: string, value: any, key: string, e
530
588
  }
531
589
  break;
532
590
  case 'doub': // Double
591
+ if (typeof value !== 'number') throw new Error(`Invalid number value: ${JSON.stringify(value)}, key: ${key}`);
533
592
  writeFloat64(writer, value);
534
593
  break;
535
594
  case 'UntF': // Unit double
@@ -546,17 +605,20 @@ function writeOSType(writer: PsdWriter, type: string, value: any, key: string, e
546
605
  writeUnicodeStringWithPadding(writer, value);
547
606
  break;
548
607
  case 'enum': { // Enumerated
608
+ if (typeof value !== 'string') throw new Error(`Invalid enum value: ${JSON.stringify(value)}, key: ${key}`);
549
609
  const [_type, val] = value.split('.');
550
610
  writeAsciiStringOrClassId(writer, _type);
551
611
  writeAsciiStringOrClassId(writer, val);
552
612
  break;
553
613
  }
554
614
  case 'long': // Integer
615
+ if (typeof value !== 'number') throw new Error(`Invalid integer value: ${JSON.stringify(value)}, key: ${key}`);
555
616
  writeInt32(writer, value);
556
617
  break;
557
618
  // case 'comp': // Large Integer
558
619
  // writeLargeInteger(reader);
559
620
  case 'bool': // Boolean
621
+ if (typeof value !== 'boolean') throw new Error(`Invalid boolean value: ${JSON.stringify(value)}, key: ${key}`);
560
622
  writeUint8(writer, value ? 1 : 0);
561
623
  break;
562
624
  // case 'type': // Class
@@ -588,8 +650,15 @@ function writeOSType(writer: PsdWriter, type: string, value: any, key: string, e
588
650
  }
589
651
  break;
590
652
  }
591
- // case 'Pth ': // File path
592
- // writeFilePath(reader);
653
+ case 'Pth ': { // File path
654
+ const length = 4 + 4 + 4 + value.path.length * 2;
655
+ writeInt32(writer, length);
656
+ writeSignature(writer, value.sig);
657
+ writeInt32LE(writer, length);
658
+ writeInt32LE(writer, value.path.length);
659
+ writeUnicodeStringWithoutLengthLE(writer, value.path);
660
+ break;
661
+ }
593
662
  default:
594
663
  throw new Error(`Not implemented descriptor OSType: ${type}`);
595
664
  }
@@ -690,7 +759,6 @@ function writeReferenceStructure(writer: PsdWriter, _key: string, items: any[])
690
759
  function readClassStructure(reader: PsdReader) {
691
760
  const name = readUnicodeString(reader);
692
761
  const classID = readAsciiStringOrClassId(reader);
693
- // console.log({ name, classID });
694
762
  return { name, classID };
695
763
  }
696
764
 
@@ -721,25 +789,37 @@ export interface DescriptorUnitsValue {
721
789
  }
722
790
 
723
791
  export type DescriptorColor = {
792
+ _name: '';
793
+ _classID: 'RGBC';
724
794
  'Rd ': number;
725
795
  'Grn ': number;
726
796
  'Bl ': number;
727
797
  } | {
798
+ _name: '';
799
+ _classID: 'HSBC'; // ???
728
800
  'H ': DescriptorUnitsValue;
729
801
  Strt: number;
730
802
  Brgh: number;
731
803
  } | {
804
+ _name: '';
805
+ _classID: 'CMYC';
732
806
  'Cyn ': number;
733
807
  Mgnt: number;
734
808
  'Ylw ': number;
735
809
  Blck: number;
736
810
  } | {
811
+ _name: '';
812
+ _classID: 'GRYC'; // ???
737
813
  'Gry ': number;
738
814
  } | {
815
+ _name: '';
816
+ _classID: 'LABC'; // ???
739
817
  Lmnc: number;
740
818
  'A ': number;
741
819
  'B ': number;
742
820
  } | {
821
+ _name: '';
822
+ _classID: 'XXXX'; // ???
743
823
  redFloat: number;
744
824
  greenFloat: number;
745
825
  blueFloat: number;
@@ -844,6 +924,8 @@ export interface WarpDescriptor {
844
924
  uOrder: number;
845
925
  vOrder: number;
846
926
  customEnvelopeWarp?: {
927
+ _name: '';
928
+ _classID: 'customEnvelopeWarp';
847
929
  meshPoints: {
848
930
  type: 'Hrzn' | 'Vrtc';
849
931
  values: number[];
@@ -855,6 +937,8 @@ export interface QuiltWarpDescriptor extends WarpDescriptor {
855
937
  deformNumRows: number;
856
938
  deformNumCols: number;
857
939
  customEnvelopeWarp: {
940
+ _name: '';
941
+ _classID: 'customEnvelopeWarp';
858
942
  quiltSliceX: {
859
943
  type: 'quiltSliceX';
860
944
  values: number[];
@@ -1122,7 +1206,8 @@ function parseKeyList(keyList: TimelineKeyDescriptor[], logMissingFeatures: bool
1122
1206
 
1123
1207
  for (let j = 0; j < keyList.length; j++) {
1124
1208
  const key = keyList[j];
1125
- const { time, selected, animKey } = key;
1209
+ const { time: { denominator, numerator }, selected, animKey } = key;
1210
+ const time = { numerator, denominator };
1126
1211
  const interpolation = animInterpStyleEnum.decode(key.animInterpStyle);
1127
1212
 
1128
1213
  switch (animKey.Type) {
@@ -1307,6 +1392,9 @@ function parseEffectObject(obj: any, reportErrors: boolean) {
1307
1392
  case 'present':
1308
1393
  case 'showInDialog':
1309
1394
  case 'antialiasGloss': result[key] = val; break;
1395
+ case '_name':
1396
+ case '_classID':
1397
+ break;
1310
1398
  default:
1311
1399
  reportErrors && console.log(`Invalid effect key: '${key}', value:`, val);
1312
1400
  }
@@ -1564,19 +1652,19 @@ export function parseColor(color: DescriptorColor): Color {
1564
1652
 
1565
1653
  export function serializeColor(color: Color | undefined): DescriptorColor {
1566
1654
  if (!color) {
1567
- return { 'Rd ': 0, 'Grn ': 0, 'Bl ': 0 };
1655
+ return { _name: '', _classID: 'RGBC', 'Rd ': 0, 'Grn ': 0, 'Bl ': 0 };
1568
1656
  } else if ('r' in color) {
1569
- return { 'Rd ': color.r || 0, 'Grn ': color.g || 0, 'Bl ': color.b || 0 };
1657
+ return { _name: '', _classID: 'RGBC', 'Rd ': color.r || 0, 'Grn ': color.g || 0, 'Bl ': color.b || 0 };
1570
1658
  } else if ('fr' in color) {
1571
- return { redFloat: color.fr, greenFloat: color.fg, blueFloat: color.fb };
1659
+ return { _name: '', _classID: 'XXXX', redFloat: color.fr, greenFloat: color.fg, blueFloat: color.fb };
1572
1660
  } else if ('h' in color) {
1573
- return { 'H ': unitsAngle(color.h * 360), Strt: color.s || 0, Brgh: color.b || 0 };
1661
+ return { _name: '', _classID: 'HSBC', 'H ': unitsAngle(color.h * 360), Strt: color.s || 0, Brgh: color.b || 0 };
1574
1662
  } else if ('c' in color) {
1575
- return { 'Cyn ': color.c || 0, Mgnt: color.m || 0, 'Ylw ': color.y || 0, Blck: color.k || 0 };
1663
+ return { _name: '', _classID: 'CMYC', 'Cyn ': color.c || 0, Mgnt: color.m || 0, 'Ylw ': color.y || 0, Blck: color.k || 0 };
1576
1664
  } else if ('l' in color) {
1577
- return { Lmnc: color.l || 0, 'A ': color.a || 0, 'B ': color.b || 0 };
1665
+ return { _name: '', _classID: 'LABC', Lmnc: color.l || 0, 'A ': color.a || 0, 'B ': color.b || 0 };
1578
1666
  } else if ('k' in color) {
1579
- return { 'Gry ': color.k };
1667
+ return { _name: '', _classID: 'GRYC', 'Gry ': color.k };
1580
1668
  } else {
1581
1669
  throw new Error('Invalid color value');
1582
1670
  }
@@ -1629,6 +1717,10 @@ export function unitsPercent(value: number | undefined): DescriptorUnitsValue {
1629
1717
  return { units: 'Percent', value: Math.round((value || 0) * 100) };
1630
1718
  }
1631
1719
 
1720
+ export function unitsPercentF(value: number | undefined): DescriptorUnitsValue {
1721
+ return { units: 'Percent', value: (value || 0) * 100 };
1722
+ }
1723
+
1632
1724
  export function unitsValue(x: UnitsValue | undefined, key: string): DescriptorUnitsValue {
1633
1725
  if (x == null) return { units: 'Pixels', value: 0 };
1634
1726
 
@@ -1650,6 +1742,10 @@ export function unitsValue(x: UnitsValue | undefined, key: string): DescriptorUn
1650
1742
  return { units, value };
1651
1743
  }
1652
1744
 
1745
+ export function frac({ numerator, denominator }: FractionDescriptor) {
1746
+ return { numerator, denominator };
1747
+ }
1748
+
1653
1749
  export const textGridding = createEnum<TextGridding>('textGridding', 'none', {
1654
1750
  none: 'None',
1655
1751
  round: 'Rnd ',
@@ -1785,6 +1881,7 @@ export const ClrS = createEnum<'rgb' | 'hsb' | 'lab'>('ClrS', 'rgb', {
1785
1881
  rgb: 'RGBC',
1786
1882
  hsb: 'HSBl',
1787
1883
  lab: 'LbCl',
1884
+ hsl: 'HSLC',
1788
1885
  });
1789
1886
 
1790
1887
  export const FStl = createEnum<'inside' | 'center' | 'outside'>('FStl', 'outside', {
@@ -1841,3 +1938,166 @@ export const strokeStyleLineAlignment = createEnum<LineAlignment>('strokeStyleLi
1841
1938
  center: 'strokeStyleAlignCenter',
1842
1939
  outside: 'strokeStyleAlignOutside',
1843
1940
  });
1941
+
1942
+ export const BlrM = createEnum<'spin' | 'zoom'>('BlrM', 'ispinmage', {
1943
+ spin: 'Spn ',
1944
+ zoom: 'Zm ',
1945
+ });
1946
+
1947
+ export const BlrQ = createEnum<'draft' | 'good' | 'best'>('BlrQ', 'good', {
1948
+ draft: 'Drft',
1949
+ good: 'Gd ',
1950
+ best: 'Bst ',
1951
+ });
1952
+
1953
+ export const SmBM = createEnum<'normal' | 'edge only' | 'overlay edge'>('SmBM', 'normal', {
1954
+ normal: 'SBMN',
1955
+ 'edge only': 'SBME',
1956
+ 'overlay edge': 'SBMO',
1957
+ });
1958
+
1959
+ export const SmBQ = createEnum<'low' | 'medium' | 'high'>('SmBQ', 'medium', {
1960
+ low: 'SBQL',
1961
+ medium: 'SBQM',
1962
+ high: 'SBQH',
1963
+ });
1964
+
1965
+ export const DspM = createEnum<'stretch to fit' | 'tile'>('DspM', 'stretch to fit', {
1966
+ 'stretch to fit': 'StrF',
1967
+ 'tile': 'Tile',
1968
+ });
1969
+
1970
+ export const UndA = createEnum<'wrap around' | 'repeat edge pixels'>('UndA', 'repeat edge pixels', {
1971
+ 'wrap around': 'WrpA',
1972
+ 'repeat edge pixels': 'RptE',
1973
+ });
1974
+
1975
+ export const Cnvr = createEnum<'rectangular to polar' | 'polar to rectangular'>('Cnvr', 'rectangular to polar', {
1976
+ 'rectangular to polar': 'RctP',
1977
+ 'polar to rectangular': 'PlrR',
1978
+ });
1979
+
1980
+ export const RplS = createEnum<'small' | 'medium' | 'large'>('RplS', 'medium', {
1981
+ small: 'Sml ',
1982
+ medium: 'Mdm ',
1983
+ large: 'Lrg ',
1984
+ });
1985
+
1986
+ export const SphM = createEnum<'normal' | 'horizontal only' | 'vertical only'>('SphM', 'normal', {
1987
+ 'normal': 'Nrml',
1988
+ 'horizontal only': 'HrzO',
1989
+ 'vertical only': 'VrtO',
1990
+ });
1991
+
1992
+ export const Wvtp = createEnum<'sine' | 'triangle' | 'square'>('Wvtp', 'sine', {
1993
+ sine: 'WvSn',
1994
+ triangle: 'WvTr',
1995
+ square: 'WvSq',
1996
+ });
1997
+
1998
+ export const ZZTy = createEnum<'around center' | 'out from center' | 'pond ripples'>('ZZTy', 'pond ripples', {
1999
+ 'around center': 'ArnC',
2000
+ 'out from center': 'OtFr',
2001
+ 'pond ripples': 'PndR',
2002
+ });
2003
+
2004
+ export const Dstr = createEnum<'uniform' | 'gaussian'>('Dstr', 'uniform', {
2005
+ uniform: 'Unfr',
2006
+ gaussian: 'Gsn ',
2007
+ });
2008
+
2009
+ export const Chnl = createEnum<'red' | 'green' | 'blue' | 'composite'>('Chnl', 'composite', {
2010
+ red: 'Rd ',
2011
+ green: 'Grn ',
2012
+ blue: 'Bl ',
2013
+ composite: 'Cmps',
2014
+ });
2015
+
2016
+ export const MztT = createEnum<'fine dots' | 'medium dots' | 'grainy dots' | 'coarse dots' | 'short lines' | 'medium lines' | 'long lines' | 'short strokes' | 'medium strokes' | 'long strokes'>('MztT', 'fine dots', {
2017
+ 'fine dots': 'FnDt',
2018
+ 'medium dots': 'MdmD',
2019
+ 'grainy dots': 'GrnD',
2020
+ 'coarse dots': 'CrsD',
2021
+ 'short lines': 'ShrL',
2022
+ 'medium lines': 'MdmL',
2023
+ 'long lines': 'LngL',
2024
+ 'short strokes': 'ShSt',
2025
+ 'medium strokes': 'MdmS',
2026
+ 'long strokes': 'LngS',
2027
+ });
2028
+
2029
+ export const Lns = createEnum<'50-300mm zoom' | '32mm prime' | '105mm prime' | 'movie prime'>('Lns ', '50-300mm zoom', {
2030
+ '50-300mm zoom': 'Zm ',
2031
+ '32mm prime': 'Nkn ',
2032
+ '105mm prime': 'Nkn1',
2033
+ 'movie prime': 'PnVs',
2034
+ });
2035
+
2036
+ export const blurType = createEnum<'gaussian blur' | 'lens blur' | 'motion blur'>('blurType', 'gaussian blur', {
2037
+ 'gaussian blur': 'GsnB',
2038
+ 'lens blur': 'lensBlur',
2039
+ 'motion blur': 'MtnB',
2040
+ });
2041
+
2042
+ export const DfsM = createEnum<'normal' | 'darken only' | 'lighten only' | 'anisotropic'>('DfsM', 'normal', {
2043
+ 'normal': 'Nrml',
2044
+ 'darken only': 'DrkO',
2045
+ 'lighten only': 'LghO',
2046
+ 'anisotropic': 'anisotropic',
2047
+ });
2048
+
2049
+ export const ExtT = createEnum<'blocks' | 'pyramids'>('ExtT', 'blocks', {
2050
+ blocks: 'Blks',
2051
+ pyramids: 'Pyrm',
2052
+ });
2053
+
2054
+ export const ExtR = createEnum<'random' | 'level-based'>('ExtR', 'random', {
2055
+ random: 'Rndm',
2056
+ 'level-based': 'LvlB',
2057
+ });
2058
+
2059
+ export const FlCl = createEnum<'background color' | 'foreground color' | 'inverse image' | 'unaltered image'>('FlCl', 'background color', {
2060
+ 'background color': 'FlBc',
2061
+ 'foreground color': 'FlFr',
2062
+ 'inverse image': 'FlIn',
2063
+ 'unaltered image': 'FlSm',
2064
+ });
2065
+
2066
+ export const CntE = createEnum<'lower' | 'upper'>('CntE', 'upper', {
2067
+ lower: 'Lwr ',
2068
+ upper: 'Upr ',
2069
+ });
2070
+
2071
+ export const WndM = createEnum<'wind' | 'blast' | 'stagger'>('WndM', 'wind', {
2072
+ wind: 'Wnd ',
2073
+ blast: 'Blst',
2074
+ stagger: 'Stgr',
2075
+ });
2076
+
2077
+ export const Drct = createEnum<'left' | 'right'>('Drct', 'from the right', {
2078
+ left: 'Left',
2079
+ right: 'Rght',
2080
+ });
2081
+
2082
+ export const IntE = createEnum<'odd lines' | 'even lines'>('IntE', 'odd lines', {
2083
+ 'odd lines': 'ElmO',
2084
+ 'even lines': 'ElmE',
2085
+ });
2086
+
2087
+ export const IntC = createEnum<'duplication' | 'interpolation'>('IntC', 'interpolation', {
2088
+ duplication: 'CrtD',
2089
+ interpolation: 'CrtI',
2090
+ });
2091
+
2092
+ export const FlMd = createEnum<'set to transparent' | 'repeat edge pixels' | 'wrap around'>('FlMd', 'wrap around', {
2093
+ 'set to transparent': 'Bckg',
2094
+ 'repeat edge pixels': 'Rpt ',
2095
+ 'wrap around': 'Wrp ',
2096
+ });
2097
+
2098
+ export const prjM = createEnum<'fisheye' | 'perspective' | 'auto' | 'full spherical'>('prjM', 'fisheye', {
2099
+ 'fisheye': 'fisP',
2100
+ 'perspective': 'perP',
2101
+ 'auto': 'auto',
2102
+ 'full spherical': 'fusP',
2103
+ });