ag-psd 20.0.0 → 20.1.1
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/CHANGELOG.md +5 -0
- package/README_PSD.md +16 -4
- package/TODO +2 -0
- package/dist/additionalInfo.js +8 -2
- package/dist/additionalInfo.js.map +1 -1
- package/dist/bundle.js +77 -20
- package/dist/engineData2.d.ts +1 -0
- package/dist/engineData2.js +349 -0
- package/dist/engineData2.js.map +1 -0
- package/dist/helpers.js +15 -5
- package/dist/helpers.js.map +1 -1
- package/dist/imageResources.js +5 -1
- package/dist/imageResources.js.map +1 -1
- package/dist/psd.d.ts +1 -1
- package/dist/psdReader.js +39 -8
- package/dist/psdReader.js.map +1 -1
- package/dist/utf8.js +10 -4
- package/dist/utf8.js.map +1 -1
- package/dist-es/additionalInfo.js +8 -2
- package/dist-es/additionalInfo.js.map +1 -1
- package/dist-es/engineData2.d.ts +1 -0
- package/dist-es/engineData2.js +345 -0
- package/dist-es/engineData2.js.map +1 -0
- package/dist-es/helpers.js +17 -7
- package/dist-es/helpers.js.map +1 -1
- package/dist-es/imageResources.js +5 -1
- package/dist-es/imageResources.js.map +1 -1
- package/dist-es/psd.d.ts +1 -1
- package/dist-es/psdReader.js +41 -10
- package/dist-es/psdReader.js.map +1 -1
- package/dist-es/utf8.js +10 -4
- package/dist-es/utf8.js.map +1 -1
- package/package.json +6 -6
- package/src/additionalInfo.ts +14 -2
- package/src/engineData2.ts +367 -0
- package/src/helpers.ts +17 -7
- package/src/imageResources.ts +6 -2
- package/src/psd.ts +1 -1
- package/src/psdReader.ts +47 -9
- package/src/utf8.ts +12 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ag-psd",
|
|
3
|
-
"version": "20.
|
|
3
|
+
"version": "20.1.1",
|
|
4
4
|
"description": "Library for reading and writing PSD files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist-es/index.js",
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
"author": "Agamnentzar",
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@types/mocha": "^
|
|
37
|
+
"@types/mocha": "^10.0.6",
|
|
38
38
|
"@types/node": "^18.11.18",
|
|
39
|
+
"@types/pako": "^2.0.3",
|
|
39
40
|
"browserify": "^17.0.0",
|
|
40
41
|
"canvas": "^2.11.0",
|
|
41
42
|
"chai": "^4.3.7",
|
|
42
|
-
"mocha": "^
|
|
43
|
+
"mocha": "^10.4.0",
|
|
44
|
+
"source-map-support": "^0.5.21",
|
|
43
45
|
"tslint": "^6.1.3",
|
|
44
|
-
"typescript": "^4.9.4"
|
|
45
|
-
"source-map-support": "^0.5.21"
|
|
46
|
+
"typescript": "^4.9.4"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"@types/base64-js": "^1.3.0",
|
|
49
|
-
"@types/pako": "^2.0.0",
|
|
50
50
|
"base64-js": "^1.5.1",
|
|
51
51
|
"pako": "^2.1.0"
|
|
52
52
|
}
|
package/src/additionalInfo.ts
CHANGED
|
@@ -3351,6 +3351,16 @@ addHandler(
|
|
|
3351
3351
|
},
|
|
3352
3352
|
);
|
|
3353
3353
|
|
|
3354
|
+
addHandler(
|
|
3355
|
+
'Lr32',
|
|
3356
|
+
() => false,
|
|
3357
|
+
(reader, _target, _left, psd, options) => {
|
|
3358
|
+
readLayerInfo(reader, psd, options);
|
|
3359
|
+
},
|
|
3360
|
+
(_writer, _target) => {
|
|
3361
|
+
},
|
|
3362
|
+
);
|
|
3363
|
+
|
|
3354
3364
|
addHandler(
|
|
3355
3365
|
'LMsk',
|
|
3356
3366
|
hasKey('userMask'),
|
|
@@ -4634,9 +4644,11 @@ addHandler(
|
|
|
4634
4644
|
const data = readBytes(reader, left());
|
|
4635
4645
|
target.engineData = fromByteArray(data);
|
|
4636
4646
|
// const engineData = parseEngineData(data);
|
|
4647
|
+
// const engineData2 = decodeEngineData2(engineData);
|
|
4637
4648
|
// console.log(require('util').inspect(engineData, false, 99, true));
|
|
4638
|
-
// require('fs').writeFileSync('
|
|
4639
|
-
// require('fs').writeFileSync('test_data.
|
|
4649
|
+
// require('fs').writeFileSync('test_data.bin', data);
|
|
4650
|
+
// require('fs').writeFileSync('test_data.txt', require('util').inspect(engineData, false, 99, false), 'utf8');
|
|
4651
|
+
// require('fs').writeFileSync('test_data.json', JSON.stringify(engineData2, null, 2), 'utf8');
|
|
4640
4652
|
},
|
|
4641
4653
|
(writer, target) => {
|
|
4642
4654
|
const buffer = toByteArray(target.engineData!);
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/// Engine data 2 experiments
|
|
2
|
+
// /test/engineData2.json:1109 is character codes
|
|
3
|
+
|
|
4
|
+
interface KeysDict {
|
|
5
|
+
[key: string]: {
|
|
6
|
+
name?: string;
|
|
7
|
+
uproot?: boolean;
|
|
8
|
+
children?: KeysDict;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const keysColor: KeysDict = {
|
|
13
|
+
'0': {
|
|
14
|
+
uproot: true,
|
|
15
|
+
children: {
|
|
16
|
+
'0': { name: 'Type' },
|
|
17
|
+
'1': { name: 'Values' },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const keysStyleSheet: KeysDict = {
|
|
23
|
+
'0': { name: 'Font' },
|
|
24
|
+
'1': { name: 'FontSize' },
|
|
25
|
+
'2': { name: 'FauxBold' },
|
|
26
|
+
'3': { name: 'FauxItalic' },
|
|
27
|
+
'4': { name: 'AutoLeading' },
|
|
28
|
+
'5': { name: 'Leading' },
|
|
29
|
+
'6': { name: 'HorizontalScale' },
|
|
30
|
+
'7': { name: 'VerticalScale' },
|
|
31
|
+
'8': { name: 'Tracking' },
|
|
32
|
+
'9': { name: 'BaselineShift' },
|
|
33
|
+
// '10': ???
|
|
34
|
+
'11': { name: 'Kerning?' }, // different value than EngineData
|
|
35
|
+
'12': { name: 'FontCaps' },
|
|
36
|
+
'13': { name: 'FontBaseline' },
|
|
37
|
+
|
|
38
|
+
'15': { name: 'Strikethrough?' }, // number instead of bool
|
|
39
|
+
'16': { name: 'Underline?' }, // number instead of bool
|
|
40
|
+
|
|
41
|
+
'18': { name: 'Ligatures' },
|
|
42
|
+
'19': { name: 'DLigatures' },
|
|
43
|
+
// '20': ???
|
|
44
|
+
// '21': ???
|
|
45
|
+
// '22': ???
|
|
46
|
+
'23': { name: 'Fractions' }, // not present in EngineData
|
|
47
|
+
'24': { name: 'Ordinals' }, // not present in EngineData
|
|
48
|
+
// '25': ???
|
|
49
|
+
// '26': ???
|
|
50
|
+
// '27': ???
|
|
51
|
+
'28': { name: 'StylisticAlternates' }, // not present in EngineData
|
|
52
|
+
// '29': ???
|
|
53
|
+
'30': { name: 'OldStyle?' }, // OpenType > OldStyle, number instead of bool, not present in EngineData
|
|
54
|
+
|
|
55
|
+
'35': { name: 'BaselineDirection' },
|
|
56
|
+
|
|
57
|
+
'38': { name: 'Language' },
|
|
58
|
+
|
|
59
|
+
'52': { name: 'NoBreak' },
|
|
60
|
+
'53': { name: 'FillColor', children: keysColor },
|
|
61
|
+
'54': { name: 'StrokeColor?', children: keysColor },
|
|
62
|
+
'55': { children: { '99': { uproot: true } } },
|
|
63
|
+
|
|
64
|
+
// '68': ???
|
|
65
|
+
|
|
66
|
+
// '70': ???
|
|
67
|
+
// '71': ???
|
|
68
|
+
// '72': ???
|
|
69
|
+
// '73': ???
|
|
70
|
+
|
|
71
|
+
'79': { children: keysColor },
|
|
72
|
+
|
|
73
|
+
// '85': ???
|
|
74
|
+
|
|
75
|
+
// '87': ???
|
|
76
|
+
// '88': ???
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const keysParagraph: KeysDict = {
|
|
80
|
+
'0': { name: 'Justification' },
|
|
81
|
+
'1': { name: 'FirstLineIndent' },
|
|
82
|
+
'2': { name: 'StartIndent' },
|
|
83
|
+
'3': { name: 'EndIndent' },
|
|
84
|
+
'4': { name: 'SpaceBefore' },
|
|
85
|
+
'5': { name: 'SpaceAfter' },
|
|
86
|
+
|
|
87
|
+
'7': { name: 'AutoLeading' },
|
|
88
|
+
|
|
89
|
+
'9': { name: 'AutoHyphenate' },
|
|
90
|
+
'10': { name: 'HyphenatedWordSize' },
|
|
91
|
+
'11': { name: 'PreHyphen' },
|
|
92
|
+
'12': { name: 'PostHyphen' },
|
|
93
|
+
'13': { name: 'ConsecutiveHyphens?' }, // different value than EngineData
|
|
94
|
+
'14': { name: 'Zone' },
|
|
95
|
+
'15': { name: 'HypenateCapitalizedWords' }, // not present in EngineData
|
|
96
|
+
|
|
97
|
+
'17': { name: 'WordSpacing' },
|
|
98
|
+
'18': { name: 'LetterSpacing' },
|
|
99
|
+
'19': { name: 'GlyphSpacing' },
|
|
100
|
+
|
|
101
|
+
'32': { name: 'StyleSheet', children: keysStyleSheet },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const keysStyleSheetData: KeysDict[''] = {
|
|
105
|
+
name: 'StyleSheetData',
|
|
106
|
+
children: keysStyleSheet,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const keysRoot: KeysDict = {
|
|
110
|
+
'0': {
|
|
111
|
+
name: 'ResourceDict',
|
|
112
|
+
children: {
|
|
113
|
+
'1': {
|
|
114
|
+
name: 'FontSet',
|
|
115
|
+
children: {
|
|
116
|
+
'0': {
|
|
117
|
+
uproot: true,
|
|
118
|
+
children: {
|
|
119
|
+
'0': {
|
|
120
|
+
uproot: true,
|
|
121
|
+
children: {
|
|
122
|
+
'0': {
|
|
123
|
+
uproot: true,
|
|
124
|
+
children: {
|
|
125
|
+
'0': { name: 'Name' },
|
|
126
|
+
'2': { name: 'FontType' },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
'2': {
|
|
136
|
+
name: '2',
|
|
137
|
+
children: {},
|
|
138
|
+
},
|
|
139
|
+
'3': {
|
|
140
|
+
name: 'MojiKumiSet',
|
|
141
|
+
children: {
|
|
142
|
+
'0': {
|
|
143
|
+
uproot: true,
|
|
144
|
+
children: {
|
|
145
|
+
'0': {
|
|
146
|
+
uproot: true,
|
|
147
|
+
children: {
|
|
148
|
+
'0': { name: 'InternalName' },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
'4': {
|
|
156
|
+
name: 'KinsokuSet',
|
|
157
|
+
children: {
|
|
158
|
+
'0': {
|
|
159
|
+
uproot: true,
|
|
160
|
+
children: {
|
|
161
|
+
'0': {
|
|
162
|
+
uproot: true,
|
|
163
|
+
children: {
|
|
164
|
+
'0': { name: 'Name' },
|
|
165
|
+
'5': {
|
|
166
|
+
uproot: true,
|
|
167
|
+
children: {
|
|
168
|
+
'0': { name: 'NoStart' },
|
|
169
|
+
'1': { name: 'NoEnd' },
|
|
170
|
+
'2': { name: 'Keep' },
|
|
171
|
+
'3': { name: 'Hanging' },
|
|
172
|
+
'4': { name: 'Name' },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
'5': {
|
|
182
|
+
name: 'StyleSheetSet',
|
|
183
|
+
children: {
|
|
184
|
+
'0': {
|
|
185
|
+
uproot: true,
|
|
186
|
+
children: {
|
|
187
|
+
'0': {
|
|
188
|
+
uproot: true,
|
|
189
|
+
children: {
|
|
190
|
+
'0': { name: 'Name' },
|
|
191
|
+
'6': keysStyleSheetData,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
'6': {
|
|
199
|
+
name: 'ParagraphSheetSet',
|
|
200
|
+
children: {
|
|
201
|
+
'0': {
|
|
202
|
+
uproot: true,
|
|
203
|
+
children: {
|
|
204
|
+
'0': {
|
|
205
|
+
uproot: true,
|
|
206
|
+
children: {
|
|
207
|
+
'0': { name: 'Name' },
|
|
208
|
+
'5': {
|
|
209
|
+
name: 'Properties',
|
|
210
|
+
children: keysParagraph,
|
|
211
|
+
},
|
|
212
|
+
'6': { name: 'DefaultStyleSheet' },
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
'8': {
|
|
220
|
+
name: '8',
|
|
221
|
+
children: {},
|
|
222
|
+
},
|
|
223
|
+
'9': {
|
|
224
|
+
name: 'Predefined',
|
|
225
|
+
children: {
|
|
226
|
+
'0': {
|
|
227
|
+
children: { '0': { uproot: true } },
|
|
228
|
+
},
|
|
229
|
+
'1': {
|
|
230
|
+
children: { '0': { uproot: true } },
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
'1': {
|
|
237
|
+
name: 'EngineDict',
|
|
238
|
+
children: {
|
|
239
|
+
'0': {
|
|
240
|
+
name: '0',
|
|
241
|
+
children: {
|
|
242
|
+
// 0: ???
|
|
243
|
+
// 1: ???
|
|
244
|
+
// 2: ???
|
|
245
|
+
'3': { name: 'SuperscriptSize' },
|
|
246
|
+
'4': { name: 'SuperscriptPosition' },
|
|
247
|
+
'5': { name: 'SubscriptSize' },
|
|
248
|
+
'6': { name: 'SubscriptPosition' },
|
|
249
|
+
'7': { name: 'SmallCapSize' },
|
|
250
|
+
'8': { name: 'UseFractionalGlyphWidths' }, // ???
|
|
251
|
+
|
|
252
|
+
'15': { children: { '0': { uproot: true } } },
|
|
253
|
+
// 16: ???
|
|
254
|
+
// 17: ???
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
'1': {
|
|
258
|
+
name: 'Editors?',
|
|
259
|
+
children: {
|
|
260
|
+
'0': {
|
|
261
|
+
name: 'Editor',
|
|
262
|
+
children: {
|
|
263
|
+
'0': { name: 'Text' },
|
|
264
|
+
'5': {
|
|
265
|
+
name: 'ParagraphRun',
|
|
266
|
+
children: {
|
|
267
|
+
'0': {
|
|
268
|
+
name: 'RunArray',
|
|
269
|
+
children: {
|
|
270
|
+
'0': {
|
|
271
|
+
name: 'ParagraphSheet',
|
|
272
|
+
children: {
|
|
273
|
+
'0': {
|
|
274
|
+
uproot: true,
|
|
275
|
+
children: {
|
|
276
|
+
'0': { name: '0' },
|
|
277
|
+
'5': {
|
|
278
|
+
name: '5',
|
|
279
|
+
children: keysParagraph,
|
|
280
|
+
},
|
|
281
|
+
'6': { name: '6' },
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
'1': { name: 'RunLength' },
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
'6': {
|
|
292
|
+
name: 'StyleRun',
|
|
293
|
+
children: {
|
|
294
|
+
'0': {
|
|
295
|
+
name: 'RunArray',
|
|
296
|
+
children: {
|
|
297
|
+
'0': {
|
|
298
|
+
name: 'StyleSheet',
|
|
299
|
+
children: {
|
|
300
|
+
'0': {
|
|
301
|
+
uproot: true,
|
|
302
|
+
children: {
|
|
303
|
+
'6': keysStyleSheetData,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
'1': { name: 'RunLength' },
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
'1': {
|
|
316
|
+
name: 'FontVectorData ???',
|
|
317
|
+
// children: {
|
|
318
|
+
// '0': {},
|
|
319
|
+
// '2': {
|
|
320
|
+
// // '5'
|
|
321
|
+
// // '6'
|
|
322
|
+
// },
|
|
323
|
+
// }
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
'2': {
|
|
328
|
+
name: 'StyleSheet',
|
|
329
|
+
children: keysStyleSheet,
|
|
330
|
+
},
|
|
331
|
+
'3': {
|
|
332
|
+
name: 'ParagraphSheet',
|
|
333
|
+
children: keysParagraph,
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
function decodeObj(obj: any, keys: KeysDict): any {
|
|
340
|
+
if (obj === null) return obj;
|
|
341
|
+
if (Array.isArray(obj)) return obj.map(x => decodeObj(x, keys));
|
|
342
|
+
if (typeof obj !== 'object') return obj;
|
|
343
|
+
|
|
344
|
+
let result: any = {};
|
|
345
|
+
|
|
346
|
+
for (const key of Object.keys(obj)) {
|
|
347
|
+
if (keys[key]) {
|
|
348
|
+
if (keys[key].uproot) {
|
|
349
|
+
if (key !== '99') result = decodeObj(obj[key], keys[key].children ?? {});
|
|
350
|
+
if (obj['99']) result._type = obj['99'];
|
|
351
|
+
break;
|
|
352
|
+
} else {
|
|
353
|
+
result[keys[key].name || key] = decodeObj(obj[key], keys[key].children ?? {});
|
|
354
|
+
}
|
|
355
|
+
} else if (key === '99') {
|
|
356
|
+
result._type = obj[key];
|
|
357
|
+
} else {
|
|
358
|
+
result[key] = decodeObj(obj[key], {});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function decodeEngineData2(data: any) {
|
|
366
|
+
return decodeObj(data, keysRoot);
|
|
367
|
+
}
|
package/src/helpers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fromByteArray } from 'base64-js';
|
|
2
|
-
import { deflate } from 'pako';
|
|
2
|
+
import { deflate as deflateSync } from 'pako';
|
|
3
3
|
import { Layer, BlendMode, LayerColor, PixelData, PixelArray } from './psd';
|
|
4
4
|
|
|
5
5
|
export const MOCK_HANDLERS = false;
|
|
@@ -166,7 +166,7 @@ export function hasAlpha(data: PixelData) {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
export function resetImageData({ data }: PixelData) {
|
|
169
|
-
const alpha = (data instanceof
|
|
169
|
+
const alpha = (data instanceof Float32Array) ? 1.0 : ((data instanceof Uint16Array) ? 0xffff : 0xff);
|
|
170
170
|
|
|
171
171
|
for (let p = 0, size = data.length | 0; p < size; p = (p + 4) | 0) {
|
|
172
172
|
data[p + 0] = 0;
|
|
@@ -186,10 +186,20 @@ export function imageDataToCanvas(pixelData: PixelData) {
|
|
|
186
186
|
imageData = createImageData(pixelData.width, pixelData.height);
|
|
187
187
|
const src = pixelData.data;
|
|
188
188
|
const dst = imageData.data;
|
|
189
|
-
const shift = (src instanceof Uint32Array) ? 24 : ((src instanceof Uint16Array) ? 8 : 0);
|
|
190
189
|
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
if (src instanceof Float32Array) {
|
|
191
|
+
for (let i = 0, size = src.length; i < size; i += 4) {
|
|
192
|
+
dst[i + 0] = Math.round(Math.pow(src[i + 0], 1.0 / 2.2) * 255);
|
|
193
|
+
dst[i + 1] = Math.round(Math.pow(src[i + 1], 1.0 / 2.2) * 255);
|
|
194
|
+
dst[i + 2] = Math.round(Math.pow(src[i + 2], 1.0 / 2.2) * 255);
|
|
195
|
+
dst[i + 3] = Math.round(src[i + 3] * 255);
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
const shift = (src instanceof Uint16Array) ? 8 : 0;
|
|
199
|
+
|
|
200
|
+
for (let i = 0, size = src.length; i < size; i++) {
|
|
201
|
+
dst[i] = src[i] >>> shift;
|
|
202
|
+
}
|
|
193
203
|
}
|
|
194
204
|
}
|
|
195
205
|
|
|
@@ -198,7 +208,7 @@ export function imageDataToCanvas(pixelData: PixelData) {
|
|
|
198
208
|
}
|
|
199
209
|
|
|
200
210
|
export function decodeBitmap(input: PixelArray, output: PixelArray, width: number, height: number) {
|
|
201
|
-
if (input instanceof
|
|
211
|
+
if (!(input instanceof Uint8Array || input instanceof Uint8ClampedArray)) throw new Error('Invalid bit depth');
|
|
202
212
|
|
|
203
213
|
for (let y = 0, p = 0, o = 0; y < height; y++) {
|
|
204
214
|
for (let x = 0; x < width;) {
|
|
@@ -339,7 +349,7 @@ export function writeDataZipWithoutPrediction({ data, width, height }: PixelData
|
|
|
339
349
|
channel[i] = data[o];
|
|
340
350
|
}
|
|
341
351
|
|
|
342
|
-
const buffer =
|
|
352
|
+
const buffer = deflateSync(channel);
|
|
343
353
|
buffers.push(buffer);
|
|
344
354
|
totalLength += buffer.byteLength;
|
|
345
355
|
}
|
package/src/imageResources.ts
CHANGED
|
@@ -98,8 +98,12 @@ addHandler(
|
|
|
98
98
|
addHandler(
|
|
99
99
|
1060,
|
|
100
100
|
target => target.xmpMetadata !== undefined,
|
|
101
|
-
(reader, target, left) =>
|
|
102
|
-
|
|
101
|
+
(reader, target, left) => {
|
|
102
|
+
target.xmpMetadata = readUtf8String(reader, left());
|
|
103
|
+
},
|
|
104
|
+
(writer, target) => {
|
|
105
|
+
writeUtf8String(writer, target.xmpMetadata!);
|
|
106
|
+
},
|
|
103
107
|
);
|
|
104
108
|
|
|
105
109
|
const Inte = createEnum<RenderingIntent>('Inte', 'perceptual', {
|
package/src/psd.ts
CHANGED
|
@@ -222,7 +222,7 @@ export interface LayerEffectsInfo {
|
|
|
222
222
|
patternOverlay?: LayerEffectPatternOverlay; // not supported yet because of `Patt` section not implemented
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
export type PixelArray = Uint8ClampedArray | Uint8Array | Uint16Array |
|
|
225
|
+
export type PixelArray = Uint8ClampedArray | Uint8Array | Uint16Array | Float32Array;
|
|
226
226
|
|
|
227
227
|
export interface PixelData {
|
|
228
228
|
data: PixelArray; // type depends on document bit depth
|
package/src/psdReader.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inflate } from 'pako';
|
|
1
|
+
import { inflate as inflateSync } from 'pako';
|
|
2
2
|
import { Psd, Layer, ColorMode, SectionDividerType, LayerAdditionalInfo, ReadOptions, LayerMaskData, Color, PatternInfo, GlobalLayerMaskInfo, RGB, PixelData, PixelArray } from './psd';
|
|
3
3
|
import { resetImageData, offsetForChannel, decodeBitmap, createImageData, toBlendMode, ChannelID, Compression, LayerMaskFlags, MaskParams, ColorSpace, RAW_IMAGE_DATA, largeAdditionalInfoKeys, imageDataToCanvas } from './helpers';
|
|
4
4
|
import { infoHandlersMap } from './additionalInfo';
|
|
@@ -230,7 +230,16 @@ export function readPsd(reader: PsdReader, readOptions: ReadOptions = {}) {
|
|
|
230
230
|
|
|
231
231
|
// color mode data
|
|
232
232
|
readSection(reader, 1, left => {
|
|
233
|
-
if (
|
|
233
|
+
if (!left()) return;
|
|
234
|
+
|
|
235
|
+
// const numbers: number[] = [];
|
|
236
|
+
// console.log('color mode', left());
|
|
237
|
+
// while (left()) {
|
|
238
|
+
// numbers.push(readUint32(reader));
|
|
239
|
+
// }
|
|
240
|
+
// console.log('color mode', numbers);
|
|
241
|
+
|
|
242
|
+
// if (options.throwForMissingFeatures) throw new Error('Color mode data not supported');
|
|
234
243
|
skipBytes(reader, left());
|
|
235
244
|
});
|
|
236
245
|
|
|
@@ -661,7 +670,7 @@ function createImageDataBitDepth(width: number, height: number, bitDepth: number
|
|
|
661
670
|
} else if (bitDepth === 16) {
|
|
662
671
|
return { width, height, data: new Uint16Array(width * height * 4) };
|
|
663
672
|
} else if (bitDepth === 32) {
|
|
664
|
-
return { width, height, data: new
|
|
673
|
+
return { width, height, data: new Float32Array(width * height * 4) };
|
|
665
674
|
} else {
|
|
666
675
|
throw new Error(`Invalid bitDepth (${bitDepth})`);
|
|
667
676
|
}
|
|
@@ -682,13 +691,15 @@ function readImageData(reader: PsdReader, psd: Psd, options: ReadOptionsExt) {
|
|
|
682
691
|
|
|
683
692
|
switch (psd.colorMode) {
|
|
684
693
|
case ColorMode.Bitmap: {
|
|
694
|
+
if (bitsPerChannel !== 1) throw new Error('Invalid bitsPerChannel for bitmap color mode');
|
|
695
|
+
|
|
685
696
|
let bytes: Uint8Array;
|
|
686
697
|
|
|
687
698
|
if (compression === Compression.RawData) {
|
|
688
699
|
bytes = readBytes(reader, Math.ceil(psd.width / 8) * psd.height);
|
|
689
700
|
} else if (compression === Compression.RleCompressed) {
|
|
690
701
|
bytes = new Uint8Array(psd.width * psd.height);
|
|
691
|
-
readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height,
|
|
702
|
+
readDataRLE(reader, { data: bytes, width: psd.width, height: psd.height }, psd.width, psd.height, 8, 1, [0], options.large);
|
|
692
703
|
} else {
|
|
693
704
|
throw new Error(`Bitmap compression not supported: ${compression}`);
|
|
694
705
|
}
|
|
@@ -828,11 +839,11 @@ function bytesToArray(bytes: Uint8Array, bitDepth: number) {
|
|
|
828
839
|
}
|
|
829
840
|
} else if (bitDepth === 32) {
|
|
830
841
|
if (bytes.byteOffset % 4) {
|
|
831
|
-
const result = new
|
|
842
|
+
const result = new Float32Array(bytes.byteLength / 4);
|
|
832
843
|
new Uint8Array(result.buffer, result.byteOffset, result.byteLength).set(bytes);
|
|
833
844
|
return result;
|
|
834
845
|
} else {
|
|
835
|
-
return new
|
|
846
|
+
return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
|
|
836
847
|
}
|
|
837
848
|
} else {
|
|
838
849
|
throw new Error(`Invalid bitDepth (${bitDepth})`)
|
|
@@ -850,6 +861,20 @@ function copyChannelToPixelData(pixelData: PixelData, channel: PixelArray, offse
|
|
|
850
861
|
|
|
851
862
|
function readDataRaw(reader: PsdReader, pixelData: PixelData | undefined, width: number, height: number, bitDepth: number, step: number, offset: number) {
|
|
852
863
|
const buffer = readBytes(reader, width * height * Math.floor(bitDepth / 8));
|
|
864
|
+
|
|
865
|
+
if (bitDepth == 32) {
|
|
866
|
+
for (let i = 0; i < buffer.byteLength; i += 4) {
|
|
867
|
+
const a = buffer[i + 0];
|
|
868
|
+
const b = buffer[i + 1];
|
|
869
|
+
const c = buffer[i + 2];
|
|
870
|
+
const d = buffer[i + 3];
|
|
871
|
+
buffer[i + 0] = d;
|
|
872
|
+
buffer[i + 1] = c;
|
|
873
|
+
buffer[i + 2] = b;
|
|
874
|
+
buffer[i + 3] = a;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
853
878
|
const array = bytesToArray(buffer, bitDepth);
|
|
854
879
|
|
|
855
880
|
if (pixelData && offset < step) {
|
|
@@ -869,7 +894,7 @@ function decodePredicted(data: Uint8Array | Uint16Array, width: number, height:
|
|
|
869
894
|
|
|
870
895
|
export function readDataZip(reader: PsdReader, length: number, pixelData: PixelData | undefined, width: number, height: number, bitDepth: number, step: number, offset: number, prediction: boolean) {
|
|
871
896
|
const compressed = readBytes(reader, length);
|
|
872
|
-
const decompressed =
|
|
897
|
+
const decompressed = inflateSync(compressed);
|
|
873
898
|
|
|
874
899
|
if (pixelData && offset < step) {
|
|
875
900
|
const array = bytesToArray(decompressed, bitDepth);
|
|
@@ -881,8 +906,21 @@ export function readDataZip(reader: PsdReader, length: number, pixelData: PixelD
|
|
|
881
906
|
if (prediction) decodePredicted(array as Uint16Array, width, height, 0x10000);
|
|
882
907
|
copyChannelToPixelData(pixelData, array, offset, step);
|
|
883
908
|
} else if (bitDepth === 32) {
|
|
884
|
-
if (prediction) decodePredicted(decompressed, width, height, 0x100);
|
|
885
|
-
|
|
909
|
+
if (prediction) decodePredicted(decompressed, width * 4, height, 0x100);
|
|
910
|
+
|
|
911
|
+
let di = offset;
|
|
912
|
+
const dst = new Uint32Array(pixelData.data.buffer, pixelData.data.byteOffset, pixelData.data.length);
|
|
913
|
+
|
|
914
|
+
for (let y = 0; y < height; y++) {
|
|
915
|
+
let a = width * 4 * y;
|
|
916
|
+
|
|
917
|
+
for (let x = 0; x < width; x++, a++, di += step) {
|
|
918
|
+
const b = a + width;
|
|
919
|
+
const c = b + width;
|
|
920
|
+
const d = c + width;
|
|
921
|
+
dst[di] = ((decompressed[a] << 24) | (decompressed[b] << 16) | (decompressed[c] << 8) | decompressed[d]) >>> 0;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
886
924
|
} else {
|
|
887
925
|
throw new Error('Invalid bitDepth');
|
|
888
926
|
}
|
package/src/utf8.ts
CHANGED
|
@@ -87,6 +87,10 @@ export function encodeStringTo(buffer: Uint8Array | Buffer, offset: number, valu
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export function encodeString(value: string): Uint8Array {
|
|
90
|
+
if (value.length > 1000 && typeof TextEncoder !== 'undefined') {
|
|
91
|
+
return (new TextEncoder()).encode(value);
|
|
92
|
+
}
|
|
93
|
+
|
|
90
94
|
const buffer = new Uint8Array(stringLengthInBytes(value));
|
|
91
95
|
encodeStringTo(buffer, 0, value);
|
|
92
96
|
return buffer;
|
|
@@ -107,7 +111,11 @@ function continuationByte(buffer: Uint8Array, index: number): number {
|
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
export function decodeString(value: Uint8Array): string {
|
|
110
|
-
|
|
114
|
+
if (value.byteLength > 1000 && typeof TextDecoder !== 'undefined') {
|
|
115
|
+
return (new TextDecoder()).decode(value);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let result: string[] = [];
|
|
111
119
|
|
|
112
120
|
for (let i = 0; i < value.length;) {
|
|
113
121
|
const byte1 = value[i++];
|
|
@@ -149,12 +157,12 @@ export function decodeString(value: Uint8Array): string {
|
|
|
149
157
|
|
|
150
158
|
if (code > 0xffff) {
|
|
151
159
|
code -= 0x10000;
|
|
152
|
-
result
|
|
160
|
+
result.push(String.fromCharCode(code >>> 10 & 0x3ff | 0xd800));
|
|
153
161
|
code = 0xdc00 | code & 0x3ff;
|
|
154
162
|
}
|
|
155
163
|
|
|
156
|
-
result
|
|
164
|
+
result.push(String.fromCharCode(code));
|
|
157
165
|
}
|
|
158
166
|
|
|
159
|
-
return result;
|
|
167
|
+
return result.join('');
|
|
160
168
|
}
|