@pixerate/editor 0.194.0 → 0.195.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.
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Magnetic Lasso: an outline that follows the edges of the image (live-wire, Mortensen & Barrett,
3
+ * "Intelligent Scissors", 1995). Each step between neighbouring pixels costs less where it runs
4
+ * along a strong edge (gradient magnitude), on a Laplacian zero-crossing and in the edge's
5
+ * direction; the outline between two points is the cheapest path, found with Dijkstra in a corridor
6
+ * around them. The direction term ignores which side of the edge is darker, so the path holds to an
7
+ * edge whichever way round it is traced.
8
+ */
9
+ import type { ImagePoint } from '../types.cjs';
10
+ import type { PixelBuffer } from './mask.cjs';
11
+ export interface MagneticEdgeOptions {
12
+ /** Detection width in px: a point snaps to the strongest edge this close to it (default 10). */
13
+ width?: number;
14
+ /** 0..1: edges with less contrast than this are ignored (default 0.1, Photoshop's 10 %). */
15
+ contrast?: number;
16
+ }
17
+ /**
18
+ * The edge features of an image, computed lazily in 64 px blocks as the outline reaches them, so a
19
+ * click on a large image costs one luminance pass, not a full-image edge map.
20
+ */
21
+ export declare class EdgeMap {
22
+ readonly width: number;
23
+ readonly height: number;
24
+ readonly contrast: number;
25
+ private readonly luma;
26
+ private readonly blocks;
27
+ constructor(pixels: PixelBuffer, options?: Pick<MagneticEdgeOptions, 'contrast'>);
28
+ /** Edge strength at (x, y) in whole pixels, 0..1 (0 outside the image or below the contrast). */
29
+ strength(x: number, y: number): number;
30
+ private block;
31
+ private computeBlock;
32
+ /** Features of the pixel at (x, y), which must be inside the image. */
33
+ features(x: number, y: number): {
34
+ strength: number;
35
+ dirX: number;
36
+ dirY: number;
37
+ zero: number;
38
+ };
39
+ }
40
+ /**
41
+ * `point` moved onto the strongest edge within `width` px (the nearest of equal ones); unchanged
42
+ * when there is no edge above the contrast that close. Returns a pixel centre.
43
+ */
44
+ export declare function snapToEdge(map: EdgeMap, point: ImagePoint, width?: number): ImagePoint;
45
+ /**
46
+ * The cheapest path along the edges from `from` to `to` (pixel centres, both included), searched
47
+ * in a corridor around the straight line between them: `band` px either side (default the larger
48
+ * of 16 px and a quarter of the distance). Points inside the image.
49
+ */
50
+ export declare function liveWire(map: EdgeMap, from: ImagePoint, to: ImagePoint, band?: number): ImagePoint[];
51
+ /** `points` with runs along one straight line reduced to their ends (exact for 8-connected paths). */
52
+ export declare function simplifyPixelPath(points: readonly ImagePoint[]): ImagePoint[];
53
+ /**
54
+ * The Magnetic Lasso for a given outline (the agent path): each point snaps to the strongest edge
55
+ * within `width` px, and consecutive points are joined by the live-wire path between them (the
56
+ * last back to the first). Points should run along the edge in order, a few dozen px apart.
57
+ */
58
+ export declare function snapPolygonToEdges(pixels: PixelBuffer | EdgeMap, points: readonly ImagePoint[], options?: MagneticEdgeOptions): ImagePoint[];
59
+ /** Path length in px between auto-placed anchors for a Frequency of 0..100 (Photoshop's default 57). */
60
+ export declare function magneticAnchorSpacing(frequency?: number): number;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Magnetic Lasso: an outline that follows the edges of the image (live-wire, Mortensen & Barrett,
3
+ * "Intelligent Scissors", 1995). Each step between neighbouring pixels costs less where it runs
4
+ * along a strong edge (gradient magnitude), on a Laplacian zero-crossing and in the edge's
5
+ * direction; the outline between two points is the cheapest path, found with Dijkstra in a corridor
6
+ * around them. The direction term ignores which side of the edge is darker, so the path holds to an
7
+ * edge whichever way round it is traced.
8
+ */
9
+ import type { ImagePoint } from '../types.js';
10
+ import type { PixelBuffer } from './mask.js';
11
+ export interface MagneticEdgeOptions {
12
+ /** Detection width in px: a point snaps to the strongest edge this close to it (default 10). */
13
+ width?: number;
14
+ /** 0..1: edges with less contrast than this are ignored (default 0.1, Photoshop's 10 %). */
15
+ contrast?: number;
16
+ }
17
+ /**
18
+ * The edge features of an image, computed lazily in 64 px blocks as the outline reaches them, so a
19
+ * click on a large image costs one luminance pass, not a full-image edge map.
20
+ */
21
+ export declare class EdgeMap {
22
+ readonly width: number;
23
+ readonly height: number;
24
+ readonly contrast: number;
25
+ private readonly luma;
26
+ private readonly blocks;
27
+ constructor(pixels: PixelBuffer, options?: Pick<MagneticEdgeOptions, 'contrast'>);
28
+ /** Edge strength at (x, y) in whole pixels, 0..1 (0 outside the image or below the contrast). */
29
+ strength(x: number, y: number): number;
30
+ private block;
31
+ private computeBlock;
32
+ /** Features of the pixel at (x, y), which must be inside the image. */
33
+ features(x: number, y: number): {
34
+ strength: number;
35
+ dirX: number;
36
+ dirY: number;
37
+ zero: number;
38
+ };
39
+ }
40
+ /**
41
+ * `point` moved onto the strongest edge within `width` px (the nearest of equal ones); unchanged
42
+ * when there is no edge above the contrast that close. Returns a pixel centre.
43
+ */
44
+ export declare function snapToEdge(map: EdgeMap, point: ImagePoint, width?: number): ImagePoint;
45
+ /**
46
+ * The cheapest path along the edges from `from` to `to` (pixel centres, both included), searched
47
+ * in a corridor around the straight line between them: `band` px either side (default the larger
48
+ * of 16 px and a quarter of the distance). Points inside the image.
49
+ */
50
+ export declare function liveWire(map: EdgeMap, from: ImagePoint, to: ImagePoint, band?: number): ImagePoint[];
51
+ /** `points` with runs along one straight line reduced to their ends (exact for 8-connected paths). */
52
+ export declare function simplifyPixelPath(points: readonly ImagePoint[]): ImagePoint[];
53
+ /**
54
+ * The Magnetic Lasso for a given outline (the agent path): each point snaps to the strongest edge
55
+ * within `width` px, and consecutive points are joined by the live-wire path between them (the
56
+ * last back to the first). Points should run along the edge in order, a few dozen px apart.
57
+ */
58
+ export declare function snapPolygonToEdges(pixels: PixelBuffer | EdgeMap, points: readonly ImagePoint[], options?: MagneticEdgeOptions): ImagePoint[];
59
+ /** Path length in px between auto-placed anchors for a Frequency of 0..100 (Photoshop's default 57). */
60
+ export declare function magneticAnchorSpacing(frequency?: number): number;
@@ -2,7 +2,7 @@ import { type SelectionMask, type SelectionMode } from './mask.cjs';
2
2
  import type { ColorDistance, ColorRangePreset } from './wand.cjs';
3
3
  import type { RefineEdgeParams } from './refine.cjs';
4
4
  /** Selection tools of the image editor UI. */
5
- export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'range' | 'type' | 'type-vertical';
5
+ export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'magnetic' | 'range' | 'type' | 'type-vertical';
6
6
  export declare const SELECTION_TOOLS: readonly {
7
7
  id: SelectionToolKind;
8
8
  label: string;
@@ -31,6 +31,12 @@ export interface SelectionToolOptions {
31
31
  localized?: number;
32
32
  /** Color Range: select everything except the sampled colours. */
33
33
  rangeInvert?: boolean;
34
+ /** Magnetic Lasso: snap to the strongest edge within this many px (1..256, default 10). */
35
+ magneticWidth?: number;
36
+ /** Magnetic Lasso: ignore edges with less contrast than this, in % (1..100, default 10). */
37
+ magneticContrast?: number;
38
+ /** Magnetic Lasso: how often anchors are placed as the pointer moves (0..100, default 57). */
39
+ magneticFrequency?: number;
34
40
  /** Type Mask: the text to select (default "Type"). A click places its first baseline. */
35
41
  typeText?: string;
36
42
  /** Type Mask: font size in px (default 72). */
@@ -2,7 +2,7 @@ import { type SelectionMask, type SelectionMode } from './mask.js';
2
2
  import type { ColorDistance, ColorRangePreset } from './wand.js';
3
3
  import type { RefineEdgeParams } from './refine.js';
4
4
  /** Selection tools of the image editor UI. */
5
- export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'range' | 'type' | 'type-vertical';
5
+ export type SelectionToolKind = 'wand' | 'rect' | 'ellipse' | 'row' | 'column' | 'lasso' | 'polygon' | 'magnetic' | 'range' | 'type' | 'type-vertical';
6
6
  export declare const SELECTION_TOOLS: readonly {
7
7
  id: SelectionToolKind;
8
8
  label: string;
@@ -31,6 +31,12 @@ export interface SelectionToolOptions {
31
31
  localized?: number;
32
32
  /** Color Range: select everything except the sampled colours. */
33
33
  rangeInvert?: boolean;
34
+ /** Magnetic Lasso: snap to the strongest edge within this many px (1..256, default 10). */
35
+ magneticWidth?: number;
36
+ /** Magnetic Lasso: ignore edges with less contrast than this, in % (1..100, default 10). */
37
+ magneticContrast?: number;
38
+ /** Magnetic Lasso: how often anchors are placed as the pointer moves (0..100, default 57). */
39
+ magneticFrequency?: number;
34
40
  /** Type Mask: the text to select (default "Type"). A click places its first baseline. */
35
41
  typeText?: string;
36
42
  /** Type Mask: font size in px (default 72). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.194.0",
3
+ "version": "0.195.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -252,7 +252,7 @@ in the source frame at the document's bit depth, colour mode and profile. Read
252
252
  | `select_rect` | Rectangular marquee: `x`, `y`, `width`, `height` (natural px), `mode` (replace, add, subtract, intersect), `feather` px, `antiAlias`. Returns the summary. |
253
253
  | `select_ellipse` | Elliptical marquee inscribed in `x`, `y`, `width`, `height`; same options. A feathered ellipse makes a vignette. Returns the summary. |
254
254
  | `select_line` | Single row or column marquee: `orientation` `row` (at y) or `column` (at x), `position` in natural px, `mode`. A 1 px line across the image. Returns the summary. |
255
- | `select_polygon` | The lasso: `points` (at least 3 `{x, y}` along the outline, closed automatically), `mode`, `feather`, `antiAlias`. Trace a subject's contour, not its box. Returns the summary. |
255
+ | `select_polygon` | The lasso: `points` (at least 3 `{x, y}` along the outline, closed automatically), `mode`, `feather`, `antiAlias`; `snapToEdges: {width, contrast}` makes it the Magnetic Lasso (points snap to edges, the outline follows them). Trace a subject's contour, not its box. Returns the summary (plus `outlinePoints` when snapped). |
256
256
  | `magic_wand` | Select similar colour from `x`, `y`: `tolerance` 0..255 (default 32), `contiguous` (default true), `distance` `rgb` or `perceptual`, `sampleMerged`, `sample` (`composite` or `active-layer`), `mode`, `feather`. For flat backdrops and solid colours. Returns the summary. |
257
257
  | `select_color_range` | Color Range, soft: `samples` (`[{color, x?, y?}]`) or a `preset` (reds … magentas, highlights, midtones, shadows, skinTones); `fuzziness` (samples 0..200, default 40; tone presets' falloff, default 20), `localized` px radius around positioned samples, `invert`, `sample`, `mode`, `feather`. Returns the summary. |
258
258
  | `load_selection_from_image` | Load a mask image (`image` data URL or URL; white = selected) by `channel` (luminance, alpha, red, green, blue), with `threshold`, `invert`, `mode`. For AI or saved mattes; then `refine_selection`. Returns the summary. |
@@ -96,7 +96,8 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
96
96
  | Subject | Method |
97
97
  | --- | --- |
98
98
  | Geometric areas: a frame, a screen, a band | `select_rect` / `select_ellipse`, with `feather` for soft transitions |
99
- | A subject with a clear outline (product, person, animal) | `select_subject` if the host has a model; else `select_polygon` along the contour (20–60 points), then `refine_selection` |
99
+ | A subject with a clear outline (product, person, animal) | `select_subject` if the host has a model; else `select_polygon` with `snapToEdges` (12–30 points within `width` of the edge), then `refine_selection` |
100
+ | A low-contrast or busy outline the edges don't follow | `select_polygon` without `snapToEdges`, along the contour (20–60 points) |
100
101
  | Flat backdrop or solid colour (studio white, green screen, sky without clouds) | `magic_wand` on the backdrop (`tolerance` 20–40; `distance: "perceptual"` for gradients), then `invert_selection` |
101
102
  | A colour spread across the image (all the reds, a dress) | `select_color_range` with `samples` (several picks) or a hue `preset`; `localized` to keep one area |
102
103
  | Tones (shadows, highlights, a luminosity mask) | `select_color_range` with `preset` `shadows` / `midtones` / `highlights` |
@@ -155,6 +156,10 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
155
156
  30–60), check `percent`, and grow with `mode: "add"`.
156
157
  - **Box instead of outline:** `select_rect` around a subject masks its background too. Trace
157
158
  the contour.
159
+ - **Magnetic outline jumps to the wrong edge:** `snapToEdges` follows the strongest edge near
160
+ each point, which can be a shadow or a texture. Put points within `width` of the edge you
161
+ want, add points where it turns or runs past another edge, raise `contrast` on a busy
162
+ background, and drop `snapToEdges` where the edge is too faint.
158
163
  - **Over-feathering hard objects:** a 10 px feather on a product looks like a glow. Keep hard
159
164
  edges at 0–2 px and refine soft ones instead.
160
165
  - **Halo:** the old background shows as a light or dark fringe. `contract` 1–2 px or
@@ -183,7 +188,7 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
183
188
  - `get_selection`: empty, bounds, area and percent after every step
184
189
  - `select_all`, `deselect`, `invert_selection`: whole-image selections
185
190
  - `select_rect`, `select_ellipse`: marquees
186
- - `select_polygon`: the lasso, along a contour
191
+ - `select_polygon`: the lasso, along a contour; with `snapToEdges`, the Magnetic Lasso
187
192
  - `select_line`: a single row or column
188
193
  - `select_layer_transparency`: a layer's own pixels
189
194
  - `grow_selection`, `select_similar`: add similar colour, connected or anywhere