@pixerate/editor 0.113.0 → 0.115.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 +8 -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-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-G5NMLUVF.cjs +2574 -0
- package/dist/chunk-G5NMLUVF.cjs.map +1 -0
- package/dist/{chunk-YGIMK4NX.cjs → chunk-I7FQBWMQ.cjs} +813 -842
- package/dist/chunk-I7FQBWMQ.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-CZOXTEMN.js → chunk-XICA4PVO.js} +392 -421
- package/dist/chunk-XICA4PVO.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-CEXEzqBf.d.cts → export-BJE8T0YA.d.cts} +279 -191
- package/dist/{export-DIkoK8-r.d.ts → export-Con3UKkm.d.ts} +279 -191
- package/dist/image-editor/index.cjs +1848 -1218
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +85 -93
- package/dist/image-editor/index.d.ts +85 -93
- package/dist/image-editor/index.js +871 -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 +147 -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 +7 -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 +9 -2
- package/skills/pixerate-image-editor/SKILL.md +13 -36
- package/skills/pixerate-image-editor/references/color-management.md +42 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +41 -0
- package/skills/pixerate-paint-editor/SKILL.md +136 -4
- package/skills/pixerate-vector/SKILL.md +72 -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-XICA4PVO.js";
|
|
362
|
+
import {
|
|
363
|
+
loadDocument
|
|
364
|
+
} from "../chunk-U5HZSFCS.js";
|
|
403
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";
|
|
570
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";
|
|
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,179 @@ 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
|
+
function serializeColorMode(m) {
|
|
3102
|
+
return m.mode === "cmyk" ? { mode: "cmyk", profile: serializeColorProfile(m.profile), intent: m.intent } : { mode: "lab" };
|
|
3103
|
+
}
|
|
3104
|
+
function deserializeColorMode(raw, problems) {
|
|
3105
|
+
const r = raw;
|
|
3106
|
+
if (!r || typeof r !== "object") return null;
|
|
3107
|
+
if (r.mode === "lab") return { mode: "lab" };
|
|
3108
|
+
if (r.mode !== "cmyk") return null;
|
|
3109
|
+
const profile = r.profile && deserializeColorProfile(r.profile, problems) || documentProfile("coated-cmyk");
|
|
3110
|
+
const intent = ["perceptual", "relative", "saturation", "absolute"].includes(r.intent) ? r.intent : "relative";
|
|
3111
|
+
return { mode: "cmyk", profile, intent };
|
|
3112
|
+
}
|
|
3113
|
+
function effectiveProof(proof, mode) {
|
|
3114
|
+
if (proof) return proof;
|
|
3115
|
+
if (mode?.mode === "cmyk") return { ...DEFAULT_PROOF, profile: mode.profile, intent: mode.intent };
|
|
3116
|
+
return null;
|
|
3117
|
+
}
|
|
3118
|
+
function colorModePlanes(doc, mode) {
|
|
3119
|
+
const src = resolveProfile(doc);
|
|
3120
|
+
if (mode.mode === "cmyk") {
|
|
3121
|
+
const t2 = Transform.create(src, resolveProfile(mode.profile), { intent: mode.intent, bpc: true });
|
|
3122
|
+
return (rgba, n) => {
|
|
3123
|
+
const ink = new Uint8Array(n * 4);
|
|
3124
|
+
t2.convert8(rgba, 4, ink, 4, false);
|
|
3125
|
+
const planes = [0, 1, 2, 3].map(() => new Uint8Array(n));
|
|
3126
|
+
for (let i = 0; i < n; i++) for (let c = 0; c < 4; c++) planes[c][i] = 255 - ink[i * 4 + c];
|
|
3127
|
+
return planes;
|
|
3128
|
+
};
|
|
3129
|
+
}
|
|
3130
|
+
const t = Transform.create(src, builtinProfile("lab-d50"), { intent: "relative", bpc: false });
|
|
3131
|
+
return (rgba, n) => {
|
|
3132
|
+
const lab = new Uint8Array(n * 4);
|
|
3133
|
+
t.convert8(rgba, 4, lab, 4, false);
|
|
3134
|
+
const planes = [0, 1, 2].map(() => new Uint8Array(n));
|
|
3135
|
+
for (let i = 0; i < n; i++) for (let c = 0; c < 3; c++) planes[c][i] = lab[i * 4 + c];
|
|
3136
|
+
return planes;
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
var resolved = /* @__PURE__ */ new WeakMap();
|
|
3140
|
+
var fromBytes = /* @__PURE__ */ new Map();
|
|
3141
|
+
function resolveProfile(doc) {
|
|
3142
|
+
if (!doc) return srgbProfile();
|
|
3143
|
+
const hit = resolved.get(doc);
|
|
3144
|
+
if (hit) return hit;
|
|
3145
|
+
let p;
|
|
3146
|
+
if (doc.builtin) p = builtinProfile(doc.builtin);
|
|
3147
|
+
else if (doc.icc) {
|
|
3148
|
+
const key = bytesToBase64(doc.icc);
|
|
3149
|
+
p = fromBytes.get(key) ?? parseProfile(doc.icc);
|
|
3150
|
+
if (fromBytes.size > 32) fromBytes.clear();
|
|
3151
|
+
fromBytes.set(key, p);
|
|
3152
|
+
} else p = srgbProfile();
|
|
3153
|
+
resolved.set(doc, p);
|
|
3154
|
+
return p;
|
|
3155
|
+
}
|
|
3156
|
+
function profileBytes(doc) {
|
|
3157
|
+
if (doc?.icc) return doc.icc;
|
|
3158
|
+
const p = resolveProfile(doc);
|
|
3159
|
+
return p.bytes ?? encodeProfile(p);
|
|
3160
|
+
}
|
|
3161
|
+
function documentProfile(input) {
|
|
3162
|
+
if (typeof input === "string") {
|
|
3163
|
+
const id = builtinProfileId(input);
|
|
3164
|
+
if (!id) throw new CmsError(`Unknown colour profile "${input}"; use one of ${BUILTIN_PROFILES.map((b) => b.id).join(", ")}, or ICC bytes.`);
|
|
3165
|
+
return { builtin: id, name: BUILTIN_PROFILES.find((b) => b.id === id).description };
|
|
3166
|
+
}
|
|
3167
|
+
const p = parseProfile(input);
|
|
3168
|
+
return { name: p.description || "Embedded profile", icc: input.slice() };
|
|
3169
|
+
}
|
|
3170
|
+
function isSrgb(doc) {
|
|
3171
|
+
if (!doc || doc.builtin === "srgb") return true;
|
|
3172
|
+
try {
|
|
3173
|
+
return sameColors(resolveProfile(doc), srgbProfile(), builtinProfile("lab-d50"));
|
|
3174
|
+
} catch {
|
|
3175
|
+
return false;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
function serializeColorProfile(doc) {
|
|
3179
|
+
return doc.builtin ? { builtin: doc.builtin, name: doc.name } : { name: doc.name, icc: bytesToBase64(doc.icc ?? new Uint8Array(0)) };
|
|
3180
|
+
}
|
|
3181
|
+
function deserializeColorProfile(raw, problems) {
|
|
3182
|
+
const r = raw;
|
|
3183
|
+
if (!r || typeof r !== "object") return null;
|
|
3184
|
+
try {
|
|
3185
|
+
if (r.builtin) {
|
|
3186
|
+
const id = builtinProfileId(r.builtin);
|
|
3187
|
+
if (!id) throw new CmsError(`unknown built-in profile "${r.builtin}"`);
|
|
3188
|
+
return documentProfile(id);
|
|
3189
|
+
}
|
|
3190
|
+
if (typeof r.icc === "string") {
|
|
3191
|
+
const icc = base64ToBytes(r.icc);
|
|
3192
|
+
parseProfile(icc);
|
|
3193
|
+
return { name: typeof r.name === "string" ? r.name : "Embedded profile", icc };
|
|
3194
|
+
}
|
|
3195
|
+
} catch (e) {
|
|
3196
|
+
problems.push(`The colour profile could not be read (${e instanceof Error ? e.message : String(e)}); the document is treated as sRGB`);
|
|
3197
|
+
}
|
|
3198
|
+
return null;
|
|
3199
|
+
}
|
|
3200
|
+
function displayTransform(doc, proof) {
|
|
3201
|
+
const src = resolveProfile(doc);
|
|
3202
|
+
const display = srgbProfile();
|
|
3203
|
+
let t = null;
|
|
3204
|
+
let gamut = null;
|
|
3205
|
+
if (proof) {
|
|
3206
|
+
const p = resolveProfile(proof.profile);
|
|
3207
|
+
t = Transform.proof(src, p, display, proof.intent, proof.bpc, proof.simulatePaper);
|
|
3208
|
+
if (proof.gamutWarning) gamut = new GamutCheck(src, p, builtinProfile("lab-d50"));
|
|
3209
|
+
} else if (!isSrgb(doc)) t = Transform.create(src, display, { intent: "relative", bpc: true });
|
|
3210
|
+
if (!t) return null;
|
|
3211
|
+
const tr = t;
|
|
3212
|
+
const g = gamut;
|
|
3213
|
+
return (rgba) => {
|
|
3214
|
+
if (g) {
|
|
3215
|
+
const px2 = [0, 0, 0];
|
|
3216
|
+
const flags = new Uint8Array(rgba.length >> 2);
|
|
3217
|
+
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
|
|
3218
|
+
if (rgba[i + 3] === 0) continue;
|
|
3219
|
+
px2[0] = rgba[i] / 255;
|
|
3220
|
+
px2[1] = rgba[i + 1] / 255;
|
|
3221
|
+
px2[2] = rgba[i + 2] / 255;
|
|
3222
|
+
if (g.outOfGamut(px2)) flags[p] = 1;
|
|
3223
|
+
}
|
|
3224
|
+
tr.convert8(rgba, 4, rgba, 4);
|
|
3225
|
+
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) if (flags[p]) rgba[i] = rgba[i + 1] = rgba[i + 2] = 128;
|
|
3226
|
+
return;
|
|
3227
|
+
}
|
|
3228
|
+
tr.convert8(rgba, 4, rgba, 4);
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
function convertHex(hex, from, to, intent = "relative", bpc = true) {
|
|
3232
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
3233
|
+
if (!m) return hex;
|
|
3234
|
+
const n = parseInt(m[1], 16);
|
|
3235
|
+
const out = new Float32Array(4);
|
|
3236
|
+
Transform.create(from, to, { intent, bpc }).eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], out);
|
|
3237
|
+
const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0");
|
|
3238
|
+
return `#${c(out[0])}${c(out[1])}${c(out[2])}`;
|
|
3239
|
+
}
|
|
3240
|
+
function convertSurfaceColors(surface, t) {
|
|
3241
|
+
if (surface.channels !== 4 || t.inputs !== 3 || t.outputs !== 3) return surface;
|
|
3242
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
3243
|
+
const memo = /* @__PURE__ */ new Map();
|
|
3244
|
+
for (const [key, tile] of surface.tiles) {
|
|
3245
|
+
let next = memo.get(tile);
|
|
3246
|
+
if (next === void 0) {
|
|
3247
|
+
if (tile.deep instanceof Uint16Array) {
|
|
3248
|
+
const out = new Uint16Array(tile.deep.length);
|
|
3249
|
+
t.convert16(tile.deep, 4, out, 4);
|
|
3250
|
+
next = deepTile(out, 4, surface.defaultValue);
|
|
3251
|
+
} else if (tile.deep instanceof Float32Array) {
|
|
3252
|
+
const enc = new Float32Array(tile.deep.length);
|
|
3253
|
+
for (let i = 0; i < enc.length; i += 4) {
|
|
3254
|
+
for (let c = 0; c < 3; c++) enc[i + c] = srgbEncode(tile.deep[i + c]);
|
|
3255
|
+
enc[i + 3] = tile.deep[i + 3];
|
|
3256
|
+
}
|
|
3257
|
+
t.convertFloat(enc, 4, enc, 4);
|
|
3258
|
+
for (let i = 0; i < enc.length; i += 4) for (let c = 0; c < 3; c++) enc[i + c] = srgbDecode(enc[i + c]);
|
|
3259
|
+
next = deepTile(enc, 4, surface.defaultValue);
|
|
3260
|
+
} else {
|
|
3261
|
+
const out = new Uint8ClampedArray(tile.data.length);
|
|
3262
|
+
t.convert8(tile.data, 4, out, 4);
|
|
3263
|
+
next = finishTile(out, 4, surface.defaultValue);
|
|
3264
|
+
}
|
|
3265
|
+
memo.set(tile, next);
|
|
3266
|
+
}
|
|
3267
|
+
if (next) tiles.set(key, next);
|
|
3268
|
+
}
|
|
3269
|
+
return new TiledSurface(4, tiles, surface.defaultValue);
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3184
3272
|
// src/image-editor/controller.ts
|
|
3185
3273
|
var IMAGE_EDITOR_SCHEMA_VERSION = LAYERED_SCHEMA_VERSION;
|
|
3186
3274
|
var RETOUCH_TOOLS = ["clone", "heal", "spot-heal", "smudge", "dodge", "burn", "sponge"];
|
|
@@ -3593,10 +3681,24 @@ var ImageEditorController = class {
|
|
|
3593
3681
|
if (strokeRects && this.pendingDirty !== "all") this.pendingDirty.push(...strokeRects);
|
|
3594
3682
|
else if (!strokeRects) this.pendingDirty = "all";
|
|
3595
3683
|
this.syncViews();
|
|
3684
|
+
this.syncDisplay();
|
|
3596
3685
|
const currentState = { ...this.state };
|
|
3597
3686
|
this.onStateChange?.(currentState);
|
|
3598
3687
|
this.listeners.forEach((l) => l(currentState));
|
|
3599
3688
|
}
|
|
3689
|
+
displayFor = null;
|
|
3690
|
+
/** Keeps the renderer's display transform in step with the document profile, mode and Proof Setup. */
|
|
3691
|
+
syncDisplay() {
|
|
3692
|
+
const s = this.state;
|
|
3693
|
+
const d = this.displayFor;
|
|
3694
|
+
if (d && d[0] === s.colorProfile && d[1] === s.proofSetup && d[2] === s.colorMode) return;
|
|
3695
|
+
this.displayFor = [s.colorProfile, s.proofSetup, s.colorMode];
|
|
3696
|
+
try {
|
|
3697
|
+
this.renderer.setDisplayTransform(displayTransform(s.colorProfile, effectiveProof(s.proofSetup, s.colorMode)));
|
|
3698
|
+
} catch {
|
|
3699
|
+
this.renderer.setDisplayTransform(null);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3600
3702
|
/** Recomputes the compatibility views (`adjustments`, `depthMask`, `annotations`) when the stack changed. */
|
|
3601
3703
|
syncViews() {
|
|
3602
3704
|
const s = this.state;
|
|
@@ -3634,6 +3736,9 @@ var ImageEditorController = class {
|
|
|
3634
3736
|
if (s.legacyOutputBlur !== void 0) entry.legacyOutputBlur = s.legacyOutputBlur;
|
|
3635
3737
|
if (s.globalLight) entry.globalLight = { ...s.globalLight };
|
|
3636
3738
|
if (s.patterns) entry.patterns = s.patterns;
|
|
3739
|
+
if (s.colorProfile) entry.colorProfile = s.colorProfile;
|
|
3740
|
+
if (s.colorMode) entry.colorMode = s.colorMode;
|
|
3741
|
+
if (s.bitDepth && s.bitDepth !== 8) entry.bitDepth = s.bitDepth;
|
|
3637
3742
|
return entry;
|
|
3638
3743
|
}
|
|
3639
3744
|
restoreHistoryEntry(entry) {
|
|
@@ -3650,6 +3755,12 @@ var ImageEditorController = class {
|
|
|
3650
3755
|
else delete s.globalLight;
|
|
3651
3756
|
if (entry.patterns) s.patterns = entry.patterns;
|
|
3652
3757
|
else delete s.patterns;
|
|
3758
|
+
if (entry.bitDepth) s.bitDepth = entry.bitDepth;
|
|
3759
|
+
else delete s.bitDepth;
|
|
3760
|
+
if (entry.colorProfile) s.colorProfile = entry.colorProfile;
|
|
3761
|
+
else delete s.colorProfile;
|
|
3762
|
+
if (entry.colorMode) s.colorMode = entry.colorMode;
|
|
3763
|
+
else delete s.colorMode;
|
|
3653
3764
|
s.selection = entry.selection;
|
|
3654
3765
|
if (this.imageElement !== entry.source.element && !this.samplePixelsOverride) this.samplePixels = null;
|
|
3655
3766
|
this.imageElement = entry.source.element;
|
|
@@ -4933,9 +5044,28 @@ var ImageEditorController = class {
|
|
|
4933
5044
|
throw new LayerOperationError("Merging annotation layers needs a canvas (a browser); hide or delete them first, or merge in the browser.");
|
|
4934
5045
|
}
|
|
4935
5046
|
await this.renderer.prepareLayerAssets(layers, width, height);
|
|
4936
|
-
const
|
|
5047
|
+
const sources = this.renderer.compositorSources(width, height);
|
|
5048
|
+
const depth = this.bitDepth;
|
|
5049
|
+
if (depth !== 8) {
|
|
5050
|
+
const samples = workingToSamples(compositeDeep(layers, rect, sources, depth), depth);
|
|
5051
|
+
return surfaceFromDeepPixels({ width: rect.width, height: rect.height, data: samples }, 4, rect.x, rect.y);
|
|
5052
|
+
}
|
|
5053
|
+
const data = new LayerCompositor().composite(layers, rect, sources);
|
|
4937
5054
|
return surfaceFromPixels({ width: rect.width, height: rect.height, data }, 4, rect.x, rect.y);
|
|
4938
5055
|
}
|
|
5056
|
+
/**
|
|
5057
|
+
* The composite of the layer stack at the document's bit depth (as `compositePixels`, no
|
|
5058
|
+
* canvas): 16-bit sRGB samples, or 32-bit linear float, over `rect` (default the canvas). At 8
|
|
5059
|
+
* bits, the 8-bit composite widened to 16 bits.
|
|
5060
|
+
*/
|
|
5061
|
+
compositeDeepPixels(rect) {
|
|
5062
|
+
const { width, height } = this.naturalSize;
|
|
5063
|
+
const r = rect ?? { x: 0, y: 0, width, height };
|
|
5064
|
+
const depth = this.bitDepth;
|
|
5065
|
+
if (depth === 8) return { width: r.width, height: r.height, depth: 16, data: to16From8(this.compositePixels(r).data) };
|
|
5066
|
+
const data = workingToSamples(compositeDeep(this.state.layers, r, this.compositorSources(), depth), depth);
|
|
5067
|
+
return { width: r.width, height: r.height, depth, data };
|
|
5068
|
+
}
|
|
4939
5069
|
/** Document bounds a layer can paint into (pixel content, annotations, or the canvas for the rest). */
|
|
4940
5070
|
paintBounds(layer) {
|
|
4941
5071
|
const { width, height } = this.naturalSize;
|
|
@@ -6138,16 +6268,37 @@ var ImageEditorController = class {
|
|
|
6138
6268
|
const canvas = await this.renderExport(options);
|
|
6139
6269
|
const format = options.format || "image/png";
|
|
6140
6270
|
const quality = options.quality ?? 0.92;
|
|
6141
|
-
|
|
6271
|
+
const url = canvas.toDataURL(format, quality);
|
|
6272
|
+
if (!this.state.colorProfile) return url;
|
|
6273
|
+
const parsed = parseDataUrl(url);
|
|
6274
|
+
if (!parsed) return url;
|
|
6275
|
+
const bytes = this.withEmbeddedProfile(parsed.bytes, parsed.mime);
|
|
6276
|
+
return bytes === parsed.bytes ? url : `data:${parsed.mime};base64,${bytesToBase64(bytes)}`;
|
|
6277
|
+
}
|
|
6278
|
+
/** PNG or JPEG bytes with the document's ICC profile embedded (other formats unchanged). */
|
|
6279
|
+
withEmbeddedProfile(bytes, mime) {
|
|
6280
|
+
const icc = profileBytes(this.state.colorProfile);
|
|
6281
|
+
try {
|
|
6282
|
+
if (mime === "image/png") return writePngIcc(bytes, icc, this.getColorProfile().name);
|
|
6283
|
+
if (mime === "image/jpeg") return writeJpegIcc(bytes, icc);
|
|
6284
|
+
} catch {
|
|
6285
|
+
}
|
|
6286
|
+
return bytes;
|
|
6142
6287
|
}
|
|
6143
6288
|
async toBlob(options = {}) {
|
|
6144
6289
|
const canvas = await this.renderExport(options);
|
|
6145
6290
|
const format = options.format || "image/png";
|
|
6146
6291
|
const quality = options.quality ?? 0.92;
|
|
6292
|
+
const tag = async (blob) => {
|
|
6293
|
+
if (!this.state.colorProfile || typeof blob.arrayBuffer !== "function") return blob;
|
|
6294
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
6295
|
+
const out = this.withEmbeddedProfile(bytes, blob.type || format);
|
|
6296
|
+
return out === bytes ? blob : new Blob([out], { type: blob.type || format });
|
|
6297
|
+
};
|
|
6147
6298
|
return new Promise((resolve, reject) => {
|
|
6148
6299
|
if (canvas.toBlob) {
|
|
6149
6300
|
canvas.toBlob((blob) => {
|
|
6150
|
-
if (blob)
|
|
6301
|
+
if (blob) tag(blob).then(resolve, reject);
|
|
6151
6302
|
else reject(new Error("Failed to create Blob from canvas"));
|
|
6152
6303
|
}, format, quality);
|
|
6153
6304
|
} else {
|
|
@@ -6160,7 +6311,7 @@ var ImageEditorController = class {
|
|
|
6160
6311
|
for (let i = 0; i < byteStr.length; i++) {
|
|
6161
6312
|
ia[i] = byteStr.charCodeAt(i);
|
|
6162
6313
|
}
|
|
6163
|
-
|
|
6314
|
+
tag(new Blob([ab], { type: format })).then(resolve, reject);
|
|
6164
6315
|
} catch (err) {
|
|
6165
6316
|
reject(err);
|
|
6166
6317
|
}
|
|
@@ -6680,6 +6831,206 @@ var ImageEditorController = class {
|
|
|
6680
6831
|
return id;
|
|
6681
6832
|
}
|
|
6682
6833
|
// --- PSD ---
|
|
6834
|
+
// --- Colour management ---
|
|
6835
|
+
/** The document's colour profile: its name, built-in id (or `null` for an embedded profile), colour space, and Image › Mode. */
|
|
6836
|
+
getColorProfile() {
|
|
6837
|
+
const doc = this.state.colorProfile;
|
|
6838
|
+
const p = resolveProfile(doc);
|
|
6839
|
+
const m = this.state.colorMode;
|
|
6840
|
+
const out = { name: doc?.name ?? p.description, builtin: doc ? doc.builtin ?? null : "srgb", colorSpace: p.colorSpace, srgb: isSrgb(doc), mode: m?.mode ?? "rgb" };
|
|
6841
|
+
if (m?.mode === "cmyk") out.cmykProfile = { name: m.profile.name, builtin: m.profile.builtin ?? null, intent: m.intent };
|
|
6842
|
+
return out;
|
|
6843
|
+
}
|
|
6844
|
+
/**
|
|
6845
|
+
* Image › Mode (one undo step): `rgb`, `cmyk` (with a CMYK `profile`, default the coated
|
|
6846
|
+
* CMYK, and the `intent` RGB is separated with) or `lab`. The pixels stay RGB in the working
|
|
6847
|
+
* space; a CMYK document is soft-proofed through its profile in the viewport, and PSD export
|
|
6848
|
+
* writes CMYK or Lab channels. Returns the profile summary.
|
|
6849
|
+
*/
|
|
6850
|
+
setColorMode(mode, options = {}) {
|
|
6851
|
+
let next;
|
|
6852
|
+
if (mode === "rgb") {
|
|
6853
|
+
if (options.profile !== void 0) throw new LayerOperationError("An RGB document takes no CMYK profile; use assign_profile for its working space.");
|
|
6854
|
+
next = null;
|
|
6855
|
+
} else if (mode === "lab") next = { mode: "lab" };
|
|
6856
|
+
else if (mode === "cmyk") {
|
|
6857
|
+
let doc;
|
|
6858
|
+
try {
|
|
6859
|
+
doc = documentProfile(options.profile ?? "coated-cmyk");
|
|
6860
|
+
} catch (e) {
|
|
6861
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6862
|
+
}
|
|
6863
|
+
const cs = resolveProfile(doc).colorSpace;
|
|
6864
|
+
if (cs !== "cmyk") throw new LayerOperationError(`CMYK mode needs a CMYK profile; "${doc.name}" is ${cs.toUpperCase()}.`);
|
|
6865
|
+
const intent = options.intent ?? "relative";
|
|
6866
|
+
if (!INTENTS.includes(intent)) throw new LayerOperationError(`Unknown rendering intent "${String(intent)}"; use ${INTENTS.join(", ")}.`);
|
|
6867
|
+
next = { mode: "cmyk", profile: doc, intent };
|
|
6868
|
+
} else throw new LayerOperationError(`Unknown colour mode "${String(mode)}"; use rgb, cmyk or lab.`);
|
|
6869
|
+
this.recordHistory();
|
|
6870
|
+
if (next) this.state.colorMode = next;
|
|
6871
|
+
else delete this.state.colorMode;
|
|
6872
|
+
this.notify();
|
|
6873
|
+
return this.getColorProfile();
|
|
6874
|
+
}
|
|
6875
|
+
/** Resolves a profile argument (built-in id or alias, or ICC bytes) as an RGB document profile. */
|
|
6876
|
+
rgbProfileArg(profile, action) {
|
|
6877
|
+
let doc;
|
|
6878
|
+
try {
|
|
6879
|
+
doc = documentProfile(profile);
|
|
6880
|
+
} catch (e) {
|
|
6881
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6882
|
+
}
|
|
6883
|
+
const cs = resolveProfile(doc).colorSpace;
|
|
6884
|
+
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.`);
|
|
6885
|
+
return doc;
|
|
6886
|
+
}
|
|
6887
|
+
/**
|
|
6888
|
+
* Edit › Assign Profile (one undo step): the document's numbers now mean colours in
|
|
6889
|
+
* `profile` (a built-in id such as `display-p3`, or ICC bytes); no pixel changes, so colours
|
|
6890
|
+
* look different unless the profiles match. Returns the new profile.
|
|
6891
|
+
*/
|
|
6892
|
+
assignProfile(profile) {
|
|
6893
|
+
const doc = this.rgbProfileArg(profile, "Assign Profile");
|
|
6894
|
+
this.recordHistory();
|
|
6895
|
+
if (doc.builtin === "srgb") delete this.state.colorProfile;
|
|
6896
|
+
else this.state.colorProfile = doc;
|
|
6897
|
+
this.notify();
|
|
6898
|
+
return this.getColorProfile();
|
|
6899
|
+
}
|
|
6900
|
+
/**
|
|
6901
|
+
* Edit › Convert to Profile (one undo step): every pixel layer's numbers are converted so its
|
|
6902
|
+
* colours stay the same in `profile` (with `intent` and black point compensation), and
|
|
6903
|
+
* `profile` becomes the document's. Shape and type layers, layer effects and adjustment layers
|
|
6904
|
+
* keep their numbers (they are listed in `unconvertedLayerIds`). Returns the profile and the
|
|
6905
|
+
* layers changed.
|
|
6906
|
+
*/
|
|
6907
|
+
convertToProfile(profile, options = {}) {
|
|
6908
|
+
const doc = this.rgbProfileArg(profile, "Convert to Profile");
|
|
6909
|
+
const intent = options.intent ?? "relative";
|
|
6910
|
+
if (!INTENTS.includes(intent)) throw new LayerOperationError(`Unknown rendering intent "${String(intent)}"; use ${INTENTS.join(", ")}.`);
|
|
6911
|
+
const t = Transform.create(resolveProfile(this.state.colorProfile), resolveProfile(doc), { intent, bpc: options.bpc ?? true });
|
|
6912
|
+
const converted = [];
|
|
6913
|
+
const unconverted = [];
|
|
6914
|
+
const walk = (layers) => layers.map((l) => {
|
|
6915
|
+
if (l.type === "group") return { ...l, children: walk(l.children) };
|
|
6916
|
+
if (l.type === "pixel" && l.source !== "document") {
|
|
6917
|
+
converted.push(l.id);
|
|
6918
|
+
return { ...l, surface: convertSurfaceColors(l.surface, t) };
|
|
6919
|
+
}
|
|
6920
|
+
if (l.type === "pixel" && l.source === "document") {
|
|
6921
|
+
converted.push(l.id);
|
|
6922
|
+
return { ...l, surface: convertSurfaceColors(this.surfaceOf(l), t), source: void 0 };
|
|
6923
|
+
}
|
|
6924
|
+
if (l.type === "shape" || l.type === "type" || l.type === "smart" || l.effects?.items.length) unconverted.push(l.id);
|
|
6925
|
+
return l;
|
|
6926
|
+
});
|
|
6927
|
+
const next = walk(this.state.layers);
|
|
6928
|
+
this.commitLayers(next, () => {
|
|
6929
|
+
if (doc.builtin === "srgb") delete this.state.colorProfile;
|
|
6930
|
+
else this.state.colorProfile = doc;
|
|
6931
|
+
});
|
|
6932
|
+
return { profile: this.getColorProfile(), convertedLayerIds: converted, unconvertedLayerIds: unconverted };
|
|
6933
|
+
}
|
|
6934
|
+
/**
|
|
6935
|
+
* View › Proof Setup (view state, not an undo step): shows the document as `profile` would
|
|
6936
|
+
* reproduce it, or turns proofing off with `null`. Returns the setup.
|
|
6937
|
+
*/
|
|
6938
|
+
setProofSetup(setup) {
|
|
6939
|
+
if (!setup) {
|
|
6940
|
+
this.state.proofSetup = null;
|
|
6941
|
+
this.notify();
|
|
6942
|
+
return null;
|
|
6943
|
+
}
|
|
6944
|
+
let doc;
|
|
6945
|
+
try {
|
|
6946
|
+
doc = documentProfile(setup.profile);
|
|
6947
|
+
} catch (e) {
|
|
6948
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6949
|
+
}
|
|
6950
|
+
const intent = setup.intent ?? DEFAULT_PROOF.intent;
|
|
6951
|
+
if (!INTENTS.includes(intent)) throw new LayerOperationError(`Unknown rendering intent "${String(intent)}"; use ${INTENTS.join(", ")}.`);
|
|
6952
|
+
const next = { ...DEFAULT_PROOF, ...setup, intent, profile: doc };
|
|
6953
|
+
if (!canBeDestination(resolveProfile(doc))) throw new LayerOperationError(`"${doc.name}" describes a source only, so colours cannot be proofed through it.`);
|
|
6954
|
+
this.state.proofSetup = next;
|
|
6955
|
+
this.notify();
|
|
6956
|
+
return next;
|
|
6957
|
+
}
|
|
6958
|
+
/**
|
|
6959
|
+
* Converts colours (`#rrggbb`) from one profile to another (default from the document's), with
|
|
6960
|
+
* `intent`. For RGB targets returns hex; for others the channel values 0..1 (CMYK, grey, Lab
|
|
6961
|
+
* encoded as L/100, (a+128)/255, (b+128)/255) and, for Lab, L*a*b*.
|
|
6962
|
+
*/
|
|
6963
|
+
convertColors(colors, to, options = {}) {
|
|
6964
|
+
let src;
|
|
6965
|
+
let dst;
|
|
6966
|
+
try {
|
|
6967
|
+
src = options.from !== void 0 ? resolveProfile(documentProfile(options.from)) : resolveProfile(this.state.colorProfile);
|
|
6968
|
+
dst = resolveProfile(documentProfile(to));
|
|
6969
|
+
} catch (e) {
|
|
6970
|
+
throw new LayerOperationError(e instanceof Error ? e.message : String(e));
|
|
6971
|
+
}
|
|
6972
|
+
if (src.colorSpace !== "rgb") throw new LayerOperationError("Colours are given as #rrggbb, so the source profile must be RGB.");
|
|
6973
|
+
const t = Transform.create(src, dst, { intent: options.intent ?? "relative", bpc: options.bpc ?? true });
|
|
6974
|
+
const toLab = Transform.create(src, builtinProfile("lab-d50"), { intent: "relative", bpc: false });
|
|
6975
|
+
return colors.map((input) => {
|
|
6976
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(input.trim());
|
|
6977
|
+
if (!m) throw new LayerOperationError(`Invalid colour "${input}"; use #rrggbb.`);
|
|
6978
|
+
const n = parseInt(m[1], 16);
|
|
6979
|
+
const rgb = [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
6980
|
+
const out = new Float32Array(16);
|
|
6981
|
+
t.eval(rgb, out);
|
|
6982
|
+
const values = Array.from(out.subarray(0, t.outputs), (v) => Math.round(Math.min(1, Math.max(0, v)) * 1e4) / 1e4);
|
|
6983
|
+
const l = new Float32Array(3);
|
|
6984
|
+
toLab.eval(rgb, l);
|
|
6985
|
+
const lab = [Math.round(l[0] * 1e4) / 100, Math.round((l[1] * 255 - 128) * 100) / 100, Math.round((l[2] * 255 - 128) * 100) / 100];
|
|
6986
|
+
const res = { input, values, lab };
|
|
6987
|
+
if (dst.colorSpace === "rgb") res.hex = `#${values.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("")}`;
|
|
6988
|
+
return res;
|
|
6989
|
+
});
|
|
6990
|
+
}
|
|
6991
|
+
/** The document's bits per channel (8 unless set to 16 or 32). */
|
|
6992
|
+
get bitDepth() {
|
|
6993
|
+
return this.state.bitDepth ?? 8;
|
|
6994
|
+
}
|
|
6995
|
+
/**
|
|
6996
|
+
* Image › Mode › 8 / 16 / 32 Bits/Channel (one undo step). Going up costs nothing: layers keep
|
|
6997
|
+
* their pixels and read them at the new depth, and edits that understand depth keep the extra
|
|
6998
|
+
* precision from then on. Going down rounds every pixel layer's deep samples to the new depth
|
|
6999
|
+
* (8 bits: their 8-bit rendering; 32 → 16: colour above 1 is clipped). Returns the depth and
|
|
7000
|
+
* the ids of the layers whose pixels changed.
|
|
7001
|
+
*/
|
|
7002
|
+
setBitDepth(depth) {
|
|
7003
|
+
if (!isBitDepth(depth)) throw new LayerOperationError(`Bit depth must be 8, 16 or 32, not ${String(depth)}.`);
|
|
7004
|
+
const changed = [];
|
|
7005
|
+
const convert = (layers) => layers.map((l) => {
|
|
7006
|
+
if (l.type === "group") {
|
|
7007
|
+
const children = convert(l.children);
|
|
7008
|
+
return children.some((c, i) => c !== l.children[i]) ? { ...l, children } : l;
|
|
7009
|
+
}
|
|
7010
|
+
if (l.type !== "pixel") return l;
|
|
7011
|
+
const surface = convertSurfaceDepth(l.surface, depth);
|
|
7012
|
+
if (surface === l.surface) return l;
|
|
7013
|
+
changed.push(l.id);
|
|
7014
|
+
return { ...l, surface };
|
|
7015
|
+
});
|
|
7016
|
+
if (depth === this.bitDepth) return { bitDepth: depth, changedLayerIds: [] };
|
|
7017
|
+
const next = convert(this.state.layers);
|
|
7018
|
+
this.commitLayers(next, () => {
|
|
7019
|
+
if (depth === 8) delete this.state.bitDepth;
|
|
7020
|
+
else this.state.bitDepth = depth;
|
|
7021
|
+
});
|
|
7022
|
+
return { bitDepth: depth, changedLayerIds: changed };
|
|
7023
|
+
}
|
|
7024
|
+
/** How `toPsd` writes colour: RGB with the working space, or CMYK / Lab channels for those modes. */
|
|
7025
|
+
psdColorOptions(warnings) {
|
|
7026
|
+
const m = this.state.colorMode;
|
|
7027
|
+
if (!m) return { iccProfile: profileBytes(this.state.colorProfile) };
|
|
7028
|
+
if (flattenLayers(this.state.layers).some((l) => l.type === "adjustment" && l.visible)) {
|
|
7029
|
+
warnings.push(`Adjustment layers were written with their RGB settings; in a ${m.mode.toUpperCase()} file Photoshop applies them to its own channels, so they may look different there.`);
|
|
7030
|
+
}
|
|
7031
|
+
const planes = colorModePlanes(this.state.colorProfile, m);
|
|
7032
|
+
return m.mode === "cmyk" ? { colorMode: "cmyk", colorPlanes: planes, iccProfile: profileBytes(m.profile) } : { colorMode: "lab", colorPlanes: planes };
|
|
7033
|
+
}
|
|
6683
7034
|
/** Pixels per inch of the last opened PSD (written back by `toPsd`). */
|
|
6684
7035
|
psdResolution;
|
|
6685
7036
|
/**
|
|
@@ -6712,6 +7063,23 @@ var ImageEditorController = class {
|
|
|
6712
7063
|
else delete s.patterns;
|
|
6713
7064
|
if (result.globalLight) s.globalLight = result.globalLight;
|
|
6714
7065
|
else delete s.globalLight;
|
|
7066
|
+
if (result.bitDepth !== 8) s.bitDepth = result.bitDepth;
|
|
7067
|
+
else delete s.bitDepth;
|
|
7068
|
+
delete s.colorProfile;
|
|
7069
|
+
delete s.colorMode;
|
|
7070
|
+
if (result.sourceMode?.mode === "cmyk") s.colorMode = { mode: "cmyk", profile: result.sourceMode.profile, intent: "relative" };
|
|
7071
|
+
else if (result.sourceMode?.mode === "lab") s.colorMode = { mode: "lab" };
|
|
7072
|
+
else if (result.iccProfile) {
|
|
7073
|
+
try {
|
|
7074
|
+
const doc = documentProfile(result.iccProfile);
|
|
7075
|
+
const cs = resolveProfile(doc).colorSpace;
|
|
7076
|
+
if (cs === "rgb") {
|
|
7077
|
+
if (!isSrgb(doc)) s.colorProfile = doc;
|
|
7078
|
+
} else result.warnings.push(`The file's ${cs.toUpperCase()} profile "${doc.name}" was not used; its colours were read as sRGB.`);
|
|
7079
|
+
} catch (e) {
|
|
7080
|
+
result.warnings.push(`The embedded ICC profile could not be read (${e instanceof Error ? e.message : String(e)}); colours are read as sRGB.`);
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
6715
7083
|
this.lastLoadProblems = result.warnings;
|
|
6716
7084
|
this.notify();
|
|
6717
7085
|
return {
|
|
@@ -6747,7 +7115,7 @@ var ImageEditorController = class {
|
|
|
6747
7115
|
return layers;
|
|
6748
7116
|
}
|
|
6749
7117
|
/**
|
|
6750
|
-
* The document as an
|
|
7118
|
+
* 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
7119
|
* layers and masks, in the source frame. Layer filters and parametric (depth) masks are baked
|
|
6752
7120
|
* into pixels and masks, annotation layers are rasterized (in a browser; elsewhere they are left
|
|
6753
7121
|
* out), and the merged image is our composite. `warnings` lists every such change.
|
|
@@ -6873,7 +7241,11 @@ var ImageEditorController = class {
|
|
|
6873
7241
|
if (s.legacyOutputBlur) warnings.push("The document-level blur of an old document is not written.");
|
|
6874
7242
|
for (const [msg, names] of note) warnings.push(`${msg} (${names.length === 1 ? "layer" : "layers"} ${names.map((n) => `"${n}"`).join(", ")}).`);
|
|
6875
7243
|
const merged = compositor.composite(prepared, canvas, { ...sources, version: `psd:${Date.now()}` });
|
|
6876
|
-
const
|
|
7244
|
+
const color = this.psdColorOptions(warnings);
|
|
7245
|
+
if (color.colorMode && this.bitDepth !== 8) warnings.push(`${color.colorMode.toUpperCase()} files are written at 8 bits per channel; the ${this.bitDepth}-bit samples were rounded.`);
|
|
7246
|
+
const depth = color.colorMode ? 8 : this.bitDepth;
|
|
7247
|
+
const mergedDeep = depth === 8 ? void 0 : workingToSamples(compositeDeep(prepared, canvas, sources, depth), depth);
|
|
7248
|
+
const result = exportPsd({ width, height, layers: prepared, merged, mergedDeep, resolution: this.psdResolution, patterns: this.state.patterns, globalLight: this.state.globalLight, depth, ...color });
|
|
6877
7249
|
warnings.push(...result.warnings);
|
|
6878
7250
|
return { bytes: result.bytes, warnings, psb: result.psb, width, height };
|
|
6879
7251
|
}
|
|
@@ -7019,6 +7391,14 @@ var ImageEditorController = class {
|
|
|
7019
7391
|
const patterns = deserializePatterns(data.patterns, problems);
|
|
7020
7392
|
if (patterns.length) s.patterns = patterns;
|
|
7021
7393
|
else delete s.patterns;
|
|
7394
|
+
if (data.bitDepth === 16 || data.bitDepth === 32) s.bitDepth = data.bitDepth;
|
|
7395
|
+
else delete s.bitDepth;
|
|
7396
|
+
const profile = data.colorProfile ? deserializeColorProfile(data.colorProfile, problems) : null;
|
|
7397
|
+
if (profile) s.colorProfile = profile;
|
|
7398
|
+
else delete s.colorProfile;
|
|
7399
|
+
const cmode = data.colorMode ? deserializeColorMode(data.colorMode, problems) : null;
|
|
7400
|
+
if (cmode) s.colorMode = cmode;
|
|
7401
|
+
else delete s.colorMode;
|
|
7022
7402
|
if (!this.imageElement && typeof data.width === "number" && typeof data.height === "number" && data.width > 0 && data.height > 0) {
|
|
7023
7403
|
s.imageDimensions = { width: data.width, height: data.height };
|
|
7024
7404
|
}
|
|
@@ -7034,6 +7414,9 @@ var ImageEditorController = class {
|
|
|
7034
7414
|
s.activeLayerId = null;
|
|
7035
7415
|
delete s.globalLight;
|
|
7036
7416
|
delete s.patterns;
|
|
7417
|
+
delete s.bitDepth;
|
|
7418
|
+
delete s.colorProfile;
|
|
7419
|
+
delete s.colorMode;
|
|
7037
7420
|
}
|
|
7038
7421
|
s.activeTarget = "pixels";
|
|
7039
7422
|
this.viewKey = [];
|
|
@@ -7043,7 +7426,7 @@ var ImageEditorController = class {
|
|
|
7043
7426
|
serializeState() {
|
|
7044
7427
|
const { width, height } = this.naturalSize;
|
|
7045
7428
|
const view = legacyView(this.stack(), width, height, null);
|
|
7046
|
-
if (view.exact && !this.state.globalLight && !this.state.patterns?.length) {
|
|
7429
|
+
if (view.exact && !this.state.globalLight && !this.state.patterns?.length && this.bitDepth === 8 && !this.state.colorProfile && !this.state.colorMode) {
|
|
7047
7430
|
return {
|
|
7048
7431
|
// States without adjustment layers keep schema 1, so they round-trip unchanged.
|
|
7049
7432
|
version: view.adjustments.layers?.length ? 2 : 1,
|
|
@@ -7073,6 +7456,9 @@ var ImageEditorController = class {
|
|
|
7073
7456
|
if (this.state.globalLight) out.globalLight = { ...this.state.globalLight };
|
|
7074
7457
|
if (this.state.patterns?.length) out.patterns = serializePatterns(this.state.patterns);
|
|
7075
7458
|
if (smartContents) out.smartContents = smartContents;
|
|
7459
|
+
if (this.state.bitDepth === 16 || this.state.bitDepth === 32) out.bitDepth = this.state.bitDepth;
|
|
7460
|
+
if (this.state.colorProfile) out.colorProfile = serializeColorProfile(this.state.colorProfile);
|
|
7461
|
+
if (this.state.colorMode) out.colorMode = serializeColorMode(this.state.colorMode);
|
|
7076
7462
|
return out;
|
|
7077
7463
|
}
|
|
7078
7464
|
};
|
|
@@ -8281,10 +8667,23 @@ function createImageEditTools(controller) {
|
|
|
8281
8667
|
const getImageInfo = {
|
|
8282
8668
|
name: "get_image_info",
|
|
8283
8669
|
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.",
|
|
8670
|
+
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
8671
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
8286
8672
|
annotations: { title: "Read image geometry", ...READ },
|
|
8287
|
-
handler: () => ({ ...geometry2(), layers: controller.getAdjustmentLayers().length, ...history() })
|
|
8673
|
+
handler: () => ({ ...geometry2(), bitDepth: controller.bitDepth, layers: controller.getAdjustmentLayers().length, ...history() })
|
|
8674
|
+
};
|
|
8675
|
+
const setBitDepth = {
|
|
8676
|
+
name: "set_bit_depth",
|
|
8677
|
+
title: "Set the bit depth",
|
|
8678
|
+
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).",
|
|
8679
|
+
inputSchema: {
|
|
8680
|
+
type: "object",
|
|
8681
|
+
properties: { depth: { type: "number", enum: [8, 16, 32], description: "Bits per channel: 8, 16 or 32 (float, linear light)." } },
|
|
8682
|
+
required: ["depth"],
|
|
8683
|
+
additionalProperties: false
|
|
8684
|
+
},
|
|
8685
|
+
annotations: { title: "Set the bit depth", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
8686
|
+
handler: (args) => ({ ...controller.setBitDepth(args.depth), ...history() })
|
|
8288
8687
|
};
|
|
8289
8688
|
const getHistogram = {
|
|
8290
8689
|
name: "get_histogram",
|
|
@@ -8460,7 +8859,7 @@ function createImageEditTools(controller) {
|
|
|
8460
8859
|
return history();
|
|
8461
8860
|
}
|
|
8462
8861
|
};
|
|
8463
|
-
return [getImageInfo, getHistogram, updateLayer, removeLayer2, moveLayer2, setCrop, resetCrop, setRotation, flipImage, undo, redo];
|
|
8862
|
+
return [getImageInfo, getHistogram, updateLayer, removeLayer2, moveLayer2, setCrop, resetCrop, setRotation, flipImage, setBitDepth, undo, redo];
|
|
8464
8863
|
}
|
|
8465
8864
|
|
|
8466
8865
|
// src/image-editor/layer-tools.ts
|
|
@@ -9775,8 +10174,155 @@ function createImagePaintTools(controller) {
|
|
|
9775
10174
|
return [paintStroke, fill, clear, getMixer, loadMixerTool, cleanMixerTool];
|
|
9776
10175
|
}
|
|
9777
10176
|
|
|
9778
|
-
// src/image-editor/
|
|
10177
|
+
// src/image-editor/color-tools.ts
|
|
9779
10178
|
var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10179
|
+
var PROFILE = {
|
|
10180
|
+
type: "string",
|
|
10181
|
+
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.`
|
|
10182
|
+
};
|
|
10183
|
+
var INTENT = {
|
|
10184
|
+
type: "string",
|
|
10185
|
+
enum: [...INTENTS],
|
|
10186
|
+
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)."
|
|
10187
|
+
};
|
|
10188
|
+
function profileArg(v) {
|
|
10189
|
+
const s = String(v);
|
|
10190
|
+
if (s.startsWith("icc:")) {
|
|
10191
|
+
try {
|
|
10192
|
+
return base64ToBytes(s.slice(4));
|
|
10193
|
+
} catch {
|
|
10194
|
+
throw new LayerOperationError("The icc: value is not valid base64.");
|
|
10195
|
+
}
|
|
10196
|
+
}
|
|
10197
|
+
return s;
|
|
10198
|
+
}
|
|
10199
|
+
function createImageColorTools(controller) {
|
|
10200
|
+
const getProfile = {
|
|
10201
|
+
name: "get_color_profile",
|
|
10202
|
+
title: "Get the colour profile",
|
|
10203
|
+
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, mode rgb / cmyk / lab and, for cmyk, cmykProfile), 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}).",
|
|
10204
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
10205
|
+
annotations: { title: "Get the colour profile", ...READ5 },
|
|
10206
|
+
handler: () => {
|
|
10207
|
+
const proof2 = controller.getState().proofSetup;
|
|
10208
|
+
return {
|
|
10209
|
+
profile: controller.getColorProfile(),
|
|
10210
|
+
proof: proof2 ? { profile: proof2.profile.name, builtin: proof2.profile.builtin ?? null, intent: proof2.intent, bpc: proof2.bpc, simulatePaper: proof2.simulatePaper, gamutWarning: proof2.gamutWarning } : null,
|
|
10211
|
+
builtins: BUILTIN_PROFILES.map((b) => ({ ...b }))
|
|
10212
|
+
};
|
|
10213
|
+
}
|
|
10214
|
+
};
|
|
10215
|
+
const assign = {
|
|
10216
|
+
name: "assign_profile",
|
|
10217
|
+
title: "Assign a colour profile",
|
|
10218
|
+
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.",
|
|
10219
|
+
inputSchema: { type: "object", properties: { profile: PROFILE }, required: ["profile"], additionalProperties: false },
|
|
10220
|
+
annotations: { title: "Assign a colour profile", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10221
|
+
handler: (args) => controller.assignProfile(profileArg(args.profile))
|
|
10222
|
+
};
|
|
10223
|
+
const convert = {
|
|
10224
|
+
name: "convert_to_profile",
|
|
10225
|
+
title: "Convert to a colour profile",
|
|
10226
|
+
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.",
|
|
10227
|
+
inputSchema: {
|
|
10228
|
+
type: "object",
|
|
10229
|
+
properties: {
|
|
10230
|
+
profile: PROFILE,
|
|
10231
|
+
intent: INTENT,
|
|
10232
|
+
bpc: { type: "boolean", description: "Black point compensation: map black to black (default true)." }
|
|
10233
|
+
},
|
|
10234
|
+
required: ["profile"],
|
|
10235
|
+
additionalProperties: false
|
|
10236
|
+
},
|
|
10237
|
+
annotations: { title: "Convert to a colour profile", readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
10238
|
+
handler: (args) => controller.convertToProfile(profileArg(args.profile), { intent: args.intent, bpc: args.bpc })
|
|
10239
|
+
};
|
|
10240
|
+
const proof = {
|
|
10241
|
+
name: "set_proof_setup",
|
|
10242
|
+
title: "Set up soft proofing",
|
|
10243
|
+
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).",
|
|
10244
|
+
inputSchema: {
|
|
10245
|
+
type: "object",
|
|
10246
|
+
properties: {
|
|
10247
|
+
profile: PROFILE,
|
|
10248
|
+
intent: INTENT,
|
|
10249
|
+
bpc: { type: "boolean", description: "Black point compensation (default true)." },
|
|
10250
|
+
simulatePaper: { type: "boolean", description: "Simulate paper colour and black ink (default false)." },
|
|
10251
|
+
gamutWarning: { type: "boolean", description: "Grey out out-of-gamut colours (default false)." },
|
|
10252
|
+
off: { type: "boolean", description: "Turn proofing off instead (default false)." }
|
|
10253
|
+
},
|
|
10254
|
+
additionalProperties: false
|
|
10255
|
+
},
|
|
10256
|
+
annotations: { title: "Set up soft proofing", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10257
|
+
handler: (args) => {
|
|
10258
|
+
if (args.off === true) {
|
|
10259
|
+
if (args.profile !== void 0) throw new LayerOperationError("Give either off true or a profile, not both.");
|
|
10260
|
+
return controller.setProofSetup(null);
|
|
10261
|
+
}
|
|
10262
|
+
if (args.profile === void 0) throw new LayerOperationError("Pass the profile to proof with (e.g. coated-cmyk), or off true.");
|
|
10263
|
+
const s = controller.setProofSetup({
|
|
10264
|
+
profile: profileArg(args.profile),
|
|
10265
|
+
...args.intent !== void 0 ? { intent: args.intent } : {},
|
|
10266
|
+
...args.bpc !== void 0 ? { bpc: args.bpc } : {},
|
|
10267
|
+
...args.simulatePaper !== void 0 ? { simulatePaper: args.simulatePaper } : {},
|
|
10268
|
+
...args.gamutWarning !== void 0 ? { gamutWarning: args.gamutWarning } : {}
|
|
10269
|
+
});
|
|
10270
|
+
return { profile: s.profile.name, builtin: s.profile.builtin ?? null, intent: s.intent, bpc: s.bpc, simulatePaper: s.simulatePaper, gamutWarning: s.gamutWarning };
|
|
10271
|
+
}
|
|
10272
|
+
};
|
|
10273
|
+
const convertColors = {
|
|
10274
|
+
name: "convert_colors",
|
|
10275
|
+
title: "Convert colours between profiles",
|
|
10276
|
+
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.',
|
|
10277
|
+
inputSchema: {
|
|
10278
|
+
type: "object",
|
|
10279
|
+
properties: {
|
|
10280
|
+
colors: { type: "array", minItems: 1, maxItems: 64, items: { type: "string", description: "A colour #rrggbb." }, description: "Colours in the source profile." },
|
|
10281
|
+
to: PROFILE,
|
|
10282
|
+
from: { ...PROFILE, description: `Source profile (default the document's). ${PROFILE.description}` },
|
|
10283
|
+
intent: INTENT,
|
|
10284
|
+
bpc: { type: "boolean", description: "Black point compensation (default true)." }
|
|
10285
|
+
},
|
|
10286
|
+
required: ["colors", "to"],
|
|
10287
|
+
additionalProperties: false
|
|
10288
|
+
},
|
|
10289
|
+
annotations: { title: "Convert colours between profiles", ...READ5 },
|
|
10290
|
+
handler: (args) => ({
|
|
10291
|
+
colors: controller.convertColors(args.colors, profileArg(args.to), {
|
|
10292
|
+
...args.from !== void 0 ? { from: profileArg(args.from) } : {},
|
|
10293
|
+
intent: args.intent,
|
|
10294
|
+
bpc: args.bpc
|
|
10295
|
+
})
|
|
10296
|
+
})
|
|
10297
|
+
};
|
|
10298
|
+
const setMode = {
|
|
10299
|
+
name: "set_color_mode",
|
|
10300
|
+
title: "Set the colour mode",
|
|
10301
|
+
description: "Image \u203A Mode: rgb, cmyk (for print: give the press `profile`, default coated-cmyk, and the `intent` RGB is separated with) or lab. The document is still edited as RGB in its working space; a CMYK document is soft-proofed through its profile in the viewport (unless set_proof_setup says otherwise), and export_psd writes CMYK or Lab channels with the profile. Changes no pixels. One undo step. Returns the profile summary with mode and cmykProfile.",
|
|
10302
|
+
inputSchema: {
|
|
10303
|
+
type: "object",
|
|
10304
|
+
properties: {
|
|
10305
|
+
mode: { type: "string", enum: ["rgb", "cmyk", "lab"], description: "The colour mode." },
|
|
10306
|
+
profile: { ...PROFILE, description: `CMYK mode only: the CMYK profile (default coated-cmyk). ${PROFILE.description}` },
|
|
10307
|
+
intent: INTENT
|
|
10308
|
+
},
|
|
10309
|
+
required: ["mode"],
|
|
10310
|
+
additionalProperties: false
|
|
10311
|
+
},
|
|
10312
|
+
annotations: { title: "Set the colour mode", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
10313
|
+
handler: (args) => {
|
|
10314
|
+
if (args.mode !== "cmyk" && (args.profile !== void 0 || args.intent !== void 0)) throw new LayerOperationError("profile and intent apply to CMYK mode only.");
|
|
10315
|
+
return controller.setColorMode(args.mode, {
|
|
10316
|
+
...args.profile !== void 0 ? { profile: profileArg(args.profile) } : {},
|
|
10317
|
+
...args.intent !== void 0 ? { intent: args.intent } : {}
|
|
10318
|
+
});
|
|
10319
|
+
}
|
|
10320
|
+
};
|
|
10321
|
+
return [getProfile, assign, convert, proof, convertColors, setMode];
|
|
10322
|
+
}
|
|
10323
|
+
|
|
10324
|
+
// src/image-editor/retouch-tools.ts
|
|
10325
|
+
var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
9780
10326
|
var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
9781
10327
|
var POINTS = {
|
|
9782
10328
|
type: "array",
|
|
@@ -9980,7 +10526,7 @@ function createImageRetouchTools(controller) {
|
|
|
9980
10526
|
title: "Get retouch options",
|
|
9981
10527
|
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
10528
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
9983
|
-
annotations: { title: "Get retouch options", ...
|
|
10529
|
+
annotations: { title: "Get retouch options", ...READ6 },
|
|
9984
10530
|
handler: () => {
|
|
9985
10531
|
const { retouch, cloneSource } = controller.getState().paint;
|
|
9986
10532
|
return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null };
|
|
@@ -10040,7 +10586,7 @@ function pick(args, keys) {
|
|
|
10040
10586
|
}
|
|
10041
10587
|
|
|
10042
10588
|
// src/image-editor/psd-tools.ts
|
|
10043
|
-
var
|
|
10589
|
+
var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10044
10590
|
var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
10045
10591
|
var DATA = {
|
|
10046
10592
|
type: "string",
|
|
@@ -10061,7 +10607,7 @@ function createImagePsdTools(controller) {
|
|
|
10061
10607
|
title: "Inspect a PSD",
|
|
10062
10608
|
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
10609
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
10064
|
-
annotations: { title: "Inspect a PSD", ...
|
|
10610
|
+
annotations: { title: "Inspect a PSD", ...READ7 },
|
|
10065
10611
|
handler: ({ data }) => {
|
|
10066
10612
|
const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
|
|
10067
10613
|
return {
|
|
@@ -10096,9 +10642,9 @@ function createImagePsdTools(controller) {
|
|
|
10096
10642
|
const save = {
|
|
10097
10643
|
name: "export_psd",
|
|
10098
10644
|
title: "Export the document as a PSD",
|
|
10099
|
-
description: "Writes the document as an
|
|
10645
|
+
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
10646
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
10101
|
-
annotations: { title: "Export the document as a PSD", ...
|
|
10647
|
+
annotations: { title: "Export the document as a PSD", ...READ7 },
|
|
10102
10648
|
handler: async () => {
|
|
10103
10649
|
const res = await controller.toPsd();
|
|
10104
10650
|
return {
|
|
@@ -10116,7 +10662,7 @@ function createImagePsdTools(controller) {
|
|
|
10116
10662
|
}
|
|
10117
10663
|
|
|
10118
10664
|
// src/image-editor/transform-tools.ts
|
|
10119
|
-
var
|
|
10665
|
+
var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10120
10666
|
var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10121
10667
|
var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
10122
10668
|
var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
|
|
@@ -10216,7 +10762,7 @@ function createImageTransformTools(controller) {
|
|
|
10216
10762
|
},
|
|
10217
10763
|
additionalProperties: false
|
|
10218
10764
|
},
|
|
10219
|
-
annotations: { title: "Get the Free Transform frame", ...
|
|
10765
|
+
annotations: { title: "Get the Free Transform frame", ...READ8 },
|
|
10220
10766
|
handler: (args) => {
|
|
10221
10767
|
const init = targetFrom(args);
|
|
10222
10768
|
if (init.content === "selection-copy") init.content = "selection";
|
|
@@ -10359,7 +10905,7 @@ function createImageTransformTools(controller) {
|
|
|
10359
10905
|
}
|
|
10360
10906
|
|
|
10361
10907
|
// src/image-editor/smart-tools.ts
|
|
10362
|
-
var
|
|
10908
|
+
var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10363
10909
|
var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10364
10910
|
var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10365
10911
|
var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -10418,7 +10964,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10418
10964
|
title: "Read a smart object",
|
|
10419
10965
|
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
10966
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
10421
|
-
annotations: { title: "Read a smart object", ...
|
|
10967
|
+
annotations: { title: "Read a smart object", ...READ9 },
|
|
10422
10968
|
handler: ({ layerId }) => info(smartId(layerId))
|
|
10423
10969
|
};
|
|
10424
10970
|
const convert = {
|
|
@@ -10552,7 +11098,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10552
11098
|
title: "Export a smart object\u2019s contents",
|
|
10553
11099
|
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
11100
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
10555
|
-
annotations: { title: "Export a smart object\u2019s contents", ...
|
|
11101
|
+
annotations: { title: "Export a smart object\u2019s contents", ...READ9 },
|
|
10556
11102
|
handler: ({ layerId }) => {
|
|
10557
11103
|
const f = controller.exportSmartObjectContents(smartId(layerId));
|
|
10558
11104
|
return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
|
|
@@ -10719,7 +11265,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
10719
11265
|
}
|
|
10720
11266
|
|
|
10721
11267
|
// src/image-editor/shape-tools.ts
|
|
10722
|
-
var
|
|
11268
|
+
var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10723
11269
|
var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
10724
11270
|
var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
10725
11271
|
var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -10973,7 +11519,7 @@ function createImageShapeTools(controller) {
|
|
|
10973
11519
|
title: "Read a shape layer",
|
|
10974
11520
|
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
11521
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
10976
|
-
annotations: { title: "Read a shape layer", ...
|
|
11522
|
+
annotations: { title: "Read a shape layer", ...READ10 },
|
|
10977
11523
|
handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
|
|
10978
11524
|
};
|
|
10979
11525
|
const add2 = {
|
|
@@ -11122,7 +11668,7 @@ function createImageShapeTools(controller) {
|
|
|
11122
11668
|
}
|
|
11123
11669
|
|
|
11124
11670
|
// src/image-editor/type-tools.ts
|
|
11125
|
-
var
|
|
11671
|
+
var READ11 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
11126
11672
|
var WRITE9 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
11127
11673
|
var WRITE_IDEMPOTENT6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
11128
11674
|
var DESTRUCTIVE7 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
@@ -11173,7 +11719,7 @@ function createImageTypeTools(controller) {
|
|
|
11173
11719
|
title: "List fonts",
|
|
11174
11720
|
description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
|
|
11175
11721
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
11176
|
-
annotations: { title: "List fonts", ...
|
|
11722
|
+
annotations: { title: "List fonts", ...READ11 },
|
|
11177
11723
|
handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
|
|
11178
11724
|
};
|
|
11179
11725
|
const get = {
|
|
@@ -11181,7 +11727,7 @@ function createImageTypeTools(controller) {
|
|
|
11181
11727
|
title: "Read a type layer",
|
|
11182
11728
|
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
11729
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID6 }, required: ["layerId"], additionalProperties: false },
|
|
11184
|
-
annotations: { title: "Read a type layer", ...
|
|
11730
|
+
annotations: { title: "Read a type layer", ...READ11 },
|
|
11185
11731
|
handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
|
|
11186
11732
|
};
|
|
11187
11733
|
const add2 = {
|
|
@@ -11534,6 +12080,7 @@ function createImageEditorToolProvider(controller, options = {}) {
|
|
|
11534
12080
|
...createImageTypeTools(controller),
|
|
11535
12081
|
...createImageEffectTools(controller),
|
|
11536
12082
|
...createImagePaintTools(controller),
|
|
12083
|
+
...createImageColorTools(controller),
|
|
11537
12084
|
...createImageRetouchTools(controller),
|
|
11538
12085
|
...createPigmentTools(),
|
|
11539
12086
|
...createImagePsdTools(controller)
|
|
@@ -12529,6 +13076,11 @@ function extractNormalizedLayerItems(controller, fallbackImageUrl = "") {
|
|
|
12529
13076
|
};
|
|
12530
13077
|
});
|
|
12531
13078
|
}
|
|
13079
|
+
var BIT_DEPTH_OPTIONS = [
|
|
13080
|
+
{ depth: 8, label: "8-bit", title: "8 bits per channel" },
|
|
13081
|
+
{ depth: 16, label: "16-bit", title: "16 bits per channel: smooth gradients, no banding under strong adjustments" },
|
|
13082
|
+
{ depth: 32, label: "32-bit", title: "32-bit float per channel, linear light (HDR)" }
|
|
13083
|
+
];
|
|
12532
13084
|
|
|
12533
13085
|
// src/image-editor/layers/effects-ui.ts
|
|
12534
13086
|
function layerEffectsPanel(layer) {
|
|
@@ -12703,6 +13255,32 @@ function effectControlChange(effect, key, value, patterns = []) {
|
|
|
12703
13255
|
return { [top]: setPath(getPath(effect, top), rest, value) };
|
|
12704
13256
|
}
|
|
12705
13257
|
|
|
13258
|
+
// src/image-editor/layers/color-ui.ts
|
|
13259
|
+
var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
|
|
13260
|
+
var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
|
|
13261
|
+
var INTENT_OPTIONS = [
|
|
13262
|
+
{ id: "relative", label: "Relative Colorimetric", title: "Keep in-gamut colours exact, clip the rest (photos)" },
|
|
13263
|
+
{ id: "perceptual", label: "Perceptual", title: "Compress the whole gamut smoothly" },
|
|
13264
|
+
{ id: "saturation", label: "Saturation", title: "Keep colours vivid (graphics)" },
|
|
13265
|
+
{ id: "absolute", label: "Absolute Colorimetric", title: "Keep the source white too (paper proofs)" }
|
|
13266
|
+
];
|
|
13267
|
+
var COLOR_MODE_OPTIONS = [
|
|
13268
|
+
{ id: "rgb", label: "RGB", title: "Edit and export RGB in the working space" },
|
|
13269
|
+
{ id: "cmyk", label: "CMYK", title: "For print: proof through the CMYK profile and export CMYK" },
|
|
13270
|
+
{ id: "lab", label: "Lab", title: "Export Lab channels" }
|
|
13271
|
+
];
|
|
13272
|
+
function colorPanelView(controller) {
|
|
13273
|
+
const profile = controller.getColorProfile();
|
|
13274
|
+
const proof = controller.getState().proofSetup ?? null;
|
|
13275
|
+
return {
|
|
13276
|
+
profileName: profile.name,
|
|
13277
|
+
workingSpace: profile.builtin,
|
|
13278
|
+
mode: profile.mode,
|
|
13279
|
+
cmykProfileName: profile.cmykProfile?.name ?? null,
|
|
13280
|
+
proof: proof ? { id: proof.profile.builtin ?? null, name: proof.profile.name, intent: proof.intent, simulatePaper: proof.simulatePaper, gamutWarning: proof.gamutWarning, bpc: proof.bpc } : null
|
|
13281
|
+
};
|
|
13282
|
+
}
|
|
13283
|
+
|
|
12706
13284
|
// src/image-editor/psd/ui.ts
|
|
12707
13285
|
var PSD_FILE_ACCEPT = ".psd,.psb,image/vnd.adobe.photoshop,application/x-photoshop";
|
|
12708
13286
|
function blobBytes(file) {
|
|
@@ -13315,9 +13893,13 @@ export {
|
|
|
13315
13893
|
AS_SHOT_KELVIN,
|
|
13316
13894
|
BACKGROUND_LAYER_ID,
|
|
13317
13895
|
BACKGROUND_LAYER_NAME,
|
|
13896
|
+
BIT_DEPTHS,
|
|
13897
|
+
BIT_DEPTH_OPTIONS,
|
|
13318
13898
|
BLEND_MODES,
|
|
13319
13899
|
BLUR_FILTER_ID,
|
|
13320
13900
|
BRUSH_OPTION_CONTROLS,
|
|
13901
|
+
BUILTIN_PROFILES,
|
|
13902
|
+
COLOR_MODE_OPTIONS,
|
|
13321
13903
|
CoverageMap,
|
|
13322
13904
|
D50,
|
|
13323
13905
|
D65,
|
|
@@ -13329,6 +13911,7 @@ export {
|
|
|
13329
13911
|
DEFAULT_GLOBAL_LIGHT,
|
|
13330
13912
|
DEFAULT_MITER_LIMIT,
|
|
13331
13913
|
DEFAULT_MIXER,
|
|
13914
|
+
DEFAULT_PROOF,
|
|
13332
13915
|
DEFAULT_REFINE_EDGE_PARAMS,
|
|
13333
13916
|
DEFAULT_RETOUCH,
|
|
13334
13917
|
DEFAULT_SELECTION_TOOL_OPTIONS,
|
|
@@ -13358,6 +13941,8 @@ export {
|
|
|
13358
13941
|
IMAGE_EDITOR_SCHEMA_VERSION,
|
|
13359
13942
|
IMAGE_EDITOR_STATE_VERSION,
|
|
13360
13943
|
IMAGE_FILTER_PRESETS,
|
|
13944
|
+
INTENTS,
|
|
13945
|
+
INTENT_OPTIONS,
|
|
13361
13946
|
INTERPOLATIONS,
|
|
13362
13947
|
ImageEditorController,
|
|
13363
13948
|
ImageEditorRenderer,
|
|
@@ -13391,6 +13976,7 @@ export {
|
|
|
13391
13976
|
PIGMENT_LAMBDA_MIN,
|
|
13392
13977
|
PIGMENT_LAMBDA_STEP,
|
|
13393
13978
|
PIGMENT_WAVELENGTHS,
|
|
13979
|
+
PROOF_PROFILE_OPTIONS,
|
|
13394
13980
|
PSD_BLEND_KEYS,
|
|
13395
13981
|
PSD_FILE_ACCEPT,
|
|
13396
13982
|
PaintExchange,
|
|
@@ -13444,6 +14030,7 @@ export {
|
|
|
13444
14030
|
WARP_STYLES,
|
|
13445
14031
|
WARP_STYLE_LABELS,
|
|
13446
14032
|
WARP_STYLE_OPTIONS,
|
|
14033
|
+
WORKING_SPACE_OPTIONS,
|
|
13447
14034
|
XYZ_D50_TO_SRGB,
|
|
13448
14035
|
ZlibError,
|
|
13449
14036
|
activeAdjustmentLayers,
|
|
@@ -13465,6 +14052,7 @@ export {
|
|
|
13465
14052
|
annotationOfShape,
|
|
13466
14053
|
annotationOfType,
|
|
13467
14054
|
applyAdjustmentLayers,
|
|
14055
|
+
applyAdjustmentLayersFloat,
|
|
13468
14056
|
applyAdjustments,
|
|
13469
14057
|
applyBoxBlur,
|
|
13470
14058
|
applyDepthMask,
|
|
@@ -13517,10 +14105,13 @@ export {
|
|
|
13517
14105
|
cloneSourceLabel,
|
|
13518
14106
|
collectTiles,
|
|
13519
14107
|
colorBalanceChannel,
|
|
14108
|
+
colorModePlanes,
|
|
14109
|
+
colorPanelView,
|
|
13520
14110
|
colorRange,
|
|
13521
14111
|
combineSelections,
|
|
13522
14112
|
compileAdjustmentLayer,
|
|
13523
14113
|
componentPath,
|
|
14114
|
+
compositeDeep,
|
|
13524
14115
|
compositeSurfaceOver,
|
|
13525
14116
|
computeHistogram,
|
|
13526
14117
|
computeSelectionBounds,
|
|
@@ -13530,6 +14121,9 @@ export {
|
|
|
13530
14121
|
contractCoverage,
|
|
13531
14122
|
controlPosition,
|
|
13532
14123
|
controlTrackBackground,
|
|
14124
|
+
convertHex,
|
|
14125
|
+
convertSurfaceColors,
|
|
14126
|
+
convertSurfaceDepth,
|
|
13533
14127
|
convertToSmartObject,
|
|
13534
14128
|
copySmartObject,
|
|
13535
14129
|
cornersFromMatrix,
|
|
@@ -13540,6 +14134,7 @@ export {
|
|
|
13540
14134
|
createBlenderScratch,
|
|
13541
14135
|
createCanvasTextShaper,
|
|
13542
14136
|
createImageCaptureSurface,
|
|
14137
|
+
createImageColorTools,
|
|
13543
14138
|
createImageEditTools,
|
|
13544
14139
|
createImageEditorToolProvider,
|
|
13545
14140
|
createImageEffectTools,
|
|
@@ -13552,6 +14147,7 @@ export {
|
|
|
13552
14147
|
createImageSmartObjectTools,
|
|
13553
14148
|
createImageTransformTools,
|
|
13554
14149
|
createImageTypeTools,
|
|
14150
|
+
createMetricTextShaper,
|
|
13555
14151
|
createOutlineTextShaper,
|
|
13556
14152
|
createPigment,
|
|
13557
14153
|
createPigmentTools,
|
|
@@ -13566,6 +14162,7 @@ export {
|
|
|
13566
14162
|
curveSvgPath,
|
|
13567
14163
|
dabCoverage,
|
|
13568
14164
|
dabRect,
|
|
14165
|
+
decodeDeepSurface,
|
|
13569
14166
|
decodeLayerChannel,
|
|
13570
14167
|
decodeLayerMask,
|
|
13571
14168
|
decodeMergedImage,
|
|
@@ -13573,6 +14170,8 @@ export {
|
|
|
13573
14170
|
decodePng,
|
|
13574
14171
|
decodePngDataUrl,
|
|
13575
14172
|
decodeSelectionRle,
|
|
14173
|
+
deepBytes,
|
|
14174
|
+
deepTile,
|
|
13576
14175
|
defaultAdjustmentParams,
|
|
13577
14176
|
defaultEffectGradient,
|
|
13578
14177
|
defaultLayerEffect,
|
|
@@ -13580,11 +14179,14 @@ export {
|
|
|
13580
14179
|
deflate,
|
|
13581
14180
|
deflateRaw,
|
|
13582
14181
|
depthMaskAlpha,
|
|
14182
|
+
depthOf,
|
|
13583
14183
|
depthRasterMask,
|
|
13584
14184
|
describeLayer,
|
|
13585
14185
|
describeLayerEffects,
|
|
13586
14186
|
describeSelection,
|
|
13587
14187
|
describeTransform,
|
|
14188
|
+
deserializeColorMode,
|
|
14189
|
+
deserializeColorProfile,
|
|
13588
14190
|
deserializeEffects,
|
|
13589
14191
|
deserializeLayer,
|
|
13590
14192
|
deserializeLayers,
|
|
@@ -13594,8 +14196,10 @@ export {
|
|
|
13594
14196
|
developFromAdjustments,
|
|
13595
14197
|
developTarget,
|
|
13596
14198
|
dilateMask,
|
|
14199
|
+
displayTransform,
|
|
13597
14200
|
distanceTransform,
|
|
13598
14201
|
documentContents,
|
|
14202
|
+
documentProfile,
|
|
13599
14203
|
dodgeBurn,
|
|
13600
14204
|
dodgeBurnCurve,
|
|
13601
14205
|
downloadPsd,
|
|
@@ -13607,6 +14211,7 @@ export {
|
|
|
13607
14211
|
effectColorHex,
|
|
13608
14212
|
effectControlChange,
|
|
13609
14213
|
effectReach,
|
|
14214
|
+
effectiveProof,
|
|
13610
14215
|
effectsFingerprint,
|
|
13611
14216
|
effectsMargin,
|
|
13612
14217
|
effectsScale,
|
|
@@ -13614,6 +14219,7 @@ export {
|
|
|
13614
14219
|
ellipseSelection,
|
|
13615
14220
|
emptyHistogram,
|
|
13616
14221
|
emptySurface,
|
|
14222
|
+
encodeDeepSurface,
|
|
13617
14223
|
encodePng,
|
|
13618
14224
|
encodeRle,
|
|
13619
14225
|
encodeSelectionRle,
|
|
@@ -13689,6 +14295,7 @@ export {
|
|
|
13689
14295
|
invertSelection,
|
|
13690
14296
|
isActiveFilter,
|
|
13691
14297
|
isAdjustmentKind,
|
|
14298
|
+
isBitDepth,
|
|
13692
14299
|
isBlendMode,
|
|
13693
14300
|
isContentsDecoded,
|
|
13694
14301
|
isDefaultDepthMask,
|
|
@@ -13709,6 +14316,7 @@ export {
|
|
|
13709
14316
|
isSelectionMode,
|
|
13710
14317
|
isSeparableBlendMode,
|
|
13711
14318
|
isSpatialFilter,
|
|
14319
|
+
isSrgb,
|
|
13712
14320
|
isTransformAnchor,
|
|
13713
14321
|
isValidWarp,
|
|
13714
14322
|
kelvinToTemperature,
|
|
@@ -13746,6 +14354,7 @@ export {
|
|
|
13746
14354
|
liveShapeSubpaths,
|
|
13747
14355
|
loadImageEditorDocument,
|
|
13748
14356
|
loadMixer,
|
|
14357
|
+
loadOpenTypeFont,
|
|
13749
14358
|
luma,
|
|
13750
14359
|
magicWand,
|
|
13751
14360
|
mapCropHandle,
|
|
@@ -13812,6 +14421,7 @@ export {
|
|
|
13812
14421
|
parseEffectColor,
|
|
13813
14422
|
parseLfx2,
|
|
13814
14423
|
parseLrfx,
|
|
14424
|
+
parseOpenTypeFont,
|
|
13815
14425
|
parsePatternBlock,
|
|
13816
14426
|
parseSelectionMode,
|
|
13817
14427
|
parseVersionedDescriptor,
|
|
@@ -13834,10 +14444,12 @@ export {
|
|
|
13834
14444
|
posterizeValue,
|
|
13835
14445
|
presetWarp,
|
|
13836
14446
|
previewStep,
|
|
14447
|
+
profileBytes,
|
|
13837
14448
|
projectImagePoint,
|
|
13838
14449
|
projectImageRect,
|
|
13839
14450
|
projectMaskCoverage,
|
|
13840
14451
|
projectQuarterTurn,
|
|
14452
|
+
proxyOf,
|
|
13841
14453
|
psdBytesFromBase64,
|
|
13842
14454
|
psdFileName,
|
|
13843
14455
|
psdPatternToEffectPattern,
|
|
@@ -13851,6 +14463,7 @@ export {
|
|
|
13851
14463
|
rasterizeDab,
|
|
13852
14464
|
rasterizeSmartObject,
|
|
13853
14465
|
readAdjustmentControls,
|
|
14466
|
+
readDeepRegion,
|
|
13854
14467
|
readPixel,
|
|
13855
14468
|
readPsd,
|
|
13856
14469
|
readRegion,
|
|
@@ -13891,6 +14504,7 @@ export {
|
|
|
13891
14504
|
resizeWarpMesh,
|
|
13892
14505
|
resolveExternalAssets,
|
|
13893
14506
|
resolveMosaicRegionBounds,
|
|
14507
|
+
resolveProfile,
|
|
13894
14508
|
restyleRange,
|
|
13895
14509
|
rgbToGray,
|
|
13896
14510
|
rgbToHsl,
|
|
@@ -13912,6 +14526,8 @@ export {
|
|
|
13912
14526
|
selectionToCoverage,
|
|
13913
14527
|
selectionToPixels,
|
|
13914
14528
|
selectionValueAt,
|
|
14529
|
+
serializeColorMode,
|
|
14530
|
+
serializeColorProfile,
|
|
13915
14531
|
serializeContents,
|
|
13916
14532
|
serializeEffects,
|
|
13917
14533
|
serializeLayer,
|
|
@@ -13951,11 +14567,15 @@ export {
|
|
|
13951
14567
|
spotHealPixels,
|
|
13952
14568
|
spotHealWindow,
|
|
13953
14569
|
srgb8ToLab,
|
|
14570
|
+
srgbDecode,
|
|
14571
|
+
srgbEncode,
|
|
13954
14572
|
srgbToLinear,
|
|
13955
14573
|
standardBlendMode,
|
|
13956
14574
|
styleAt,
|
|
13957
14575
|
sumHistograms,
|
|
13958
14576
|
surfaceBytes,
|
|
14577
|
+
surfaceDepth,
|
|
14578
|
+
surfaceFromDeepPixels,
|
|
13959
14579
|
surfaceFromPixels,
|
|
13960
14580
|
surfacesEqual,
|
|
13961
14581
|
tempTintToXy,
|
|
@@ -13967,10 +14587,19 @@ export {
|
|
|
13967
14587
|
tileCoord,
|
|
13968
14588
|
tileKey,
|
|
13969
14589
|
tileRect,
|
|
14590
|
+
tileSamples,
|
|
14591
|
+
tileSamples16,
|
|
14592
|
+
tileSamples32,
|
|
13970
14593
|
tilesInRect,
|
|
13971
14594
|
tipFalloff,
|
|
13972
14595
|
tipReach,
|
|
13973
14596
|
tipShape,
|
|
14597
|
+
to16From32,
|
|
14598
|
+
to16From8,
|
|
14599
|
+
to32From16,
|
|
14600
|
+
to32From8,
|
|
14601
|
+
to8From16,
|
|
14602
|
+
to8From32,
|
|
13974
14603
|
toHex,
|
|
13975
14604
|
toTextSpace,
|
|
13976
14605
|
toneCurve,
|
|
@@ -14020,6 +14649,7 @@ export {
|
|
|
14020
14649
|
withFilterMaskSurface,
|
|
14021
14650
|
withNewIds,
|
|
14022
14651
|
writeAdjustmentBlock,
|
|
14652
|
+
writeDeepRegion,
|
|
14023
14653
|
writeLfx2,
|
|
14024
14654
|
writePatternBlock,
|
|
14025
14655
|
writePsd,
|