ag-psd 15.0.3 → 15.0.5

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/text.ts ADDED
@@ -0,0 +1,751 @@
1
+ import { TextStyle, LayerTextData, ParagraphStyle, Font, AntiAlias, TextGridInfo, Justification, Color } from './psd';
2
+
3
+ interface Adjustments {
4
+ Axis: number[];
5
+ XY: number[];
6
+ }
7
+
8
+ interface TypeValues {
9
+ Type: number;
10
+ Values: number[];
11
+ }
12
+
13
+ interface ParagraphProperties {
14
+ Justification?: number;
15
+ FirstLineIndent?: number;
16
+ StartIndent?: number;
17
+ EndIndent?: number;
18
+ SpaceBefore?: number;
19
+ SpaceAfter?: number;
20
+ AutoHyphenate?: boolean;
21
+ HyphenatedWordSize?: number;
22
+ PreHyphen?: number;
23
+ PostHyphen?: number;
24
+ ConsecutiveHyphens?: number;
25
+ Zone?: number;
26
+ WordSpacing?: number[];
27
+ LetterSpacing?: number[];
28
+ GlyphSpacing?: number[];
29
+ AutoLeading?: number;
30
+ LeadingType?: number;
31
+ Hanging?: boolean;
32
+ Burasagari?: boolean;
33
+ KinsokuOrder?: number;
34
+ EveryLineComposer?: boolean;
35
+ }
36
+
37
+ interface ParagraphSheet {
38
+ Name?: string;
39
+ DefaultStyleSheet: number;
40
+ Properties: ParagraphProperties;
41
+ }
42
+
43
+ interface StyleSheetData {
44
+ Font?: number;
45
+ FontSize?: number;
46
+ FauxBold?: boolean;
47
+ FauxItalic?: boolean;
48
+ AutoLeading?: boolean;
49
+ Leading?: number;
50
+ HorizontalScale?: number;
51
+ VerticalScale?: number;
52
+ Tracking?: number;
53
+ AutoKerning?: boolean;
54
+ Kerning?: number;
55
+ BaselineShift?: number;
56
+ FontCaps?: number;
57
+ FontBaseline?: number;
58
+ Underline?: boolean;
59
+ Strikethrough?: boolean;
60
+ Ligatures?: boolean;
61
+ DLigatures?: boolean;
62
+ BaselineDirection?: number;
63
+ Tsume?: number;
64
+ StyleRunAlignment?: number;
65
+ Language?: number;
66
+ NoBreak?: boolean;
67
+ FillColor?: TypeValues;
68
+ StrokeColor?: TypeValues;
69
+ FillFlag?: boolean;
70
+ StrokeFlag?: boolean;
71
+ FillFirst?: boolean;
72
+ YUnderline?: number;
73
+ OutlineWidth?: number;
74
+ CharacterDirection?: number;
75
+ HindiNumbers?: boolean;
76
+ Kashida?: number;
77
+ DiacriticPos?: number;
78
+ }
79
+
80
+ interface FontSet {
81
+ Name: string;
82
+ Script: number;
83
+ FontType: number;
84
+ Synthetic: number;
85
+ }
86
+
87
+ interface ResourceDict {
88
+ KinsokuSet: any[];
89
+ MojiKumiSet: any[];
90
+ TheNormalStyleSheet: number;
91
+ TheNormalParagraphSheet: number;
92
+ ParagraphSheetSet: ParagraphSheet[];
93
+ StyleSheetSet: { Name: string; StyleSheetData: StyleSheetData; }[];
94
+ FontSet: FontSet[];
95
+ SuperscriptSize: number;
96
+ SuperscriptPosition: number;
97
+ SubscriptSize: number;
98
+ SubscriptPosition: number;
99
+ SmallCapSize: number;
100
+ }
101
+
102
+ interface ParagraphRun {
103
+ ParagraphSheet: ParagraphSheet;
104
+ Adjustments: Adjustments;
105
+ }
106
+
107
+ interface StyleRun {
108
+ StyleSheet: { StyleSheetData: StyleSheetData; };
109
+ }
110
+
111
+ interface PhotoshopNode {
112
+ ShapeType?: number;
113
+ PointBase?: number[];
114
+ BoxBounds?: number[];
115
+ Base?: {
116
+ ShapeType: number;
117
+ TransformPoint0: number[];
118
+ TransformPoint1: number[];
119
+ TransformPoint2: number[];
120
+ };
121
+ }
122
+
123
+ interface EngineData {
124
+ EngineDict: {
125
+ Editor: { Text: string; };
126
+ ParagraphRun: {
127
+ DefaultRunData: ParagraphRun;
128
+ RunArray: ParagraphRun[];
129
+ RunLengthArray: number[];
130
+ IsJoinable: number;
131
+ };
132
+ StyleRun: {
133
+ DefaultRunData: StyleRun;
134
+ RunArray: StyleRun[];
135
+ RunLengthArray: number[];
136
+ IsJoinable: number;
137
+ };
138
+ GridInfo: {
139
+ GridIsOn: boolean;
140
+ ShowGrid: boolean;
141
+ GridSize: number;
142
+ GridLeading: number;
143
+ GridColor: TypeValues;
144
+ GridLeadingFillColor: TypeValues;
145
+ AlignLineHeightToGridFlags: boolean;
146
+ };
147
+ AntiAlias: number;
148
+ UseFractionalGlyphWidths: boolean;
149
+ Rendered?: {
150
+ Version: number;
151
+ Shapes?: {
152
+ WritingDirection: number;
153
+ Children?: {
154
+ ShapeType?: number;
155
+ Procession: number;
156
+ Lines: { WritingDirection: number; Children: any[]; };
157
+ Cookie?: {
158
+ Photoshop?: PhotoshopNode;
159
+ };
160
+ }[];
161
+ };
162
+ };
163
+ };
164
+ ResourceDict: ResourceDict;
165
+ DocumentResources: ResourceDict;
166
+ }
167
+
168
+ const defaultFont: Font = {
169
+ name: 'MyriadPro-Regular',
170
+ script: 0,
171
+ type: 0,
172
+ synthetic: 0,
173
+ };
174
+
175
+ const defaultParagraphStyle: ParagraphStyle = {
176
+ justification: 'left',
177
+ firstLineIndent: 0,
178
+ startIndent: 0,
179
+ endIndent: 0,
180
+ spaceBefore: 0,
181
+ spaceAfter: 0,
182
+ autoHyphenate: true,
183
+ hyphenatedWordSize: 6,
184
+ preHyphen: 2,
185
+ postHyphen: 2,
186
+ consecutiveHyphens: 8,
187
+ zone: 36,
188
+ wordSpacing: [0.8, 1, 1.33],
189
+ letterSpacing: [0, 0, 0],
190
+ glyphSpacing: [1, 1, 1],
191
+ autoLeading: 1.2,
192
+ leadingType: 0,
193
+ hanging: false,
194
+ burasagari: false,
195
+ kinsokuOrder: 0,
196
+ everyLineComposer: false,
197
+ };
198
+
199
+ const defaultStyle: TextStyle = {
200
+ font: defaultFont,
201
+ fontSize: 12,
202
+ fauxBold: false,
203
+ fauxItalic: false,
204
+ autoLeading: true,
205
+ leading: 0,
206
+ horizontalScale: 1,
207
+ verticalScale: 1,
208
+ tracking: 0,
209
+ autoKerning: true,
210
+ kerning: 0,
211
+ baselineShift: 0,
212
+ fontCaps: 0,
213
+ fontBaseline: 0,
214
+ underline: false,
215
+ strikethrough: false,
216
+ ligatures: true,
217
+ dLigatures: false,
218
+ baselineDirection: 2,
219
+ tsume: 0,
220
+ styleRunAlignment: 2,
221
+ language: 0,
222
+ noBreak: false,
223
+ fillColor: { r: 0, g: 0, b: 0 },
224
+ strokeColor: { r: 0, g: 0, b: 0 },
225
+ fillFlag: true,
226
+ strokeFlag: false,
227
+ fillFirst: true,
228
+ yUnderline: 1,
229
+ outlineWidth: 1,
230
+ characterDirection: 0,
231
+ hindiNumbers: false,
232
+ kashida: 1,
233
+ diacriticPos: 2,
234
+ };
235
+
236
+ const defaultGridInfo: TextGridInfo = {
237
+ isOn: false,
238
+ show: false,
239
+ size: 18,
240
+ leading: 22,
241
+ color: { r: 0, g: 0, b: 255 },
242
+ leadingFillColor: { r: 0, g: 0, b: 255 },
243
+ alignLineHeightToGridFlags: false,
244
+ };
245
+
246
+ const paragraphStyleKeys: (keyof ParagraphStyle)[] = [
247
+ 'justification', 'firstLineIndent', 'startIndent', 'endIndent', 'spaceBefore', 'spaceAfter',
248
+ 'autoHyphenate', 'hyphenatedWordSize', 'preHyphen', 'postHyphen', 'consecutiveHyphens',
249
+ 'zone', 'wordSpacing', 'letterSpacing', 'glyphSpacing', 'autoLeading', 'leadingType',
250
+ 'hanging', 'burasagari', 'kinsokuOrder', 'everyLineComposer',
251
+ ];
252
+
253
+ const styleKeys: (keyof TextStyle)[] = [
254
+ 'font', 'fontSize', 'fauxBold', 'fauxItalic', 'autoLeading', 'leading', 'horizontalScale',
255
+ 'verticalScale', 'tracking', 'autoKerning', 'kerning', 'baselineShift', 'fontCaps', 'fontBaseline',
256
+ 'underline', 'strikethrough', 'ligatures', 'dLigatures', 'baselineDirection', 'tsume',
257
+ 'styleRunAlignment', 'language', 'noBreak', 'fillColor', 'strokeColor', 'fillFlag',
258
+ 'strokeFlag', 'fillFirst', 'yUnderline', 'outlineWidth', 'characterDirection', 'hindiNumbers',
259
+ 'kashida', 'diacriticPos',
260
+ ];
261
+
262
+ const antialias: AntiAlias[] = ['none', 'crisp', 'strong', 'smooth', 'sharp'];
263
+ const justification: Justification[] = ['left', 'right', 'center'];
264
+
265
+ function upperFirst(value: string) {
266
+ return value.substr(0, 1).toUpperCase() + value.substr(1);
267
+ }
268
+
269
+ function decodeColor(color: { Type: number; Values: number[]; }): Color {
270
+ const c = color.Values;
271
+
272
+ if (color.Type === 0) { // grayscale
273
+ return { r: c[1] * 255, g: c[1] * 255, b: c[1] * 255 }; // , c[0] * 255];
274
+ } else { // rgb
275
+ return { r: c[1] * 255, g: c[2] * 255, b: c[3] * 255, a: c[0] }; // , c[0] * 255];
276
+ }
277
+ }
278
+
279
+ function encodeColor(color: Color | undefined) {
280
+ if (color && 'r' in color) {
281
+ return ['a' in color ? color.a : 1, color.r / 255, color.g / 255, color.b / 255];
282
+ } else {
283
+ return [0, 0, 0, 0];
284
+ }
285
+ }
286
+
287
+ function arraysEqual(a: any[], b: any[]) {
288
+ if (!a || !b) return false;
289
+ if (a.length !== b.length) return false;
290
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
291
+ return true;
292
+ }
293
+
294
+ function objectsEqual(a: any, b: any) {
295
+ if (!a || !b) return false;
296
+ for (const key of Object.keys(a)) if (a[key] !== b[key]) return false;
297
+ for (const key of Object.keys(b)) if (a[key] !== b[key]) return false;
298
+ return true;
299
+ }
300
+
301
+ function findOrAddFont(fonts: Font[], font: Font) {
302
+ for (let i = 0; i < fonts.length; i++) {
303
+ if (fonts[i].name === font.name) return i;
304
+ }
305
+
306
+ fonts.push(font);
307
+ return fonts.length - 1;
308
+ }
309
+
310
+ function decodeObject(obj: any, keys: string[], fonts: Font[]) {
311
+ const result: any = {};
312
+
313
+ for (const key of keys) {
314
+ const Key = upperFirst(key);
315
+
316
+ if (obj[Key] === undefined) continue;
317
+
318
+ if (key === 'justification') {
319
+ result[key] = justification[obj[Key]];
320
+ } else if (key === 'font') {
321
+ result[key] = fonts[obj[Key]];
322
+ } else if (key === 'fillColor' || key === 'strokeColor') {
323
+ result[key] = decodeColor(obj[Key]);
324
+ } else {
325
+ result[key] = obj[Key];
326
+ }
327
+ }
328
+
329
+ return result;
330
+ }
331
+
332
+ function encodeObject(obj: any, keys: string[], fonts: Font[]) {
333
+ const result: any = {};
334
+
335
+ for (const key of keys) {
336
+ const Key = upperFirst(key);
337
+
338
+ if (obj[key] === undefined) continue;
339
+
340
+ if (key === 'justification') {
341
+ result[Key] = justification.indexOf(obj[key] ?? 'left');
342
+ } else if (key === 'font') {
343
+ result[Key] = findOrAddFont(fonts, obj[key]);
344
+ } else if (key === 'fillColor' || key === 'strokeColor') {
345
+ result[Key] = { Type: 1, Values: encodeColor(obj[key]) } as TypeValues;
346
+ } else {
347
+ result[Key] = obj[key];
348
+ }
349
+ }
350
+
351
+ return result;
352
+ }
353
+
354
+ function decodeParagraphStyle(obj: ParagraphProperties, fonts: Font[]): ParagraphStyle {
355
+ return decodeObject(obj, paragraphStyleKeys, fonts);
356
+ }
357
+
358
+ function decodeStyle(obj: StyleSheetData, fonts: Font[]): TextStyle {
359
+ return decodeObject(obj, styleKeys, fonts);
360
+ }
361
+
362
+ function encodeParagraphStyle(obj: ParagraphStyle, fonts: Font[]): ParagraphProperties {
363
+ return encodeObject(obj, paragraphStyleKeys, fonts);
364
+ }
365
+
366
+ function encodeStyle(obj: TextStyle, fonts: Font[]): StyleSheetData {
367
+ return encodeObject(obj, styleKeys, fonts);
368
+ }
369
+
370
+ function deduplicateValues<T>(base: T, runs: { style: T; }[], keys: (keyof T)[]) {
371
+ if (!runs.length) return;
372
+
373
+ for (const key of keys) {
374
+ const value = runs[0].style[key];
375
+
376
+ if (value !== undefined) {
377
+ let identical = false;
378
+
379
+ if (Array.isArray(value)) {
380
+ identical = runs.every(r => arraysEqual(r.style[key] as any, value));
381
+ } else if (typeof value === 'object') {
382
+ identical = runs.every(r => objectsEqual(r.style[key] as any, value));
383
+ } else {
384
+ identical = runs.every(r => r.style[key] === value);
385
+ }
386
+
387
+ if (identical) {
388
+ base[key] = value as any;
389
+ }
390
+ }
391
+
392
+ const styleValue = base[key];
393
+
394
+ if (styleValue !== undefined) {
395
+ for (const r of runs) {
396
+ let same = false;
397
+
398
+ if (Array.isArray(value)) {
399
+ same = arraysEqual(r.style[key] as any, value);
400
+ } else if (typeof value === 'object') {
401
+ same = objectsEqual(r.style[key] as any, value);
402
+ } else {
403
+ same = r.style[key] === value;
404
+ }
405
+
406
+ if (same) delete r.style[key];
407
+ }
408
+ }
409
+ }
410
+
411
+ if (runs.every(x => Object.keys(x.style as any).length === 0)) {
412
+ runs.length = 0;
413
+ }
414
+ }
415
+
416
+ export function decodeEngineData(engineData: EngineData) {
417
+ // console.log('engineData', require('util').inspect(engineData, false, 99, true));
418
+ const engineDict = engineData.EngineDict;
419
+ const resourceDict = engineData.ResourceDict;
420
+
421
+ const fonts = resourceDict.FontSet.map<Font>(f => ({
422
+ name: f.Name,
423
+ script: f.Script,
424
+ type: f.FontType,
425
+ synthetic: f.Synthetic,
426
+ }));
427
+
428
+ let text = engineDict.Editor.Text.replace(/\r/g, '\n');
429
+ let removedCharacters = 0;
430
+
431
+ while (/\n$/.test(text)) {
432
+ text = text.substr(0, text.length - 1);
433
+ removedCharacters++;
434
+ }
435
+
436
+ const result: LayerTextData = {
437
+ text,
438
+ antiAlias: antialias[engineDict.AntiAlias] ?? 'smooth',
439
+ useFractionalGlyphWidths: !!engineDict.UseFractionalGlyphWidths,
440
+ superscriptSize: resourceDict.SuperscriptSize,
441
+ superscriptPosition: resourceDict.SuperscriptPosition,
442
+ subscriptSize: resourceDict.SubscriptSize,
443
+ subscriptPosition: resourceDict.SubscriptPosition,
444
+ smallCapSize: resourceDict.SmallCapSize,
445
+ };
446
+
447
+ // shape
448
+
449
+ const photoshop = engineDict.Rendered?.Shapes?.Children?.[0]?.Cookie?.Photoshop;
450
+
451
+ if (photoshop) {
452
+ result.shapeType = photoshop.ShapeType === 1 ? 'box' : 'point';
453
+ if (photoshop.PointBase) result.pointBase = photoshop.PointBase;
454
+ if (photoshop.BoxBounds) result.boxBounds = photoshop.BoxBounds;
455
+ }
456
+
457
+ // paragraph style
458
+
459
+ // const theNormalParagraphSheet = resourceDict.TheNormalParagraphSheet;
460
+ // const paragraphSheetSet = resourceDict.ParagraphSheetSet;
461
+ // const paragraphProperties = paragraphSheetSet[theNormalParagraphSheet].Properties;
462
+ const paragraphRun = engineData.EngineDict.ParagraphRun;
463
+
464
+ result.paragraphStyle = {}; // decodeParagraphStyle(paragraphProperties, fonts);
465
+ result.paragraphStyleRuns = [];
466
+
467
+ for (let i = 0; i < paragraphRun.RunArray.length; i++) {
468
+ const run = paragraphRun.RunArray[i];
469
+ const length = paragraphRun.RunLengthArray[i];
470
+ const style = decodeParagraphStyle(run.ParagraphSheet.Properties, fonts);
471
+ // const adjustments = {
472
+ // axis: run.Adjustments.Axis,
473
+ // xy: run.Adjustments.XY,
474
+ // };
475
+ result.paragraphStyleRuns.push({ length, style/*, adjustments*/ });
476
+ }
477
+
478
+ for (let counter = removedCharacters; result.paragraphStyleRuns.length && counter > 0; counter--) {
479
+ if (--result.paragraphStyleRuns[result.paragraphStyleRuns.length - 1].length === 0) {
480
+ result.paragraphStyleRuns.pop();
481
+ }
482
+ }
483
+
484
+ deduplicateValues(result.paragraphStyle, result.paragraphStyleRuns, paragraphStyleKeys);
485
+
486
+ if (!result.paragraphStyleRuns.length) delete result.paragraphStyleRuns;
487
+
488
+ // style
489
+
490
+ // const theNormalStyleSheet = resourceDict.TheNormalStyleSheet;
491
+ // const styleSheetSet = resourceDict.StyleSheetSet;
492
+ // const styleSheetData = styleSheetSet[theNormalStyleSheet].StyleSheetData;
493
+ const styleRun = engineData.EngineDict.StyleRun;
494
+
495
+ result.style = {}; // decodeStyle(styleSheetData, fonts);
496
+ result.styleRuns = [];
497
+
498
+ for (let i = 0; i < styleRun.RunArray.length; i++) {
499
+ const length = styleRun.RunLengthArray[i];
500
+ const style = decodeStyle(styleRun.RunArray[i].StyleSheet.StyleSheetData, fonts);
501
+ result.styleRuns.push({ length, style });
502
+ }
503
+
504
+ for (let counter = removedCharacters; result.styleRuns.length && counter > 0; counter--) {
505
+ if (--result.styleRuns[result.styleRuns.length - 1].length === 0) {
506
+ result.styleRuns.pop();
507
+ }
508
+ }
509
+
510
+ deduplicateValues(result.style, result.styleRuns, styleKeys);
511
+
512
+ if (!result.styleRuns.length) delete result.styleRuns;
513
+
514
+ return result;
515
+ }
516
+
517
+ export function encodeEngineData(data: LayerTextData) {
518
+ const text = `${(data.text || '').replace(/\r?\n/g, '\r')}\r`;
519
+
520
+ const fonts: Font[] = [
521
+ { name: 'AdobeInvisFont', script: 0, type: 0, synthetic: 0 },
522
+ ];
523
+
524
+ const defFont = data.style?.font || data.styleRuns?.find(s => s.style.font)?.style.font || defaultFont;
525
+ const paragraphRunArray: ParagraphRun[] = [];
526
+ const paragraphRunLengthArray: number[] = [];
527
+ const paragraphRuns = data.paragraphStyleRuns;
528
+
529
+ if (paragraphRuns && paragraphRuns.length) {
530
+ let leftLength = text.length;
531
+
532
+ for (const run of paragraphRuns) {
533
+ let runLength = Math.min(run.length, leftLength);
534
+ leftLength -= runLength;
535
+
536
+ if (!runLength) continue; // ignore 0 size runs
537
+
538
+ // extend last run if it's only for trailing \r
539
+ if (leftLength === 1 && run === paragraphRuns[paragraphRuns.length - 1]) {
540
+ runLength++;
541
+ leftLength--;
542
+ }
543
+
544
+ paragraphRunLengthArray.push(runLength);
545
+ paragraphRunArray.push({
546
+ ParagraphSheet: {
547
+ DefaultStyleSheet: 0,
548
+ Properties: encodeParagraphStyle({ ...defaultParagraphStyle, ...data.paragraphStyle, ...run.style }, fonts),
549
+ },
550
+ Adjustments: { Axis: [1, 0, 1], XY: [0, 0] },
551
+ });
552
+ }
553
+
554
+ if (leftLength) {
555
+ paragraphRunLengthArray.push(leftLength);
556
+ paragraphRunArray.push({
557
+ ParagraphSheet: {
558
+ DefaultStyleSheet: 0,
559
+ Properties: encodeParagraphStyle({ ...defaultParagraphStyle, ...data.paragraphStyle }, fonts),
560
+ },
561
+ Adjustments: { Axis: [1, 0, 1], XY: [0, 0] },
562
+ });
563
+ }
564
+ } else {
565
+ for (let i = 0, last = 0; i < text.length; i++) {
566
+ if (text.charCodeAt(i) === 13) { // \r
567
+ paragraphRunLengthArray.push(i - last + 1);
568
+ paragraphRunArray.push({
569
+ ParagraphSheet: {
570
+ DefaultStyleSheet: 0,
571
+ Properties: encodeParagraphStyle({ ...defaultParagraphStyle, ...data.paragraphStyle }, fonts),
572
+ },
573
+ Adjustments: { Axis: [1, 0, 1], XY: [0, 0] },
574
+ });
575
+ last = i + 1;
576
+ }
577
+ }
578
+ }
579
+
580
+ const styleSheetData = encodeStyle({ ...defaultStyle, font: defFont }, fonts);
581
+ const styleRuns = data.styleRuns || [{ length: text.length, style: data.style || {} }];
582
+ const styleRunArray: StyleRun[] = [];
583
+ const styleRunLengthArray: number[] = [];
584
+
585
+ let leftLength = text.length;
586
+
587
+ for (const run of styleRuns) {
588
+ let runLength = Math.min(run.length, leftLength);
589
+ leftLength -= runLength;
590
+
591
+ if (!runLength) continue; // ignore 0 size runs
592
+
593
+ // extend last run if it's only for trailing \r
594
+ if (leftLength === 1 && run === styleRuns[styleRuns.length - 1]) {
595
+ runLength++;
596
+ leftLength--;
597
+ }
598
+
599
+ styleRunLengthArray.push(runLength);
600
+ styleRunArray.push({
601
+ StyleSheet: {
602
+ StyleSheetData: encodeStyle({
603
+ kerning: 0,
604
+ autoKerning: true,
605
+ fillColor: { r: 0, g: 0, b: 0 },
606
+ ...data.style,
607
+ ...run.style,
608
+ }, fonts),
609
+ },
610
+ });
611
+ }
612
+
613
+ // add extra run to the end if existing ones didn't fill it up
614
+ if (leftLength && styleRuns.length) {
615
+ styleRunLengthArray.push(leftLength);
616
+ styleRunArray.push({
617
+ StyleSheet: {
618
+ StyleSheetData: encodeStyle({
619
+ kerning: 0,
620
+ autoKerning: true,
621
+ fillColor: { r: 0, g: 0, b: 0 },
622
+ ...data.style,
623
+ }, fonts),
624
+ },
625
+ });
626
+ }
627
+
628
+ const gridInfo = { ...defaultGridInfo, ...data.gridInfo };
629
+ const WritingDirection = data.orientation === 'vertical' ? 2 : 0;
630
+ const Procession = data.orientation === 'vertical' ? 1 : 0;
631
+ const ShapeType = data.shapeType === 'box' ? 1 : 0;
632
+ const Photoshop: PhotoshopNode = {
633
+ ShapeType,
634
+ };
635
+
636
+ if (ShapeType === 0) {
637
+ Photoshop.PointBase = data.pointBase || [0, 0];
638
+ } else {
639
+ Photoshop.BoxBounds = data.boxBounds || [0, 0, 0, 0];
640
+ }
641
+
642
+ // needed for correct order of properties
643
+ Photoshop.Base = {
644
+ ShapeType,
645
+ TransformPoint0: [1, 0],
646
+ TransformPoint1: [0, 1],
647
+ TransformPoint2: [0, 0],
648
+ };
649
+
650
+ const defaultResources = {
651
+ KinsokuSet: [
652
+ {
653
+ Name: 'PhotoshopKinsokuHard',
654
+ NoStart: '、。,.・:;?!ー―’”)〕]}〉》」』】ヽヾゝゞ々ぁぃぅぇぉっゃゅょゎァィゥェォッャュョヮヵヶ゛゜?!)]},.:;℃℉¢%‰',
655
+ NoEnd: '‘“(〔[{〈《「『【([{¥$£@§〒#',
656
+ Keep: '―‥',
657
+ Hanging: '、。.,',
658
+ },
659
+ {
660
+ Name: 'PhotoshopKinsokuSoft',
661
+ NoStart: '、。,.・:;?!’”)〕]}〉》」』】ヽヾゝゞ々',
662
+ NoEnd: '‘“(〔[{〈《「『【',
663
+ Keep: '―‥',
664
+ Hanging: '、。.,',
665
+ },
666
+ ],
667
+ MojiKumiSet: [
668
+ { InternalName: 'Photoshop6MojiKumiSet1' },
669
+ { InternalName: 'Photoshop6MojiKumiSet2' },
670
+ { InternalName: 'Photoshop6MojiKumiSet3' },
671
+ { InternalName: 'Photoshop6MojiKumiSet4' },
672
+ ],
673
+ TheNormalStyleSheet: 0,
674
+ TheNormalParagraphSheet: 0,
675
+ ParagraphSheetSet: [
676
+ {
677
+ Name: 'Normal RGB',
678
+ DefaultStyleSheet: 0,
679
+ Properties: encodeParagraphStyle({ ...defaultParagraphStyle, ...data.paragraphStyle }, fonts),
680
+ },
681
+ ],
682
+ StyleSheetSet: [
683
+ {
684
+ Name: 'Normal RGB',
685
+ StyleSheetData: styleSheetData,
686
+ },
687
+ ],
688
+ FontSet: fonts.map<FontSet>(f => ({
689
+ Name: f.name,
690
+ Script: f.script || 0,
691
+ FontType: f.type || 0,
692
+ Synthetic: f.synthetic || 0,
693
+ })),
694
+ SuperscriptSize: data.superscriptSize ?? 0.583,
695
+ SuperscriptPosition: data.superscriptPosition ?? 0.333,
696
+ SubscriptSize: data.subscriptSize ?? 0.583,
697
+ SubscriptPosition: data.subscriptPosition ?? 0.333,
698
+ SmallCapSize: data.smallCapSize ?? 0.7,
699
+ };
700
+
701
+ const engineData: EngineData = {
702
+ EngineDict: {
703
+ Editor: { Text: text },
704
+ ParagraphRun: {
705
+ DefaultRunData: {
706
+ ParagraphSheet: { DefaultStyleSheet: 0, Properties: {} },
707
+ Adjustments: { Axis: [1, 0, 1], XY: [0, 0] },
708
+ },
709
+ RunArray: paragraphRunArray,
710
+ RunLengthArray: paragraphRunLengthArray,
711
+ IsJoinable: 1,
712
+ },
713
+ StyleRun: {
714
+ DefaultRunData: { StyleSheet: { StyleSheetData: {} } },
715
+ RunArray: styleRunArray,
716
+ RunLengthArray: styleRunLengthArray,
717
+ IsJoinable: 2,
718
+ },
719
+ GridInfo: {
720
+ GridIsOn: !!gridInfo.isOn,
721
+ ShowGrid: !!gridInfo.show,
722
+ GridSize: gridInfo.size ?? 18,
723
+ GridLeading: gridInfo.leading ?? 22,
724
+ GridColor: { Type: 1, Values: encodeColor(gridInfo.color) },
725
+ GridLeadingFillColor: { Type: 1, Values: encodeColor(gridInfo.color) },
726
+ AlignLineHeightToGridFlags: !!gridInfo.alignLineHeightToGridFlags,
727
+ },
728
+ AntiAlias: antialias.indexOf(data.antiAlias ?? 'sharp'),
729
+ UseFractionalGlyphWidths: data.useFractionalGlyphWidths ?? true,
730
+ Rendered: {
731
+ Version: 1,
732
+ Shapes: {
733
+ WritingDirection,
734
+ Children: [
735
+ {
736
+ ShapeType,
737
+ Procession,
738
+ Lines: { WritingDirection, Children: [] },
739
+ Cookie: { Photoshop },
740
+ },
741
+ ],
742
+ },
743
+ },
744
+ },
745
+ ResourceDict: { ...defaultResources },
746
+ DocumentResources: { ...defaultResources },
747
+ };
748
+
749
+ // console.log('encodeEngineData', require('util').inspect(engineData, false, 99, true));
750
+ return engineData;
751
+ }