@pixerate/editor 0.246.0 → 0.248.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/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.js +3 -3
- package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-DTDPFBLC.cjs} +5 -5
- package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-QLCXROJK.js} +2 -2
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-DQWPMGH2.js → chunk-5GLYUSNT.js} +1 -1
- package/dist/{chunk-Q2UYUWAZ.cjs → chunk-6G6ZDDDB.cjs} +390 -27
- package/dist/chunk-7T7JWTVE.cjs +192 -0
- package/dist/{chunk-UVPD55UZ.cjs → chunk-IBDU6EGZ.cjs} +35 -35
- package/dist/{chunk-FK5LTDOO.cjs → chunk-L6REDLNB.cjs} +2 -2
- package/dist/{chunk-LDPLEZ5T.js → chunk-NZ3O3A5C.js} +1 -1
- package/dist/{chunk-N6WUB3Y5.js → chunk-Q2HA52V4.js} +1 -1
- package/dist/chunk-SC2RZ5EF.js +192 -0
- package/dist/{chunk-5MFDD7SP.cjs → chunk-TPWB4Y6L.cjs} +1 -1
- package/dist/{chunk-VDAWA546.js → chunk-VNBUDVD4.js} +388 -25
- package/dist/{chunk-XTWXBQD4.cjs → chunk-WVS5KQDH.cjs} +442 -87
- package/dist/{chunk-A23PSOBB.js → chunk-XNRBMYNB.js} +1 -1
- package/dist/{chunk-CEPKXLBS.cjs → chunk-XWTRATIM.cjs} +23 -23
- package/dist/{chunk-4PMCMWQS.js → chunk-ZFSLEOSQ.js} +357 -2
- 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 +1059 -1552
- package/dist/image-editor/index.d.cts +1 -1
- package/dist/image-editor/index.d.ts +1 -1
- package/dist/image-editor/index.js +275 -768
- package/dist/paint-editor/controller.d.cts +34 -1
- package/dist/paint-editor/controller.d.ts +34 -1
- package/dist/paint-editor/index.cjs +426 -257
- package/dist/paint-editor/index.js +184 -15
- package/dist/paint-editor/procedural.d.cts +82 -5
- package/dist/paint-editor/procedural.d.ts +82 -5
- 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 +15 -2
- package/dist/paint-editor/ui.d.ts +15 -2
- package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.cts} +32 -5
- package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.ts} +32 -5
- package/dist/raster/index.cjs +13 -1
- package/dist/raster/index.d.cts +1 -0
- package/dist/raster/index.d.ts +1 -0
- package/dist/raster/index.js +12 -0
- package/dist/vector/index.cjs +962 -962
- package/dist/vector/index.js +4 -4
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +18 -27
- 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
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
parseOpenTypeFont,
|
|
9
9
|
removeAnchorsKeepingShape,
|
|
10
10
|
traceField
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-5GLYUSNT.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-ZFSLEOSQ.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-SC2RZ5EF.js";
|
|
468
478
|
import {
|
|
469
479
|
DEFAULT_GLOBAL_LIGHT,
|
|
470
480
|
INTERPOLATIONS,
|
|
@@ -733,8 +743,8 @@ import {
|
|
|
733
743
|
warpMeshParamAt,
|
|
734
744
|
warpMeshRows,
|
|
735
745
|
warpPresetMesh
|
|
736
|
-
} from "../chunk-
|
|
737
|
-
import "../chunk-
|
|
746
|
+
} from "../chunk-Q2HA52V4.js";
|
|
747
|
+
import "../chunk-VNBUDVD4.js";
|
|
738
748
|
import "../chunk-M6DNZNVY.js";
|
|
739
749
|
import {
|
|
740
750
|
bezierPathToSvg,
|
|
@@ -1686,13 +1696,13 @@ var ImageEditorRenderer = class {
|
|
|
1686
1696
|
ctx.save();
|
|
1687
1697
|
try {
|
|
1688
1698
|
applyImageProjectionToContext(ctx, projection);
|
|
1689
|
-
const
|
|
1699
|
+
const px = u / (projection.scale || 1);
|
|
1690
1700
|
ctx.beginPath();
|
|
1691
|
-
ctx.arc(b.x, b.y, Math.max(
|
|
1692
|
-
ctx.lineWidth = 2 *
|
|
1701
|
+
ctx.arc(b.x, b.y, Math.max(px, b.diameter / 2), 0, Math.PI * 2);
|
|
1702
|
+
ctx.lineWidth = 2 * px;
|
|
1693
1703
|
ctx.strokeStyle = "rgba(0,0,0,0.6)";
|
|
1694
1704
|
ctx.stroke();
|
|
1695
|
-
ctx.lineWidth =
|
|
1705
|
+
ctx.lineWidth = px;
|
|
1696
1706
|
ctx.strokeStyle = "#ffffff";
|
|
1697
1707
|
ctx.stroke();
|
|
1698
1708
|
} catch {
|
|
@@ -2239,32 +2249,32 @@ var ImageEditorRenderer = class {
|
|
|
2239
2249
|
this.outlineCache.set(selection, paths);
|
|
2240
2250
|
}
|
|
2241
2251
|
if (!paths.length) return;
|
|
2242
|
-
const
|
|
2252
|
+
const px = 1 / (scale || 1);
|
|
2243
2253
|
ctx.beginPath();
|
|
2244
2254
|
for (const p of paths) {
|
|
2245
2255
|
ctx.moveTo(p[0], p[1]);
|
|
2246
2256
|
for (let i = 2; i < p.length; i += 2) ctx.lineTo(p[i], p[i + 1]);
|
|
2247
2257
|
}
|
|
2248
|
-
ctx.lineWidth =
|
|
2258
|
+
ctx.lineWidth = px;
|
|
2249
2259
|
ctx.strokeStyle = "#ffffff";
|
|
2250
2260
|
ctx.stroke();
|
|
2251
2261
|
if (typeof ctx.setLineDash === "function") {
|
|
2252
|
-
ctx.setLineDash([4 *
|
|
2253
|
-
ctx.lineDashOffset = -offset *
|
|
2262
|
+
ctx.setLineDash([4 * px, 4 * px]);
|
|
2263
|
+
ctx.lineDashOffset = -offset * px;
|
|
2254
2264
|
}
|
|
2255
2265
|
ctx.strokeStyle = "#000000";
|
|
2256
2266
|
ctx.stroke();
|
|
2257
2267
|
if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
|
|
2258
2268
|
}
|
|
2259
2269
|
drawDraftPath(ctx, points, scale) {
|
|
2260
|
-
const
|
|
2270
|
+
const px = 1 / (scale || 1);
|
|
2261
2271
|
ctx.beginPath();
|
|
2262
2272
|
points.forEach((p, i) => i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y));
|
|
2263
2273
|
ctx.closePath();
|
|
2264
|
-
ctx.lineWidth =
|
|
2274
|
+
ctx.lineWidth = px;
|
|
2265
2275
|
ctx.strokeStyle = "#ffffff";
|
|
2266
2276
|
ctx.stroke();
|
|
2267
|
-
if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 *
|
|
2277
|
+
if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px, 4 * px]);
|
|
2268
2278
|
ctx.strokeStyle = "#000000";
|
|
2269
2279
|
ctx.stroke();
|
|
2270
2280
|
if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
|
|
@@ -2929,9 +2939,9 @@ function inspectMaskEdge(mask, image, options = {}) {
|
|
|
2929
2939
|
turnExcess += Math.max(0, total - closure);
|
|
2930
2940
|
outline += L;
|
|
2931
2941
|
for (let i = 0; i < n; i++) {
|
|
2932
|
-
const [
|
|
2933
|
-
if (
|
|
2934
|
-
const blk = block(Math.floor(
|
|
2942
|
+
const [px, py] = pts[i];
|
|
2943
|
+
if (px < 0 || py < 0 || px >= W || py >= H) continue;
|
|
2944
|
+
const blk = block(Math.floor(px), Math.floor(py));
|
|
2935
2945
|
blk.turn += Math.abs(turns[i]) - closure / n;
|
|
2936
2946
|
blk.len += 2;
|
|
2937
2947
|
}
|
|
@@ -4118,10 +4128,10 @@ function liveWire(map, from, to, band) {
|
|
|
4118
4128
|
const uy = (by - ay) / len;
|
|
4119
4129
|
for (let y = 0; y < h; y++) {
|
|
4120
4130
|
for (let x = 0; x < w; x++) {
|
|
4121
|
-
const
|
|
4131
|
+
const px = rx0 + x - ax;
|
|
4122
4132
|
const py = ry0 + y - ay;
|
|
4123
|
-
const t = Math.min(len, Math.max(0,
|
|
4124
|
-
if (Math.hypot(
|
|
4133
|
+
const t = Math.min(len, Math.max(0, px * ux + py * uy));
|
|
4134
|
+
if (Math.hypot(px - t * ux, py - t * uy) > half) continue;
|
|
4125
4135
|
const i = y * w + x;
|
|
4126
4136
|
inside[i] = 1;
|
|
4127
4137
|
const f = map.features(rx0 + x, ry0 + y);
|
|
@@ -5015,43 +5025,43 @@ function liftPixels(surface, sel, o) {
|
|
|
5015
5025
|
const area = { x: sb.x - o.x, y: sb.y - o.y, width: sb.width, height: sb.height };
|
|
5016
5026
|
const depth = surfaceDepth(surface);
|
|
5017
5027
|
if (depth !== 8) {
|
|
5018
|
-
const
|
|
5019
|
-
const kept2 =
|
|
5028
|
+
const px2 = readDeepRegion(surface, area, depth);
|
|
5029
|
+
const kept2 = px2.slice();
|
|
5020
5030
|
const r16 = depth === 16;
|
|
5021
5031
|
for (let y = 0; y < area.height; y++) {
|
|
5022
5032
|
for (let x = 0; x < area.width; x++) {
|
|
5023
5033
|
const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
|
|
5024
5034
|
const i = (y * area.width + x) * 4;
|
|
5025
5035
|
if (k <= 0) {
|
|
5026
|
-
|
|
5036
|
+
px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
|
|
5027
5037
|
continue;
|
|
5028
5038
|
}
|
|
5029
|
-
|
|
5030
|
-
if (!
|
|
5039
|
+
px2[i + 3] = r16 ? Math.round(px2[i + 3] * k) : px2[i + 3] * k;
|
|
5040
|
+
if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
|
|
5031
5041
|
kept2[i + 3] = r16 ? Math.round(kept2[i + 3] * (1 - k)) : kept2[i + 3] * (1 - k);
|
|
5032
5042
|
if (!kept2[i + 3]) kept2[i] = kept2[i + 1] = kept2[i + 2] = 0;
|
|
5033
5043
|
}
|
|
5034
5044
|
}
|
|
5035
|
-
const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area,
|
|
5045
|
+
const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px2);
|
|
5036
5046
|
return { lifted, rest: writeDeepRegion(surface, area, kept2) };
|
|
5037
5047
|
}
|
|
5038
|
-
const
|
|
5039
|
-
const kept = new Uint8ClampedArray(
|
|
5048
|
+
const px = readRegion(surface, area);
|
|
5049
|
+
const kept = new Uint8ClampedArray(px);
|
|
5040
5050
|
for (let y = 0; y < area.height; y++) {
|
|
5041
5051
|
for (let x = 0; x < area.width; x++) {
|
|
5042
5052
|
const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
|
|
5043
5053
|
const i = (y * area.width + x) * 4;
|
|
5044
5054
|
if (k <= 0) {
|
|
5045
|
-
|
|
5055
|
+
px[i] = px[i + 1] = px[i + 2] = px[i + 3] = 0;
|
|
5046
5056
|
continue;
|
|
5047
5057
|
}
|
|
5048
|
-
|
|
5049
|
-
if (!
|
|
5058
|
+
px[i + 3] = px[i + 3] * k;
|
|
5059
|
+
if (!px[i + 3]) px[i] = px[i + 1] = px[i + 2] = 0;
|
|
5050
5060
|
kept[i + 3] = kept[i + 3] * (1 - k);
|
|
5051
5061
|
if (!kept[i + 3]) kept[i] = kept[i + 1] = kept[i + 2] = 0;
|
|
5052
5062
|
}
|
|
5053
5063
|
}
|
|
5054
|
-
return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data:
|
|
5064
|
+
return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
|
|
5055
5065
|
}
|
|
5056
5066
|
function liftMask(mask, sel, o) {
|
|
5057
5067
|
const sb = sel.bounds;
|
|
@@ -5642,14 +5652,14 @@ function displayTransform(doc, proof) {
|
|
|
5642
5652
|
const g = gamut;
|
|
5643
5653
|
return (rgba) => {
|
|
5644
5654
|
if (g) {
|
|
5645
|
-
const
|
|
5655
|
+
const px = [0, 0, 0];
|
|
5646
5656
|
const flags = new Uint8Array(rgba.length >> 2);
|
|
5647
5657
|
for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
|
|
5648
5658
|
if (rgba[i + 3] === 0) continue;
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
if (g.outOfGamut(
|
|
5659
|
+
px[0] = rgba[i] / 255;
|
|
5660
|
+
px[1] = rgba[i + 1] / 255;
|
|
5661
|
+
px[2] = rgba[i + 2] / 255;
|
|
5662
|
+
if (g.outOfGamut(px)) flags[p] = 1;
|
|
5653
5663
|
}
|
|
5654
5664
|
tr.convert8(rgba, 4, rgba, 4);
|
|
5655
5665
|
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 +6463,12 @@ var ImageEditorController = class {
|
|
|
6453
6463
|
} else {
|
|
6454
6464
|
const sb = sel.bounds;
|
|
6455
6465
|
const src = { x: sb.x - layer.offset.x, y: sb.y - layer.offset.y, width: sb.width, height: sb.height };
|
|
6456
|
-
const
|
|
6466
|
+
const px = readRegion(surface, src);
|
|
6457
6467
|
const data = sel.data;
|
|
6458
6468
|
for (let y = 0; y < sb.height; y++) {
|
|
6459
|
-
for (let x = 0; x < sb.width; x++)
|
|
6469
|
+
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
6470
|
}
|
|
6461
|
-
copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data:
|
|
6471
|
+
copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y) };
|
|
6462
6472
|
delete copy.mask;
|
|
6463
6473
|
}
|
|
6464
6474
|
delete copy.source;
|
|
@@ -7109,9 +7119,9 @@ var ImageEditorController = class {
|
|
|
7109
7119
|
const bounds = this.getLayerBounds(layer.id);
|
|
7110
7120
|
if (bounds && point2.x >= bounds.x && point2.x <= bounds.x + bounds.width && point2.y >= bounds.y && point2.y <= bounds.y + bounds.height) {
|
|
7111
7121
|
const surface = this.surfaceOf(layer);
|
|
7112
|
-
const
|
|
7122
|
+
const px = Math.floor(point2.x - layer.offset.x);
|
|
7113
7123
|
const py = Math.floor(point2.y - layer.offset.y);
|
|
7114
|
-
const pixel = readPixel(surface,
|
|
7124
|
+
const pixel = readPixel(surface, px, py);
|
|
7115
7125
|
if (pixel.length >= 4 && pixel[3] >= alphaThreshold) return layer.id;
|
|
7116
7126
|
}
|
|
7117
7127
|
return null;
|
|
@@ -7123,9 +7133,9 @@ var ImageEditorController = class {
|
|
|
7123
7133
|
return null;
|
|
7124
7134
|
}
|
|
7125
7135
|
const surface = this.surfaceOf(layer);
|
|
7126
|
-
const
|
|
7136
|
+
const px = Math.floor(point2.x - layer.offset.x);
|
|
7127
7137
|
const py = Math.floor(point2.y - layer.offset.y);
|
|
7128
|
-
const pixel = readPixel(surface,
|
|
7138
|
+
const pixel = readPixel(surface, px, py);
|
|
7129
7139
|
if (pixel.length >= 4 && pixel[3] >= alphaThreshold) {
|
|
7130
7140
|
return layer.id;
|
|
7131
7141
|
}
|
|
@@ -7276,17 +7286,17 @@ var ImageEditorController = class {
|
|
|
7276
7286
|
*/
|
|
7277
7287
|
sourceSurface() {
|
|
7278
7288
|
const { width, height } = this.naturalSize;
|
|
7279
|
-
const fromPixels = (
|
|
7280
|
-
let s = this.sourceSurfaces.get(
|
|
7289
|
+
const fromPixels = (px2) => {
|
|
7290
|
+
let s = this.sourceSurfaces.get(px2);
|
|
7281
7291
|
if (!s) {
|
|
7282
|
-
s = surfaceFromPixels(
|
|
7283
|
-
this.sourceSurfaces.set(
|
|
7292
|
+
s = surfaceFromPixels(px2, 4);
|
|
7293
|
+
this.sourceSurfaces.set(px2, s);
|
|
7284
7294
|
}
|
|
7285
7295
|
return s;
|
|
7286
7296
|
};
|
|
7287
|
-
const
|
|
7288
|
-
const fits = Boolean(
|
|
7289
|
-
if (this.samplePixelsOverride && fits) return fromPixels(
|
|
7297
|
+
const px = this.samplePixels;
|
|
7298
|
+
const fits = Boolean(px && px.width === width && px.height === height);
|
|
7299
|
+
if (this.samplePixelsOverride && fits) return fromPixels(px);
|
|
7290
7300
|
const el = this.imageElement;
|
|
7291
7301
|
if (el) {
|
|
7292
7302
|
const cached = this.sourceSurfaces.get(el);
|
|
@@ -7300,7 +7310,7 @@ var ImageEditorController = class {
|
|
|
7300
7310
|
return s;
|
|
7301
7311
|
}
|
|
7302
7312
|
}
|
|
7303
|
-
return fits ? fromPixels(
|
|
7313
|
+
return fits ? fromPixels(px) : null;
|
|
7304
7314
|
}
|
|
7305
7315
|
opaqueCache = /* @__PURE__ */ new WeakMap();
|
|
7306
7316
|
/** Whether every source pixel is opaque (some legacy renders depend on it). */
|
|
@@ -7362,11 +7372,11 @@ var ImageEditorController = class {
|
|
|
7362
7372
|
const { width, height } = this.naturalSize;
|
|
7363
7373
|
let surface = emptySurface(4);
|
|
7364
7374
|
if (init.pixels) {
|
|
7365
|
-
const
|
|
7366
|
-
if (!(
|
|
7375
|
+
const px = init.pixels;
|
|
7376
|
+
if (!(px.width > 0 && px.height > 0) || px.data.length < px.width * px.height * 4) {
|
|
7367
7377
|
throw new LayerOperationError("pixels must be RGBA with width \xD7 height \xD7 4 bytes.");
|
|
7368
7378
|
}
|
|
7369
|
-
surface = surfaceFromPixels(
|
|
7379
|
+
surface = surfaceFromPixels(px, 4);
|
|
7370
7380
|
} else if (init.color !== void 0) {
|
|
7371
7381
|
const c = parseColor(init.color);
|
|
7372
7382
|
surface = solidSurface(4, { x: 0, y: 0, width, height }, packRgba(c[0], c[1], c[2], c[3]));
|
|
@@ -7470,9 +7480,9 @@ var ImageEditorController = class {
|
|
|
7470
7480
|
getEdgeColor(id) {
|
|
7471
7481
|
const layer = this.requireEdgeLayer(id);
|
|
7472
7482
|
const e = layer.edge ?? {};
|
|
7473
|
-
const
|
|
7483
|
+
const pct = (v) => Math.round((v ?? 0) * 1e3) / 10;
|
|
7474
7484
|
const hex = (c) => "#" + c.map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
7475
|
-
return { layerId: layer.id, decontaminate:
|
|
7485
|
+
return { layerId: layer.id, decontaminate: pct(e.decontaminate), despill: pct(e.despill), ambient: pct(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
|
|
7476
7486
|
}
|
|
7477
7487
|
requireEdgeLayer(id) {
|
|
7478
7488
|
const layer = this.getLayer(id);
|
|
@@ -7527,9 +7537,9 @@ var ImageEditorController = class {
|
|
|
7527
7537
|
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
7538
|
}
|
|
7529
7539
|
if (turningOn("ambient") && !this.maskHasSoftBand(layer) && layer.type === "pixel") {
|
|
7530
|
-
const
|
|
7540
|
+
const px = this.getLayerPixels(layer.id);
|
|
7531
7541
|
let soft = false;
|
|
7532
|
-
if (
|
|
7542
|
+
if (px) for (let i = 3; i < px.data.length && !soft; i += 4) soft = px.data[i] > 5 && px.data[i] < 250;
|
|
7533
7543
|
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
7544
|
}
|
|
7535
7545
|
const edge = next.decontaminate || next.despill || next.ambient || next.ambientColor ? next : void 0;
|
|
@@ -8155,14 +8165,14 @@ var ImageEditorController = class {
|
|
|
8155
8165
|
const surface = this.surfaceOf(layer);
|
|
8156
8166
|
const sb = sel.bounds;
|
|
8157
8167
|
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(
|
|
8168
|
+
const px = readRegion(surface, src);
|
|
8169
|
+
const kept = options.cut ? new Uint8ClampedArray(px) : null;
|
|
8160
8170
|
for (let y = 0; y < sb.height; y++) {
|
|
8161
8171
|
for (let x = 0; x < sb.width; x++) {
|
|
8162
8172
|
const c = sel.data[(sb.y + y) * sel.width + sb.x + x];
|
|
8163
8173
|
const i = (y * sb.width + x) * 4 + 3;
|
|
8164
8174
|
if (kept) kept[i] = Math.round(kept[i] * (1 - c / 255));
|
|
8165
|
-
|
|
8175
|
+
px[i] = Math.round(px[i] * (c / 255));
|
|
8166
8176
|
}
|
|
8167
8177
|
}
|
|
8168
8178
|
const copy = {
|
|
@@ -8172,7 +8182,7 @@ var ImageEditorController = class {
|
|
|
8172
8182
|
visible: true,
|
|
8173
8183
|
opacity: 1,
|
|
8174
8184
|
blend: "normal",
|
|
8175
|
-
surface: surfaceFromPixels({ width: src.width, height: src.height, data:
|
|
8185
|
+
surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y),
|
|
8176
8186
|
offset: { ...layer.offset }
|
|
8177
8187
|
};
|
|
8178
8188
|
let next = insertLayer(this.state.layers, copy, loc.parent?.id ?? null, loc.index + 1);
|
|
@@ -8609,8 +8619,8 @@ var ImageEditorController = class {
|
|
|
8609
8619
|
for (const [cid, c] of pending) {
|
|
8610
8620
|
try {
|
|
8611
8621
|
const url = `data:${BROWSER_IMAGE_TYPES[c.file.type]};base64,${bytesToBase64(c.file.bytes)}`;
|
|
8612
|
-
const
|
|
8613
|
-
const decoded = { ...c, kind: "raster", raster: rasterContents(
|
|
8622
|
+
const px = await this.decodeImage(url);
|
|
8623
|
+
const decoded = { ...c, kind: "raster", raster: rasterContents(px, c.name, cid).raster, width: px.width, height: px.height };
|
|
8614
8624
|
const swap = (layers) => {
|
|
8615
8625
|
let out = layers;
|
|
8616
8626
|
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 +8716,8 @@ var ImageEditorController = class {
|
|
|
8706
8716
|
const only = edited.layers.length === 1 ? edited.layers[0] : null;
|
|
8707
8717
|
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
8718
|
if (old?.kind === "raster" && plain3) {
|
|
8709
|
-
const
|
|
8710
|
-
next = rasterContents({ width, height, data:
|
|
8719
|
+
const px = readRegion(only.surface, { x: -only.offset.x, y: -only.offset.y, width, height });
|
|
8720
|
+
next = rasterContents({ width, height, data: px }, old.name, old.id);
|
|
8711
8721
|
} else {
|
|
8712
8722
|
const doc = { layers: edited.layers, globalLight: edited.globalLight, patterns: edited.patterns };
|
|
8713
8723
|
next = documentContents(doc, width, height, old?.kind === "document" ? old.name : `${(old?.name ?? "Contents").replace(/\.\w+$/, "")}.psb`, top.contentsId);
|
|
@@ -11499,9 +11509,9 @@ var ImageEditorController = class {
|
|
|
11499
11509
|
return;
|
|
11500
11510
|
}
|
|
11501
11511
|
const { width, height } = this.naturalSize;
|
|
11502
|
-
let
|
|
11503
|
-
if (
|
|
11504
|
-
const data = new Uint8ClampedArray(
|
|
11512
|
+
let px = await this.decodeImage(newDataUrl);
|
|
11513
|
+
if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
|
|
11514
|
+
const data = new Uint8ClampedArray(px.data);
|
|
11505
11515
|
const sel = this.state.selection?.bounds ? this.state.selection : null;
|
|
11506
11516
|
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
11517
|
return this.addPixelLayer({ name: "Inpaint", pixels: { width, height, data } });
|
|
@@ -11522,10 +11532,10 @@ var ImageEditorController = class {
|
|
|
11522
11532
|
if (!target) throw new LayerOperationError("There is no pixel layer to mask.");
|
|
11523
11533
|
requireUnlocked(target, "all", "mask it");
|
|
11524
11534
|
const { width, height } = this.naturalSize;
|
|
11525
|
-
let
|
|
11526
|
-
if (
|
|
11535
|
+
let px = await this.decodeImage(newDataUrl);
|
|
11536
|
+
if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
|
|
11527
11537
|
const alpha = new Uint8ClampedArray(width * height);
|
|
11528
|
-
for (let p = 0; p < alpha.length; p++) alpha[p] =
|
|
11538
|
+
for (let p = 0; p < alpha.length; p++) alpha[p] = px.data[p * 4 + 3];
|
|
11529
11539
|
let surface = surfaceFromPixels({ width, height, data: alpha }, 1, 0, 0, 0);
|
|
11530
11540
|
if (target.offset.x || target.offset.y) surface = translateSurface(surface, -target.offset.x, -target.offset.y);
|
|
11531
11541
|
this.commitLayers(setLayerMask(this.state.layers, target.id, { surface, defaultValue: 0 }));
|
|
@@ -12098,14 +12108,14 @@ var ImageEditorController = class {
|
|
|
12098
12108
|
const converted = [];
|
|
12099
12109
|
const unconverted = [];
|
|
12100
12110
|
const memo = /* @__PURE__ */ new Map();
|
|
12101
|
-
const
|
|
12111
|
+
const px = new Float32Array(4);
|
|
12102
12112
|
const hex = (h) => {
|
|
12103
12113
|
let out = memo.get(h.toLowerCase());
|
|
12104
12114
|
if (out === void 0) {
|
|
12105
12115
|
const n = parseInt(h.slice(1), 16);
|
|
12106
|
-
t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255],
|
|
12116
|
+
t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px);
|
|
12107
12117
|
const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0");
|
|
12108
|
-
out = `#${c(
|
|
12118
|
+
out = `#${c(px[0])}${c(px[1])}${c(px[2])}`;
|
|
12109
12119
|
memo.set(h.toLowerCase(), out);
|
|
12110
12120
|
}
|
|
12111
12121
|
return out;
|
|
@@ -12914,24 +12924,24 @@ function pixelsOnly(layers) {
|
|
|
12914
12924
|
}
|
|
12915
12925
|
return out;
|
|
12916
12926
|
}
|
|
12917
|
-
function resizePixels(
|
|
12918
|
-
const src =
|
|
12927
|
+
function resizePixels(px, width, height) {
|
|
12928
|
+
const src = px.data;
|
|
12919
12929
|
const out = new Uint8ClampedArray(width * height * 4);
|
|
12920
|
-
const kx =
|
|
12921
|
-
const ky =
|
|
12930
|
+
const kx = px.width / width;
|
|
12931
|
+
const ky = px.height / height;
|
|
12922
12932
|
for (let y = 0; y < height; y++) {
|
|
12923
|
-
const fy = Math.min(
|
|
12933
|
+
const fy = Math.min(px.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
|
|
12924
12934
|
const y0 = Math.floor(fy);
|
|
12925
|
-
const y1 = Math.min(
|
|
12935
|
+
const y1 = Math.min(px.height - 1, y0 + 1);
|
|
12926
12936
|
const ty = fy - y0;
|
|
12927
12937
|
for (let x = 0; x < width; x++) {
|
|
12928
|
-
const fx = Math.min(
|
|
12938
|
+
const fx = Math.min(px.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
|
|
12929
12939
|
const x0 = Math.floor(fx);
|
|
12930
|
-
const x1 = Math.min(
|
|
12940
|
+
const x1 = Math.min(px.width - 1, x0 + 1);
|
|
12931
12941
|
const tx = fx - x0;
|
|
12932
12942
|
for (let c = 0; c < 4; c++) {
|
|
12933
|
-
const a = src[(y0 *
|
|
12934
|
-
const b = src[(y1 *
|
|
12943
|
+
const a = src[(y0 * px.width + x0) * 4 + c] * (1 - tx) + src[(y0 * px.width + x1) * 4 + c] * tx;
|
|
12944
|
+
const b = src[(y1 * px.width + x0) * 4 + c] * (1 - tx) + src[(y1 * px.width + x1) * 4 + c] * tx;
|
|
12935
12945
|
out[(y * width + x) * 4 + c] = a * (1 - ty) + b * ty;
|
|
12936
12946
|
}
|
|
12937
12947
|
}
|
|
@@ -13803,8 +13813,8 @@ var REFINE_OUTPUTS = [
|
|
|
13803
13813
|
];
|
|
13804
13814
|
function describeSelection(mask) {
|
|
13805
13815
|
if (!mask || !mask.bounds) return "No selection";
|
|
13806
|
-
const
|
|
13807
|
-
const shown =
|
|
13816
|
+
const pct = selectionArea(mask) / (mask.width * mask.height) * 100;
|
|
13817
|
+
const shown = pct >= 10 ? Math.round(pct) : Math.round(pct * 10) / 10;
|
|
13808
13818
|
return `${mask.bounds.width} \xD7 ${mask.bounds.height} px selected (${shown}% of the image)`;
|
|
13809
13819
|
}
|
|
13810
13820
|
|
|
@@ -15341,14 +15351,14 @@ function rebin(bins, count) {
|
|
|
15341
15351
|
return out;
|
|
15342
15352
|
}
|
|
15343
15353
|
function histogramSummary(h, bins) {
|
|
15344
|
-
const
|
|
15354
|
+
const pct = (n) => h.samples ? round(n / h.samples * 100) : 0;
|
|
15345
15355
|
const channels = { red: h.red, green: h.green, blue: h.blue, luminance: h.luminance };
|
|
15346
15356
|
return {
|
|
15347
15357
|
samples: h.samples,
|
|
15348
15358
|
transparent: h.transparent,
|
|
15349
15359
|
clipping: {
|
|
15350
|
-
shadowsPercent: { red:
|
|
15351
|
-
highlightsPercent: { red:
|
|
15360
|
+
shadowsPercent: { red: pct(h.shadows[0]), green: pct(h.shadows[1]), blue: pct(h.shadows[2]) },
|
|
15361
|
+
highlightsPercent: { red: pct(h.highlights[0]), green: pct(h.highlights[1]), blue: pct(h.highlights[2]) }
|
|
15352
15362
|
},
|
|
15353
15363
|
stats: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, binStats(v, h.samples)])),
|
|
15354
15364
|
...bins ? { bins: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, rebin(v, bins)])) } : {}
|
|
@@ -16249,337 +16259,6 @@ function createImageLayerTools(controller) {
|
|
|
16249
16259
|
];
|
|
16250
16260
|
}
|
|
16251
16261
|
|
|
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
16262
|
// src/image-editor/selection/gesture.ts
|
|
16584
16263
|
function snapTo45(from, point2) {
|
|
16585
16264
|
const dx = point2.x - from.x;
|
|
@@ -17315,10 +16994,10 @@ var PaintGesture = class {
|
|
|
17315
16994
|
};
|
|
17316
16995
|
|
|
17317
16996
|
// src/image-editor/paint-tools.ts
|
|
17318
|
-
var
|
|
17319
|
-
var
|
|
16997
|
+
var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
16998
|
+
var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
17320
16999
|
var SET = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17321
|
-
var
|
|
17000
|
+
var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
17322
17001
|
var TARGET = {
|
|
17323
17002
|
layerId: { type: "string", description: "Layer to paint (default the active layer; see list_layers)." },
|
|
17324
17003
|
channel: {
|
|
@@ -17408,7 +17087,7 @@ function createImagePaintTools(controller) {
|
|
|
17408
17087
|
required: ["points"],
|
|
17409
17088
|
additionalProperties: false
|
|
17410
17089
|
},
|
|
17411
|
-
annotations: { title: "Paint a brush stroke", ...
|
|
17090
|
+
annotations: { title: "Paint a brush stroke", ...WRITE3 },
|
|
17412
17091
|
handler: (args) => {
|
|
17413
17092
|
const tool = args.tool;
|
|
17414
17093
|
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 +17110,7 @@ function createImagePaintTools(controller) {
|
|
|
17431
17110
|
title: "Get the Mixer Brush",
|
|
17432
17111
|
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
17112
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17434
|
-
annotations: { title: "Get the Mixer Brush", ...
|
|
17113
|
+
annotations: { title: "Get the Mixer Brush", ...READ3 },
|
|
17435
17114
|
handler: () => {
|
|
17436
17115
|
const { mixer, mixerLoad } = controller.getState().paint;
|
|
17437
17116
|
return { settings: { ...mixer }, load: mixerLoadResult(mixerLoad) };
|
|
@@ -17446,7 +17125,7 @@ function createImagePaintTools(controller) {
|
|
|
17446
17125
|
properties: { color: { type: "string", description: "Paint colour #rrggbb (default the foreground)." } },
|
|
17447
17126
|
additionalProperties: false
|
|
17448
17127
|
},
|
|
17449
|
-
annotations: { title: "Load the Mixer Brush", ...
|
|
17128
|
+
annotations: { title: "Load the Mixer Brush", ...WRITE3, idempotentHint: true },
|
|
17450
17129
|
handler: (args) => mixerLoadResult(controller.loadMixerBrush(args.color))
|
|
17451
17130
|
};
|
|
17452
17131
|
const cleanMixerTool = {
|
|
@@ -17458,7 +17137,7 @@ function createImagePaintTools(controller) {
|
|
|
17458
17137
|
properties: { emptyReservoir: { type: "boolean", description: "Also drop the reservoir (default false)." } },
|
|
17459
17138
|
additionalProperties: false
|
|
17460
17139
|
},
|
|
17461
|
-
annotations: { title: "Clean the Mixer Brush", ...
|
|
17140
|
+
annotations: { title: "Clean the Mixer Brush", ...WRITE3, idempotentHint: true },
|
|
17462
17141
|
handler: (args) => mixerLoadResult(args.emptyReservoir === true ? controller.emptyMixerBrush() : controller.cleanMixerBrush())
|
|
17463
17142
|
};
|
|
17464
17143
|
const fill = {
|
|
@@ -17476,7 +17155,7 @@ function createImagePaintTools(controller) {
|
|
|
17476
17155
|
},
|
|
17477
17156
|
additionalProperties: false
|
|
17478
17157
|
},
|
|
17479
|
-
annotations: { title: "Fill pixels", ...
|
|
17158
|
+
annotations: { title: "Fill pixels", ...WRITE3 },
|
|
17480
17159
|
handler: (args) => controller.fillPixels({
|
|
17481
17160
|
color: args.color,
|
|
17482
17161
|
opacity: args.opacity,
|
|
@@ -17498,7 +17177,7 @@ function createImagePaintTools(controller) {
|
|
|
17498
17177
|
},
|
|
17499
17178
|
additionalProperties: false
|
|
17500
17179
|
},
|
|
17501
|
-
annotations: { title: "Clear pixels", ...
|
|
17180
|
+
annotations: { title: "Clear pixels", ...DESTRUCTIVE2 },
|
|
17502
17181
|
handler: (args) => controller.clearPixels({ opacity: args.opacity, useSelection: args.useSelection, ...readTarget(args) })
|
|
17503
17182
|
};
|
|
17504
17183
|
const paintView = () => {
|
|
@@ -17521,7 +17200,7 @@ function createImagePaintTools(controller) {
|
|
|
17521
17200
|
title: "Get the paint",
|
|
17522
17201
|
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
17202
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17524
|
-
annotations: { title: "Get the paint", ...
|
|
17203
|
+
annotations: { title: "Get the paint", ...READ3 },
|
|
17525
17204
|
handler: () => paintView()
|
|
17526
17205
|
};
|
|
17527
17206
|
const sampleColor2 = {
|
|
@@ -17564,7 +17243,7 @@ function createImagePaintTools(controller) {
|
|
|
17564
17243
|
required: ["start", "end"],
|
|
17565
17244
|
additionalProperties: false
|
|
17566
17245
|
},
|
|
17567
|
-
annotations: { title: "Sample a gradient along a line", ...
|
|
17246
|
+
annotations: { title: "Sample a gradient along a line", ...READ3 },
|
|
17568
17247
|
handler: (args) => {
|
|
17569
17248
|
const start = args.start;
|
|
17570
17249
|
const end = args.end;
|
|
@@ -17593,7 +17272,7 @@ function createImagePaintTools(controller) {
|
|
|
17593
17272
|
}
|
|
17594
17273
|
|
|
17595
17274
|
// src/image-editor/color-tools.ts
|
|
17596
|
-
var
|
|
17275
|
+
var READ4 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17597
17276
|
var PROFILE = {
|
|
17598
17277
|
type: "string",
|
|
17599
17278
|
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 +17299,7 @@ function createImageColorTools(controller) {
|
|
|
17620
17299
|
title: "Get the colour profile",
|
|
17621
17300
|
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
17301
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17623
|
-
annotations: { title: "Get the colour profile", ...
|
|
17302
|
+
annotations: { title: "Get the colour profile", ...READ4 },
|
|
17624
17303
|
handler: () => {
|
|
17625
17304
|
const proof2 = controller.getState().proofSetup;
|
|
17626
17305
|
return {
|
|
@@ -17704,7 +17383,7 @@ function createImageColorTools(controller) {
|
|
|
17704
17383
|
required: ["colors", "to"],
|
|
17705
17384
|
additionalProperties: false
|
|
17706
17385
|
},
|
|
17707
|
-
annotations: { title: "Convert colours between profiles", ...
|
|
17386
|
+
annotations: { title: "Convert colours between profiles", ...READ4 },
|
|
17708
17387
|
handler: (args) => ({
|
|
17709
17388
|
colors: controller.convertColors(args.colors, profileArg(args.to), {
|
|
17710
17389
|
...args.from !== void 0 ? { from: profileArg(args.from) } : {},
|
|
@@ -17740,8 +17419,8 @@ function createImageColorTools(controller) {
|
|
|
17740
17419
|
}
|
|
17741
17420
|
|
|
17742
17421
|
// src/image-editor/retouch-tools.ts
|
|
17743
|
-
var
|
|
17744
|
-
var
|
|
17422
|
+
var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17423
|
+
var WRITE4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
17745
17424
|
var POINTS = {
|
|
17746
17425
|
type: "array",
|
|
17747
17426
|
minItems: 1,
|
|
@@ -17831,7 +17510,7 @@ function createImageRetouchTools(controller) {
|
|
|
17831
17510
|
required: ["points"],
|
|
17832
17511
|
additionalProperties: false
|
|
17833
17512
|
},
|
|
17834
|
-
annotations: { title: "Clone Stamp stroke", ...
|
|
17513
|
+
annotations: { title: "Clone Stamp stroke", ...WRITE4 },
|
|
17835
17514
|
handler: (args) => stroke("clone", args, pick(args, ["aligned", "sample"]))
|
|
17836
17515
|
};
|
|
17837
17516
|
const healBrush = {
|
|
@@ -17851,7 +17530,7 @@ function createImageRetouchTools(controller) {
|
|
|
17851
17530
|
required: ["points"],
|
|
17852
17531
|
additionalProperties: false
|
|
17853
17532
|
},
|
|
17854
|
-
annotations: { title: "Healing Brush stroke", ...
|
|
17533
|
+
annotations: { title: "Healing Brush stroke", ...WRITE4 },
|
|
17855
17534
|
handler: (args) => stroke("heal", args, pick(args, ["aligned", "sample"]))
|
|
17856
17535
|
};
|
|
17857
17536
|
const spotHeal = {
|
|
@@ -17870,7 +17549,7 @@ function createImageRetouchTools(controller) {
|
|
|
17870
17549
|
required: ["points"],
|
|
17871
17550
|
additionalProperties: false
|
|
17872
17551
|
},
|
|
17873
|
-
annotations: { title: "Spot Healing stroke", ...
|
|
17552
|
+
annotations: { title: "Spot Healing stroke", ...WRITE4 },
|
|
17874
17553
|
handler: (args) => stroke("spot-heal", args, { ...pick(args, ["sample"]), ...args.type !== void 0 ? { spotType: args.type } : {} })
|
|
17875
17554
|
};
|
|
17876
17555
|
const smudge = {
|
|
@@ -17888,7 +17567,7 @@ function createImageRetouchTools(controller) {
|
|
|
17888
17567
|
required: ["points"],
|
|
17889
17568
|
additionalProperties: false
|
|
17890
17569
|
},
|
|
17891
|
-
annotations: { title: "Smudge stroke", ...
|
|
17570
|
+
annotations: { title: "Smudge stroke", ...WRITE4 },
|
|
17892
17571
|
handler: (args) => stroke("smudge", args, pick(args, ["strength"]))
|
|
17893
17572
|
};
|
|
17894
17573
|
const toneSchema = (verb) => ({
|
|
@@ -17909,7 +17588,7 @@ function createImageRetouchTools(controller) {
|
|
|
17909
17588
|
title: "Dodge stroke",
|
|
17910
17589
|
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
17590
|
inputSchema: toneSchema("lighten"),
|
|
17912
|
-
annotations: { title: "Dodge stroke", ...
|
|
17591
|
+
annotations: { title: "Dodge stroke", ...WRITE4 },
|
|
17913
17592
|
handler: (args) => stroke("dodge", args, pick(args, ["range", "exposure", "protectTones"]))
|
|
17914
17593
|
};
|
|
17915
17594
|
const burn = {
|
|
@@ -17917,7 +17596,7 @@ function createImageRetouchTools(controller) {
|
|
|
17917
17596
|
title: "Burn stroke",
|
|
17918
17597
|
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
17598
|
inputSchema: toneSchema("darken"),
|
|
17920
|
-
annotations: { title: "Burn stroke", ...
|
|
17599
|
+
annotations: { title: "Burn stroke", ...WRITE4 },
|
|
17921
17600
|
handler: (args) => stroke("burn", args, pick(args, ["range", "exposure", "protectTones"]))
|
|
17922
17601
|
};
|
|
17923
17602
|
const spongeTool = {
|
|
@@ -17936,7 +17615,7 @@ function createImageRetouchTools(controller) {
|
|
|
17936
17615
|
required: ["points"],
|
|
17937
17616
|
additionalProperties: false
|
|
17938
17617
|
},
|
|
17939
|
-
annotations: { title: "Sponge stroke", ...
|
|
17618
|
+
annotations: { title: "Sponge stroke", ...WRITE4 },
|
|
17940
17619
|
handler: (args) => stroke("sponge", { ...args, channel: "pixels" }, { ...pick(args, ["vibrance"]), ...args.mode !== void 0 ? { spongeMode: args.mode } : {} })
|
|
17941
17620
|
};
|
|
17942
17621
|
const filterSchema = (verb) => ({
|
|
@@ -17955,7 +17634,7 @@ function createImageRetouchTools(controller) {
|
|
|
17955
17634
|
title: "Blur stroke",
|
|
17956
17635
|
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
17636
|
inputSchema: filterSchema("blur"),
|
|
17958
|
-
annotations: { title: "Blur stroke", ...
|
|
17637
|
+
annotations: { title: "Blur stroke", ...WRITE4 },
|
|
17959
17638
|
handler: (args) => stroke("blur", args, pick(args, ["strength"]))
|
|
17960
17639
|
};
|
|
17961
17640
|
const sharpenTool = {
|
|
@@ -17963,7 +17642,7 @@ function createImageRetouchTools(controller) {
|
|
|
17963
17642
|
title: "Sharpen stroke",
|
|
17964
17643
|
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
17644
|
inputSchema: filterSchema("sharpen"),
|
|
17966
|
-
annotations: { title: "Sharpen stroke", ...
|
|
17645
|
+
annotations: { title: "Sharpen stroke", ...WRITE4 },
|
|
17967
17646
|
handler: (args) => stroke("sharpen", args, pick(args, ["strength"]))
|
|
17968
17647
|
};
|
|
17969
17648
|
const historyBrush = {
|
|
@@ -17981,7 +17660,7 @@ function createImageRetouchTools(controller) {
|
|
|
17981
17660
|
required: ["points"],
|
|
17982
17661
|
additionalProperties: false
|
|
17983
17662
|
},
|
|
17984
|
-
annotations: { title: "History Brush stroke", ...
|
|
17663
|
+
annotations: { title: "History Brush stroke", ...WRITE4 },
|
|
17985
17664
|
handler: (args) => stroke("history", args, pick(args, ["historySteps"]))
|
|
17986
17665
|
};
|
|
17987
17666
|
const getOptions = {
|
|
@@ -17989,7 +17668,7 @@ function createImageRetouchTools(controller) {
|
|
|
17989
17668
|
title: "Get retouch options",
|
|
17990
17669
|
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
17670
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17992
|
-
annotations: { title: "Get retouch options", ...
|
|
17671
|
+
annotations: { title: "Get retouch options", ...READ5 },
|
|
17993
17672
|
handler: () => {
|
|
17994
17673
|
const { retouch, cloneSource, cloneTransform } = controller.getState().paint;
|
|
17995
17674
|
return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null, cloneTransform: { ...cloneTransform } };
|
|
@@ -18015,7 +17694,7 @@ function createImageRetouchTools(controller) {
|
|
|
18015
17694
|
},
|
|
18016
17695
|
additionalProperties: false
|
|
18017
17696
|
},
|
|
18018
|
-
annotations: { title: "Set retouch options", ...
|
|
17697
|
+
annotations: { title: "Set retouch options", ...WRITE4, idempotentHint: true },
|
|
18019
17698
|
handler: (args) => ({ ...controller.setPaintOptions({ retouch: args }).retouch })
|
|
18020
17699
|
};
|
|
18021
17700
|
const setSource = {
|
|
@@ -18031,7 +17710,7 @@ function createImageRetouchTools(controller) {
|
|
|
18031
17710
|
},
|
|
18032
17711
|
additionalProperties: false
|
|
18033
17712
|
},
|
|
18034
|
-
annotations: { title: "Set the clone source", ...
|
|
17713
|
+
annotations: { title: "Set the clone source", ...WRITE4, idempotentHint: true },
|
|
18035
17714
|
handler: (args) => {
|
|
18036
17715
|
if (args.clear === true) {
|
|
18037
17716
|
if (args.x !== void 0 || args.y !== void 0) throw new LayerOperationError("Give either clear true or x and y, not both.");
|
|
@@ -18057,7 +17736,7 @@ function createImageRetouchTools(controller) {
|
|
|
18057
17736
|
},
|
|
18058
17737
|
additionalProperties: false
|
|
18059
17738
|
},
|
|
18060
|
-
annotations: { title: "Transform the clone source", ...
|
|
17739
|
+
annotations: { title: "Transform the clone source", ...WRITE4, idempotentHint: false },
|
|
18061
17740
|
handler: (args) => {
|
|
18062
17741
|
if (args.reset === true) {
|
|
18063
17742
|
if (Object.keys(args).some((k) => k !== "reset")) throw new LayerOperationError("Give either reset true or transform values, not both.");
|
|
@@ -18083,8 +17762,8 @@ function pick(args, keys) {
|
|
|
18083
17762
|
}
|
|
18084
17763
|
|
|
18085
17764
|
// src/image-editor/psd-tools.ts
|
|
18086
|
-
var
|
|
18087
|
-
var
|
|
17765
|
+
var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17766
|
+
var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18088
17767
|
var DATA = {
|
|
18089
17768
|
type: "string",
|
|
18090
17769
|
minLength: 1,
|
|
@@ -18104,7 +17783,7 @@ function createImagePsdTools(controller) {
|
|
|
18104
17783
|
title: "Inspect a PSD",
|
|
18105
17784
|
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
17785
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
18107
|
-
annotations: { title: "Inspect a PSD", ...
|
|
17786
|
+
annotations: { title: "Inspect a PSD", ...READ6 },
|
|
18108
17787
|
handler: ({ data }) => {
|
|
18109
17788
|
const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
|
|
18110
17789
|
return {
|
|
@@ -18122,7 +17801,7 @@ function createImagePsdTools(controller) {
|
|
|
18122
17801
|
title: "Open a PSD as the document",
|
|
18123
17802
|
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
17803
|
inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
|
|
18125
|
-
annotations: { title: "Open a PSD as the document", ...
|
|
17804
|
+
annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE3 },
|
|
18126
17805
|
handler: ({ data }) => {
|
|
18127
17806
|
const res = controller.loadPsd(psdBytesFromBase64(data));
|
|
18128
17807
|
const s = controller.getState();
|
|
@@ -18141,7 +17820,7 @@ function createImagePsdTools(controller) {
|
|
|
18141
17820
|
title: "Export the document as a PSD",
|
|
18142
17821
|
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
17822
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
18144
|
-
annotations: { title: "Export the document as a PSD", ...
|
|
17823
|
+
annotations: { title: "Export the document as a PSD", ...READ6 },
|
|
18145
17824
|
handler: async () => {
|
|
18146
17825
|
const res = await controller.toPsd();
|
|
18147
17826
|
return {
|
|
@@ -18159,8 +17838,8 @@ function createImagePsdTools(controller) {
|
|
|
18159
17838
|
}
|
|
18160
17839
|
|
|
18161
17840
|
// src/image-editor/transform-tools.ts
|
|
18162
|
-
var
|
|
18163
|
-
var
|
|
17841
|
+
var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
17842
|
+
var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18164
17843
|
var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
18165
17844
|
var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
|
|
18166
17845
|
var POINT = {
|
|
@@ -18259,7 +17938,7 @@ function createImageTransformTools(controller) {
|
|
|
18259
17938
|
},
|
|
18260
17939
|
additionalProperties: false
|
|
18261
17940
|
},
|
|
18262
|
-
annotations: { title: "Get the Free Transform frame", ...
|
|
17941
|
+
annotations: { title: "Get the Free Transform frame", ...READ7 },
|
|
18263
17942
|
handler: (args) => {
|
|
18264
17943
|
const init = targetFrom(args);
|
|
18265
17944
|
if (init.content === "selection-copy") init.content = "selection";
|
|
@@ -18292,7 +17971,7 @@ function createImageTransformTools(controller) {
|
|
|
18292
17971
|
properties: { ...TARGET3, ...GEOMETRY },
|
|
18293
17972
|
additionalProperties: false
|
|
18294
17973
|
},
|
|
18295
|
-
annotations: { title: "Free Transform a layer", ...
|
|
17974
|
+
annotations: { title: "Free Transform a layer", ...WRITE5 },
|
|
18296
17975
|
handler: (args) => summary2(controller.transformLayer({ ...targetFrom(args), ...geometryFrom(args) }))
|
|
18297
17976
|
};
|
|
18298
17977
|
const warpLayer = {
|
|
@@ -18322,7 +18001,7 @@ function createImageTransformTools(controller) {
|
|
|
18322
18001
|
},
|
|
18323
18002
|
additionalProperties: false
|
|
18324
18003
|
},
|
|
18325
|
-
annotations: { title: "Warp a layer", ...
|
|
18004
|
+
annotations: { title: "Warp a layer", ...WRITE5 },
|
|
18326
18005
|
handler: (args) => {
|
|
18327
18006
|
const hasPreset = ["style", "bend", "horizontal", "vertical", "orientation"].some((k) => args[k] !== void 0);
|
|
18328
18007
|
if (hasPreset && args.mesh !== void 0) throw new LayerOperationError("Give a preset (style, bend, horizontal, vertical, orientation) or a mesh, not both.");
|
|
@@ -18356,7 +18035,7 @@ function createImageTransformTools(controller) {
|
|
|
18356
18035
|
properties: { interpolation: { ...TARGET3.interpolation, description: "Resampling of soft edges: nearest, bilinear or bicubic (default)." }, ...GEOMETRY },
|
|
18357
18036
|
additionalProperties: false
|
|
18358
18037
|
},
|
|
18359
|
-
annotations: { title: "Transform the selection outline", ...
|
|
18038
|
+
annotations: { title: "Transform the selection outline", ...WRITE5 },
|
|
18360
18039
|
handler: (args) => {
|
|
18361
18040
|
const res = controller.transformLayer({ content: "selection-outline", interpolation: args.interpolation, ...geometryFrom(args) });
|
|
18362
18041
|
return { changed: res.changed, frame: { ...res.box }, corners: res.corners.map(roundPoint), bounds: res.bounds };
|
|
@@ -18377,7 +18056,7 @@ function createImageTransformTools(controller) {
|
|
|
18377
18056
|
required: ["axis"],
|
|
18378
18057
|
additionalProperties: false
|
|
18379
18058
|
},
|
|
18380
|
-
annotations: { title: "Flip a layer", ...
|
|
18059
|
+
annotations: { title: "Flip a layer", ...WRITE5 },
|
|
18381
18060
|
handler: (args) => summary2(controller.flipLayer(args.axis, targetFrom(args)))
|
|
18382
18061
|
};
|
|
18383
18062
|
const rotate90 = {
|
|
@@ -18395,20 +18074,20 @@ function createImageTransformTools(controller) {
|
|
|
18395
18074
|
required: ["turn"],
|
|
18396
18075
|
additionalProperties: false
|
|
18397
18076
|
},
|
|
18398
|
-
annotations: { title: "Rotate a layer by quarter turns", ...
|
|
18077
|
+
annotations: { title: "Rotate a layer by quarter turns", ...WRITE5 },
|
|
18399
18078
|
handler: (args) => summary2(controller.rotateLayer90(args.turn, targetFrom(args)))
|
|
18400
18079
|
};
|
|
18401
18080
|
return [getFrame, transformLayer, warpLayer, transformSelection, flipLayer, rotate90];
|
|
18402
18081
|
}
|
|
18403
18082
|
|
|
18404
18083
|
// src/image-editor/smart-tools.ts
|
|
18405
|
-
var
|
|
18406
|
-
var
|
|
18407
|
-
var
|
|
18408
|
-
var
|
|
18084
|
+
var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18085
|
+
var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18086
|
+
var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18087
|
+
var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18409
18088
|
var round5 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
|
|
18410
18089
|
var roundPoint2 = (p) => ({ x: round5(p.x), y: round5(p.y) });
|
|
18411
|
-
var
|
|
18090
|
+
var LAYER_ID3 = { type: "string", description: "Smart object layer id from list_layers (type smart)." };
|
|
18412
18091
|
var FILTER_ID = { type: "string", description: "Smart filter id from get_smart_object or add_smart_filter." };
|
|
18413
18092
|
var POINT2 = {
|
|
18414
18093
|
type: "object",
|
|
@@ -18460,8 +18139,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18460
18139
|
name: "get_smart_object",
|
|
18461
18140
|
title: "Read a smart object",
|
|
18462
18141
|
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", ...
|
|
18142
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18143
|
+
annotations: { title: "Read a smart object", ...READ8 },
|
|
18465
18144
|
handler: ({ layerId }) => info(smartId(layerId))
|
|
18466
18145
|
};
|
|
18467
18146
|
const convert = {
|
|
@@ -18476,7 +18155,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18476
18155
|
},
|
|
18477
18156
|
additionalProperties: false
|
|
18478
18157
|
},
|
|
18479
|
-
annotations: { title: "Convert to Smart Object", ...
|
|
18158
|
+
annotations: { title: "Convert to Smart Object", ...WRITE6 },
|
|
18480
18159
|
handler: ({ layerIds, name }) => {
|
|
18481
18160
|
for (const id2 of layerIds ?? []) requireLayer(controller.getLayers(), id2);
|
|
18482
18161
|
const id = controller.convertToSmartObject(layerIds, { name });
|
|
@@ -18487,8 +18166,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18487
18166
|
name: "rasterize_smart_object",
|
|
18488
18167
|
title: "Rasterize a smart object",
|
|
18489
18168
|
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", ...
|
|
18169
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18170
|
+
annotations: { title: "Rasterize a smart object", ...DESTRUCTIVE4 },
|
|
18492
18171
|
handler: ({ layerId }) => ({ layer: layerSummary(controller.rasterizeSmartObject(smartId(layerId))) })
|
|
18493
18172
|
};
|
|
18494
18173
|
const setTransform = {
|
|
@@ -18498,7 +18177,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18498
18177
|
inputSchema: {
|
|
18499
18178
|
type: "object",
|
|
18500
18179
|
properties: {
|
|
18501
|
-
layerId:
|
|
18180
|
+
layerId: LAYER_ID3,
|
|
18502
18181
|
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
18182
|
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
18183
|
scaleX: { type: "number", description: "Width in percent of the contents\u2019 own width (negative flips)." },
|
|
@@ -18541,7 +18220,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18541
18220
|
required: ["layerId"],
|
|
18542
18221
|
additionalProperties: false
|
|
18543
18222
|
},
|
|
18544
|
-
annotations: { title: "Set a smart object\u2019s transform", ...
|
|
18223
|
+
annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT3 },
|
|
18545
18224
|
handler: (args) => {
|
|
18546
18225
|
const id = smartId(args.layerId);
|
|
18547
18226
|
let warp;
|
|
@@ -18580,22 +18259,22 @@ function createImageSmartObjectTools(controller) {
|
|
|
18580
18259
|
inputSchema: {
|
|
18581
18260
|
type: "object",
|
|
18582
18261
|
properties: {
|
|
18583
|
-
layerId:
|
|
18262
|
+
layerId: LAYER_ID3,
|
|
18584
18263
|
image: { type: "string", description: "The new contents: a PNG as a data URL or base64 (other formats and URLs need a browser)." },
|
|
18585
18264
|
name: { type: "string", description: "File name of the contents (default the old name with .png)." }
|
|
18586
18265
|
},
|
|
18587
18266
|
required: ["layerId", "image"],
|
|
18588
18267
|
additionalProperties: false
|
|
18589
18268
|
},
|
|
18590
|
-
annotations: { title: "Replace a smart object\u2019s contents", ...
|
|
18269
|
+
annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE4 },
|
|
18591
18270
|
handler: async ({ layerId, image, name }) => controller.replaceSmartObjectContentsFromImage(smartId(layerId), imageArg(image), name)
|
|
18592
18271
|
};
|
|
18593
18272
|
const exportContents = {
|
|
18594
18273
|
name: "export_smart_object_contents",
|
|
18595
18274
|
title: "Export a smart object\u2019s contents",
|
|
18596
18275
|
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", ...
|
|
18276
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18277
|
+
annotations: { title: "Export a smart object\u2019s contents", ...READ8 },
|
|
18599
18278
|
handler: ({ layerId }) => {
|
|
18600
18279
|
const f = controller.exportSmartObjectContents(smartId(layerId));
|
|
18601
18280
|
return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
|
|
@@ -18608,14 +18287,14 @@ function createImageSmartObjectTools(controller) {
|
|
|
18608
18287
|
inputSchema: {
|
|
18609
18288
|
type: "object",
|
|
18610
18289
|
properties: {
|
|
18611
|
-
layerId:
|
|
18290
|
+
layerId: LAYER_ID3,
|
|
18612
18291
|
linked: { type: "boolean", description: "true shares the contents with the original; false (default) makes independent contents." },
|
|
18613
18292
|
name: { type: "string", description: 'Name of the copy (default "<name> copy").' }
|
|
18614
18293
|
},
|
|
18615
18294
|
required: ["layerId"],
|
|
18616
18295
|
additionalProperties: false
|
|
18617
18296
|
},
|
|
18618
|
-
annotations: { title: "Copy a smart object", ...
|
|
18297
|
+
annotations: { title: "Copy a smart object", ...WRITE6 },
|
|
18619
18298
|
handler: ({ layerId, linked, name }) => {
|
|
18620
18299
|
const id = controller.copySmartObject(smartId(layerId), linked === true, name);
|
|
18621
18300
|
return { layer: layerSummary(id), contentsId: controller.getSmartObject(id).contents.id };
|
|
@@ -18625,8 +18304,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18625
18304
|
name: "edit_smart_object_contents",
|
|
18626
18305
|
title: "Edit a smart object\u2019s contents",
|
|
18627
18306
|
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", ...
|
|
18307
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
|
|
18308
|
+
annotations: { title: "Edit a smart object\u2019s contents", ...WRITE6 },
|
|
18630
18309
|
handler: ({ layerId }) => {
|
|
18631
18310
|
const res = controller.editSmartObjectContents(smartId(layerId));
|
|
18632
18311
|
const s = controller.getState();
|
|
@@ -18642,7 +18321,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18642
18321
|
properties: { save: { type: "boolean", description: "true (default) saves the edits into the smart object; false discards them." } },
|
|
18643
18322
|
additionalProperties: false
|
|
18644
18323
|
},
|
|
18645
|
-
annotations: { title: "Close a smart object\u2019s contents", ...
|
|
18324
|
+
annotations: { title: "Close a smart object\u2019s contents", ...WRITE6 },
|
|
18646
18325
|
handler: ({ save }) => ({ ...controller.closeSmartObjectContents(save !== false), editing: controller.getEditingContents() })
|
|
18647
18326
|
};
|
|
18648
18327
|
const addFilter = {
|
|
@@ -18652,7 +18331,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18652
18331
|
inputSchema: {
|
|
18653
18332
|
type: "object",
|
|
18654
18333
|
properties: {
|
|
18655
|
-
layerId:
|
|
18334
|
+
layerId: LAYER_ID3,
|
|
18656
18335
|
kind: { type: "string", enum: ["develop", "blur"], description: "Filter kind." },
|
|
18657
18336
|
index: { type: "integer", minimum: 0, description: "Position in the stack, 0 = bottom, applied first (default the top)." },
|
|
18658
18337
|
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 +18340,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18661
18340
|
required: ["layerId", "kind"],
|
|
18662
18341
|
additionalProperties: false
|
|
18663
18342
|
},
|
|
18664
|
-
annotations: { title: "Add a smart filter", ...
|
|
18343
|
+
annotations: { title: "Add a smart filter", ...WRITE6 },
|
|
18665
18344
|
handler: (args) => {
|
|
18666
18345
|
const id = smartId(args.layerId);
|
|
18667
18346
|
const masked = args.useSelection !== false && controller.hasSelection;
|
|
@@ -18675,11 +18354,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18675
18354
|
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
18355
|
inputSchema: {
|
|
18677
18356
|
type: "object",
|
|
18678
|
-
properties: { layerId:
|
|
18357
|
+
properties: { layerId: LAYER_ID3, filterId: FILTER_ID, ...FILTER_SETTINGS },
|
|
18679
18358
|
required: ["layerId", "filterId"],
|
|
18680
18359
|
additionalProperties: false
|
|
18681
18360
|
},
|
|
18682
|
-
annotations: { title: "Change a smart filter", ...
|
|
18361
|
+
annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT3 },
|
|
18683
18362
|
handler: (args) => {
|
|
18684
18363
|
const id = smartId(args.layerId);
|
|
18685
18364
|
const changes = settingsFrom(args);
|
|
@@ -18692,8 +18371,8 @@ function createImageSmartObjectTools(controller) {
|
|
|
18692
18371
|
name: "remove_smart_filter",
|
|
18693
18372
|
title: "Remove a smart filter",
|
|
18694
18373
|
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", ...
|
|
18374
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID3, filterId: FILTER_ID }, required: ["layerId", "filterId"], additionalProperties: false },
|
|
18375
|
+
annotations: { title: "Remove a smart filter", ...DESTRUCTIVE4 },
|
|
18697
18376
|
handler: ({ layerId, filterId }) => {
|
|
18698
18377
|
const id = smartId(layerId);
|
|
18699
18378
|
controller.removeSmartFilter(id, filterId);
|
|
@@ -18706,11 +18385,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18706
18385
|
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
18386
|
inputSchema: {
|
|
18708
18387
|
type: "object",
|
|
18709
|
-
properties: { layerId:
|
|
18388
|
+
properties: { layerId: LAYER_ID3, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
|
|
18710
18389
|
required: ["layerId", "filterId", "index"],
|
|
18711
18390
|
additionalProperties: false
|
|
18712
18391
|
},
|
|
18713
|
-
annotations: { title: "Reorder a smart filter", ...
|
|
18392
|
+
annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT3 },
|
|
18714
18393
|
handler: ({ layerId, filterId, index }) => {
|
|
18715
18394
|
const id = smartId(layerId);
|
|
18716
18395
|
controller.moveSmartFilter(id, filterId, index);
|
|
@@ -18723,11 +18402,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18723
18402
|
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
18403
|
inputSchema: {
|
|
18725
18404
|
type: "object",
|
|
18726
|
-
properties: { layerId:
|
|
18405
|
+
properties: { layerId: LAYER_ID3, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
|
|
18727
18406
|
required: ["layerId", "enabled"],
|
|
18728
18407
|
additionalProperties: false
|
|
18729
18408
|
},
|
|
18730
|
-
annotations: { title: "Turn smart filters on or off", ...
|
|
18409
|
+
annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT3 },
|
|
18731
18410
|
handler: ({ layerId, enabled }) => {
|
|
18732
18411
|
const id = smartId(layerId);
|
|
18733
18412
|
controller.setSmartFiltersEnabled(id, enabled === true);
|
|
@@ -18741,7 +18420,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18741
18420
|
inputSchema: {
|
|
18742
18421
|
type: "object",
|
|
18743
18422
|
properties: {
|
|
18744
|
-
layerId:
|
|
18423
|
+
layerId: LAYER_ID3,
|
|
18745
18424
|
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
18425
|
density: { type: "number", minimum: 0, maximum: 1, description: "How much hidden areas hide, 0..1 (default 1)." },
|
|
18747
18426
|
feather: { type: "number", minimum: 0, maximum: 1e3, description: "Gaussian softening in px (default 0)." },
|
|
@@ -18751,7 +18430,7 @@ function createImageSmartObjectTools(controller) {
|
|
|
18751
18430
|
required: ["layerId", "from"],
|
|
18752
18431
|
additionalProperties: false
|
|
18753
18432
|
},
|
|
18754
|
-
annotations: { title: "Set the smart filter mask", ...
|
|
18433
|
+
annotations: { title: "Set the smart filter mask", ...WRITE6 },
|
|
18755
18434
|
handler: (args) => {
|
|
18756
18435
|
const id = smartId(args.layerId);
|
|
18757
18436
|
const props = {};
|
|
@@ -18764,11 +18443,11 @@ function createImageSmartObjectTools(controller) {
|
|
|
18764
18443
|
}
|
|
18765
18444
|
|
|
18766
18445
|
// src/image-editor/shape-tools.ts
|
|
18767
|
-
var
|
|
18768
|
-
var
|
|
18769
|
-
var
|
|
18770
|
-
var
|
|
18771
|
-
var
|
|
18446
|
+
var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18447
|
+
var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
18448
|
+
var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
18449
|
+
var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
18450
|
+
var LAYER_ID4 = { type: "string", description: "Shape layer id from list_layers (type shape) or add_shape_layer." };
|
|
18772
18451
|
var COMPONENT_INDEX = { type: "integer", minimum: 0, description: "Component index from get_shape_layer (0 = bottom component)." };
|
|
18773
18452
|
var OP = {
|
|
18774
18453
|
type: "string",
|
|
@@ -18790,7 +18469,7 @@ var BOX = {
|
|
|
18790
18469
|
height: NUM("Height in pixels."),
|
|
18791
18470
|
transform: { $ref: "#/$defs/matrix" }
|
|
18792
18471
|
};
|
|
18793
|
-
var
|
|
18472
|
+
var DEFS = {
|
|
18794
18473
|
matrix: MATRIX,
|
|
18795
18474
|
point: {
|
|
18796
18475
|
type: "object",
|
|
@@ -19017,8 +18696,8 @@ function createImageShapeTools(controller) {
|
|
|
19017
18696
|
name: "get_shape_layer",
|
|
19018
18697
|
title: "Read a shape layer",
|
|
19019
18698
|
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", ...
|
|
18699
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
18700
|
+
annotations: { title: "Read a shape layer", ...READ9 },
|
|
19022
18701
|
handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
|
|
19023
18702
|
};
|
|
19024
18703
|
const add2 = {
|
|
@@ -19027,7 +18706,7 @@ function createImageShapeTools(controller) {
|
|
|
19027
18706
|
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
18707
|
inputSchema: {
|
|
19029
18708
|
type: "object",
|
|
19030
|
-
$defs:
|
|
18709
|
+
$defs: DEFS,
|
|
19031
18710
|
properties: {
|
|
19032
18711
|
...GEOMETRY2,
|
|
19033
18712
|
components: {
|
|
@@ -19049,7 +18728,7 @@ function createImageShapeTools(controller) {
|
|
|
19049
18728
|
},
|
|
19050
18729
|
additionalProperties: false
|
|
19051
18730
|
},
|
|
19052
|
-
annotations: { title: "Add a shape layer", ...
|
|
18731
|
+
annotations: { title: "Add a shape layer", ...WRITE7 },
|
|
19053
18732
|
handler: (args) => {
|
|
19054
18733
|
const init = { ...geometry(args) };
|
|
19055
18734
|
if (args.components !== void 0) init.components = args.components.map(geometry);
|
|
@@ -19067,9 +18746,9 @@ function createImageShapeTools(controller) {
|
|
|
19067
18746
|
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
18747
|
inputSchema: {
|
|
19069
18748
|
type: "object",
|
|
19070
|
-
$defs:
|
|
18749
|
+
$defs: DEFS,
|
|
19071
18750
|
properties: {
|
|
19072
|
-
layerId:
|
|
18751
|
+
layerId: LAYER_ID4,
|
|
19073
18752
|
fill: { anyOf: [{ $ref: "#/$defs/paint" }, { type: "null", description: "No fill." }], description: "New fill paint, or null for none." },
|
|
19074
18753
|
stroke: { anyOf: [{ $ref: "#/$defs/stroke" }, { type: "null", description: "No stroke." }], description: "Stroke settings to change, or null to remove the stroke." },
|
|
19075
18754
|
fillRule: { type: "string", enum: ["nonzero", "evenodd"], description: "Winding rule within a component." }
|
|
@@ -19077,7 +18756,7 @@ function createImageShapeTools(controller) {
|
|
|
19077
18756
|
required: ["layerId"],
|
|
19078
18757
|
additionalProperties: false
|
|
19079
18758
|
},
|
|
19080
|
-
annotations: { title: "Restyle a shape", ...
|
|
18759
|
+
annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT4 },
|
|
19081
18760
|
handler: ({ layerId, fill, stroke, fillRule }) => {
|
|
19082
18761
|
const id = shapeId(layerId);
|
|
19083
18762
|
if (fill === void 0 && stroke === void 0 && fillRule === void 0) throw new LayerOperationError("Give fill, stroke or fillRule to change.");
|
|
@@ -19090,9 +18769,9 @@ function createImageShapeTools(controller) {
|
|
|
19090
18769
|
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
18770
|
inputSchema: {
|
|
19092
18771
|
type: "object",
|
|
19093
|
-
$defs:
|
|
18772
|
+
$defs: DEFS,
|
|
19094
18773
|
properties: {
|
|
19095
|
-
layerId:
|
|
18774
|
+
layerId: LAYER_ID4,
|
|
19096
18775
|
componentIndex: COMPONENT_INDEX,
|
|
19097
18776
|
shape: {
|
|
19098
18777
|
type: "object",
|
|
@@ -19125,7 +18804,7 @@ function createImageShapeTools(controller) {
|
|
|
19125
18804
|
required: ["layerId", "componentIndex"],
|
|
19126
18805
|
additionalProperties: false
|
|
19127
18806
|
},
|
|
19128
|
-
annotations: { title: "Edit a shape component", ...
|
|
18807
|
+
annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT4 },
|
|
19129
18808
|
handler: ({ layerId, componentIndex, ...rest }) => {
|
|
19130
18809
|
const id = shapeId(layerId);
|
|
19131
18810
|
const change = geometry(rest);
|
|
@@ -19139,28 +18818,28 @@ function createImageShapeTools(controller) {
|
|
|
19139
18818
|
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
18819
|
inputSchema: {
|
|
19141
18820
|
type: "object",
|
|
19142
|
-
$defs:
|
|
19143
|
-
properties: { layerId:
|
|
18821
|
+
$defs: DEFS,
|
|
18822
|
+
properties: { layerId: LAYER_ID4, ...GEOMETRY2, op: OP, index: { type: "integer", minimum: 0, description: "Position among the components, 0 = bottom (default the top)." } },
|
|
19144
18823
|
required: ["layerId"],
|
|
19145
18824
|
additionalProperties: false
|
|
19146
18825
|
},
|
|
19147
|
-
annotations: { title: "Add a shape component", ...
|
|
18826
|
+
annotations: { title: "Add a shape component", ...WRITE7 },
|
|
19148
18827
|
handler: ({ layerId, index, ...rest }) => controller.addShapeComponent(shapeId(layerId), geometry(rest), index)
|
|
19149
18828
|
};
|
|
19150
18829
|
const removeComponent = {
|
|
19151
18830
|
name: "remove_shape_component",
|
|
19152
18831
|
title: "Delete a shape component",
|
|
19153
18832
|
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", ...
|
|
18833
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4, componentIndex: COMPONENT_INDEX }, required: ["layerId", "componentIndex"], additionalProperties: false },
|
|
18834
|
+
annotations: { title: "Delete a shape component", ...DESTRUCTIVE5 },
|
|
19156
18835
|
handler: ({ layerId, componentIndex }) => controller.removeShapeComponent(shapeId(layerId), componentIndex)
|
|
19157
18836
|
};
|
|
19158
18837
|
const merge = {
|
|
19159
18838
|
name: "merge_shape_components",
|
|
19160
18839
|
title: "Merge shape components",
|
|
19161
18840
|
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", ...
|
|
18841
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
|
|
18842
|
+
annotations: { title: "Merge shape components", ...DESTRUCTIVE5 },
|
|
19164
18843
|
handler: ({ layerId }) => controller.mergeShapeComponents(shapeId(layerId))
|
|
19165
18844
|
};
|
|
19166
18845
|
const layerArg = (v) => {
|
|
@@ -19214,7 +18893,7 @@ function createImageShapeTools(controller) {
|
|
|
19214
18893
|
title: "Make a path from the selection",
|
|
19215
18894
|
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
18895
|
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", ...
|
|
18896
|
+
annotations: { title: "Make a path from the selection", ...READ9 },
|
|
19218
18897
|
handler: (args) => {
|
|
19219
18898
|
const out = controller.selectionToPath(traceOptions(args));
|
|
19220
18899
|
const { subpaths, ...rest } = out;
|
|
@@ -19227,7 +18906,7 @@ function createImageShapeTools(controller) {
|
|
|
19227
18906
|
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
18907
|
inputSchema: {
|
|
19229
18908
|
type: "object",
|
|
19230
|
-
$defs:
|
|
18909
|
+
$defs: DEFS,
|
|
19231
18910
|
properties: {
|
|
19232
18911
|
pathId: { ...PATH_ID, description: "A document path from list_paths, instead of shape / subpaths / components." },
|
|
19233
18912
|
...PATH_PROPS,
|
|
@@ -19237,7 +18916,7 @@ function createImageShapeTools(controller) {
|
|
|
19237
18916
|
},
|
|
19238
18917
|
additionalProperties: false
|
|
19239
18918
|
},
|
|
19240
|
-
annotations: { title: "Make a selection from a path", ...
|
|
18919
|
+
annotations: { title: "Make a selection from a path", ...WRITE7 },
|
|
19241
18920
|
handler: (args) => {
|
|
19242
18921
|
const mode = args.mode;
|
|
19243
18922
|
controller.pathToSelection(fromPathId(args) ?? pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
|
|
@@ -19250,7 +18929,7 @@ function createImageShapeTools(controller) {
|
|
|
19250
18929
|
title: "Read a vector mask",
|
|
19251
18930
|
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
18931
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19253
|
-
annotations: { title: "Read a vector mask", ...
|
|
18932
|
+
annotations: { title: "Read a vector mask", ...READ9 },
|
|
19254
18933
|
handler: ({ layerId }) => ({ vectorMask: controller.getVectorMask(layerArg(layerId)) })
|
|
19255
18934
|
};
|
|
19256
18935
|
const addVectorMask = {
|
|
@@ -19259,7 +18938,7 @@ function createImageShapeTools(controller) {
|
|
|
19259
18938
|
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
18939
|
inputSchema: {
|
|
19261
18940
|
type: "object",
|
|
19262
|
-
$defs:
|
|
18941
|
+
$defs: DEFS,
|
|
19263
18942
|
properties: {
|
|
19264
18943
|
layerId: LAYER,
|
|
19265
18944
|
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 +18949,7 @@ function createImageShapeTools(controller) {
|
|
|
19270
18949
|
required: ["layerId"],
|
|
19271
18950
|
additionalProperties: false
|
|
19272
18951
|
},
|
|
19273
|
-
annotations: { title: "Add a vector mask", ...
|
|
18952
|
+
annotations: { title: "Add a vector mask", ...WRITE7 },
|
|
19274
18953
|
handler: (args) => {
|
|
19275
18954
|
const id = layerArg(args.layerId);
|
|
19276
18955
|
const spec = fromPathId(args) ?? pathSpec(args);
|
|
@@ -19285,8 +18964,8 @@ function createImageShapeTools(controller) {
|
|
|
19285
18964
|
name: "set_vector_mask_path",
|
|
19286
18965
|
title: "Replace a vector mask path",
|
|
19287
18966
|
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", ...
|
|
18967
|
+
inputSchema: { type: "object", $defs: DEFS, properties: { layerId: LAYER, ...PATH_PROPS }, required: ["layerId"], additionalProperties: false },
|
|
18968
|
+
annotations: { title: "Replace a vector mask path", ...WRITE_IDEMPOTENT4 },
|
|
19290
18969
|
handler: (args) => {
|
|
19291
18970
|
const id = layerArg(args.layerId);
|
|
19292
18971
|
controller.setVectorMaskPath(id, pathSpec(args));
|
|
@@ -19310,7 +18989,7 @@ function createImageShapeTools(controller) {
|
|
|
19310
18989
|
required: ["layerId"],
|
|
19311
18990
|
additionalProperties: false
|
|
19312
18991
|
},
|
|
19313
|
-
annotations: { title: "Set vector mask properties", ...
|
|
18992
|
+
annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT4 },
|
|
19314
18993
|
handler: ({ layerId, ...props }) => {
|
|
19315
18994
|
const id = layerArg(layerId);
|
|
19316
18995
|
controller.setVectorMaskProps(id, props);
|
|
@@ -19336,7 +19015,7 @@ function createImageShapeTools(controller) {
|
|
|
19336
19015
|
required: ["layerId", "component", "subpath", "segment", "mode"],
|
|
19337
19016
|
additionalProperties: false
|
|
19338
19017
|
},
|
|
19339
|
-
annotations: { title: "Set a vector mask segment's edge", ...
|
|
19018
|
+
annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT4 },
|
|
19340
19019
|
handler: ({ layerId, component, subpath, segment, mode, radius, inner, outer }) => {
|
|
19341
19020
|
const id = layerArg(layerId);
|
|
19342
19021
|
const vectorMask = controller.setVectorMaskEdge(
|
|
@@ -19353,7 +19032,7 @@ function createImageShapeTools(controller) {
|
|
|
19353
19032
|
title: "Rasterize a vector mask",
|
|
19354
19033
|
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
19034
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19356
|
-
annotations: { title: "Rasterize a vector mask", ...
|
|
19035
|
+
annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE5 },
|
|
19357
19036
|
handler: ({ layerId }) => {
|
|
19358
19037
|
const id = layerArg(layerId);
|
|
19359
19038
|
const mask = controller.rasterizeVectorMask(id);
|
|
@@ -19365,7 +19044,7 @@ function createImageShapeTools(controller) {
|
|
|
19365
19044
|
title: "Delete a vector mask",
|
|
19366
19045
|
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
19046
|
inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
|
|
19368
|
-
annotations: { title: "Delete a vector mask", ...
|
|
19047
|
+
annotations: { title: "Delete a vector mask", ...DESTRUCTIVE5 },
|
|
19369
19048
|
handler: ({ layerId }) => {
|
|
19370
19049
|
const id = layerArg(layerId);
|
|
19371
19050
|
controller.removeVectorMask(id);
|
|
@@ -19377,15 +19056,15 @@ function createImageShapeTools(controller) {
|
|
|
19377
19056
|
title: "List document paths",
|
|
19378
19057
|
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
19058
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
19380
|
-
annotations: { title: "List document paths", ...
|
|
19059
|
+
annotations: { title: "List document paths", ...READ9 },
|
|
19381
19060
|
handler: () => ({ paths: controller.getPaths().map((p) => pathSummary(p.id)), activePathId: controller.getState().activePathId ?? null })
|
|
19382
19061
|
};
|
|
19383
|
-
const
|
|
19062
|
+
const getPath = {
|
|
19384
19063
|
name: "get_path",
|
|
19385
19064
|
title: "Read a document path",
|
|
19386
19065
|
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
19066
|
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
19388
|
-
annotations: { title: "Read a document path", ...
|
|
19067
|
+
annotations: { title: "Read a document path", ...READ9 },
|
|
19389
19068
|
handler: ({ pathId }) => {
|
|
19390
19069
|
const p = controller.getPath(String(pathId));
|
|
19391
19070
|
if (!p) throw new Error(`No path "${String(pathId)}". Call list_paths for ids.`);
|
|
@@ -19397,7 +19076,7 @@ function createImageShapeTools(controller) {
|
|
|
19397
19076
|
title: "Make a work path from the selection",
|
|
19398
19077
|
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
19078
|
inputSchema: { type: "object", properties: { ...TRACE_PROPS }, additionalProperties: false },
|
|
19400
|
-
annotations: { title: "Make a work path from the selection", ...
|
|
19079
|
+
annotations: { title: "Make a work path from the selection", ...WRITE7 },
|
|
19401
19080
|
handler: (args) => ({ path: pathSummary(controller.makeWorkPath(traceOptions(args)).id) })
|
|
19402
19081
|
};
|
|
19403
19082
|
const addPath = {
|
|
@@ -19406,11 +19085,11 @@ function createImageShapeTools(controller) {
|
|
|
19406
19085
|
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
19086
|
inputSchema: {
|
|
19408
19087
|
type: "object",
|
|
19409
|
-
$defs:
|
|
19088
|
+
$defs: DEFS,
|
|
19410
19089
|
properties: { name: { type: "string", description: 'The path name (default "Path n").' }, ...PATH_PROPS },
|
|
19411
19090
|
additionalProperties: false
|
|
19412
19091
|
},
|
|
19413
|
-
annotations: { title: "Add a document path", ...
|
|
19092
|
+
annotations: { title: "Add a document path", ...WRITE7 },
|
|
19414
19093
|
handler: (args) => {
|
|
19415
19094
|
const spec = pathSpec(args);
|
|
19416
19095
|
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 +19100,8 @@ function createImageShapeTools(controller) {
|
|
|
19421
19100
|
name: "set_path_geometry",
|
|
19422
19101
|
title: "Replace a document path",
|
|
19423
19102
|
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", ...
|
|
19103
|
+
inputSchema: { type: "object", $defs: DEFS, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
19104
|
+
annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT4 },
|
|
19426
19105
|
handler: (args) => ({ path: pathSummary(controller.setPathGeometry(String(args.pathId), pathSpec(args)).id) })
|
|
19427
19106
|
};
|
|
19428
19107
|
const renamePath = {
|
|
@@ -19430,7 +19109,7 @@ function createImageShapeTools(controller) {
|
|
|
19430
19109
|
title: "Rename or save a path",
|
|
19431
19110
|
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
19111
|
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", ...
|
|
19112
|
+
annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT4 },
|
|
19434
19113
|
handler: ({ pathId, name }) => ({ path: pathSummary(controller.renamePath(String(pathId), String(name)).id) })
|
|
19435
19114
|
};
|
|
19436
19115
|
const duplicatePath = {
|
|
@@ -19438,7 +19117,7 @@ function createImageShapeTools(controller) {
|
|
|
19438
19117
|
title: "Duplicate a path",
|
|
19439
19118
|
description: 'Duplicates a document path as a saved path (default name "<name> copy"). One undo step. Returns the new path.',
|
|
19440
19119
|
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", ...
|
|
19120
|
+
annotations: { title: "Duplicate a path", ...WRITE7 },
|
|
19442
19121
|
handler: ({ pathId, name }) => ({ path: pathSummary(controller.duplicatePath(String(pathId), name).id) })
|
|
19443
19122
|
};
|
|
19444
19123
|
const deletePath = {
|
|
@@ -19446,7 +19125,7 @@ function createImageShapeTools(controller) {
|
|
|
19446
19125
|
title: "Delete a path",
|
|
19447
19126
|
description: "Deletes a document path (undo_image brings it back). Returns the remaining paths.",
|
|
19448
19127
|
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
19449
|
-
annotations: { title: "Delete a path", ...
|
|
19128
|
+
annotations: { title: "Delete a path", ...DESTRUCTIVE5 },
|
|
19450
19129
|
handler: ({ pathId }) => {
|
|
19451
19130
|
controller.deletePath(String(pathId));
|
|
19452
19131
|
return { paths: controller.getPaths().map((p) => pathSummary(p.id)) };
|
|
@@ -19462,7 +19141,7 @@ function createImageShapeTools(controller) {
|
|
|
19462
19141
|
title: "Fill a path",
|
|
19463
19142
|
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
19143
|
inputSchema: { type: "object", properties: { pathId: PATH_ID, ...PAINT_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
19465
|
-
annotations: { title: "Fill a path", ...
|
|
19144
|
+
annotations: { title: "Fill a path", ...WRITE7 },
|
|
19466
19145
|
handler: (args) => controller.fillPath(String(args.pathId), { layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
19467
19146
|
};
|
|
19468
19147
|
const strokePath = {
|
|
@@ -19475,7 +19154,7 @@ function createImageShapeTools(controller) {
|
|
|
19475
19154
|
required: ["pathId", "width"],
|
|
19476
19155
|
additionalProperties: false
|
|
19477
19156
|
},
|
|
19478
|
-
annotations: { title: "Stroke a path", ...
|
|
19157
|
+
annotations: { title: "Stroke a path", ...WRITE7 },
|
|
19479
19158
|
handler: (args) => controller.strokePath(String(args.pathId), { width: args.width, layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
19480
19159
|
};
|
|
19481
19160
|
return [
|
|
@@ -19496,7 +19175,7 @@ function createImageShapeTools(controller) {
|
|
|
19496
19175
|
selectionToPath,
|
|
19497
19176
|
pathToSelection2,
|
|
19498
19177
|
listPaths,
|
|
19499
|
-
|
|
19178
|
+
getPath,
|
|
19500
19179
|
makeWorkPath,
|
|
19501
19180
|
addPath,
|
|
19502
19181
|
setPathGeometry,
|
|
@@ -19509,11 +19188,11 @@ function createImageShapeTools(controller) {
|
|
|
19509
19188
|
}
|
|
19510
19189
|
|
|
19511
19190
|
// src/image-editor/type-tools.ts
|
|
19512
|
-
var
|
|
19513
|
-
var
|
|
19514
|
-
var
|
|
19515
|
-
var
|
|
19516
|
-
var
|
|
19191
|
+
var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
19192
|
+
var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
19193
|
+
var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
19194
|
+
var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
19195
|
+
var LAYER_ID5 = { type: "string", description: "Type layer id from list_layers (type type) or add_text_layer." };
|
|
19517
19196
|
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
19197
|
var END = { type: "integer", minimum: 0, description: "End of the range, exclusive (default the end of the text)." };
|
|
19519
19198
|
var STYLE = {
|
|
@@ -19566,15 +19245,15 @@ function createImageTypeTools(controller) {
|
|
|
19566
19245
|
title: "List fonts",
|
|
19567
19246
|
description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
|
|
19568
19247
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
19569
|
-
annotations: { title: "List fonts", ...
|
|
19248
|
+
annotations: { title: "List fonts", ...READ10 },
|
|
19570
19249
|
handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
|
|
19571
19250
|
};
|
|
19572
19251
|
const get = {
|
|
19573
19252
|
name: "get_text_layer",
|
|
19574
19253
|
title: "Read a type layer",
|
|
19575
19254
|
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", ...
|
|
19255
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
19256
|
+
annotations: { title: "Read a type layer", ...READ10 },
|
|
19578
19257
|
handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
|
|
19579
19258
|
};
|
|
19580
19259
|
const add2 = {
|
|
@@ -19609,7 +19288,7 @@ function createImageTypeTools(controller) {
|
|
|
19609
19288
|
required: ["text", "x", "y"],
|
|
19610
19289
|
additionalProperties: false
|
|
19611
19290
|
},
|
|
19612
|
-
annotations: { title: "Add a type layer", ...
|
|
19291
|
+
annotations: { title: "Add a type layer", ...WRITE8 },
|
|
19613
19292
|
handler: (args) => {
|
|
19614
19293
|
const init = pick2(args, ["text", "x", "y", "box", "style", "paragraph", "orientation", "rotation", "name", "opacity", "blend", "aboveId", "belowId", "parentId", "index"]);
|
|
19615
19294
|
if (init.blend !== void 0) init.blend = init.blend;
|
|
@@ -19621,16 +19300,16 @@ function createImageTypeTools(controller) {
|
|
|
19621
19300
|
name: "set_text",
|
|
19622
19301
|
title: "Edit text",
|
|
19623
19302
|
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", ...
|
|
19303
|
+
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 },
|
|
19304
|
+
annotations: { title: "Edit text", ...WRITE8 },
|
|
19626
19305
|
handler: (args) => controller.setText(typeId(args.layerId), args.text, range(args))
|
|
19627
19306
|
};
|
|
19628
19307
|
const setStyle = {
|
|
19629
19308
|
name: "set_text_style",
|
|
19630
19309
|
title: "Style a range of text",
|
|
19631
19310
|
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", ...
|
|
19311
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...STYLE }, required: ["layerId"], additionalProperties: false },
|
|
19312
|
+
annotations: { title: "Style a range of text", ...WRITE_IDEMPOTENT5 },
|
|
19634
19313
|
handler: (args) => {
|
|
19635
19314
|
const style = pick2(args, Object.keys(STYLE));
|
|
19636
19315
|
if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one style field: ${Object.keys(STYLE).join(", ")}.`);
|
|
@@ -19641,8 +19320,8 @@ function createImageTypeTools(controller) {
|
|
|
19641
19320
|
name: "set_paragraph_style",
|
|
19642
19321
|
title: "Style paragraphs",
|
|
19643
19322
|
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", ...
|
|
19323
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...PARAGRAPH }, required: ["layerId"], additionalProperties: false },
|
|
19324
|
+
annotations: { title: "Style paragraphs", ...WRITE_IDEMPOTENT5 },
|
|
19646
19325
|
handler: (args) => {
|
|
19647
19326
|
const style = pick2(args, Object.keys(PARAGRAPH));
|
|
19648
19327
|
if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one paragraph field: ${Object.keys(PARAGRAPH).join(", ")}.`);
|
|
@@ -19656,7 +19335,7 @@ function createImageTypeTools(controller) {
|
|
|
19656
19335
|
inputSchema: {
|
|
19657
19336
|
type: "object",
|
|
19658
19337
|
properties: {
|
|
19659
|
-
layerId:
|
|
19338
|
+
layerId: LAYER_ID5,
|
|
19660
19339
|
kind: { type: "string", enum: ["point", "box"], description: "point or box." },
|
|
19661
19340
|
width: { type: "number", minimum: 1, description: "Box width in pixels (kind box)." },
|
|
19662
19341
|
height: { type: "number", minimum: 1, description: "Box height in pixels (kind box)." }
|
|
@@ -19664,7 +19343,7 @@ function createImageTypeTools(controller) {
|
|
|
19664
19343
|
required: ["layerId", "kind"],
|
|
19665
19344
|
additionalProperties: false
|
|
19666
19345
|
},
|
|
19667
|
-
annotations: { title: "Point or paragraph text", ...
|
|
19346
|
+
annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT5 },
|
|
19668
19347
|
handler: ({ layerId, kind, width, height }) => {
|
|
19669
19348
|
const id = typeId(layerId);
|
|
19670
19349
|
if (kind === "box" && (width === void 0 || height === void 0)) throw new LayerOperationError("kind box needs width and height in pixels.");
|
|
@@ -19675,16 +19354,16 @@ function createImageTypeTools(controller) {
|
|
|
19675
19354
|
name: "set_text_orientation",
|
|
19676
19355
|
title: "Horizontal or vertical type",
|
|
19677
19356
|
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", ...
|
|
19357
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5, orientation: { ...ORIENTATION, description: "horizontal or vertical." } }, required: ["layerId", "orientation"], additionalProperties: false },
|
|
19358
|
+
annotations: { title: "Horizontal or vertical type", ...WRITE_IDEMPOTENT5 },
|
|
19680
19359
|
handler: ({ layerId, orientation }) => controller.setTextOrientation(typeId(layerId), orientation)
|
|
19681
19360
|
};
|
|
19682
19361
|
const toShape = {
|
|
19683
19362
|
name: "convert_text_to_shape",
|
|
19684
19363
|
title: "Convert text to a shape",
|
|
19685
19364
|
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", ...
|
|
19365
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
|
|
19366
|
+
annotations: { title: "Convert text to a shape", ...DESTRUCTIVE6 },
|
|
19688
19367
|
handler: ({ layerId }) => {
|
|
19689
19368
|
const { layerId: id, warnings } = controller.convertTextToShape(typeId(layerId));
|
|
19690
19369
|
return { layer: layerSummary(id), shape: controller.getShapeLayer(id), warnings };
|
|
@@ -19718,7 +19397,7 @@ function createImageTypeTools(controller) {
|
|
|
19718
19397
|
required: ["text", "x", "y"],
|
|
19719
19398
|
additionalProperties: false
|
|
19720
19399
|
},
|
|
19721
|
-
annotations: { title: "Select the shape of text", ...
|
|
19400
|
+
annotations: { title: "Select the shape of text", ...WRITE8 },
|
|
19722
19401
|
handler: (args) => {
|
|
19723
19402
|
const init = pick2(args, ["text", "x", "y", "orientation", "box", "style", "paragraph", "rotation", "mode", "feather", "antiAlias"]);
|
|
19724
19403
|
controller.selectTextShape(init);
|
|
@@ -20231,12 +19910,12 @@ var SelectAndMaskSession = class {
|
|
|
20231
19910
|
this.recompute();
|
|
20232
19911
|
}
|
|
20233
19912
|
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(
|
|
19913
|
+
const px = this.pixels;
|
|
19914
|
+
if (!px) return;
|
|
19915
|
+
const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(px.width, px.height));
|
|
19916
|
+
const w = Math.max(1, Math.round(px.width * s));
|
|
19917
|
+
const h = Math.max(1, Math.round(px.height * s));
|
|
19918
|
+
this.previewPixels = scalePixels(px, w, h);
|
|
20240
19919
|
this.belowPreview = this.below ? scalePixels(this.below, w, h) : null;
|
|
20241
19920
|
this.baseMask = this.base?.bounds ? s === 1 ? this.base : resizeSelection(this.base, w, h) : null;
|
|
20242
19921
|
}
|
|
@@ -20245,8 +19924,8 @@ var SelectAndMaskSession = class {
|
|
|
20245
19924
|
* the page, or in the worker, where one job runs at a time and the newest state follows it.
|
|
20246
19925
|
*/
|
|
20247
19926
|
recompute() {
|
|
20248
|
-
const
|
|
20249
|
-
if (!
|
|
19927
|
+
const px = this.previewPixels;
|
|
19928
|
+
if (!px) return;
|
|
20250
19929
|
this.note = this.settingsValue.refineMode === "object" ? "Object aware refinement asks the segmentation model on OK; the preview refines by colour." : null;
|
|
20251
19930
|
if (this.controller.hasSelectionWorker) {
|
|
20252
19931
|
void this.recomputeInWorker();
|
|
@@ -20255,8 +19934,8 @@ var SelectAndMaskSession = class {
|
|
|
20255
19934
|
const { scale } = this.previewSize;
|
|
20256
19935
|
const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
|
|
20257
19936
|
try {
|
|
20258
|
-
const { selection, refineBrush } = applyRefineEdits(
|
|
20259
|
-
this.previewMask = selection?.bounds ? refineSelection(
|
|
19937
|
+
const { selection, refineBrush } = applyRefineEdits(px, this.baseMask, edits, px.width, px.height);
|
|
19938
|
+
this.previewMask = selection?.bounds ? refineSelection(px, selection, scaleParams(this.settingsValue.params, scale), refineBrush) : null;
|
|
20260
19939
|
this.error = null;
|
|
20261
19940
|
} catch (err) {
|
|
20262
19941
|
this.previewMask = null;
|
|
@@ -20272,13 +19951,13 @@ var SelectAndMaskSession = class {
|
|
|
20272
19951
|
this.computing = true;
|
|
20273
19952
|
do {
|
|
20274
19953
|
this.dirty = false;
|
|
20275
|
-
const
|
|
19954
|
+
const px = this.previewPixels;
|
|
20276
19955
|
const { scale } = this.previewSize;
|
|
20277
19956
|
const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
|
|
20278
19957
|
try {
|
|
20279
19958
|
const { mask } = await this.controller.runSelectionJob(
|
|
20280
19959
|
{ op: "refine-preview", base: this.baseMask ? serializeMask(this.baseMask) : null, edits, params: scaleParams(this.settingsValue.params, scale) },
|
|
20281
|
-
|
|
19960
|
+
px
|
|
20282
19961
|
);
|
|
20283
19962
|
this.previewMask = mask.bounds ? mask : null;
|
|
20284
19963
|
this.error = null;
|
|
@@ -20306,9 +19985,9 @@ var SelectAndMaskSession = class {
|
|
|
20306
19985
|
}
|
|
20307
19986
|
/** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
|
|
20308
19987
|
render() {
|
|
20309
|
-
const
|
|
20310
|
-
if (!
|
|
20311
|
-
const { width: w, height: h } =
|
|
19988
|
+
const px = this.previewPixels;
|
|
19989
|
+
if (!px) return new Uint8ClampedArray(0);
|
|
19990
|
+
const { width: w, height: h } = px;
|
|
20312
19991
|
const n = w * h;
|
|
20313
19992
|
const s = this.settingsValue;
|
|
20314
19993
|
const mask = (s.showOriginal ? this.baseMask : this.previewMask) ?? createSelectionMask(w, h);
|
|
@@ -20330,9 +20009,9 @@ var SelectAndMaskSession = class {
|
|
|
20330
20009
|
for (let i = 0; i < n; i++) {
|
|
20331
20010
|
const a = m[i] / 255;
|
|
20332
20011
|
const p = i * 4;
|
|
20333
|
-
const r =
|
|
20334
|
-
const g =
|
|
20335
|
-
const b =
|
|
20012
|
+
const r = px.data[p];
|
|
20013
|
+
const g = px.data[p + 1];
|
|
20014
|
+
const b = px.data[p + 2];
|
|
20336
20015
|
let o;
|
|
20337
20016
|
const x = i % w;
|
|
20338
20017
|
const y = (i - x) / w;
|
|
@@ -20559,8 +20238,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
|
|
|
20559
20238
|
const count = bw * bh;
|
|
20560
20239
|
for (let py = by; py < by + bh; py++) {
|
|
20561
20240
|
const rowOffset = py * width;
|
|
20562
|
-
for (let
|
|
20563
|
-
const idx = (rowOffset +
|
|
20241
|
+
for (let px = bx; px < bx + bw; px++) {
|
|
20242
|
+
const idx = (rowOffset + px) * 4;
|
|
20564
20243
|
rSum += data[idx];
|
|
20565
20244
|
gSum += data[idx + 1];
|
|
20566
20245
|
bSum += data[idx + 2];
|
|
@@ -20573,8 +20252,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
|
|
|
20573
20252
|
const aAvg = Math.round(aSum / count);
|
|
20574
20253
|
for (let py = by; py < by + bh; py++) {
|
|
20575
20254
|
const rowOffset = py * width;
|
|
20576
|
-
for (let
|
|
20577
|
-
const idx = (rowOffset +
|
|
20255
|
+
for (let px = bx; px < bx + bw; px++) {
|
|
20256
|
+
const idx = (rowOffset + px) * 4;
|
|
20578
20257
|
data[idx] = rAvg;
|
|
20579
20258
|
data[idx + 1] = gAvg;
|
|
20580
20259
|
data[idx + 2] = bAvg;
|
|
@@ -21074,179 +20753,6 @@ function layerPanels(layer, options = {}) {
|
|
|
21074
20753
|
return panels;
|
|
21075
20754
|
}
|
|
21076
20755
|
|
|
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
20756
|
// src/image-editor/layers/color-ui.ts
|
|
21251
20757
|
var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
|
|
21252
20758
|
var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
|
|
@@ -22846,10 +22352,10 @@ var ContentAwareFillSession = class _ContentAwareFillSession {
|
|
|
22846
22352
|
const len2 = dx * dx + dy * dy;
|
|
22847
22353
|
for (let y = y0; y <= y1; y++) {
|
|
22848
22354
|
for (let x = x0; x <= x1; x++) {
|
|
22849
|
-
const
|
|
22355
|
+
const px = win.x + x + 0.5 - from.x;
|
|
22850
22356
|
const py = win.y + y + 0.5 - from.y;
|
|
22851
|
-
const t = len2 > 0 ? Math.min(1, Math.max(0, (
|
|
22852
|
-
if ((
|
|
22357
|
+
const t = len2 > 0 ? Math.min(1, Math.max(0, (px * dx + py * dy) / len2)) : 0;
|
|
22358
|
+
if ((px - t * dx) ** 2 + (py - t * dy) ** 2 > r * r) continue;
|
|
22853
22359
|
const i = y * win.width + x;
|
|
22854
22360
|
area[i] = add2 && !hole[i] ? 1 : 0;
|
|
22855
22361
|
}
|
|
@@ -23414,6 +22920,7 @@ export {
|
|
|
23414
22920
|
createImageSubjectSelectionTool,
|
|
23415
22921
|
createImageTransformTools,
|
|
23416
22922
|
createImageTypeTools,
|
|
22923
|
+
createLayerEffectTools,
|
|
23417
22924
|
createMetricTextShaper,
|
|
23418
22925
|
createOutlineTextShaper,
|
|
23419
22926
|
createPigment,
|