@pixerate/editor 0.266.2 → 0.268.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/agent/index.cjs +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/controller.d.cts +8 -0
- package/dist/animation-editor/controller.d.ts +8 -0
- package/dist/animation-editor/effect-tools.d.cts +1 -1
- package/dist/animation-editor/effect-tools.d.ts +1 -1
- package/dist/animation-editor/index.cjs +175 -108
- package/dist/animation-editor/index.js +94 -27
- package/dist/brushes/index.cjs +201 -75
- package/dist/brushes/index.d.cts +4 -3
- package/dist/brushes/index.d.ts +4 -3
- package/dist/brushes/index.js +138 -12
- package/dist/brushes/library.d.cts +27 -1
- package/dist/brushes/library.d.ts +27 -1
- package/dist/brushes/profiles.d.cts +10 -1
- package/dist/brushes/profiles.d.ts +10 -1
- package/dist/brushes/schema.d.cts +4 -0
- package/dist/brushes/schema.d.ts +4 -0
- package/dist/brushes/sources.d.cts +114 -0
- package/dist/brushes/sources.d.ts +114 -0
- package/dist/brushes/types.d.cts +37 -5
- package/dist/brushes/types.d.ts +37 -5
- package/dist/brushes/ui.d.cts +40 -4
- package/dist/brushes/ui.d.ts +40 -4
- package/dist/{brushstrokeRender-KD453OBX.js → brushstrokeRender-A727TTNQ.js} +7 -7
- package/dist/{brushstrokeRender-FSUWXUZY.cjs → brushstrokeRender-WR2N5HHY.cjs} +23 -23
- package/dist/canvas/brushTypes.d.cts +12 -0
- package/dist/canvas/brushTypes.d.ts +12 -0
- package/dist/canvas/brushstroke.d.cts +1 -1
- package/dist/canvas/brushstroke.d.ts +1 -1
- package/dist/canvas/drawController.d.cts +19 -4
- package/dist/canvas/drawController.d.ts +19 -4
- package/dist/canvas/index.cjs +144 -105
- package/dist/canvas/index.js +46 -7
- package/dist/{chunk-TOID45I2.cjs → chunk-2WOGXEDX.cjs} +1 -1
- package/dist/{chunk-XORJ7UZO.cjs → chunk-3VHH6V67.cjs} +13 -12
- package/dist/{chunk-3C33YTNN.js → chunk-3XDSNIGF.js} +73 -6
- package/dist/chunk-62MFUHSI.cjs +802 -0
- package/dist/{chunk-R44Y3EFS.js → chunk-74ODPZLX.js} +17 -345
- package/dist/{chunk-GCVFEPJG.js → chunk-ACTHSQOI.js} +182 -0
- package/dist/chunk-ADMRNWR7.js +340 -0
- package/dist/{chunk-MVUQSK5J.cjs → chunk-B3G7BKUV.cjs} +111 -439
- package/dist/{chunk-DXYHQ2VN.js → chunk-BAZMCFVL.js} +1 -1
- package/dist/{chunk-VRK322ZC.cjs → chunk-BPJSI4NT.cjs} +2 -2
- package/dist/{chunk-RFJZGTHA.cjs → chunk-EU2ZZA6L.cjs} +400 -69
- package/dist/{chunk-XC6DPRYI.js → chunk-GSTSZPSR.js} +154 -949
- package/dist/{chunk-EZOJBP4D.js → chunk-HFY5LG5J.js} +1 -1
- package/dist/chunk-HVO6XCI4.js +802 -0
- package/dist/{chunk-YHDHFJUC.cjs → chunk-J5VQYK7T.cjs} +217 -1012
- package/dist/{chunk-XRXFVRGY.cjs → chunk-JBB3GDBB.cjs} +2483 -208
- package/dist/{chunk-ACFSFUQH.js → chunk-JL6YH5WD.js} +4 -0
- package/dist/{chunk-CIJBSUM5.js → chunk-KZI3YWKW.js} +353 -22
- package/dist/{chunk-4ODRXQRW.js → chunk-LETF75CA.js} +1 -1
- package/dist/{chunk-FQPUF2W2.cjs → chunk-NIBFKXMD.cjs} +217 -35
- package/dist/{chunk-AQZQWXEU.cjs → chunk-NPWWSCWT.cjs} +35 -35
- package/dist/{chunk-DOZ6F2K2.js → chunk-NSETJI74.js} +3 -2
- package/dist/{chunk-PE6YJMQT.cjs → chunk-PFHJS4HE.cjs} +20 -19
- package/dist/{chunk-7KNW3WXZ.cjs → chunk-QEVLRLUN.cjs} +63 -0
- package/dist/{chunk-LK4SXL3V.js → chunk-QNY7BDFP.js} +1 -1
- package/dist/{chunk-OTN6VB5S.cjs → chunk-RDFHWAHL.cjs} +5 -1
- package/dist/{chunk-PXDIAYB6.cjs → chunk-STLTOISW.cjs} +34 -214
- package/dist/{chunk-T2LDTEXK.js → chunk-UVTO3D4E.js} +2333 -58
- package/dist/{chunk-6JL2D5SG.js → chunk-VE6UKYQ2.js} +3 -2
- package/dist/{chunk-TXFWZ5ZJ.js → chunk-W6JDUXP3.js} +4 -184
- package/dist/{chunk-3SBLVGOM.cjs → chunk-YOVXQHA3.cjs} +23 -23
- package/dist/{chunk-WLUVZKVD.cjs → chunk-YXP6X3SY.cjs} +103 -36
- package/dist/chunk-YZWM6ZIP.cjs +340 -0
- package/dist/{chunk-472INMWH.js → chunk-ZA7L5YJB.js} +63 -0
- package/dist/commands/builtins.d.cts +12 -1
- package/dist/commands/builtins.d.ts +12 -1
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/image-editor/controller.d.cts +1 -1
- package/dist/image-editor/controller.d.ts +1 -1
- package/dist/image-editor/index.cjs +868 -864
- package/dist/image-editor/index.js +123 -119
- package/dist/paint/index.cjs +8 -6
- package/dist/paint/index.js +56 -54
- package/dist/paint-editor/brush-library-tools.d.cts +12 -2
- package/dist/paint-editor/brush-library-tools.d.ts +12 -2
- package/dist/paint-editor/brush-model.d.cts +29 -1
- package/dist/paint-editor/brush-model.d.ts +29 -1
- package/dist/paint-editor/brush-source-art.d.cts +32 -0
- package/dist/paint-editor/brush-source-art.d.ts +32 -0
- package/dist/paint-editor/controller.d.cts +11 -4
- package/dist/paint-editor/controller.d.ts +11 -4
- package/dist/paint-editor/dab-stroke.d.cts +2 -0
- package/dist/paint-editor/dab-stroke.d.ts +2 -0
- package/dist/paint-editor/engine.d.cts +11 -2
- package/dist/paint-editor/engine.d.ts +11 -2
- package/dist/paint-editor/index.cjs +967 -2335
- package/dist/paint-editor/index.d.cts +3 -1
- package/dist/paint-editor/index.d.ts +3 -1
- package/dist/paint-editor/index.js +394 -1762
- package/dist/paint-editor/path-samples.d.cts +2 -0
- package/dist/paint-editor/path-samples.d.ts +2 -0
- package/dist/paint-editor/presence.d.cts +20 -1
- package/dist/paint-editor/presence.d.ts +20 -1
- package/dist/paint-editor/stamp-tip.d.cts +8 -5
- package/dist/paint-editor/stamp-tip.d.ts +8 -5
- package/dist/paint-editor/thumbnails.d.cts +6 -0
- package/dist/paint-editor/thumbnails.d.ts +6 -0
- package/dist/paint-editor/tip-grain.d.cts +34 -0
- package/dist/paint-editor/tip-grain.d.ts +34 -0
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.js +9 -9
- package/dist/stickers/helpers.d.cts +2 -0
- package/dist/stickers/helpers.d.ts +2 -0
- package/dist/stickers/index.cjs +41 -35
- package/dist/stickers/index.js +22 -16
- package/dist/stickers/types.d.cts +4 -2
- package/dist/stickers/types.d.ts +4 -2
- package/dist/vector/backdrop.d.cts +13 -0
- package/dist/vector/backdrop.d.ts +13 -0
- package/dist/vector/brushstroke.d.cts +54 -7
- package/dist/vector/brushstroke.d.ts +54 -7
- package/dist/vector/brushstrokeMedia.d.cts +96 -0
- package/dist/vector/brushstrokeMedia.d.ts +96 -0
- package/dist/vector/controller.d.cts +17 -3
- package/dist/vector/controller.d.ts +17 -3
- package/dist/vector/index.cjs +1850 -1390
- package/dist/vector/index.d.cts +2 -0
- package/dist/vector/index.d.ts +2 -0
- package/dist/vector/index.js +520 -60
- package/dist/vector/render.d.cts +6 -0
- package/dist/vector/render.d.ts +6 -0
- package/dist/vector/types.d.cts +14 -0
- package/dist/vector/types.d.ts +14 -0
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +1 -0
- package/skills/pixerate-brushes/SKILL.md +37 -10
- package/skills/pixerate-brushes-design/SKILL.md +15 -5
- package/skills/pixerate-brushes-design/evals/port-to-vector.json +8 -8
- package/skills/pixerate-canvas/SKILL.md +11 -1
- package/skills/pixerate-image-editor/SKILL.md +19 -64
- package/skills/pixerate-image-editor/references/color-management.md +2 -1
- package/skills/pixerate-image-editor/references/free-transform.md +12 -0
- package/skills/pixerate-image-editor/references/layer-effects.md +10 -0
- package/skills/pixerate-image-editor/references/painting.md +17 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +1 -1
- package/skills/pixerate-image-editor/references/shapes-and-type.md +14 -0
- package/skills/pixerate-image-editor/references/smart-objects.md +10 -0
- package/skills/pixerate-paint-editor/SKILL.md +14 -4
- package/skills/pixerate-paint-editor/references/brush-facets.md +3 -1
- package/skills/pixerate-paint-editor/references/wet-media.md +9 -0
- package/skills/pixerate-paint-sketch-to-finish/SKILL.md +1 -0
- package/skills/pixerate-vector/SKILL.md +16 -6
- package/skills/pixerate-vector/references/best-practices.md +1 -0
- package/skills/pixerate-vector/references/commands.md +19 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkPFHJS4HEcjs = require('./chunk-PFHJS4HE.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -16,12 +16,20 @@ var _chunkPE6YJMQTcjs = require('./chunk-PE6YJMQT.cjs');
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
var _chunkEU2ZZA6Lcjs = require('./chunk-EU2ZZA6L.cjs');
|
|
20
28
|
|
|
21
29
|
// src/brushes/patch.ts
|
|
22
30
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
23
31
|
var copy = (v) => JSON.parse(JSON.stringify(v));
|
|
24
|
-
var FACETS =
|
|
32
|
+
var FACETS = _chunkEU2ZZA6Lcjs.BRUSH_JSON_SCHEMA.properties;
|
|
25
33
|
var BRUSH_PATCH_PROPERTIES = (() => {
|
|
26
34
|
const { id: _id, name: _name, ...rest } = FACETS;
|
|
27
35
|
const { required: _r, ...tip } = rest.tip;
|
|
@@ -53,17 +61,17 @@ function changedBrushPaths(a, b, path = "") {
|
|
|
53
61
|
// src/brushes/tools.ts
|
|
54
62
|
var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
55
63
|
var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
56
|
-
var FACETS2 =
|
|
64
|
+
var FACETS2 = _chunkEU2ZZA6Lcjs.BRUSH_JSON_SCHEMA.properties;
|
|
57
65
|
var ID = { type: "string", pattern: String(FACETS2.id.pattern), description: "Brush id from list_brush_presets (lowercase letters, digits and dashes)." };
|
|
58
66
|
var FACET_PROPS = BRUSH_PATCH_PROPERTIES;
|
|
59
|
-
var HOSTS = Object.keys(
|
|
67
|
+
var HOSTS = Object.keys(_chunkEU2ZZA6Lcjs.BRUSH_HOST_PROFILES);
|
|
60
68
|
var copy2 = (v) => JSON.parse(JSON.stringify(v));
|
|
61
69
|
var merge = mergeBrushPatch;
|
|
62
70
|
var changedPaths = changedBrushPaths;
|
|
63
71
|
function summary(entry, profile, withCheck) {
|
|
64
72
|
const b = entry.brush;
|
|
65
|
-
const engine =
|
|
66
|
-
const check = withCheck ?
|
|
73
|
+
const engine = _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, b);
|
|
74
|
+
const check = withCheck ? _chunkEU2ZZA6Lcjs.checkBrush.call(void 0, b, profile) : null;
|
|
67
75
|
return {
|
|
68
76
|
id: b.id,
|
|
69
77
|
name: b.name,
|
|
@@ -72,7 +80,7 @@ function summary(entry, profile, withCheck) {
|
|
|
72
80
|
...b.medium ? { medium: b.medium } : {},
|
|
73
81
|
...b.variety ? { variety: b.variety } : {},
|
|
74
82
|
...b.tool ? { tool: b.tool } : {},
|
|
75
|
-
category:
|
|
83
|
+
category: _chunkEU2ZZA6Lcjs.resolveCategory.call(void 0, b, engine),
|
|
76
84
|
engine,
|
|
77
85
|
tip: b.tip.shape,
|
|
78
86
|
...b.tip.size !== void 0 ? { size: b.tip.size } : {},
|
|
@@ -86,28 +94,35 @@ function summary(entry, profile, withCheck) {
|
|
|
86
94
|
var refusal = (check, host) => `${host.name} can't use this brush: ${check.issues.filter((i) => i.severity === "error").map((i) => `${i.facet}: ${i.reason} ${i.fix}`).join(" ")} (check_brush lists every issue; nothing was saved.)`;
|
|
87
95
|
var warnings = (check) => check.issues.filter((i) => i.severity === "warning");
|
|
88
96
|
function createBrushLibraryTools(library, options = {}) {
|
|
89
|
-
const profile = _nullishCoalesce(options.profile, () => (
|
|
97
|
+
const profile = _nullishCoalesce(options.profile, () => ( _chunkEU2ZZA6Lcjs.PAINT_PROFILE));
|
|
90
98
|
const hostOf = (id) => {
|
|
91
99
|
if (id === void 0) return profile;
|
|
92
|
-
const p =
|
|
93
|
-
if (!p) throw new (0,
|
|
100
|
+
const p = _chunkEU2ZZA6Lcjs.BRUSH_HOST_PROFILES[id];
|
|
101
|
+
if (!p) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
|
|
94
102
|
return p;
|
|
95
103
|
};
|
|
96
104
|
const entry = async (id) => {
|
|
97
105
|
const found = await library.get(id);
|
|
98
106
|
if (found) return found;
|
|
99
107
|
const ids = (await library.list()).map((e) => e.brush.id);
|
|
100
|
-
throw new (0,
|
|
108
|
+
throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkEU2ZZA6Lcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
|
|
101
109
|
};
|
|
102
110
|
const checkFor = async (brush, p) => {
|
|
103
|
-
const check2 =
|
|
104
|
-
const provider = _optionalChain([options, 'access', _9 => _9.stickers, 'optionalCall', _10 => _10()]);
|
|
105
|
-
if (!provider || brush.tip.shape !== "stamp") return check2;
|
|
111
|
+
const check2 = _chunkEU2ZZA6Lcjs.checkBrush.call(void 0, brush, p);
|
|
106
112
|
const issues = [...check2.issues];
|
|
113
|
+
const refs = [...(_nullishCoalesce(brush.tip.stamps, () => ( []))).map((r) => ["tip.stamps", r]), ...brush.tip.grain ? [["tip.grain.source", brush.tip.grain.source]] : []];
|
|
114
|
+
for (const [facet, ref] of refs) {
|
|
115
|
+
const id = _chunkEU2ZZA6Lcjs.brushSourceIdOf.call(void 0, ref);
|
|
116
|
+
if (id === null || await library.getSource(id)) continue;
|
|
117
|
+
const ids = (await library.listSources()).map((x) => x.id);
|
|
118
|
+
issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${_chunkEU2ZZA6Lcjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
|
|
119
|
+
}
|
|
120
|
+
const provider = _optionalChain([options, 'access', _9 => _9.stickers, 'optionalCall', _10 => _10()]);
|
|
121
|
+
if (!provider || brush.tip.shape !== "stamp") return { ok: !issues.some((i) => i.severity === "error"), issues };
|
|
107
122
|
for (const ref of _nullishCoalesce(brush.tip.stamps, () => ( []))) {
|
|
108
|
-
if (ref.startsWith("editor:")) continue;
|
|
123
|
+
if (ref.startsWith("editor:") || _chunkEU2ZZA6Lcjs.isBrushSourceRef.call(void 0, ref)) continue;
|
|
109
124
|
try {
|
|
110
|
-
await
|
|
125
|
+
await _chunkPFHJS4HEcjs.describeStickerRef.call(void 0, provider, ref);
|
|
111
126
|
} catch (e) {
|
|
112
127
|
issues.push({ facet: "tip.stamps", severity: "error", reason: `${p.name} can't load sticker "${ref}": ${e.message}`, fix: "Use a ref from find_stickers, or an editor stamp (editor:star, editor:dot\u2026)." });
|
|
113
128
|
}
|
|
@@ -118,12 +133,12 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
118
133
|
const problems = [];
|
|
119
134
|
let brush;
|
|
120
135
|
try {
|
|
121
|
-
brush =
|
|
136
|
+
brush = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, raw, problems);
|
|
122
137
|
} catch (e) {
|
|
123
|
-
throw new (0,
|
|
138
|
+
throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", e.message);
|
|
124
139
|
}
|
|
125
|
-
const check2 =
|
|
126
|
-
if (!check2.ok) throw new (0,
|
|
140
|
+
const check2 = _chunkEU2ZZA6Lcjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
|
|
141
|
+
if (!check2.ok) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", refusal(check2, profile));
|
|
127
142
|
const saved = await library.save(brush, { overwrite });
|
|
128
143
|
return { ...saved, problems, check: check2 };
|
|
129
144
|
};
|
|
@@ -134,10 +149,10 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
134
149
|
inputSchema: {
|
|
135
150
|
type: "object",
|
|
136
151
|
properties: {
|
|
137
|
-
kind: { type: "string", enum: [...
|
|
138
|
-
medium: { type: "string", enum: [...
|
|
152
|
+
kind: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
|
|
153
|
+
medium: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
|
|
139
154
|
variety: { type: "string", maxLength: 40, description: "This variety (oil, watercolor, pencil, highlighter\u2026)." },
|
|
140
|
-
tool: { type: "string", enum: [...
|
|
155
|
+
tool: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_TOOLS], description: "Tools that do this." },
|
|
141
156
|
tag: { type: "string", maxLength: 40, description: "Brushes with this tag." },
|
|
142
157
|
text: { type: "string", maxLength: 200, description: "Words in the id, name, description, variety or tags (each word must match the start of one)." },
|
|
143
158
|
source: { type: "string", enum: ["all", "builtin", "user"], description: "all (default), builtin presets only, or user (saved) brushes only." },
|
|
@@ -164,8 +179,8 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
164
179
|
annotations: { title: "Describe a brush", ...READ },
|
|
165
180
|
handler: async ({ id }) => {
|
|
166
181
|
const e = await entry(id);
|
|
167
|
-
const engine =
|
|
168
|
-
return { brush: e.brush, builtin: e.builtin, engine, category:
|
|
182
|
+
const engine = _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, e.brush);
|
|
183
|
+
return { brush: e.brush, builtin: e.builtin, engine, category: _chunkEU2ZZA6Lcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
|
|
169
184
|
}
|
|
170
185
|
};
|
|
171
186
|
const check = {
|
|
@@ -183,20 +198,20 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
183
198
|
},
|
|
184
199
|
annotations: { title: "Check a brush for a host", ...READ },
|
|
185
200
|
handler: async ({ id, brush, host }) => {
|
|
186
|
-
if (id === void 0 === (brush === void 0)) throw new (0,
|
|
201
|
+
if (id === void 0 === (brush === void 0)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
|
|
187
202
|
const p = hostOf(host);
|
|
188
203
|
let b;
|
|
189
204
|
const problems = [];
|
|
190
205
|
if (id !== void 0) b = (await entry(id)).brush;
|
|
191
206
|
else {
|
|
192
207
|
try {
|
|
193
|
-
b =
|
|
208
|
+
b = _chunkEU2ZZA6Lcjs.normalizeBrushSpec.call(void 0, brush, problems);
|
|
194
209
|
} catch (e) {
|
|
195
|
-
throw new (0,
|
|
210
|
+
throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("invalid", e.message);
|
|
196
211
|
}
|
|
197
212
|
}
|
|
198
213
|
const result = await checkFor(b, p);
|
|
199
|
-
return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded:
|
|
214
|
+
return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkEU2ZZA6Lcjs.degrade.call(void 0, b, p) } : {} };
|
|
200
215
|
}
|
|
201
216
|
};
|
|
202
217
|
const exportTool = {
|
|
@@ -207,7 +222,34 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
207
222
|
annotations: { title: "Export brushes", ...READ },
|
|
208
223
|
handler: async ({ ids }) => ({ file: await library.exportFile(ids) })
|
|
209
224
|
};
|
|
210
|
-
const
|
|
225
|
+
const listSources = {
|
|
226
|
+
name: "list_brush_sources",
|
|
227
|
+
title: "List brush image sources",
|
|
228
|
+
description: "Lists the image sources in the brush library: the images image tips and image grain are made from. Returns each source's id, ref (source:<id>, for tip.stamps of a stamp tip or tip.grain.source in create_brush / update_brush), name, width and height in px, licence and origin when it has them, and usedBy (the saved brushes that name it), plus total. Built-in grain patterns need no source. Changes nothing.",
|
|
229
|
+
inputSchema: {
|
|
230
|
+
type: "object",
|
|
231
|
+
properties: {
|
|
232
|
+
text: { type: "string", maxLength: 200, description: "Words in the id, name or origin (each word must match the start of one)." },
|
|
233
|
+
offset: { type: "integer", minimum: 0, description: "Skip this many (default 0)." },
|
|
234
|
+
limit: { type: "integer", minimum: 1, maximum: 200, description: "At most this many (default 100)." }
|
|
235
|
+
},
|
|
236
|
+
additionalProperties: false
|
|
237
|
+
},
|
|
238
|
+
annotations: { title: "List brush image sources", ...READ },
|
|
239
|
+
handler: async ({ text, offset, limit }) => {
|
|
240
|
+
const brushes = (await library.list({ source: "user" })).map((e) => e.brush);
|
|
241
|
+
const wordsOf = (v) => v.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
|
|
242
|
+
const want = typeof text === "string" ? wordsOf(text) : [];
|
|
243
|
+
const found = (await library.listSources()).filter((x) => {
|
|
244
|
+
const have = wordsOf([x.id, x.name, _nullishCoalesce(x.origin, () => ( ""))].join(" "));
|
|
245
|
+
return want.every((w) => have.some((h) => h.startsWith(w)));
|
|
246
|
+
});
|
|
247
|
+
const start = _nullishCoalesce(offset, () => ( 0));
|
|
248
|
+
const page = found.slice(start, start + (_nullishCoalesce(limit, () => ( 100))));
|
|
249
|
+
return { total: found.length, sources: page.map((x) => ({ ..._chunkEU2ZZA6Lcjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunkEU2ZZA6Lcjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const tools = [list, describe, check, exportTool, listSources];
|
|
211
253
|
if (options.renderPreview) {
|
|
212
254
|
const render = options.renderPreview;
|
|
213
255
|
tools.push({
|
|
@@ -255,12 +297,12 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
255
297
|
},
|
|
256
298
|
annotations: { title: "Save a new brush", ...WRITE },
|
|
257
299
|
handler: async ({ basedOn, ...spec }) => {
|
|
258
|
-
if (library.isBuiltin(spec.id)) throw new (0,
|
|
259
|
-
if (await library.get(spec.id)) throw new (0,
|
|
300
|
+
if (library.isBuiltin(spec.id)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
|
|
301
|
+
if (await library.get(spec.id)) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
|
|
260
302
|
const base = basedOn !== void 0 ? (await entry(basedOn)).brush : void 0;
|
|
261
303
|
const raw = base ? merge(base, spec) : spec;
|
|
262
304
|
const saved = await store(raw, false);
|
|
263
|
-
return { id: saved.brush.id, brush: saved.brush, engine:
|
|
305
|
+
return { id: saved.brush.id, brush: saved.brush, engine: _chunkEU2ZZA6Lcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
|
|
264
306
|
}
|
|
265
307
|
},
|
|
266
308
|
{
|
|
@@ -281,13 +323,38 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
281
323
|
annotations: { title: "Update a brush", ...WRITE, idempotentHint: true },
|
|
282
324
|
handler: async ({ id, unset, ...patch }) => {
|
|
283
325
|
const e = await entry(id);
|
|
284
|
-
if (e.builtin) throw new (0,
|
|
326
|
+
if (e.builtin) throw new (0, _chunkEU2ZZA6Lcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
|
|
285
327
|
const base = copy2(e.brush);
|
|
286
328
|
for (const k of _nullishCoalesce(unset, () => ( []))) delete base[k];
|
|
287
329
|
const saved = await store(merge(base, { ...patch, id }), true, e.brush);
|
|
288
330
|
return { id, brush: saved.brush, changed: changedPaths(e.brush, saved.brush), problems: saved.problems, warnings: warnings(saved.check), ...saved.check.kept.length ? { kept: saved.check.kept } : {} };
|
|
289
331
|
}
|
|
290
332
|
},
|
|
333
|
+
{
|
|
334
|
+
name: "add_brush_source",
|
|
335
|
+
title: "Add a brush image source",
|
|
336
|
+
description: `Adds an image to the brush library as a source for image tips and image grain (as Procreate's shape and grain sources). The image is a PNG data: URL; the marks are read from its transparency, its dark parts (a scan of marks on paper) or its light parts (white on black), as channel says, and kept as a grey mask at most ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_SIZE} px on a side. Returns id, ref (source:<id>), the stored source's width and height, problems (the channel auto picked, scaling) and replaced. Then make the brush: create_brush or update_brush with tip { shape: "stamp", stamps: [ref] } for an image tip, or tip.grain { source: ref } for grain. A taken id is refused unless overwrite.`,
|
|
337
|
+
inputSchema: {
|
|
338
|
+
type: "object",
|
|
339
|
+
properties: {
|
|
340
|
+
name: { type: "string", minLength: 1, maxLength: 80, description: 'Display name, e.g. "Charcoal scan".' },
|
|
341
|
+
image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunkEU2ZZA6Lcjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
|
|
342
|
+
id: { type: "string", pattern: String(FACETS2.id.pattern), description: "The source id (default: from the name, made unique): lowercase letters, digits and dashes." },
|
|
343
|
+
channel: { type: "string", enum: [..._chunkEU2ZZA6Lcjs.BRUSH_SOURCE_CHANNELS], description: "Where the marks are: auto (default: the transparency when the image has any, else the dark parts), alpha, darkness (dark marks on light paper) or lightness (light marks on black)." },
|
|
344
|
+
invert: { type: "boolean", description: "Swap painted and empty parts (default false)." },
|
|
345
|
+
licence: { type: "string", maxLength: 2e3, description: "The licence or terms the image came with, kept with the source." },
|
|
346
|
+
origin: { type: "string", maxLength: 200, description: "Where it came from: a file name, a pack or a URL." },
|
|
347
|
+
overwrite: { type: "boolean", description: "Replace the image of a source with the same id (default false); brushes using it change with it." }
|
|
348
|
+
},
|
|
349
|
+
required: ["name", "image"],
|
|
350
|
+
additionalProperties: false
|
|
351
|
+
},
|
|
352
|
+
annotations: { title: "Add a brush image source", ...WRITE },
|
|
353
|
+
handler: async ({ overwrite, ...input }) => {
|
|
354
|
+
const r = await library.addSource(input, { overwrite: !!overwrite });
|
|
355
|
+
return { id: r.source.id, ref: _chunkEU2ZZA6Lcjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
|
|
356
|
+
}
|
|
357
|
+
},
|
|
291
358
|
{
|
|
292
359
|
name: "duplicate_brush",
|
|
293
360
|
title: "Duplicate a brush",
|
|
@@ -340,7 +407,7 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
340
407
|
return tools;
|
|
341
408
|
}
|
|
342
409
|
function createBrushLibraryToolProvider(library, options = {}) {
|
|
343
|
-
const profile = _nullishCoalesce(options.profile, () => (
|
|
410
|
+
const profile = _nullishCoalesce(options.profile, () => ( _chunkEU2ZZA6Lcjs.PAINT_PROFILE));
|
|
344
411
|
const tools = createBrushLibraryTools(library, options);
|
|
345
412
|
return {
|
|
346
413
|
id: _nullishCoalesce(options.id, () => ( "brushes")),
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/image-editor/layers/vector-raster.ts
|
|
2
|
+
var FLATNESS = 0.01;
|
|
3
|
+
function flattenPath(path, tolerance = FLATNESS) {
|
|
4
|
+
const out = [];
|
|
5
|
+
let pts = [];
|
|
6
|
+
let cx = 0;
|
|
7
|
+
let cy = 0;
|
|
8
|
+
let sx = 0;
|
|
9
|
+
let sy = 0;
|
|
10
|
+
const flush = () => {
|
|
11
|
+
if (pts.length >= 6) out.push(Float64Array.from(pts));
|
|
12
|
+
pts = [];
|
|
13
|
+
};
|
|
14
|
+
const steps = (dd, degree) => Math.max(1, Math.min(1024, Math.ceil(Math.sqrt(degree * (degree - 1) * dd / (8 * tolerance)))));
|
|
15
|
+
for (const c of path) {
|
|
16
|
+
switch (c.type) {
|
|
17
|
+
case "M":
|
|
18
|
+
flush();
|
|
19
|
+
cx = sx = c.x;
|
|
20
|
+
cy = sy = c.y;
|
|
21
|
+
pts.push(cx, cy);
|
|
22
|
+
break;
|
|
23
|
+
case "L":
|
|
24
|
+
if (!pts.length) pts.push(cx, cy);
|
|
25
|
+
cx = c.x;
|
|
26
|
+
cy = c.y;
|
|
27
|
+
pts.push(cx, cy);
|
|
28
|
+
break;
|
|
29
|
+
case "Q": {
|
|
30
|
+
if (!pts.length) pts.push(cx, cy);
|
|
31
|
+
const n = steps(Math.hypot(cx - 2 * c.x1 + c.x, cy - 2 * c.y1 + c.y), 2);
|
|
32
|
+
for (let k = 1; k <= n; k++) {
|
|
33
|
+
const t = k / n;
|
|
34
|
+
const u = 1 - t;
|
|
35
|
+
pts.push(u * u * cx + 2 * u * t * c.x1 + t * t * c.x, u * u * cy + 2 * u * t * c.y1 + t * t * c.y);
|
|
36
|
+
}
|
|
37
|
+
cx = c.x;
|
|
38
|
+
cy = c.y;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "C": {
|
|
42
|
+
if (!pts.length) pts.push(cx, cy);
|
|
43
|
+
const dd = Math.max(Math.hypot(cx - 2 * c.x1 + c.x2, cy - 2 * c.y1 + c.y2), Math.hypot(c.x1 - 2 * c.x2 + c.x, c.y1 - 2 * c.y2 + c.y));
|
|
44
|
+
const n = steps(dd, 3);
|
|
45
|
+
for (let k = 1; k <= n; k++) {
|
|
46
|
+
const t = k / n;
|
|
47
|
+
const u = 1 - t;
|
|
48
|
+
const a = u * u * u;
|
|
49
|
+
const b = 3 * u * u * t;
|
|
50
|
+
const d = 3 * u * t * t;
|
|
51
|
+
const e = t * t * t;
|
|
52
|
+
pts.push(a * cx + b * c.x1 + d * c.x2 + e * c.x, a * cy + b * c.y1 + d * c.y2 + e * c.y);
|
|
53
|
+
}
|
|
54
|
+
cx = c.x;
|
|
55
|
+
cy = c.y;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case "Z":
|
|
59
|
+
flush();
|
|
60
|
+
cx = sx;
|
|
61
|
+
cy = sy;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
flush();
|
|
66
|
+
return out.filter((p) => p.every(Number.isFinite));
|
|
67
|
+
}
|
|
68
|
+
function flatBounds(flat) {
|
|
69
|
+
let x0 = Infinity;
|
|
70
|
+
let y0 = Infinity;
|
|
71
|
+
let x1 = -Infinity;
|
|
72
|
+
let y1 = -Infinity;
|
|
73
|
+
for (const p of flat) {
|
|
74
|
+
for (let i = 0; i < p.length; i += 2) {
|
|
75
|
+
if (p[i] < x0) x0 = p[i];
|
|
76
|
+
if (p[i] > x1) x1 = p[i];
|
|
77
|
+
if (p[i + 1] < y0) y0 = p[i + 1];
|
|
78
|
+
if (p[i + 1] > y1) y1 = p[i + 1];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (x0 === Infinity) return null;
|
|
82
|
+
const x = Math.floor(x0);
|
|
83
|
+
const y = Math.floor(y0);
|
|
84
|
+
return { x, y, width: Math.ceil(x1) - x, height: Math.ceil(y1) - y };
|
|
85
|
+
}
|
|
86
|
+
function drawLine(a, w, h, x0, y0, x1, y1) {
|
|
87
|
+
if (y0 === y1) return;
|
|
88
|
+
let dir = 1;
|
|
89
|
+
if (y0 > y1) {
|
|
90
|
+
dir = -1;
|
|
91
|
+
let t = x0;
|
|
92
|
+
x0 = x1;
|
|
93
|
+
x1 = t;
|
|
94
|
+
t = y0;
|
|
95
|
+
y0 = y1;
|
|
96
|
+
y1 = t;
|
|
97
|
+
}
|
|
98
|
+
if (y1 <= 0 || y0 >= h) return;
|
|
99
|
+
const dxdy = (x1 - x0) / (y1 - y0);
|
|
100
|
+
let x = x0;
|
|
101
|
+
if (y0 < 0) x -= y0 * dxdy;
|
|
102
|
+
const rowStart = Math.max(0, Math.floor(y0));
|
|
103
|
+
const rowEnd = Math.min(h, Math.ceil(y1));
|
|
104
|
+
for (let y = rowStart; y < rowEnd; y++) {
|
|
105
|
+
const line = y * w;
|
|
106
|
+
const dy = Math.min(y + 1, y1) - Math.max(y, y0);
|
|
107
|
+
const xnext = x + dxdy * dy;
|
|
108
|
+
const d = dy * dir;
|
|
109
|
+
const xa = x < xnext ? x : xnext;
|
|
110
|
+
const xb = x < xnext ? xnext : x;
|
|
111
|
+
const xaFloor = Math.floor(xa);
|
|
112
|
+
const xai = xaFloor;
|
|
113
|
+
const xbCeil = Math.ceil(xb);
|
|
114
|
+
const xbi = xbCeil;
|
|
115
|
+
if (xbi <= xai + 1) {
|
|
116
|
+
const xmf = 0.5 * (x + xnext) - xaFloor;
|
|
117
|
+
a[line + xai] += d - d * xmf;
|
|
118
|
+
a[line + xai + 1] += d * xmf;
|
|
119
|
+
} else {
|
|
120
|
+
const s = 1 / (xb - xa);
|
|
121
|
+
const xaf = xa - xaFloor;
|
|
122
|
+
const a0 = 0.5 * s * (1 - xaf) * (1 - xaf);
|
|
123
|
+
const xbf = xb - xbCeil + 1;
|
|
124
|
+
const am = 0.5 * s * xbf * xbf;
|
|
125
|
+
a[line + xai] += d * a0;
|
|
126
|
+
if (xbi === xai + 2) a[line + xai + 1] += d * (1 - a0 - am);
|
|
127
|
+
else {
|
|
128
|
+
const a1 = s * (1.5 - xaf);
|
|
129
|
+
a[line + xai + 1] += d * (a1 - a0);
|
|
130
|
+
for (let xi = xai + 2; xi < xbi - 1; xi++) a[line + xi] += d * s;
|
|
131
|
+
const a2 = a1 + (xbi - xai - 3) * s;
|
|
132
|
+
a[line + xbi - 1] += d * (1 - a2 - am);
|
|
133
|
+
}
|
|
134
|
+
a[line + xbi] += d * am;
|
|
135
|
+
}
|
|
136
|
+
x = xnext;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function drawClippedLine(a, w, h, x0, y0, x1, y1) {
|
|
140
|
+
if (y0 === y1) return;
|
|
141
|
+
if (y0 <= 0 && y1 <= 0 || y0 >= h && y1 >= h) return;
|
|
142
|
+
if (x0 >= 0 && x0 <= w && x1 >= 0 && x1 <= w) return drawLine(a, w, h, x0, y0, x1, y1);
|
|
143
|
+
const ts = [0, 1];
|
|
144
|
+
const dx = x1 - x0;
|
|
145
|
+
if (dx !== 0) {
|
|
146
|
+
for (const edge of [0, w]) {
|
|
147
|
+
const t = (edge - x0) / dx;
|
|
148
|
+
if (t > 0 && t < 1) ts.push(t);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
ts.sort((p, q) => p - q);
|
|
152
|
+
const clamp = (v) => v < 0 ? 0 : v > w ? w : v;
|
|
153
|
+
for (let i = 0; i + 1 < ts.length; i++) {
|
|
154
|
+
const ta = ts[i];
|
|
155
|
+
const tb = ts[i + 1];
|
|
156
|
+
drawLine(a, w, h, clamp(x0 + dx * ta), y0 + (y1 - y0) * ta, clamp(x0 + dx * tb), y0 + (y1 - y0) * tb);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function ruleCoverage(v, rule) {
|
|
160
|
+
const m = v < 0 ? -v : v;
|
|
161
|
+
if (rule === "nonzero") return m >= 1 ? 1 : m;
|
|
162
|
+
const f = m % 2;
|
|
163
|
+
return f > 1 ? 2 - f : f;
|
|
164
|
+
}
|
|
165
|
+
function rasterizeCoverage(flat, rect, rule = "nonzero") {
|
|
166
|
+
const w = rect.width;
|
|
167
|
+
const h = rect.height;
|
|
168
|
+
if (w <= 0 || h <= 0 || !flat.length) return null;
|
|
169
|
+
const a = new Float64Array(w * h + w + 4);
|
|
170
|
+
const ox = rect.x;
|
|
171
|
+
const oy = rect.y;
|
|
172
|
+
let touched = false;
|
|
173
|
+
for (const p of flat) {
|
|
174
|
+
const n = p.length;
|
|
175
|
+
for (let i = 0; i < n; i += 2) {
|
|
176
|
+
const j = i + 2 < n ? i + 2 : 0;
|
|
177
|
+
const ya = p[i + 1] - oy;
|
|
178
|
+
const yb = p[j + 1] - oy;
|
|
179
|
+
if (ya <= 0 && yb <= 0 || ya >= h && yb >= h || ya === yb) continue;
|
|
180
|
+
drawClippedLine(a, w, h, p[i] - ox, ya, p[j] - ox, yb);
|
|
181
|
+
touched = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!touched) return null;
|
|
185
|
+
const out = new Float32Array(w * h);
|
|
186
|
+
let acc = 0;
|
|
187
|
+
let any = false;
|
|
188
|
+
for (let i = 0; i < out.length; i++) {
|
|
189
|
+
acc += a[i];
|
|
190
|
+
const c = ruleCoverage(acc, rule);
|
|
191
|
+
if (c > 1e-6) {
|
|
192
|
+
out[i] = c;
|
|
193
|
+
any = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return any ? out : null;
|
|
197
|
+
}
|
|
198
|
+
var SUB_ROWS = 16;
|
|
199
|
+
function rasterizeCoverageSampled(flat, rect, rule = "nonzero") {
|
|
200
|
+
const w = rect.width;
|
|
201
|
+
const h = rect.height;
|
|
202
|
+
if (w <= 0 || h <= 0 || !flat.length) return null;
|
|
203
|
+
let n = 0;
|
|
204
|
+
for (const p of flat) n += p.length >> 1;
|
|
205
|
+
const ey0 = new Float64Array(n);
|
|
206
|
+
const ey1 = new Float64Array(n);
|
|
207
|
+
const ex0 = new Float64Array(n);
|
|
208
|
+
const eslope = new Float64Array(n);
|
|
209
|
+
const edir = new Int8Array(n);
|
|
210
|
+
let count = 0;
|
|
211
|
+
for (const p of flat) {
|
|
212
|
+
const len = p.length;
|
|
213
|
+
for (let i = 0; i < len; i += 2) {
|
|
214
|
+
const j = i + 2 < len ? i + 2 : 0;
|
|
215
|
+
let xa = p[i] - rect.x;
|
|
216
|
+
let ya = p[i + 1] - rect.y;
|
|
217
|
+
let xb = p[j] - rect.x;
|
|
218
|
+
let yb = p[j + 1] - rect.y;
|
|
219
|
+
if (ya === yb) continue;
|
|
220
|
+
let dir = 1;
|
|
221
|
+
if (ya > yb) {
|
|
222
|
+
dir = -1;
|
|
223
|
+
let t = xa;
|
|
224
|
+
xa = xb;
|
|
225
|
+
xb = t;
|
|
226
|
+
t = ya;
|
|
227
|
+
ya = yb;
|
|
228
|
+
yb = t;
|
|
229
|
+
}
|
|
230
|
+
if (yb <= 0 || ya >= h) continue;
|
|
231
|
+
ey0[count] = ya;
|
|
232
|
+
ey1[count] = yb;
|
|
233
|
+
ex0[count] = xa;
|
|
234
|
+
eslope[count] = (xb - xa) / (yb - ya);
|
|
235
|
+
edir[count] = dir;
|
|
236
|
+
count++;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (!count) return null;
|
|
240
|
+
const order = Array.from({ length: count }, (_, i) => i).sort((a, b) => ey0[a] - ey0[b]);
|
|
241
|
+
const out = new Float32Array(w * h);
|
|
242
|
+
const diff = new Float32Array(w + 1);
|
|
243
|
+
let active = [];
|
|
244
|
+
let next = 0;
|
|
245
|
+
const xs = [];
|
|
246
|
+
const ds = [];
|
|
247
|
+
const idx = [];
|
|
248
|
+
const f = 1 / SUB_ROWS;
|
|
249
|
+
let any = false;
|
|
250
|
+
const firstRow = Math.max(0, Math.floor(ey0[order[0]]));
|
|
251
|
+
for (let y = firstRow; y < h; y++) {
|
|
252
|
+
if (next >= count && !active.length) break;
|
|
253
|
+
const row = y * w;
|
|
254
|
+
let rowTouched = false;
|
|
255
|
+
for (let s = 0; s < SUB_ROWS; s++) {
|
|
256
|
+
const sy = y + (s + 0.5) * f;
|
|
257
|
+
while (next < count && ey0[order[next]] <= sy) active.push(order[next++]);
|
|
258
|
+
if (!active.length) continue;
|
|
259
|
+
active = active.filter((e) => ey1[e] > sy);
|
|
260
|
+
xs.length = 0;
|
|
261
|
+
ds.length = 0;
|
|
262
|
+
idx.length = 0;
|
|
263
|
+
for (const e of active) {
|
|
264
|
+
if (ey0[e] > sy) continue;
|
|
265
|
+
idx.push(xs.length);
|
|
266
|
+
xs.push(ex0[e] + (sy - ey0[e]) * eslope[e]);
|
|
267
|
+
ds.push(edir[e]);
|
|
268
|
+
}
|
|
269
|
+
if (xs.length < 2) continue;
|
|
270
|
+
idx.sort((a, b) => xs[a] - xs[b]);
|
|
271
|
+
let wind = 0;
|
|
272
|
+
for (let k = 0; k + 1 < idx.length; k++) {
|
|
273
|
+
wind += ds[idx[k]];
|
|
274
|
+
const inside = rule === "nonzero" ? wind !== 0 : (wind & 1) !== 0;
|
|
275
|
+
if (!inside) continue;
|
|
276
|
+
let xa = xs[idx[k]];
|
|
277
|
+
let xb = xs[idx[k + 1]];
|
|
278
|
+
if (xb <= 0 || xa >= w || xb <= xa) continue;
|
|
279
|
+
if (xa < 0) xa = 0;
|
|
280
|
+
if (xb > w) xb = w;
|
|
281
|
+
const ia = Math.floor(xa);
|
|
282
|
+
const ib = Math.floor(xb);
|
|
283
|
+
rowTouched = true;
|
|
284
|
+
if (ia === ib) {
|
|
285
|
+
out[row + ia] += (xb - xa) * f;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
out[row + ia] += (ia + 1 - xa) * f;
|
|
289
|
+
diff[ia + 1] += f;
|
|
290
|
+
diff[ib] -= f;
|
|
291
|
+
if (ib < w) out[row + ib] += (xb - ib) * f;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (!rowTouched) continue;
|
|
295
|
+
let run = 0;
|
|
296
|
+
for (let x = 0; x < w; x++) {
|
|
297
|
+
run += diff[x];
|
|
298
|
+
diff[x] = 0;
|
|
299
|
+
const v = out[row + x] + run;
|
|
300
|
+
out[row + x] = v > 1 ? 1 : v < 1e-6 ? 0 : v;
|
|
301
|
+
if (out[row + x] > 0) any = true;
|
|
302
|
+
}
|
|
303
|
+
diff[w] = 0;
|
|
304
|
+
}
|
|
305
|
+
return any ? out : null;
|
|
306
|
+
}
|
|
307
|
+
function combineCoverage(a, b, op, n) {
|
|
308
|
+
if (op === "combine") {
|
|
309
|
+
if (!a) return b;
|
|
310
|
+
if (!b) return a;
|
|
311
|
+
const out2 = new Float32Array(n);
|
|
312
|
+
for (let i = 0; i < n; i++) out2[i] = a[i] + b[i] - a[i] * b[i];
|
|
313
|
+
return out2;
|
|
314
|
+
}
|
|
315
|
+
if (op === "subtract") {
|
|
316
|
+
if (!a || !b) return a;
|
|
317
|
+
const out2 = new Float32Array(n);
|
|
318
|
+
for (let i = 0; i < n; i++) out2[i] = a[i] * (1 - b[i]);
|
|
319
|
+
return out2;
|
|
320
|
+
}
|
|
321
|
+
if (op === "intersect") {
|
|
322
|
+
if (!a || !b) return null;
|
|
323
|
+
const out2 = new Float32Array(n);
|
|
324
|
+
for (let i = 0; i < n; i++) out2[i] = a[i] * b[i];
|
|
325
|
+
return out2;
|
|
326
|
+
}
|
|
327
|
+
if (!a) return b;
|
|
328
|
+
if (!b) return a;
|
|
329
|
+
const out = new Float32Array(n);
|
|
330
|
+
for (let i = 0; i < n; i++) out[i] = a[i] + b[i] - 2 * a[i] * b[i];
|
|
331
|
+
return out;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
exports.flattenPath = flattenPath; exports.flatBounds = flatBounds; exports.rasterizeCoverage = rasterizeCoverage; exports.rasterizeCoverageSampled = rasterizeCoverageSampled; exports.combineCoverage = combineCoverage;
|