@pixerate/editor 0.246.0 → 0.249.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/README.md +1 -0
- package/dist/animation-editor/index.cjs +64 -61
- package/dist/animation-editor/index.js +8 -5
- package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-GCKK7V2I.cjs} +14 -11
- package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-T3JZST44.js} +7 -4
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-UVPD55UZ.cjs → chunk-2SMMZDMG.cjs} +35 -35
- package/dist/chunk-2VJAVXLI.js +192 -0
- package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
- package/dist/chunk-3K6HWEXZ.cjs +92 -0
- package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
- package/dist/chunk-4D6KP5BV.js +92 -0
- package/dist/chunk-5RH3VXAK.js +269 -0
- package/dist/{chunk-LDPLEZ5T.js → chunk-6BIDVPED.js} +1 -1
- package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
- package/dist/chunk-BOHDJJ2O.cjs +192 -0
- package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
- package/dist/{chunk-DQWPMGH2.js → chunk-DOIU7VJG.js} +1 -1
- package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
- package/dist/chunk-EJLRBS5Q.js +301 -0
- package/dist/{chunk-Q2UYUWAZ.cjs → chunk-H4AOUUBE.cjs} +679 -164
- package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
- package/dist/{chunk-FK5LTDOO.cjs → chunk-IOFVM3L3.cjs} +7 -7
- package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
- package/dist/{chunk-VDAWA546.js → chunk-J7T5QZ45.js} +614 -99
- package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
- package/dist/{chunk-5MFDD7SP.cjs → chunk-KYX7NZ5V.cjs} +1 -1
- package/dist/chunk-LJRCU3BJ.cjs +301 -0
- package/dist/{chunk-XTWXBQD4.cjs → chunk-LP2MCSBE.cjs} +593 -236
- package/dist/{chunk-A23PSOBB.js → chunk-O75V4ZS3.js} +1 -1
- package/dist/chunk-OTTT5N3K.js +322 -0
- package/dist/{chunk-N6WUB3Y5.js → chunk-PZP2SZIZ.js} +2 -2
- package/dist/{chunk-4PMCMWQS.js → chunk-UBRJOIR5.js} +367 -10
- package/dist/chunk-W5M3J7PV.cjs +322 -0
- package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
- package/dist/{chunk-CEPKXLBS.cjs → chunk-WLJZZHUZ.cjs} +23 -23
- package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
- package/dist/chunk-ZEYMKDYS.cjs +269 -0
- package/dist/image-editor/effect-tools.d.cts +37 -4
- package/dist/image-editor/effect-tools.d.ts +37 -4
- package/dist/image-editor/index.cjs +1340 -1828
- package/dist/image-editor/index.d.cts +1 -1
- package/dist/image-editor/index.d.ts +1 -1
- package/dist/image-editor/index.js +298 -786
- package/dist/paint/index.cjs +8 -5
- package/dist/paint/index.js +13 -10
- package/dist/paint-editor/controller.d.cts +71 -2
- package/dist/paint-editor/controller.d.ts +71 -2
- package/dist/paint-editor/index.cjs +901 -589
- package/dist/paint-editor/index.d.cts +3 -0
- package/dist/paint-editor/index.d.ts +3 -0
- package/dist/paint-editor/index.js +365 -53
- package/dist/paint-editor/procedural.d.cts +82 -5
- package/dist/paint-editor/procedural.d.ts +82 -5
- package/dist/paint-editor/sticker-art.d.cts +55 -0
- package/dist/paint-editor/sticker-art.d.ts +55 -0
- package/dist/paint-editor/stickers.d.cts +30 -17
- package/dist/paint-editor/stickers.d.ts +30 -17
- package/dist/paint-editor/stroke.d.cts +4 -0
- package/dist/paint-editor/stroke.d.ts +4 -0
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/paint-editor/ui.d.cts +25 -4
- package/dist/paint-editor/ui.d.ts +25 -4
- package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.cts} +32 -5
- package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.ts} +32 -5
- package/dist/raster/index.cjs +17 -3
- package/dist/raster/index.d.cts +1 -0
- package/dist/raster/index.d.ts +1 -0
- package/dist/raster/index.js +23 -9
- package/dist/stickers/browser.d.cts +48 -0
- package/dist/stickers/browser.d.ts +48 -0
- package/dist/stickers/combine.d.cts +10 -0
- package/dist/stickers/combine.d.ts +10 -0
- package/dist/stickers/conformance.d.cts +18 -0
- package/dist/stickers/conformance.d.ts +18 -0
- package/dist/stickers/editor.d.cts +14 -0
- package/dist/stickers/editor.d.ts +14 -0
- package/dist/stickers/errors.d.cts +6 -0
- package/dist/stickers/errors.d.ts +6 -0
- package/dist/stickers/fake.d.cts +16 -0
- package/dist/stickers/fake.d.ts +16 -0
- package/dist/stickers/helpers.d.cts +51 -0
- package/dist/stickers/helpers.d.ts +51 -0
- package/dist/stickers/index.cjs +331 -0
- package/dist/stickers/index.d.cts +16 -0
- package/dist/stickers/index.d.ts +16 -0
- package/dist/stickers/index.js +331 -0
- package/dist/stickers/stamps.d.cts +13 -0
- package/dist/stickers/stamps.d.ts +13 -0
- package/dist/stickers/tools.d.cts +25 -0
- package/dist/stickers/tools.d.ts +25 -0
- package/dist/stickers/types.d.cts +123 -0
- package/dist/stickers/types.d.ts +123 -0
- package/dist/vector/index.cjs +978 -975
- package/dist/vector/index.js +9 -6
- package/package.json +11 -1
- package/skills/README.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +26 -32
- package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
- package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
- package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
- package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
- package/skills/pixerate-stickers/SKILL.md +45 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
parseOpenTypeFont,
|
|
9
9
|
removeAnchorsKeepingShape,
|
|
10
10
|
traceField
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-DOIU7VJG.js";
|
|
12
12
|
import {
|
|
13
13
|
ColorGmm,
|
|
14
14
|
GAMMA,
|
|
@@ -153,6 +153,8 @@ import {
|
|
|
153
153
|
copySmartObject,
|
|
154
154
|
cornersFromMatrix,
|
|
155
155
|
createAdjustmentLayer,
|
|
156
|
+
createImageEffectTools,
|
|
157
|
+
createLayerEffectTools,
|
|
156
158
|
createShapeLayer,
|
|
157
159
|
createTypeLayer,
|
|
158
160
|
curveLutFromLevels,
|
|
@@ -167,6 +169,7 @@ import {
|
|
|
167
169
|
defaultShapeName,
|
|
168
170
|
depthMaskAlpha,
|
|
169
171
|
depthRasterMask,
|
|
172
|
+
describeLayerEffects,
|
|
170
173
|
describeTransform,
|
|
171
174
|
deserializeEffects,
|
|
172
175
|
deserializeLayer,
|
|
@@ -410,7 +413,7 @@ import {
|
|
|
410
413
|
writePsd,
|
|
411
414
|
xyToTempTint,
|
|
412
415
|
xyToUv
|
|
413
|
-
} from "../chunk-
|
|
416
|
+
} from "../chunk-UBRJOIR5.js";
|
|
414
417
|
import {
|
|
415
418
|
parseCssColor
|
|
416
419
|
} from "../chunk-3CI7FRMK.js";
|
|
@@ -465,6 +468,13 @@ import {
|
|
|
465
468
|
import {
|
|
466
469
|
createCaptureTool
|
|
467
470
|
} from "../chunk-5ED73EC6.js";
|
|
471
|
+
import {
|
|
472
|
+
LAYER_EFFECT_MENU,
|
|
473
|
+
effectControlChange,
|
|
474
|
+
layerEffectControls,
|
|
475
|
+
layerEffectsBadge,
|
|
476
|
+
layerEffectsPanel
|
|
477
|
+
} from "../chunk-2VJAVXLI.js";
|
|
468
478
|
import {
|
|
469
479
|
DEFAULT_GLOBAL_LIGHT,
|
|
470
480
|
INTERPOLATIONS,
|
|
@@ -514,7 +524,7 @@ import {
|
|
|
514
524
|
validateLayerEffects,
|
|
515
525
|
warpSurface,
|
|
516
526
|
workingToSamples
|
|
517
|
-
} from "../chunk-
|
|
527
|
+
} from "../chunk-3PPJRMIG.js";
|
|
518
528
|
import {
|
|
519
529
|
applyHomography,
|
|
520
530
|
boxQuad,
|
|
@@ -559,7 +569,7 @@ import {
|
|
|
559
569
|
spotHealPixels,
|
|
560
570
|
spotHealWindow,
|
|
561
571
|
toneOf
|
|
562
|
-
} from "../chunk-
|
|
572
|
+
} from "../chunk-WA44NKPF.js";
|
|
563
573
|
import {
|
|
564
574
|
bestOffset,
|
|
565
575
|
contentAwareFill,
|
|
@@ -664,7 +674,7 @@ import {
|
|
|
664
674
|
wetGpuSupport,
|
|
665
675
|
wetSimdSupported,
|
|
666
676
|
wetSupport
|
|
667
|
-
} from "../chunk-
|
|
677
|
+
} from "../chunk-WQCNC4DK.js";
|
|
668
678
|
import {
|
|
669
679
|
BUILTIN_PROFILES,
|
|
670
680
|
CmsError,
|
|
@@ -733,8 +743,9 @@ import {
|
|
|
733
743
|
warpMeshParamAt,
|
|
734
744
|
warpMeshRows,
|
|
735
745
|
warpPresetMesh
|
|
736
|
-
} from "../chunk-
|
|
737
|
-
import "../chunk-
|
|
746
|
+
} from "../chunk-PZP2SZIZ.js";
|
|
747
|
+
import "../chunk-J7T5QZ45.js";
|
|
748
|
+
import "../chunk-5RH3VXAK.js";
|
|
738
749
|
import "../chunk-M6DNZNVY.js";
|
|
739
750
|
import {
|
|
740
751
|
bezierPathToSvg,
|
|
@@ -792,7 +803,6 @@ import {
|
|
|
792
803
|
StrokeCoverage,
|
|
793
804
|
TIP_GRADIENT_STEPS,
|
|
794
805
|
TileMedium,
|
|
795
|
-
TileableNoise,
|
|
796
806
|
addPaintGradientStop,
|
|
797
807
|
applyStrokeToDeepTile,
|
|
798
808
|
applyStrokeToTile,
|
|
@@ -812,12 +822,10 @@ import {
|
|
|
812
822
|
gradientDabColor,
|
|
813
823
|
grainCatch,
|
|
814
824
|
grainHeights,
|
|
815
|
-
hash2,
|
|
816
825
|
hexToPaintRgb,
|
|
817
826
|
isBrushstrokeBrush,
|
|
818
827
|
isGradientPaint,
|
|
819
828
|
loadMixer,
|
|
820
|
-
mix32,
|
|
821
829
|
mixerRates,
|
|
822
830
|
normalizeBlender,
|
|
823
831
|
normalizeBrush,
|
|
@@ -832,8 +840,6 @@ import {
|
|
|
832
840
|
pathStrokeCoverage,
|
|
833
841
|
pathStrokeDabs,
|
|
834
842
|
put255,
|
|
835
|
-
rand01,
|
|
836
|
-
randSigned,
|
|
837
843
|
rasterizeDab,
|
|
838
844
|
readPaintSource,
|
|
839
845
|
removePaintGradientStop,
|
|
@@ -841,7 +847,6 @@ import {
|
|
|
841
847
|
resolvePaintGradient,
|
|
842
848
|
reversePaintGradient,
|
|
843
849
|
scalePaintGradient,
|
|
844
|
-
seedFromString,
|
|
845
850
|
smoothPoints,
|
|
846
851
|
solidPaint,
|
|
847
852
|
strokeGrainCatch,
|
|
@@ -850,7 +855,15 @@ import {
|
|
|
850
855
|
tipShape,
|
|
851
856
|
updatePaintGradientStop,
|
|
852
857
|
walkDabs
|
|
853
|
-
} from "../chunk-
|
|
858
|
+
} from "../chunk-D5KGAO4Z.js";
|
|
859
|
+
import {
|
|
860
|
+
TileableNoise,
|
|
861
|
+
hash2,
|
|
862
|
+
mix32,
|
|
863
|
+
rand01,
|
|
864
|
+
randSigned,
|
|
865
|
+
seedFromString
|
|
866
|
+
} from "../chunk-4D6KP5BV.js";
|
|
854
867
|
import {
|
|
855
868
|
BRUSHSTROKE_MAX_SCALE,
|
|
856
869
|
BRUSHSTROKE_MIN_SCALE,
|
|
@@ -865,25 +878,20 @@ import {
|
|
|
865
878
|
PIGMENT_LAMBDA_STEP,
|
|
866
879
|
PIGMENT_WAVELENGTHS,
|
|
867
880
|
SHADOW_AMBIENT,
|
|
868
|
-
base64ToBytes,
|
|
869
881
|
blendChannel,
|
|
870
882
|
blendImageData,
|
|
871
883
|
blendLum,
|
|
872
884
|
blendPixel,
|
|
873
885
|
blendRgb,
|
|
874
|
-
bytesToBase64,
|
|
875
886
|
canvasCompositeOperation,
|
|
876
887
|
convertSurfaceDepth,
|
|
877
888
|
createPigment,
|
|
878
|
-
decodePng,
|
|
879
889
|
deepBytes,
|
|
880
890
|
deepTile,
|
|
881
891
|
depthOf,
|
|
882
|
-
encodePng,
|
|
883
892
|
isBitDepth,
|
|
884
893
|
isBlendMode,
|
|
885
894
|
isPainterlyBlendMode,
|
|
886
|
-
isPng,
|
|
887
895
|
isSeparableBlendMode,
|
|
888
896
|
keepDeepSamples,
|
|
889
897
|
lerpPigment,
|
|
@@ -892,9 +900,7 @@ import {
|
|
|
892
900
|
mixPigmentRgb,
|
|
893
901
|
mixPigments,
|
|
894
902
|
normalizeBlendMode,
|
|
895
|
-
parseDataUrl,
|
|
896
903
|
pigment8,
|
|
897
|
-
pngDataUrl,
|
|
898
904
|
proxyOf,
|
|
899
905
|
readDeepRegion,
|
|
900
906
|
reflectanceToRgb,
|
|
@@ -916,7 +922,16 @@ import {
|
|
|
916
922
|
to8From16,
|
|
917
923
|
to8From32,
|
|
918
924
|
writeDeepRegion
|
|
919
|
-
} from "../chunk-
|
|
925
|
+
} from "../chunk-IRSTHLQQ.js";
|
|
926
|
+
import {
|
|
927
|
+
base64ToBytes,
|
|
928
|
+
bytesToBase64,
|
|
929
|
+
decodePng,
|
|
930
|
+
encodePng,
|
|
931
|
+
isPng,
|
|
932
|
+
parseDataUrl,
|
|
933
|
+
pngDataUrl
|
|
934
|
+
} from "../chunk-OTTT5N3K.js";
|
|
920
935
|
import {
|
|
921
936
|
SurfaceDraft,
|
|
922
937
|
TILE,
|
|
@@ -1686,13 +1701,13 @@ var ImageEditorRenderer = class {
|
|
|
1686
1701
|
ctx.save();
|
|
1687
1702
|
try {
|
|
1688
1703
|
applyImageProjectionToContext(ctx, projection);
|
|
1689
|
-
const
|
|
1704
|
+
const px = u / (projection.scale || 1);
|
|
1690
1705
|
ctx.beginPath();
|
|
1691
|
-
ctx.arc(b.x, b.y, Math.max(
|
|
1692
|
-
ctx.lineWidth = 2 *
|
|
1706
|
+
ctx.arc(b.x, b.y, Math.max(px, b.diameter / 2), 0, Math.PI * 2);
|
|
1707
|
+
ctx.lineWidth = 2 * px;
|
|
1693
1708
|
ctx.strokeStyle = "rgba(0,0,0,0.6)";
|
|
1694
1709
|
ctx.stroke();
|
|
1695
|
-
ctx.lineWidth =
|
|
1710
|
+
ctx.lineWidth = px;
|
|
1696
1711
|
ctx.strokeStyle = "#ffffff";
|
|
1697
1712
|
ctx.stroke();
|
|
1698
1713
|
} catch {
|
|
@@ -2239,32 +2254,32 @@ var ImageEditorRenderer = class {
|
|
|
2239
2254
|
this.outlineCache.set(selection, paths);
|
|
2240
2255
|
}
|
|
2241
2256
|
if (!paths.length) return;
|
|
2242
|
-
const
|
|
2257
|
+
const px = 1 / (scale || 1);
|
|
2243
2258
|
ctx.beginPath();
|
|
2244
2259
|
for (const p of paths) {
|
|
2245
2260
|
ctx.moveTo(p[0], p[1]);
|
|
2246
2261
|
for (let i = 2; i < p.length; i += 2) ctx.lineTo(p[i], p[i + 1]);
|
|
2247
2262
|
}
|
|
2248
|
-
ctx.lineWidth =
|
|
2263
|
+
ctx.lineWidth = px;
|
|
2249
2264
|
ctx.strokeStyle = "#ffffff";
|
|
2250
2265
|
ctx.stroke();
|
|
2251
2266
|
if (typeof ctx.setLineDash === "function") {
|
|
2252
|
-
ctx.setLineDash([4 *
|
|
2253
|
-
ctx.lineDashOffset = -offset *
|
|
2267
|
+
ctx.setLineDash([4 * px, 4 * px]);
|
|
2268
|
+
ctx.lineDashOffset = -offset * px;
|
|
2254
2269
|
}
|
|
2255
2270
|
ctx.strokeStyle = "#000000";
|
|
2256
2271
|
ctx.stroke();
|
|
2257
2272
|
if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
|
|
2258
2273
|
}
|
|
2259
2274
|
drawDraftPath(ctx, points, scale) {
|
|
2260
|
-
const
|
|
2275
|
+
const px = 1 / (scale || 1);
|
|
2261
2276
|
ctx.beginPath();
|
|
2262
2277
|
points.forEach((p, i) => i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y));
|
|
2263
2278
|
ctx.closePath();
|
|
2264
|
-
ctx.lineWidth =
|
|
2279
|
+
ctx.lineWidth = px;
|
|
2265
2280
|
ctx.strokeStyle = "#ffffff";
|
|
2266
2281
|
ctx.stroke();
|
|
2267
|
-
if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 *
|
|
2282
|
+
if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px, 4 * px]);
|
|
2268
2283
|
ctx.strokeStyle = "#000000";
|
|
2269
2284
|
ctx.stroke();
|
|
2270
2285
|
if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
|
|
@@ -2929,9 +2944,9 @@ function inspectMaskEdge(mask, image, options = {}) {
|
|
|
2929
2944
|
turnExcess += Math.max(0, total - closure);
|
|
2930
2945
|
outline += L;
|
|
2931
2946
|
for (let i = 0; i < n; i++) {
|
|
2932
|
-
const [
|
|
2933
|
-
if (
|
|
2934
|
-
const blk = block(Math.floor(
|
|
2947
|
+
const [px, py] = pts[i];
|
|
2948
|
+
if (px < 0 || py < 0 || px >= W || py >= H) continue;
|
|
2949
|
+
const blk = block(Math.floor(px), Math.floor(py));
|
|
2935
2950
|
blk.turn += Math.abs(turns[i]) - closure / n;
|
|
2936
2951
|
blk.len += 2;
|
|
2937
2952
|
}
|
|
@@ -4118,10 +4133,10 @@ function liveWire(map, from, to, band) {
|
|
|
4118
4133
|
const uy = (by - ay) / len;
|
|
4119
4134
|
for (let y = 0; y < h; y++) {
|
|
4120
4135
|
for (let x = 0; x < w; x++) {
|
|
4121
|
-
const
|
|
4136
|
+
const px = rx0 + x - ax;
|
|
4122
4137
|
const py = ry0 + y - ay;
|
|
4123
|
-
const t = Math.min(len, Math.max(0,
|
|
4124
|
-
if (Math.hypot(
|
|
4138
|
+
const t = Math.min(len, Math.max(0, px * ux + py * uy));
|
|
4139
|
+
if (Math.hypot(px - t * ux, py - t * uy) > half) continue;
|
|
4125
4140
|
const i = y * w + x;
|
|
4126
4141
|
inside[i] = 1;
|
|
4127
4142
|
const f = map.features(rx0 + x, ry0 + y);
|
|
@@ -5015,43 +5030,43 @@ function liftPixels(surface, sel, o) {
|
|
|
5015
5030
|
const area = { x: sb.x - o.x, y: sb.y - o.y, width: sb.width, height: sb.height };
|
|
5016
5031
|
const depth = surfaceDepth(surface);
|
|
5017
5032
|
if (depth !== 8) {
|
|
5018
|
-
const
|
|
5019
|
-
const kept2 =
|
|
5033
|
+
const px2 = readDeepRegion(surface, area, depth);
|
|
5034
|
+
const kept2 = px2.slice();
|
|
5020
5035
|
const r16 = depth === 16;
|
|
5021
5036
|
for (let y = 0; y < area.height; y++) {
|
|
5022
5037
|
for (let x = 0; x < area.width; x++) {
|
|
5023
5038
|
const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
|
|
5024
5039
|
const i = (y * area.width + x) * 4;
|
|
5025
5040
|
if (k <= 0) {
|
|
5026
|
-
|
|
5041
|
+
px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
|
|
5027
5042
|
continue;
|
|
5028
5043
|
}
|
|
5029
|
-
|
|
5030
|
-
if (!
|
|
5044
|
+
px2[i + 3] = r16 ? Math.round(px2[i + 3] * k) : px2[i + 3] * k;
|
|
5045
|
+
if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
|
|
5031
5046
|
kept2[i + 3] = r16 ? Math.round(kept2[i + 3] * (1 - k)) : kept2[i + 3] * (1 - k);
|
|
5032
5047
|
if (!kept2[i + 3]) kept2[i] = kept2[i + 1] = kept2[i + 2] = 0;
|
|
5033
5048
|
}
|
|
5034
5049
|
}
|
|
5035
|
-
const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area,
|
|
5050
|
+
const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px2);
|
|
5036
5051
|
return { lifted, rest: writeDeepRegion(surface, area, kept2) };
|
|
5037
5052
|
}
|
|
5038
|
-
const
|
|
5039
|
-
const kept = new Uint8ClampedArray(
|
|
5053
|
+
const px = readRegion(surface, area);
|
|
5054
|
+
const kept = new Uint8ClampedArray(px);
|
|
5040
5055
|
for (let y = 0; y < area.height; y++) {
|
|
5041
5056
|
for (let x = 0; x < area.width; x++) {
|
|
5042
5057
|
const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
|
|
5043
5058
|
const i = (y * area.width + x) * 4;
|
|
5044
5059
|
if (k <= 0) {
|
|
5045
|
-
|
|
5060
|
+
px[i] = px[i + 1] = px[i + 2] = px[i + 3] = 0;
|
|
5046
5061
|
continue;
|
|
5047
5062
|
}
|
|
5048
|
-
|
|
5049
|
-
if (!
|
|
5063
|
+
px[i + 3] = px[i + 3] * k;
|
|
5064
|
+
if (!px[i + 3]) px[i] = px[i + 1] = px[i + 2] = 0;
|
|
5050
5065
|
kept[i + 3] = kept[i + 3] * (1 - k);
|
|
5051
5066
|
if (!kept[i + 3]) kept[i] = kept[i + 1] = kept[i + 2] = 0;
|
|
5052
5067
|
}
|
|
5053
5068
|
}
|
|
5054
|
-
return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data:
|
|
5069
|
+
return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
|
|
5055
5070
|
}
|
|
5056
5071
|
function liftMask(mask, sel, o) {
|
|
5057
5072
|
const sb = sel.bounds;
|
|
@@ -5642,14 +5657,14 @@ function displayTransform(doc, proof) {
|
|
|
5642
5657
|
const g = gamut;
|
|
5643
5658
|
return (rgba) => {
|
|
5644
5659
|
if (g) {
|
|
5645
|
-
const
|
|
5660
|
+
const px = [0, 0, 0];
|
|
5646
5661
|
const flags = new Uint8Array(rgba.length >> 2);
|
|
5647
5662
|
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
|
|
5648
5663
|
if (rgba[i + 3] === 0) continue;
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
if (g.outOfGamut(
|
|
5664
|
+
px[0] = rgba[i] / 255;
|
|
5665
|
+
px[1] = rgba[i + 1] / 255;
|
|
5666
|
+
px[2] = rgba[i + 2] / 255;
|
|
5667
|
+
if (g.outOfGamut(px)) flags[p] = 1;
|
|
5653
5668
|
}
|
|
5654
5669
|
tr.convert8(rgba, 4, rgba, 4);
|
|
5655
5670
|
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) if (flags[p]) rgba[i] = rgba[i + 1] = rgba[i + 2] = 128;
|
|
@@ -6453,12 +6468,12 @@ var ImageEditorController = class {
|
|
|
6453
6468
|
} else {
|
|
6454
6469
|
const sb = sel.bounds;
|
|
6455
6470
|
const src = { x: sb.x - layer.offset.x, y: sb.y - layer.offset.y, width: sb.width, height: sb.height };
|
|
6456
|
-
const
|
|
6471
|
+
const px = readRegion(surface, src);
|
|
6457
6472
|
const data = sel.data;
|
|
6458
6473
|
for (let y = 0; y < sb.height; y++) {
|
|
6459
|
-
for (let x = 0; x < sb.width; x++)
|
|
6474
|
+
for (let x = 0; x < sb.width; x++) px[(y * sb.width + x) * 4 + 3] = Math.round(px[(y * sb.width + x) * 4 + 3] * (data[(sb.y + y) * width + sb.x + x] / 255));
|
|
6460
6475
|
}
|
|
6461
|
-
copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data:
|
|
6476
|
+
copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y) };
|
|
6462
6477
|
delete copy.mask;
|
|
6463
6478
|
}
|
|
6464
6479
|
delete copy.source;
|
|
@@ -7109,9 +7124,9 @@ var ImageEditorController = class {
|
|
|
7109
7124
|
const bounds = this.getLayerBounds(layer.id);
|
|
7110
7125
|
if (bounds && point2.x >= bounds.x && point2.x <= bounds.x + bounds.width && point2.y >= bounds.y && point2.y <= bounds.y + bounds.height) {
|
|
7111
7126
|
const surface = this.surfaceOf(layer);
|
|
7112
|
-
const
|
|
7127
|
+
const px = Math.floor(point2.x - layer.offset.x);
|
|
7113
7128
|
const py = Math.floor(point2.y - layer.offset.y);
|
|
7114
|
-
const pixel = readPixel(surface,
|
|
7129
|
+
const pixel = readPixel(surface, px, py);
|
|
7115
7130
|
if (pixel.length >= 4 && pixel[3] >= alphaThreshold) return layer.id;
|
|
7116
7131
|
}
|
|
7117
7132
|
return null;
|
|
@@ -7123,9 +7138,9 @@ var ImageEditorController = class {
|
|
|
7123
7138
|
return null;
|
|
7124
7139
|
}
|
|
7125
7140
|
const surface = this.surfaceOf(layer);
|
|
7126
|
-
const
|
|
7141
|
+
const px = Math.floor(point2.x - layer.offset.x);
|
|
7127
7142
|
const py = Math.floor(point2.y - layer.offset.y);
|
|
7128
|
-
const pixel = readPixel(surface,
|
|
7143
|
+
const pixel = readPixel(surface, px, py);
|
|
7129
7144
|
if (pixel.length >= 4 && pixel[3] >= alphaThreshold) {
|
|
7130
7145
|
return layer.id;
|
|
7131
7146
|
}
|
|
@@ -7276,17 +7291,17 @@ var ImageEditorController = class {
|
|
|
7276
7291
|
*/
|
|
7277
7292
|
sourceSurface() {
|
|
7278
7293
|
const { width, height } = this.naturalSize;
|
|
7279
|
-
const fromPixels = (
|
|
7280
|
-
let s = this.sourceSurfaces.get(
|
|
7294
|
+
const fromPixels = (px2) => {
|
|
7295
|
+
let s = this.sourceSurfaces.get(px2);
|
|
7281
7296
|
if (!s) {
|
|
7282
|
-
s = surfaceFromPixels(
|
|
7283
|
-
this.sourceSurfaces.set(
|
|
7297
|
+
s = surfaceFromPixels(px2, 4);
|
|
7298
|
+
this.sourceSurfaces.set(px2, s);
|
|
7284
7299
|
}
|
|
7285
7300
|
return s;
|
|
7286
7301
|
};
|
|
7287
|
-
const
|
|
7288
|
-
const fits = Boolean(
|
|
7289
|
-
if (this.samplePixelsOverride && fits) return fromPixels(
|
|
7302
|
+
const px = this.samplePixels;
|
|
7303
|
+
const fits = Boolean(px && px.width === width && px.height === height);
|
|
7304
|
+
if (this.samplePixelsOverride && fits) return fromPixels(px);
|
|
7290
7305
|
const el = this.imageElement;
|
|
7291
7306
|
if (el) {
|
|
7292
7307
|
const cached = this.sourceSurfaces.get(el);
|
|
@@ -7300,7 +7315,7 @@ var ImageEditorController = class {
|
|
|
7300
7315
|
return s;
|
|
7301
7316
|
}
|
|
7302
7317
|
}
|
|
7303
|
-
return fits ? fromPixels(
|
|
7318
|
+
return fits ? fromPixels(px) : null;
|
|
7304
7319
|
}
|
|
7305
7320
|
opaqueCache = /* @__PURE__ */ new WeakMap();
|
|
7306
7321
|
/** Whether every source pixel is opaque (some legacy renders depend on it). */
|
|
@@ -7362,11 +7377,11 @@ var ImageEditorController = class {
|
|
|
7362
7377
|
const { width, height } = this.naturalSize;
|
|
7363
7378
|
let surface = emptySurface(4);
|
|
7364
7379
|
if (init.pixels) {
|
|
7365
|
-
const
|
|
7366
|
-
if (!(
|
|
7380
|
+
const px = init.pixels;
|
|
7381
|
+
if (!(px.width > 0 && px.height > 0) || px.data.length < px.width * px.height * 4) {
|
|
7367
7382
|
throw new LayerOperationError("pixels must be RGBA with width \xD7 height \xD7 4 bytes.");
|
|
7368
7383
|
}
|
|
7369
|
-
surface = surfaceFromPixels(
|
|
7384
|
+
surface = surfaceFromPixels(px, 4);
|
|
7370
7385
|
} else if (init.color !== void 0) {
|
|
7371
7386
|
const c = parseColor(init.color);
|
|
7372
7387
|
surface = solidSurface(4, { x: 0, y: 0, width, height }, packRgba(c[0], c[1], c[2], c[3]));
|
|
@@ -7470,9 +7485,9 @@ var ImageEditorController = class {
|
|
|
7470
7485
|
getEdgeColor(id) {
|
|
7471
7486
|
const layer = this.requireEdgeLayer(id);
|
|
7472
7487
|
const e = layer.edge ?? {};
|
|
7473
|
-
const
|
|
7488
|
+
const pct = (v) => Math.round((v ?? 0) * 1e3) / 10;
|
|
7474
7489
|
const hex = (c) => "#" + c.map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
7475
|
-
return { layerId: layer.id, decontaminate:
|
|
7490
|
+
return { layerId: layer.id, decontaminate: pct(e.decontaminate), despill: pct(e.despill), ambient: pct(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
|
|
7476
7491
|
}
|
|
7477
7492
|
requireEdgeLayer(id) {
|
|
7478
7493
|
const layer = this.getLayer(id);
|
|
@@ -7527,9 +7542,9 @@ var ImageEditorController = class {
|
|
|
7527
7542
|
throw new LayerOperationError(`"${name}" has no mask with a soft edge: decontamination and despill work in the partly hidden band of a layer mask. Add one with add_layer_mask from a refined selection (refine_selection), or feather the mask (set_layer_mask_properties feather).`);
|
|
7528
7543
|
}
|
|
7529
7544
|
if (turningOn("ambient") && !this.maskHasSoftBand(layer) && layer.type === "pixel") {
|
|
7530
|
-
const
|
|
7545
|
+
const px = this.getLayerPixels(layer.id);
|
|
7531
7546
|
let soft = false;
|
|
7532
|
-
if (
|
|
7547
|
+
if (px) for (let i = 3; i < px.data.length && !soft; i += 4) soft = px.data[i] > 5 && px.data[i] < 250;
|
|
7533
7548
|
if (!soft) throw new LayerOperationError(`"${name}" has no soft edge (no soft-edged mask and no partly transparent pixels) for the edge cast to work on.`);
|
|
7534
7549
|
}
|
|
7535
7550
|
const edge = next.decontaminate || next.despill || next.ambient || next.ambientColor ? next : void 0;
|
|
@@ -8155,14 +8170,14 @@ var ImageEditorController = class {
|
|
|
8155
8170
|
const surface = this.surfaceOf(layer);
|
|
8156
8171
|
const sb = sel.bounds;
|
|
8157
8172
|
const src = { x: sb.x - layer.offset.x, y: sb.y - layer.offset.y, width: sb.width, height: sb.height };
|
|
8158
|
-
const
|
|
8159
|
-
const kept = options.cut ? new Uint8ClampedArray(
|
|
8173
|
+
const px = readRegion(surface, src);
|
|
8174
|
+
const kept = options.cut ? new Uint8ClampedArray(px) : null;
|
|
8160
8175
|
for (let y = 0; y < sb.height; y++) {
|
|
8161
8176
|
for (let x = 0; x < sb.width; x++) {
|
|
8162
8177
|
const c = sel.data[(sb.y + y) * sel.width + sb.x + x];
|
|
8163
8178
|
const i = (y * sb.width + x) * 4 + 3;
|
|
8164
8179
|
if (kept) kept[i] = Math.round(kept[i] * (1 - c / 255));
|
|
8165
|
-
|
|
8180
|
+
px[i] = Math.round(px[i] * (c / 255));
|
|
8166
8181
|
}
|
|
8167
8182
|
}
|
|
8168
8183
|
const copy = {
|
|
@@ -8172,7 +8187,7 @@ var ImageEditorController = class {
|
|
|
8172
8187
|
visible: true,
|
|
8173
8188
|
opacity: 1,
|
|
8174
8189
|
blend: "normal",
|
|
8175
|
-
surface: surfaceFromPixels({ width: src.width, height: src.height, data:
|
|
8190
|
+
surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y),
|
|
8176
8191
|
offset: { ...layer.offset }
|
|
8177
8192
|
};
|
|
8178
8193
|
let next = insertLayer(this.state.layers, copy, loc.parent?.id ?? null, loc.index + 1);
|
|
@@ -8609,8 +8624,8 @@ var ImageEditorController = class {
|
|
|
8609
8624
|
for (const [cid, c] of pending) {
|
|
8610
8625
|
try {
|
|
8611
8626
|
const url = `data:${BROWSER_IMAGE_TYPES[c.file.type]};base64,${bytesToBase64(c.file.bytes)}`;
|
|
8612
|
-
const
|
|
8613
|
-
const decoded = { ...c, kind: "raster", raster: rasterContents(
|
|
8627
|
+
const px = await this.decodeImage(url);
|
|
8628
|
+
const decoded = { ...c, kind: "raster", raster: rasterContents(px, c.name, cid).raster, width: px.width, height: px.height };
|
|
8614
8629
|
const swap = (layers) => {
|
|
8615
8630
|
let out = layers;
|
|
8616
8631
|
for (const l of flattenLayers(layers)) if (l.type === "smart" && l.contents.id === cid) out = mapLayer(out, l.id, (x) => ({ ...x, contents: decoded }));
|
|
@@ -8706,8 +8721,8 @@ var ImageEditorController = class {
|
|
|
8706
8721
|
const only = edited.layers.length === 1 ? edited.layers[0] : null;
|
|
8707
8722
|
const plain3 = only?.type === "pixel" && only.visible && only.opacity === 1 && only.blend === "normal" && !only.mask && !only.effects && !only.filters?.length && !only.clipped && (only.fillOpacity ?? 1) === 1 && only.source !== "document";
|
|
8708
8723
|
if (old?.kind === "raster" && plain3) {
|
|
8709
|
-
const
|
|
8710
|
-
next = rasterContents({ width, height, data:
|
|
8724
|
+
const px = readRegion(only.surface, { x: -only.offset.x, y: -only.offset.y, width, height });
|
|
8725
|
+
next = rasterContents({ width, height, data: px }, old.name, old.id);
|
|
8711
8726
|
} else {
|
|
8712
8727
|
const doc = { layers: edited.layers, globalLight: edited.globalLight, patterns: edited.patterns };
|
|
8713
8728
|
next = documentContents(doc, width, height, old?.kind === "document" ? old.name : `${(old?.name ?? "Contents").replace(/\.\w+$/, "")}.psb`, top.contentsId);
|
|
@@ -11499,9 +11514,9 @@ var ImageEditorController = class {
|
|
|
11499
11514
|
return;
|
|
11500
11515
|
}
|
|
11501
11516
|
const { width, height } = this.naturalSize;
|
|
11502
|
-
let
|
|
11503
|
-
if (
|
|
11504
|
-
const data = new Uint8ClampedArray(
|
|
11517
|
+
let px = await this.decodeImage(newDataUrl);
|
|
11518
|
+
if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
|
|
11519
|
+
const data = new Uint8ClampedArray(px.data);
|
|
11505
11520
|
const sel = this.state.selection?.bounds ? this.state.selection : null;
|
|
11506
11521
|
if (sel) for (let p = 0, i = 3; p < width * height; p++, i += 4) data[i] = Math.round(data[i] * sel.data[p] / 255);
|
|
11507
11522
|
return this.addPixelLayer({ name: "Inpaint", pixels: { width, height, data } });
|
|
@@ -11522,10 +11537,10 @@ var ImageEditorController = class {
|
|
|
11522
11537
|
if (!target) throw new LayerOperationError("There is no pixel layer to mask.");
|
|
11523
11538
|
requireUnlocked(target, "all", "mask it");
|
|
11524
11539
|
const { width, height } = this.naturalSize;
|
|
11525
|
-
let
|
|
11526
|
-
if (
|
|
11540
|
+
let px = await this.decodeImage(newDataUrl);
|
|
11541
|
+
if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
|
|
11527
11542
|
const alpha = new Uint8ClampedArray(width * height);
|
|
11528
|
-
for (let p = 0; p < alpha.length; p++) alpha[p] =
|
|
11543
|
+
for (let p = 0; p < alpha.length; p++) alpha[p] = px.data[p * 4 + 3];
|
|
11529
11544
|
let surface = surfaceFromPixels({ width, height, data: alpha }, 1, 0, 0, 0);
|
|
11530
11545
|
if (target.offset.x || target.offset.y) surface = translateSurface(surface, -target.offset.x, -target.offset.y);
|
|
11531
11546
|
this.commitLayers(setLayerMask(this.state.layers, target.id, { surface, defaultValue: 0 }));
|
|
@@ -12098,14 +12113,14 @@ var ImageEditorController = class {
|
|
|
12098
12113
|
const converted = [];
|
|
12099
12114
|
const unconverted = [];
|
|
12100
12115
|
const memo = /* @__PURE__ */ new Map();
|
|
12101
|
-
const
|
|
12116
|
+
const px = new Float32Array(4);
|
|
12102
12117
|
const hex = (h) => {
|
|
12103
12118
|
let out = memo.get(h.toLowerCase());
|
|
12104
12119
|
if (out === void 0) {
|
|
12105
12120
|
const n = parseInt(h.slice(1), 16);
|
|
12106
|
-
t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255],
|
|
12121
|
+
t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px);
|
|
12107
12122
|
const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0");
|
|
12108
|
-
out = `#${c(
|
|
12123
|
+
out = `#${c(px[0])}${c(px[1])}${c(px[2])}`;
|
|
12109
12124
|
memo.set(h.toLowerCase(), out);
|
|
12110
12125
|
}
|
|
12111
12126
|
return out;
|
|
@@ -12914,24 +12929,24 @@ function pixelsOnly(layers) {
|
|
|
12914
12929
|
}
|
|
12915
12930
|
return out;
|
|
12916
12931
|
}
|
|
12917
|
-
function resizePixels(
|
|
12918
|
-
const src =
|
|
12932
|
+
function resizePixels(px, width, height) {
|
|
12933
|
+
const src = px.data;
|
|
12919
12934
|
const out = new Uint8ClampedArray(width * height * 4);
|
|
12920
|
-
const kx =
|
|
12921
|
-
const ky =
|
|
12935
|
+
const kx = px.width / width;
|
|
12936
|
+
const ky = px.height / height;
|
|
12922
12937
|
for (let y = 0; y < height; y++) {
|
|
12923
|
-
const fy = Math.min(
|
|
12938
|
+
const fy = Math.min(px.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
|
|
12924
12939
|
const y0 = Math.floor(fy);
|
|
12925
|
-
const y1 = Math.min(
|
|
12940
|
+
const y1 = Math.min(px.height - 1, y0 + 1);
|
|
12926
12941
|
const ty = fy - y0;
|
|
12927
12942
|
for (let x = 0; x < width; x++) {
|
|
12928
|
-
const fx = Math.min(
|
|
12943
|
+
const fx = Math.min(px.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
|
|
12929
12944
|
const x0 = Math.floor(fx);
|
|
12930
|
-
const x1 = Math.min(
|
|
12945
|
+
const x1 = Math.min(px.width - 1, x0 + 1);
|
|
12931
12946
|
const tx = fx - x0;
|
|
12932
12947
|
for (let c = 0; c < 4; c++) {
|
|
12933
|
-
const a = src[(y0 *
|
|
12934
|
-
const b = src[(y1 *
|
|
12948
|
+
const a = src[(y0 * px.width + x0) * 4 + c] * (1 - tx) + src[(y0 * px.width + x1) * 4 + c] * tx;
|
|
12949
|
+
const b = src[(y1 * px.width + x0) * 4 + c] * (1 - tx) + src[(y1 * px.width + x1) * 4 + c] * tx;
|
|
12935
12950
|
out[(y * width + x) * 4 + c] = a * (1 - ty) + b * ty;
|
|
12936
12951
|
}
|
|
12937
12952
|
}
|
|
@@ -13803,8 +13818,8 @@ var REFINE_OUTPUTS = [
|
|
|
13803
13818
|
];
|
|
13804
13819
|
function describeSelection(mask) {
|
|
13805
13820
|
if (!mask || !mask.bounds) return "No selection";
|
|
13806
|
-
const
|
|
13807
|
-
const shown =
|
|
13821
|
+
const pct = selectionArea(mask) / (mask.width * mask.height) * 100;
|
|
13822
|
+
const shown = pct >= 10 ? Math.round(pct) : Math.round(pct * 10) / 10;
|
|
13808
13823
|
return `${mask.bounds.width} \xD7 ${mask.bounds.height} px selected (${shown}% of the image)`;
|
|
13809
13824
|
}
|
|
13810
13825
|
|
|
@@ -15341,14 +15356,14 @@ function rebin(bins, count) {
|
|
|
15341
15356
|
return out;
|
|
15342
15357
|
}
|
|
15343
15358
|
function histogramSummary(h, bins) {
|
|
15344
|
-
const
|
|
15359
|
+
const pct = (n) => h.samples ? round(n / h.samples * 100) : 0;
|
|
15345
15360
|
const channels = { red: h.red, green: h.green, blue: h.blue, luminance: h.luminance };
|
|
15346
15361
|
return {
|
|
15347
15362
|
samples: h.samples,
|
|
15348
15363
|
transparent: h.transparent,
|
|
15349
15364
|
clipping: {
|
|
15350
|
-
shadowsPercent: { red:
|
|
15351
|
-
highlightsPercent: { red:
|
|
15365
|
+
shadowsPercent: { red: pct(h.shadows[0]), green: pct(h.shadows[1]), blue: pct(h.shadows[2]) },
|
|
15366
|
+
highlightsPercent: { red: pct(h.highlights[0]), green: pct(h.highlights[1]), blue: pct(h.highlights[2]) }
|
|
15352
15367
|
},
|
|
15353
15368
|
stats: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, binStats(v, h.samples)])),
|
|
15354
15369
|
...bins ? { bins: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, rebin(v, bins)])) } : {}
|
|
@@ -16249,337 +16264,6 @@ function createImageLayerTools(controller) {
|
|
|
16249
16264
|
];
|
|
16250
16265
|
}
|
|
16251
16266
|
|
|
16252
|
-
// src/image-editor/effect-tools.ts
|
|
16253
|
-
var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
16254
|
-
var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
16255
|
-
var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
16256
|
-
var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
16257
|
-
var LAYER_ID3 = { type: "string", description: "Layer id from list_layers (a pixel, shape, smart object, annotation or group layer)." };
|
|
16258
|
-
var EFFECT_ID = { type: "string", description: "Effect id from list_layer_effects or add_layer_effect." };
|
|
16259
|
-
var BLEND_IDS = BLEND_MODES.map((m) => m.id).filter((id) => id !== "pigment");
|
|
16260
|
-
var DEFS = {
|
|
16261
|
-
color: { type: "string", pattern: "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$", description: "Colour as #rrggbb." },
|
|
16262
|
-
contour: {
|
|
16263
|
-
type: "object",
|
|
16264
|
-
description: "A transfer curve over the effect coverage: points { input, output } from 0 to 1 (at least 2), sorted by input. Linear is [{0,0},{1,1}].",
|
|
16265
|
-
properties: {
|
|
16266
|
-
name: { type: "string", description: 'Display name (e.g. "Cone", "Gaussian").' },
|
|
16267
|
-
points: {
|
|
16268
|
-
type: "array",
|
|
16269
|
-
minItems: 2,
|
|
16270
|
-
description: "Curve points.",
|
|
16271
|
-
items: {
|
|
16272
|
-
type: "object",
|
|
16273
|
-
properties: {
|
|
16274
|
-
input: { type: "number", minimum: 0, maximum: 1, description: "Coverage in (0..1)." },
|
|
16275
|
-
output: { type: "number", minimum: 0, maximum: 1, description: "Coverage out (0..1)." },
|
|
16276
|
-
corner: { type: "boolean", description: "Sharp corner instead of a smooth point (default false)." }
|
|
16277
|
-
},
|
|
16278
|
-
required: ["input", "output"],
|
|
16279
|
-
additionalProperties: false
|
|
16280
|
-
}
|
|
16281
|
-
}
|
|
16282
|
-
},
|
|
16283
|
-
required: ["name", "points"],
|
|
16284
|
-
additionalProperties: false
|
|
16285
|
-
},
|
|
16286
|
-
gradient: {
|
|
16287
|
-
type: "object",
|
|
16288
|
-
description: "A gradient: colour stops, optional opacity stops and its layout.",
|
|
16289
|
-
properties: {
|
|
16290
|
-
stops: {
|
|
16291
|
-
type: "array",
|
|
16292
|
-
minItems: 1,
|
|
16293
|
-
description: "Colour stops { position 0..1, color #rrggbb }.",
|
|
16294
|
-
items: {
|
|
16295
|
-
type: "object",
|
|
16296
|
-
properties: { position: { type: "number", minimum: 0, maximum: 1, description: "0..1 along the gradient." }, color: { $ref: "#/$defs/color" } },
|
|
16297
|
-
required: ["position", "color"],
|
|
16298
|
-
additionalProperties: false
|
|
16299
|
-
}
|
|
16300
|
-
},
|
|
16301
|
-
opacityStops: {
|
|
16302
|
-
type: "array",
|
|
16303
|
-
description: "Opacity stops { position 0..1, opacity 0..1 } (default opaque).",
|
|
16304
|
-
items: {
|
|
16305
|
-
type: "object",
|
|
16306
|
-
properties: {
|
|
16307
|
-
position: { type: "number", minimum: 0, maximum: 1, description: "0..1 along the gradient." },
|
|
16308
|
-
opacity: { type: "number", minimum: 0, maximum: 1, description: "0..1." }
|
|
16309
|
-
},
|
|
16310
|
-
required: ["position", "opacity"],
|
|
16311
|
-
additionalProperties: false
|
|
16312
|
-
}
|
|
16313
|
-
},
|
|
16314
|
-
style: { type: "string", enum: ["linear", "radial", "angle", "reflected", "diamond"], description: "Geometry." },
|
|
16315
|
-
angle: { type: "number", minimum: -360, maximum: 360, description: "Degrees, 90 = bottom to top." },
|
|
16316
|
-
scale: { type: "number", minimum: 0.1, maximum: 1.5, description: "1 = 100 %." },
|
|
16317
|
-
reverse: { type: "boolean", description: "Swap the ends." },
|
|
16318
|
-
align: { type: "boolean", description: "Lay out over the layer bounds (true) or the canvas." },
|
|
16319
|
-
offset: {
|
|
16320
|
-
type: "object",
|
|
16321
|
-
description: "Centre offset as fractions of the bounds.",
|
|
16322
|
-
properties: { x: { type: "number", minimum: -1, maximum: 1, description: "Fraction of the width." }, y: { type: "number", minimum: -1, maximum: 1, description: "Fraction of the height." } },
|
|
16323
|
-
required: ["x", "y"],
|
|
16324
|
-
additionalProperties: false
|
|
16325
|
-
}
|
|
16326
|
-
},
|
|
16327
|
-
required: ["stops", "style", "angle", "scale", "reverse", "align", "offset"],
|
|
16328
|
-
additionalProperties: false
|
|
16329
|
-
},
|
|
16330
|
-
phase: {
|
|
16331
|
-
type: "object",
|
|
16332
|
-
description: "Pattern origin offset in px.",
|
|
16333
|
-
properties: { x: { type: "number", description: "px." }, y: { type: "number", description: "px." } },
|
|
16334
|
-
required: ["x", "y"],
|
|
16335
|
-
additionalProperties: false
|
|
16336
|
-
},
|
|
16337
|
-
fill: {
|
|
16338
|
-
description: "What a stroke or glow paints with. Glows take color or gradient only.",
|
|
16339
|
-
anyOf: [
|
|
16340
|
-
{
|
|
16341
|
-
type: "object",
|
|
16342
|
-
properties: { type: { const: "color", description: "Solid colour." }, color: { $ref: "#/$defs/color" } },
|
|
16343
|
-
required: ["type", "color"],
|
|
16344
|
-
additionalProperties: false
|
|
16345
|
-
},
|
|
16346
|
-
{
|
|
16347
|
-
type: "object",
|
|
16348
|
-
properties: { type: { const: "gradient", description: "Gradient." }, gradient: { $ref: "#/$defs/gradient" } },
|
|
16349
|
-
required: ["type", "gradient"],
|
|
16350
|
-
additionalProperties: false
|
|
16351
|
-
},
|
|
16352
|
-
{
|
|
16353
|
-
type: "object",
|
|
16354
|
-
properties: {
|
|
16355
|
-
type: { const: "pattern", description: "Pattern (strokes only)." },
|
|
16356
|
-
patternId: { type: "string", description: "Pattern id from list_layer_effects.patterns." },
|
|
16357
|
-
name: { type: "string", description: "Display name." },
|
|
16358
|
-
scale: { type: "number", minimum: 0.01, maximum: 10, description: "1 = 100 %." },
|
|
16359
|
-
angle: { type: "number", minimum: -360, maximum: 360, description: "Rotation in degrees (default 0)." },
|
|
16360
|
-
link: { type: "boolean", description: "Tile from the layer (default true) or the canvas origin." },
|
|
16361
|
-
phase: { $ref: "#/$defs/phase" }
|
|
16362
|
-
},
|
|
16363
|
-
required: ["type", "patternId", "scale"],
|
|
16364
|
-
additionalProperties: false
|
|
16365
|
-
}
|
|
16366
|
-
]
|
|
16367
|
-
}
|
|
16368
|
-
};
|
|
16369
|
-
var nullable = (schema, description) => ({ anyOf: [schema, { type: "null" }], description });
|
|
16370
|
-
function settingsSchema(forUpdate) {
|
|
16371
|
-
const opt2 = (schema, description) => forUpdate ? nullable(schema, `${description} null removes it.`) : { ...schema, description };
|
|
16372
|
-
return {
|
|
16373
|
-
type: "object",
|
|
16374
|
-
description: forUpdate ? "Settings to change (only these; nested objects are replaced whole). Which settings a kind takes: see add_layer_effect." : "Settings to change from Photoshop's defaults (all optional). Unknown settings for the kind are refused with the list of its settings.",
|
|
16375
|
-
properties: {
|
|
16376
|
-
enabled: { type: "boolean", description: "All kinds: false keeps the effect but hides it (default true)." },
|
|
16377
|
-
blend: { type: "string", enum: BLEND_IDS, description: "All but bevel-emboss: blend mode (shadows multiply, glows screen, others normal)." },
|
|
16378
|
-
opacity: { type: "number", minimum: 0, maximum: 1, description: "All but bevel-emboss: 0..1 (shadows / glows 0.75, satin 0.5, others 1)." },
|
|
16379
|
-
color: { $ref: "#/$defs/color", description: "drop-shadow, inner-shadow, satin, color-overlay: #rrggbb." },
|
|
16380
|
-
angle: { type: "number", minimum: -360, maximum: 360, description: "Shadows, satin, bevel-emboss: light direction in degrees, counter-clockwise from 3 o'clock (default 120; satin 19)." },
|
|
16381
|
-
useGlobalLight: { type: "boolean", description: "Shadows, bevel-emboss: follow the document global light instead of angle (default true)." },
|
|
16382
|
-
distance: { type: "number", minimum: 0, maximum: 3e4, description: "Shadows, satin: offset in px (default 5; satin 11)." },
|
|
16383
|
-
spread: { type: "number", minimum: 0, maximum: 1, description: "drop-shadow, outer-glow: 0..1 of the size made solid (default 0)." },
|
|
16384
|
-
choke: { type: "number", minimum: 0, maximum: 1, description: "inner-shadow, inner-glow: 0..1 of the size made solid (default 0)." },
|
|
16385
|
-
size: { type: "number", minimum: 0, maximum: 250, description: "Shadows, glows, satin, bevel-emboss: blur / size in px (default 5; satin 14); stroke: width in px (default 3)." },
|
|
16386
|
-
contour: opt2({ $ref: "#/$defs/contour" }, "Shadows, glows, satin: coverage contour (default linear)."),
|
|
16387
|
-
antiAlias: { type: "boolean", description: "Shadows, glows, satin: smooth the contour (default false; satin true)." },
|
|
16388
|
-
noise: { type: "number", minimum: 0, maximum: 1, description: "Shadows, glows: speckle 0..1 (default 0)." },
|
|
16389
|
-
knocksOut: { type: "boolean", description: "drop-shadow: the layer hides the shadow beneath its see-through fill (default true)." },
|
|
16390
|
-
fill: { $ref: "#/$defs/fill", description: "outer-glow, inner-glow (color or gradient), stroke (color, gradient or pattern)." },
|
|
16391
|
-
technique: { type: "string", enum: ["softer", "precise", "smooth", "chisel-hard", "chisel-soft"], description: "Glows: softer | precise (default softer); bevel-emboss: smooth | chisel-hard | chisel-soft (default smooth)." },
|
|
16392
|
-
range: { type: "number", minimum: 0.01, maximum: 1, description: "Glows: the part of the glow the contour spans (default 0.5)." },
|
|
16393
|
-
jitter: { type: "number", minimum: 0, maximum: 1, description: "Glows: gradient jitter 0..1 (stored, not rendered; default 0)." },
|
|
16394
|
-
source: { type: "string", enum: ["edge", "center"], description: "inner-glow: glow from the edge (default) or the centre." },
|
|
16395
|
-
style: { type: "string", enum: ["inner-bevel", "outer-bevel", "emboss", "pillow-emboss", "stroke-emboss"], description: "bevel-emboss: style (default inner-bevel)." },
|
|
16396
|
-
depth: { type: "number", minimum: 0, maximum: 10, description: "bevel-emboss: depth, 1 = 100 % (default 1)." },
|
|
16397
|
-
direction: { type: "string", enum: ["up", "down"], description: "bevel-emboss: raised (up, default) or sunk (down)." },
|
|
16398
|
-
soften: { type: "number", minimum: 0, maximum: 16, description: "bevel-emboss: blur of the height in px (default 0)." },
|
|
16399
|
-
altitude: { type: "number", minimum: 0, maximum: 90, description: "bevel-emboss: light altitude in degrees (default 30)." },
|
|
16400
|
-
glossContour: opt2({ $ref: "#/$defs/contour" }, "bevel-emboss: gloss contour over the shading (default linear)."),
|
|
16401
|
-
highlightColor: { $ref: "#/$defs/color", description: "bevel-emboss: highlight colour (default #ffffff)." },
|
|
16402
|
-
highlightBlend: { type: "string", enum: BLEND_IDS, description: "bevel-emboss: highlight mode (default screen)." },
|
|
16403
|
-
highlightOpacity: { type: "number", minimum: 0, maximum: 1, description: "bevel-emboss: highlight opacity (default 0.75)." },
|
|
16404
|
-
shadowColor: { $ref: "#/$defs/color", description: "bevel-emboss: shadow colour (default #000000)." },
|
|
16405
|
-
shadowBlend: { type: "string", enum: BLEND_IDS, description: "bevel-emboss: shadow mode (default multiply)." },
|
|
16406
|
-
shadowOpacity: { type: "number", minimum: 0, maximum: 1, description: "bevel-emboss: shadow opacity (default 0.75)." },
|
|
16407
|
-
contourElement: opt2(
|
|
16408
|
-
{
|
|
16409
|
-
type: "object",
|
|
16410
|
-
properties: {
|
|
16411
|
-
contour: { $ref: "#/$defs/contour" },
|
|
16412
|
-
range: { type: "number", minimum: 0, maximum: 1, description: "Stored range (default 0.5)." },
|
|
16413
|
-
antiAlias: { type: "boolean", description: "Smooth the contour." }
|
|
16414
|
-
},
|
|
16415
|
-
required: ["contour", "range", "antiAlias"],
|
|
16416
|
-
additionalProperties: false
|
|
16417
|
-
},
|
|
16418
|
-
"bevel-emboss: the Contour element, shaping the bevel's height profile (default off)."
|
|
16419
|
-
),
|
|
16420
|
-
texture: opt2(
|
|
16421
|
-
{
|
|
16422
|
-
type: "object",
|
|
16423
|
-
properties: {
|
|
16424
|
-
patternId: { type: "string", description: "Pattern id from list_layer_effects.patterns." },
|
|
16425
|
-
name: { type: "string", description: "Display name." },
|
|
16426
|
-
scale: { type: "number", minimum: 0.01, maximum: 10, description: "1 = 100 %." },
|
|
16427
|
-
depth: { type: "number", minimum: -10, maximum: 10, description: "1 = +100 %; negative carves the pattern in." },
|
|
16428
|
-
invert: { type: "boolean", description: "Invert the pattern." },
|
|
16429
|
-
link: { type: "boolean", description: "Tile from the layer (default true)." },
|
|
16430
|
-
phase: { $ref: "#/$defs/phase" }
|
|
16431
|
-
},
|
|
16432
|
-
required: ["patternId", "scale", "depth", "invert"],
|
|
16433
|
-
additionalProperties: false
|
|
16434
|
-
},
|
|
16435
|
-
"bevel-emboss: the Texture element, a pattern's luminance as extra height (default off)."
|
|
16436
|
-
),
|
|
16437
|
-
invert: { type: "boolean", description: "satin: invert (default true)." },
|
|
16438
|
-
gradient: { $ref: "#/$defs/gradient", description: "gradient-overlay: the gradient (default black to white, 90\xB0)." },
|
|
16439
|
-
dither: { type: "boolean", description: "gradient-overlay: dither (stored; default false)." },
|
|
16440
|
-
patternId: { type: "string", description: "pattern-overlay: pattern id from list_layer_effects.patterns (default checker)." },
|
|
16441
|
-
name: { type: "string", description: "pattern-overlay: pattern display name." },
|
|
16442
|
-
scale: { type: "number", minimum: 0.01, maximum: 10, description: "pattern-overlay: 1 = 100 % (default 1)." },
|
|
16443
|
-
link: { type: "boolean", description: "pattern-overlay: tile from the layer (default true) or the canvas origin." },
|
|
16444
|
-
phase: { $ref: "#/$defs/phase", description: "pattern-overlay: origin offset in px (default 0, 0)." },
|
|
16445
|
-
position: { type: "string", enum: ["outside", "inside", "center"], description: "stroke: where the stroke sits on the edge (default outside)." }
|
|
16446
|
-
},
|
|
16447
|
-
additionalProperties: false
|
|
16448
|
-
};
|
|
16449
|
-
}
|
|
16450
|
-
function patternList(controller) {
|
|
16451
|
-
const doc = controller.getDocumentPatterns().map((p) => ({ id: p.id, name: p.name, width: p.width, height: p.height, builtin: false }));
|
|
16452
|
-
const builtins = builtinPatternIds().map((id) => {
|
|
16453
|
-
const p = builtinPattern(id);
|
|
16454
|
-
return { id, name: p.name, width: p.width, height: p.height, builtin: true };
|
|
16455
|
-
});
|
|
16456
|
-
return [...doc, ...builtins];
|
|
16457
|
-
}
|
|
16458
|
-
function describeLayerEffects(effects) {
|
|
16459
|
-
return {
|
|
16460
|
-
enabled: effects.enabled,
|
|
16461
|
-
scale: effects.scale ?? 1,
|
|
16462
|
-
margin: effectsMargin(effects),
|
|
16463
|
-
fromPsd: Boolean(effects.psd),
|
|
16464
|
-
effects: effects.items.map((e) => ({ ...JSON.parse(JSON.stringify(e)), label: layerEffectLabel(e.kind) }))
|
|
16465
|
-
};
|
|
16466
|
-
}
|
|
16467
|
-
function createImageEffectTools(controller) {
|
|
16468
|
-
const layerArg = (id) => {
|
|
16469
|
-
if (typeof id !== "string" || !id) throw new LayerOperationError("layerId is required (a layer id from list_layers).");
|
|
16470
|
-
requireLayer(controller.getLayers(), id);
|
|
16471
|
-
return id;
|
|
16472
|
-
};
|
|
16473
|
-
const result = (layerId, extra = {}) => ({ layerId, ...extra, ...describeLayerEffects(controller.getLayerEffects(layerId)) });
|
|
16474
|
-
const list = {
|
|
16475
|
-
name: "list_layer_effects",
|
|
16476
|
-
title: "List layer effects",
|
|
16477
|
-
description: "Returns a layer's effects: the master switch (enabled), Scale Effects (scale, 1 = 100 %), margin (px the effects reach beyond the shape), whether they came from a PSD, and every effect with its id, kind, label and all settings. Also returns the document global light and the pattern ids pattern effects can use.",
|
|
16478
|
-
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
16479
|
-
annotations: { title: "List layer effects", ...READ3 },
|
|
16480
|
-
handler: ({ layerId }) => result(layerArg(layerId), { globalLight: controller.getGlobalLight(), patterns: patternList(controller), kinds: [...LAYER_EFFECT_KINDS] })
|
|
16481
|
-
};
|
|
16482
|
-
const add2 = {
|
|
16483
|
-
name: "add_layer_effect",
|
|
16484
|
-
title: "Add a layer effect",
|
|
16485
|
-
description: "Adds a live effect to a pixel, shape, type, smart object, annotation or group layer with Photoshop's defaults, changed by settings: drop-shadow, inner-shadow, outer-glow, inner-glow, bevel-emboss, satin, color-overlay, gradient-overlay, pattern-overlay or stroke. Several of one kind are allowed (the first listed is on top). One undo step. Returns the new effect's id and the layer's effects.",
|
|
16486
|
-
inputSchema: {
|
|
16487
|
-
type: "object",
|
|
16488
|
-
$defs: DEFS,
|
|
16489
|
-
properties: {
|
|
16490
|
-
layerId: LAYER_ID3,
|
|
16491
|
-
kind: { type: "string", enum: [...LAYER_EFFECT_KINDS], description: "Effect kind." },
|
|
16492
|
-
settings: settingsSchema(false),
|
|
16493
|
-
index: { type: "integer", minimum: 0, description: "Position in the layer's effect list (default the end)." }
|
|
16494
|
-
},
|
|
16495
|
-
required: ["layerId", "kind"],
|
|
16496
|
-
additionalProperties: false
|
|
16497
|
-
},
|
|
16498
|
-
annotations: { title: "Add a layer effect", ...WRITE3 },
|
|
16499
|
-
handler: ({ layerId, kind, settings, index }) => {
|
|
16500
|
-
const id = layerArg(layerId);
|
|
16501
|
-
if (!isLayerEffectKind(kind)) throw new LayerOperationError(`kind must be one of ${LAYER_EFFECT_KINDS.join(", ")}.`);
|
|
16502
|
-
const { effect } = controller.addLayerEffect(id, kind, settings ?? {}, index);
|
|
16503
|
-
return result(id, { effectId: effect.id });
|
|
16504
|
-
}
|
|
16505
|
-
};
|
|
16506
|
-
const update = {
|
|
16507
|
-
name: "update_layer_effect",
|
|
16508
|
-
title: "Change a layer effect",
|
|
16509
|
-
description: "Changes settings of one effect (only the given ones; fill, gradient, contour and texture objects are replaced whole, null removes an optional contour or texture). The kind cannot change. Validates everything before changing anything. One undo step. Returns the layer's effects.",
|
|
16510
|
-
inputSchema: {
|
|
16511
|
-
type: "object",
|
|
16512
|
-
$defs: DEFS,
|
|
16513
|
-
properties: { layerId: LAYER_ID3, effectId: EFFECT_ID, settings: settingsSchema(true) },
|
|
16514
|
-
required: ["layerId", "effectId", "settings"],
|
|
16515
|
-
additionalProperties: false
|
|
16516
|
-
},
|
|
16517
|
-
annotations: { title: "Change a layer effect", ...WRITE_IDEMPOTENT3 },
|
|
16518
|
-
handler: ({ layerId, effectId, settings }) => {
|
|
16519
|
-
const id = layerArg(layerId);
|
|
16520
|
-
const changes = settings ?? {};
|
|
16521
|
-
if (!Object.keys(changes).length) throw new LayerOperationError("Give at least one setting to change.");
|
|
16522
|
-
controller.updateLayerEffect(id, effectId, changes);
|
|
16523
|
-
return result(id);
|
|
16524
|
-
}
|
|
16525
|
-
};
|
|
16526
|
-
const remove = {
|
|
16527
|
-
name: "remove_layer_effect",
|
|
16528
|
-
title: "Remove a layer effect",
|
|
16529
|
-
description: "Removes one effect from a layer (to hide it but keep its settings, set enabled false with update_layer_effect instead). One undo step. Returns the layer's remaining effects.",
|
|
16530
|
-
inputSchema: { type: "object", properties: { layerId: LAYER_ID3, effectId: EFFECT_ID }, required: ["layerId", "effectId"], additionalProperties: false },
|
|
16531
|
-
annotations: { title: "Remove a layer effect", ...DESTRUCTIVE2 },
|
|
16532
|
-
handler: ({ layerId, effectId }) => {
|
|
16533
|
-
const id = layerArg(layerId);
|
|
16534
|
-
controller.removeLayerEffect(id, effectId);
|
|
16535
|
-
return result(id);
|
|
16536
|
-
}
|
|
16537
|
-
};
|
|
16538
|
-
const setEnabled = {
|
|
16539
|
-
name: "set_layer_effects_enabled",
|
|
16540
|
-
title: "Switch layer effects on or off",
|
|
16541
|
-
description: "Turns all of a layer's effects on or off at once (the master switch; each effect keeps its own enabled flag) and optionally sets Scale Effects, which multiplies every size, distance and pattern scale. One undo step. Returns the layer's effects.",
|
|
16542
|
-
inputSchema: {
|
|
16543
|
-
type: "object",
|
|
16544
|
-
properties: {
|
|
16545
|
-
layerId: LAYER_ID3,
|
|
16546
|
-
enabled: { type: "boolean", description: "true renders the enabled effects; false hides them all." },
|
|
16547
|
-
scale: { type: "number", minimum: 0.01, maximum: 10, description: "Scale Effects, 1 = 100 % (unchanged when left out)." }
|
|
16548
|
-
},
|
|
16549
|
-
required: ["layerId", "enabled"],
|
|
16550
|
-
additionalProperties: false
|
|
16551
|
-
},
|
|
16552
|
-
annotations: { title: "Switch layer effects on or off", ...WRITE_IDEMPOTENT3 },
|
|
16553
|
-
handler: ({ layerId, enabled, scale }) => {
|
|
16554
|
-
const id = layerArg(layerId);
|
|
16555
|
-
controller.setLayerEffectsEnabled(id, enabled, scale);
|
|
16556
|
-
return result(id);
|
|
16557
|
-
}
|
|
16558
|
-
};
|
|
16559
|
-
const light = {
|
|
16560
|
-
name: "set_global_light",
|
|
16561
|
-
title: "Set the global light",
|
|
16562
|
-
description: "Sets the document global light that shadows and bevels with useGlobalLight follow (Photoshop default: angle 120\xB0, altitude 30\xB0). One undo step. Returns the light.",
|
|
16563
|
-
inputSchema: {
|
|
16564
|
-
type: "object",
|
|
16565
|
-
properties: {
|
|
16566
|
-
angle: { type: "number", minimum: -360, maximum: 360, description: "Degrees, counter-clockwise from 3 o'clock: where the light comes from (unchanged when left out)." },
|
|
16567
|
-
altitude: { type: "number", minimum: 0, maximum: 90, description: "Degrees above the canvas, for bevels (unchanged when left out)." }
|
|
16568
|
-
},
|
|
16569
|
-
additionalProperties: false
|
|
16570
|
-
},
|
|
16571
|
-
annotations: { title: "Set the global light", ...WRITE_IDEMPOTENT3 },
|
|
16572
|
-
handler: ({ angle, altitude }) => {
|
|
16573
|
-
if (angle === void 0 && altitude === void 0) throw new LayerOperationError("Give angle, altitude or both.");
|
|
16574
|
-
const next = {};
|
|
16575
|
-
if (angle !== void 0) next.angle = angle;
|
|
16576
|
-
if (altitude !== void 0) next.altitude = altitude;
|
|
16577
|
-
return { globalLight: controller.setGlobalLight(next) };
|
|
16578
|
-
}
|
|
16579
|
-
};
|
|
16580
|
-
return [list, add2, update, remove, setEnabled, light];
|
|
16581
|
-
}
|
|
16582
|
-
|
|
16583
16267
|
// src/image-editor/selection/gesture.ts
|
|
16584
16268
|
function snapTo45(from, point2) {
|
|
16585
16269
|
const dx = point2.x - from.x;
|
|
@@ -17315,10 +16999,10 @@ var PaintGesture = class {
|
|
|
17315
16999
|
};
|
|
17316
17000
|
|
|
17317
17001
|
// src/image-editor/paint-tools.ts
|
|
17318
|
-
var
|
|
17319
|
-
var
|
|
17002
|
+
var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17003
|
+
var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
17320
17004
|
var SET = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17321
|
-
var
|
|
17005
|
+
var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
17322
17006
|
var TARGET = {
|
|
17323
17007
|
layerId: { type: "string", description: "Layer to paint (default the active layer; see list_layers)." },
|
|
17324
17008
|
channel: {
|
|
@@ -17408,7 +17092,7 @@ function createImagePaintTools(controller) {
|
|
|
17408
17092
|
required: ["points"],
|
|
17409
17093
|
additionalProperties: false
|
|
17410
17094
|
},
|
|
17411
|
-
annotations: { title: "Paint a brush stroke", ...
|
|
17095
|
+
annotations: { title: "Paint a brush stroke", ...WRITE3 },
|
|
17412
17096
|
handler: (args) => {
|
|
17413
17097
|
const tool = args.tool;
|
|
17414
17098
|
if (args.mixer !== void 0 && tool !== "mixer") throw new LayerOperationError('mixer settings apply to the Mixer Brush only; pass tool "mixer", or drop mixer.');
|
|
@@ -17431,7 +17115,7 @@ function createImagePaintTools(controller) {
|
|
|
17431
17115
|
title: "Get the Mixer Brush",
|
|
17432
17116
|
description: "Reads the Mixer Brush: its settings (wet, load, mix, loadEachStroke, cleanEachStroke, mixing) and what it carries now (reservoir #rrggbb or null, amount 0..1 left, pickup #rrggbb or null). Call it before a paint_stroke with tool mixer and loadEachStroke false, to know the brush's starting paint.",
|
|
17433
17117
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17434
|
-
annotations: { title: "Get the Mixer Brush", ...
|
|
17118
|
+
annotations: { title: "Get the Mixer Brush", ...READ3 },
|
|
17435
17119
|
handler: () => {
|
|
17436
17120
|
const { mixer, mixerLoad } = controller.getState().paint;
|
|
17437
17121
|
return { settings: { ...mixer }, load: mixerLoadResult(mixerLoad) };
|
|
@@ -17446,7 +17130,7 @@ function createImagePaintTools(controller) {
|
|
|
17446
17130
|
properties: { color: { type: "string", description: "Paint colour #rrggbb (default the foreground)." } },
|
|
17447
17131
|
additionalProperties: false
|
|
17448
17132
|
},
|
|
17449
|
-
annotations: { title: "Load the Mixer Brush", ...
|
|
17133
|
+
annotations: { title: "Load the Mixer Brush", ...WRITE3, idempotentHint: true },
|
|
17450
17134
|
handler: (args) => mixerLoadResult(controller.loadMixerBrush(args.color))
|
|
17451
17135
|
};
|
|
17452
17136
|
const cleanMixerTool = {
|
|
@@ -17458,7 +17142,7 @@ function createImagePaintTools(controller) {
|
|
|
17458
17142
|
properties: { emptyReservoir: { type: "boolean", description: "Also drop the reservoir (default false)." } },
|
|
17459
17143
|
additionalProperties: false
|
|
17460
17144
|
},
|
|
17461
|
-
annotations: { title: "Clean the Mixer Brush", ...
|
|
17145
|
+
annotations: { title: "Clean the Mixer Brush", ...WRITE3, idempotentHint: true },
|
|
17462
17146
|
handler: (args) => mixerLoadResult(args.emptyReservoir === true ? controller.emptyMixerBrush() : controller.cleanMixerBrush())
|
|
17463
17147
|
};
|
|
17464
17148
|
const fill = {
|
|
@@ -17476,7 +17160,7 @@ function createImagePaintTools(controller) {
|
|
|
17476
17160
|
},
|
|
17477
17161
|
additionalProperties: false
|
|
17478
17162
|
},
|
|
17479
|
-
annotations: { title: "Fill pixels", ...
|
|
17163
|
+
annotations: { title: "Fill pixels", ...WRITE3 },
|
|
17480
17164
|
handler: (args) => controller.fillPixels({
|
|
17481
17165
|
color: args.color,
|
|
17482
17166
|
opacity: args.opacity,
|
|
@@ -17498,7 +17182,7 @@ function createImagePaintTools(controller) {
|
|
|
17498
17182
|
},
|
|
17499
17183
|
additionalProperties: false
|
|
17500
17184
|
},
|
|
17501
|
-
annotations: { title: "Clear pixels", ...
|
|
17185
|
+
annotations: { title: "Clear pixels", ...DESTRUCTIVE2 },
|
|
17502
17186
|
handler: (args) => controller.clearPixels({ opacity: args.opacity, useSelection: args.useSelection, ...readTarget(args) })
|
|
17503
17187
|
};
|
|
17504
17188
|
const paintView = () => {
|
|
@@ -17521,7 +17205,7 @@ function createImagePaintTools(controller) {
|
|
|
17521
17205
|
title: "Get the paint",
|
|
17522
17206
|
description: "Reads what the brush paints (paint: the foreground colour or gradient paint), the foreground and background colours and the brush settings (size, hardness, spacing, opacity, flow \u2026). Changes nothing.",
|
|
17523
17207
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17524
|
-
annotations: { title: "Get the paint", ...
|
|
17208
|
+
annotations: { title: "Get the paint", ...READ3 },
|
|
17525
17209
|
handler: () => paintView()
|
|
17526
17210
|
};
|
|
17527
17211
|
const sampleColor2 = {
|
|
@@ -17564,7 +17248,7 @@ function createImagePaintTools(controller) {
|
|
|
17564
17248
|
required: ["start", "end"],
|
|
17565
17249
|
additionalProperties: false
|
|
17566
17250
|
},
|
|
17567
|
-
annotations: { title: "Sample a gradient along a line", ...
|
|
17251
|
+
annotations: { title: "Sample a gradient along a line", ...READ3 },
|
|
17568
17252
|
handler: (args) => {
|
|
17569
17253
|
const start = args.start;
|
|
17570
17254
|
const end = args.end;
|
|
@@ -17593,7 +17277,7 @@ function createImagePaintTools(controller) {
|
|
|
17593
17277
|
}
|
|
17594
17278
|
|
|
17595
17279
|
// src/image-editor/color-tools.ts
|
|
17596
|
-
var
|
|
17280
|
+
var READ4 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17597
17281
|
var PROFILE = {
|
|
17598
17282
|
type: "string",
|
|
17599
17283
|
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.`
|
|
@@ -17620,7 +17304,7 @@ function createImageColorTools(controller) {
|
|
|
17620
17304
|
title: "Get the colour profile",
|
|
17621
17305
|
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}).",
|
|
17622
17306
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17623
|
-
annotations: { title: "Get the colour profile", ...
|
|
17307
|
+
annotations: { title: "Get the colour profile", ...READ4 },
|
|
17624
17308
|
handler: () => {
|
|
17625
17309
|
const proof2 = controller.getState().proofSetup;
|
|
17626
17310
|
return {
|
|
@@ -17704,7 +17388,7 @@ function createImageColorTools(controller) {
|
|
|
17704
17388
|
required: ["colors", "to"],
|
|
17705
17389
|
additionalProperties: false
|
|
17706
17390
|
},
|
|
17707
|
-
annotations: { title: "Convert colours between profiles", ...
|
|
17391
|
+
annotations: { title: "Convert colours between profiles", ...READ4 },
|
|
17708
17392
|
handler: (args) => ({
|
|
17709
17393
|
colors: controller.convertColors(args.colors, profileArg(args.to), {
|
|
17710
17394
|
...args.from !== void 0 ? { from: profileArg(args.from) } : {},
|
|
@@ -17740,8 +17424,8 @@ function createImageColorTools(controller) {
|
|
|
17740
17424
|
}
|
|
17741
17425
|
|
|
17742
17426
|
// src/image-editor/retouch-tools.ts
|
|
17743
|
-
var
|
|
17744
|
-
var
|
|
17427
|
+
var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17428
|
+
var WRITE4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
17745
17429
|
var POINTS = {
|
|
17746
17430
|
type: "array",
|
|
17747
17431
|
minItems: 1,
|
|
@@ -17831,7 +17515,7 @@ function createImageRetouchTools(controller) {
|
|
|
17831
17515
|
required: ["points"],
|
|
17832
17516
|
additionalProperties: false
|
|
17833
17517
|
},
|
|
17834
|
-
annotations: { title: "Clone Stamp stroke", ...
|
|
17518
|
+
annotations: { title: "Clone Stamp stroke", ...WRITE4 },
|
|
17835
17519
|
handler: (args) => stroke("clone", args, pick(args, ["aligned", "sample"]))
|
|
17836
17520
|
};
|
|
17837
17521
|
const healBrush = {
|
|
@@ -17851,7 +17535,7 @@ function createImageRetouchTools(controller) {
|
|
|
17851
17535
|
required: ["points"],
|
|
17852
17536
|
additionalProperties: false
|
|
17853
17537
|
},
|
|
17854
|
-
annotations: { title: "Healing Brush stroke", ...
|
|
17538
|
+
annotations: { title: "Healing Brush stroke", ...WRITE4 },
|
|
17855
17539
|
handler: (args) => stroke("heal", args, pick(args, ["aligned", "sample"]))
|
|
17856
17540
|
};
|
|
17857
17541
|
const spotHeal = {
|
|
@@ -17870,7 +17554,7 @@ function createImageRetouchTools(controller) {
|
|
|
17870
17554
|
required: ["points"],
|
|
17871
17555
|
additionalProperties: false
|
|
17872
17556
|
},
|
|
17873
|
-
annotations: { title: "Spot Healing stroke", ...
|
|
17557
|
+
annotations: { title: "Spot Healing stroke", ...WRITE4 },
|
|
17874
17558
|
handler: (args) => stroke("spot-heal", args, { ...pick(args, ["sample"]), ...args.type !== void 0 ? { spotType: args.type } : {} })
|
|
17875
17559
|
};
|
|
17876
17560
|
const smudge = {
|
|
@@ -17888,7 +17572,7 @@ function createImageRetouchTools(controller) {
|
|
|
17888
17572
|
required: ["points"],
|
|
17889
17573
|
additionalProperties: false
|
|
17890
17574
|
},
|
|
17891
|
-
annotations: { title: "Smudge stroke", ...
|
|
17575
|
+
annotations: { title: "Smudge stroke", ...WRITE4 },
|
|
17892
17576
|
handler: (args) => stroke("smudge", args, pick(args, ["strength"]))
|
|
17893
17577
|
};
|
|
17894
17578
|
const toneSchema = (verb) => ({
|
|
@@ -17909,7 +17593,7 @@ function createImageRetouchTools(controller) {
|
|
|
17909
17593
|
title: "Dodge stroke",
|
|
17910
17594
|
description: "Lightens the pixels a stroke covers (Photoshop's Dodge), most in the chosen tonal range. Alpha is kept. One undo step. Returns the layerId, channel, changed bounds and dab count. Inspect the result with capture_view or get_histogram; several light strokes look more natural than one strong one.",
|
|
17911
17595
|
inputSchema: toneSchema("lighten"),
|
|
17912
|
-
annotations: { title: "Dodge stroke", ...
|
|
17596
|
+
annotations: { title: "Dodge stroke", ...WRITE4 },
|
|
17913
17597
|
handler: (args) => stroke("dodge", args, pick(args, ["range", "exposure", "protectTones"]))
|
|
17914
17598
|
};
|
|
17915
17599
|
const burn = {
|
|
@@ -17917,7 +17601,7 @@ function createImageRetouchTools(controller) {
|
|
|
17917
17601
|
title: "Burn stroke",
|
|
17918
17602
|
description: "Darkens the pixels a stroke covers (Photoshop's Burn), most in the chosen tonal range. Alpha is kept. One undo step. Returns the layerId, channel, changed bounds and dab count.",
|
|
17919
17603
|
inputSchema: toneSchema("darken"),
|
|
17920
|
-
annotations: { title: "Burn stroke", ...
|
|
17604
|
+
annotations: { title: "Burn stroke", ...WRITE4 },
|
|
17921
17605
|
handler: (args) => stroke("burn", args, pick(args, ["range", "exposure", "protectTones"]))
|
|
17922
17606
|
};
|
|
17923
17607
|
const spongeTool = {
|
|
@@ -17936,7 +17620,7 @@ function createImageRetouchTools(controller) {
|
|
|
17936
17620
|
required: ["points"],
|
|
17937
17621
|
additionalProperties: false
|
|
17938
17622
|
},
|
|
17939
|
-
annotations: { title: "Sponge stroke", ...
|
|
17623
|
+
annotations: { title: "Sponge stroke", ...WRITE4 },
|
|
17940
17624
|
handler: (args) => stroke("sponge", { ...args, channel: "pixels" }, { ...pick(args, ["vibrance"]), ...args.mode !== void 0 ? { spongeMode: args.mode } : {} })
|
|
17941
17625
|
};
|
|
17942
17626
|
const filterSchema = (verb) => ({
|
|
@@ -17955,7 +17639,7 @@ function createImageRetouchTools(controller) {
|
|
|
17955
17639
|
title: "Blur stroke",
|
|
17956
17640
|
description: "Softens the pixels a stroke covers (Photoshop's Blur tool): a soft blur of the layer laid through the brush at `strength`. Overlapping dabs in one stroke do not compound; another stroke blurs further. Works on pixels and masks, at any bit depth. One undo step. Returns the layerId, channel, changed bounds and dab count.",
|
|
17957
17641
|
inputSchema: filterSchema("blur"),
|
|
17958
|
-
annotations: { title: "Blur stroke", ...
|
|
17642
|
+
annotations: { title: "Blur stroke", ...WRITE4 },
|
|
17959
17643
|
handler: (args) => stroke("blur", args, pick(args, ["strength"]))
|
|
17960
17644
|
};
|
|
17961
17645
|
const sharpenTool = {
|
|
@@ -17963,7 +17647,7 @@ function createImageRetouchTools(controller) {
|
|
|
17963
17647
|
title: "Sharpen stroke",
|
|
17964
17648
|
description: "Crisps the pixels a stroke covers (Photoshop's Sharpen tool): an unsharp mask of the layer laid through the brush at `strength`. Keep strength low (0.2..0.5) and inspect with capture_view; strong sharpening shows halos and noise. One undo step. Returns the layerId, channel, changed bounds and dab count.",
|
|
17965
17649
|
inputSchema: filterSchema("sharpen"),
|
|
17966
|
-
annotations: { title: "Sharpen stroke", ...
|
|
17650
|
+
annotations: { title: "Sharpen stroke", ...WRITE4 },
|
|
17967
17651
|
handler: (args) => stroke("sharpen", args, pick(args, ["strength"]))
|
|
17968
17652
|
};
|
|
17969
17653
|
const historyBrush = {
|
|
@@ -17981,7 +17665,7 @@ function createImageRetouchTools(controller) {
|
|
|
17981
17665
|
required: ["points"],
|
|
17982
17666
|
additionalProperties: false
|
|
17983
17667
|
},
|
|
17984
|
-
annotations: { title: "History Brush stroke", ...
|
|
17668
|
+
annotations: { title: "History Brush stroke", ...WRITE4 },
|
|
17985
17669
|
handler: (args) => stroke("history", args, pick(args, ["historySteps"]))
|
|
17986
17670
|
};
|
|
17987
17671
|
const getOptions = {
|
|
@@ -17989,7 +17673,7 @@ function createImageRetouchTools(controller) {
|
|
|
17989
17673
|
title: "Get retouch options",
|
|
17990
17674
|
description: "Reads the retouching tools' options (aligned, sample, spotType, range, exposure, protectTones, spongeMode, vibrance, strength, historySteps), the Clone Source transform ({scaleX, scaleY, rotate}) and the clone source ({x, y, offset} or null; offset is the aligned offset the last clone or heal stroke fixed: an aligned stroke samples at the brush plus offset, which the editors show as a crosshair). Call it before clone_stamp or heal_brush without a source to see where they will sample.",
|
|
17991
17675
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17992
|
-
annotations: { title: "Get retouch options", ...
|
|
17676
|
+
annotations: { title: "Get retouch options", ...READ5 },
|
|
17993
17677
|
handler: () => {
|
|
17994
17678
|
const { retouch, cloneSource, cloneTransform } = controller.getState().paint;
|
|
17995
17679
|
return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null, cloneTransform: { ...cloneTransform } };
|
|
@@ -18015,7 +17699,7 @@ function createImageRetouchTools(controller) {
|
|
|
18015
17699
|
},
|
|
18016
17700
|
additionalProperties: false
|
|
18017
17701
|
},
|
|
18018
|
-
annotations: { title: "Set retouch options", ...
|
|
17702
|
+
annotations: { title: "Set retouch options", ...WRITE4, idempotentHint: true },
|
|
18019
17703
|
handler: (args) => ({ ...controller.setPaintOptions({ retouch: args }).retouch })
|
|
18020
17704
|
};
|
|
18021
17705
|
const setSource = {
|
|
@@ -18031,7 +17715,7 @@ function createImageRetouchTools(controller) {
|
|
|
18031
17715
|
},
|
|
18032
17716
|
additionalProperties: false
|
|
18033
17717
|
},
|
|
18034
|
-
annotations: { title: "Set the clone source", ...
|
|
17718
|
+
annotations: { title: "Set the clone source", ...WRITE4, idempotentHint: true },
|
|
18035
17719
|
handler: (args) => {
|
|
18036
17720
|
if (args.clear === true) {
|
|
18037
17721
|
if (args.x !== void 0 || args.y !== void 0) throw new LayerOperationError("Give either clear true or x and y, not both.");
|
|
@@ -18057,7 +17741,7 @@ function createImageRetouchTools(controller) {
|
|
|
18057
17741
|
},
|
|
18058
17742
|
additionalProperties: false
|
|
18059
17743
|
},
|
|
18060
|
-
annotations: { title: "Transform the clone source", ...
|
|
17744
|
+
annotations: { title: "Transform the clone source", ...WRITE4, idempotentHint: false },
|
|
18061
17745
|
handler: (args) => {
|
|
18062
17746
|
if (args.reset === true) {
|
|
18063
17747
|
if (Object.keys(args).some((k) => k !== "reset")) throw new LayerOperationError("Give either reset true or transform values, not both.");
|
|
@@ -18083,8 +17767,8 @@ function pick(args, keys) {
|
|
|
18083
17767
|
}
|
|
18084
17768
|
|
|
18085
17769
|
// src/image-editor/psd-tools.ts
|
|
18086
|
-
var
|
|
18087
|
-
var
|
|
17770
|
+
var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17771
|
+
var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18088
17772
|
var DATA = {
|
|
18089
17773
|
type: "string",
|
|
18090
17774
|
minLength: 1,
|
|
@@ -18104,7 +17788,7 @@ function createImagePsdTools(controller) {
|
|
|
18104
17788
|
title: "Inspect a PSD",
|
|
18105
17789
|
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.",
|
|
18106
17790
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
18107
|
-
annotations: { title: "Inspect a PSD", ...
|
|
17791
|
+
annotations: { title: "Inspect a PSD", ...READ6 },
|
|
18108
17792
|
handler: ({ data }) => {
|
|
18109
17793
|
const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
|
|
18110
17794
|
return {
|
|
@@ -18122,7 +17806,7 @@ function createImagePsdTools(controller) {
|
|
|
18122
17806
|
title: "Open a PSD as the document",
|
|
18123
17807
|
description: "Opens a PSD / PSB as the document, replacing the current layers, crop and rotation (one undo step; undo brings the previous document back). Pixel, group and adjustment layers, masks, blend modes, opacity, fill, clipping, visibility, locks, layer effects (with the patterns and global light of the file) map directly; smart objects come in as smart objects (embedded contents, placement and warp, smart filters: Box Blur is drawn, other Photoshop filters are kept but not drawn, filter mask; linked contents as their stored pixels); shape layers come in as live shapes (paths, path operations, fill, stroke, live rectangles, ellipses and lines); type layers come in as live text (runs, paragraphs, frame, transform) showing Photoshop\u2019s pixels until edited, with a warning for fonts missing here; fill layers come in as their pixels; unsupported adjustments are left out. Returns the new layer tree with ids, the size and the warnings (each names the affected layers).",
|
|
18124
17808
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
18125
|
-
annotations: { title: "Open a PSD as the document", ...
|
|
17809
|
+
annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE3 },
|
|
18126
17810
|
handler: ({ data }) => {
|
|
18127
17811
|
const res = controller.loadPsd(psdBytesFromBase64(data));
|
|
18128
17812
|
const s = controller.getState();
|
|
@@ -18141,7 +17825,7 @@ function createImagePsdTools(controller) {
|
|
|
18141
17825
|
title: "Export the document as a PSD",
|
|
18142
17826
|
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.",
|
|
18143
17827
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
18144
|
-
annotations: { title: "Export the document as a PSD", ...
|
|
17828
|
+
annotations: { title: "Export the document as a PSD", ...READ6 },
|
|
18145
17829
|
handler: async () => {
|
|
18146
17830
|
const res = await controller.toPsd();
|
|
18147
17831
|
return {
|
|
@@ -18159,8 +17843,8 @@ function createImagePsdTools(controller) {
|
|
|
18159
17843
|
}
|
|
18160
17844
|
|
|
18161
17845
|
// src/image-editor/transform-tools.ts
|
|
18162
|
-
var
|
|
18163
|
-
var
|
|
17846
|
+
var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17847
|
+
var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18164
17848
|
var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
18165
17849
|
var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
|
|
18166
17850
|
var POINT = {
|
|
@@ -18259,7 +17943,7 @@ function createImageTransformTools(controller) {
|
|
|
18259
17943
|
},
|
|
18260
17944
|
additionalProperties: false
|
|
18261
17945
|
},
|
|
18262
|
-
annotations: { title: "Get the Free Transform frame", ...
|
|
17946
|
+
annotations: { title: "Get the Free Transform frame", ...READ7 },
|
|
18263
17947
|
handler: (args) => {
|
|
18264
17948
|
const init = targetFrom(args);
|
|
18265
17949
|
if (init.content === "selection-copy") init.content = "selection";
|
|
@@ -18292,7 +17976,7 @@ function createImageTransformTools(controller) {
|
|
|
18292
17976
|
properties: { ...TARGET3, ...GEOMETRY },
|
|
18293
17977
|
additionalProperties: false
|
|
18294
17978
|
},
|
|
18295
|
-
annotations: { title: "Free Transform a layer", ...
|
|
17979
|
+
annotations: { title: "Free Transform a layer", ...WRITE5 },
|
|
18296
17980
|
handler: (args) => summary2(controller.transformLayer({ ...targetFrom(args), ...geometryFrom(args) }))
|
|
18297
17981
|
};
|
|
18298
17982
|
const warpLayer = {
|
|
@@ -18322,7 +18006,7 @@ function createImageTransformTools(controller) {
|
|
|
18322
18006
|
},
|
|
18323
18007
|
additionalProperties: false
|
|
18324
18008
|
},
|
|
18325
|
-
annotations: { title: "Warp a layer", ...
|
|
18009
|
+
annotations: { title: "Warp a layer", ...WRITE5 },
|
|
18326
18010
|
handler: (args) => {
|
|
18327
18011
|
const hasPreset = ["style", "bend", "horizontal", "vertical", "orientation"].some((k) => args[k] !== void 0);
|
|
18328
18012
|
if (hasPreset && args.mesh !== void 0) throw new LayerOperationError("Give a preset (style, bend, horizontal, vertical, orientation) or a mesh, not both.");
|
|
@@ -18356,7 +18040,7 @@ function createImageTransformTools(controller) {
|
|
|
18356
18040
|
properties: { interpolation: { ...TARGET3.interpolation, description: "Resampling of soft edges: nearest, bilinear or bicubic (default)." }, ...GEOMETRY },
|
|
18357
18041
|
additionalProperties: false
|
|
18358
18042
|
},
|
|
18359
|
-
annotations: { title: "Transform the selection outline", ...
|
|
18043
|
+
annotations: { title: "Transform the selection outline", ...WRITE5 },
|
|
18360
18044
|
handler: (args) => {
|
|
18361
18045
|
const res = controller.transformLayer({ content: "selection-outline", interpolation: args.interpolation, ...geometryFrom(args) });
|
|
18362
18046
|
return { changed: res.changed, frame: { ...res.box }, corners: res.corners.map(roundPoint), bounds: res.bounds };
|
|
@@ -18377,7 +18061,7 @@ function createImageTransformTools(controller) {
|
|
|
18377
18061
|
required: ["axis"],
|
|
18378
18062
|
additionalProperties: false
|
|
18379
18063
|
},
|
|
18380
|
-
annotations: { title: "Flip a layer", ...
|
|
18064
|
+
annotations: { title: "Flip a layer", ...WRITE5 },
|
|
18381
18065
|
handler: (args) => summary2(controller.flipLayer(args.axis, targetFrom(args)))
|
|
18382
18066
|
};
|
|
18383
18067
|
const rotate90 = {
|
|
@@ -18395,20 +18079,20 @@ function createImageTransformTools(controller) {
|
|
|
18395
18079
|
required: ["turn"],
|
|
18396
18080
|
additionalProperties: false
|
|
18397
18081
|
},
|
|
18398
|
-
annotations: { title: "Rotate a layer by quarter turns", ...
|
|
18082
|
+
annotations: { title: "Rotate a layer by quarter turns", ...WRITE5 },
|
|
18399
18083
|
handler: (args) => summary2(controller.rotateLayer90(args.turn, targetFrom(args)))
|
|
18400
18084
|
};
|
|
18401
18085
|
return [getFrame, transformLayer, warpLayer, transformSelection, flipLayer, rotate90];
|
|
18402
18086
|
}
|
|
18403
18087
|
|
|
18404
18088
|
// src/image-editor/smart-tools.ts
|
|
18405
|
-
var
|
|
18406
|
-
var
|
|
18407
|
-
var
|
|
18408
|
-
var
|
|
18089
|
+
var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18090
|
+
var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18091
|
+
var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18092
|
+
var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18409
18093
|
var round5 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
18410
18094
|
var roundPoint2 = (p) => ({ x: round5(p.x), y: round5(p.y) });
|
|
18411
|
-
var
|
|
18095
|
+
var LAYER_ID3 = { type: "string", description: "Smart object layer id from list_layers (type smart)." };
|
|
18412
18096
|
var FILTER_ID = { type: "string", description: "Smart filter id from get_smart_object or add_smart_filter." };
|
|
18413
18097
|
var POINT2 = {
|
|
18414
18098
|
type: "object",
|
|
@@ -18460,8 +18144,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18460
18144
|
name: "get_smart_object",
|
|
18461
18145
|
title: "Read a smart object",
|
|
18462
18146
|
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.",
|
|
18463
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
18464
|
-
annotations: { title: "Read a smart object", ...
|
|
18147
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18148
|
+
annotations: { title: "Read a smart object", ...READ8 },
|
|
18465
18149
|
handler: ({ layerId }) => info(smartId(layerId))
|
|
18466
18150
|
};
|
|
18467
18151
|
const convert = {
|
|
@@ -18476,7 +18160,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18476
18160
|
},
|
|
18477
18161
|
additionalProperties: false
|
|
18478
18162
|
},
|
|
18479
|
-
annotations: { title: "Convert to Smart Object", ...
|
|
18163
|
+
annotations: { title: "Convert to Smart Object", ...WRITE6 },
|
|
18480
18164
|
handler: ({ layerIds, name }) => {
|
|
18481
18165
|
for (const id2 of layerIds ?? []) requireLayer(controller.getLayers(), id2);
|
|
18482
18166
|
const id = controller.convertToSmartObject(layerIds, { name });
|
|
@@ -18487,8 +18171,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18487
18171
|
name: "rasterize_smart_object",
|
|
18488
18172
|
title: "Rasterize a smart object",
|
|
18489
18173
|
description: "Layer \u203A Smart Objects \u203A Rasterize: the smart object becomes a pixel layer holding what it shows now (smart filters baked; same id, mask, effects, opacity, blend and fill). The contents, placement and filters are gone, so later transforms resample the pixels. One undo step. Returns the layer.",
|
|
18490
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
18491
|
-
annotations: { title: "Rasterize a smart object", ...
|
|
18174
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18175
|
+
annotations: { title: "Rasterize a smart object", ...DESTRUCTIVE4 },
|
|
18492
18176
|
handler: ({ layerId }) => ({ layer: layerSummary(controller.rasterizeSmartObject(smartId(layerId))) })
|
|
18493
18177
|
};
|
|
18494
18178
|
const setTransform = {
|
|
@@ -18498,7 +18182,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18498
18182
|
inputSchema: {
|
|
18499
18183
|
type: "object",
|
|
18500
18184
|
properties: {
|
|
18501
|
-
layerId:
|
|
18185
|
+
layerId: LAYER_ID3,
|
|
18502
18186
|
corners: { type: "array", items: POINT2, minItems: 4, maxItems: 4, description: "Where the contents\u2019 corners land: [top-left, top-right, bottom-right, bottom-left] in document pixels. The quad must stay convex." },
|
|
18503
18187
|
matrix: { type: "array", items: { type: "number" }, minItems: 6, maxItems: 6, description: "Affine map from contents pixels to document pixels [a, b, c, d, e, f] (x' = a\xB7x + c\xB7y + e, y' = b\xB7x + d\xB7y + f)." },
|
|
18504
18188
|
scaleX: { type: "number", description: "Width in percent of the contents\u2019 own width (negative flips)." },
|
|
@@ -18541,7 +18225,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18541
18225
|
required: ["layerId"],
|
|
18542
18226
|
additionalProperties: false
|
|
18543
18227
|
},
|
|
18544
|
-
annotations: { title: "Set a smart object\u2019s transform", ...
|
|
18228
|
+
annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT3 },
|
|
18545
18229
|
handler: (args) => {
|
|
18546
18230
|
const id = smartId(args.layerId);
|
|
18547
18231
|
let warp;
|
|
@@ -18580,22 +18264,22 @@ function createImageSmartObjectTools(controller) {
|
|
|
18580
18264
|
inputSchema: {
|
|
18581
18265
|
type: "object",
|
|
18582
18266
|
properties: {
|
|
18583
|
-
layerId:
|
|
18267
|
+
layerId: LAYER_ID3,
|
|
18584
18268
|
image: { type: "string", description: "The new contents: a PNG as a data URL or base64 (other formats and URLs need a browser)." },
|
|
18585
18269
|
name: { type: "string", description: "File name of the contents (default the old name with .png)." }
|
|
18586
18270
|
},
|
|
18587
18271
|
required: ["layerId", "image"],
|
|
18588
18272
|
additionalProperties: false
|
|
18589
18273
|
},
|
|
18590
|
-
annotations: { title: "Replace a smart object\u2019s contents", ...
|
|
18274
|
+
annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE4 },
|
|
18591
18275
|
handler: async ({ layerId, image, name }) => controller.replaceSmartObjectContentsFromImage(smartId(layerId), imageArg(image), name)
|
|
18592
18276
|
};
|
|
18593
18277
|
const exportContents = {
|
|
18594
18278
|
name: "export_smart_object_contents",
|
|
18595
18279
|
title: "Export a smart object\u2019s contents",
|
|
18596
18280
|
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.",
|
|
18597
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
18598
|
-
annotations: { title: "Export a smart object\u2019s contents", ...
|
|
18281
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18282
|
+
annotations: { title: "Export a smart object\u2019s contents", ...READ8 },
|
|
18599
18283
|
handler: ({ layerId }) => {
|
|
18600
18284
|
const f = controller.exportSmartObjectContents(smartId(layerId));
|
|
18601
18285
|
return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
|
|
@@ -18608,14 +18292,14 @@ function createImageSmartObjectTools(controller) {
|
|
|
18608
18292
|
inputSchema: {
|
|
18609
18293
|
type: "object",
|
|
18610
18294
|
properties: {
|
|
18611
|
-
layerId:
|
|
18295
|
+
layerId: LAYER_ID3,
|
|
18612
18296
|
linked: { type: "boolean", description: "true shares the contents with the original; false (default) makes independent contents." },
|
|
18613
18297
|
name: { type: "string", description: 'Name of the copy (default "<name> copy").' }
|
|
18614
18298
|
},
|
|
18615
18299
|
required: ["layerId"],
|
|
18616
18300
|
additionalProperties: false
|
|
18617
18301
|
},
|
|
18618
|
-
annotations: { title: "Copy a smart object", ...
|
|
18302
|
+
annotations: { title: "Copy a smart object", ...WRITE6 },
|
|
18619
18303
|
handler: ({ layerId, linked, name }) => {
|
|
18620
18304
|
const id = controller.copySmartObject(smartId(layerId), linked === true, name);
|
|
18621
18305
|
return { layer: layerSummary(id), contentsId: controller.getSmartObject(id).contents.id };
|
|
@@ -18625,8 +18309,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18625
18309
|
name: "edit_smart_object_contents",
|
|
18626
18310
|
title: "Edit a smart object\u2019s contents",
|
|
18627
18311
|
description: 'Layer \u203A Smart Objects \u203A Edit Contents: opens the contents as a document of their own (a layer document, or raster contents as one pixel layer "Layer 0") with their own undo history. Every other tool (list_layers, paint, adjustments\u2026) then works inside the contents until close_smart_object_contents saves them back. Contents can nest. Returns the contents\u2019 size and layers.',
|
|
18628
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
18629
|
-
annotations: { title: "Edit a smart object\u2019s contents", ...
|
|
18312
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18313
|
+
annotations: { title: "Edit a smart object\u2019s contents", ...WRITE6 },
|
|
18630
18314
|
handler: ({ layerId }) => {
|
|
18631
18315
|
const res = controller.editSmartObjectContents(smartId(layerId));
|
|
18632
18316
|
const s = controller.getState();
|
|
@@ -18642,7 +18326,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18642
18326
|
properties: { save: { type: "boolean", description: "true (default) saves the edits into the smart object; false discards them." } },
|
|
18643
18327
|
additionalProperties: false
|
|
18644
18328
|
},
|
|
18645
|
-
annotations: { title: "Close a smart object\u2019s contents", ...
|
|
18329
|
+
annotations: { title: "Close a smart object\u2019s contents", ...WRITE6 },
|
|
18646
18330
|
handler: ({ save }) => ({ ...controller.closeSmartObjectContents(save !== false), editing: controller.getEditingContents() })
|
|
18647
18331
|
};
|
|
18648
18332
|
const addFilter = {
|
|
@@ -18652,7 +18336,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18652
18336
|
inputSchema: {
|
|
18653
18337
|
type: "object",
|
|
18654
18338
|
properties: {
|
|
18655
|
-
layerId:
|
|
18339
|
+
layerId: LAYER_ID3,
|
|
18656
18340
|
kind: { type: "string", enum: ["develop", "blur"], description: "Filter kind." },
|
|
18657
18341
|
index: { type: "integer", minimum: 0, description: "Position in the stack, 0 = bottom, applied first (default the top)." },
|
|
18658
18342
|
useSelection: { type: "boolean", description: "With a selection, set the filter mask from it so the filter only changes the selected area (default true)." },
|
|
@@ -18661,7 +18345,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18661
18345
|
required: ["layerId", "kind"],
|
|
18662
18346
|
additionalProperties: false
|
|
18663
18347
|
},
|
|
18664
|
-
annotations: { title: "Add a smart filter", ...
|
|
18348
|
+
annotations: { title: "Add a smart filter", ...WRITE6 },
|
|
18665
18349
|
handler: (args) => {
|
|
18666
18350
|
const id = smartId(args.layerId);
|
|
18667
18351
|
const masked = args.useSelection !== false && controller.hasSelection;
|
|
@@ -18675,11 +18359,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18675
18359
|
description: "Changes one smart filter: its settings, enabled, blend or opacity (only the given values; the kind cannot change). A Photoshop filter kept from a PSD (kind psd) only takes enabled, blend and opacity. One undo step. Returns the filter and the stack.",
|
|
18676
18360
|
inputSchema: {
|
|
18677
18361
|
type: "object",
|
|
18678
|
-
properties: { layerId:
|
|
18362
|
+
properties: { layerId: LAYER_ID3, filterId: FILTER_ID, ...FILTER_SETTINGS },
|
|
18679
18363
|
required: ["layerId", "filterId"],
|
|
18680
18364
|
additionalProperties: false
|
|
18681
18365
|
},
|
|
18682
|
-
annotations: { title: "Change a smart filter", ...
|
|
18366
|
+
annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT3 },
|
|
18683
18367
|
handler: (args) => {
|
|
18684
18368
|
const id = smartId(args.layerId);
|
|
18685
18369
|
const changes = settingsFrom(args);
|
|
@@ -18692,8 +18376,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18692
18376
|
name: "remove_smart_filter",
|
|
18693
18377
|
title: "Remove a smart filter",
|
|
18694
18378
|
description: "Removes one smart filter (the filter mask goes with the last one). One undo step. Returns the remaining stack.",
|
|
18695
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
18696
|
-
annotations: { title: "Remove a smart filter", ...
|
|
18379
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3, filterId: FILTER_ID }, required: ["layerId", "filterId"], additionalProperties: false },
|
|
18380
|
+
annotations: { title: "Remove a smart filter", ...DESTRUCTIVE4 },
|
|
18697
18381
|
handler: ({ layerId, filterId }) => {
|
|
18698
18382
|
const id = smartId(layerId);
|
|
18699
18383
|
controller.removeSmartFilter(id, filterId);
|
|
@@ -18706,11 +18390,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18706
18390
|
description: "Moves one smart filter to a position in the stack (0 = bottom, applied first), as dragging it in the Layers panel. One undo step. Returns the stack in its new order.",
|
|
18707
18391
|
inputSchema: {
|
|
18708
18392
|
type: "object",
|
|
18709
|
-
properties: { layerId:
|
|
18393
|
+
properties: { layerId: LAYER_ID3, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
|
|
18710
18394
|
required: ["layerId", "filterId", "index"],
|
|
18711
18395
|
additionalProperties: false
|
|
18712
18396
|
},
|
|
18713
|
-
annotations: { title: "Reorder a smart filter", ...
|
|
18397
|
+
annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT3 },
|
|
18714
18398
|
handler: ({ layerId, filterId, index }) => {
|
|
18715
18399
|
const id = smartId(layerId);
|
|
18716
18400
|
controller.moveSmartFilter(id, filterId, index);
|
|
@@ -18723,11 +18407,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18723
18407
|
description: "Layer \u203A Smart Filter \u203A Disable / Enable Smart Filters: switches the whole stack; each filter keeps its own enabled flag. One undo step. Returns the stack.",
|
|
18724
18408
|
inputSchema: {
|
|
18725
18409
|
type: "object",
|
|
18726
|
-
properties: { layerId:
|
|
18410
|
+
properties: { layerId: LAYER_ID3, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
|
|
18727
18411
|
required: ["layerId", "enabled"],
|
|
18728
18412
|
additionalProperties: false
|
|
18729
18413
|
},
|
|
18730
|
-
annotations: { title: "Turn smart filters on or off", ...
|
|
18414
|
+
annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT3 },
|
|
18731
18415
|
handler: ({ layerId, enabled }) => {
|
|
18732
18416
|
const id = smartId(layerId);
|
|
18733
18417
|
controller.setSmartFiltersEnabled(id, enabled === true);
|
|
@@ -18741,7 +18425,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18741
18425
|
inputSchema: {
|
|
18742
18426
|
type: "object",
|
|
18743
18427
|
properties: {
|
|
18744
|
-
layerId:
|
|
18428
|
+
layerId: LAYER_ID3,
|
|
18745
18429
|
from: { type: "string", enum: ["reveal-all", "hide-all", "selection", "none", "keep"], description: "What the mask starts from; none removes it; keep only changes the properties below." },
|
|
18746
18430
|
density: { type: "number", minimum: 0, maximum: 1, description: "How much hidden areas hide, 0..1 (default 1)." },
|
|
18747
18431
|
feather: { type: "number", minimum: 0, maximum: 1e3, description: "Gaussian softening in px (default 0)." },
|
|
@@ -18751,7 +18435,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18751
18435
|
required: ["layerId", "from"],
|
|
18752
18436
|
additionalProperties: false
|
|
18753
18437
|
},
|
|
18754
|
-
annotations: { title: "Set the smart filter mask", ...
|
|
18438
|
+
annotations: { title: "Set the smart filter mask", ...WRITE6 },
|
|
18755
18439
|
handler: (args) => {
|
|
18756
18440
|
const id = smartId(args.layerId);
|
|
18757
18441
|
const props = {};
|
|
@@ -18764,11 +18448,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18764
18448
|
}
|
|
18765
18449
|
|
|
18766
18450
|
// src/image-editor/shape-tools.ts
|
|
18767
|
-
var
|
|
18768
|
-
var
|
|
18769
|
-
var
|
|
18770
|
-
var
|
|
18771
|
-
var
|
|
18451
|
+
var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18452
|
+
var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18453
|
+
var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18454
|
+
var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18455
|
+
var LAYER_ID4 = { type: "string", description: "Shape layer id from list_layers (type shape) or add_shape_layer." };
|
|
18772
18456
|
var COMPONENT_INDEX = { type: "integer", minimum: 0, description: "Component index from get_shape_layer (0 = bottom component)." };
|
|
18773
18457
|
var OP = {
|
|
18774
18458
|
type: "string",
|
|
@@ -18790,7 +18474,7 @@ var BOX = {
|
|
|
18790
18474
|
height: NUM("Height in pixels."),
|
|
18791
18475
|
transform: { $ref: "#/$defs/matrix" }
|
|
18792
18476
|
};
|
|
18793
|
-
var
|
|
18477
|
+
var DEFS = {
|
|
18794
18478
|
matrix: MATRIX,
|
|
18795
18479
|
point: {
|
|
18796
18480
|
type: "object",
|
|
@@ -19017,8 +18701,8 @@ function createImageShapeTools(controller) {
|
|
|
19017
18701
|
name: "get_shape_layer",
|
|
19018
18702
|
title: "Read a shape layer",
|
|
19019
18703
|
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.",
|
|
19020
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19021
|
-
annotations: { title: "Read a shape layer", ...
|
|
18704
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
18705
|
+
annotations: { title: "Read a shape layer", ...READ9 },
|
|
19022
18706
|
handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
|
|
19023
18707
|
};
|
|
19024
18708
|
const add2 = {
|
|
@@ -19027,7 +18711,7 @@ function createImageShapeTools(controller) {
|
|
|
19027
18711
|
description: "Adds a vector shape layer and makes it active: a live shape (rect, ellipse, polygon, star, line), a free path (SVG path data or anchors), or several components combined with path operations. fill defaults to the foreground colour (none for an open path with a stroke); give stroke for an outline. It renders sharp at any size, can be moved and transformed without losing quality, and takes masks, effects, clipping and blend modes like any layer. Goes above the active layer unless placed. One undo step. Returns the layer and the shape.",
|
|
19028
18712
|
inputSchema: {
|
|
19029
18713
|
type: "object",
|
|
19030
|
-
$defs:
|
|
18714
|
+
$defs: DEFS,
|
|
19031
18715
|
properties: {
|
|
19032
18716
|
...GEOMETRY2,
|
|
19033
18717
|
components: {
|
|
@@ -19049,7 +18733,7 @@ function createImageShapeTools(controller) {
|
|
|
19049
18733
|
},
|
|
19050
18734
|
additionalProperties: false
|
|
19051
18735
|
},
|
|
19052
|
-
annotations: { title: "Add a shape layer", ...
|
|
18736
|
+
annotations: { title: "Add a shape layer", ...WRITE7 },
|
|
19053
18737
|
handler: (args) => {
|
|
19054
18738
|
const init = { ...geometry(args) };
|
|
19055
18739
|
if (args.components !== void 0) init.components = args.components.map(geometry);
|
|
@@ -19067,9 +18751,9 @@ function createImageShapeTools(controller) {
|
|
|
19067
18751
|
description: "Changes a shape layer\u2019s fill, stroke or fill rule and renders it again: fill replaces the fill (null removes it); stroke changes only the settings given (null removes the stroke; a new stroke needs width and paint). Geometry is untouched (set_shape_component edits paths). One undo step. Returns the shape.",
|
|
19068
18752
|
inputSchema: {
|
|
19069
18753
|
type: "object",
|
|
19070
|
-
$defs:
|
|
18754
|
+
$defs: DEFS,
|
|
19071
18755
|
properties: {
|
|
19072
|
-
layerId:
|
|
18756
|
+
layerId: LAYER_ID4,
|
|
19073
18757
|
fill: { anyOf: [{ $ref: "#/$defs/paint" }, { type: "null", description: "No fill." }], description: "New fill paint, or null for none." },
|
|
19074
18758
|
stroke: { anyOf: [{ $ref: "#/$defs/stroke" }, { type: "null", description: "No stroke." }], description: "Stroke settings to change, or null to remove the stroke." },
|
|
19075
18759
|
fillRule: { type: "string", enum: ["nonzero", "evenodd"], description: "Winding rule within a component." }
|
|
@@ -19077,7 +18761,7 @@ function createImageShapeTools(controller) {
|
|
|
19077
18761
|
required: ["layerId"],
|
|
19078
18762
|
additionalProperties: false
|
|
19079
18763
|
},
|
|
19080
|
-
annotations: { title: "Restyle a shape", ...
|
|
18764
|
+
annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT4 },
|
|
19081
18765
|
handler: ({ layerId, fill, stroke, fillRule }) => {
|
|
19082
18766
|
const id = shapeId(layerId);
|
|
19083
18767
|
if (fill === void 0 && stroke === void 0 && fillRule === void 0) throw new LayerOperationError("Give fill, stroke or fillRule to change.");
|
|
@@ -19090,9 +18774,9 @@ function createImageShapeTools(controller) {
|
|
|
19090
18774
|
description: "Changes one component of a shape layer: shape sets its live shape (fields you leave out keep their values when the kind stays the same, e.g. only radii), subpaths replaces its path (which ends the live shape), op changes its path operation. Positions are document pixels. One undo step. Returns the shape.",
|
|
19091
18775
|
inputSchema: {
|
|
19092
18776
|
type: "object",
|
|
19093
|
-
$defs:
|
|
18777
|
+
$defs: DEFS,
|
|
19094
18778
|
properties: {
|
|
19095
|
-
layerId:
|
|
18779
|
+
layerId: LAYER_ID4,
|
|
19096
18780
|
componentIndex: COMPONENT_INDEX,
|
|
19097
18781
|
shape: {
|
|
19098
18782
|
type: "object",
|
|
@@ -19125,7 +18809,7 @@ function createImageShapeTools(controller) {
|
|
|
19125
18809
|
required: ["layerId", "componentIndex"],
|
|
19126
18810
|
additionalProperties: false
|
|
19127
18811
|
},
|
|
19128
|
-
annotations: { title: "Edit a shape component", ...
|
|
18812
|
+
annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT4 },
|
|
19129
18813
|
handler: ({ layerId, componentIndex, ...rest }) => {
|
|
19130
18814
|
const id = shapeId(layerId);
|
|
19131
18815
|
const change = geometry(rest);
|
|
@@ -19139,28 +18823,28 @@ function createImageShapeTools(controller) {
|
|
|
19139
18823
|
description: "Adds a component to a shape layer and combines it with the components below it by op: combine (union), subtract, intersect or exclude, as Photoshop\u2019s path operations. Goes on top unless index is given. One undo step. Returns the shape.",
|
|
19140
18824
|
inputSchema: {
|
|
19141
18825
|
type: "object",
|
|
19142
|
-
$defs:
|
|
19143
|
-
properties: { layerId:
|
|
18826
|
+
$defs: DEFS,
|
|
18827
|
+
properties: { layerId: LAYER_ID4, ...GEOMETRY2, op: OP, index: { type: "integer", minimum: 0, description: "Position among the components, 0 = bottom (default the top)." } },
|
|
19144
18828
|
required: ["layerId"],
|
|
19145
18829
|
additionalProperties: false
|
|
19146
18830
|
},
|
|
19147
|
-
annotations: { title: "Add a shape component", ...
|
|
18831
|
+
annotations: { title: "Add a shape component", ...WRITE7 },
|
|
19148
18832
|
handler: ({ layerId, index, ...rest }) => controller.addShapeComponent(shapeId(layerId), geometry(rest), index)
|
|
19149
18833
|
};
|
|
19150
18834
|
const removeComponent = {
|
|
19151
18835
|
name: "remove_shape_component",
|
|
19152
18836
|
title: "Delete a shape component",
|
|
19153
18837
|
description: "Deletes one component of a shape layer (the last one cannot go: delete the layer instead). One undo step. Returns the shape.",
|
|
19154
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19155
|
-
annotations: { title: "Delete a shape component", ...
|
|
18838
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4, componentIndex: COMPONENT_INDEX }, required: ["layerId", "componentIndex"], additionalProperties: false },
|
|
18839
|
+
annotations: { title: "Delete a shape component", ...DESTRUCTIVE5 },
|
|
19156
18840
|
handler: ({ layerId, componentIndex }) => controller.removeShapeComponent(shapeId(layerId), componentIndex)
|
|
19157
18841
|
};
|
|
19158
18842
|
const merge = {
|
|
19159
18843
|
name: "merge_shape_components",
|
|
19160
18844
|
title: "Merge shape components",
|
|
19161
18845
|
description: "Merge Shape Components: the area a shape\u2019s components combine to (after their path operations) becomes one plain component; live shapes become paths. The look is unchanged. One undo step. Returns the shape.",
|
|
19162
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19163
|
-
annotations: { title: "Merge shape components", ...
|
|
18846
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
18847
|
+
annotations: { title: "Merge shape components", ...DESTRUCTIVE5 },
|
|
19164
18848
|
handler: ({ layerId }) => controller.mergeShapeComponents(shapeId(layerId))
|
|
19165
18849
|
};
|
|
19166
18850
|
const layerArg = (v) => {
|
|
@@ -19214,7 +18898,7 @@ function createImageShapeTools(controller) {
|
|
|
19214
18898
|
title: "Make a path from the selection",
|
|
19215
18899
|
description: "Make Work Path: traces the selection's outline (where it is at least half selected) into closed B\xE9zier subpaths in document pixels, holes included, within tolerance px. Changes nothing. Returns svg (compact SVG path data) and fillRule evenodd, ready for add_vector_mask, set_vector_mask_path or add_shape_layer (pass the svg as subpaths and fillRule evenodd), plus bounds and the anchor count. Use add_vector_mask from selection to do it in one step.",
|
|
19216
18900
|
inputSchema: { type: "object", properties: { ...TRACE_PROPS, anchors: { type: "boolean", description: "Also return the subpaths as anchors with handles (default false: svg only)." } }, additionalProperties: false },
|
|
19217
|
-
annotations: { title: "Make a path from the selection", ...
|
|
18901
|
+
annotations: { title: "Make a path from the selection", ...READ9 },
|
|
19218
18902
|
handler: (args) => {
|
|
19219
18903
|
const out = controller.selectionToPath(traceOptions(args));
|
|
19220
18904
|
const { subpaths, ...rest } = out;
|
|
@@ -19227,7 +18911,7 @@ function createImageShapeTools(controller) {
|
|
|
19227
18911
|
description: "Make Selection: fills a path (a live shape, free subpaths or SVG path data, or components, in document pixels, as add_shape_layer takes) into a selection, combined with the current one by mode, with feather px and antiAlias. Use it to select along B\xE9zier curves, or to turn a path from selection_to_path or get_vector_mask back into a selection. One undo step. Returns the selection.",
|
|
19228
18912
|
inputSchema: {
|
|
19229
18913
|
type: "object",
|
|
19230
|
-
$defs:
|
|
18914
|
+
$defs: DEFS,
|
|
19231
18915
|
properties: {
|
|
19232
18916
|
pathId: { ...PATH_ID, description: "A document path from list_paths, instead of shape / subpaths / components." },
|
|
19233
18917
|
...PATH_PROPS,
|
|
@@ -19237,7 +18921,7 @@ function createImageShapeTools(controller) {
|
|
|
19237
18921
|
},
|
|
19238
18922
|
additionalProperties: false
|
|
19239
18923
|
},
|
|
19240
|
-
annotations: { title: "Make a selection from a path", ...
|
|
18924
|
+
annotations: { title: "Make a selection from a path", ...WRITE7 },
|
|
19241
18925
|
handler: (args) => {
|
|
19242
18926
|
const mode = args.mode;
|
|
19243
18927
|
controller.pathToSelection(fromPathId(args) ?? pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
|
|
@@ -19250,7 +18934,7 @@ function createImageShapeTools(controller) {
|
|
|
19250
18934
|
title: "Read a vector mask",
|
|
19251
18935
|
description: "Reads a layer's vector mask: enabled, linked, inverted, fill rule, density, feather, the bounds of its path and its components (op, live shape, subpaths in document pixels). Use it before set_vector_mask_path to edit the path. Returns null when the layer has none.",
|
|
19252
18936
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19253
|
-
annotations: { title: "Read a vector mask", ...
|
|
18937
|
+
annotations: { title: "Read a vector mask", ...READ9 },
|
|
19254
18938
|
handler: ({ layerId }) => ({ vectorMask: controller.getVectorMask(layerArg(layerId)) })
|
|
19255
18939
|
};
|
|
19256
18940
|
const addVectorMask = {
|
|
@@ -19259,7 +18943,7 @@ function createImageShapeTools(controller) {
|
|
|
19259
18943
|
description: "Layer \u203A Vector Mask: a path that reveals the layer inside it and stays sharp at any size, on top of any raster mask (both apply). from path takes a live shape, free subpaths or components like add_shape_layer; from selection traces the current selection (within tolerance px); reveal-all and hide-all start with an empty path. Use it for hard-edged geometric or traced cutouts that must stay editable; use add_layer_mask for soft or painted ones. A linked vector mask moves and transforms with the layer. Replaces an existing vector mask. One undo step. Returns the vector mask.",
|
|
19260
18944
|
inputSchema: {
|
|
19261
18945
|
type: "object",
|
|
19262
|
-
$defs:
|
|
18946
|
+
$defs: DEFS,
|
|
19263
18947
|
properties: {
|
|
19264
18948
|
layerId: LAYER,
|
|
19265
18949
|
from: { type: "string", enum: ["path", "selection", "reveal-all", "hide-all"], description: "path (default when a shape, subpaths, components or pathId are given), selection (trace the current selection), reveal-all or hide-all (an empty path)." },
|
|
@@ -19270,7 +18954,7 @@ function createImageShapeTools(controller) {
|
|
|
19270
18954
|
required: ["layerId"],
|
|
19271
18955
|
additionalProperties: false
|
|
19272
18956
|
},
|
|
19273
|
-
annotations: { title: "Add a vector mask", ...
|
|
18957
|
+
annotations: { title: "Add a vector mask", ...WRITE7 },
|
|
19274
18958
|
handler: (args) => {
|
|
19275
18959
|
const id = layerArg(args.layerId);
|
|
19276
18960
|
const spec = fromPathId(args) ?? pathSpec(args);
|
|
@@ -19285,8 +18969,8 @@ function createImageShapeTools(controller) {
|
|
|
19285
18969
|
name: "set_vector_mask_path",
|
|
19286
18970
|
title: "Replace a vector mask path",
|
|
19287
18971
|
description: "Replaces the path of a layer's vector mask (shape, subpaths or components, document pixels); enabled, linked, inverted, density and feather are kept. Read the current path with get_vector_mask first to change part of it. One undo step. Returns the vector mask.",
|
|
19288
|
-
inputSchema: { type: "object", $defs:
|
|
19289
|
-
annotations: { title: "Replace a vector mask path", ...
|
|
18972
|
+
inputSchema: { type: "object", $defs: DEFS, properties: { layerId: LAYER, ...PATH_PROPS }, required: ["layerId"], additionalProperties: false },
|
|
18973
|
+
annotations: { title: "Replace a vector mask path", ...WRITE_IDEMPOTENT4 },
|
|
19290
18974
|
handler: (args) => {
|
|
19291
18975
|
const id = layerArg(args.layerId);
|
|
19292
18976
|
controller.setVectorMaskPath(id, pathSpec(args));
|
|
@@ -19310,7 +18994,7 @@ function createImageShapeTools(controller) {
|
|
|
19310
18994
|
required: ["layerId"],
|
|
19311
18995
|
additionalProperties: false
|
|
19312
18996
|
},
|
|
19313
|
-
annotations: { title: "Set vector mask properties", ...
|
|
18997
|
+
annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT4 },
|
|
19314
18998
|
handler: ({ layerId, ...props }) => {
|
|
19315
18999
|
const id = layerArg(layerId);
|
|
19316
19000
|
controller.setVectorMaskProps(id, props);
|
|
@@ -19336,7 +19020,7 @@ function createImageShapeTools(controller) {
|
|
|
19336
19020
|
required: ["layerId", "component", "subpath", "segment", "mode"],
|
|
19337
19021
|
additionalProperties: false
|
|
19338
19022
|
},
|
|
19339
|
-
annotations: { title: "Set a vector mask segment's edge", ...
|
|
19023
|
+
annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT4 },
|
|
19340
19024
|
handler: ({ layerId, component, subpath, segment, mode, radius, inner, outer }) => {
|
|
19341
19025
|
const id = layerArg(layerId);
|
|
19342
19026
|
const vectorMask = controller.setVectorMaskEdge(
|
|
@@ -19353,7 +19037,7 @@ function createImageShapeTools(controller) {
|
|
|
19353
19037
|
title: "Rasterize a vector mask",
|
|
19354
19038
|
description: "Layer \u203A Rasterize \u203A Vector Mask: multiplies the path (with its density and feather) into the layer's raster mask, adding one if needed, and removes the vector mask, so the mask can be painted. The path can no longer be edited (undo_image brings it back). One undo step. Returns the layer's raster mask summary.",
|
|
19355
19039
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19356
|
-
annotations: { title: "Rasterize a vector mask", ...
|
|
19040
|
+
annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE5 },
|
|
19357
19041
|
handler: ({ layerId }) => {
|
|
19358
19042
|
const id = layerArg(layerId);
|
|
19359
19043
|
const mask = controller.rasterizeVectorMask(id);
|
|
@@ -19365,7 +19049,7 @@ function createImageShapeTools(controller) {
|
|
|
19365
19049
|
title: "Delete a vector mask",
|
|
19366
19050
|
description: "Deletes a layer's vector mask without applying it (the raster mask, if any, stays). Disable it instead with set_vector_mask_properties enabled false to keep it. One undo step. Returns the layer id.",
|
|
19367
19051
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19368
|
-
annotations: { title: "Delete a vector mask", ...
|
|
19052
|
+
annotations: { title: "Delete a vector mask", ...DESTRUCTIVE5 },
|
|
19369
19053
|
handler: ({ layerId }) => {
|
|
19370
19054
|
const id = layerArg(layerId);
|
|
19371
19055
|
controller.removeVectorMask(id);
|
|
@@ -19377,15 +19061,15 @@ function createImageShapeTools(controller) {
|
|
|
19377
19061
|
title: "List document paths",
|
|
19378
19062
|
description: "Paths panel: the document's saved paths and its Work Path (paths kept with the document, on no layer), each with id, name, work (true for the Work Path, which the next make_work_path replaces), fill rule, anchor count and bounds, and which is active. Use the ids with path_to_selection, add_vector_mask, fill_path, stroke_path and the other path tools.",
|
|
19379
19063
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
19380
|
-
annotations: { title: "List document paths", ...
|
|
19064
|
+
annotations: { title: "List document paths", ...READ9 },
|
|
19381
19065
|
handler: () => ({ paths: controller.getPaths().map((p) => pathSummary(p.id)), activePathId: controller.getState().activePathId ?? null })
|
|
19382
19066
|
};
|
|
19383
|
-
const
|
|
19067
|
+
const getPath = {
|
|
19384
19068
|
name: "get_path",
|
|
19385
19069
|
title: "Read a document path",
|
|
19386
19070
|
description: "Reads a document path: its summary, svg (compact SVG path data) and components (op, subpaths of anchors with handles, in document pixels), ready to edit and pass back to set_path_geometry.",
|
|
19387
19071
|
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
19388
|
-
annotations: { title: "Read a document path", ...
|
|
19072
|
+
annotations: { title: "Read a document path", ...READ9 },
|
|
19389
19073
|
handler: ({ pathId }) => {
|
|
19390
19074
|
const p = controller.getPath(String(pathId));
|
|
19391
19075
|
if (!p) throw new Error(`No path "${String(pathId)}". Call list_paths for ids.`);
|
|
@@ -19397,7 +19081,7 @@ function createImageShapeTools(controller) {
|
|
|
19397
19081
|
title: "Make a work path from the selection",
|
|
19398
19082
|
description: "Paths \u203A Make Work Path: traces the selection's outline (within tolerance px) into the Work Path, replacing the last Work Path unless it was saved (rename_path saves it). Use it to keep a selection as an editable, resolution-independent outline. One undo step. Returns the path.",
|
|
19399
19083
|
inputSchema: { type: "object", properties: { ...TRACE_PROPS }, additionalProperties: false },
|
|
19400
|
-
annotations: { title: "Make a work path from the selection", ...
|
|
19084
|
+
annotations: { title: "Make a work path from the selection", ...WRITE7 },
|
|
19401
19085
|
handler: (args) => ({ path: pathSummary(controller.makeWorkPath(traceOptions(args)).id) })
|
|
19402
19086
|
};
|
|
19403
19087
|
const addPath = {
|
|
@@ -19406,11 +19090,11 @@ function createImageShapeTools(controller) {
|
|
|
19406
19090
|
description: "Adds a saved document path from a live shape, free subpaths or SVG path data, or components (document pixels), as add_shape_layer takes them. One undo step. Returns the path.",
|
|
19407
19091
|
inputSchema: {
|
|
19408
19092
|
type: "object",
|
|
19409
|
-
$defs:
|
|
19093
|
+
$defs: DEFS,
|
|
19410
19094
|
properties: { name: { type: "string", description: 'The path name (default "Path n").' }, ...PATH_PROPS },
|
|
19411
19095
|
additionalProperties: false
|
|
19412
19096
|
},
|
|
19413
|
-
annotations: { title: "Add a document path", ...
|
|
19097
|
+
annotations: { title: "Add a document path", ...WRITE7 },
|
|
19414
19098
|
handler: (args) => {
|
|
19415
19099
|
const spec = pathSpec(args);
|
|
19416
19100
|
if (!spec.components?.length && spec.shape === void 0 && spec.subpaths === void 0) throw new Error("Give the path as shape, subpaths or components.");
|
|
@@ -19421,8 +19105,8 @@ function createImageShapeTools(controller) {
|
|
|
19421
19105
|
name: "set_path_geometry",
|
|
19422
19106
|
title: "Replace a document path",
|
|
19423
19107
|
description: "Replaces a document path's geometry (shape, subpaths or components, document pixels); its name is kept. Read it with get_path first to change part of it. One undo step. Returns the path.",
|
|
19424
|
-
inputSchema: { type: "object", $defs:
|
|
19425
|
-
annotations: { title: "Replace a document path", ...
|
|
19108
|
+
inputSchema: { type: "object", $defs: DEFS, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
19109
|
+
annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT4 },
|
|
19426
19110
|
handler: (args) => ({ path: pathSummary(controller.setPathGeometry(String(args.pathId), pathSpec(args)).id) })
|
|
19427
19111
|
};
|
|
19428
19112
|
const renamePath = {
|
|
@@ -19430,7 +19114,7 @@ function createImageShapeTools(controller) {
|
|
|
19430
19114
|
title: "Rename or save a path",
|
|
19431
19115
|
description: "Renames a document path. Renaming the Work Path saves it (Paths \u203A Save Path), so make_work_path no longer replaces it. One undo step. Returns the path.",
|
|
19432
19116
|
inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", minLength: 1, description: "The new name." } }, required: ["pathId", "name"], additionalProperties: false },
|
|
19433
|
-
annotations: { title: "Rename or save a path", ...
|
|
19117
|
+
annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT4 },
|
|
19434
19118
|
handler: ({ pathId, name }) => ({ path: pathSummary(controller.renamePath(String(pathId), String(name)).id) })
|
|
19435
19119
|
};
|
|
19436
19120
|
const duplicatePath = {
|
|
@@ -19438,7 +19122,7 @@ function createImageShapeTools(controller) {
|
|
|
19438
19122
|
title: "Duplicate a path",
|
|
19439
19123
|
description: 'Duplicates a document path as a saved path (default name "<name> copy"). One undo step. Returns the new path.',
|
|
19440
19124
|
inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", description: "The copy's name." } }, required: ["pathId"], additionalProperties: false },
|
|
19441
|
-
annotations: { title: "Duplicate a path", ...
|
|
19125
|
+
annotations: { title: "Duplicate a path", ...WRITE7 },
|
|
19442
19126
|
handler: ({ pathId, name }) => ({ path: pathSummary(controller.duplicatePath(String(pathId), name).id) })
|
|
19443
19127
|
};
|
|
19444
19128
|
const deletePath = {
|
|
@@ -19446,7 +19130,7 @@ function createImageShapeTools(controller) {
|
|
|
19446
19130
|
title: "Delete a path",
|
|
19447
19131
|
description: "Deletes a document path (undo_image brings it back). Returns the remaining paths.",
|
|
19448
19132
|
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
19449
|
-
annotations: { title: "Delete a path", ...
|
|
19133
|
+
annotations: { title: "Delete a path", ...DESTRUCTIVE5 },
|
|
19450
19134
|
handler: ({ pathId }) => {
|
|
19451
19135
|
controller.deletePath(String(pathId));
|
|
19452
19136
|
return { paths: controller.getPaths().map((p) => pathSummary(p.id)) };
|
|
@@ -19462,7 +19146,7 @@ function createImageShapeTools(controller) {
|
|
|
19462
19146
|
title: "Fill a path",
|
|
19463
19147
|
description: "Paths \u203A Fill Path: fills the area a document path encloses on a pixel layer with a colour. The selection is not changed. One undo step. Returns what was painted.",
|
|
19464
19148
|
inputSchema: { type: "object", properties: { pathId: PATH_ID, ...PAINT_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
19465
|
-
annotations: { title: "Fill a path", ...
|
|
19149
|
+
annotations: { title: "Fill a path", ...WRITE7 },
|
|
19466
19150
|
handler: (args) => controller.fillPath(String(args.pathId), { layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
19467
19151
|
};
|
|
19468
19152
|
const strokePath = {
|
|
@@ -19475,7 +19159,7 @@ function createImageShapeTools(controller) {
|
|
|
19475
19159
|
required: ["pathId", "width"],
|
|
19476
19160
|
additionalProperties: false
|
|
19477
19161
|
},
|
|
19478
|
-
annotations: { title: "Stroke a path", ...
|
|
19162
|
+
annotations: { title: "Stroke a path", ...WRITE7 },
|
|
19479
19163
|
handler: (args) => controller.strokePath(String(args.pathId), { width: args.width, layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
19480
19164
|
};
|
|
19481
19165
|
return [
|
|
@@ -19496,7 +19180,7 @@ function createImageShapeTools(controller) {
|
|
|
19496
19180
|
selectionToPath,
|
|
19497
19181
|
pathToSelection2,
|
|
19498
19182
|
listPaths,
|
|
19499
|
-
|
|
19183
|
+
getPath,
|
|
19500
19184
|
makeWorkPath,
|
|
19501
19185
|
addPath,
|
|
19502
19186
|
setPathGeometry,
|
|
@@ -19509,11 +19193,11 @@ function createImageShapeTools(controller) {
|
|
|
19509
19193
|
}
|
|
19510
19194
|
|
|
19511
19195
|
// src/image-editor/type-tools.ts
|
|
19512
|
-
var
|
|
19513
|
-
var
|
|
19514
|
-
var
|
|
19515
|
-
var
|
|
19516
|
-
var
|
|
19196
|
+
var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
19197
|
+
var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
19198
|
+
var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
19199
|
+
var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
19200
|
+
var LAYER_ID5 = { type: "string", description: "Type layer id from list_layers (type type) or add_text_layer." };
|
|
19517
19201
|
var START = { type: "integer", minimum: 0, description: "Start of the range in UTF-16 code units, as get_text_layer counts them (default 0)." };
|
|
19518
19202
|
var END = { type: "integer", minimum: 0, description: "End of the range, exclusive (default the end of the text)." };
|
|
19519
19203
|
var STYLE = {
|
|
@@ -19566,15 +19250,15 @@ function createImageTypeTools(controller) {
|
|
|
19566
19250
|
title: "List fonts",
|
|
19567
19251
|
description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
|
|
19568
19252
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
19569
|
-
annotations: { title: "List fonts", ...
|
|
19253
|
+
annotations: { title: "List fonts", ...READ10 },
|
|
19570
19254
|
handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
|
|
19571
19255
|
};
|
|
19572
19256
|
const get = {
|
|
19573
19257
|
name: "get_text_layer",
|
|
19574
19258
|
title: "Read a type layer",
|
|
19575
19259
|
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 orientation (horizontal or vertical), 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.",
|
|
19576
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19577
|
-
annotations: { title: "Read a type layer", ...
|
|
19260
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
19261
|
+
annotations: { title: "Read a type layer", ...READ10 },
|
|
19578
19262
|
handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
|
|
19579
19263
|
};
|
|
19580
19264
|
const add2 = {
|
|
@@ -19609,7 +19293,7 @@ function createImageTypeTools(controller) {
|
|
|
19609
19293
|
required: ["text", "x", "y"],
|
|
19610
19294
|
additionalProperties: false
|
|
19611
19295
|
},
|
|
19612
|
-
annotations: { title: "Add a type layer", ...
|
|
19296
|
+
annotations: { title: "Add a type layer", ...WRITE8 },
|
|
19613
19297
|
handler: (args) => {
|
|
19614
19298
|
const init = pick2(args, ["text", "x", "y", "box", "style", "paragraph", "orientation", "rotation", "name", "opacity", "blend", "aboveId", "belowId", "parentId", "index"]);
|
|
19615
19299
|
if (init.blend !== void 0) init.blend = init.blend;
|
|
@@ -19621,16 +19305,16 @@ function createImageTypeTools(controller) {
|
|
|
19621
19305
|
name: "set_text",
|
|
19622
19306
|
title: "Edit text",
|
|
19623
19307
|
description: "Replaces the text in [start, end) (default all of it) with text; inserted text takes the style of the character at start. Use start = end to insert. Returns the text layer with its new runs.",
|
|
19624
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19625
|
-
annotations: { title: "Edit text", ...
|
|
19308
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, text: { type: "string", description: "Replacement text (\\n starts a paragraph; empty deletes the range)." }, start: START, end: END }, required: ["layerId", "text"], additionalProperties: false },
|
|
19309
|
+
annotations: { title: "Edit text", ...WRITE8 },
|
|
19626
19310
|
handler: (args) => controller.setText(typeId(args.layerId), args.text, range(args))
|
|
19627
19311
|
};
|
|
19628
19312
|
const setStyle = {
|
|
19629
19313
|
name: "set_text_style",
|
|
19630
19314
|
title: "Style a range of text",
|
|
19631
19315
|
description: "Sets character style fields (font, weight, italic, size, colour, tracking, leading, baseline shift, underline, strike-through) over [start, end) of a type layer (default all of it); fields not given keep their values per run. Returns the text layer with its runs and missingFonts.",
|
|
19632
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19633
|
-
annotations: { title: "Style a range of text", ...
|
|
19316
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...STYLE }, required: ["layerId"], additionalProperties: false },
|
|
19317
|
+
annotations: { title: "Style a range of text", ...WRITE_IDEMPOTENT5 },
|
|
19634
19318
|
handler: (args) => {
|
|
19635
19319
|
const style = pick2(args, Object.keys(STYLE));
|
|
19636
19320
|
if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one style field: ${Object.keys(STYLE).join(", ")}.`);
|
|
@@ -19641,8 +19325,8 @@ function createImageTypeTools(controller) {
|
|
|
19641
19325
|
name: "set_paragraph_style",
|
|
19642
19326
|
title: "Style paragraphs",
|
|
19643
19327
|
description: "Sets paragraph fields (alignment, auto leading, indents, spacing) on every paragraph that [start, end) touches (default all). Returns the text layer.",
|
|
19644
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19645
|
-
annotations: { title: "Style paragraphs", ...
|
|
19328
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...PARAGRAPH }, required: ["layerId"], additionalProperties: false },
|
|
19329
|
+
annotations: { title: "Style paragraphs", ...WRITE_IDEMPOTENT5 },
|
|
19646
19330
|
handler: (args) => {
|
|
19647
19331
|
const style = pick2(args, Object.keys(PARAGRAPH));
|
|
19648
19332
|
if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one paragraph field: ${Object.keys(PARAGRAPH).join(", ")}.`);
|
|
@@ -19656,7 +19340,7 @@ function createImageTypeTools(controller) {
|
|
|
19656
19340
|
inputSchema: {
|
|
19657
19341
|
type: "object",
|
|
19658
19342
|
properties: {
|
|
19659
|
-
layerId:
|
|
19343
|
+
layerId: LAYER_ID5,
|
|
19660
19344
|
kind: { type: "string", enum: ["point", "box"], description: "point or box." },
|
|
19661
19345
|
width: { type: "number", minimum: 1, description: "Box width in pixels (kind box)." },
|
|
19662
19346
|
height: { type: "number", minimum: 1, description: "Box height in pixels (kind box)." }
|
|
@@ -19664,7 +19348,7 @@ function createImageTypeTools(controller) {
|
|
|
19664
19348
|
required: ["layerId", "kind"],
|
|
19665
19349
|
additionalProperties: false
|
|
19666
19350
|
},
|
|
19667
|
-
annotations: { title: "Point or paragraph text", ...
|
|
19351
|
+
annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT5 },
|
|
19668
19352
|
handler: ({ layerId, kind, width, height }) => {
|
|
19669
19353
|
const id = typeId(layerId);
|
|
19670
19354
|
if (kind === "box" && (width === void 0 || height === void 0)) throw new LayerOperationError("kind box needs width and height in pixels.");
|
|
@@ -19675,16 +19359,16 @@ function createImageTypeTools(controller) {
|
|
|
19675
19359
|
name: "set_text_orientation",
|
|
19676
19360
|
title: "Horizontal or vertical type",
|
|
19677
19361
|
description: "Type \u203A Orientation: sets a type layer horizontal (lines left to right) or vertical (columns top to bottom, right to left). The text, styles, frame and origin stay. One undo step. Returns the text layer with its orientation and new lines (columns).",
|
|
19678
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19679
|
-
annotations: { title: "Horizontal or vertical type", ...
|
|
19362
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, orientation: { ...ORIENTATION, description: "horizontal or vertical." } }, required: ["layerId", "orientation"], additionalProperties: false },
|
|
19363
|
+
annotations: { title: "Horizontal or vertical type", ...WRITE_IDEMPOTENT5 },
|
|
19680
19364
|
handler: ({ layerId, orientation }) => controller.setTextOrientation(typeId(layerId), orientation)
|
|
19681
19365
|
};
|
|
19682
19366
|
const toShape = {
|
|
19683
19367
|
name: "convert_text_to_shape",
|
|
19684
19368
|
title: "Convert text to a shape",
|
|
19685
19369
|
description: "Type \u203A Convert to Shape: the text\u2019s glyph outlines become a shape layer (same id, name, mask, effects, opacity, blend) that can be edited with the shape tools; the text is no longer editable. Needs a font shaper that gives outlines (the browser\u2019s canvas cannot). The fill is the first run\u2019s colour. One undo step. Returns the layer and warnings.",
|
|
19686
|
-
inputSchema: { type: "object", properties: { layerId:
|
|
19687
|
-
annotations: { title: "Convert text to a shape", ...
|
|
19370
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
19371
|
+
annotations: { title: "Convert text to a shape", ...DESTRUCTIVE6 },
|
|
19688
19372
|
handler: ({ layerId }) => {
|
|
19689
19373
|
const { layerId: id, warnings } = controller.convertTextToShape(typeId(layerId));
|
|
19690
19374
|
return { layer: layerSummary(id), shape: controller.getShapeLayer(id), warnings };
|
|
@@ -19718,7 +19402,7 @@ function createImageTypeTools(controller) {
|
|
|
19718
19402
|
required: ["text", "x", "y"],
|
|
19719
19403
|
additionalProperties: false
|
|
19720
19404
|
},
|
|
19721
|
-
annotations: { title: "Select the shape of text", ...
|
|
19405
|
+
annotations: { title: "Select the shape of text", ...WRITE8 },
|
|
19722
19406
|
handler: (args) => {
|
|
19723
19407
|
const init = pick2(args, ["text", "x", "y", "orientation", "box", "style", "paragraph", "rotation", "mode", "feather", "antiAlias"]);
|
|
19724
19408
|
controller.selectTextShape(init);
|
|
@@ -20231,12 +19915,12 @@ var SelectAndMaskSession = class {
|
|
|
20231
19915
|
this.recompute();
|
|
20232
19916
|
}
|
|
20233
19917
|
rescale() {
|
|
20234
|
-
const
|
|
20235
|
-
if (!
|
|
20236
|
-
const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(
|
|
20237
|
-
const w = Math.max(1, Math.round(
|
|
20238
|
-
const h = Math.max(1, Math.round(
|
|
20239
|
-
this.previewPixels = scalePixels(
|
|
19918
|
+
const px = this.pixels;
|
|
19919
|
+
if (!px) return;
|
|
19920
|
+
const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(px.width, px.height));
|
|
19921
|
+
const w = Math.max(1, Math.round(px.width * s));
|
|
19922
|
+
const h = Math.max(1, Math.round(px.height * s));
|
|
19923
|
+
this.previewPixels = scalePixels(px, w, h);
|
|
20240
19924
|
this.belowPreview = this.below ? scalePixels(this.below, w, h) : null;
|
|
20241
19925
|
this.baseMask = this.base?.bounds ? s === 1 ? this.base : resizeSelection(this.base, w, h) : null;
|
|
20242
19926
|
}
|
|
@@ -20245,8 +19929,8 @@ var SelectAndMaskSession = class {
|
|
|
20245
19929
|
* the page, or in the worker, where one job runs at a time and the newest state follows it.
|
|
20246
19930
|
*/
|
|
20247
19931
|
recompute() {
|
|
20248
|
-
const
|
|
20249
|
-
if (!
|
|
19932
|
+
const px = this.previewPixels;
|
|
19933
|
+
if (!px) return;
|
|
20250
19934
|
this.note = this.settingsValue.refineMode === "object" ? "Object aware refinement asks the segmentation model on OK; the preview refines by colour." : null;
|
|
20251
19935
|
if (this.controller.hasSelectionWorker) {
|
|
20252
19936
|
void this.recomputeInWorker();
|
|
@@ -20255,8 +19939,8 @@ var SelectAndMaskSession = class {
|
|
|
20255
19939
|
const { scale } = this.previewSize;
|
|
20256
19940
|
const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
|
|
20257
19941
|
try {
|
|
20258
|
-
const { selection, refineBrush } = applyRefineEdits(
|
|
20259
|
-
this.previewMask = selection?.bounds ? refineSelection(
|
|
19942
|
+
const { selection, refineBrush } = applyRefineEdits(px, this.baseMask, edits, px.width, px.height);
|
|
19943
|
+
this.previewMask = selection?.bounds ? refineSelection(px, selection, scaleParams(this.settingsValue.params, scale), refineBrush) : null;
|
|
20260
19944
|
this.error = null;
|
|
20261
19945
|
} catch (err) {
|
|
20262
19946
|
this.previewMask = null;
|
|
@@ -20272,13 +19956,13 @@ var SelectAndMaskSession = class {
|
|
|
20272
19956
|
this.computing = true;
|
|
20273
19957
|
do {
|
|
20274
19958
|
this.dirty = false;
|
|
20275
|
-
const
|
|
19959
|
+
const px = this.previewPixels;
|
|
20276
19960
|
const { scale } = this.previewSize;
|
|
20277
19961
|
const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
|
|
20278
19962
|
try {
|
|
20279
19963
|
const { mask } = await this.controller.runSelectionJob(
|
|
20280
19964
|
{ op: "refine-preview", base: this.baseMask ? serializeMask(this.baseMask) : null, edits, params: scaleParams(this.settingsValue.params, scale) },
|
|
20281
|
-
|
|
19965
|
+
px
|
|
20282
19966
|
);
|
|
20283
19967
|
this.previewMask = mask.bounds ? mask : null;
|
|
20284
19968
|
this.error = null;
|
|
@@ -20306,9 +19990,9 @@ var SelectAndMaskSession = class {
|
|
|
20306
19990
|
}
|
|
20307
19991
|
/** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
|
|
20308
19992
|
render() {
|
|
20309
|
-
const
|
|
20310
|
-
if (!
|
|
20311
|
-
const { width: w, height: h } =
|
|
19993
|
+
const px = this.previewPixels;
|
|
19994
|
+
if (!px) return new Uint8ClampedArray(0);
|
|
19995
|
+
const { width: w, height: h } = px;
|
|
20312
19996
|
const n = w * h;
|
|
20313
19997
|
const s = this.settingsValue;
|
|
20314
19998
|
const mask = (s.showOriginal ? this.baseMask : this.previewMask) ?? createSelectionMask(w, h);
|
|
@@ -20330,9 +20014,9 @@ var SelectAndMaskSession = class {
|
|
|
20330
20014
|
for (let i = 0; i < n; i++) {
|
|
20331
20015
|
const a = m[i] / 255;
|
|
20332
20016
|
const p = i * 4;
|
|
20333
|
-
const r =
|
|
20334
|
-
const g =
|
|
20335
|
-
const b =
|
|
20017
|
+
const r = px.data[p];
|
|
20018
|
+
const g = px.data[p + 1];
|
|
20019
|
+
const b = px.data[p + 2];
|
|
20336
20020
|
let o;
|
|
20337
20021
|
const x = i % w;
|
|
20338
20022
|
const y = (i - x) / w;
|
|
@@ -20559,8 +20243,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
|
|
|
20559
20243
|
const count = bw * bh;
|
|
20560
20244
|
for (let py = by; py < by + bh; py++) {
|
|
20561
20245
|
const rowOffset = py * width;
|
|
20562
|
-
for (let
|
|
20563
|
-
const idx = (rowOffset +
|
|
20246
|
+
for (let px = bx; px < bx + bw; px++) {
|
|
20247
|
+
const idx = (rowOffset + px) * 4;
|
|
20564
20248
|
rSum += data[idx];
|
|
20565
20249
|
gSum += data[idx + 1];
|
|
20566
20250
|
bSum += data[idx + 2];
|
|
@@ -20573,8 +20257,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
|
|
|
20573
20257
|
const aAvg = Math.round(aSum / count);
|
|
20574
20258
|
for (let py = by; py < by + bh; py++) {
|
|
20575
20259
|
const rowOffset = py * width;
|
|
20576
|
-
for (let
|
|
20577
|
-
const idx = (rowOffset +
|
|
20260
|
+
for (let px = bx; px < bx + bw; px++) {
|
|
20261
|
+
const idx = (rowOffset + px) * 4;
|
|
20578
20262
|
data[idx] = rAvg;
|
|
20579
20263
|
data[idx + 1] = gAvg;
|
|
20580
20264
|
data[idx + 2] = bAvg;
|
|
@@ -21074,179 +20758,6 @@ function layerPanels(layer, options = {}) {
|
|
|
21074
20758
|
return panels;
|
|
21075
20759
|
}
|
|
21076
20760
|
|
|
21077
|
-
// src/image-editor/layers/effects-ui.ts
|
|
21078
|
-
function layerEffectsPanel(layer) {
|
|
21079
|
-
const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
|
|
21080
|
-
if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
|
|
21081
|
-
if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
|
|
21082
|
-
const fx = layer.effects;
|
|
21083
|
-
const readOnly = Boolean(layer.locks?.all);
|
|
21084
|
-
return {
|
|
21085
|
-
available: true,
|
|
21086
|
-
readOnly,
|
|
21087
|
-
reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
|
|
21088
|
-
enabled: fx?.enabled ?? true,
|
|
21089
|
-
scale: fx?.scale ?? 1,
|
|
21090
|
-
rows: (fx?.items ?? []).map((e) => ({ id: e.id, kind: e.kind, label: layerEffectLabel(e.kind), enabled: e.enabled }))
|
|
21091
|
-
};
|
|
21092
|
-
}
|
|
21093
|
-
function layerEffectsBadge(layer) {
|
|
21094
|
-
if (!layer.effects?.items.length) return null;
|
|
21095
|
-
return hasActiveEffects(layer.effects) ? "on" : "off";
|
|
21096
|
-
}
|
|
21097
|
-
var LAYER_EFFECT_MENU = LAYER_EFFECT_KINDS.map((kind) => ({ kind, label: layerEffectLabel(kind) }));
|
|
21098
|
-
var BLENDS = BLEND_MODES.filter((m) => m.id !== "pigment").map((m) => ({ value: m.id, label: m.label }));
|
|
21099
|
-
var opt = (...pairs) => pairs.map(([value, label]) => ({ value, label }));
|
|
21100
|
-
function patternOptions(patterns) {
|
|
21101
|
-
return [...patterns.map((p) => ({ value: p.id, label: p.name || p.id })), ...builtinPatternIds().map((id) => ({ value: id, label: builtinPattern(id).name }))];
|
|
21102
|
-
}
|
|
21103
|
-
function getPath(o, path) {
|
|
21104
|
-
let v = o;
|
|
21105
|
-
for (const p of path.split(".")) {
|
|
21106
|
-
if (v === null || v === void 0) return void 0;
|
|
21107
|
-
if (Array.isArray(v)) v = p === "last" ? v[v.length - 1] : v[Number(p)];
|
|
21108
|
-
else v = v[p];
|
|
21109
|
-
}
|
|
21110
|
-
return v;
|
|
21111
|
-
}
|
|
21112
|
-
function setPath(o, parts, value) {
|
|
21113
|
-
if (!parts.length) return value;
|
|
21114
|
-
const [p, ...rest] = parts;
|
|
21115
|
-
if (Array.isArray(o)) {
|
|
21116
|
-
const i = p === "last" ? o.length - 1 : Number(p);
|
|
21117
|
-
const out = [...o];
|
|
21118
|
-
out[i] = setPath(o[i], rest, value);
|
|
21119
|
-
return out;
|
|
21120
|
-
}
|
|
21121
|
-
const r = o ?? {};
|
|
21122
|
-
return { ...r, [p]: setPath(r[p], rest, value) };
|
|
21123
|
-
}
|
|
21124
|
-
function fillControls(f, allowPattern, patterns) {
|
|
21125
|
-
const types = allowPattern ? opt(["color", "Color"], ["gradient", "Gradient"], ["pattern", "Pattern"]) : opt(["color", "Color"], ["gradient", "Gradient"]);
|
|
21126
|
-
const out = [{ key: "fill.type", label: "Fill", type: "select", value: f.type, options: types }];
|
|
21127
|
-
if (f.type === "color") out.push({ key: "fill.color", label: "Color", type: "color", value: f.color });
|
|
21128
|
-
else if (f.type === "gradient") out.push(...gradientControls("fill.gradient", f.gradient));
|
|
21129
|
-
else {
|
|
21130
|
-
out.push(
|
|
21131
|
-
{ key: "fill.patternId", label: "Pattern", type: "select", value: f.patternId, options: patternOptions(patterns) },
|
|
21132
|
-
{ key: "fill.scale", label: "Scale", type: "range", min: 0.01, max: 10, step: 0.01, value: f.scale, percent: true, unit: "%" }
|
|
21133
|
-
);
|
|
21134
|
-
}
|
|
21135
|
-
return out;
|
|
21136
|
-
}
|
|
21137
|
-
function gradientControls(prefix, g) {
|
|
21138
|
-
return [
|
|
21139
|
-
{ key: `${prefix}.stops.0.color`, label: "Start colour", type: "color", value: g.stops[0]?.color ?? "#000000" },
|
|
21140
|
-
{ key: `${prefix}.stops.last.color`, label: "End colour", type: "color", value: g.stops[g.stops.length - 1]?.color ?? "#ffffff" },
|
|
21141
|
-
{ key: `${prefix}.style`, label: "Style", type: "select", value: g.style, options: opt(["linear", "Linear"], ["radial", "Radial"], ["angle", "Angle"], ["reflected", "Reflected"], ["diamond", "Diamond"]) },
|
|
21142
|
-
{ key: `${prefix}.angle`, label: "Angle", type: "range", min: -180, max: 180, step: 1, value: g.angle, unit: "\xB0" },
|
|
21143
|
-
{ key: `${prefix}.scale`, label: "Scale", type: "range", min: 0.1, max: 1.5, step: 0.01, value: g.scale, percent: true, unit: "%" },
|
|
21144
|
-
{ key: `${prefix}.reverse`, label: "Reverse", type: "checkbox", value: g.reverse },
|
|
21145
|
-
{ key: `${prefix}.align`, label: "Align with layer", type: "checkbox", value: g.align }
|
|
21146
|
-
];
|
|
21147
|
-
}
|
|
21148
|
-
var px = (key2, label, value, max = 250) => ({ key: key2, label, type: "range", min: 0, max, step: 1, value, unit: "px" });
|
|
21149
|
-
var pct = (key2, label, value, min = 0, max = 1) => ({ key: key2, label, type: "range", min, max, step: 0.01, value, percent: true, unit: "%" });
|
|
21150
|
-
var deg = (key2, label, value, min = -180, max = 180) => ({ key: key2, label, type: "range", min, max, step: 1, value, unit: "\xB0" });
|
|
21151
|
-
function layerEffectControls(e, patterns = []) {
|
|
21152
|
-
const blended = e.kind === "bevel-emboss" ? [] : [
|
|
21153
|
-
{ key: "blend", label: "Blend mode", type: "select", value: e.blend, options: BLENDS },
|
|
21154
|
-
pct("opacity", "Opacity", e.opacity)
|
|
21155
|
-
];
|
|
21156
|
-
switch (e.kind) {
|
|
21157
|
-
case "drop-shadow":
|
|
21158
|
-
case "inner-shadow":
|
|
21159
|
-
return [
|
|
21160
|
-
...blended,
|
|
21161
|
-
{ key: "color", label: "Color", type: "color", value: e.color },
|
|
21162
|
-
{ key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
|
|
21163
|
-
deg("angle", "Angle", e.angle),
|
|
21164
|
-
px("distance", "Distance", e.distance, 500),
|
|
21165
|
-
e.kind === "drop-shadow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
|
|
21166
|
-
px("size", "Size", e.size),
|
|
21167
|
-
pct("noise", "Noise", e.noise),
|
|
21168
|
-
...e.kind === "drop-shadow" ? [{ key: "knocksOut", label: "Layer knocks out shadow", type: "checkbox", value: e.knocksOut }] : []
|
|
21169
|
-
];
|
|
21170
|
-
case "outer-glow":
|
|
21171
|
-
case "inner-glow":
|
|
21172
|
-
return [
|
|
21173
|
-
...blended,
|
|
21174
|
-
...fillControls(e.fill, false, patterns),
|
|
21175
|
-
{ key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["softer", "Softer"], ["precise", "Precise"]) },
|
|
21176
|
-
...e.kind === "inner-glow" ? [{ key: "source", label: "Source", type: "select", value: e.source, options: opt(["edge", "Edge"], ["center", "Center"]) }] : [],
|
|
21177
|
-
e.kind === "outer-glow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
|
|
21178
|
-
px("size", "Size", e.size),
|
|
21179
|
-
pct("range", "Range", e.range, 0.01, 1),
|
|
21180
|
-
pct("noise", "Noise", e.noise)
|
|
21181
|
-
];
|
|
21182
|
-
case "bevel-emboss":
|
|
21183
|
-
return [
|
|
21184
|
-
{ key: "style", label: "Style", type: "select", value: e.style, options: opt(["inner-bevel", "Inner Bevel"], ["outer-bevel", "Outer Bevel"], ["emboss", "Emboss"], ["pillow-emboss", "Pillow Emboss"], ["stroke-emboss", "Stroke Emboss"]) },
|
|
21185
|
-
{ key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["smooth", "Smooth"], ["chisel-hard", "Chisel Hard"], ["chisel-soft", "Chisel Soft"]) },
|
|
21186
|
-
pct("depth", "Depth", e.depth, 0, 10),
|
|
21187
|
-
{ key: "direction", label: "Direction", type: "select", value: e.direction, options: opt(["up", "Up"], ["down", "Down"]) },
|
|
21188
|
-
px("size", "Size", e.size),
|
|
21189
|
-
px("soften", "Soften", e.soften, 16),
|
|
21190
|
-
{ key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
|
|
21191
|
-
deg("angle", "Angle", e.angle),
|
|
21192
|
-
deg("altitude", "Altitude", e.altitude, 0, 90),
|
|
21193
|
-
{ key: "highlightColor", label: "Highlight", type: "color", value: e.highlightColor },
|
|
21194
|
-
{ key: "highlightBlend", label: "Highlight mode", type: "select", value: e.highlightBlend, options: BLENDS },
|
|
21195
|
-
pct("highlightOpacity", "Highlight opacity", e.highlightOpacity),
|
|
21196
|
-
{ key: "shadowColor", label: "Shadow", type: "color", value: e.shadowColor },
|
|
21197
|
-
{ key: "shadowBlend", label: "Shadow mode", type: "select", value: e.shadowBlend, options: BLENDS },
|
|
21198
|
-
pct("shadowOpacity", "Shadow opacity", e.shadowOpacity)
|
|
21199
|
-
];
|
|
21200
|
-
case "satin":
|
|
21201
|
-
return [
|
|
21202
|
-
...blended,
|
|
21203
|
-
{ key: "color", label: "Color", type: "color", value: e.color },
|
|
21204
|
-
deg("angle", "Angle", e.angle),
|
|
21205
|
-
px("distance", "Distance", e.distance),
|
|
21206
|
-
px("size", "Size", e.size),
|
|
21207
|
-
{ key: "invert", label: "Invert", type: "checkbox", value: e.invert }
|
|
21208
|
-
];
|
|
21209
|
-
case "color-overlay":
|
|
21210
|
-
return [...blended, { key: "color", label: "Color", type: "color", value: e.color }];
|
|
21211
|
-
case "gradient-overlay":
|
|
21212
|
-
return [...blended, ...gradientControls("gradient", e.gradient)];
|
|
21213
|
-
case "pattern-overlay":
|
|
21214
|
-
return [
|
|
21215
|
-
...blended,
|
|
21216
|
-
{ key: "patternId", label: "Pattern", type: "select", value: e.patternId, options: patternOptions(patterns) },
|
|
21217
|
-
pct("scale", "Scale", e.scale, 0.01, 10),
|
|
21218
|
-
deg("angle", "Angle", e.angle ?? 0),
|
|
21219
|
-
{ key: "link", label: "Link with layer", type: "checkbox", value: e.link ?? true }
|
|
21220
|
-
];
|
|
21221
|
-
case "stroke":
|
|
21222
|
-
return [
|
|
21223
|
-
...blended,
|
|
21224
|
-
px("size", "Size", e.size),
|
|
21225
|
-
{ key: "position", label: "Position", type: "select", value: e.position, options: opt(["outside", "Outside"], ["inside", "Inside"], ["center", "Center"]) },
|
|
21226
|
-
...fillControls(e.fill, true, patterns)
|
|
21227
|
-
];
|
|
21228
|
-
}
|
|
21229
|
-
}
|
|
21230
|
-
function fillOfType(current, type, patterns) {
|
|
21231
|
-
if (type === "gradient") return { type: "gradient", gradient: defaultEffectGradient() };
|
|
21232
|
-
if (type === "pattern") return { type: "pattern", patternId: patterns[0]?.id ?? "checker", scale: 1 };
|
|
21233
|
-
return { type: "color", color: current.type === "color" ? current.color : "#000000" };
|
|
21234
|
-
}
|
|
21235
|
-
function effectControlChange(effect, key2, value, patterns = []) {
|
|
21236
|
-
const [top, ...rest] = key2.split(".");
|
|
21237
|
-
if (top === "fill" && rest[0] === "type") return { fill: fillOfType(effect.fill, String(value), patterns) };
|
|
21238
|
-
if (top === "patternId" && !rest.length) {
|
|
21239
|
-
const name = patternOptions(patterns).find((o) => o.value === value)?.label;
|
|
21240
|
-
return name ? { patternId: value, name } : { patternId: value };
|
|
21241
|
-
}
|
|
21242
|
-
if (!rest.length) return { [top]: value };
|
|
21243
|
-
if (top === "fill" && rest[0] === "patternId") {
|
|
21244
|
-
const name = patternOptions(patterns).find((o) => o.value === value)?.label;
|
|
21245
|
-
return { fill: { ...effect.fill, patternId: value, ...name ? { name } : {} } };
|
|
21246
|
-
}
|
|
21247
|
-
return { [top]: setPath(getPath(effect, top), rest, value) };
|
|
21248
|
-
}
|
|
21249
|
-
|
|
21250
20761
|
// src/image-editor/layers/color-ui.ts
|
|
21251
20762
|
var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
|
|
21252
20763
|
var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
|
|
@@ -22846,10 +22357,10 @@ var ContentAwareFillSession = class _ContentAwareFillSession {
|
|
|
22846
22357
|
const len2 = dx * dx + dy * dy;
|
|
22847
22358
|
for (let y = y0; y <= y1; y++) {
|
|
22848
22359
|
for (let x = x0; x <= x1; x++) {
|
|
22849
|
-
const
|
|
22360
|
+
const px = win.x + x + 0.5 - from.x;
|
|
22850
22361
|
const py = win.y + y + 0.5 - from.y;
|
|
22851
|
-
const t = len2 > 0 ? Math.min(1, Math.max(0, (
|
|
22852
|
-
if ((
|
|
22362
|
+
const t = len2 > 0 ? Math.min(1, Math.max(0, (px * dx + py * dy) / len2)) : 0;
|
|
22363
|
+
if ((px - t * dx) ** 2 + (py - t * dy) ** 2 > r * r) continue;
|
|
22853
22364
|
const i = y * win.width + x;
|
|
22854
22365
|
area[i] = add2 && !hole[i] ? 1 : 0;
|
|
22855
22366
|
}
|
|
@@ -23414,6 +22925,7 @@ export {
|
|
|
23414
22925
|
createImageSubjectSelectionTool,
|
|
23415
22926
|
createImageTransformTools,
|
|
23416
22927
|
createImageTypeTools,
|
|
22928
|
+
createLayerEffectTools,
|
|
23417
22929
|
createMetricTextShaper,
|
|
23418
22930
|
createOutlineTextShaper,
|
|
23419
22931
|
createPigment,
|