@pixerate/editor 0.228.2 → 0.229.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/{chunk-2XGW6DKL.cjs → chunk-5VQXSS2S.cjs} +8 -2
- package/dist/{chunk-SWKXPAJC.js → chunk-JVNGCS26.js} +7 -1
- package/dist/image-editor/controller.d.cts +12 -0
- package/dist/image-editor/controller.d.ts +12 -0
- package/dist/image-editor/geometry.d.cts +6 -0
- package/dist/image-editor/geometry.d.ts +6 -0
- package/dist/image-editor/index.cjs +824 -725
- package/dist/image-editor/index.js +116 -17
- package/dist/image-editor/tool-groups.d.cts +57 -9
- package/dist/image-editor/tool-groups.d.ts +57 -9
- package/dist/image-editor/types.d.cts +3 -1
- package/dist/image-editor/types.d.ts +3 -1
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +1 -0
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
LUMA_709,
|
|
73
73
|
LayerCompositor,
|
|
74
74
|
LayerOperationError,
|
|
75
|
+
MARGIN_FIT_MIN_GUTTER,
|
|
75
76
|
MAX_EFFECT_ANIMATION_MS,
|
|
76
77
|
MAX_KELVIN,
|
|
77
78
|
MIN_KELVIN,
|
|
@@ -405,7 +406,7 @@ import {
|
|
|
405
406
|
writePsd,
|
|
406
407
|
xyToTempTint,
|
|
407
408
|
xyToUv
|
|
408
|
-
} from "../chunk-
|
|
409
|
+
} from "../chunk-JVNGCS26.js";
|
|
409
410
|
import {
|
|
410
411
|
parseCssColor
|
|
411
412
|
} from "../chunk-3CI7FRMK.js";
|
|
@@ -7156,6 +7157,35 @@ var ImageEditorController = class {
|
|
|
7156
7157
|
const data = this.compositor.composite(layers, r, this.compositorSources());
|
|
7157
7158
|
return { width: r.width, height: r.height, data };
|
|
7158
7159
|
}
|
|
7160
|
+
/**
|
|
7161
|
+
* The Eyedropper: the colour (#rrggbb) of the composite at a document point, or the average of
|
|
7162
|
+
* the `size` × `size` square round it (1, 3 or 5…), or null outside the canvas or where every
|
|
7163
|
+
* layer is transparent. With `setForeground` it also becomes the paint foreground.
|
|
7164
|
+
*/
|
|
7165
|
+
sampleColor(point2, options = {}) {
|
|
7166
|
+
const { width, height } = this.naturalSize;
|
|
7167
|
+
const size = Math.max(1, Math.floor(options.size ?? 1));
|
|
7168
|
+
const cx = Math.floor(point2.x);
|
|
7169
|
+
const cy = Math.floor(point2.y);
|
|
7170
|
+
if (cx < 0 || cy < 0 || cx >= width || cy >= height) return null;
|
|
7171
|
+
const half = Math.floor(size / 2);
|
|
7172
|
+
const x = Math.max(0, cx - half);
|
|
7173
|
+
const y = Math.max(0, cy - half);
|
|
7174
|
+
const rect3 = { x, y, width: Math.min(width, cx + half + 1) - x, height: Math.min(height, cy + half + 1) - y };
|
|
7175
|
+
const { data } = this.compositePixels(rect3);
|
|
7176
|
+
let r = 0, g = 0, b = 0, a = 0;
|
|
7177
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
7178
|
+
const w = data[i + 3];
|
|
7179
|
+
r += data[i] * w;
|
|
7180
|
+
g += data[i + 1] * w;
|
|
7181
|
+
b += data[i + 2] * w;
|
|
7182
|
+
a += w;
|
|
7183
|
+
}
|
|
7184
|
+
if (a === 0) return null;
|
|
7185
|
+
const hex = toHex([r / a, g / a, b / a]);
|
|
7186
|
+
if (options.setForeground) this.setPaintOptions({ foreground: hex });
|
|
7187
|
+
return hex;
|
|
7188
|
+
}
|
|
7159
7189
|
compositorSources() {
|
|
7160
7190
|
const { width, height } = this.naturalSize;
|
|
7161
7191
|
return {
|
|
@@ -13523,7 +13553,7 @@ var DEPTH_MASK_CONTROLS = [
|
|
|
13523
13553
|
|
|
13524
13554
|
// src/image-editor/playback.ts
|
|
13525
13555
|
var IMAGE_PLAYBACK_KIND = "layer";
|
|
13526
|
-
var PAINT = /^(paint_stroke|clone_stamp|heal_brush|spot_heal|dodge|burn|sponge|smudge|blur_stroke|sharpen_stroke|history_brush|set_clone_source|set_clone_transform|fill_pixels|clear_pixels|set_paint|set_retouch_options|load_mixer_brush|clean_mixer_brush)$/;
|
|
13556
|
+
var PAINT = /^(paint_stroke|clone_stamp|heal_brush|spot_heal|dodge|burn|sponge|smudge|blur_stroke|sharpen_stroke|history_brush|set_clone_source|set_clone_transform|fill_pixels|clear_pixels|set_paint|sample_color|set_retouch_options|load_mixer_brush|clean_mixer_brush)$/;
|
|
13527
13557
|
var SELECT = /^(make_work_path|add_path|set_path_geometry|rename_path|duplicate_path|delete_path|fill_path|stroke_path|select_region|select_subject|select_by_color|select_all|deselect|invert_selection|select_rect|select_ellipse|select_polygon|quick_select|select_object|select_focus_area|select_sky|select_line|magic_wand|grow_selection|select_similar|reselect|select_layer_transparency|select_color_range|load_selection_from_image|load_selection_from_mask|set_selection_display|modify_selection|refine_selection|transform_selection|apply_selection_as_mask|layer_via_copy|stroke_selection|content_aware_fill|copy_pixels|cut_pixels|paste_pixels|save_selection|load_selection_from_channel|set_channel_properties|duplicate_channel|delete_channel|load_channel_from_image|set_quick_mask|path_to_selection|select_text_shape|compare_selections|edit_selection_step|insert_selection_step|remove_selection_step|freeze_selection|separate_subject)$/;
|
|
13528
13558
|
var ANNOTATE = /^(add_shape_layer|update_shape|add_shape_component|set_shape_component|remove_shape_component|merge_shape_components|add_text_layer|set_text|set_text_style|set_paragraph_style|set_text_frame|set_text_orientation|convert_text_to_shape)$/;
|
|
13529
13559
|
var CROP = /^(set_crop|crop_to_selection|reset_crop|set_rotation|flip_image|transform_layer|warp_layer|flip_layer|offset_layer)$/;
|
|
@@ -17441,7 +17471,29 @@ function createImagePaintTools(controller) {
|
|
|
17441
17471
|
annotations: { title: "Get the paint", ...READ4 },
|
|
17442
17472
|
handler: () => paintView()
|
|
17443
17473
|
};
|
|
17444
|
-
|
|
17474
|
+
const sampleColor2 = {
|
|
17475
|
+
name: "sample_color",
|
|
17476
|
+
title: "Sample a colour (Eyedropper)",
|
|
17477
|
+
description: "The Eyedropper: reads the composite colour at a point in document pixels, averaged over a size \xD7 size square (default 1), and by default makes it the paint foreground. Fails outside the canvas or where every layer is transparent. View state, not an undo step. Returns the colour (#rrggbb) and the foreground.",
|
|
17478
|
+
inputSchema: {
|
|
17479
|
+
type: "object",
|
|
17480
|
+
properties: {
|
|
17481
|
+
x: { type: "number", description: "Document x in pixels." },
|
|
17482
|
+
y: { type: "number", description: "Document y in pixels." },
|
|
17483
|
+
size: { type: "integer", minimum: 1, maximum: 101, description: "Sample square in pixels (odd values centre on the point). Default 1." },
|
|
17484
|
+
setForeground: { type: "boolean", description: "Make the colour the paint foreground (default true)." }
|
|
17485
|
+
},
|
|
17486
|
+
required: ["x", "y"],
|
|
17487
|
+
additionalProperties: false
|
|
17488
|
+
},
|
|
17489
|
+
annotations: { title: "Sample a colour (Eyedropper)", ...SET },
|
|
17490
|
+
handler: (args) => {
|
|
17491
|
+
const color = controller.sampleColor({ x: args.x, y: args.y }, { size: args.size, setForeground: args.setForeground !== false });
|
|
17492
|
+
if (!color) throw new LayerOperationError(`Nothing to sample at (${args.x}, ${args.y}): the point is outside the canvas or transparent. Read the canvas size with get_image_info, then sample inside it.`);
|
|
17493
|
+
return { color, foreground: controller.getState().paint.foreground };
|
|
17494
|
+
}
|
|
17495
|
+
};
|
|
17496
|
+
return [paintStroke, fill, clear, getMixer, loadMixerTool, cleanMixerTool, setPaint, getPaint, sampleColor2];
|
|
17445
17497
|
}
|
|
17446
17498
|
|
|
17447
17499
|
// src/image-editor/color-tools.ts
|
|
@@ -20902,6 +20954,7 @@ function layerPanels(layer, options = {}) {
|
|
|
20902
20954
|
};
|
|
20903
20955
|
if (layer.type === "pixel") {
|
|
20904
20956
|
effects();
|
|
20957
|
+
panels.push({ id: "color", title: "Color Adjustments" });
|
|
20905
20958
|
panels.push({ id: "paint", title: "Brush Options" });
|
|
20906
20959
|
} else if (layer.type === "adjustment") {
|
|
20907
20960
|
panels.push({ id: "adjustment", title: adjustmentKindLabel(layer.kind) });
|
|
@@ -20911,7 +20964,10 @@ function layerPanels(layer, options = {}) {
|
|
|
20911
20964
|
} else if (layer.type === "shape") {
|
|
20912
20965
|
panels.push({ id: "shape", title: "Shape Options" });
|
|
20913
20966
|
effects();
|
|
20914
|
-
} else if (layer.type === "smart"
|
|
20967
|
+
} else if (layer.type === "smart") {
|
|
20968
|
+
effects();
|
|
20969
|
+
panels.push({ id: "color", title: "Color Adjustments" });
|
|
20970
|
+
} else if (layer.type === "group") {
|
|
20915
20971
|
effects();
|
|
20916
20972
|
}
|
|
20917
20973
|
if (layer.mask || layer.vectorMask) {
|
|
@@ -21935,18 +21991,28 @@ var IMAGE_TOOL_GROUPS = [
|
|
|
21935
21991
|
{ id: "move", label: "Move", tools: ["move"] },
|
|
21936
21992
|
{ id: "select", label: "Select", tools: ["select"] },
|
|
21937
21993
|
{ id: "crop", label: "Crop", tools: ["crop"] },
|
|
21938
|
-
{ id: "
|
|
21939
|
-
{ id: "
|
|
21940
|
-
{
|
|
21941
|
-
|
|
21942
|
-
|
|
21943
|
-
|
|
21994
|
+
{ id: "draw", label: "Draw", tools: ["brush", "pen", "mixer"] },
|
|
21995
|
+
{ id: "erase", label: "Erase", tools: ["eraser", "history"] },
|
|
21996
|
+
{
|
|
21997
|
+
id: "retouch",
|
|
21998
|
+
label: "Retouch",
|
|
21999
|
+
tools: ["spot-heal", "heal", "clone", "dodge", "burn", "sponge", "blur", "sharpen", "smudge"],
|
|
22000
|
+
sections: [
|
|
22001
|
+
{ label: "Fix", tools: ["spot-heal", "heal", "clone"] },
|
|
22002
|
+
{ label: "Tone", tools: ["dodge", "burn", "sponge"] },
|
|
22003
|
+
{ label: "Detail", tools: ["blur", "sharpen", "smudge"] }
|
|
22004
|
+
]
|
|
22005
|
+
},
|
|
21944
22006
|
{ id: "shape", label: "Shape", tools: ["shape"] },
|
|
21945
|
-
{ id: "
|
|
22007
|
+
{ id: "paths", label: "Paths", tools: ["path-pen", "path-select", "direct-select"] },
|
|
21946
22008
|
{ id: "type", label: "Type", tools: ["type"] },
|
|
21947
|
-
{ id: "
|
|
21948
|
-
{ id: "annotate", label: "Annotate", tools: ["pen", "line", "arrow", "rect", "circle"] }
|
|
22009
|
+
{ id: "eyedropper", label: "Eyedropper", tools: ["eyedropper"] }
|
|
21949
22010
|
];
|
|
22011
|
+
function imageToolVariants(tool) {
|
|
22012
|
+
if (tool === "select") return SELECTION_TOOLS.map((t) => ({ tool: "select", id: t.id, label: t.label }));
|
|
22013
|
+
if (tool === "shape") return LIVE_SHAPE_KINDS.map((kind) => ({ tool: "shape", id: kind, label: SHAPE_KIND_LABELS[kind] }));
|
|
22014
|
+
return [];
|
|
22015
|
+
}
|
|
21950
22016
|
function imageToolGroup(tool) {
|
|
21951
22017
|
return IMAGE_TOOL_GROUPS.find((group) => group.tools.includes(tool)) ?? IMAGE_TOOL_GROUPS[0];
|
|
21952
22018
|
}
|
|
@@ -21958,13 +22024,14 @@ var OTHER_TOOL_LABELS = {
|
|
|
21958
22024
|
"path-pen": "Pen",
|
|
21959
22025
|
"path-select": "Path Selection",
|
|
21960
22026
|
"direct-select": "Direct Selection",
|
|
21961
|
-
pen: "
|
|
22027
|
+
pen: "Pencil",
|
|
21962
22028
|
line: "Line",
|
|
21963
22029
|
arrow: "Arrow",
|
|
21964
22030
|
rect: "Rectangle",
|
|
21965
22031
|
circle: "Ellipse",
|
|
21966
22032
|
text: "Text",
|
|
21967
|
-
watermark: "Watermark"
|
|
22033
|
+
watermark: "Watermark",
|
|
22034
|
+
eyedropper: "Eyedropper"
|
|
21968
22035
|
};
|
|
21969
22036
|
function imageToolLabel(tool) {
|
|
21970
22037
|
return PAINT_TOOLS.find((t) => t.id === tool)?.label ?? OTHER_TOOL_LABELS[tool] ?? tool;
|
|
@@ -21977,7 +22044,8 @@ var IMAGE_TOOL_SHORTCUTS = {
|
|
|
21977
22044
|
type: "T",
|
|
21978
22045
|
"path-pen": "P",
|
|
21979
22046
|
"path-select": "A",
|
|
21980
|
-
"direct-select": "Shift+A"
|
|
22047
|
+
"direct-select": "Shift+A",
|
|
22048
|
+
eyedropper: "I"
|
|
21981
22049
|
};
|
|
21982
22050
|
function imageToolForShortcut(key2, shift = false) {
|
|
21983
22051
|
const shortcut = `${shift ? "Shift+" : ""}${key2.toUpperCase()}`;
|
|
@@ -21991,6 +22059,7 @@ function imageToolCanvasMode(tool) {
|
|
|
21991
22059
|
if (isPaintTool(tool)) return "paint";
|
|
21992
22060
|
if (tool === "select") return "select";
|
|
21993
22061
|
if (tool === "crop") return "crop";
|
|
22062
|
+
if (tool === "eyedropper") return "sample";
|
|
21994
22063
|
return "annotate";
|
|
21995
22064
|
}
|
|
21996
22065
|
function imageToolPanel(tool) {
|
|
@@ -22002,12 +22071,37 @@ function imageToolPanel(tool) {
|
|
|
22002
22071
|
if (tool === "shape" || tool === "type") return tool;
|
|
22003
22072
|
return null;
|
|
22004
22073
|
}
|
|
22074
|
+
function imageToolPanelIds(tool) {
|
|
22075
|
+
const own = imageToolPanel(tool);
|
|
22076
|
+
if (!own) return [];
|
|
22077
|
+
return own === "selection" ? [own, "channels"] : [own];
|
|
22078
|
+
}
|
|
22005
22079
|
function imagePanelTool(panel) {
|
|
22006
22080
|
for (const group of IMAGE_TOOL_GROUPS) {
|
|
22007
|
-
for (const tool of group.tools) if (
|
|
22081
|
+
for (const tool of group.tools) if (imageToolPanelIds(tool).includes(panel)) return tool;
|
|
22008
22082
|
}
|
|
22009
22083
|
return null;
|
|
22010
22084
|
}
|
|
22085
|
+
var TOOL_ONLY_PANELS = /* @__PURE__ */ new Set(["paint", "selection", "canvas-size", "channels", "paths"]);
|
|
22086
|
+
var TOOL_PANEL_TITLES = {
|
|
22087
|
+
paint: "Brush Options",
|
|
22088
|
+
selection: "Selection",
|
|
22089
|
+
"canvas-size": "Composition Size",
|
|
22090
|
+
channels: "Channels",
|
|
22091
|
+
paths: "Paths",
|
|
22092
|
+
shape: "Shape Options",
|
|
22093
|
+
type: "Typography"
|
|
22094
|
+
};
|
|
22095
|
+
function imageToolPanels(tool, layer, options = {}) {
|
|
22096
|
+
const own = imageToolPanelIds(tool);
|
|
22097
|
+
const listed = layerPanels(layer, options);
|
|
22098
|
+
const first = own.map((id) => listed.find((p) => p.id === id) ?? { id, title: TOOL_PANEL_TITLES[id] ?? id });
|
|
22099
|
+
const rest = listed.filter((p) => !own.includes(p.id) && !TOOL_ONLY_PANELS.has(p.id));
|
|
22100
|
+
return [...first, ...rest];
|
|
22101
|
+
}
|
|
22102
|
+
function imageToolUsesColor(tool) {
|
|
22103
|
+
return tool === "brush" || tool === "mixer" || tool === "pen" || tool === "line" || tool === "arrow" || tool === "rect" || tool === "circle" || tool === "shape" || tool === "type" || tool === "eyedropper";
|
|
22104
|
+
}
|
|
22011
22105
|
|
|
22012
22106
|
// src/image-editor/editorDocument.ts
|
|
22013
22107
|
function createImageEditorDocument(controller, options = {}) {
|
|
@@ -22905,6 +22999,7 @@ export {
|
|
|
22905
22999
|
LayerEffectError,
|
|
22906
23000
|
LayerOperationError,
|
|
22907
23001
|
MARCHING_ANTS_STEP_MS,
|
|
23002
|
+
MARGIN_FIT_MIN_GUTTER,
|
|
22908
23003
|
MASK_EDGE_THRESHOLDS,
|
|
22909
23004
|
MASK_FILE_ACCEPT,
|
|
22910
23005
|
MAX_BATCH,
|
|
@@ -23406,6 +23501,10 @@ export {
|
|
|
23406
23501
|
imageToolGroup,
|
|
23407
23502
|
imageToolLabel,
|
|
23408
23503
|
imageToolPanel,
|
|
23504
|
+
imageToolPanelIds,
|
|
23505
|
+
imageToolPanels,
|
|
23506
|
+
imageToolUsesColor,
|
|
23507
|
+
imageToolVariants,
|
|
23409
23508
|
importPsd,
|
|
23410
23509
|
inflate,
|
|
23411
23510
|
inflateRaw,
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The image editor's tools as a toolbar shows them: grouped
|
|
3
|
-
* rest of the group in a flyout), with labels and shortcuts,
|
|
4
|
-
* the layer panel (`layerPanels`) holding its options. Hosts
|
|
5
|
-
* of listing tools themselves, so new tools show up without
|
|
2
|
+
* The image editor's tools as a toolbar shows them: grouped by what each tool is for (a slot per
|
|
3
|
+
* group, the rest of the group in a flyout or the host's tool options), with labels and shortcuts,
|
|
4
|
+
* the canvas mode each tool draws in and the layer panel (`layerPanels`) holding its options. Hosts
|
|
5
|
+
* build their toolbar from these instead of listing tools themselves, so new tools show up without
|
|
6
|
+
* host changes.
|
|
6
7
|
*/
|
|
7
8
|
import type { ImageEditorTool } from './types.cjs';
|
|
9
|
+
import { type SelectionToolKind } from './selection/tool-options.cjs';
|
|
10
|
+
import { type ImageLayer, type LiveShapeKind } from './layers/model.cjs';
|
|
11
|
+
import { type LayerPanelDescriptor, type LayerPanelsOptions } from './layers/panel.cjs';
|
|
12
|
+
/** Tools of a group shown together under a heading (Retouch's Fix, Tone and Detail). */
|
|
13
|
+
export interface ImageToolSection {
|
|
14
|
+
label: string;
|
|
15
|
+
tools: readonly ImageEditorTool[];
|
|
16
|
+
}
|
|
8
17
|
export interface ImageToolGroup {
|
|
9
18
|
id: string;
|
|
10
19
|
label: string;
|
|
11
20
|
tools: readonly ImageEditorTool[];
|
|
21
|
+
/** The group's tools split by purpose, in `tools` order; absent when the group is one set. */
|
|
22
|
+
sections?: readonly ImageToolSection[];
|
|
12
23
|
}
|
|
13
24
|
/**
|
|
14
|
-
* Every tool a toolbar offers, in toolbar order
|
|
15
|
-
*
|
|
25
|
+
* Every tool a toolbar offers, in toolbar order, grouped by intent: choose (Move, Select, Crop),
|
|
26
|
+
* put paint down (Draw), take it away (Erase), retouch (Fix, Tone, Detail), build shapes, paths and
|
|
27
|
+
* type, and pick colours (Eyedropper). The `text` and `watermark` annotations are left out: they
|
|
28
|
+
* are added through the API (`addAnnotation`), not drawn. So are the `line`, `arrow`, `rect` and
|
|
29
|
+
* `circle` annotations, which the Shape tool's live shapes cover (they still draw for API callers).
|
|
16
30
|
*/
|
|
17
31
|
export declare const IMAGE_TOOL_GROUPS: readonly ImageToolGroup[];
|
|
32
|
+
/**
|
|
33
|
+
* One way of using a tool that a toolbar offers as a tool of its own: a selection tool (`select`
|
|
34
|
+
* with `SelectionToolOptions.tool`) or a shape kind (`shape` with `ShapeToolOptions.kind`).
|
|
35
|
+
*/
|
|
36
|
+
export type ImageToolVariant = {
|
|
37
|
+
tool: 'select';
|
|
38
|
+
id: SelectionToolKind;
|
|
39
|
+
label: string;
|
|
40
|
+
} | {
|
|
41
|
+
tool: 'shape';
|
|
42
|
+
id: LiveShapeKind;
|
|
43
|
+
label: string;
|
|
44
|
+
};
|
|
45
|
+
/** The variants a tool offers (the selection tools, the shape kinds), or none. */
|
|
46
|
+
export declare function imageToolVariants(tool: ImageEditorTool): readonly ImageToolVariant[];
|
|
18
47
|
/** The group a tool is in (the first group for a tool no group holds). */
|
|
19
48
|
export declare function imageToolGroup(tool: ImageEditorTool): ImageToolGroup;
|
|
20
49
|
export declare function imageToolLabel(tool: ImageEditorTool): string;
|
|
@@ -23,13 +52,32 @@ export declare const IMAGE_TOOL_SHORTCUTS: Partial<Record<ImageEditorTool, strin
|
|
|
23
52
|
/** The tool a shortcut picks (the first tool listed for a shared key), or null. */
|
|
24
53
|
export declare function imageToolForShortcut(key: string, shift?: boolean): ImageEditorTool | null;
|
|
25
54
|
/** How a canvas handles pointer gestures for a tool (the Svelte and React canvases' `mode`). */
|
|
26
|
-
export type ImageToolCanvasMode = 'transform' | 'crop' | 'select' | 'paint' | 'annotate';
|
|
55
|
+
export type ImageToolCanvasMode = 'transform' | 'crop' | 'select' | 'paint' | 'annotate' | 'sample';
|
|
27
56
|
/**
|
|
28
57
|
* The canvas mode a tool works in. Move picks and transforms layers; shapes, type, the path tools
|
|
29
|
-
* and the annotations draw in `annotate`.
|
|
58
|
+
* and the annotations draw in `annotate`; the Eyedropper picks colours in `sample`.
|
|
30
59
|
*/
|
|
31
60
|
export declare function imageToolCanvasMode(tool: ImageEditorTool): ImageToolCanvasMode;
|
|
32
61
|
/** The `layerPanels` panel holding a tool's options, or null when it has none. */
|
|
33
62
|
export declare function imageToolPanel(tool: ImageEditorTool): string | null;
|
|
34
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* The panels that work with a tool: the one holding its options (`imageToolPanel`) and, for the
|
|
65
|
+
* selection tools, Channels (where a selection is saved and loaded).
|
|
66
|
+
*/
|
|
67
|
+
export declare function imageToolPanelIds(tool: ImageEditorTool): string[];
|
|
68
|
+
/** The first tool whose panels include `panel` (in toolbar order), or null. */
|
|
35
69
|
export declare function imagePanelTool(panel: string): ImageEditorTool | null;
|
|
70
|
+
/**
|
|
71
|
+
* The panels a sidebar shows for the active tool and layer: the tool's own panels first
|
|
72
|
+
* (`imageToolPanelIds`: Brush Options only with a paint tool, Selection and Channels with Select,
|
|
73
|
+
* Composition Size with Crop, Paths with the path tools, Shape Options or Typography with Shape or
|
|
74
|
+
* Type), then the active layer's (`layerPanels`: its properties, effects, colour adjustments, mask,
|
|
75
|
+
* and its shape or type options when it is a shape or type layer). Move shows the layer's panels only.
|
|
76
|
+
*/
|
|
77
|
+
export declare function imageToolPanels(tool: ImageEditorTool, layer: ImageLayer | null, options?: LayerPanelsOptions): LayerPanelDescriptor[];
|
|
78
|
+
/**
|
|
79
|
+
* Tools that put down a colour the host chooses: the brush and mixer (the paint foreground), the
|
|
80
|
+
* pencil and annotations, shapes and type (their fill or colour), and the Eyedropper that picks it.
|
|
81
|
+
* Hosts show their colour picker or palette for these.
|
|
82
|
+
*/
|
|
83
|
+
export declare function imageToolUsesColor(tool: ImageEditorTool): boolean;
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The image editor's tools as a toolbar shows them: grouped
|
|
3
|
-
* rest of the group in a flyout), with labels and shortcuts,
|
|
4
|
-
* the layer panel (`layerPanels`) holding its options. Hosts
|
|
5
|
-
* of listing tools themselves, so new tools show up without
|
|
2
|
+
* The image editor's tools as a toolbar shows them: grouped by what each tool is for (a slot per
|
|
3
|
+
* group, the rest of the group in a flyout or the host's tool options), with labels and shortcuts,
|
|
4
|
+
* the canvas mode each tool draws in and the layer panel (`layerPanels`) holding its options. Hosts
|
|
5
|
+
* build their toolbar from these instead of listing tools themselves, so new tools show up without
|
|
6
|
+
* host changes.
|
|
6
7
|
*/
|
|
7
8
|
import type { ImageEditorTool } from './types.js';
|
|
9
|
+
import { type SelectionToolKind } from './selection/tool-options.js';
|
|
10
|
+
import { type ImageLayer, type LiveShapeKind } from './layers/model.js';
|
|
11
|
+
import { type LayerPanelDescriptor, type LayerPanelsOptions } from './layers/panel.js';
|
|
12
|
+
/** Tools of a group shown together under a heading (Retouch's Fix, Tone and Detail). */
|
|
13
|
+
export interface ImageToolSection {
|
|
14
|
+
label: string;
|
|
15
|
+
tools: readonly ImageEditorTool[];
|
|
16
|
+
}
|
|
8
17
|
export interface ImageToolGroup {
|
|
9
18
|
id: string;
|
|
10
19
|
label: string;
|
|
11
20
|
tools: readonly ImageEditorTool[];
|
|
21
|
+
/** The group's tools split by purpose, in `tools` order; absent when the group is one set. */
|
|
22
|
+
sections?: readonly ImageToolSection[];
|
|
12
23
|
}
|
|
13
24
|
/**
|
|
14
|
-
* Every tool a toolbar offers, in toolbar order
|
|
15
|
-
*
|
|
25
|
+
* Every tool a toolbar offers, in toolbar order, grouped by intent: choose (Move, Select, Crop),
|
|
26
|
+
* put paint down (Draw), take it away (Erase), retouch (Fix, Tone, Detail), build shapes, paths and
|
|
27
|
+
* type, and pick colours (Eyedropper). The `text` and `watermark` annotations are left out: they
|
|
28
|
+
* are added through the API (`addAnnotation`), not drawn. So are the `line`, `arrow`, `rect` and
|
|
29
|
+
* `circle` annotations, which the Shape tool's live shapes cover (they still draw for API callers).
|
|
16
30
|
*/
|
|
17
31
|
export declare const IMAGE_TOOL_GROUPS: readonly ImageToolGroup[];
|
|
32
|
+
/**
|
|
33
|
+
* One way of using a tool that a toolbar offers as a tool of its own: a selection tool (`select`
|
|
34
|
+
* with `SelectionToolOptions.tool`) or a shape kind (`shape` with `ShapeToolOptions.kind`).
|
|
35
|
+
*/
|
|
36
|
+
export type ImageToolVariant = {
|
|
37
|
+
tool: 'select';
|
|
38
|
+
id: SelectionToolKind;
|
|
39
|
+
label: string;
|
|
40
|
+
} | {
|
|
41
|
+
tool: 'shape';
|
|
42
|
+
id: LiveShapeKind;
|
|
43
|
+
label: string;
|
|
44
|
+
};
|
|
45
|
+
/** The variants a tool offers (the selection tools, the shape kinds), or none. */
|
|
46
|
+
export declare function imageToolVariants(tool: ImageEditorTool): readonly ImageToolVariant[];
|
|
18
47
|
/** The group a tool is in (the first group for a tool no group holds). */
|
|
19
48
|
export declare function imageToolGroup(tool: ImageEditorTool): ImageToolGroup;
|
|
20
49
|
export declare function imageToolLabel(tool: ImageEditorTool): string;
|
|
@@ -23,13 +52,32 @@ export declare const IMAGE_TOOL_SHORTCUTS: Partial<Record<ImageEditorTool, strin
|
|
|
23
52
|
/** The tool a shortcut picks (the first tool listed for a shared key), or null. */
|
|
24
53
|
export declare function imageToolForShortcut(key: string, shift?: boolean): ImageEditorTool | null;
|
|
25
54
|
/** How a canvas handles pointer gestures for a tool (the Svelte and React canvases' `mode`). */
|
|
26
|
-
export type ImageToolCanvasMode = 'transform' | 'crop' | 'select' | 'paint' | 'annotate';
|
|
55
|
+
export type ImageToolCanvasMode = 'transform' | 'crop' | 'select' | 'paint' | 'annotate' | 'sample';
|
|
27
56
|
/**
|
|
28
57
|
* The canvas mode a tool works in. Move picks and transforms layers; shapes, type, the path tools
|
|
29
|
-
* and the annotations draw in `annotate`.
|
|
58
|
+
* and the annotations draw in `annotate`; the Eyedropper picks colours in `sample`.
|
|
30
59
|
*/
|
|
31
60
|
export declare function imageToolCanvasMode(tool: ImageEditorTool): ImageToolCanvasMode;
|
|
32
61
|
/** The `layerPanels` panel holding a tool's options, or null when it has none. */
|
|
33
62
|
export declare function imageToolPanel(tool: ImageEditorTool): string | null;
|
|
34
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* The panels that work with a tool: the one holding its options (`imageToolPanel`) and, for the
|
|
65
|
+
* selection tools, Channels (where a selection is saved and loaded).
|
|
66
|
+
*/
|
|
67
|
+
export declare function imageToolPanelIds(tool: ImageEditorTool): string[];
|
|
68
|
+
/** The first tool whose panels include `panel` (in toolbar order), or null. */
|
|
35
69
|
export declare function imagePanelTool(panel: string): ImageEditorTool | null;
|
|
70
|
+
/**
|
|
71
|
+
* The panels a sidebar shows for the active tool and layer: the tool's own panels first
|
|
72
|
+
* (`imageToolPanelIds`: Brush Options only with a paint tool, Selection and Channels with Select,
|
|
73
|
+
* Composition Size with Crop, Paths with the path tools, Shape Options or Typography with Shape or
|
|
74
|
+
* Type), then the active layer's (`layerPanels`: its properties, effects, colour adjustments, mask,
|
|
75
|
+
* and its shape or type options when it is a shape or type layer). Move shows the layer's panels only.
|
|
76
|
+
*/
|
|
77
|
+
export declare function imageToolPanels(tool: ImageEditorTool, layer: ImageLayer | null, options?: LayerPanelsOptions): LayerPanelDescriptor[];
|
|
78
|
+
/**
|
|
79
|
+
* Tools that put down a colour the host chooses: the brush and mixer (the paint foreground), the
|
|
80
|
+
* pencil and annotations, shapes and type (their fill or colour), and the Eyedropper that picks it.
|
|
81
|
+
* Hosts show their colour picker or palette for these.
|
|
82
|
+
*/
|
|
83
|
+
export declare function imageToolUsesColor(tool: ImageEditorTool): boolean;
|
|
@@ -282,7 +282,9 @@ export type ImageEditorTool = 'select' | 'crop' | 'pen' | 'rect' | 'circle' | 'a
|
|
|
282
282
|
/** Live type layers, edited on the canvas (see `TypeToolGesture`). */
|
|
283
283
|
| 'type'
|
|
284
284
|
/** The path tools (see `PathEditGesture`): Path Selection, Direct Selection and the Pen for paths. */
|
|
285
|
-
| 'path-select' | 'direct-select' | 'path-pen'
|
|
285
|
+
| 'path-select' | 'direct-select' | 'path-pen'
|
|
286
|
+
/** The Eyedropper: clicking the canvas picks the composite's colour as the paint foreground. */
|
|
287
|
+
| 'eyedropper';
|
|
286
288
|
export type ImageEditorFit = 'contain' | 'margin';
|
|
287
289
|
import type { DocumentColorMode, DocumentColorProfile, ProofSetup } from './color-management.cjs';
|
|
288
290
|
import type { SelectionRecipeStep } from './selection/recipe.cjs';
|
|
@@ -282,7 +282,9 @@ export type ImageEditorTool = 'select' | 'crop' | 'pen' | 'rect' | 'circle' | 'a
|
|
|
282
282
|
/** Live type layers, edited on the canvas (see `TypeToolGesture`). */
|
|
283
283
|
| 'type'
|
|
284
284
|
/** The path tools (see `PathEditGesture`): Path Selection, Direct Selection and the Pen for paths. */
|
|
285
|
-
| 'path-select' | 'direct-select' | 'path-pen'
|
|
285
|
+
| 'path-select' | 'direct-select' | 'path-pen'
|
|
286
|
+
/** The Eyedropper: clicking the canvas picks the composite's colour as the paint foreground. */
|
|
287
|
+
| 'eyedropper';
|
|
286
288
|
export type ImageEditorFit = 'contain' | 'margin';
|
|
287
289
|
import type { DocumentColorMode, DocumentColorProfile, ProofSetup } from './color-management.js';
|
|
288
290
|
import type { SelectionRecipeStep } from './selection/recipe.js';
|
|
@@ -7,7 +7,7 @@ var _chunkIGPEBXUDcjs = require('../chunk-IGPEBXUD.cjs');
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunk5VQXSS2Scjs = require('../chunk-5VQXSS2S.cjs');
|
|
11
11
|
require('../chunk-A2IS7EHE.cjs');
|
|
12
12
|
require('../chunk-SS53NNZO.cjs');
|
|
13
13
|
|
|
@@ -1673,11 +1673,11 @@ function header(state, options) {
|
|
|
1673
1673
|
return out;
|
|
1674
1674
|
}
|
|
1675
1675
|
function serializePaintDocument(state, options = {}) {
|
|
1676
|
-
const { layers, assets } =
|
|
1676
|
+
const { layers, assets } = _chunk5VQXSS2Scjs.serializeLayers.call(void 0, state.layers);
|
|
1677
1677
|
return { ...header(state, options), layers, assets };
|
|
1678
1678
|
}
|
|
1679
1679
|
async function serializePaintDocumentExternal(state, store, options = {}) {
|
|
1680
|
-
const { layers, assets } = await
|
|
1680
|
+
const { layers, assets } = await _chunk5VQXSS2Scjs.serializeLayersExternal.call(void 0, state.layers, store);
|
|
1681
1681
|
return { ...header(state, options), layers, assets };
|
|
1682
1682
|
}
|
|
1683
1683
|
function paintLayersOnly(layers, problems) {
|
|
@@ -1714,7 +1714,7 @@ function deserializePaintDocument(raw) {
|
|
|
1714
1714
|
const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
|
|
1715
1715
|
const paper = _chunkGNZI3KYKcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
|
|
1716
1716
|
const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
|
|
1717
|
-
const layers = paintLayersOnly(
|
|
1717
|
+
const layers = paintLayersOnly(_chunk5VQXSS2Scjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
|
|
1718
1718
|
const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
|
|
1719
1719
|
const activeLayerId = wanted && _chunkHB4ICNNAcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHB4ICNNAcjs.flattenLayers.call(void 0, layers), 'access', _74 => _74.filter, 'call', _75 => _75((l) => l.type === "pixel"), 'access', _76 => _76.pop, 'call', _77 => _77(), 'optionalAccess', _78 => _78.id]), () => ( null));
|
|
1720
1720
|
const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
|
|
@@ -1730,7 +1730,7 @@ async function deserializePaintDocumentAsync(raw, store) {
|
|
|
1730
1730
|
if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
|
|
1731
1731
|
const r = raw;
|
|
1732
1732
|
const problems = [];
|
|
1733
|
-
const assets = await
|
|
1733
|
+
const assets = await _chunk5VQXSS2Scjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
|
|
1734
1734
|
const loaded = deserializePaintDocument({ ...r, assets });
|
|
1735
1735
|
return { ...loaded, problems: [...problems, ...loaded.problems] };
|
|
1736
1736
|
}
|
|
@@ -5649,7 +5649,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
|
|
|
5649
5649
|
return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
|
|
5650
5650
|
});
|
|
5651
5651
|
const layers = toStandard(dried);
|
|
5652
|
-
const result =
|
|
5652
|
+
const result = _chunk5VQXSS2Scjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
|
|
5653
5653
|
for (const [mode, names] of changed) {
|
|
5654
5654
|
const label = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _289 => _289.find, 'call', _290 => _290((m) => m.id === mode), 'optionalAccess', _291 => _291.label]), () => ( mode));
|
|
5655
5655
|
const std = _nullishCoalesce(_optionalChain([_chunkOLNIPTB3cjs.BLEND_MODES, 'access', _292 => _292.find, 'call', _293 => _293((m) => m.id === _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _294 => _294.label]), () => ( _chunkOLNIPTB3cjs.standardBlendMode.call(void 0, mode)));
|
package/package.json
CHANGED
|
@@ -311,6 +311,7 @@ in the source frame at the document's bit depth, colour mode and profile. Read
|
|
|
311
311
|
| `set_global_light` | Set the document light (`angle`, `altitude` in degrees) that every shadow and bevel with `useGlobalLight` follows. Returns the light. |
|
|
312
312
|
| `paint_stroke` | Paint (`tool` brush), blend with the Mixer Brush (`tool` mixer) or erase (`tool` eraser) along `points` in document px (optional `pressure` 0..1) on a pixel layer or its mask (`channel`; the mixer paints pixels only); `color` #rrggbb (on a mask: black hides, white reveals; for the mixer, the reservoir colour) or `paint` (brush only: a gradient for this stroke); `brush` `{size, hardness, spacing, angle, roundness, opacity, flow, smoothing, pressureSize, pressureOpacity, blend}`; `mixer` `{wet, load, mix, loadEachStroke, cleanEachStroke, mixing: rgb \| pigment}` (tool mixer only). The selection limits the paint. One undo step per call. Returns the layer, channel, changed `bounds`, dab count and, for the mixer, `mixerLoad` `{reservoir, amount, pickup}`. |
|
|
313
313
|
| `set_paint` | Set what the brush paints: one colour (it becomes the foreground) or gradient paint (`stops` sorted by offset, `space` pigment / oklab / srgb, `map`, `softness`). Errors say what is wrong. Returns `paint`, `foreground`, `background`, `brush`. |
|
|
314
|
+
| `sample_color` | The Eyedropper: read the composite colour at a document point (`size` averages a square; default 1 px) and, unless `setForeground` is false, make it the paint foreground. Use it to match a colour already in the image before painting or retouching. Fails outside the canvas or on transparent pixels. Returns `color` and `foreground`. |
|
|
314
315
|
| `get_paint` | Read-only. What the brush paints (`paint`), the foreground and background colours and the brush settings. |
|
|
315
316
|
| `get_mixer_brush` | Read-only. The Mixer Brush settings and what it carries (`reservoir` #rrggbb or null, `amount` left 0..1, `pickup` #rrggbb or null). Call it before a mixer stroke with `loadEachStroke: false`. |
|
|
316
317
|
| `load_mixer_brush` | Fill the Mixer Brush reservoir with `color` (default the foreground), amount 1; keeps the pickup. View state, not an undo step. Use before strokes with `loadEachStroke: false`. Returns the load. |
|