@pixerate/editor 0.113.0 → 0.114.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/THIRD_PARTY_NOTICES.md +5 -0
- package/dist/animation-editor/index.cjs +60 -54
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +3 -3
- package/dist/animation-editor/index.d.ts +3 -3
- package/dist/animation-editor/index.js +14 -8
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/builtin-CY97ppKM.d.cts +354 -0
- package/dist/builtin-CY97ppKM.d.ts +354 -0
- package/dist/canvas/index.cjs +3 -3
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.js +9 -9
- package/dist/chunk-26PGXHY7.cjs +753 -0
- package/dist/chunk-26PGXHY7.cjs.map +1 -0
- package/dist/chunk-2OJACTPR.cjs +929 -0
- package/dist/chunk-2OJACTPR.cjs.map +1 -0
- package/dist/chunk-3UFGNHSP.js +929 -0
- package/dist/chunk-3UFGNHSP.js.map +1 -0
- package/dist/{chunk-YGIMK4NX.cjs → chunk-5OVJHMZQ.cjs} +757 -825
- package/dist/chunk-5OVJHMZQ.cjs.map +1 -0
- package/dist/chunk-643B2HKC.cjs +534 -0
- package/dist/chunk-643B2HKC.cjs.map +1 -0
- package/dist/chunk-6FCKOS2B.js +534 -0
- package/dist/chunk-6FCKOS2B.js.map +1 -0
- package/dist/chunk-BRLYOPLT.js +2574 -0
- package/dist/chunk-BRLYOPLT.js.map +1 -0
- package/dist/{chunk-LQEEDHOP.js → chunk-C6C5PDKU.js} +759 -761
- package/dist/chunk-C6C5PDKU.js.map +1 -0
- package/dist/{chunk-4KLT7ZYS.cjs → chunk-DFQEX3AM.cjs} +29 -29
- package/dist/{chunk-4KLT7ZYS.cjs.map → chunk-DFQEX3AM.cjs.map} +1 -1
- package/dist/{chunk-CZOXTEMN.js → chunk-EUVSQ25B.js} +336 -404
- package/dist/chunk-EUVSQ25B.js.map +1 -0
- package/dist/chunk-G5NMLUVF.cjs +2574 -0
- package/dist/chunk-G5NMLUVF.cjs.map +1 -0
- package/dist/{chunk-LPYOIVLA.js → chunk-LKCYANMW.js} +3 -3
- package/dist/{chunk-W3GXSUSQ.cjs → chunk-LPLCWZTM.cjs} +5087 -1283
- package/dist/chunk-LPLCWZTM.cjs.map +1 -0
- package/dist/chunk-MMVHBKMM.js +753 -0
- package/dist/chunk-MMVHBKMM.js.map +1 -0
- package/dist/{chunk-POGBUYWE.cjs → chunk-ST7E3NEE.cjs} +857 -859
- package/dist/chunk-ST7E3NEE.cjs.map +1 -0
- package/dist/{chunk-7VOHOPLW.cjs → chunk-TCKIXI46.cjs} +59 -59
- package/dist/{chunk-7VOHOPLW.cjs.map → chunk-TCKIXI46.cjs.map} +1 -1
- package/dist/{chunk-XIOMMGPD.cjs → chunk-TFOPHZ3U.cjs} +1 -1
- package/dist/chunk-TFOPHZ3U.cjs.map +1 -0
- package/dist/{chunk-Z4BC6M74.js → chunk-UBIXVXPR.js} +2 -2
- package/dist/{chunk-BLWCAQCW.js → chunk-VXR7XWMF.js} +4574 -770
- package/dist/chunk-VXR7XWMF.js.map +1 -0
- package/dist/{chunk-HNS7UHCM.js → chunk-XK5LZKBD.js} +1 -1
- package/dist/chunk-XK5LZKBD.js.map +1 -0
- package/dist/cms/index.cjs +146 -0
- package/dist/cms/index.cjs.map +1 -0
- package/dist/cms/index.d.cts +51 -0
- package/dist/cms/index.d.ts +51 -0
- package/dist/cms/index.js +146 -0
- package/dist/cms/index.js.map +1 -0
- package/dist/{export-DIkoK8-r.d.ts → export-_1dUKwpF.d.ts} +217 -191
- package/dist/{export-CEXEzqBf.d.cts → export-b6NjCZ5-.d.cts} +217 -191
- package/dist/image-editor/index.cjs +1779 -1280
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +77 -93
- package/dist/image-editor/index.d.ts +77 -93
- package/dist/image-editor/index.js +740 -241
- package/dist/image-editor/index.js.map +1 -1
- package/dist/opentype-BZEOSOX3.d.ts +188 -0
- package/dist/opentype-Dpe75vL5.d.cts +188 -0
- package/dist/paint/index.cjs +4 -4
- package/dist/paint/index.d.cts +2 -2
- package/dist/paint/index.d.ts +2 -2
- package/dist/paint/index.js +3 -3
- package/dist/paint-editor/index.cjs +146 -145
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +9 -8
- package/dist/paint-editor/index.d.ts +9 -8
- package/dist/paint-editor/index.js +6 -5
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +53 -3
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.d.cts +62 -91
- package/dist/raster/index.d.ts +62 -91
- package/dist/raster/index.js +59 -9
- package/dist/{render-BEriFuqK.d.cts → render-B1K_OoLy.d.cts} +87 -2
- package/dist/{render-tjzKaik-.d.ts → render-CrmHOgpo.d.ts} +87 -2
- package/dist/{retouch-CEIKR22W.d.cts → retouch-Bxkuc0KH.d.cts} +1 -1
- package/dist/{retouch-BXmeSCaB.d.ts → retouch-Do6tBs2H.d.ts} +1 -1
- package/dist/{surface-C8RRg_Bh.d.cts → surface-Cn30xIV6.d.cts} +6 -1
- package/dist/{surface-C8RRg_Bh.d.ts → surface-Cn30xIV6.d.ts} +6 -1
- package/dist/{svg-D_cfkhlB.d.cts → svg-BnRj0q8i.d.cts} +16 -4
- package/dist/{svg-wIaKLrU0.d.ts → svg-CmmBFfGT.d.ts} +16 -4
- package/dist/{types-DtL_qLFz.d.ts → types-1SUQKDAw.d.ts} +273 -4
- package/dist/{types-DyQq-WPY.d.cts → types-yINF17Ta.d.cts} +273 -4
- package/dist/vector/index.cjs +12170 -7343
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +1579 -16
- package/dist/vector/index.d.ts +1579 -16
- package/dist/vector/index.js +6303 -1476
- package/dist/vector/index.js.map +1 -1
- package/dist/warp-B39VsOtd.d.cts +348 -0
- package/dist/warp-DMN30aY6.d.ts +348 -0
- package/dist/zlib-dxQdgHyN.d.cts +95 -0
- package/dist/zlib-dxQdgHyN.d.ts +95 -0
- package/package.json +6 -1
- package/skills/pixerate-image-editor/SKILL.md +12 -36
- package/skills/pixerate-image-editor/references/color-management.md +37 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +39 -0
- package/skills/pixerate-vector/SKILL.md +54 -2
- package/dist/chunk-BLWCAQCW.js.map +0 -1
- package/dist/chunk-CZOXTEMN.js.map +0 -1
- package/dist/chunk-HNS7UHCM.js.map +0 -1
- package/dist/chunk-JLYX4V57.cjs +0 -2001
- package/dist/chunk-JLYX4V57.cjs.map +0 -1
- package/dist/chunk-KB2YBCVS.js +0 -2001
- package/dist/chunk-KB2YBCVS.js.map +0 -1
- package/dist/chunk-LQEEDHOP.js.map +0 -1
- package/dist/chunk-POGBUYWE.cjs.map +0 -1
- package/dist/chunk-W3GXSUSQ.cjs.map +0 -1
- package/dist/chunk-XIOMMGPD.cjs.map +0 -1
- package/dist/chunk-YGIMK4NX.cjs.map +0 -1
- package/dist/homography-CZ-tFjay.d.cts +0 -50
- package/dist/homography-Ctfjoc1b.d.ts +0 -50
- package/dist/warp-CWHZzE3x.d.ts +0 -118
- package/dist/warp-D5jz_tN7.d.cts +0 -118
- /package/dist/{chunk-LPYOIVLA.js.map → chunk-LKCYANMW.js.map} +0 -0
- /package/dist/{chunk-Z4BC6M74.js.map → chunk-UBIXVXPR.js.map} +0 -0
|
@@ -1,40 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
createCaptureTool
|
|
6
|
-
} from "../chunk-REOJJIY3.js";
|
|
7
|
-
import {
|
|
8
|
-
DEFAULT_RETOUCH,
|
|
9
|
-
RETOUCH_SAMPLES,
|
|
10
|
-
RegionPixelSource,
|
|
11
|
-
RetouchDabStroke,
|
|
12
|
-
SPOT_HEAL_TYPES,
|
|
13
|
-
TONE_RANGES,
|
|
14
|
-
TilePixelSource,
|
|
15
|
-
applyRetouchToTile,
|
|
16
|
-
bestOffset,
|
|
17
|
-
dilateMask,
|
|
18
|
-
dodgeBurn,
|
|
19
|
-
dodgeBurnCurve,
|
|
20
|
-
healPixels,
|
|
21
|
-
luma,
|
|
22
|
-
maskBounds,
|
|
23
|
-
membraneFill,
|
|
24
|
-
normalizeRetouch,
|
|
25
|
-
perDabStrength,
|
|
26
|
-
readSourceRegion,
|
|
27
|
-
rgbaViewOfGrey,
|
|
28
|
-
saturationOf,
|
|
29
|
-
seamlessClone,
|
|
30
|
-
smudgeEffect,
|
|
31
|
-
solveMembrane,
|
|
32
|
-
sponge,
|
|
33
|
-
spongeEffect,
|
|
34
|
-
spotHealPixels,
|
|
35
|
-
spotHealWindow,
|
|
36
|
-
toneOf
|
|
37
|
-
} from "../chunk-LPYOIVLA.js";
|
|
2
|
+
loadOpenTypeFont,
|
|
3
|
+
parseOpenTypeFont
|
|
4
|
+
} from "../chunk-3UFGNHSP.js";
|
|
38
5
|
import {
|
|
39
6
|
ADJUSTMENT_KEYS,
|
|
40
7
|
ADJUSTMENT_KINDS,
|
|
@@ -47,10 +14,8 @@ import {
|
|
|
47
14
|
D50,
|
|
48
15
|
D65,
|
|
49
16
|
DEFAULT_ADJUSTMENTS_VALUES,
|
|
50
|
-
DEFAULT_AUTO_LEADING,
|
|
51
17
|
DEFAULT_DEPTH_MASK_VALUES,
|
|
52
18
|
DEFAULT_MITER_LIMIT,
|
|
53
|
-
DEFAULT_TEXT_STYLE,
|
|
54
19
|
DEFAULT_TRANSFORM_VALUES,
|
|
55
20
|
DEVELOP_FILTER_ID,
|
|
56
21
|
EMPTY_DISTANCE,
|
|
@@ -102,6 +67,7 @@ import {
|
|
|
102
67
|
annotationOfShape,
|
|
103
68
|
annotationOfType,
|
|
104
69
|
applyAdjustmentLayers,
|
|
70
|
+
applyAdjustmentLayersFloat,
|
|
105
71
|
applyAdjustments,
|
|
106
72
|
applyBoxBlur,
|
|
107
73
|
applyDepthMask,
|
|
@@ -121,12 +87,12 @@ import {
|
|
|
121
87
|
buildToneLut,
|
|
122
88
|
calculateCropDrag,
|
|
123
89
|
canvasToImagePoint,
|
|
124
|
-
caretAt,
|
|
125
90
|
clampCropToImage,
|
|
126
91
|
colorBalanceChannel,
|
|
127
92
|
combineSelections,
|
|
128
93
|
compileAdjustmentLayer,
|
|
129
94
|
componentPath,
|
|
95
|
+
compositeDeep,
|
|
130
96
|
computeSelectionBounds,
|
|
131
97
|
contentsBox,
|
|
132
98
|
contentsSurface,
|
|
@@ -140,6 +106,7 @@ import {
|
|
|
140
106
|
createShapeLayer,
|
|
141
107
|
createTypeLayer,
|
|
142
108
|
curveLutFromLevels,
|
|
109
|
+
decodeDeepSurface,
|
|
143
110
|
decodeLayerChannel,
|
|
144
111
|
decodeLayerMask,
|
|
145
112
|
decodeMergedImage,
|
|
@@ -162,6 +129,7 @@ import {
|
|
|
162
129
|
distanceTransform,
|
|
163
130
|
documentContents,
|
|
164
131
|
duplicateLayer,
|
|
132
|
+
encodeDeepSurface,
|
|
165
133
|
encodeRle,
|
|
166
134
|
encodeSelectionRle,
|
|
167
135
|
encodeSurface,
|
|
@@ -170,11 +138,8 @@ import {
|
|
|
170
138
|
exportPsd,
|
|
171
139
|
featherCoverage,
|
|
172
140
|
filterMaskCoverage,
|
|
173
|
-
fitParagraphRuns,
|
|
174
|
-
fitRuns,
|
|
175
141
|
flattenPath,
|
|
176
142
|
flipCorners,
|
|
177
|
-
fontOf,
|
|
178
143
|
fullSelection,
|
|
179
144
|
geometryHomography,
|
|
180
145
|
getAnnotationBounds,
|
|
@@ -225,7 +190,6 @@ import {
|
|
|
225
190
|
layerTree,
|
|
226
191
|
layerTypeLabel,
|
|
227
192
|
layersFromLegacy,
|
|
228
|
-
layoutText,
|
|
229
193
|
legacyAdjustmentLayer,
|
|
230
194
|
legacyMaskOf,
|
|
231
195
|
legacyView,
|
|
@@ -262,7 +226,6 @@ import {
|
|
|
262
226
|
offsetLayer,
|
|
263
227
|
offsetShape,
|
|
264
228
|
offsetSmartObject,
|
|
265
|
-
paragraphRanges,
|
|
266
229
|
parseAdjustmentBlock,
|
|
267
230
|
parseBlend,
|
|
268
231
|
parseCssColor,
|
|
@@ -317,7 +280,6 @@ import {
|
|
|
317
280
|
rerenderText,
|
|
318
281
|
resizeSelection,
|
|
319
282
|
resolveExternalAssets,
|
|
320
|
-
restyleRange,
|
|
321
283
|
rgbToGray,
|
|
322
284
|
rgbToHsl,
|
|
323
285
|
runLayerFilters,
|
|
@@ -353,12 +315,9 @@ import {
|
|
|
353
315
|
smartContentsFile,
|
|
354
316
|
smartObjectLayers,
|
|
355
317
|
smoothCoverage,
|
|
356
|
-
spliceRuns,
|
|
357
318
|
srgbToLinear,
|
|
358
|
-
styleAt,
|
|
359
319
|
tempTintToXy,
|
|
360
320
|
temperatureToKelvin,
|
|
361
|
-
textIndexAt,
|
|
362
321
|
textMatrix,
|
|
363
322
|
textOutlines,
|
|
364
323
|
textRange,
|
|
@@ -399,8 +358,15 @@ import {
|
|
|
399
358
|
writePsd,
|
|
400
359
|
xyToTempTint,
|
|
401
360
|
xyToUv
|
|
402
|
-
} from "../chunk-
|
|
361
|
+
} from "../chunk-EUVSQ25B.js";
|
|
403
362
|
import {
|
|
363
|
+
loadDocument
|
|
364
|
+
} from "../chunk-U5HZSFCS.js";
|
|
365
|
+
import {
|
|
366
|
+
createCaptureTool
|
|
367
|
+
} from "../chunk-REOJJIY3.js";
|
|
368
|
+
import {
|
|
369
|
+
BIT_DEPTHS,
|
|
404
370
|
DEFAULT_GLOBAL_LIGHT,
|
|
405
371
|
DIRECT_GAUSSIAN_MAX_SIGMA,
|
|
406
372
|
INTERPOLATIONS,
|
|
@@ -411,8 +377,6 @@ import {
|
|
|
411
377
|
PatternPlacement,
|
|
412
378
|
PatternTile,
|
|
413
379
|
TransformTooLargeError,
|
|
414
|
-
ZlibError,
|
|
415
|
-
adler32,
|
|
416
380
|
base64ToBytes,
|
|
417
381
|
blendTile,
|
|
418
382
|
builtinPattern,
|
|
@@ -420,12 +384,14 @@ import {
|
|
|
420
384
|
bytesToBase64,
|
|
421
385
|
changedTiles,
|
|
422
386
|
compositeSurfaceOver,
|
|
387
|
+
convertSurfaceDepth,
|
|
423
388
|
curveLut,
|
|
424
389
|
decodePng,
|
|
390
|
+
deepBytes,
|
|
391
|
+
deepTile,
|
|
425
392
|
defaultEffectGradient,
|
|
426
393
|
defaultLayerEffect,
|
|
427
|
-
|
|
428
|
-
deflateRaw,
|
|
394
|
+
depthOf,
|
|
429
395
|
effectColorHex,
|
|
430
396
|
effectReach,
|
|
431
397
|
effectsFingerprint,
|
|
@@ -437,9 +403,8 @@ import {
|
|
|
437
403
|
gaussianBlur,
|
|
438
404
|
hasActiveEffects,
|
|
439
405
|
hashNoise,
|
|
440
|
-
inflate,
|
|
441
|
-
inflateRaw,
|
|
442
406
|
insertLayer,
|
|
407
|
+
isBitDepth,
|
|
443
408
|
isInterpolation,
|
|
444
409
|
isLayerEffectKind,
|
|
445
410
|
isLayerLocked,
|
|
@@ -454,16 +419,33 @@ import {
|
|
|
454
419
|
parseDataUrl,
|
|
455
420
|
parseEffectColor,
|
|
456
421
|
pngDataUrl,
|
|
422
|
+
proxyOf,
|
|
423
|
+
readDeepRegion,
|
|
457
424
|
reduceSurface,
|
|
458
425
|
renderLayerEffects,
|
|
459
426
|
scaleLayerEffect,
|
|
427
|
+
srgbDecode,
|
|
428
|
+
srgbEncode,
|
|
429
|
+
surfaceDepth,
|
|
430
|
+
surfaceFromDeepPixels,
|
|
431
|
+
tileSamples,
|
|
432
|
+
tileSamples16,
|
|
433
|
+
tileSamples32,
|
|
434
|
+
to16From32,
|
|
435
|
+
to16From8,
|
|
436
|
+
to32From16,
|
|
437
|
+
to32From8,
|
|
438
|
+
to8From16,
|
|
439
|
+
to8From32,
|
|
460
440
|
transformSurface,
|
|
461
441
|
transformedBounds,
|
|
462
442
|
validateEffectGradient,
|
|
463
443
|
validateLayerEffect,
|
|
464
444
|
validateLayerEffects,
|
|
465
|
-
warpSurface
|
|
466
|
-
|
|
445
|
+
warpSurface,
|
|
446
|
+
workingToSamples,
|
|
447
|
+
writeDeepRegion
|
|
448
|
+
} from "../chunk-C6C5PDKU.js";
|
|
467
449
|
import {
|
|
468
450
|
applyHomography,
|
|
469
451
|
boxQuad,
|
|
@@ -473,6 +455,37 @@ import {
|
|
|
473
455
|
multiplyHomographies,
|
|
474
456
|
rectToQuad
|
|
475
457
|
} from "../chunk-GX332W2C.js";
|
|
458
|
+
import {
|
|
459
|
+
DEFAULT_RETOUCH,
|
|
460
|
+
RETOUCH_SAMPLES,
|
|
461
|
+
RegionPixelSource,
|
|
462
|
+
RetouchDabStroke,
|
|
463
|
+
SPOT_HEAL_TYPES,
|
|
464
|
+
TONE_RANGES,
|
|
465
|
+
TilePixelSource,
|
|
466
|
+
applyRetouchToTile,
|
|
467
|
+
bestOffset,
|
|
468
|
+
dilateMask,
|
|
469
|
+
dodgeBurn,
|
|
470
|
+
dodgeBurnCurve,
|
|
471
|
+
healPixels,
|
|
472
|
+
luma,
|
|
473
|
+
maskBounds,
|
|
474
|
+
membraneFill,
|
|
475
|
+
normalizeRetouch,
|
|
476
|
+
perDabStrength,
|
|
477
|
+
readSourceRegion,
|
|
478
|
+
rgbaViewOfGrey,
|
|
479
|
+
saturationOf,
|
|
480
|
+
seamlessClone,
|
|
481
|
+
smudgeEffect,
|
|
482
|
+
solveMembrane,
|
|
483
|
+
sponge,
|
|
484
|
+
spongeEffect,
|
|
485
|
+
spotHealPixels,
|
|
486
|
+
spotHealWindow,
|
|
487
|
+
toneOf
|
|
488
|
+
} from "../chunk-LKCYANMW.js";
|
|
476
489
|
import {
|
|
477
490
|
CoverageMap,
|
|
478
491
|
DEFAULT_BLENDER,
|
|
@@ -512,7 +525,7 @@ import {
|
|
|
512
525
|
tipReach,
|
|
513
526
|
tipShape,
|
|
514
527
|
walkDabs
|
|
515
|
-
} from "../chunk-
|
|
528
|
+
} from "../chunk-UBIXVXPR.js";
|
|
516
529
|
import {
|
|
517
530
|
BLEND_MODES,
|
|
518
531
|
PAINTERLY_BLEND_MODES,
|
|
@@ -566,21 +579,62 @@ import {
|
|
|
566
579
|
translateSurface,
|
|
567
580
|
uniformTile,
|
|
568
581
|
writeRegion
|
|
569
|
-
} from "../chunk-
|
|
582
|
+
} from "../chunk-XK5LZKBD.js";
|
|
583
|
+
import {
|
|
584
|
+
BUILTIN_PROFILES,
|
|
585
|
+
CmsError,
|
|
586
|
+
GamutCheck,
|
|
587
|
+
INTENTS,
|
|
588
|
+
Transform,
|
|
589
|
+
builtinProfile,
|
|
590
|
+
builtinProfileId,
|
|
591
|
+
canBeDestination,
|
|
592
|
+
encodeProfile,
|
|
593
|
+
parseProfile,
|
|
594
|
+
sameColors,
|
|
595
|
+
srgbProfile,
|
|
596
|
+
writeJpegIcc,
|
|
597
|
+
writePngIcc
|
|
598
|
+
} from "../chunk-BRLYOPLT.js";
|
|
570
599
|
import {
|
|
600
|
+
ZlibError,
|
|
601
|
+
adler32,
|
|
602
|
+
deflate,
|
|
603
|
+
deflateRaw,
|
|
604
|
+
inflate,
|
|
605
|
+
inflateRaw
|
|
606
|
+
} from "../chunk-6FCKOS2B.js";
|
|
607
|
+
import {
|
|
608
|
+
DEFAULT_AUTO_LEADING,
|
|
609
|
+
DEFAULT_TEXT_STYLE,
|
|
571
610
|
WARP_STYLES,
|
|
572
611
|
WARP_STYLE_LABELS,
|
|
573
612
|
applyMatrix,
|
|
574
613
|
bezierToSubpaths,
|
|
614
|
+
caretAt,
|
|
615
|
+
createCanvasTextShaper,
|
|
616
|
+
createMetricTextShaper,
|
|
617
|
+
createOutlineTextShaper,
|
|
618
|
+
cssFont,
|
|
619
|
+
cssFontFamily,
|
|
575
620
|
dragWarpMeshPoint,
|
|
576
621
|
evalWarpMesh,
|
|
622
|
+
fitParagraphRuns,
|
|
623
|
+
fitRuns,
|
|
624
|
+
fontOf,
|
|
577
625
|
identityWarpMesh,
|
|
578
626
|
invertMatrix,
|
|
627
|
+
layoutText,
|
|
579
628
|
multiplyMatrices,
|
|
629
|
+
paragraphRanges,
|
|
580
630
|
pullWarpMesh,
|
|
581
631
|
resizeWarpMesh,
|
|
632
|
+
restyleRange,
|
|
582
633
|
rotateMatrix,
|
|
583
634
|
roundSubpaths,
|
|
635
|
+
spliceRuns,
|
|
636
|
+
styleAt,
|
|
637
|
+
textIndexAt,
|
|
584
638
|
translateMatrix,
|
|
585
639
|
warpMeshColumns,
|
|
586
640
|
warpMeshEditPoints,
|
|
@@ -588,7 +642,7 @@ import {
|
|
|
588
642
|
warpMeshParamAt,
|
|
589
643
|
warpMeshRows,
|
|
590
644
|
warpPresetMesh
|
|
591
|
-
} from "../chunk-
|
|
645
|
+
} from "../chunk-VXR7XWMF.js";
|
|
592
646
|
import "../chunk-YCSFS3GK.js";
|
|
593
647
|
import "../chunk-ZRJMJIQU.js";
|
|
594
648
|
import "../chunk-TGD52FEZ.js";
|
|
@@ -943,6 +997,17 @@ var ImageEditorRenderer = class {
|
|
|
943
997
|
/** Which path the last base render took. */
|
|
944
998
|
lastBaseRoute = null;
|
|
945
999
|
comp = null;
|
|
1000
|
+
/** Colour transform from the document to the display (see `color-management`), or none. */
|
|
1001
|
+
display = null;
|
|
1002
|
+
displayKey = 0;
|
|
1003
|
+
/** Sets the viewport's display transform (document profile → sRGB, or a soft proof); `null` for none. */
|
|
1004
|
+
setDisplayTransform(t) {
|
|
1005
|
+
if (t === this.display) return;
|
|
1006
|
+
this.display = t;
|
|
1007
|
+
this.displayKey++;
|
|
1008
|
+
this.comp = null;
|
|
1009
|
+
this.cachedBaseKey = "";
|
|
1010
|
+
}
|
|
946
1011
|
depthMaps = /* @__PURE__ */ new Map();
|
|
947
1012
|
assetVersion = 0;
|
|
948
1013
|
scratch = null;
|
|
@@ -1012,13 +1077,15 @@ var ImageEditorRenderer = class {
|
|
|
1012
1077
|
`${projection.angle},${transform.flipH},${transform.flipV}`,
|
|
1013
1078
|
`${adjustments.brightness},${adjustments.contrast},${adjustments.saturation},${adjustments.exposure},${adjustments.temperature},${adjustments.tint ?? 0},${adjustments.blur},${adjustments.opacity},p${normalizeProcessVersion(adjustments.process)}`,
|
|
1014
1079
|
adjustmentLayersKey(adjustments.layers),
|
|
1015
|
-
`${depthMask.enabled},${depthMask.maskSource},${depthMask.depthRange?.[0]}-${depthMask.depthRange?.[1]},${depthMask.softness},${depthMask.invert},${depthMask.mode}
|
|
1080
|
+
`${depthMask.enabled},${depthMask.maskSource},${depthMask.depthRange?.[0]}-${depthMask.depthRange?.[1]},${depthMask.softness},${depthMask.invert},${depthMask.mode}`,
|
|
1081
|
+
`d${this.displayKey}`
|
|
1016
1082
|
].join("|");
|
|
1017
1083
|
let baseCanvas = this.cachedBaseCanvas;
|
|
1018
1084
|
if (!baseCanvas || this.cachedBaseKey !== baseKey) {
|
|
1019
1085
|
let histogram = null;
|
|
1020
1086
|
baseCanvas = await this.renderBaseImage(img, naturalWidth, naturalHeight, region, transform, state, (pixels) => {
|
|
1021
1087
|
histogram = computeHistogram(pixels);
|
|
1088
|
+
this.display?.(pixels.data);
|
|
1022
1089
|
});
|
|
1023
1090
|
this.cachedBaseCanvas = baseCanvas;
|
|
1024
1091
|
this.cachedBaseKey = baseKey;
|
|
@@ -1369,6 +1436,7 @@ var ImageEditorRenderer = class {
|
|
|
1369
1436
|
if (x1 <= x0 || y1 <= y0) return;
|
|
1370
1437
|
const img = ctx.createImageData(TILE, TILE);
|
|
1371
1438
|
img.data.set(data);
|
|
1439
|
+
this.display?.(img.data);
|
|
1372
1440
|
ctx.putImageData(img, ox, oy, x0, y0, x1 - x0, y1 - y0);
|
|
1373
1441
|
}
|
|
1374
1442
|
/**
|
|
@@ -1411,7 +1479,7 @@ var ImageEditorRenderer = class {
|
|
|
1411
1479
|
const rotated = getRotatedSize(region.width, region.height, transform);
|
|
1412
1480
|
const baseW = Math.max(1, Math.round(rotated.width));
|
|
1413
1481
|
const baseH = Math.max(1, Math.round(rotated.height));
|
|
1414
|
-
const key = `${comp.version}|${region.x},${region.y},${region.width},${region.height}|${normalizeAngle(transform.rotate)},${transform.flipH},${transform.flipV}|${opacity}|${blur}`;
|
|
1482
|
+
const key = `${this.displayKey}:${comp.version}|${region.x},${region.y},${region.width},${region.height}|${normalizeAngle(transform.rotate)},${transform.flipH},${transform.flipV}|${opacity}|${blur}`;
|
|
1415
1483
|
if (this.cachedPostCanvas && this.cachedPostKey === key) return { canvas: this.cachedPostCanvas, histogram: this.cachedPostHistogram };
|
|
1416
1484
|
const canvas = this.cachedPostCanvas && this.cachedPostCanvas.width === baseW && this.cachedPostCanvas.height === baseH ? this.cachedPostCanvas : this.createCanvas(baseW, baseH);
|
|
1417
1485
|
const ctx = canvas.getContext("2d");
|
|
@@ -2548,159 +2616,6 @@ function refineSelection(pixels, mask, params = {}) {
|
|
|
2548
2616
|
return createSelectionMask(mask.width, mask.height, out);
|
|
2549
2617
|
}
|
|
2550
2618
|
|
|
2551
|
-
// src/image-editor/layers/text-shapers.ts
|
|
2552
|
-
var GENERIC = /* @__PURE__ */ new Set(["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded", "math", "emoji", "fangsong"]);
|
|
2553
|
-
function cssFontFamily(family) {
|
|
2554
|
-
const f = family.trim();
|
|
2555
|
-
if (GENERIC.has(f.toLowerCase()) || f.includes(",") || /^["']/.test(f)) return f;
|
|
2556
|
-
return /^[A-Za-z_-][\w -]*$/.test(f) && !/\s{2}/.test(f) ? f : `"${f.replace(/"/g, '\\"')}"`;
|
|
2557
|
-
}
|
|
2558
|
-
function cssFont(font, family = font.family) {
|
|
2559
|
-
return `${font.italic ? "italic " : ""}${font.weight} ${font.size}px ${cssFontFamily(family)}`;
|
|
2560
|
-
}
|
|
2561
|
-
function createCanvasTextShaper(options = {}) {
|
|
2562
|
-
const make = options.createCanvas ?? ((w, h) => {
|
|
2563
|
-
if (typeof OffscreenCanvas !== "undefined") return new OffscreenCanvas(w, h);
|
|
2564
|
-
if (typeof document !== "undefined") {
|
|
2565
|
-
const c = document.createElement("canvas");
|
|
2566
|
-
c.width = w;
|
|
2567
|
-
c.height = h;
|
|
2568
|
-
return c;
|
|
2569
|
-
}
|
|
2570
|
-
return null;
|
|
2571
|
-
});
|
|
2572
|
-
const canvas = make(1, 1);
|
|
2573
|
-
const ctx = canvas?.getContext("2d");
|
|
2574
|
-
if (!ctx || typeof ctx.measureText !== "function") return null;
|
|
2575
|
-
const fallback = options.fallbackFamily ?? "sans-serif";
|
|
2576
|
-
const available = /* @__PURE__ */ new Map();
|
|
2577
|
-
const widths = /* @__PURE__ */ new Map();
|
|
2578
|
-
const metrics = /* @__PURE__ */ new Map();
|
|
2579
|
-
const probe = "mmmmmmmmmmlli1WQ@#";
|
|
2580
|
-
const width = (font, text) => {
|
|
2581
|
-
ctx.font = font;
|
|
2582
|
-
return ctx.measureText(text).width;
|
|
2583
|
-
};
|
|
2584
|
-
const isAvailable = (family) => {
|
|
2585
|
-
const f = family.trim();
|
|
2586
|
-
if (GENERIC.has(f.toLowerCase()) || f.includes(",")) return true;
|
|
2587
|
-
let hit = available.get(f);
|
|
2588
|
-
if (hit === void 0) {
|
|
2589
|
-
const q = cssFontFamily(f);
|
|
2590
|
-
hit = width(`72px ${q}, monospace`, probe) !== width("72px monospace", probe) || width(`72px ${q}, serif`, probe) !== width("72px serif", probe);
|
|
2591
|
-
available.set(f, hit);
|
|
2592
|
-
}
|
|
2593
|
-
return hit;
|
|
2594
|
-
};
|
|
2595
|
-
return {
|
|
2596
|
-
id: "canvas",
|
|
2597
|
-
resolve(font) {
|
|
2598
|
-
const ok = isAvailable(font.family);
|
|
2599
|
-
return { family: ok ? font.family : fallback, available: ok };
|
|
2600
|
-
},
|
|
2601
|
-
metrics(font) {
|
|
2602
|
-
const key = cssFont(font);
|
|
2603
|
-
let m = metrics.get(key);
|
|
2604
|
-
if (!m) {
|
|
2605
|
-
ctx.font = key;
|
|
2606
|
-
ctx.textBaseline = "alphabetic";
|
|
2607
|
-
const t = ctx.measureText("Hg");
|
|
2608
|
-
const ascent = t.emHeightAscent ?? t.fontBoundingBoxAscent ?? font.size * 0.8;
|
|
2609
|
-
const descent = t.emHeightDescent ?? t.fontBoundingBoxDescent ?? font.size * 0.2;
|
|
2610
|
-
m = { ascent: Number.isFinite(ascent) ? ascent : font.size * 0.8, descent: Number.isFinite(descent) ? descent : font.size * 0.2 };
|
|
2611
|
-
metrics.set(key, m);
|
|
2612
|
-
}
|
|
2613
|
-
return m;
|
|
2614
|
-
},
|
|
2615
|
-
measure(text, font) {
|
|
2616
|
-
const key = `${cssFont(font)}|${text}`;
|
|
2617
|
-
let w = widths.get(key);
|
|
2618
|
-
if (!w) {
|
|
2619
|
-
ctx.font = cssFont(font);
|
|
2620
|
-
w = [0];
|
|
2621
|
-
for (let i = 1; i <= text.length; i++) w.push(ctx.measureText(text.slice(0, i)).width);
|
|
2622
|
-
if (widths.size > 2e3) widths.clear();
|
|
2623
|
-
widths.set(key, w);
|
|
2624
|
-
}
|
|
2625
|
-
return w;
|
|
2626
|
-
},
|
|
2627
|
-
draw(target, text, font, x, y) {
|
|
2628
|
-
target.font = cssFont(font);
|
|
2629
|
-
target.textBaseline = "alphabetic";
|
|
2630
|
-
target.textAlign = "left";
|
|
2631
|
-
target.fillText(text, x, y);
|
|
2632
|
-
},
|
|
2633
|
-
families() {
|
|
2634
|
-
const out = /* @__PURE__ */ new Set(["sans-serif", "serif", "monospace"]);
|
|
2635
|
-
const fonts = typeof document !== "undefined" ? document.fonts : void 0;
|
|
2636
|
-
if (fonts && typeof fonts.forEach === "function") fonts.forEach((f) => out.add(f.family.replace(/^["']|["']$/g, "")));
|
|
2637
|
-
return [...out];
|
|
2638
|
-
}
|
|
2639
|
-
};
|
|
2640
|
-
}
|
|
2641
|
-
function createOutlineTextShaper(fonts, options = {}) {
|
|
2642
|
-
if (!fonts.length) throw new Error("createOutlineTextShaper needs at least one font.");
|
|
2643
|
-
const entries = fonts.map((f) => {
|
|
2644
|
-
const e = "face" in f ? f : { face: f };
|
|
2645
|
-
const names = e.face.names;
|
|
2646
|
-
const family = e.family ?? names?.fontFamily?.en ?? Object.values(names?.fontFamily ?? {})[0] ?? "Font";
|
|
2647
|
-
const weight = e.weight ?? e.face.tables?.os2?.usWeightClass ?? 400;
|
|
2648
|
-
const italic = e.italic ?? Boolean((e.face.tables?.os2?.fsSelection ?? 0) & 1);
|
|
2649
|
-
const postScript = names?.postScriptName?.en ?? Object.values(names?.postScriptName ?? {})[0];
|
|
2650
|
-
return { face: e.face, family, key: family.toLowerCase(), weight, italic, postScript };
|
|
2651
|
-
});
|
|
2652
|
-
const fallbackKey = (options.fallback ?? entries[0].family).toLowerCase();
|
|
2653
|
-
const pick3 = (font) => {
|
|
2654
|
-
if (font.postScriptName) {
|
|
2655
|
-
const exact = entries.find((e) => e.postScript === font.postScriptName);
|
|
2656
|
-
if (exact) return { entry: exact, available: true };
|
|
2657
|
-
}
|
|
2658
|
-
const key = font.family.trim().toLowerCase();
|
|
2659
|
-
let pool = entries.filter((e) => e.key === key);
|
|
2660
|
-
const available = pool.length > 0;
|
|
2661
|
-
if (!available) pool = entries.filter((e) => e.key === fallbackKey);
|
|
2662
|
-
if (!pool.length) pool = entries;
|
|
2663
|
-
const styled = pool.filter((e) => e.italic === font.italic);
|
|
2664
|
-
const list = styled.length ? styled : pool;
|
|
2665
|
-
const entry = list.reduce((best, e) => Math.abs(e.weight - font.weight) < Math.abs(best.weight - font.weight) ? e : best);
|
|
2666
|
-
return { entry, available };
|
|
2667
|
-
};
|
|
2668
|
-
const toPath = (cmds) => {
|
|
2669
|
-
const out = [];
|
|
2670
|
-
for (const c of cmds) {
|
|
2671
|
-
if (c.type === "M" || c.type === "L") out.push({ type: c.type, x: c.x, y: c.y });
|
|
2672
|
-
else if (c.type === "C") out.push({ type: "C", x1: c.x1, y1: c.y1, x2: c.x2, y2: c.y2, x: c.x, y: c.y });
|
|
2673
|
-
else if (c.type === "Q") out.push({ type: "Q", x1: c.x1, y1: c.y1, x: c.x, y: c.y });
|
|
2674
|
-
else out.push({ type: "Z" });
|
|
2675
|
-
}
|
|
2676
|
-
return out;
|
|
2677
|
-
};
|
|
2678
|
-
return {
|
|
2679
|
-
id: options.id ?? `outline:${entries.map((e) => `${e.family}/${e.weight}${e.italic ? "i" : ""}`).join(",")}`,
|
|
2680
|
-
resolve(font) {
|
|
2681
|
-
const { entry, available } = pick3(font);
|
|
2682
|
-
return { family: entry.family, available };
|
|
2683
|
-
},
|
|
2684
|
-
metrics(font) {
|
|
2685
|
-
const { face } = pick3(font).entry;
|
|
2686
|
-
const k = font.size / face.unitsPerEm;
|
|
2687
|
-
return { ascent: face.ascender * k, descent: -face.descender * k };
|
|
2688
|
-
},
|
|
2689
|
-
measure(text, font) {
|
|
2690
|
-
const { face } = pick3(font).entry;
|
|
2691
|
-
const out = [0];
|
|
2692
|
-
for (let i = 1; i <= text.length; i++) out.push(face.getAdvanceWidth(text.slice(0, i), font.size, { kerning: true }));
|
|
2693
|
-
return out;
|
|
2694
|
-
},
|
|
2695
|
-
outline(text, font, x, y) {
|
|
2696
|
-
return toPath(pick3(font).entry.face.getPath(text, x, y, font.size, { kerning: true }).commands);
|
|
2697
|
-
},
|
|
2698
|
-
families() {
|
|
2699
|
-
return [...new Set(entries.map((e) => e.family))];
|
|
2700
|
-
}
|
|
2701
|
-
};
|
|
2702
|
-
}
|
|
2703
|
-
|
|
2704
2619
|
// src/image-editor/free-transform.ts
|
|
2705
2620
|
var FREE_TRANSFORM_CONTENTS = ["auto", "layer", "selection", "selection-copy", "selection-outline"];
|
|
2706
2621
|
var fail = (message) => {
|
|
@@ -3181,6 +3096,141 @@ var FreeTransformSession = class {
|
|
|
3181
3096
|
}
|
|
3182
3097
|
};
|
|
3183
3098
|
|
|
3099
|
+
// src/image-editor/color-management.ts
|
|
3100
|
+
var DEFAULT_PROOF = { intent: "relative", bpc: true, simulatePaper: false, gamutWarning: false };
|
|
3101
|
+
var resolved = /* @__PURE__ */ new WeakMap();
|
|
3102
|
+
var fromBytes = /* @__PURE__ */ new Map();
|
|
3103
|
+
function resolveProfile(doc) {
|
|
3104
|
+
if (!doc) return srgbProfile();
|
|
3105
|
+
const hit = resolved.get(doc);
|
|
3106
|
+
if (hit) return hit;
|
|
3107
|
+
let p;
|
|
3108
|
+
if (doc.builtin) p = builtinProfile(doc.builtin);
|
|
3109
|
+
else if (doc.icc) {
|
|
3110
|
+
const key = bytesToBase64(doc.icc);
|
|
3111
|
+
p = fromBytes.get(key) ?? parseProfile(doc.icc);
|
|
3112
|
+
if (fromBytes.size > 32) fromBytes.clear();
|
|
3113
|
+
fromBytes.set(key, p);
|
|
3114
|
+
} else p = srgbProfile();
|
|
3115
|
+
resolved.set(doc, p);
|
|
3116
|
+
return p;
|
|
3117
|
+
}
|
|
3118
|
+
function profileBytes(doc) {
|
|
3119
|
+
if (doc?.icc) return doc.icc;
|
|
3120
|
+
const p = resolveProfile(doc);
|
|
3121
|
+
return p.bytes ?? encodeProfile(p);
|
|
3122
|
+
}
|
|
3123
|
+
function documentProfile(input) {
|
|
3124
|
+
if (typeof input === "string") {
|
|
3125
|
+
const id = builtinProfileId(input);
|
|
3126
|
+
if (!id) throw new CmsError(`Unknown colour profile "${input}"; use one of ${BUILTIN_PROFILES.map((b) => b.id).join(", ")}, or ICC bytes.`);
|
|
3127
|
+
return { builtin: id, name: BUILTIN_PROFILES.find((b) => b.id === id).description };
|
|
3128
|
+
}
|
|
3129
|
+
const p = parseProfile(input);
|
|
3130
|
+
return { name: p.description || "Embedded profile", icc: input.slice() };
|
|
3131
|
+
}
|
|
3132
|
+
function isSrgb(doc) {
|
|
3133
|
+
if (!doc || doc.builtin === "srgb") return true;
|
|
3134
|
+
try {
|
|
3135
|
+
return sameColors(resolveProfile(doc), srgbProfile(), builtinProfile("lab-d50"));
|
|
3136
|
+
} catch {
|
|
3137
|
+
return false;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
function serializeColorProfile(doc) {
|
|
3141
|
+
return doc.builtin ? { builtin: doc.builtin, name: doc.name } : { name: doc.name, icc: bytesToBase64(doc.icc ?? new Uint8Array(0)) };
|
|
3142
|
+
}
|
|
3143
|
+
function deserializeColorProfile(raw, problems) {
|
|
3144
|
+
const r = raw;
|
|
3145
|
+
if (!r || typeof r !== "object") return null;
|
|
3146
|
+
try {
|
|
3147
|
+
if (r.builtin) {
|
|
3148
|
+
const id = builtinProfileId(r.builtin);
|
|
3149
|
+
if (!id) throw new CmsError(`unknown built-in profile "${r.builtin}"`);
|
|
3150
|
+
return documentProfile(id);
|
|
3151
|
+
}
|
|
3152
|
+
if (typeof r.icc === "string") {
|
|
3153
|
+
const icc = base64ToBytes(r.icc);
|
|
3154
|
+
parseProfile(icc);
|
|
3155
|
+
return { name: typeof r.name === "string" ? r.name : "Embedded profile", icc };
|
|
3156
|
+
}
|
|
3157
|
+
} catch (e) {
|
|
3158
|
+
problems.push(`The colour profile could not be read (${e instanceof Error ? e.message : String(e)}); the document is treated as sRGB`);
|
|
3159
|
+
}
|
|
3160
|
+
return null;
|
|
3161
|
+
}
|
|
3162
|
+
function displayTransform(doc, proof) {
|
|
3163
|
+
const src = resolveProfile(doc);
|
|
3164
|
+
const display = srgbProfile();
|
|
3165
|
+
let t = null;
|
|
3166
|
+
let gamut = null;
|
|
3167
|
+
if (proof) {
|
|
3168
|
+
const p = resolveProfile(proof.profile);
|
|
3169
|
+
t = Transform.proof(src, p, display, proof.intent, proof.bpc, proof.simulatePaper);
|
|
3170
|
+
if (proof.gamutWarning) gamut = new GamutCheck(src, p, builtinProfile("lab-d50"));
|
|
3171
|
+
} else if (!isSrgb(doc)) t = Transform.create(src, display, { intent: "relative", bpc: true });
|
|
3172
|
+
if (!t) return null;
|
|
3173
|
+
const tr = t;
|
|
3174
|
+
const g = gamut;
|
|
3175
|
+
return (rgba) => {
|
|
3176
|
+
if (g) {
|
|
3177
|
+
const px2 = [0, 0, 0];
|
|
3178
|
+
const flags = new Uint8Array(rgba.length >> 2);
|
|
3179
|
+
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
|
|
3180
|
+
if (rgba[i + 3] === 0) continue;
|
|
3181
|
+
px2[0] = rgba[i] / 255;
|
|
3182
|
+
px2[1] = rgba[i + 1] / 255;
|
|
3183
|
+
px2[2] = rgba[i + 2] / 255;
|
|
3184
|
+
if (g.outOfGamut(px2)) flags[p] = 1;
|
|
3185
|
+
}
|
|
3186
|
+
tr.convert8(rgba, 4, rgba, 4);
|
|
3187
|
+
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) if (flags[p]) rgba[i] = rgba[i + 1] = rgba[i + 2] = 128;
|
|
3188
|
+
return;
|
|
3189
|
+
}
|
|
3190
|
+
tr.convert8(rgba, 4, rgba, 4);
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
function convertHex(hex, from, to, intent = "relative", bpc = true) {
|
|
3194
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
3195
|
+
if (!m) return hex;
|
|
3196
|
+
const n = parseInt(m[1], 16);
|
|
3197
|
+
const out = new Float32Array(4);
|
|
3198
|
+
Transform.create(from, to, { intent, bpc }).eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], out);
|
|
3199
|
+
const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0");
|
|
3200
|
+
return `#${c(out[0])}${c(out[1])}${c(out[2])}`;
|
|
3201
|
+
}
|
|
3202
|
+
function convertSurfaceColors(surface, t) {
|
|
3203
|
+
if (surface.channels !== 4 || t.inputs !== 3 || t.outputs !== 3) return surface;
|
|
3204
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
3205
|
+
const memo = /* @__PURE__ */ new Map();
|
|
3206
|
+
for (const [key, tile] of surface.tiles) {
|
|
3207
|
+
let next = memo.get(tile);
|
|
3208
|
+
if (next === void 0) {
|
|
3209
|
+
if (tile.deep instanceof Uint16Array) {
|
|
3210
|
+
const out = new Uint16Array(tile.deep.length);
|
|
3211
|
+
t.convert16(tile.deep, 4, out, 4);
|
|
3212
|
+
next = deepTile(out, 4, surface.defaultValue);
|
|
3213
|
+
} else if (tile.deep instanceof Float32Array) {
|
|
3214
|
+
const enc = new Float32Array(tile.deep.length);
|
|
3215
|
+
for (let i = 0; i < enc.length; i += 4) {
|
|
3216
|
+
for (let c = 0; c < 3; c++) enc[i + c] = srgbEncode(tile.deep[i + c]);
|
|
3217
|
+
enc[i + 3] = tile.deep[i + 3];
|
|
3218
|
+
}
|
|
3219
|
+
t.convertFloat(enc, 4, enc, 4);
|
|
3220
|
+
for (let i = 0; i < enc.length; i += 4) for (let c = 0; c < 3; c++) enc[i + c] = srgbDecode(enc[i + c]);
|
|
3221
|
+
next = deepTile(enc, 4, surface.defaultValue);
|
|
3222
|
+
} else {
|
|
3223
|
+
const out = new Uint8ClampedArray(tile.data.length);
|
|
3224
|
+
t.convert8(tile.data, 4, out, 4);
|
|
3225
|
+
next = finishTile(out, 4, surface.defaultValue);
|
|
3226
|
+
}
|
|
3227
|
+
memo.set(tile, next);
|
|
3228
|
+
}
|
|
3229
|
+
if (next) tiles.set(key, next);
|
|
3230
|
+
}
|
|
3231
|
+
return new TiledSurface(4, tiles, surface.defaultValue);
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3184
3234
|
// src/image-editor/controller.ts
|
|
3185
3235
|
var IMAGE_EDITOR_SCHEMA_VERSION = LAYERED_SCHEMA_VERSION;
|
|
3186
3236
|
var RETOUCH_TOOLS = ["clone", "heal", "spot-heal", "smudge", "dodge", "burn", "sponge"];
|
|
@@ -3593,10 +3643,23 @@ var ImageEditorController = class {
|
|
|
3593
3643
|
if (strokeRects && this.pendingDirty !== "all") this.pendingDirty.push(...strokeRects);
|
|
3594
3644
|
else if (!strokeRects) this.pendingDirty = "all";
|
|
3595
3645
|
this.syncViews();
|
|
3646
|
+
this.syncDisplay();
|
|
3596
3647
|
const currentState = { ...this.state };
|
|
3597
3648
|
this.onStateChange?.(currentState);
|
|
3598
3649
|
this.listeners.forEach((l) => l(currentState));
|
|
3599
3650
|
}
|
|
3651
|
+
displayFor = null;
|
|
3652
|
+
/** Keeps the renderer's display transform in step with the document profile and Proof Setup. */
|
|
3653
|
+
syncDisplay() {
|
|
3654
|
+
const s = this.state;
|
|
3655
|
+
if (this.displayFor && this.displayFor[0] === s.colorProfile && this.displayFor[1] === s.proofSetup) return;
|
|
3656
|
+
this.displayFor = [s.colorProfile, s.proofSetup];
|
|
3657
|
+
try {
|
|
3658
|
+
this.renderer.setDisplayTransform(displayTransform(s.colorProfile, s.proofSetup));
|
|
3659
|
+
} catch {
|
|
3660
|
+
this.renderer.setDisplayTransform(null);
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3600
3663
|
/** Recomputes the compatibility views (`adjustments`, `depthMask`, `annotations`) when the stack changed. */
|
|
3601
3664
|
syncViews() {
|
|
3602
3665
|
const s = this.state;
|
|
@@ -3634,6 +3697,8 @@ var ImageEditorController = class {
|
|
|
3634
3697
|
if (s.legacyOutputBlur !== void 0) entry.legacyOutputBlur = s.legacyOutputBlur;
|
|
3635
3698
|
if (s.globalLight) entry.globalLight = { ...s.globalLight };
|
|
3636
3699
|
if (s.patterns) entry.patterns = s.patterns;
|
|
3700
|
+
if (s.colorProfile) entry.colorProfile = s.colorProfile;
|
|
3701
|
+
if (s.bitDepth && s.bitDepth !== 8) entry.bitDepth = s.bitDepth;
|
|
3637
3702
|
return entry;
|
|
3638
3703
|
}
|
|
3639
3704
|
restoreHistoryEntry(entry) {
|
|
@@ -3650,6 +3715,10 @@ var ImageEditorController = class {
|
|
|
3650
3715
|
else delete s.globalLight;
|
|
3651
3716
|
if (entry.patterns) s.patterns = entry.patterns;
|
|
3652
3717
|
else delete s.patterns;
|
|
3718
|
+
if (entry.bitDepth) s.bitDepth = entry.bitDepth;
|
|
3719
|
+
else delete s.bitDepth;
|
|
3720
|
+
if (entry.colorProfile) s.colorProfile = entry.colorProfile;
|
|
3721
|
+
else delete s.colorProfile;
|
|
3653
3722
|
s.selection = entry.selection;
|
|
3654
3723
|
if (this.imageElement !== entry.source.element && !this.samplePixelsOverride) this.samplePixels = null;
|
|
3655
3724
|
this.imageElement = entry.source.element;
|
|
@@ -4933,9 +5002,28 @@ var ImageEditorController = class {
|
|
|
4933
5002
|
throw new LayerOperationError("Merging annotation layers needs a canvas (a browser); hide or delete them first, or merge in the browser.");
|
|
4934
5003
|
}
|
|
4935
5004
|
await this.renderer.prepareLayerAssets(layers, width, height);
|
|
4936
|
-
const
|
|
5005
|
+
const sources = this.renderer.compositorSources(width, height);
|
|
5006
|
+
const depth = this.bitDepth;
|
|
5007
|
+
if (depth !== 8) {
|
|
5008
|
+
const samples = workingToSamples(compositeDeep(layers, rect, sources, depth), depth);
|
|
5009
|
+
return surfaceFromDeepPixels({ width: rect.width, height: rect.height, data: samples }, 4, rect.x, rect.y);
|
|
5010
|
+
}
|
|
5011
|
+
const data = new LayerCompositor().composite(layers, rect, sources);
|
|
4937
5012
|
return surfaceFromPixels({ width: rect.width, height: rect.height, data }, 4, rect.x, rect.y);
|
|
4938
5013
|
}
|
|
5014
|
+
/**
|
|
5015
|
+
* The composite of the layer stack at the document's bit depth (as `compositePixels`, no
|
|
5016
|
+
* canvas): 16-bit sRGB samples, or 32-bit linear float, over `rect` (default the canvas). At 8
|
|
5017
|
+
* bits, the 8-bit composite widened to 16 bits.
|
|
5018
|
+
*/
|
|
5019
|
+
compositeDeepPixels(rect) {
|
|
5020
|
+
const { width, height } = this.naturalSize;
|
|
5021
|
+
const r = rect ?? { x: 0, y: 0, width, height };
|
|
5022
|
+
const depth = this.bitDepth;
|
|
5023
|
+
if (depth === 8) return { width: r.width, height: r.height, depth: 16, data: to16From8(this.compositePixels(r).data) };
|
|
5024
|
+
const data = workingToSamples(compositeDeep(this.state.layers, r, this.compositorSources(), depth), depth);
|
|
5025
|
+
return { width: r.width, height: r.height, depth, data };
|
|
5026
|
+
}
|
|
4939
5027
|
/** Document bounds a layer can paint into (pixel content, annotations, or the canvas for the rest). */
|
|
4940
5028
|
paintBounds(layer) {
|
|
4941
5029
|
const { width, height } = this.naturalSize;
|
|
@@ -6138,16 +6226,37 @@ var ImageEditorController = class {
|
|
|
6138
6226
|
const canvas = await this.renderExport(options);
|
|
6139
6227
|
const format = options.format || "image/png";
|
|
6140
6228
|
const quality = options.quality ?? 0.92;
|
|
6141
|
-
|
|
6229
|
+
const url = canvas.toDataURL(format, quality);
|
|
6230
|
+
if (!this.state.colorProfile) return url;
|
|
6231
|
+
const parsed = parseDataUrl(url);
|
|
6232
|
+
if (!parsed) return url;
|
|
6233
|
+
const bytes = this.withEmbeddedProfile(parsed.bytes, parsed.mime);
|
|
6234
|
+
return bytes === parsed.bytes ? url : `data:${parsed.mime};base64,${bytesToBase64(bytes)}`;
|
|
6235
|
+
}
|
|
6236
|
+
/** PNG or JPEG bytes with the document's ICC profile embedded (other formats unchanged). */
|
|
6237
|
+
withEmbeddedProfile(bytes, mime) {
|
|
6238
|
+
const icc = profileBytes(this.state.colorProfile);
|
|
6239
|
+
try {
|
|
6240
|
+
if (mime === "image/png") return writePngIcc(bytes, icc, this.getColorProfile().name);
|
|
6241
|
+
if (mime === "image/jpeg") return writeJpegIcc(bytes, icc);
|
|
6242
|
+
} catch {
|
|
6243
|
+
}
|
|
6244
|
+
return bytes;
|
|
6142
6245
|
}
|
|
6143
6246
|
async toBlob(options = {}) {
|
|
6144
6247
|
const canvas = await this.renderExport(options);
|
|
6145
6248
|
const format = options.format || "image/png";
|
|
6146
6249
|
const quality = options.quality ?? 0.92;
|
|
6250
|
+
const tag = async (blob) => {
|
|
6251
|
+
if (!this.state.colorProfile || typeof blob.arrayBuffer !== "function") return blob;
|
|
6252
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
6253
|
+
const out = this.withEmbeddedProfile(bytes, blob.type || format);
|
|
6254
|
+
return out === bytes ? blob : new Blob([out], { type: blob.type || format });
|
|
6255
|
+
};
|
|
6147
6256
|
return new Promise((resolve, reject) => {
|
|
6148
6257
|
if (canvas.toBlob) {
|
|
6149
6258
|
canvas.toBlob((blob) => {
|
|
6150
|
-
if (blob)
|
|
6259
|
+
if (blob) tag(blob).then(resolve, reject);
|
|
6151
6260
|
else reject(new Error("Failed to create Blob from canvas"));
|
|
6152
6261
|
}, format, quality);
|
|
6153
6262
|
} else {
|
|
@@ -6160,7 +6269,7 @@ var ImageEditorController = class {
|
|
|
6160
6269
|
for (let i = 0; i < byteStr.length; i++) {
|
|
6161
6270
|
ia[i] = byteStr.charCodeAt(i);
|
|
6162
6271
|
}
|
|
6163
|
-
|
|
6272
|
+
tag(new Blob([ab], { type: format })).then(resolve, reject);
|
|
6164
6273
|
} catch (err) {
|
|
6165
6274
|
reject(err);
|
|
6166
6275
|
}
|
|
@@ -6680,6 +6789,162 @@ var ImageEditorController = class {
|
|
|
6680
6789
|
return id;
|
|
6681
6790
|
}
|
|
6682
6791
|
// --- PSD ---
|
|
6792
|
+
// --- Colour management ---
|
|
6793
|
+
/** The document's colour profile: its name, built-in id (or `null` for an embedded profile) and colour space. */
|
|
6794
|
+
getColorProfile() {
|
|
6795
|
+
const doc = this.state.colorProfile;
|
|
6796
|
+
const p = resolveProfile(doc);
|
|
6797
|
+
return { name: doc?.name ?? p.description, builtin: doc ? doc.builtin ?? null : "srgb", colorSpace: p.colorSpace, srgb: isSrgb(doc) };
|
|
6798
|
+
}
|
|
6799
|
+
/** Resolves a profile argument (built-in id or alias, or ICC bytes) as an RGB document profile. */
|
|
6800
|
+
rgbProfileArg(profile, action) {
|
|
6801
|
+
let doc;
|
|
6802
|
+
try {
|
|
6803
|
+
doc = documentProfile(profile);
|
|
6804
|
+
} catch (e) {
|
|
6805
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6806
|
+
}
|
|
6807
|
+
const cs = resolveProfile(doc).colorSpace;
|
|
6808
|
+
if (cs !== "rgb") throw new LayerOperationError(`${action} needs an RGB profile; "${doc.name}" is ${cs.toUpperCase()}. The document is RGB: soft-proof CMYK with set_proof_setup, or export to it.`);
|
|
6809
|
+
return doc;
|
|
6810
|
+
}
|
|
6811
|
+
/**
|
|
6812
|
+
* Edit › Assign Profile (one undo step): the document's numbers now mean colours in
|
|
6813
|
+
* `profile` (a built-in id such as `display-p3`, or ICC bytes); no pixel changes, so colours
|
|
6814
|
+
* look different unless the profiles match. Returns the new profile.
|
|
6815
|
+
*/
|
|
6816
|
+
assignProfile(profile) {
|
|
6817
|
+
const doc = this.rgbProfileArg(profile, "Assign Profile");
|
|
6818
|
+
this.recordHistory();
|
|
6819
|
+
if (doc.builtin === "srgb") delete this.state.colorProfile;
|
|
6820
|
+
else this.state.colorProfile = doc;
|
|
6821
|
+
this.notify();
|
|
6822
|
+
return this.getColorProfile();
|
|
6823
|
+
}
|
|
6824
|
+
/**
|
|
6825
|
+
* Edit › Convert to Profile (one undo step): every pixel layer's numbers are converted so its
|
|
6826
|
+
* colours stay the same in `profile` (with `intent` and black point compensation), and
|
|
6827
|
+
* `profile` becomes the document's. Shape and type layers, layer effects and adjustment layers
|
|
6828
|
+
* keep their numbers (they are listed in `unconvertedLayerIds`). Returns the profile and the
|
|
6829
|
+
* layers changed.
|
|
6830
|
+
*/
|
|
6831
|
+
convertToProfile(profile, options = {}) {
|
|
6832
|
+
const doc = this.rgbProfileArg(profile, "Convert to Profile");
|
|
6833
|
+
const intent = options.intent ?? "relative";
|
|
6834
|
+
if (!INTENTS.includes(intent)) throw new LayerOperationError(`Unknown rendering intent "${String(intent)}"; use ${INTENTS.join(", ")}.`);
|
|
6835
|
+
const t = Transform.create(resolveProfile(this.state.colorProfile), resolveProfile(doc), { intent, bpc: options.bpc ?? true });
|
|
6836
|
+
const converted = [];
|
|
6837
|
+
const unconverted = [];
|
|
6838
|
+
const walk = (layers) => layers.map((l) => {
|
|
6839
|
+
if (l.type === "group") return { ...l, children: walk(l.children) };
|
|
6840
|
+
if (l.type === "pixel" && l.source !== "document") {
|
|
6841
|
+
converted.push(l.id);
|
|
6842
|
+
return { ...l, surface: convertSurfaceColors(l.surface, t) };
|
|
6843
|
+
}
|
|
6844
|
+
if (l.type === "pixel" && l.source === "document") {
|
|
6845
|
+
converted.push(l.id);
|
|
6846
|
+
return { ...l, surface: convertSurfaceColors(this.surfaceOf(l), t), source: void 0 };
|
|
6847
|
+
}
|
|
6848
|
+
if (l.type === "shape" || l.type === "type" || l.type === "smart" || l.effects?.items.length) unconverted.push(l.id);
|
|
6849
|
+
return l;
|
|
6850
|
+
});
|
|
6851
|
+
const next = walk(this.state.layers);
|
|
6852
|
+
this.commitLayers(next, () => {
|
|
6853
|
+
if (doc.builtin === "srgb") delete this.state.colorProfile;
|
|
6854
|
+
else this.state.colorProfile = doc;
|
|
6855
|
+
});
|
|
6856
|
+
return { profile: this.getColorProfile(), convertedLayerIds: converted, unconvertedLayerIds: unconverted };
|
|
6857
|
+
}
|
|
6858
|
+
/**
|
|
6859
|
+
* View › Proof Setup (view state, not an undo step): shows the document as `profile` would
|
|
6860
|
+
* reproduce it, or turns proofing off with `null`. Returns the setup.
|
|
6861
|
+
*/
|
|
6862
|
+
setProofSetup(setup) {
|
|
6863
|
+
if (!setup) {
|
|
6864
|
+
this.state.proofSetup = null;
|
|
6865
|
+
this.notify();
|
|
6866
|
+
return null;
|
|
6867
|
+
}
|
|
6868
|
+
let doc;
|
|
6869
|
+
try {
|
|
6870
|
+
doc = documentProfile(setup.profile);
|
|
6871
|
+
} catch (e) {
|
|
6872
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6873
|
+
}
|
|
6874
|
+
const intent = setup.intent ?? DEFAULT_PROOF.intent;
|
|
6875
|
+
if (!INTENTS.includes(intent)) throw new LayerOperationError(`Unknown rendering intent "${String(intent)}"; use ${INTENTS.join(", ")}.`);
|
|
6876
|
+
const next = { ...DEFAULT_PROOF, ...setup, intent, profile: doc };
|
|
6877
|
+
if (!canBeDestination(resolveProfile(doc))) throw new LayerOperationError(`"${doc.name}" describes a source only, so colours cannot be proofed through it.`);
|
|
6878
|
+
this.state.proofSetup = next;
|
|
6879
|
+
this.notify();
|
|
6880
|
+
return next;
|
|
6881
|
+
}
|
|
6882
|
+
/**
|
|
6883
|
+
* Converts colours (`#rrggbb`) from one profile to another (default from the document's), with
|
|
6884
|
+
* `intent`. For RGB targets returns hex; for others the channel values 0..1 (CMYK, grey, Lab
|
|
6885
|
+
* encoded as L/100, (a+128)/255, (b+128)/255) and, for Lab, L*a*b*.
|
|
6886
|
+
*/
|
|
6887
|
+
convertColors(colors, to, options = {}) {
|
|
6888
|
+
let src;
|
|
6889
|
+
let dst;
|
|
6890
|
+
try {
|
|
6891
|
+
src = options.from !== void 0 ? resolveProfile(documentProfile(options.from)) : resolveProfile(this.state.colorProfile);
|
|
6892
|
+
dst = resolveProfile(documentProfile(to));
|
|
6893
|
+
} catch (e) {
|
|
6894
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6895
|
+
}
|
|
6896
|
+
if (src.colorSpace !== "rgb") throw new LayerOperationError("Colours are given as #rrggbb, so the source profile must be RGB.");
|
|
6897
|
+
const t = Transform.create(src, dst, { intent: options.intent ?? "relative", bpc: options.bpc ?? true });
|
|
6898
|
+
const toLab = Transform.create(src, builtinProfile("lab-d50"), { intent: "relative", bpc: false });
|
|
6899
|
+
return colors.map((input) => {
|
|
6900
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(input.trim());
|
|
6901
|
+
if (!m) throw new LayerOperationError(`Invalid colour "${input}"; use #rrggbb.`);
|
|
6902
|
+
const n = parseInt(m[1], 16);
|
|
6903
|
+
const rgb = [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
6904
|
+
const out = new Float32Array(16);
|
|
6905
|
+
t.eval(rgb, out);
|
|
6906
|
+
const values = Array.from(out.subarray(0, t.outputs), (v) => Math.round(Math.min(1, Math.max(0, v)) * 1e4) / 1e4);
|
|
6907
|
+
const l = new Float32Array(3);
|
|
6908
|
+
toLab.eval(rgb, l);
|
|
6909
|
+
const lab = [Math.round(l[0] * 1e4) / 100, Math.round((l[1] * 255 - 128) * 100) / 100, Math.round((l[2] * 255 - 128) * 100) / 100];
|
|
6910
|
+
const res = { input, values, lab };
|
|
6911
|
+
if (dst.colorSpace === "rgb") res.hex = `#${values.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("")}`;
|
|
6912
|
+
return res;
|
|
6913
|
+
});
|
|
6914
|
+
}
|
|
6915
|
+
/** The document's bits per channel (8 unless set to 16 or 32). */
|
|
6916
|
+
get bitDepth() {
|
|
6917
|
+
return this.state.bitDepth ?? 8;
|
|
6918
|
+
}
|
|
6919
|
+
/**
|
|
6920
|
+
* Image › Mode › 8 / 16 / 32 Bits/Channel (one undo step). Going up costs nothing: layers keep
|
|
6921
|
+
* their pixels and read them at the new depth, and edits that understand depth keep the extra
|
|
6922
|
+
* precision from then on. Going down rounds every pixel layer's deep samples to the new depth
|
|
6923
|
+
* (8 bits: their 8-bit rendering; 32 → 16: colour above 1 is clipped). Returns the depth and
|
|
6924
|
+
* the ids of the layers whose pixels changed.
|
|
6925
|
+
*/
|
|
6926
|
+
setBitDepth(depth) {
|
|
6927
|
+
if (!isBitDepth(depth)) throw new LayerOperationError(`Bit depth must be 8, 16 or 32, not ${String(depth)}.`);
|
|
6928
|
+
const changed = [];
|
|
6929
|
+
const convert = (layers) => layers.map((l) => {
|
|
6930
|
+
if (l.type === "group") {
|
|
6931
|
+
const children = convert(l.children);
|
|
6932
|
+
return children.some((c, i) => c !== l.children[i]) ? { ...l, children } : l;
|
|
6933
|
+
}
|
|
6934
|
+
if (l.type !== "pixel") return l;
|
|
6935
|
+
const surface = convertSurfaceDepth(l.surface, depth);
|
|
6936
|
+
if (surface === l.surface) return l;
|
|
6937
|
+
changed.push(l.id);
|
|
6938
|
+
return { ...l, surface };
|
|
6939
|
+
});
|
|
6940
|
+
if (depth === this.bitDepth) return { bitDepth: depth, changedLayerIds: [] };
|
|
6941
|
+
const next = convert(this.state.layers);
|
|
6942
|
+
this.commitLayers(next, () => {
|
|
6943
|
+
if (depth === 8) delete this.state.bitDepth;
|
|
6944
|
+
else this.state.bitDepth = depth;
|
|
6945
|
+
});
|
|
6946
|
+
return { bitDepth: depth, changedLayerIds: changed };
|
|
6947
|
+
}
|
|
6683
6948
|
/** Pixels per inch of the last opened PSD (written back by `toPsd`). */
|
|
6684
6949
|
psdResolution;
|
|
6685
6950
|
/**
|
|
@@ -6712,6 +6977,20 @@ var ImageEditorController = class {
|
|
|
6712
6977
|
else delete s.patterns;
|
|
6713
6978
|
if (result.globalLight) s.globalLight = result.globalLight;
|
|
6714
6979
|
else delete s.globalLight;
|
|
6980
|
+
if (result.bitDepth !== 8) s.bitDepth = result.bitDepth;
|
|
6981
|
+
else delete s.bitDepth;
|
|
6982
|
+
delete s.colorProfile;
|
|
6983
|
+
if (result.iccProfile) {
|
|
6984
|
+
try {
|
|
6985
|
+
const doc = documentProfile(result.iccProfile);
|
|
6986
|
+
const cs = resolveProfile(doc).colorSpace;
|
|
6987
|
+
if (cs === "rgb") {
|
|
6988
|
+
if (!isSrgb(doc)) s.colorProfile = doc;
|
|
6989
|
+
} else result.warnings.push(`The file's ${cs.toUpperCase()} profile "${doc.name}" was not used; its colours were converted to sRGB numerically.`);
|
|
6990
|
+
} catch (e) {
|
|
6991
|
+
result.warnings.push(`The embedded ICC profile could not be read (${e instanceof Error ? e.message : String(e)}); colours are read as sRGB.`);
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6715
6994
|
this.lastLoadProblems = result.warnings;
|
|
6716
6995
|
this.notify();
|
|
6717
6996
|
return {
|
|
@@ -6747,7 +7026,7 @@ var ImageEditorController = class {
|
|
|
6747
7026
|
return layers;
|
|
6748
7027
|
}
|
|
6749
7028
|
/**
|
|
6750
|
-
* The document as an
|
|
7029
|
+
* The document as an RGB PSD at its bit depth (8, 16 or 32) (PSB above 30 000 px) with real layers, groups, adjustment
|
|
6751
7030
|
* layers and masks, in the source frame. Layer filters and parametric (depth) masks are baked
|
|
6752
7031
|
* into pixels and masks, annotation layers are rasterized (in a browser; elsewhere they are left
|
|
6753
7032
|
* out), and the merged image is our composite. `warnings` lists every such change.
|
|
@@ -6873,7 +7152,9 @@ var ImageEditorController = class {
|
|
|
6873
7152
|
if (s.legacyOutputBlur) warnings.push("The document-level blur of an old document is not written.");
|
|
6874
7153
|
for (const [msg, names] of note) warnings.push(`${msg} (${names.length === 1 ? "layer" : "layers"} ${names.map((n) => `"${n}"`).join(", ")}).`);
|
|
6875
7154
|
const merged = compositor.composite(prepared, canvas, { ...sources, version: `psd:${Date.now()}` });
|
|
6876
|
-
const
|
|
7155
|
+
const depth = this.bitDepth;
|
|
7156
|
+
const mergedDeep = depth === 8 ? void 0 : workingToSamples(compositeDeep(prepared, canvas, sources, depth), depth);
|
|
7157
|
+
const result = exportPsd({ width, height, layers: prepared, merged, mergedDeep, resolution: this.psdResolution, patterns: this.state.patterns, globalLight: this.state.globalLight, depth, iccProfile: profileBytes(this.state.colorProfile) });
|
|
6877
7158
|
warnings.push(...result.warnings);
|
|
6878
7159
|
return { bytes: result.bytes, warnings, psb: result.psb, width, height };
|
|
6879
7160
|
}
|
|
@@ -7019,6 +7300,11 @@ var ImageEditorController = class {
|
|
|
7019
7300
|
const patterns = deserializePatterns(data.patterns, problems);
|
|
7020
7301
|
if (patterns.length) s.patterns = patterns;
|
|
7021
7302
|
else delete s.patterns;
|
|
7303
|
+
if (data.bitDepth === 16 || data.bitDepth === 32) s.bitDepth = data.bitDepth;
|
|
7304
|
+
else delete s.bitDepth;
|
|
7305
|
+
const profile = data.colorProfile ? deserializeColorProfile(data.colorProfile, problems) : null;
|
|
7306
|
+
if (profile) s.colorProfile = profile;
|
|
7307
|
+
else delete s.colorProfile;
|
|
7022
7308
|
if (!this.imageElement && typeof data.width === "number" && typeof data.height === "number" && data.width > 0 && data.height > 0) {
|
|
7023
7309
|
s.imageDimensions = { width: data.width, height: data.height };
|
|
7024
7310
|
}
|
|
@@ -7034,6 +7320,8 @@ var ImageEditorController = class {
|
|
|
7034
7320
|
s.activeLayerId = null;
|
|
7035
7321
|
delete s.globalLight;
|
|
7036
7322
|
delete s.patterns;
|
|
7323
|
+
delete s.bitDepth;
|
|
7324
|
+
delete s.colorProfile;
|
|
7037
7325
|
}
|
|
7038
7326
|
s.activeTarget = "pixels";
|
|
7039
7327
|
this.viewKey = [];
|
|
@@ -7043,7 +7331,7 @@ var ImageEditorController = class {
|
|
|
7043
7331
|
serializeState() {
|
|
7044
7332
|
const { width, height } = this.naturalSize;
|
|
7045
7333
|
const view = legacyView(this.stack(), width, height, null);
|
|
7046
|
-
if (view.exact && !this.state.globalLight && !this.state.patterns?.length) {
|
|
7334
|
+
if (view.exact && !this.state.globalLight && !this.state.patterns?.length && this.bitDepth === 8 && !this.state.colorProfile) {
|
|
7047
7335
|
return {
|
|
7048
7336
|
// States without adjustment layers keep schema 1, so they round-trip unchanged.
|
|
7049
7337
|
version: view.adjustments.layers?.length ? 2 : 1,
|
|
@@ -7073,6 +7361,8 @@ var ImageEditorController = class {
|
|
|
7073
7361
|
if (this.state.globalLight) out.globalLight = { ...this.state.globalLight };
|
|
7074
7362
|
if (this.state.patterns?.length) out.patterns = serializePatterns(this.state.patterns);
|
|
7075
7363
|
if (smartContents) out.smartContents = smartContents;
|
|
7364
|
+
if (this.state.bitDepth === 16 || this.state.bitDepth === 32) out.bitDepth = this.state.bitDepth;
|
|
7365
|
+
if (this.state.colorProfile) out.colorProfile = serializeColorProfile(this.state.colorProfile);
|
|
7076
7366
|
return out;
|
|
7077
7367
|
}
|
|
7078
7368
|
};
|
|
@@ -8281,10 +8571,23 @@ function createImageEditTools(controller) {
|
|
|
8281
8571
|
const getImageInfo = {
|
|
8282
8572
|
name: "get_image_info",
|
|
8283
8573
|
title: "Read image geometry",
|
|
8284
|
-
description: "Returns the source image size in pixels, the crop box (natural image pixels, or null for the whole image), rotation in degrees, flips, the output size after crop and rotation, the number of adjustment layers and whether undo / redo are available.",
|
|
8574
|
+
description: "Returns the source image size in pixels, the crop box (natural image pixels, or null for the whole image), rotation in degrees, flips, the output size after crop and rotation, the bits per channel (bitDepth 8, 16 or 32), the number of adjustment layers and whether undo / redo are available.",
|
|
8285
8575
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
8286
8576
|
annotations: { title: "Read image geometry", ...READ },
|
|
8287
|
-
handler: () => ({ ...geometry2(), layers: controller.getAdjustmentLayers().length, ...history() })
|
|
8577
|
+
handler: () => ({ ...geometry2(), bitDepth: controller.bitDepth, layers: controller.getAdjustmentLayers().length, ...history() })
|
|
8578
|
+
};
|
|
8579
|
+
const setBitDepth = {
|
|
8580
|
+
name: "set_bit_depth",
|
|
8581
|
+
title: "Set the bit depth",
|
|
8582
|
+
description: "Image \u203A Mode \u203A 8 / 16 / 32 Bits/Channel. 16-bit keeps smooth gradients and survives strong adjustments without banding; 32-bit holds linear-light float values (HDR, colour above 1). Going up costs nothing and changes no pixels; going down rounds every pixel layer's extra precision away (32 \u2192 16 also clips colour above 1). The viewport always shows an 8-bit rendering. One undo step. Returns the bitDepth and changedLayerIds (the layers whose samples were rounded).",
|
|
8583
|
+
inputSchema: {
|
|
8584
|
+
type: "object",
|
|
8585
|
+
properties: { depth: { type: "number", enum: [8, 16, 32], description: "Bits per channel: 8, 16 or 32 (float, linear light)." } },
|
|
8586
|
+
required: ["depth"],
|
|
8587
|
+
additionalProperties: false
|
|
8588
|
+
},
|
|
8589
|
+
annotations: { title: "Set the bit depth", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
8590
|
+
handler: (args) => ({ ...controller.setBitDepth(args.depth), ...history() })
|
|
8288
8591
|
};
|
|
8289
8592
|
const getHistogram = {
|
|
8290
8593
|
name: "get_histogram",
|
|
@@ -8460,7 +8763,7 @@ function createImageEditTools(controller) {
|
|
|
8460
8763
|
return history();
|
|
8461
8764
|
}
|
|
8462
8765
|
};
|
|
8463
|
-
return [getImageInfo, getHistogram, updateLayer, removeLayer2, moveLayer2, setCrop, resetCrop, setRotation, flipImage, undo, redo];
|
|
8766
|
+
return [getImageInfo, getHistogram, updateLayer, removeLayer2, moveLayer2, setCrop, resetCrop, setRotation, flipImage, setBitDepth, undo, redo];
|
|
8464
8767
|
}
|
|
8465
8768
|
|
|
8466
8769
|
// src/image-editor/layer-tools.ts
|
|
@@ -9775,8 +10078,132 @@ function createImagePaintTools(controller) {
|
|
|
9775
10078
|
return [paintStroke, fill, clear, getMixer, loadMixerTool, cleanMixerTool];
|
|
9776
10079
|
}
|
|
9777
10080
|
|
|
9778
|
-
// src/image-editor/
|
|
10081
|
+
// src/image-editor/color-tools.ts
|
|
9779
10082
|
var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10083
|
+
var PROFILE = {
|
|
10084
|
+
type: "string",
|
|
10085
|
+
description: `A built-in profile id (${BUILTIN_PROFILES.map((b) => b.id).join(", ")}; names like "Adobe RGB (1998)" work too), or "icc:<base64>" for ICC profile bytes.`
|
|
10086
|
+
};
|
|
10087
|
+
var INTENT = {
|
|
10088
|
+
type: "string",
|
|
10089
|
+
enum: [...INTENTS],
|
|
10090
|
+
description: "Rendering intent (default relative): relative (colorimetric, white to white, clips out-of-gamut colours: best for most photos), perceptual (compresses the whole gamut smoothly), saturation (keeps colours vivid, for graphics), absolute (keeps the source white too: for proofing a paper colour)."
|
|
10091
|
+
};
|
|
10092
|
+
function profileArg(v) {
|
|
10093
|
+
const s = String(v);
|
|
10094
|
+
if (s.startsWith("icc:")) {
|
|
10095
|
+
try {
|
|
10096
|
+
return base64ToBytes(s.slice(4));
|
|
10097
|
+
} catch {
|
|
10098
|
+
throw new LayerOperationError("The icc: value is not valid base64.");
|
|
10099
|
+
}
|
|
10100
|
+
}
|
|
10101
|
+
return s;
|
|
10102
|
+
}
|
|
10103
|
+
function createImageColorTools(controller) {
|
|
10104
|
+
const getProfile = {
|
|
10105
|
+
name: "get_color_profile",
|
|
10106
|
+
title: "Get the colour profile",
|
|
10107
|
+
description: "Reads the document's colour profile (its working space: name, builtin id or null for an embedded profile, colorSpace, srgb true when it means sRGB), the Proof Setup (profile, intent, bpc, simulatePaper, gamutWarning, or null) and the built-in profiles you can assign, convert to or proof with ({id, description, colorSpace}).",
|
|
10108
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
10109
|
+
annotations: { title: "Get the colour profile", ...READ5 },
|
|
10110
|
+
handler: () => {
|
|
10111
|
+
const proof2 = controller.getState().proofSetup;
|
|
10112
|
+
return {
|
|
10113
|
+
profile: controller.getColorProfile(),
|
|
10114
|
+
proof: proof2 ? { profile: proof2.profile.name, builtin: proof2.profile.builtin ?? null, intent: proof2.intent, bpc: proof2.bpc, simulatePaper: proof2.simulatePaper, gamutWarning: proof2.gamutWarning } : null,
|
|
10115
|
+
builtins: BUILTIN_PROFILES.map((b) => ({ ...b }))
|
|
10116
|
+
};
|
|
10117
|
+
}
|
|
10118
|
+
};
|
|
10119
|
+
const assign = {
|
|
10120
|
+
name: "assign_profile",
|
|
10121
|
+
title: "Assign a colour profile",
|
|
10122
|
+
description: "Edit \u203A Assign Profile: the document's RGB numbers now mean colours in `profile`; no pixel changes, so the image looks different unless the profiles match. Use it when a file was saved without its profile, or with the wrong one. To keep the look and change the numbers, use convert_to_profile. RGB profiles only. One undo step. Returns the new profile.",
|
|
10123
|
+
inputSchema: { type: "object", properties: { profile: PROFILE }, required: ["profile"], additionalProperties: false },
|
|
10124
|
+
annotations: { title: "Assign a colour profile", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10125
|
+
handler: (args) => controller.assignProfile(profileArg(args.profile))
|
|
10126
|
+
};
|
|
10127
|
+
const convert = {
|
|
10128
|
+
name: "convert_to_profile",
|
|
10129
|
+
title: "Convert to a colour profile",
|
|
10130
|
+
description: "Edit \u203A Convert to Profile: converts every pixel layer's numbers so its colours stay the same in `profile`, then makes `profile` the document's. Colours outside the new space are mapped by `intent`. Shape and type layers, layer effects and smart objects keep their numbers and are listed in unconvertedLayerIds. RGB profiles only (proof CMYK with set_proof_setup). One undo step. Returns the profile, convertedLayerIds and unconvertedLayerIds.",
|
|
10131
|
+
inputSchema: {
|
|
10132
|
+
type: "object",
|
|
10133
|
+
properties: {
|
|
10134
|
+
profile: PROFILE,
|
|
10135
|
+
intent: INTENT,
|
|
10136
|
+
bpc: { type: "boolean", description: "Black point compensation: map black to black (default true)." }
|
|
10137
|
+
},
|
|
10138
|
+
required: ["profile"],
|
|
10139
|
+
additionalProperties: false
|
|
10140
|
+
},
|
|
10141
|
+
annotations: { title: "Convert to a colour profile", readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
10142
|
+
handler: (args) => controller.convertToProfile(profileArg(args.profile), { intent: args.intent, bpc: args.bpc })
|
|
10143
|
+
};
|
|
10144
|
+
const proof = {
|
|
10145
|
+
name: "set_proof_setup",
|
|
10146
|
+
title: "Set up soft proofing",
|
|
10147
|
+
description: "View \u203A Proof Setup: shows the document in the viewport as `profile` would reproduce it (for example coated-cmyk for a press), with `intent`; `simulatePaper` shows the paper white and ink black; `gamutWarning` greys out colours the profile cannot reproduce. Pass off true to stop proofing. View state, not an undo step; pixels never change. Check the result with capture_view. Returns the setup (or null).",
|
|
10148
|
+
inputSchema: {
|
|
10149
|
+
type: "object",
|
|
10150
|
+
properties: {
|
|
10151
|
+
profile: PROFILE,
|
|
10152
|
+
intent: INTENT,
|
|
10153
|
+
bpc: { type: "boolean", description: "Black point compensation (default true)." },
|
|
10154
|
+
simulatePaper: { type: "boolean", description: "Simulate paper colour and black ink (default false)." },
|
|
10155
|
+
gamutWarning: { type: "boolean", description: "Grey out out-of-gamut colours (default false)." },
|
|
10156
|
+
off: { type: "boolean", description: "Turn proofing off instead (default false)." }
|
|
10157
|
+
},
|
|
10158
|
+
additionalProperties: false
|
|
10159
|
+
},
|
|
10160
|
+
annotations: { title: "Set up soft proofing", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10161
|
+
handler: (args) => {
|
|
10162
|
+
if (args.off === true) {
|
|
10163
|
+
if (args.profile !== void 0) throw new LayerOperationError("Give either off true or a profile, not both.");
|
|
10164
|
+
return controller.setProofSetup(null);
|
|
10165
|
+
}
|
|
10166
|
+
if (args.profile === void 0) throw new LayerOperationError("Pass the profile to proof with (e.g. coated-cmyk), or off true.");
|
|
10167
|
+
const s = controller.setProofSetup({
|
|
10168
|
+
profile: profileArg(args.profile),
|
|
10169
|
+
...args.intent !== void 0 ? { intent: args.intent } : {},
|
|
10170
|
+
...args.bpc !== void 0 ? { bpc: args.bpc } : {},
|
|
10171
|
+
...args.simulatePaper !== void 0 ? { simulatePaper: args.simulatePaper } : {},
|
|
10172
|
+
...args.gamutWarning !== void 0 ? { gamutWarning: args.gamutWarning } : {}
|
|
10173
|
+
});
|
|
10174
|
+
return { profile: s.profile.name, builtin: s.profile.builtin ?? null, intent: s.intent, bpc: s.bpc, simulatePaper: s.simulatePaper, gamutWarning: s.gamutWarning };
|
|
10175
|
+
}
|
|
10176
|
+
};
|
|
10177
|
+
const convertColors = {
|
|
10178
|
+
name: "convert_colors",
|
|
10179
|
+
title: "Convert colours between profiles",
|
|
10180
|
+
description: 'Converts 1 to 64 #rrggbb colours from the document\'s profile (or `from`) into `to` with `intent`: returns per colour the channel values 0..1 (RGB, CMYK, grey; Lab as L/100, (a+128)/255, (b+128)/255), a hex for RGB targets, and L*a*b* (D50). Use it to answer "what are these CMYK values" or to pick colours that survive printing. Changes nothing.',
|
|
10181
|
+
inputSchema: {
|
|
10182
|
+
type: "object",
|
|
10183
|
+
properties: {
|
|
10184
|
+
colors: { type: "array", minItems: 1, maxItems: 64, items: { type: "string", description: "A colour #rrggbb." }, description: "Colours in the source profile." },
|
|
10185
|
+
to: PROFILE,
|
|
10186
|
+
from: { ...PROFILE, description: `Source profile (default the document's). ${PROFILE.description}` },
|
|
10187
|
+
intent: INTENT,
|
|
10188
|
+
bpc: { type: "boolean", description: "Black point compensation (default true)." }
|
|
10189
|
+
},
|
|
10190
|
+
required: ["colors", "to"],
|
|
10191
|
+
additionalProperties: false
|
|
10192
|
+
},
|
|
10193
|
+
annotations: { title: "Convert colours between profiles", ...READ5 },
|
|
10194
|
+
handler: (args) => ({
|
|
10195
|
+
colors: controller.convertColors(args.colors, profileArg(args.to), {
|
|
10196
|
+
...args.from !== void 0 ? { from: profileArg(args.from) } : {},
|
|
10197
|
+
intent: args.intent,
|
|
10198
|
+
bpc: args.bpc
|
|
10199
|
+
})
|
|
10200
|
+
})
|
|
10201
|
+
};
|
|
10202
|
+
return [getProfile, assign, convert, proof, convertColors];
|
|
10203
|
+
}
|
|
10204
|
+
|
|
10205
|
+
// src/image-editor/retouch-tools.ts
|
|
10206
|
+
var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
9780
10207
|
var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
9781
10208
|
var POINTS = {
|
|
9782
10209
|
type: "array",
|
|
@@ -9980,7 +10407,7 @@ function createImageRetouchTools(controller) {
|
|
|
9980
10407
|
title: "Get retouch options",
|
|
9981
10408
|
description: "Reads the retouching tools' options (aligned, sample, spotType, range, exposure, protectTones, spongeMode, vibrance, strength) and the clone source ({x, y, offset} or null; offset is the aligned offset the last clone or heal stroke fixed). Call it before clone_stamp or heal_brush without a source to see where they will sample.",
|
|
9982
10409
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
9983
|
-
annotations: { title: "Get retouch options", ...
|
|
10410
|
+
annotations: { title: "Get retouch options", ...READ6 },
|
|
9984
10411
|
handler: () => {
|
|
9985
10412
|
const { retouch, cloneSource } = controller.getState().paint;
|
|
9986
10413
|
return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null };
|
|
@@ -10040,7 +10467,7 @@ function pick(args, keys) {
|
|
|
10040
10467
|
}
|
|
10041
10468
|
|
|
10042
10469
|
// src/image-editor/psd-tools.ts
|
|
10043
|
-
var
|
|
10470
|
+
var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10044
10471
|
var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
10045
10472
|
var DATA = {
|
|
10046
10473
|
type: "string",
|
|
@@ -10061,7 +10488,7 @@ function createImagePsdTools(controller) {
|
|
|
10061
10488
|
title: "Inspect a PSD",
|
|
10062
10489
|
description: "Reads a PSD / PSB without opening it: size, bit depth, colour mode, resolution, and every layer (bottom first, a group before its children) with its PSD kind, the layer type it would become and its status (mapped, approximated or dropped, with notes), plus the import warnings. Changes nothing. Call before import_psd to see what would be lost.",
|
|
10063
10490
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
10064
|
-
annotations: { title: "Inspect a PSD", ...
|
|
10491
|
+
annotations: { title: "Inspect a PSD", ...READ7 },
|
|
10065
10492
|
handler: ({ data }) => {
|
|
10066
10493
|
const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
|
|
10067
10494
|
return {
|
|
@@ -10096,9 +10523,9 @@ function createImagePsdTools(controller) {
|
|
|
10096
10523
|
const save = {
|
|
10097
10524
|
name: "export_psd",
|
|
10098
10525
|
title: "Export the document as a PSD",
|
|
10099
|
-
description: "Writes the document as an
|
|
10526
|
+
description: "Writes the document as an RGB PSD at its bit depth (8, 16 or 32; see set_bit_depth; a PSB above 30000 px) with real layers, groups, adjustment layers, masks and layer effects (an effects block opened from a PSD is written back unchanged while its effects are; the patterns effects use are embedded), in the source frame (crop and rotation are not applied). Smart objects are written as Photoshop smart objects (contents embedded once per linked set, placement, warp, smart filters and filter mask; a Develop smart filter has no Photoshop filter and is left out of the list). Shape layers are written as Photoshop shape layers (path, fill, stroke, live shapes) and type layers as Photoshop type layers (text, runs, paragraphs, frame; blocks opened from a PSD are written back unchanged while the layer is). Layer filters and depth masks are baked, annotation layers are rasterized (in a browser; elsewhere left out), and the merged image is the editor's composite. Changes nothing. Returns the file as base64, its size in bytes, whether it is a PSB, and warnings for everything that was changed or left out.",
|
|
10100
10527
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
10101
|
-
annotations: { title: "Export the document as a PSD", ...
|
|
10528
|
+
annotations: { title: "Export the document as a PSD", ...READ7 },
|
|
10102
10529
|
handler: async () => {
|
|
10103
10530
|
const res = await controller.toPsd();
|
|
10104
10531
|
return {
|
|
@@ -10116,7 +10543,7 @@ function createImagePsdTools(controller) {
|
|
|
10116
10543
|
}
|
|
10117
10544
|
|
|
10118
10545
|
// src/image-editor/transform-tools.ts
|
|
10119
|
-
var
|
|
10546
|
+
var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10120
10547
|
var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10121
10548
|
var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
10122
10549
|
var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
|
|
@@ -10216,7 +10643,7 @@ function createImageTransformTools(controller) {
|
|
|
10216
10643
|
},
|
|
10217
10644
|
additionalProperties: false
|
|
10218
10645
|
},
|
|
10219
|
-
annotations: { title: "Get the Free Transform frame", ...
|
|
10646
|
+
annotations: { title: "Get the Free Transform frame", ...READ8 },
|
|
10220
10647
|
handler: (args) => {
|
|
10221
10648
|
const init = targetFrom(args);
|
|
10222
10649
|
if (init.content === "selection-copy") init.content = "selection";
|
|
@@ -10359,7 +10786,7 @@ function createImageTransformTools(controller) {
|
|
|
10359
10786
|
}
|
|
10360
10787
|
|
|
10361
10788
|
// src/image-editor/smart-tools.ts
|
|
10362
|
-
var
|
|
10789
|
+
var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10363
10790
|
var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10364
10791
|
var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10365
10792
|
var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -10418,7 +10845,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10418
10845
|
title: "Read a smart object",
|
|
10419
10846
|
description: "Returns a smart object\u2019s contents (id shared by linked instances, name, kind raster or document, pixel size, the file type it came from, the instances placed from it), its placement (corners in document pixels, warp mesh in contents pixels, interpolation, and scale / rotate / skew in percent and degrees of the contents\u2019 own size when affine), its smart filters bottom to top (ids, kind, settings, enabled, blend, opacity; kind psd marks a Photoshop filter kept but not drawn) with the filter mask, and the rendered bounds. Changes nothing.",
|
|
10420
10847
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
10421
|
-
annotations: { title: "Read a smart object", ...
|
|
10848
|
+
annotations: { title: "Read a smart object", ...READ9 },
|
|
10422
10849
|
handler: ({ layerId }) => info(smartId(layerId))
|
|
10423
10850
|
};
|
|
10424
10851
|
const convert = {
|
|
@@ -10552,7 +10979,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10552
10979
|
title: "Export a smart object\u2019s contents",
|
|
10553
10980
|
description: "Layer \u203A Smart Objects \u203A Export Contents: the contents as a file, base64: the file they came from while unedited (a PSB, PNG, JPEG\u2026), else a PNG for raster contents or a PSD / PSB of a nested document. Returns name, mimeType, byteLength and base64. Changes nothing.",
|
|
10554
10981
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
10555
|
-
annotations: { title: "Export a smart object\u2019s contents", ...
|
|
10982
|
+
annotations: { title: "Export a smart object\u2019s contents", ...READ9 },
|
|
10556
10983
|
handler: ({ layerId }) => {
|
|
10557
10984
|
const f = controller.exportSmartObjectContents(smartId(layerId));
|
|
10558
10985
|
return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
|
|
@@ -10719,7 +11146,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10719
11146
|
}
|
|
10720
11147
|
|
|
10721
11148
|
// src/image-editor/shape-tools.ts
|
|
10722
|
-
var
|
|
11149
|
+
var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10723
11150
|
var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10724
11151
|
var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10725
11152
|
var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -10973,7 +11400,7 @@ function createImageShapeTools(controller) {
|
|
|
10973
11400
|
title: "Read a shape layer",
|
|
10974
11401
|
description: "Returns a shape layer\u2019s components bottom to top (index, path operation, the live shape it was drawn as or null, its subpaths with absolute anchors and handles, bounds), the fill rule, fill and stroke paints and settings, the path bounds and the rendered bounds (stroke included). Changes nothing.",
|
|
10975
11402
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
10976
|
-
annotations: { title: "Read a shape layer", ...
|
|
11403
|
+
annotations: { title: "Read a shape layer", ...READ10 },
|
|
10977
11404
|
handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
|
|
10978
11405
|
};
|
|
10979
11406
|
const add2 = {
|
|
@@ -11122,7 +11549,7 @@ function createImageShapeTools(controller) {
|
|
|
11122
11549
|
}
|
|
11123
11550
|
|
|
11124
11551
|
// src/image-editor/type-tools.ts
|
|
11125
|
-
var
|
|
11552
|
+
var READ11 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
11126
11553
|
var WRITE9 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
11127
11554
|
var WRITE_IDEMPOTENT6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
11128
11555
|
var DESTRUCTIVE7 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -11173,7 +11600,7 @@ function createImageTypeTools(controller) {
|
|
|
11173
11600
|
title: "List fonts",
|
|
11174
11601
|
description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
|
|
11175
11602
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
11176
|
-
annotations: { title: "List fonts", ...
|
|
11603
|
+
annotations: { title: "List fonts", ...READ11 },
|
|
11177
11604
|
handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
|
|
11178
11605
|
};
|
|
11179
11606
|
const get = {
|
|
@@ -11181,7 +11608,7 @@ function createImageTypeTools(controller) {
|
|
|
11181
11608
|
title: "Read a type layer",
|
|
11182
11609
|
description: "Returns a type layer\u2019s text, its character runs and paragraphs as [start, end) ranges in UTF-16 code units with their styles, the frame (point text, or a paragraph box with its size), the text-to-document transform, the laid-out lines (range, baseline, width), the rendered bounds, missing fonts and whether the pixels are live or stored from a file. Call before editing text you did not write, to get the ranges. Changes nothing.",
|
|
11183
11610
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID6 }, required: ["layerId"], additionalProperties: false },
|
|
11184
|
-
annotations: { title: "Read a type layer", ...
|
|
11611
|
+
annotations: { title: "Read a type layer", ...READ11 },
|
|
11185
11612
|
handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
|
|
11186
11613
|
};
|
|
11187
11614
|
const add2 = {
|
|
@@ -11534,6 +11961,7 @@ function createImageEditorToolProvider(controller, options = {}) {
|
|
|
11534
11961
|
...createImageTypeTools(controller),
|
|
11535
11962
|
...createImageEffectTools(controller),
|
|
11536
11963
|
...createImagePaintTools(controller),
|
|
11964
|
+
...createImageColorTools(controller),
|
|
11537
11965
|
...createImageRetouchTools(controller),
|
|
11538
11966
|
...createPigmentTools(),
|
|
11539
11967
|
...createImagePsdTools(controller)
|
|
@@ -12529,6 +12957,11 @@ function extractNormalizedLayerItems(controller, fallbackImageUrl = "") {
|
|
|
12529
12957
|
};
|
|
12530
12958
|
});
|
|
12531
12959
|
}
|
|
12960
|
+
var BIT_DEPTH_OPTIONS = [
|
|
12961
|
+
{ depth: 8, label: "8-bit", title: "8 bits per channel" },
|
|
12962
|
+
{ depth: 16, label: "16-bit", title: "16 bits per channel: smooth gradients, no banding under strong adjustments" },
|
|
12963
|
+
{ depth: 32, label: "32-bit", title: "32-bit float per channel, linear light (HDR)" }
|
|
12964
|
+
];
|
|
12532
12965
|
|
|
12533
12966
|
// src/image-editor/layers/effects-ui.ts
|
|
12534
12967
|
function layerEffectsPanel(layer) {
|
|
@@ -12703,6 +13136,25 @@ function effectControlChange(effect, key, value, patterns = []) {
|
|
|
12703
13136
|
return { [top]: setPath(getPath(effect, top), rest, value) };
|
|
12704
13137
|
}
|
|
12705
13138
|
|
|
13139
|
+
// src/image-editor/layers/color-ui.ts
|
|
13140
|
+
var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
|
|
13141
|
+
var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
|
|
13142
|
+
var INTENT_OPTIONS = [
|
|
13143
|
+
{ id: "relative", label: "Relative Colorimetric", title: "Keep in-gamut colours exact, clip the rest (photos)" },
|
|
13144
|
+
{ id: "perceptual", label: "Perceptual", title: "Compress the whole gamut smoothly" },
|
|
13145
|
+
{ id: "saturation", label: "Saturation", title: "Keep colours vivid (graphics)" },
|
|
13146
|
+
{ id: "absolute", label: "Absolute Colorimetric", title: "Keep the source white too (paper proofs)" }
|
|
13147
|
+
];
|
|
13148
|
+
function colorPanelView(controller) {
|
|
13149
|
+
const profile = controller.getColorProfile();
|
|
13150
|
+
const proof = controller.getState().proofSetup ?? null;
|
|
13151
|
+
return {
|
|
13152
|
+
profileName: profile.name,
|
|
13153
|
+
workingSpace: profile.builtin,
|
|
13154
|
+
proof: proof ? { id: proof.profile.builtin ?? null, name: proof.profile.name, intent: proof.intent, simulatePaper: proof.simulatePaper, gamutWarning: proof.gamutWarning, bpc: proof.bpc } : null
|
|
13155
|
+
};
|
|
13156
|
+
}
|
|
13157
|
+
|
|
12706
13158
|
// src/image-editor/psd/ui.ts
|
|
12707
13159
|
var PSD_FILE_ACCEPT = ".psd,.psb,image/vnd.adobe.photoshop,application/x-photoshop";
|
|
12708
13160
|
function blobBytes(file) {
|
|
@@ -13315,9 +13767,12 @@ export {
|
|
|
13315
13767
|
AS_SHOT_KELVIN,
|
|
13316
13768
|
BACKGROUND_LAYER_ID,
|
|
13317
13769
|
BACKGROUND_LAYER_NAME,
|
|
13770
|
+
BIT_DEPTHS,
|
|
13771
|
+
BIT_DEPTH_OPTIONS,
|
|
13318
13772
|
BLEND_MODES,
|
|
13319
13773
|
BLUR_FILTER_ID,
|
|
13320
13774
|
BRUSH_OPTION_CONTROLS,
|
|
13775
|
+
BUILTIN_PROFILES,
|
|
13321
13776
|
CoverageMap,
|
|
13322
13777
|
D50,
|
|
13323
13778
|
D65,
|
|
@@ -13329,6 +13784,7 @@ export {
|
|
|
13329
13784
|
DEFAULT_GLOBAL_LIGHT,
|
|
13330
13785
|
DEFAULT_MITER_LIMIT,
|
|
13331
13786
|
DEFAULT_MIXER,
|
|
13787
|
+
DEFAULT_PROOF,
|
|
13332
13788
|
DEFAULT_REFINE_EDGE_PARAMS,
|
|
13333
13789
|
DEFAULT_RETOUCH,
|
|
13334
13790
|
DEFAULT_SELECTION_TOOL_OPTIONS,
|
|
@@ -13358,6 +13814,8 @@ export {
|
|
|
13358
13814
|
IMAGE_EDITOR_SCHEMA_VERSION,
|
|
13359
13815
|
IMAGE_EDITOR_STATE_VERSION,
|
|
13360
13816
|
IMAGE_FILTER_PRESETS,
|
|
13817
|
+
INTENTS,
|
|
13818
|
+
INTENT_OPTIONS,
|
|
13361
13819
|
INTERPOLATIONS,
|
|
13362
13820
|
ImageEditorController,
|
|
13363
13821
|
ImageEditorRenderer,
|
|
@@ -13391,6 +13849,7 @@ export {
|
|
|
13391
13849
|
PIGMENT_LAMBDA_MIN,
|
|
13392
13850
|
PIGMENT_LAMBDA_STEP,
|
|
13393
13851
|
PIGMENT_WAVELENGTHS,
|
|
13852
|
+
PROOF_PROFILE_OPTIONS,
|
|
13394
13853
|
PSD_BLEND_KEYS,
|
|
13395
13854
|
PSD_FILE_ACCEPT,
|
|
13396
13855
|
PaintExchange,
|
|
@@ -13444,6 +13903,7 @@ export {
|
|
|
13444
13903
|
WARP_STYLES,
|
|
13445
13904
|
WARP_STYLE_LABELS,
|
|
13446
13905
|
WARP_STYLE_OPTIONS,
|
|
13906
|
+
WORKING_SPACE_OPTIONS,
|
|
13447
13907
|
XYZ_D50_TO_SRGB,
|
|
13448
13908
|
ZlibError,
|
|
13449
13909
|
activeAdjustmentLayers,
|
|
@@ -13465,6 +13925,7 @@ export {
|
|
|
13465
13925
|
annotationOfShape,
|
|
13466
13926
|
annotationOfType,
|
|
13467
13927
|
applyAdjustmentLayers,
|
|
13928
|
+
applyAdjustmentLayersFloat,
|
|
13468
13929
|
applyAdjustments,
|
|
13469
13930
|
applyBoxBlur,
|
|
13470
13931
|
applyDepthMask,
|
|
@@ -13517,10 +13978,12 @@ export {
|
|
|
13517
13978
|
cloneSourceLabel,
|
|
13518
13979
|
collectTiles,
|
|
13519
13980
|
colorBalanceChannel,
|
|
13981
|
+
colorPanelView,
|
|
13520
13982
|
colorRange,
|
|
13521
13983
|
combineSelections,
|
|
13522
13984
|
compileAdjustmentLayer,
|
|
13523
13985
|
componentPath,
|
|
13986
|
+
compositeDeep,
|
|
13524
13987
|
compositeSurfaceOver,
|
|
13525
13988
|
computeHistogram,
|
|
13526
13989
|
computeSelectionBounds,
|
|
@@ -13530,6 +13993,9 @@ export {
|
|
|
13530
13993
|
contractCoverage,
|
|
13531
13994
|
controlPosition,
|
|
13532
13995
|
controlTrackBackground,
|
|
13996
|
+
convertHex,
|
|
13997
|
+
convertSurfaceColors,
|
|
13998
|
+
convertSurfaceDepth,
|
|
13533
13999
|
convertToSmartObject,
|
|
13534
14000
|
copySmartObject,
|
|
13535
14001
|
cornersFromMatrix,
|
|
@@ -13540,6 +14006,7 @@ export {
|
|
|
13540
14006
|
createBlenderScratch,
|
|
13541
14007
|
createCanvasTextShaper,
|
|
13542
14008
|
createImageCaptureSurface,
|
|
14009
|
+
createImageColorTools,
|
|
13543
14010
|
createImageEditTools,
|
|
13544
14011
|
createImageEditorToolProvider,
|
|
13545
14012
|
createImageEffectTools,
|
|
@@ -13552,6 +14019,7 @@ export {
|
|
|
13552
14019
|
createImageSmartObjectTools,
|
|
13553
14020
|
createImageTransformTools,
|
|
13554
14021
|
createImageTypeTools,
|
|
14022
|
+
createMetricTextShaper,
|
|
13555
14023
|
createOutlineTextShaper,
|
|
13556
14024
|
createPigment,
|
|
13557
14025
|
createPigmentTools,
|
|
@@ -13566,6 +14034,7 @@ export {
|
|
|
13566
14034
|
curveSvgPath,
|
|
13567
14035
|
dabCoverage,
|
|
13568
14036
|
dabRect,
|
|
14037
|
+
decodeDeepSurface,
|
|
13569
14038
|
decodeLayerChannel,
|
|
13570
14039
|
decodeLayerMask,
|
|
13571
14040
|
decodeMergedImage,
|
|
@@ -13573,6 +14042,8 @@ export {
|
|
|
13573
14042
|
decodePng,
|
|
13574
14043
|
decodePngDataUrl,
|
|
13575
14044
|
decodeSelectionRle,
|
|
14045
|
+
deepBytes,
|
|
14046
|
+
deepTile,
|
|
13576
14047
|
defaultAdjustmentParams,
|
|
13577
14048
|
defaultEffectGradient,
|
|
13578
14049
|
defaultLayerEffect,
|
|
@@ -13580,11 +14051,13 @@ export {
|
|
|
13580
14051
|
deflate,
|
|
13581
14052
|
deflateRaw,
|
|
13582
14053
|
depthMaskAlpha,
|
|
14054
|
+
depthOf,
|
|
13583
14055
|
depthRasterMask,
|
|
13584
14056
|
describeLayer,
|
|
13585
14057
|
describeLayerEffects,
|
|
13586
14058
|
describeSelection,
|
|
13587
14059
|
describeTransform,
|
|
14060
|
+
deserializeColorProfile,
|
|
13588
14061
|
deserializeEffects,
|
|
13589
14062
|
deserializeLayer,
|
|
13590
14063
|
deserializeLayers,
|
|
@@ -13594,8 +14067,10 @@ export {
|
|
|
13594
14067
|
developFromAdjustments,
|
|
13595
14068
|
developTarget,
|
|
13596
14069
|
dilateMask,
|
|
14070
|
+
displayTransform,
|
|
13597
14071
|
distanceTransform,
|
|
13598
14072
|
documentContents,
|
|
14073
|
+
documentProfile,
|
|
13599
14074
|
dodgeBurn,
|
|
13600
14075
|
dodgeBurnCurve,
|
|
13601
14076
|
downloadPsd,
|
|
@@ -13614,6 +14089,7 @@ export {
|
|
|
13614
14089
|
ellipseSelection,
|
|
13615
14090
|
emptyHistogram,
|
|
13616
14091
|
emptySurface,
|
|
14092
|
+
encodeDeepSurface,
|
|
13617
14093
|
encodePng,
|
|
13618
14094
|
encodeRle,
|
|
13619
14095
|
encodeSelectionRle,
|
|
@@ -13689,6 +14165,7 @@ export {
|
|
|
13689
14165
|
invertSelection,
|
|
13690
14166
|
isActiveFilter,
|
|
13691
14167
|
isAdjustmentKind,
|
|
14168
|
+
isBitDepth,
|
|
13692
14169
|
isBlendMode,
|
|
13693
14170
|
isContentsDecoded,
|
|
13694
14171
|
isDefaultDepthMask,
|
|
@@ -13709,6 +14186,7 @@ export {
|
|
|
13709
14186
|
isSelectionMode,
|
|
13710
14187
|
isSeparableBlendMode,
|
|
13711
14188
|
isSpatialFilter,
|
|
14189
|
+
isSrgb,
|
|
13712
14190
|
isTransformAnchor,
|
|
13713
14191
|
isValidWarp,
|
|
13714
14192
|
kelvinToTemperature,
|
|
@@ -13746,6 +14224,7 @@ export {
|
|
|
13746
14224
|
liveShapeSubpaths,
|
|
13747
14225
|
loadImageEditorDocument,
|
|
13748
14226
|
loadMixer,
|
|
14227
|
+
loadOpenTypeFont,
|
|
13749
14228
|
luma,
|
|
13750
14229
|
magicWand,
|
|
13751
14230
|
mapCropHandle,
|
|
@@ -13812,6 +14291,7 @@ export {
|
|
|
13812
14291
|
parseEffectColor,
|
|
13813
14292
|
parseLfx2,
|
|
13814
14293
|
parseLrfx,
|
|
14294
|
+
parseOpenTypeFont,
|
|
13815
14295
|
parsePatternBlock,
|
|
13816
14296
|
parseSelectionMode,
|
|
13817
14297
|
parseVersionedDescriptor,
|
|
@@ -13834,10 +14314,12 @@ export {
|
|
|
13834
14314
|
posterizeValue,
|
|
13835
14315
|
presetWarp,
|
|
13836
14316
|
previewStep,
|
|
14317
|
+
profileBytes,
|
|
13837
14318
|
projectImagePoint,
|
|
13838
14319
|
projectImageRect,
|
|
13839
14320
|
projectMaskCoverage,
|
|
13840
14321
|
projectQuarterTurn,
|
|
14322
|
+
proxyOf,
|
|
13841
14323
|
psdBytesFromBase64,
|
|
13842
14324
|
psdFileName,
|
|
13843
14325
|
psdPatternToEffectPattern,
|
|
@@ -13851,6 +14333,7 @@ export {
|
|
|
13851
14333
|
rasterizeDab,
|
|
13852
14334
|
rasterizeSmartObject,
|
|
13853
14335
|
readAdjustmentControls,
|
|
14336
|
+
readDeepRegion,
|
|
13854
14337
|
readPixel,
|
|
13855
14338
|
readPsd,
|
|
13856
14339
|
readRegion,
|
|
@@ -13891,6 +14374,7 @@ export {
|
|
|
13891
14374
|
resizeWarpMesh,
|
|
13892
14375
|
resolveExternalAssets,
|
|
13893
14376
|
resolveMosaicRegionBounds,
|
|
14377
|
+
resolveProfile,
|
|
13894
14378
|
restyleRange,
|
|
13895
14379
|
rgbToGray,
|
|
13896
14380
|
rgbToHsl,
|
|
@@ -13912,6 +14396,7 @@ export {
|
|
|
13912
14396
|
selectionToCoverage,
|
|
13913
14397
|
selectionToPixels,
|
|
13914
14398
|
selectionValueAt,
|
|
14399
|
+
serializeColorProfile,
|
|
13915
14400
|
serializeContents,
|
|
13916
14401
|
serializeEffects,
|
|
13917
14402
|
serializeLayer,
|
|
@@ -13951,11 +14436,15 @@ export {
|
|
|
13951
14436
|
spotHealPixels,
|
|
13952
14437
|
spotHealWindow,
|
|
13953
14438
|
srgb8ToLab,
|
|
14439
|
+
srgbDecode,
|
|
14440
|
+
srgbEncode,
|
|
13954
14441
|
srgbToLinear,
|
|
13955
14442
|
standardBlendMode,
|
|
13956
14443
|
styleAt,
|
|
13957
14444
|
sumHistograms,
|
|
13958
14445
|
surfaceBytes,
|
|
14446
|
+
surfaceDepth,
|
|
14447
|
+
surfaceFromDeepPixels,
|
|
13959
14448
|
surfaceFromPixels,
|
|
13960
14449
|
surfacesEqual,
|
|
13961
14450
|
tempTintToXy,
|
|
@@ -13967,10 +14456,19 @@ export {
|
|
|
13967
14456
|
tileCoord,
|
|
13968
14457
|
tileKey,
|
|
13969
14458
|
tileRect,
|
|
14459
|
+
tileSamples,
|
|
14460
|
+
tileSamples16,
|
|
14461
|
+
tileSamples32,
|
|
13970
14462
|
tilesInRect,
|
|
13971
14463
|
tipFalloff,
|
|
13972
14464
|
tipReach,
|
|
13973
14465
|
tipShape,
|
|
14466
|
+
to16From32,
|
|
14467
|
+
to16From8,
|
|
14468
|
+
to32From16,
|
|
14469
|
+
to32From8,
|
|
14470
|
+
to8From16,
|
|
14471
|
+
to8From32,
|
|
13974
14472
|
toHex,
|
|
13975
14473
|
toTextSpace,
|
|
13976
14474
|
toneCurve,
|
|
@@ -14020,6 +14518,7 @@ export {
|
|
|
14020
14518
|
withFilterMaskSurface,
|
|
14021
14519
|
withNewIds,
|
|
14022
14520
|
writeAdjustmentBlock,
|
|
14521
|
+
writeDeepRegion,
|
|
14023
14522
|
writeLfx2,
|
|
14024
14523
|
writePatternBlock,
|
|
14025
14524
|
writePsd,
|