Skip to content

Commit 8e1530f

Browse files
quarksbAgamnentzar
andauthored
feat: add base support for path text (#223)
Co-authored-by: Agamnentzar <agamnentzar@gmail.com>
1 parent 96ae807 commit 8e1530f

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

src/engineData2.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/// Engine data 2 experiments
22
// /test/engineData2.json:1109 is character codes
33

4+
import { EngineData } from './text';
5+
46
interface KeysDict {
57
[key: string]: {
68
name?: string;
@@ -127,7 +129,7 @@ const keysRoot: KeysDict = {
127129
},
128130
},
129131
},
130-
}
132+
},
131133
},
132134
},
133135
},
@@ -217,8 +219,64 @@ const keysRoot: KeysDict = {
217219
},
218220
},
219221
'8': {
220-
name: '8',
221-
children: {},
222+
name: 'TextFrameSet',
223+
children: {
224+
'0': {
225+
uproot: true,
226+
children: {
227+
'0': {
228+
name: 'TextPath',
229+
children: {
230+
'0': { name: 'Name' },
231+
'1': {
232+
name: 'BezierCurve',
233+
children: {
234+
'0': { name: 'ControlPoints' },
235+
},
236+
},
237+
'2': {
238+
name: 'Data',
239+
children: {
240+
'0': { name: 'Type' },
241+
'1': { name: 'Orientation' },
242+
'2': { name: 'FrameMatrix' },
243+
'4': { name: '4' },
244+
'6': { name: 'TextRange' },
245+
'7': { name: 'RowGutter' },
246+
'8': { name: 'ColumnGutter' },
247+
'9': { name: '9' },
248+
'10': {
249+
name: 'BaselineAlignment',
250+
children: {
251+
'0': { name: 'Flag' },
252+
'1': { name: 'Min' },
253+
},
254+
},
255+
'11': {
256+
name: 'PathData',
257+
children: {
258+
'1': { name: '1' },
259+
'0': { name: 'Reversed' },
260+
'2': { name: '2' },
261+
'3': { name: '3' },
262+
'4': { name: 'Spacing' },
263+
'5': { name: '5' },
264+
'6': { name: '6' },
265+
'7': { name: '7' },
266+
'18': { name: '18' },
267+
},
268+
},
269+
'12': { name: '12' },
270+
'13': { name: '13' },
271+
},
272+
},
273+
'3': { name: '3' },
274+
'97': { name: 'UUID' },
275+
},
276+
},
277+
},
278+
},
279+
},
222280
},
223281
'9': {
224282
name: 'Predefined',
@@ -343,7 +401,7 @@ const keysRoot: KeysDict = {
343401
},
344402
};
345403

346-
function decodeObj(obj: any, keys: KeysDict): any {
404+
function decodeObj(obj: EngineData, keys: KeysDict): any {
347405
if (obj === null) return obj;
348406
if (Array.isArray(obj)) return obj.map(x => decodeObj(x, keys));
349407
if (typeof obj !== 'object') return obj;

src/psd.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,18 @@ export interface LayerTextData {
427427
boxBounds?: number[];
428428
bounds?: UnitsBounds;
429429
boundingBox?: UnitsBounds;
430+
431+
textPath?: {
432+
BezierCurve?: {
433+
/**the length number should be multiples of 8, which is present a bezier curve */
434+
ControlPoints: number[];
435+
},
436+
Data: {
437+
Type: number;
438+
FrameMatrix: number[];
439+
TextRange: number[];
440+
}
441+
}
430442
}
431443

432444
export interface PatternInfo {

src/psdReader.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { Psd, Layer, ColorMode, SectionDividerType, LayerAdditionalInfo, ReadOpt
33
import { resetImageData, offsetForChannel, decodeBitmap, createImageData, toBlendMode, ChannelID, Compression, LayerMaskFlags, MaskParams, ColorSpace, RAW_IMAGE_DATA, largeAdditionalInfoKeys, imageDataToCanvas } from './helpers';
44
import { infoHandlersMap } from './additionalInfo';
55
import { resourceHandlersMap } from './imageResources';
6+
import { parseEngineData } from './engineData';
7+
import { toByteArray } from 'base64-js';
8+
import { decodeEngineData2 } from './engineData2';
9+
import type { EngineData } from './text';
610

711
interface ChannelInfo {
812
id: ChannelID;
@@ -345,6 +349,14 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
345349
// but add option to preserve file color mode (need to return image data instead of canvas in that case)
346350
// psd.colorMode = ColorMode.RGB; // we convert all color modes to RGB
347351

352+
if(psd.engineData){
353+
const byteArray = toByteArray(psd.engineData);
354+
const engineData = parseEngineData(byteArray);
355+
const parsedEngineData = decodeEngineData2(engineData);
356+
357+
assignGlobalEngineData(psd.children, parsedEngineData);
358+
}
359+
348360
return psd;
349361
}
350362

@@ -705,6 +717,31 @@ export function readAdditionalLayerInfo(reader: PsdReader, target: LayerAddition
705717
}, false, u64);
706718
}
707719

720+
/**
721+
* There is a Global text engine data outside text element.
722+
* So, we need to pick global engine data and set to per text element.
723+
*/
724+
function assignGlobalEngineData(layers: Layer[] | undefined, globalEngineData: EngineData) {
725+
const resources = globalEngineData?.ResourceDict?.TextFrameSet;
726+
727+
if (!resources || Object.keys(resources).length === 0 || !layers?.length) {
728+
return;
729+
}
730+
const resourceLength = Object.keys(resources).length;
731+
let textIndex = 0;
732+
layers.forEach((layer) => {
733+
const isText = !!layer.text;
734+
if (isText) {
735+
if (textIndex < resourceLength) {
736+
const resource = resources[textIndex++];
737+
layer.text!.textPath = resource.TextPath;
738+
} else {
739+
console.warn('Not enough resources for all text layers');
740+
}
741+
}
742+
});
743+
}
744+
708745
export function createImageDataBitDepth(width: number, height: number, bitDepth: number, channels = 4): PixelData {
709746
if (bitDepth === 1 || bitDepth === 8) {
710747
if (channels === 4) {

src/text.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ interface ResourceDict {
9797
SubscriptSize: number;
9898
SubscriptPosition: number;
9999
SmallCapSize: number;
100+
TextFrameSet?: any[];
100101
}
101102

102103
interface ParagraphRun {
@@ -120,7 +121,7 @@ interface PhotoshopNode {
120121
};
121122
}
122123

123-
interface EngineData {
124+
export interface EngineData {
124125
EngineDict: {
125126
Editor: { Text: string; };
126127
ParagraphRun: {

0 commit comments

Comments
 (0)