@pixerate/editor 0.110.0 → 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +3 -0
- package/dist/{chunk-DMRSJBJF.js → chunk-CZOXTEMN.js} +2709 -599
- package/dist/chunk-CZOXTEMN.js.map +1 -0
- package/dist/{chunk-MGL4U5WA.cjs → chunk-YGIMK4NX.cjs} +2697 -587
- package/dist/chunk-YGIMK4NX.cjs.map +1 -0
- package/dist/{export-DRiLzP_j.d.cts → export-DBba-buV.d.cts} +556 -20
- package/dist/{export-CO2ryu3I.d.ts → export-DNu_Jr8p.d.ts} +556 -20
- package/dist/image-editor/index.cjs +1953 -702
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +253 -9
- package/dist/image-editor/index.d.ts +253 -9
- package/dist/image-editor/index.js +1297 -46
- package/dist/image-editor/index.js.map +1 -1
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.d.cts +2 -2
- package/dist/paint-editor/index.d.ts +2 -2
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +27 -30
- package/skills/pixerate-image-editor/references/shapes-and-type.md +60 -0
- package/dist/chunk-DMRSJBJF.js.map +0 -1
- package/dist/chunk-MGL4U5WA.cjs.map +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkYGIMK4NXcjs = require('../chunk-YGIMK4NX.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
@@ -1697,11 +1697,11 @@ function header(state, options) {
|
|
|
1697
1697
|
return out;
|
|
1698
1698
|
}
|
|
1699
1699
|
function serializePaintDocument(state, options = {}) {
|
|
1700
|
-
const { layers, assets } =
|
|
1700
|
+
const { layers, assets } = _chunkYGIMK4NXcjs.serializeLayers.call(void 0, state.layers);
|
|
1701
1701
|
return { ...header(state, options), layers, assets };
|
|
1702
1702
|
}
|
|
1703
1703
|
async function serializePaintDocumentExternal(state, store, options = {}) {
|
|
1704
|
-
const { layers, assets } = await
|
|
1704
|
+
const { layers, assets } = await _chunkYGIMK4NXcjs.serializeLayersExternal.call(void 0, state.layers, store);
|
|
1705
1705
|
return { ...header(state, options), layers, assets };
|
|
1706
1706
|
}
|
|
1707
1707
|
function paintLayersOnly(layers, problems) {
|
|
@@ -1738,7 +1738,7 @@ function deserializePaintDocument(raw) {
|
|
|
1738
1738
|
const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
|
|
1739
1739
|
const paper = normalizePaper(_nullishCoalesce(r.paper, () => ( {})));
|
|
1740
1740
|
const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
|
|
1741
|
-
const layers = paintLayersOnly(
|
|
1741
|
+
const layers = paintLayersOnly(_chunkYGIMK4NXcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
|
|
1742
1742
|
const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
|
|
1743
1743
|
const activeLayerId = wanted && _chunkPOGBUYWEcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkPOGBUYWEcjs.flattenLayers.call(void 0, layers), 'access', _33 => _33.filter, 'call', _34 => _34((l) => l.type === "pixel"), 'access', _35 => _35.pop, 'call', _36 => _36(), 'optionalAccess', _37 => _37.id]), () => ( null));
|
|
1744
1744
|
return { state: { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) }, extensions: documentExtensions(r), guides: r.guides, swatches: r.swatches, mixingPad: r.mixingPad, problems };
|
|
@@ -1747,7 +1747,7 @@ async function deserializePaintDocumentAsync(raw, store) {
|
|
|
1747
1747
|
if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
|
|
1748
1748
|
const r = raw;
|
|
1749
1749
|
const problems = [];
|
|
1750
|
-
const assets = await
|
|
1750
|
+
const assets = await _chunkYGIMK4NXcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
|
|
1751
1751
|
const loaded = deserializePaintDocument({ ...r, assets });
|
|
1752
1752
|
return { ...loaded, problems: [...problems, ...loaded.problems] };
|
|
1753
1753
|
}
|
|
@@ -3420,7 +3420,7 @@ var PaintEditorController = (_class10 = class {
|
|
|
3420
3420
|
return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
|
|
3421
3421
|
});
|
|
3422
3422
|
const layers = toStandard(this.doc.layers);
|
|
3423
|
-
const result =
|
|
3423
|
+
const result = _chunkYGIMK4NXcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
|
|
3424
3424
|
for (const [mode, names] of changed) {
|
|
3425
3425
|
const label = _nullishCoalesce(_optionalChain([_chunkXIOMMGPDcjs.BLEND_MODES, 'access', _81 => _81.find, 'call', _82 => _82((m) => m.id === mode), 'optionalAccess', _83 => _83.label]), () => ( mode));
|
|
3426
3426
|
const std = _nullishCoalesce(_optionalChain([_chunkXIOMMGPDcjs.BLEND_MODES, 'access', _84 => _84.find, 'call', _85 => _85((m) => m.id === _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _86 => _86.label]), () => ( _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, mode)));
|
|
@@ -3,13 +3,13 @@ import { B as BrushSettings, M as MixerSettings, a as MixingModel, b as BlenderS
|
|
|
3
3
|
export { e as MAX_BRUSH_SIZE } from '../blending-aOE6Y3UE.cjs';
|
|
4
4
|
import { R as RasterRect, a as TiledSurface, B as BlendMode, c as BlendModeInfo } from '../surface-C8RRg_Bh.cjs';
|
|
5
5
|
export { d as BLEND_MODES, e as PAINTERLY_BLEND_MODES, f as Tile, i as isBlendMode, g as isPainterlyBlendMode, s as standardBlendMode } from '../surface-C8RRg_Bh.cjs';
|
|
6
|
-
import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-
|
|
6
|
+
import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-DBba-buV.cjs';
|
|
7
7
|
import { g as PresenceStore, e as PresenceClock, d as PresenceActorInfo, c as PresenceActor, f as PresenceState } from '../presence-Cb6WhcrQ.cjs';
|
|
8
8
|
import { a as AgentToolProvider } from '../registry-BqA1AZt0.cjs';
|
|
9
9
|
import '../types-CwMPoRMU.cjs';
|
|
10
|
-
import '../types-DyQq-WPY.cjs';
|
|
11
10
|
import '../bezier-BfwIbVTl.cjs';
|
|
12
11
|
import '../types-BFkYA4eF.cjs';
|
|
12
|
+
import '../types-DyQq-WPY.cjs';
|
|
13
13
|
import '../warp-D5jz_tN7.cjs';
|
|
14
14
|
import '../schema-Di0CS6Pe.cjs';
|
|
15
15
|
|
|
@@ -3,13 +3,13 @@ import { B as BrushSettings, M as MixerSettings, a as MixingModel, b as BlenderS
|
|
|
3
3
|
export { e as MAX_BRUSH_SIZE } from '../blending-DXl06NSx.js';
|
|
4
4
|
import { R as RasterRect, a as TiledSurface, B as BlendMode, c as BlendModeInfo } from '../surface-C8RRg_Bh.js';
|
|
5
5
|
export { d as BLEND_MODES, e as PAINTERLY_BLEND_MODES, f as Tile, i as isBlendMode, g as isPainterlyBlendMode, s as standardBlendMode } from '../surface-C8RRg_Bh.js';
|
|
6
|
-
import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-
|
|
6
|
+
import { I as ImageEditorAssetStore, S as SerializedLayer, P as PsdExportResult } from '../export-DNu_Jr8p.js';
|
|
7
7
|
import { g as PresenceStore, e as PresenceClock, d as PresenceActorInfo, c as PresenceActor, f as PresenceState } from '../presence-Cb6WhcrQ.js';
|
|
8
8
|
import { a as AgentToolProvider } from '../registry-D-4fit9C.js';
|
|
9
9
|
import '../types-CwMPoRMU.js';
|
|
10
|
-
import '../types-DtL_qLFz.js';
|
|
11
10
|
import '../bezier-DYBvLgUH.js';
|
|
12
11
|
import '../types-BFkYA4eF.js';
|
|
12
|
+
import '../types-DtL_qLFz.js';
|
|
13
13
|
import '../warp-CWHZzE3x.js';
|
|
14
14
|
import '../schema-Di0CS6Pe.js';
|
|
15
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pixerate-image-editor
|
|
3
|
-
description: How to colour-correct, composite and retouch a photo in the Pixerate image editor through its agent tools - layers (pixel, adjustment, group, shape, annotation and smart object layers with masks, clipping, blend modes, opacity and fill; merge, flatten, filters), smart objects (non-destructive transforms, smart filters, linked contents), vector shape layers (live
|
|
3
|
+
description: How to colour-correct, composite and retouch a photo in the Pixerate image editor through its agent tools - layers (pixel, adjustment, group, shape, type, annotation and smart object layers with masks, clipping, blend modes, opacity and fill; merge, flatten, filters), smart objects (non-destructive transforms, smart filters, linked contents), vector shape layers (live shapes, arrows, paths, path operations, fills and strokes), live type layers, live layer effects, base adjustments, adjustment layers, selections and masks, Free Transform, crop, rotate, flip, Mixer Brush, undo, PSD, histogram and previews. Use when asked to edit, grade, correct, crop, straighten or mask an image, add a shadow, glow or outline, transform or warp a layer, draw a shape or arrow, add or edit text, make a smart object, or open or save a PSD, or when list_layers, set_adjustments, add_layer_effect, transform_layer, add_shape_layer, add_text_layer, convert_to_smart_object, paint_stroke, import_psd or render_preview are available.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Image editor
|
|
@@ -9,7 +9,8 @@ The image editor holds a layer stack over a canvas the size of the source image.
|
|
|
9
9
|
image gives one pixel layer, **Background**, whose pixels are the source and whose `develop`
|
|
10
10
|
filter holds the base adjustments; adjustment layers sit above it (bottom to top, each through
|
|
11
11
|
its mask, opacity and blend mode) and every annotation is its own layer on top (pen, rectangle,
|
|
12
|
-
ellipse, line and arrow annotations are shape layers that remember
|
|
12
|
+
ellipse, line and arrow annotations are shape layers, text annotations type layers, that remember
|
|
13
|
+
them). `list_layers`
|
|
13
14
|
shows the whole stack. Edits never touch the source pixels. The base controls edit the develop
|
|
14
15
|
filter of the active pixel layer (the Background unless another pixel layer is active); base
|
|
15
16
|
`blur` blurs that layer (or, in documents saved before layers with blur and adjustment layers,
|
|
@@ -17,7 +18,8 @@ the output after the layers), and base `opacity` is the output's alpha. Pixel, a
|
|
|
17
18
|
and smart object layers can carry live effects (shadows, glows, bevels, overlays, strokes). A smart
|
|
18
19
|
object places contents (pixels or a nested layer document) through a transform and smart filters,
|
|
19
20
|
re-rendered from the contents on every change. A shape layer holds vector paths with a fill and a
|
|
20
|
-
stroke, rendered again from the paths on every change, so it stays sharp through any transform.
|
|
21
|
+
stroke, rendered again from the paths on every change, so it stays sharp through any transform. A
|
|
22
|
+
type layer holds live, styled text (point or paragraph) drawn with the editor's fonts.
|
|
21
23
|
Also an optional selection and crop/rotate/flip. See `pixerate-agent-tools` for errors, namespacing and command
|
|
22
24
|
batching.
|
|
23
25
|
|
|
@@ -119,31 +121,14 @@ batching.
|
|
|
119
121
|
6. **Finish**: `rasterize_smart_object` only when the user wants plain pixels to paint on; the
|
|
120
122
|
placement and filters are then gone.
|
|
121
123
|
|
|
122
|
-
###
|
|
124
|
+
### Shapes and text
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
(dashes in multiples of the width). It returns the layer id and `shape` (components with
|
|
131
|
-
index, op and live parameters, bounds).
|
|
132
|
-
2. **Combine paths**: `add_shape_component` with `op` `combine`, `subtract`, `intersect` or
|
|
133
|
-
`exclude` (Photoshop's path operations; the bottom component always combines). The stroke
|
|
134
|
-
follows the outline of the combined area. `merge_shape_components` turns the result into one
|
|
135
|
-
plain path (same look).
|
|
136
|
-
3. **Edit, don't redraw**: `set_shape_component` changes a live shape's fields (only `radii`, only
|
|
137
|
-
`x2` / `y2`, …; the rest stay), replaces a component's `subpaths` (ending its live shape) or
|
|
138
|
-
changes its `op`. `update_shape` restyles the fill, the stroke (only the settings given) or the
|
|
139
|
-
fill rule. Read `get_shape_layer` first for the component indices.
|
|
140
|
-
4. **Place it**: `offset_layer`, `transform_layer`, `flip_layer`, `rotate_layer_90` and `warp_layer`
|
|
141
|
-
map the paths, never resample pixels; live shapes stay live under moves, scales, rotations and
|
|
142
|
-
skews (perspective and warps turn them into plain paths). Stroke widths do not scale.
|
|
143
|
-
5. **Style it like any layer**: masks, clipping, blend modes, opacity, fill opacity and layer
|
|
144
|
-
effects (`add_layer_effect`) all work on shape layers.
|
|
145
|
-
6. **Pixels only when needed**: painting a shape's pixels is refused; `rasterize_layer` turns it
|
|
146
|
-
into a pixel layer (paths gone) when the user wants to paint on it.
|
|
126
|
+
Draw boxes, badges, arrows and callouts as shape layers (`add_shape_layer` with a live `shape`,
|
|
127
|
+
then `set_shape_component` / `update_shape` / `add_shape_component`), and text as type layers
|
|
128
|
+
(`add_text_layer`, then `set_text`, `set_text_style`, `set_paragraph_style` by `start` / `end`
|
|
129
|
+
range). Both stay sharp through transforms and take effects, masks and blend modes; rasterize only
|
|
130
|
+
to paint on them. Read [references/shapes-and-type.md](references/shapes-and-type.md) before
|
|
131
|
+
drawing or editing either.
|
|
147
132
|
|
|
148
133
|
### Layer effects
|
|
149
134
|
|
|
@@ -315,10 +300,12 @@ batching.
|
|
|
315
300
|
| `get_image_info` | Read the geometry: source `image` size, `crop` box (source pixels, or null), `rotation` degrees, `flipH` / `flipV`, the `output` size after crop and rotation, the layer count and `canUndo` / `canRedo`. Call before cropping or selecting so coordinates are right. |
|
|
316
301
|
| `get_histogram` | Judge exposure numerically: per channel and luminance `mean`, `p1` and `p99` (0..255), and `clipping` percent at pure black and white per channel. Reads the last render, so call `render_preview` first. `bins` (16, 32, 64 or 256) adds the counts. Cheaper than another image for checking a tonal change. |
|
|
317
302
|
| `render_preview` | See the edited image (crop, adjustments, layers, annotations) as a PNG, or with `layerId` one layer alone. `maxSide` 16..2048 px, default 512. Images cost tokens: render after a group of edits, use 512 for overall look and 1024+ to judge clipping, edges and masks. Fails in environments without rendering. |
|
|
318
|
-
| `inspect_psd` | Read a PSD / PSB (`data` base64) without opening it: size, `depth`, `colorMode`, `resolution`, every layer bottom first with `psdKind`, the `type` it would become (`smart` for smart objects) and `status` (`mapped`, `approximated`, `dropped`) with `notes`, and the import `warnings`. Call before `import_psd`. |
|
|
319
|
-
| `export_psd` | Save the document as an 8-bit RGB PSD (PSB above 30000 px) with layers, groups, adjustment layers and masks. Returns `data` (base64), `size` in bytes, `psb` and `warnings` (crop or rotation not applied, filters and depth masks baked,
|
|
303
|
+
| `inspect_psd` | Read a PSD / PSB (`data` base64) without opening it: size, `depth`, `colorMode`, `resolution`, every layer bottom first with `psdKind`, the `type` it would become (`smart`, `shape` and `type` for Photoshop smart objects, shapes and text) and `status` (`mapped`, `approximated`, `dropped`) with `notes`, and the import `warnings`. Call before `import_psd`. |
|
|
304
|
+
| `export_psd` | Save the document as an 8-bit RGB PSD (PSB above 30000 px) with layers, groups, adjustment layers and masks. Returns `data` (base64), `size` in bytes, `psb` and `warnings` (crop or rotation not applied, filters and depth masks baked, annotations rasterized or left out, Pigment blends written as Normal). Shape and type layers are written as real Photoshop shape and type layers. Changes nothing. |
|
|
320
305
|
| `get_transform_frame` | Before a transform: what it would move (`content`, `moved`: pixels, mask, selection), its `frame` (document bounds of the content), `corners` (top-left, top-right, bottom-right, bottom-left) and `center`. `meshColumns` / `meshRows` also return an identity warp `mesh` over the frame to edit for `warp_layer`. Changes nothing. |
|
|
321
306
|
| `get_smart_object` | Read a smart object: `contents` (`id` shared by linked instances, `name`, `kind` raster or document, `width` / `height`, `decoded`, `fileType`, `linkedPath`, `instances`), `placement` (`corners`, `warp` in contents px, `interpolation`, and when `affine` the `scaleX` / `scaleY` in percent of the contents, `rotate`, `skewX`, `center`, `bounds`) and `smartFilters` (`enabled`, `filters` bottom to top with ids, settings, `blend`, `opacity`; kind `psd` is a Photoshop filter kept but not drawn; the filter `mask`). Call before changing a smart object. |
|
|
307
|
+
| `list_fonts` | Read the font families type layers can use here (generic families always work) and which shaper draws them. Call before choosing a font. |
|
|
308
|
+
| `get_text_layer` | Read a type layer: `text`, character `runs` and `paragraphs` as `start` / `end` ranges (UTF-16 code units, end exclusive) with their styles, the `frame` (point, or box with its size), the text-to-document `transform`, laid-out `lines` (range, baseline, width), `bounds`, `missingFonts`, and `rendering` (`live`, or `stored` pixels from a file until the next edit). Call before editing text you did not write. |
|
|
322
309
|
| `get_shape_layer` | Read a shape layer: `components` bottom to top (`index`, `op`, `live` shape parameters or null, `subpaths` with absolute anchors and handles, `bounds`), `fillRule`, `fill` and `stroke` (paint and settings), `geometryBounds` (the paths) and `bounds` (rendered pixels, stroke included), and `annotationId` while it is still a migrated annotation. Call before editing a shape you did not draw. |
|
|
323
310
|
| `export_smart_object_contents` | Export Contents: the contents as a file (`name`, `mimeType`, `byteLength`, `base64`): the file they came from while unedited, else a PNG (raster) or PSD / PSB (nested document). Changes nothing. |
|
|
324
311
|
| `capture_view` | Inspect detail in natural image pixels (the space of `get_selection` and `select_region`, before crop and rotation): `region` `content` (whole image, default), `selection` or `rect`; small regions are enlarged up to 8× with hard pixel edges, so a 64 px rect shows real pixels. `includeOverlays: true` shades unselected pixels and outlines the crop: use it to check a mask's edge before `apply_selection_as_mask`. Returns the `rect` and `scale`. Use `render_preview` for the final framed result. |
|
|
@@ -366,6 +353,12 @@ batching.
|
|
|
366
353
|
| `remove_layer_mask` | Delete a mask without applying it; disable it instead to keep it. |
|
|
367
354
|
| `layer_via_copy` | Copy the selected pixels of a pixel layer (default the active one) to a new layer above it; `cut: true` removes them from the source. Needs a selection. Returns the new layer. |
|
|
368
355
|
| `rasterize_layer` | Turn a shape layer into a pixel layer showing the same pixels (same id, mask, effects, opacity, blend; the paths are gone), an annotation layer into pixels (browser only), a smart object into a pixel layer (as `rasterize_smart_object`), or bake a pixel layer's develop / blur filters into its pixels. Do it before painting over a shape or annotation, or when the user wants the filters fixed. Destructive. |
|
|
356
|
+
| `add_text_layer` | Add live type above the active layer and make it active: `text`, `x`, `y`, optional `box` (paragraph text), `style`, `paragraph`, `rotation`, `name`, `opacity`, `blend`, placement. Returns the `layer` and `text` (with `lines` and `missingFonts`). One undo step. |
|
|
357
|
+
| `set_text` | Replace text `start`..`end` (default all) with `text`; start = end inserts. New text takes the style at `start`. Returns the text layer. |
|
|
358
|
+
| `set_text_style` | Set character style fields over `start`..`end` (default all): `fontFamily`, `fontWeight`, `italic`, `fontSize`, `color`, `opacity`, `tracking`, `leading`, `baselineShift`, `underline`, `strikethrough` (`null` resets optional ones). Returns the runs. |
|
|
359
|
+
| `set_paragraph_style` | Set `align`, `autoLeading`, indents, `spaceBefore` / `spaceAfter` on every paragraph `start`..`end` touches (default all). Returns the text layer. |
|
|
360
|
+
| `set_text_frame` | `kind: point` (one line per paragraph) or `kind: box` with `width` and `height` (wrapping paragraph text), or resize a box; the first line stays put. Returns the text layer and its lines. |
|
|
361
|
+
| `convert_text_to_shape` | Type › Convert to Shape: glyph outlines become a shape layer with the same id (text no longer editable; fill from the first run's colour; `warnings` lists losses). Needs an outline font shaper. Destructive. |
|
|
369
362
|
| `add_shape_layer` | Add a vector shape layer above the active layer (or placed with `aboveId` / `belowId` / `parentId` / `index`) and make it active: `shape` (live rect, ellipse, polygon, star or line, document px), `subpaths` (SVG path data or anchors) or several `components` with path ops; `fill` (colour, gradient or pattern, default the foreground colour; `null` none), `stroke` (`width`, `paint`, `align`, `cap`, `join`, `miterLimit`, `dashes` in widths), `fillRule`, `name`, `opacity`, `blend`. Returns the `layer` and the `shape`. One undo step. |
|
|
370
363
|
| `update_shape` | Restyle a shape: `fill` (replace, `null` removes), `stroke` (only the settings given change; `null` removes; a new stroke needs `width` and `paint`), `fillRule`. Geometry is unchanged. Returns the shape. |
|
|
371
364
|
| `set_shape_component` | Change component `componentIndex` (from `get_shape_layer`): `shape` fields (without `kind`, or with the same kind, unset fields keep their values), new `subpaths` (ends the live shape), or `op`. Returns the shape. |
|
|
@@ -421,10 +414,14 @@ batching.
|
|
|
421
414
|
- `merge_down`, `merge_visible` and `flatten_image` merge annotation layers only in a browser
|
|
422
415
|
(they need a canvas); elsewhere they fail and say so.
|
|
423
416
|
- `paint_stroke`, `fill_pixels` and `clear_pixels` need a visible pixel layer (or a layer with a
|
|
424
|
-
raster mask and `channel: "mask"`); adjustment, group, shape, annotation and smart object layers can
|
|
417
|
+
raster mask and `channel: "mask"`); adjustment, group, shape, type, annotation and smart object layers can
|
|
425
418
|
only be painted through their masks (and a smart object through `channel: "filter-mask"`).
|
|
426
419
|
To paint a smart object's pixels, `edit_smart_object_contents` or rasterize it. A layer with
|
|
427
420
|
`locks.pixels` refuses paint.
|
|
421
|
+
- Text ranges count UTF-16 code units (an emoji is two). Point text grows from its origin: centred
|
|
422
|
+
text is centred on `x`. Type cannot be distorted, put in perspective or warped; it can be scaled,
|
|
423
|
+
rotated and skewed. Where no font shaper exists (a server without one), type layers keep their
|
|
424
|
+
stored pixels and edits are refused with a reason.
|
|
428
425
|
- Shape strokes are not layer-effect strokes: `stroke` on `add_shape_layer` / `update_shape`
|
|
429
426
|
follows the path (and its dashes and caps); `add_layer_effect` `stroke` outlines the rendered
|
|
430
427
|
pixels. Arrowheads belong to `line` live shapes (their `width` and `length` are pixels), not to
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Shape and type layers
|
|
2
|
+
|
|
3
|
+
Detail for the `pixerate-image-editor` skill: how to draw and edit vector shapes and live text.
|
|
4
|
+
|
|
5
|
+
## Shape layers
|
|
6
|
+
|
|
7
|
+
1. **Draw it as a live shape**: `add_shape_layer` with `shape` `{ kind: 'rect', x, y, width,
|
|
8
|
+
height, radius | radii }`, `ellipse`, `polygon` (`sides`), `star` (`points`, `innerRatio`) or
|
|
9
|
+
`line` (`x1`…`y2`, `weight`, `startArrow` / `endArrow` `{ width, length, concavity }`), all in
|
|
10
|
+
document pixels. A free path takes `subpaths` (SVG path data, or anchors with absolute `in` /
|
|
11
|
+
`out` handles). `fill` is a colour string or `{ type: 'gradient' | 'pattern', … }` (default the
|
|
12
|
+
foreground colour; `null` for none); `stroke` is `{ width, paint, align, cap, join, dashes }`
|
|
13
|
+
(dashes in multiples of the width). It returns the layer id and `shape` (components with
|
|
14
|
+
index, op and live parameters, bounds).
|
|
15
|
+
2. **Combine paths**: `add_shape_component` with `op` `combine`, `subtract`, `intersect` or
|
|
16
|
+
`exclude` (Photoshop's path operations; the bottom component always combines). The stroke
|
|
17
|
+
follows the outline of the combined area. `merge_shape_components` turns the result into one
|
|
18
|
+
plain path (same look).
|
|
19
|
+
3. **Edit, don't redraw**: `set_shape_component` changes a live shape's fields (only `radii`, only
|
|
20
|
+
`x2` / `y2`, …; the rest stay), replaces a component's `subpaths` (ending its live shape) or
|
|
21
|
+
changes its `op`. `update_shape` restyles the fill, the stroke (only the settings given) or the
|
|
22
|
+
fill rule. Read `get_shape_layer` first for the component indices.
|
|
23
|
+
4. **Place it**: `offset_layer`, `transform_layer`, `flip_layer`, `rotate_layer_90` and `warp_layer`
|
|
24
|
+
map the paths, never resample pixels; live shapes stay live under moves, scales, rotations and
|
|
25
|
+
skews (perspective and warps turn them into plain paths). Stroke widths do not scale.
|
|
26
|
+
5. **Style it like any layer**: masks, clipping, blend modes, opacity, fill opacity and layer
|
|
27
|
+
effects (`add_layer_effect`) all work on shape layers.
|
|
28
|
+
6. **Pixels only when needed**: painting a shape's pixels is refused; `rasterize_layer` turns it
|
|
29
|
+
into a pixel layer (paths gone) when the user wants to paint on it.
|
|
30
|
+
|
|
31
|
+
## Type layers
|
|
32
|
+
|
|
33
|
+
1. **Add it**: `add_text_layer` with `text` (`\n` starts a paragraph), `x`, `y` (point text: the
|
|
34
|
+
first line's baseline at its alignment edge) or a `box` `{ width, height }` for paragraph text
|
|
35
|
+
that wraps (then `x`, `y` is the box's top-left), a `style` (`fontFamily`, `fontWeight`,
|
|
36
|
+
`italic`, `fontSize` in px, `color`, `tracking` in 1/1000 em, `leading` in px, `baselineShift`,
|
|
37
|
+
`underline`, `strikethrough`) and a `paragraph` style (`align`, `autoLeading`, indents,
|
|
38
|
+
`spaceBefore` / `spaceAfter`). Call `list_fonts` first when the font matters: a missing family
|
|
39
|
+
draws with a fallback and comes back in `missingFonts`.
|
|
40
|
+
2. **Edit by range**: ranges are `start` / `end` in UTF-16 code units, `end` exclusive, as
|
|
41
|
+
`get_text_layer` reports runs and lines. `set_text` replaces a range (start = end inserts; new
|
|
42
|
+
text takes the style at `start`), `set_text_style` styles a range (only the fields given),
|
|
43
|
+
`set_paragraph_style` styles the paragraphs a range touches. Re-read the runs after an edit
|
|
44
|
+
that changes the length before using old ranges.
|
|
45
|
+
3. **Shape the block**: `set_text_frame` switches between point text and a wrapping box (or
|
|
46
|
+
resizes the box) with the first line kept in place.
|
|
47
|
+
4. **Place it**: `offset_layer`, `transform_layer`, `flip_layer` and `rotate_layer_90` change the
|
|
48
|
+
text's matrix and draw it again (scale, rotate, skew, flips). Distort, perspective and warp are
|
|
49
|
+
refused: rasterize first. Masks, clipping, blend modes and effects work as on any layer.
|
|
50
|
+
5. **Outlines and pixels**: `convert_text_to_shape` makes glyph outlines a shape layer (needs an
|
|
51
|
+
outline font shaper; the browser canvas cannot); `rasterize_layer` makes it pixels.
|
|
52
|
+
|
|
53
|
+
## Photoshop files
|
|
54
|
+
|
|
55
|
+
`import_psd` brings Photoshop shape layers in as live shapes (paths with their path operations, fill,
|
|
56
|
+
stroke, and live rectangles, rounded rectangles, ellipses and lines) and type layers as live text
|
|
57
|
+
that shows Photoshop's pixels until it is edited. `get_text_layer` reports `rendering: "stored"`
|
|
58
|
+
and `missingFonts` for those: if a font is missing, edits draw with a fallback, so tell the user
|
|
59
|
+
before editing such text, or pick an available font with `set_text_style`. `export_psd` writes both
|
|
60
|
+
kinds back as Photoshop layers; unchanged ones are written byte for byte as they were read.
|