@pixerate/editor 0.120.0 → 0.122.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.
Files changed (64) hide show
  1. package/THIRD_PARTY_NOTICES.md +1 -1
  2. package/dist/{chunk-HTAFDTNR.cjs → chunk-4PUPGALM.cjs} +251 -156
  3. package/dist/chunk-4PUPGALM.cjs.map +1 -0
  4. package/dist/{chunk-N3467VD6.js → chunk-7QN76ESJ.js} +1 -179
  5. package/dist/chunk-7QN76ESJ.js.map +1 -0
  6. package/dist/{chunk-UMVW2Q66.js → chunk-CLTTLLWA.js} +1090 -982
  7. package/dist/chunk-CLTTLLWA.js.map +1 -0
  8. package/dist/{chunk-EJVDBITD.cjs → chunk-DCLJNVZS.cjs} +2 -180
  9. package/dist/chunk-DCLJNVZS.cjs.map +1 -0
  10. package/dist/{chunk-WMRIG4XQ.cjs → chunk-DFFBJV3U.cjs} +1855 -1747
  11. package/dist/chunk-DFFBJV3U.cjs.map +1 -0
  12. package/dist/chunk-GX332W2C.js +181 -0
  13. package/dist/chunk-GX332W2C.js.map +1 -0
  14. package/dist/{chunk-BOWUU4LJ.js → chunk-IX3YKUVK.js} +105 -10
  15. package/dist/chunk-IX3YKUVK.js.map +1 -0
  16. package/dist/{chunk-TS5IEUW6.cjs → chunk-K7V27T72.cjs} +178 -3
  17. package/dist/chunk-K7V27T72.cjs.map +1 -0
  18. package/dist/chunk-MUUXNRU4.cjs +181 -0
  19. package/dist/chunk-MUUXNRU4.cjs.map +1 -0
  20. package/dist/{chunk-YHW26LS2.js → chunk-ZZPGTNXJ.js} +177 -2
  21. package/dist/chunk-ZZPGTNXJ.js.map +1 -0
  22. package/dist/{render-B05K68_h.d.ts → deep-DLwKZDFr.d.ts} +143 -134
  23. package/dist/{render-DnAbIKcs.d.cts → deep-QS3ppbMX.d.cts} +143 -134
  24. package/dist/{export-D2D8hb_u.d.ts → export-VmTofKIk.d.ts} +11 -4
  25. package/dist/{export-fP2hZYjm.d.cts → export-jKKj8Fg8.d.cts} +11 -4
  26. package/dist/image-editor/index.cjs +760 -734
  27. package/dist/image-editor/index.cjs.map +1 -1
  28. package/dist/image-editor/index.d.cts +18 -6
  29. package/dist/image-editor/index.d.ts +18 -6
  30. package/dist/image-editor/index.js +37 -11
  31. package/dist/image-editor/index.js.map +1 -1
  32. package/dist/paint/index.cjs +22 -2
  33. package/dist/paint/index.cjs.map +1 -1
  34. package/dist/paint/index.d.cts +159 -1
  35. package/dist/paint/index.d.ts +159 -1
  36. package/dist/paint/index.js +21 -1
  37. package/dist/paint-editor/index.cjs +95 -94
  38. package/dist/paint-editor/index.cjs.map +1 -1
  39. package/dist/paint-editor/index.d.cts +2 -2
  40. package/dist/paint-editor/index.d.ts +2 -2
  41. package/dist/paint-editor/index.js +12 -11
  42. package/dist/paint-editor/index.js.map +1 -1
  43. package/dist/raster/index.cjs +5 -4
  44. package/dist/raster/index.cjs.map +1 -1
  45. package/dist/raster/index.d.cts +29 -7
  46. package/dist/raster/index.d.ts +29 -7
  47. package/dist/raster/index.js +11 -10
  48. package/dist/vector/index.cjs +14 -12
  49. package/dist/vector/index.cjs.map +1 -1
  50. package/dist/vector/index.js +7 -5
  51. package/dist/vector/index.js.map +1 -1
  52. package/package.json +1 -1
  53. package/skills/pixerate-canvas/SKILL.md +23 -1
  54. package/skills/pixerate-image-editor/SKILL.md +7 -1
  55. package/skills/pixerate-image-editor/references/photoshop-files.md +4 -3
  56. package/skills/pixerate-paint-editor/SKILL.md +32 -7
  57. package/dist/chunk-BOWUU4LJ.js.map +0 -1
  58. package/dist/chunk-EJVDBITD.cjs.map +0 -1
  59. package/dist/chunk-HTAFDTNR.cjs.map +0 -1
  60. package/dist/chunk-N3467VD6.js.map +0 -1
  61. package/dist/chunk-TS5IEUW6.cjs.map +0 -1
  62. package/dist/chunk-UMVW2Q66.js.map +0 -1
  63. package/dist/chunk-WMRIG4XQ.cjs.map +0 -1
  64. package/dist/chunk-YHW26LS2.js.map +0 -1
@@ -0,0 +1,181 @@
1
+ // src/geom/homography.ts
2
+ var IDENTITY_HOMOGRAPHY = [1, 0, 0, 0, 1, 0, 0, 0, 1];
3
+ function solve8(rows) {
4
+ const m = rows.map((r) => r.slice());
5
+ for (let col = 0; col < 8; col++) {
6
+ let pivot = col;
7
+ for (let r = col + 1; r < 8; r++) if (Math.abs(m[r][col]) > Math.abs(m[pivot][col])) pivot = r;
8
+ if (!(Math.abs(m[pivot][col]) >= 1e-12)) return null;
9
+ [m[col], m[pivot]] = [m[pivot], m[col]];
10
+ const p = m[col];
11
+ for (let r = 0; r < 8; r++) {
12
+ if (r === col) continue;
13
+ const f = m[r][col] / p[col];
14
+ if (f !== 0) for (let k = 0; k < 9; k++) m[r][k] -= f * p[k];
15
+ }
16
+ }
17
+ const out = [];
18
+ for (let i = 0; i < 8; i++) {
19
+ const v = m[i][8] / m[i][i];
20
+ if (!Number.isFinite(v)) return null;
21
+ out.push(v);
22
+ }
23
+ return out;
24
+ }
25
+ function applyHomography(h, p) {
26
+ const w = h[6] * p.x + h[7] * p.y + h[8];
27
+ if (!Number.isFinite(w) || Math.abs(w) < 1e-12) return null;
28
+ const x = (h[0] * p.x + h[1] * p.y + h[2]) / w;
29
+ const y = (h[3] * p.x + h[4] * p.y + h[5]) / w;
30
+ return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
31
+ }
32
+ function homographyW(h, p) {
33
+ return h[6] * p.x + h[7] * p.y + h[8];
34
+ }
35
+ var finite = (p) => Number.isFinite(p.x) && Number.isFinite(p.y);
36
+ function homographyFromPoints(from, to) {
37
+ if (from.length !== 4 || to.length !== 4 || ![...from, ...to].every(finite)) return null;
38
+ const rows = [];
39
+ for (let i = 0; i < 4; i++) {
40
+ const { x, y } = from[i];
41
+ const { x: u, y: v } = to[i];
42
+ rows.push([x, y, 1, 0, 0, 0, -u * x, -u * y, u]);
43
+ rows.push([0, 0, 0, x, y, 1, -v * x, -v * y, v]);
44
+ }
45
+ const h = solve8(rows);
46
+ if (!h) return null;
47
+ const out = [h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], 1];
48
+ for (let i = 0; i < 4; i++) {
49
+ const r = applyHomography(out, from[i]);
50
+ const q = to[i];
51
+ const scale = 1 + Math.max(Math.abs(q.x), Math.abs(q.y));
52
+ if (!r || Math.abs(r.x - q.x) > 1e-6 * scale || Math.abs(r.y - q.y) > 1e-6 * scale) return null;
53
+ }
54
+ return out;
55
+ }
56
+ function homographyKeepsQuad(h, quad) {
57
+ const ws = quad.map((p) => h[6] * p.x + h[7] * p.y + h[8]);
58
+ return ws.every((w) => w > 1e-9) || ws.every((w) => w < -1e-9);
59
+ }
60
+ function orderQuad(points) {
61
+ if (points.length !== 4 || !points.every(finite)) return null;
62
+ const cx = points.reduce((s, p) => s + p.x, 0) / 4;
63
+ const cy = points.reduce((s, p) => s + p.y, 0) / 4;
64
+ const q = points.slice().sort((a, b) => Math.atan2(a.y - cy, a.x - cx) - Math.atan2(b.y - cy, b.x - cx));
65
+ let first = 0;
66
+ for (let i = 1; i < 4; i++) if (q[i].x + q[i].y < q[first].x + q[first].y) first = i;
67
+ const ordered = [...q.slice(first), ...q.slice(0, first)];
68
+ const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
69
+ const turns = ordered.map((_, i) => cross(ordered[i], ordered[(i + 1) % 4], ordered[(i + 2) % 4]));
70
+ const area = turns.reduce((s, t) => s + t, 0) / 2;
71
+ const xs = ordered.map((p) => p.x);
72
+ const ys = ordered.map((p) => p.y);
73
+ const size = Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));
74
+ const convex = turns.every((t) => t > 1e-9 * size * size);
75
+ return convex && area > 1e-6 * size * size ? ordered : null;
76
+ }
77
+ function multiplyHomographies(a, b) {
78
+ const r = new Array(9);
79
+ for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) r[i * 3 + j] = b[i * 3] * a[j] + b[i * 3 + 1] * a[3 + j] + b[i * 3 + 2] * a[6 + j];
80
+ return r;
81
+ }
82
+ function invertHomography(m) {
83
+ const c = [
84
+ m[4] * m[8] - m[5] * m[7],
85
+ m[2] * m[7] - m[1] * m[8],
86
+ m[1] * m[5] - m[2] * m[4],
87
+ m[5] * m[6] - m[3] * m[8],
88
+ m[0] * m[8] - m[2] * m[6],
89
+ m[2] * m[3] - m[0] * m[5],
90
+ m[3] * m[7] - m[4] * m[6],
91
+ m[1] * m[6] - m[0] * m[7],
92
+ m[0] * m[4] - m[1] * m[3]
93
+ ];
94
+ const det = m[0] * c[0] + m[1] * c[3] + m[2] * c[6];
95
+ if (!(Math.abs(det) >= 1e-12) || !Number.isFinite(det)) return null;
96
+ return c.map((v) => v / det);
97
+ }
98
+ function homographyFromAffine(m) {
99
+ return [m[0], m[2], m[4], m[1], m[3], m[5], 0, 0, 1];
100
+ }
101
+ function affineFromHomography(h, eps = 1e-12) {
102
+ if (Math.abs(h[6]) > eps * Math.abs(h[8]) || Math.abs(h[7]) > eps * Math.abs(h[8]) || !h[8]) return null;
103
+ const w = h[8];
104
+ return [h[0] / w, h[3] / w, h[1] / w, h[4] / w, h[2] / w, h[5] / w];
105
+ }
106
+ function isIdentityHomography(h, eps = 1e-9) {
107
+ const w = h[8];
108
+ if (Math.abs(w) < 1e-12) return false;
109
+ const id = IDENTITY_HOMOGRAPHY;
110
+ for (let i = 0; i < 8; i++) if (Math.abs(h[i] / w - id[i]) > eps) return false;
111
+ return true;
112
+ }
113
+ function squareToQuad(q) {
114
+ const [p0, p1, p2, p3] = q;
115
+ const sx = p0.x - p1.x + p2.x - p3.x;
116
+ const sy = p0.y - p1.y + p2.y - p3.y;
117
+ if (Math.abs(sx) < 1e-12 && Math.abs(sy) < 1e-12) {
118
+ return [p1.x - p0.x, p3.x - p0.x, p0.x, p1.y - p0.y, p3.y - p0.y, p0.y, 0, 0, 1];
119
+ }
120
+ const dx1 = p1.x - p2.x;
121
+ const dx2 = p3.x - p2.x;
122
+ const dy1 = p1.y - p2.y;
123
+ const dy2 = p3.y - p2.y;
124
+ const den = dx1 * dy2 - dx2 * dy1;
125
+ if (Math.abs(den) < 1e-12) return null;
126
+ const g = (sx * dy2 - dx2 * sy) / den;
127
+ const h = (dx1 * sy - sx * dy1) / den;
128
+ return [p1.x - p0.x + g * p1.x, p3.x - p0.x + h * p3.x, p0.x, p1.y - p0.y + g * p1.y, p3.y - p0.y + h * p3.y, p0.y, g, h, 1];
129
+ }
130
+ function rectToQuad(r, quad) {
131
+ if (!(r.width > 0 && r.height > 0) || quad.length !== 4 || !quad.every(finite)) return null;
132
+ const toUnit = [1 / r.width, 0, -r.x / r.width, 0, 1 / r.height, -r.y / r.height, 0, 0, 1];
133
+ const sq = squareToQuad(quad);
134
+ if (!sq) return null;
135
+ const h = multiplyHomographies(toUnit, sq);
136
+ return invertHomography(h) ? h : null;
137
+ }
138
+ function boxQuad(r) {
139
+ return [
140
+ { x: r.x, y: r.y },
141
+ { x: r.x + r.width, y: r.y },
142
+ { x: r.x + r.width, y: r.y + r.height },
143
+ { x: r.x, y: r.y + r.height }
144
+ ];
145
+ }
146
+ function homographyFrontSide(h, r) {
147
+ const ahead = boxQuad(r).filter((p) => homographyW(h, p) > 0).length;
148
+ if (ahead >= 3) return 1;
149
+ if (ahead <= 1) return -1;
150
+ return homographyW(h, { x: r.x + r.width / 2, y: r.y + r.height / 2 }) >= 0 ? 1 : -1;
151
+ }
152
+ var OUTPUT_LIMIT = 1 << 20;
153
+ function cornerBounds(corners) {
154
+ const lim = OUTPUT_LIMIT;
155
+ const xs = corners.map((c) => c.x);
156
+ const ys = corners.map((c) => c.y);
157
+ const x0 = Math.floor(Math.max(-lim, Math.min(...xs))) - 1;
158
+ const y0 = Math.floor(Math.max(-lim, Math.min(...ys))) - 1;
159
+ const x1 = Math.ceil(Math.min(lim, Math.max(...xs))) + 1;
160
+ const y1 = Math.ceil(Math.min(lim, Math.max(...ys))) + 1;
161
+ return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
162
+ }
163
+
164
+ export {
165
+ solve8,
166
+ applyHomography,
167
+ homographyW,
168
+ homographyFromPoints,
169
+ homographyKeepsQuad,
170
+ orderQuad,
171
+ multiplyHomographies,
172
+ invertHomography,
173
+ homographyFromAffine,
174
+ affineFromHomography,
175
+ isIdentityHomography,
176
+ rectToQuad,
177
+ boxQuad,
178
+ homographyFrontSide,
179
+ cornerBounds
180
+ };
181
+ //# sourceMappingURL=chunk-GX332W2C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/geom/homography.ts"],"sourcesContent":["/**\n * Perspective (projective) maps between quadrilaterals: Free Distort and Perspective in both the\n * vector and the image editor. Pure maths; degenerate or non-finite input gives `null` instead of\n * NaNs.\n *\n * Ported from ArtCraft (MIT OR Apache-2.0, © ArtCraft Team and contributors; see\n * THIRD_PARTY_NOTICES.md): pdfcraft `crates/geom/src/perspective.rs` (`Homography::from_points`,\n * `Homography::apply`, `solve8`, `order_quad`) and photocraft `crates/algo/src/transform.rs`\n * (`Homography::square_to_quad`, `rect_to_quad`, `inverse`, `mul`, `local_scale`, `front_side`,\n * `warp_output_bounds`, `convex_quad`).\n */\nimport type { AffineMatrix, Box, Homography, Quad, Vec2 } from './types';\n\nexport type { Homography };\n\nexport const IDENTITY_HOMOGRAPHY: Homography = [1, 0, 0, 0, 1, 0, 0, 0, 1];\n\n/**\n * Gaussian elimination with partial pivoting on an 8×8 system (the 9th column of each row is the\n * right-hand side). Null when the system is singular.\n */\nexport function solve8(rows: readonly (readonly number[])[]): number[] | null {\n const m = rows.map((r) => r.slice());\n for (let col = 0; col < 8; col++) {\n let pivot = col;\n for (let r = col + 1; r < 8; r++) if (Math.abs(m[r][col]) > Math.abs(m[pivot][col])) pivot = r;\n if (!(Math.abs(m[pivot][col]) >= 1e-12)) return null;\n [m[col], m[pivot]] = [m[pivot], m[col]];\n const p = m[col];\n for (let r = 0; r < 8; r++) {\n if (r === col) continue;\n const f = m[r][col] / p[col];\n if (f !== 0) for (let k = 0; k < 9; k++) m[r][k] -= f * p[k];\n }\n }\n const out: number[] = [];\n for (let i = 0; i < 8; i++) {\n const v = m[i][8] / m[i][i];\n if (!Number.isFinite(v)) return null;\n out.push(v);\n }\n return out;\n}\n\n/** The image of `p`, or null where the map sends it to infinity. */\nexport function applyHomography(h: Homography, p: Vec2): Vec2 | null {\n const w = h[6] * p.x + h[7] * p.y + h[8];\n if (!Number.isFinite(w) || Math.abs(w) < 1e-12) return null;\n const x = (h[0] * p.x + h[1] * p.y + h[2]) / w;\n const y = (h[3] * p.x + h[4] * p.y + h[5]) / w;\n return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;\n}\n\n/** The homogeneous `w` of `p`: its sign is the side of the horizon `p` maps to (0 on it). */\nexport function homographyW(h: Homography, p: Vec2): number {\n return h[6] * p.x + h[7] * p.y + h[8];\n}\n\nconst finite = (p: Vec2) => Number.isFinite(p.x) && Number.isFinite(p.y);\n\n/**\n * The projective map that takes each of `from` to the point at the same index of `to`. Null when\n * three of either set are collinear or a coordinate is not finite.\n */\nexport function homographyFromPoints(from: readonly Vec2[], to: readonly Vec2[]): Homography | null {\n if (from.length !== 4 || to.length !== 4 || ![...from, ...to].every(finite)) return null;\n // x' = (h0 x + h1 y + h2) / (h6 x + h7 y + 1), y' likewise with h3..h5: eight unknowns, two\n // equations per point pair.\n const rows: number[][] = [];\n for (let i = 0; i < 4; i++) {\n const { x, y } = from[i];\n const { x: u, y: v } = to[i];\n rows.push([x, y, 1, 0, 0, 0, -u * x, -u * y, u]);\n rows.push([0, 0, 0, x, y, 1, -v * x, -v * y, v]);\n }\n const h = solve8(rows);\n if (!h) return null;\n const out: Homography = [h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], 1];\n // Collinear points can leave a solvable but singular system: check the map really takes the\n // four points where they should go.\n for (let i = 0; i < 4; i++) {\n const r = applyHomography(out, from[i]);\n const q = to[i];\n const scale = 1 + Math.max(Math.abs(q.x), Math.abs(q.y));\n if (!r || Math.abs(r.x - q.x) > 1e-6 * scale || Math.abs(r.y - q.y) > 1e-6 * scale) return null;\n }\n return out;\n}\n\n/**\n * Whether `h` maps the whole convex quad `quad` without sending any of it through infinity (the\n * denominator keeps one sign over it): what a usable distortion needs.\n */\nexport function homographyKeepsQuad(h: Homography, quad: readonly Vec2[]): boolean {\n const ws = quad.map((p) => h[6] * p.x + h[7] * p.y + h[8]);\n return ws.every((w) => w > 1e-9) || ws.every((w) => w < -1e-9);\n}\n\n/**\n * The four corners in reading order for a y-down space: top-left, top-right, bottom-right,\n * bottom-left, whatever order they come in. Null unless they form a convex quadrilateral with a\n * non-negligible area.\n */\nexport function orderQuad(points: readonly Vec2[]): Vec2[] | null {\n if (points.length !== 4 || !points.every(finite)) return null;\n const cx = points.reduce((s, p) => s + p.x, 0) / 4;\n const cy = points.reduce((s, p) => s + p.y, 0) / 4;\n // Ascending angle about the centre is clockwise on screen (y down).\n const q = points.slice().sort((a, b) => Math.atan2(a.y - cy, a.x - cx) - Math.atan2(b.y - cy, b.x - cx));\n let first = 0;\n for (let i = 1; i < 4; i++) if (q[i].x + q[i].y < q[first].x + q[first].y) first = i;\n const ordered = [...q.slice(first), ...q.slice(0, first)];\n const cross = (o: Vec2, a: Vec2, b: Vec2) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);\n const turns = ordered.map((_, i) => cross(ordered[i], ordered[(i + 1) % 4], ordered[(i + 2) % 4]));\n const area = turns.reduce((s, t) => s + t, 0) / 2;\n const xs = ordered.map((p) => p.x);\n const ys = ordered.map((p) => p.y);\n const size = Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));\n const convex = turns.every((t) => t > 1e-9 * size * size);\n return convex && area > 1e-6 * size * size ? ordered : null;\n}\n\n/** `a` then `b` (apply `a` first). */\nexport function multiplyHomographies(a: Homography, b: Homography): Homography {\n // Row-major column-vector maps: (b ∘ a) = B · A.\n const r = new Array<number>(9);\n for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) r[i * 3 + j] = b[i * 3] * a[j] + b[i * 3 + 1] * a[3 + j] + b[i * 3 + 2] * a[6 + j];\n return r as unknown as Homography;\n}\n\n/** The inverse map, or null for a singular one. */\nexport function invertHomography(m: Homography): Homography | null {\n const c = [\n m[4] * m[8] - m[5] * m[7],\n m[2] * m[7] - m[1] * m[8],\n m[1] * m[5] - m[2] * m[4],\n m[5] * m[6] - m[3] * m[8],\n m[0] * m[8] - m[2] * m[6],\n m[2] * m[3] - m[0] * m[5],\n m[3] * m[7] - m[4] * m[6],\n m[1] * m[6] - m[0] * m[7],\n m[0] * m[4] - m[1] * m[3],\n ];\n const det = m[0] * c[0] + m[1] * c[3] + m[2] * c[6];\n if (!(Math.abs(det) >= 1e-12) || !Number.isFinite(det)) return null;\n return c.map((v) => v / det) as unknown as Homography;\n}\n\n/** An affine matrix (SVG order) as a homography. */\nexport function homographyFromAffine(m: AffineMatrix): Homography {\n return [m[0], m[2], m[4], m[1], m[3], m[5], 0, 0, 1];\n}\n\n/** The affine matrix of `h` when it is affine (no perspective part), else null. */\nexport function affineFromHomography(h: Homography, eps = 1e-12): AffineMatrix | null {\n if (Math.abs(h[6]) > eps * Math.abs(h[8]) || Math.abs(h[7]) > eps * Math.abs(h[8]) || !h[8]) return null;\n const w = h[8];\n return [h[0] / w, h[3] / w, h[1] / w, h[4] / w, h[2] / w, h[5] / w];\n}\n\nexport function isIdentityHomography(h: Homography, eps = 1e-9): boolean {\n const w = h[8];\n if (Math.abs(w) < 1e-12) return false;\n const id = IDENTITY_HOMOGRAPHY;\n for (let i = 0; i < 8; i++) if (Math.abs(h[i] / w - id[i]) > eps) return false;\n return true;\n}\n\n/** Unit square → quad (corners (0,0), (1,0), (1,1), (0,1) to TL, TR, BR, BL); null when degenerate. */\nfunction squareToQuad(q: readonly Vec2[]): Homography | null {\n const [p0, p1, p2, p3] = q;\n const sx = p0.x - p1.x + p2.x - p3.x;\n const sy = p0.y - p1.y + p2.y - p3.y;\n if (Math.abs(sx) < 1e-12 && Math.abs(sy) < 1e-12) {\n return [p1.x - p0.x, p3.x - p0.x, p0.x, p1.y - p0.y, p3.y - p0.y, p0.y, 0, 0, 1];\n }\n const dx1 = p1.x - p2.x;\n const dx2 = p3.x - p2.x;\n const dy1 = p1.y - p2.y;\n const dy2 = p3.y - p2.y;\n const den = dx1 * dy2 - dx2 * dy1;\n if (Math.abs(den) < 1e-12) return null;\n const g = (sx * dy2 - dx2 * sy) / den;\n const h = (dx1 * sy - sx * dy1) / den;\n return [p1.x - p0.x + g * p1.x, p3.x - p0.x + h * p3.x, p0.x, p1.y - p0.y + g * p1.y, p3.y - p0.y + h * p3.y, p0.y, g, h, 1];\n}\n\n/**\n * The map taking box `r`'s corners onto `quad` (TL, TR, BR, BL), exact for parallelograms (then\n * affine). Null for an empty box, a non-finite or degenerate quad, or a singular result.\n */\nexport function rectToQuad(r: Box, quad: readonly Vec2[]): Homography | null {\n if (!(r.width > 0 && r.height > 0) || quad.length !== 4 || !quad.every(finite)) return null;\n const toUnit: Homography = [1 / r.width, 0, -r.x / r.width, 0, 1 / r.height, -r.y / r.height, 0, 0, 1];\n const sq = squareToQuad(quad);\n if (!sq) return null;\n const h = multiplyHomographies(toUnit, sq);\n return invertHomography(h) ? h : null;\n}\n\n/** Box `r`'s corners as a quad (TL, TR, BR, BL). */\nexport function boxQuad(r: Box): Quad {\n return [\n { x: r.x, y: r.y },\n { x: r.x + r.width, y: r.y },\n { x: r.x + r.width, y: r.y + r.height },\n { x: r.x, y: r.y + r.height },\n ];\n}\n\n/** Approximate linear scale of the map near `p` (square root of the Jacobian determinant). */\nexport function homographyLocalScale(h: Homography, p: Vec2): number {\n const e = 0.5;\n const a = applyHomography(h, { x: p.x - e, y: p.y });\n const b = applyHomography(h, { x: p.x + e, y: p.y });\n const c = applyHomography(h, { x: p.x, y: p.y - e });\n const d = applyHomography(h, { x: p.x, y: p.y + e });\n if (!a || !b || !c || !d) return 0;\n const jx = { x: b.x - a.x, y: b.y - a.y };\n const jy = { x: d.x - c.x, y: d.y - c.y };\n return Math.sqrt(Math.abs(jx.x * jy.y - jx.y * jy.x));\n}\n\n/**\n * The side of the horizon (+1 or −1) most of box `r`'s corners map to (the centre's on a tie). A\n * Distort dragged past the horizon maps the rest of the source to the far side, where it would\n * show as a mirrored copy wrapped round infinity; resampling keeps to this side, as Photoshop does.\n */\nexport function homographyFrontSide(h: Homography, r: Box): 1 | -1 {\n const ahead = boxQuad(r).filter((p) => homographyW(h, p) > 0).length;\n if (ahead >= 3) return 1;\n if (ahead <= 1) return -1;\n return homographyW(h, { x: r.x + r.width / 2, y: r.y + r.height / 2 }) >= 0 ? 1 : -1;\n}\n\n/** Most pixels a side of a warped result may span (±2²⁰), as photocraft clamps. */\nconst OUTPUT_LIMIT = 1 << 20;\n\n/**\n * The integer box a warp of box `r` through `h` fills: the warped corners plus a pixel for filter\n * support, each side clamped to ±2²⁰. Null when a corner maps to infinity or `h` is singular.\n */\nexport function warpOutputBounds(r: Box, h: Homography): Box | null {\n if (!(r.width > 0 && r.height > 0) || !invertHomography(h)) return null;\n const corners = boxQuad(r).map((p) => applyHomography(h, p));\n if (corners.some((c) => !c)) return null;\n return cornerBounds(corners as Vec2[]);\n}\n\n/** The integer box around `corners`, grown by a pixel and clamped to ±2²⁰. */\nexport function cornerBounds(corners: readonly Vec2[]): Box {\n const lim = OUTPUT_LIMIT;\n const xs = corners.map((c) => c.x);\n const ys = corners.map((c) => c.y);\n const x0 = Math.floor(Math.max(-lim, Math.min(...xs))) - 1;\n const y0 = Math.floor(Math.max(-lim, Math.min(...ys))) - 1;\n const x1 = Math.ceil(Math.min(lim, Math.max(...xs))) + 1;\n const y1 = Math.ceil(Math.min(lim, Math.max(...ys))) + 1;\n return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };\n}\n\n/**\n * Whether `q` (TL, TR, BR, BL) is strictly convex with every corner turn above ~0.06°, wound\n * clockwise on screen (y down), finite and at least 1 px² in area.\n */\nexport function isConvexQuad(q: readonly Vec2[]): boolean {\n if (q.length !== 4 || !q.every(finite)) return false;\n let area2 = 0;\n for (let i = 0; i < 4; i++) {\n const a = q[i];\n const b = q[(i + 1) % 4];\n const c = q[(i + 2) % 4];\n const e1 = { x: b.x - a.x, y: b.y - a.y };\n const e2 = { x: c.x - b.x, y: c.y - b.y };\n const cross = e1.x * e2.y - e1.y * e2.x;\n if (!(cross > 1e-3 * Math.hypot(e1.x, e1.y) * Math.hypot(e2.x, e2.y))) return false;\n area2 += a.x * b.y - b.x * a.y;\n }\n return Number.isFinite(area2) && area2 >= 2;\n}\n"],"mappings":"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","names":[]}
@@ -34,23 +34,17 @@ import {
34
34
  validateEffectGradient,
35
35
  validateLayerEffects,
36
36
  warpSurface
37
- } from "./chunk-UMVW2Q66.js";
37
+ } from "./chunk-CLTTLLWA.js";
38
38
  import {
39
39
  affineFromHomography,
40
40
  applyHomography,
41
- base64ToBytes,
42
41
  boxQuad,
43
- bytesToBase64,
44
- decodePng,
45
- encodePng,
46
42
  homographyFromAffine,
47
43
  homographyKeepsQuad,
48
44
  invertHomography,
49
45
  multiplyHomographies,
50
- parseDataUrl,
51
- pngDataUrl,
52
46
  rectToQuad
53
- } from "./chunk-N3467VD6.js";
47
+ } from "./chunk-GX332W2C.js";
54
48
  import {
55
49
  TILE,
56
50
  TiledSurface,
@@ -69,9 +63,19 @@ import {
69
63
  surfaceFromPixels,
70
64
  tileKey,
71
65
  tilesInRect,
66
+ to32From8,
67
+ to8From32,
72
68
  translateSurface,
73
69
  writeDeepRegion
74
70
  } from "./chunk-HKDTM6VC.js";
71
+ import {
72
+ base64ToBytes,
73
+ bytesToBase64,
74
+ decodePng,
75
+ encodePng,
76
+ parseDataUrl,
77
+ pngDataUrl
78
+ } from "./chunk-7QN76ESJ.js";
75
79
  import {
76
80
  Transform,
77
81
  builtinProfile,
@@ -2181,6 +2185,67 @@ function applyProcess2Adjustments(imageData, adjustments) {
2181
2185
  if (hasOpacity) data[i + 3] = clamp(data[i + 3] * opacity);
2182
2186
  }
2183
2187
  }
2188
+ function applyProcess2Float(data, adjustments, linear) {
2189
+ const hasColor = !!adjustments.brightness || !!adjustments.contrast || !!adjustments.saturation || !!adjustments.exposure || !!adjustments.temperature || !!adjustments.tint;
2190
+ if (!hasColor) return;
2191
+ const { m, luts, scale, saturation } = getProcess2Plan(adjustments);
2192
+ const N = TONE_LUT_SIZE;
2193
+ const wr = LUMA_709[0], wg = LUMA_709[1], wb = LUMA_709[2];
2194
+ const c = [0, 0, 0];
2195
+ const dec = (v) => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
2196
+ const enc = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v <= 31308e-7 ? v * 12.92 : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
2197
+ for (let i = 0; i < data.length; i += 4) {
2198
+ if (!(data[i + 3] > 0)) continue;
2199
+ const r0 = linear ? data[i] : dec(data[i]);
2200
+ const g0 = linear ? data[i + 1] : dec(data[i + 1]);
2201
+ const b0 = linear ? data[i + 2] : dec(data[i + 2]);
2202
+ c[0] = m[0] * r0 + m[1] * g0 + m[2] * b0;
2203
+ c[1] = m[3] * r0 + m[4] * g0 + m[5] * b0;
2204
+ c[2] = m[6] * r0 + m[7] * g0 + m[8] * b0;
2205
+ for (let ch = 0; ch < 3; ch++) {
2206
+ const lut = luts[ch];
2207
+ const v = c[ch];
2208
+ let f;
2209
+ if (v <= 0) c[ch] = lut[0];
2210
+ else if ((f = v * scale[ch]) >= N) c[ch] = linear ? lut[N] + (lut[N] - lut[N - 1]) * (f - N) : lut[N];
2211
+ else {
2212
+ const k = f | 0;
2213
+ c[ch] = lut[k] + (lut[k + 1] - lut[k]) * (f - k);
2214
+ }
2215
+ }
2216
+ if (saturation !== 1) {
2217
+ const y = wr * c[0] + wg * c[1] + wb * c[2];
2218
+ for (let ch = 0; ch < 3; ch++) c[ch] = y + (c[ch] - y) * saturation;
2219
+ }
2220
+ for (let ch = 0; ch < 3; ch++) data[i + ch] = linear ? Math.max(0, c[ch]) : enc(c[ch]);
2221
+ }
2222
+ }
2223
+ function applyBoxBlurFloat(imageData, radius) {
2224
+ if (radius < 1) return;
2225
+ const { width: w, height: h, data: src } = imageData;
2226
+ const temp = new Float32Array(src.length);
2227
+ const n = 2 * radius + 1;
2228
+ for (let y = 0; y < h; y++) {
2229
+ for (let x = 0; x < w; x++) {
2230
+ const d = (y * w + x) * 4;
2231
+ for (let c = 0; c < 4; c++) {
2232
+ let s = 0;
2233
+ for (let k = -radius; k <= radius; k++) s += src[(y * w + Math.min(w - 1, Math.max(0, x + k))) * 4 + c];
2234
+ temp[d + c] = s / n;
2235
+ }
2236
+ }
2237
+ }
2238
+ for (let x = 0; x < w; x++) {
2239
+ for (let y = 0; y < h; y++) {
2240
+ const d = (y * w + x) * 4;
2241
+ for (let c = 0; c < 4; c++) {
2242
+ let s = 0;
2243
+ for (let k = -radius; k <= radius; k++) s += temp[(Math.min(h - 1, Math.max(0, y + k)) * w + x) * 4 + c];
2244
+ src[d + c] = s / n;
2245
+ }
2246
+ }
2247
+ }
2248
+ }
2184
2249
  function applyBoxBlur(imageData, radius) {
2185
2250
  applyFastBoxBlur(imageData, radius);
2186
2251
  }
@@ -2379,6 +2444,27 @@ function runLayerFilters(data, width, height, filters) {
2379
2444
  else if (f.kind === "blur") applyBoxBlur({ width, height, data }, Math.min(Math.round(f.radius), 40));
2380
2445
  }
2381
2446
  }
2447
+ function runLayerFiltersFloat(data, width, height, filters, linear) {
2448
+ for (const f of filters) {
2449
+ if (!isActiveFilter(f)) continue;
2450
+ if (f.kind === "blur") applyBoxBlurFloat({ width, height, data }, Math.min(Math.round(f.radius), 40));
2451
+ else if (f.kind === "develop") {
2452
+ const adj = developAdjustments(f);
2453
+ if (normalizeProcessVersion(adj.process) === LATEST_PROCESS_VERSION) applyProcess2Float(data, adj, linear);
2454
+ else {
2455
+ const bytes = linear ? to8From32(data, 4) : Uint8ClampedArray.from(data, (v) => v * 255);
2456
+ applyLegacyAdjustments({ data: bytes }, adj);
2457
+ if (linear) data.set(to32From8(bytes, 4));
2458
+ else for (let i = 0; i < data.length; i++) data[i] = bytes[i] / 255;
2459
+ }
2460
+ }
2461
+ }
2462
+ }
2463
+ function filterReach(filters) {
2464
+ let r = 0;
2465
+ for (const f of filters) if (isActiveFilter(f) && f.kind === "blur") r += Math.min(Math.round(f.radius), 40);
2466
+ return r;
2467
+ }
2382
2468
  var filterSpecCache = /* @__PURE__ */ new WeakMap();
2383
2469
  function pixelFilterSpec(layer) {
2384
2470
  const list2 = layer.filters;
@@ -2429,7 +2515,13 @@ var LayerCompositor = class extends RasterCompositor {
2429
2515
  };
2430
2516
  function compositeDeep(layers, rect, sources, depth) {
2431
2517
  const deep = new DeepCompositor(new LayerCompositor(), PHOTO_PROFILE, {
2432
- applyFilterRunDeep: (run, acc, _r, masks) => applyAdjustmentLayersFloat(acc, run.map(adjustmentNodeAsLayer), masks)
2518
+ applyFilterRunDeep: (run, acc, _r, masks) => applyAdjustmentLayersFloat(acc, run.map(adjustmentNodeAsLayer), masks),
2519
+ pixelFiltersDeep: (l) => {
2520
+ if (l.type !== "pixel") return null;
2521
+ const filters = (l.filters ?? []).filter(isActiveFilter);
2522
+ if (!filters.length) return null;
2523
+ return { reach: filterReach(filters), apply: (data, width, height, linear) => runLayerFiltersFloat(data, width, height, filters, linear) };
2524
+ }
2433
2525
  }, depth);
2434
2526
  return deep.composite(layers, rect, sources);
2435
2527
  }
@@ -11546,6 +11638,8 @@ export {
11546
11638
  applyAdjustments,
11547
11639
  applyLegacyAdjustments,
11548
11640
  applyProcess2Adjustments,
11641
+ applyProcess2Float,
11642
+ applyBoxBlurFloat,
11549
11643
  applyBoxBlur,
11550
11644
  applyDepthMask,
11551
11645
  removeAlpha,
@@ -11567,6 +11661,7 @@ export {
11567
11661
  adjustmentNodeAsLayer,
11568
11662
  depthMaskAlpha,
11569
11663
  runLayerFilters,
11664
+ runLayerFiltersFloat,
11570
11665
  LayerCompositor,
11571
11666
  compositeDeep,
11572
11667
  DEFAULT_ADJUSTMENTS_VALUES,
@@ -11770,4 +11865,4 @@ export {
11770
11865
  smartContentsFile,
11771
11866
  exportPsd
11772
11867
  };
11773
- //# sourceMappingURL=chunk-BOWUU4LJ.js.map
11868
+ //# sourceMappingURL=chunk-IX3YKUVK.js.map