@radialapps/memories-vips-editor 0.0.0-stage → 0.1.1
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/README.md +101 -2
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/math.d.ts +11 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +40 -0
- package/dist/math.js.map +1 -0
- package/dist/pipeline.d.ts +129 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +485 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/shaders.d.ts +8 -0
- package/dist/shaders.d.ts.map +1 -0
- package/dist/shaders.js +51 -0
- package/dist/shaders.js.map +1 -0
- package/dist/transforms/blur.d.ts +17 -0
- package/dist/transforms/blur.d.ts.map +1 -0
- package/dist/transforms/blur.js +35 -0
- package/dist/transforms/blur.js.map +1 -0
- package/dist/transforms/brightnessContrast.d.ts +19 -0
- package/dist/transforms/brightnessContrast.d.ts.map +1 -0
- package/dist/transforms/brightnessContrast.js +55 -0
- package/dist/transforms/brightnessContrast.js.map +1 -0
- package/dist/transforms/crop.d.ts +34 -0
- package/dist/transforms/crop.d.ts.map +1 -0
- package/dist/transforms/crop.js +103 -0
- package/dist/transforms/crop.js.map +1 -0
- package/dist/transforms/exposure.d.ts +17 -0
- package/dist/transforms/exposure.d.ts.map +1 -0
- package/dist/transforms/exposure.js +41 -0
- package/dist/transforms/exposure.js.map +1 -0
- package/dist/transforms/grayscale.d.ts +15 -0
- package/dist/transforms/grayscale.d.ts.map +1 -0
- package/dist/transforms/grayscale.js +31 -0
- package/dist/transforms/grayscale.js.map +1 -0
- package/dist/transforms/hueSaturation.d.ts +19 -0
- package/dist/transforms/hueSaturation.d.ts.map +1 -0
- package/dist/transforms/hueSaturation.js +66 -0
- package/dist/transforms/hueSaturation.js.map +1 -0
- package/dist/transforms/index.d.ts +8 -0
- package/dist/transforms/index.d.ts.map +1 -0
- package/dist/transforms/index.js +44 -0
- package/dist/transforms/index.js.map +1 -0
- package/dist/transforms/invert.d.ts +15 -0
- package/dist/transforms/invert.d.ts.map +1 -0
- package/dist/transforms/invert.js +30 -0
- package/dist/transforms/invert.js.map +1 -0
- package/dist/transforms/rotate.d.ts +45 -0
- package/dist/transforms/rotate.d.ts.map +1 -0
- package/dist/transforms/rotate.js +194 -0
- package/dist/transforms/rotate.js.map +1 -0
- package/dist/transforms/sepia.d.ts +17 -0
- package/dist/transforms/sepia.d.ts.map +1 -0
- package/dist/transforms/sepia.js +45 -0
- package/dist/transforms/sepia.js.map +1 -0
- package/dist/transforms/sharpen.d.ts +19 -0
- package/dist/transforms/sharpen.d.ts.map +1 -0
- package/dist/transforms/sharpen.js +61 -0
- package/dist/transforms/sharpen.js.map +1 -0
- package/dist/transforms/state.d.ts +6 -0
- package/dist/transforms/state.d.ts.map +1 -0
- package/dist/transforms/state.js +29 -0
- package/dist/transforms/state.js.map +1 -0
- package/dist/transforms/transform.d.ts +68 -0
- package/dist/transforms/transform.d.ts.map +1 -0
- package/dist/transforms/transform.js +14 -0
- package/dist/transforms/transform.js.map +1 -0
- package/dist/transforms/vibrance.d.ts +17 -0
- package/dist/transforms/vibrance.d.ts.map +1 -0
- package/dist/transforms/vibrance.js +43 -0
- package/dist/transforms/vibrance.js.map +1 -0
- package/dist/transforms/vignette.d.ts +19 -0
- package/dist/transforms/vignette.d.ts.map +1 -0
- package/dist/transforms/vignette.js +58 -0
- package/dist/transforms/vignette.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -4
package/README.md
CHANGED
|
@@ -1,3 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @radialapps/memories-vips-editor — headless WebGL preview + VIPS-mappable edit list
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pure-TypeScript, zero-dependency library. The caller provides a `<canvas>`
|
|
4
|
+
(layout and CSS); the pipeline renders an **ordered list of image edits**
|
|
5
|
+
with fullscreen shader passes (ping-pong, like `glfx.js`), resizing the
|
|
6
|
+
canvas backing store to the rendered output area and presenting 1:1 — the
|
|
7
|
+
image always fills the canvas exactly. The same list serializes
|
|
8
|
+
to JSON that `vips-preview` (`convert`/`thumbnail` `"edits"`) applies
|
|
9
|
+
before saving.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
editor/
|
|
13
|
+
src/
|
|
14
|
+
types.ts edit list model + JSON wire format
|
|
15
|
+
math.ts shared pixel-math helpers
|
|
16
|
+
shaders.ts shared GLSL (quad, copy, blit, gaussian)
|
|
17
|
+
pipeline.ts EditPipeline — headless, canvas-taking preview
|
|
18
|
+
transforms/ one Transform class per edit + registry (index.ts)
|
|
19
|
+
+ state serialization (state.ts); mirrors src/transforms/*.h
|
|
20
|
+
index.ts public surface (per-transform types import from their file)
|
|
21
|
+
demo/ tests/ playground (schema-driven) · vitest
|
|
22
|
+
demo/parity.html + demo/parity.ts + demo/parity-cases.json
|
|
23
|
+
committed WebGL↔VIPS side-by-side page: static shell, runtime
|
|
24
|
+
cards + live WebGL, cases as typed JSON (`satisfies` import)
|
|
25
|
+
demo/parity/ git-ignored VIPS JPEGs rendered by generate-parity.py
|
|
26
|
+
demo/generate-parity.py dumb renderer: reads parity-cases.json, runs a
|
|
27
|
+
built vips-preview (`npm run parity`)
|
|
28
|
+
UltraHDR source; VIPS side pre-rendered, WebGL side live.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Adding a transform: write its file, add one line to the registry — pipeline,
|
|
32
|
+
validation, serialization, and demo pick it up.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd editor
|
|
36
|
+
npm install
|
|
37
|
+
npm run dev # demo playground
|
|
38
|
+
npm run parity # render VIPS-side parity JPEGs via a built vips-preview
|
|
39
|
+
npm run typecheck && npm test # tsc + vitest
|
|
40
|
+
npm run format # prettier --write
|
|
41
|
+
npm run build # typecheck + demo bundle (index.html + parity.html)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Publishing
|
|
45
|
+
|
|
46
|
+
The package ships compiled `dist/` (JS + `.d.ts`, zero runtime deps).
|
|
47
|
+
`npm publish` runs `prepublishOnly` (clean → typecheck → test → `build:lib`).
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd editor
|
|
51
|
+
npm run publish:dry # verify tarball contents without uploading
|
|
52
|
+
npm publish # clean + typecheck + test + build:lib, then publish
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Wire format
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"cmd": "convert",
|
|
60
|
+
"input": "in.jpg",
|
|
61
|
+
"output": "out.jpg",
|
|
62
|
+
"edits": [{ "edit": "brightnessContrast", "brightness": 0.1, "contrast": 0.1 }]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Numerics are optional (missing = no-change, except `sepia.amount` default 1);
|
|
67
|
+
the CLI rejects out-of-range values, so normalize client-side.
|
|
68
|
+
|
|
69
|
+
## VIPS mapping
|
|
70
|
+
|
|
71
|
+
sRGB 0..1 floats, array order, single uchar clip at the end; alpha is split
|
|
72
|
+
off, normalized to 0..1 float alongside, reattached. Everything agrees to
|
|
73
|
+
float precision (±1 LSB after quantize), including `blur`/`sharpen` (both
|
|
74
|
+
sides convolve the same discrete kernel — `sigma=radius/2`,
|
|
75
|
+
`half=min(15,max(1,ceil(2σ)))`, clamp edges — via two separable passes).
|
|
76
|
+
Thumbnail edits run **after** resize (radii are output pixels). The preview
|
|
77
|
+
downscales sources larger than 2048px and scales `blur`/`sharpen` radii by
|
|
78
|
+
the working/native ratio, so it shows the same *relative* blur as the
|
|
79
|
+
full-res VIPS output. UHDR ICC+gainmap pass through untouched (gainmap is
|
|
80
|
+
not re-derived). `rotate` by
|
|
81
|
+
a non-90 angle appends a transparent alpha band (corners + fringes); 90°
|
|
82
|
+
multiples stay exact with no band change.
|
|
83
|
+
|
|
84
|
+
| edit | params | VIPS |
|
|
85
|
+
| ----------------------- | -------------------------------------- | ------------------------------ |
|
|
86
|
+
| `brightnessContrast` | `brightness`, `contrast` −1..1 | `linear(mult, bias)` |
|
|
87
|
+
| `exposure` | `stops` −5..5 | `linear(2^stops)` |
|
|
88
|
+
| `hueSaturation` | `hue`, `saturation` −1..1 | fused 3×3 (≡ `recomb`) |
|
|
89
|
+
| `sepia` | `amount` 0..1 | same matrix, clipped at cast |
|
|
90
|
+
| `vibrance` / `vignette` | `amount` −1..1 / `size`, `amount` 0..1 | identical CPU loop |
|
|
91
|
+
| `grayscale` / `invert` | — | `(r+g+b)/3` / `linear(-1, +1)` |
|
|
92
|
+
| `blur` / `sharpen` | `radius` 0..100 / +`amount` 0..5 | shared kernel + `convsep` (mix)|
|
|
93
|
+
| `crop` | `x`,`y`,`width`,`height` 0..1 fractions| `extract_area` (rounded+clamped)|
|
|
94
|
+
| `rotate` | `angle` −180..180 (clockwise °) | `rot()` @90s, else `rotate()` |
|
|
95
|
+
|
|
96
|
+
Excluded (no clean VIPS mapping): `denoise`, `noise`, `curves`,
|
|
97
|
+
`lensBlur`/`tiltShift`/`zoomBlur`, halftones, warps.
|
|
98
|
+
|
|
99
|
+
Caveats: no-float GPUs fall back to 8-bit targets (more rounding drift);
|
|
100
|
+
preview caps at 2048px longest side (VIPS renders full-res); WebGL failures
|
|
101
|
+
throw instead of rendering black. Shaders adapted from
|
|
102
|
+
[evanw/glfx.js](https://github.com/evanw/glfx.js) (BSD).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { EditPipeline } from './pipeline.js';
|
|
2
|
+
export { TRANSFORMS, validateEdit, normalizeEdit } from './transforms/index.js';
|
|
3
|
+
export { validateState, stateToJSON, stateFromJSON } from './transforms/state.js';
|
|
4
|
+
export type { Transform, ParamControl, RenderContext, Target } from './transforms/transform.js';
|
|
5
|
+
export { emptyState, EDIT_STATE_VERSION } from './types.js';
|
|
6
|
+
export type { Edit, EditName, EditState } from './types.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// index.ts — minimal public surface: the pipeline, the registry, state
|
|
2
|
+
// helpers, and the types needed to consume them (including writing a
|
|
3
|
+
// custom Transform). Internal helpers (lookup, isNumInRange,
|
|
4
|
+
// setFloatUniform, math utils, per-transform types) live in their own
|
|
5
|
+
// modules — import those directly.
|
|
6
|
+
export { EditPipeline } from './pipeline.js';
|
|
7
|
+
export { TRANSFORMS, validateEdit, normalizeEdit } from './transforms/index.js';
|
|
8
|
+
export { validateState, stateToJSON, stateFromJSON } from './transforms/state.js';
|
|
9
|
+
export { emptyState, EDIT_STATE_VERSION } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,6DAA6D;AAC7D,sEAAsE;AACtE,mCAAmC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAElF,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/math.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function clampf(lo: number, v: number, hi: number): number;
|
|
2
|
+
/** Exposure gain for a stop shift. */
|
|
3
|
+
export declare function exposureMult(stops: number): number;
|
|
4
|
+
/** 1D gaussian kernel for a blur radius (sigma = radius/2). Preview + docs.
|
|
5
|
+
*
|
|
6
|
+
* Single source of truth, ported term-for-term to src/transforms/gaussian.h:
|
|
7
|
+
* both sides convolve these exact weights (separable, clamp edges), so
|
|
8
|
+
* preview and VIPS agree to ±1 LSB at every radius.
|
|
9
|
+
*/
|
|
10
|
+
export declare function gaussianKernel(radius: number): number[];
|
|
11
|
+
//# sourceMappingURL=math.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAYA,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,sCAAsC;AACtC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAavD"}
|
package/dist/math.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// math.ts — CPU reference for every edit's pixel math.
|
|
2
|
+
//
|
|
3
|
+
// These functions are the single source of truth shared (by port, not by
|
|
4
|
+
// import) with the GLSL in shaders.ts and the libvips code in src/edit.h:
|
|
5
|
+
// preview (WebGL) == math.ts == VIPS applier
|
|
6
|
+
// all operate on sRGB-encoded 0..1 floats and apply in array order.
|
|
7
|
+
//
|
|
8
|
+
// glfx.js inspiration: brightnessContrast / hueSaturation / sepia / vibrance /
|
|
9
|
+
// vignette shaders are direct ports of evanw/glfx.js adjust filters (see
|
|
10
|
+
// shaders.ts); the matrix derivations below match those shaders term for term
|
|
11
|
+
// so a VIPS `recomb`/`linear` does exactly what the canvas showed.
|
|
12
|
+
export function clampf(lo, v, hi) {
|
|
13
|
+
return Math.min(hi, Math.max(lo, v));
|
|
14
|
+
}
|
|
15
|
+
/** Exposure gain for a stop shift. */
|
|
16
|
+
export function exposureMult(stops) {
|
|
17
|
+
return Math.pow(2, clampf(-5, stops, 5));
|
|
18
|
+
}
|
|
19
|
+
/** 1D gaussian kernel for a blur radius (sigma = radius/2). Preview + docs.
|
|
20
|
+
*
|
|
21
|
+
* Single source of truth, ported term-for-term to src/transforms/gaussian.h:
|
|
22
|
+
* both sides convolve these exact weights (separable, clamp edges), so
|
|
23
|
+
* preview and VIPS agree to ±1 LSB at every radius.
|
|
24
|
+
*/
|
|
25
|
+
export function gaussianKernel(radius) {
|
|
26
|
+
const r = clampf(0, radius, 100);
|
|
27
|
+
if (r <= 0)
|
|
28
|
+
return [1];
|
|
29
|
+
const sigma = r / 2;
|
|
30
|
+
const half = Math.min(15, Math.max(1, Math.ceil(sigma * 2)));
|
|
31
|
+
const w = [];
|
|
32
|
+
let sum = 0;
|
|
33
|
+
for (let i = -half; i <= half; i++) {
|
|
34
|
+
const v = Math.exp(-0.5 * (i / sigma) * (i / sigma));
|
|
35
|
+
w.push(v);
|
|
36
|
+
sum += v;
|
|
37
|
+
}
|
|
38
|
+
return w.map((v) => v / sum);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=math.js.map
|
package/dist/math.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,mDAAmD;AACnD,oEAAoE;AACpE,EAAE;AACF,+EAA+E;AAC/E,yEAAyE;AACzE,8EAA8E;AAC9E,mEAAmE;AAEnE,MAAM,UAAU,MAAM,CAAC,EAAU,EAAE,CAAS,EAAE,EAAU;IACtD,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,GAAa,EAAE,CAAC;IACvB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,GAAG,IAAI,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Target, UniformSetter, ExtraTex } from './transforms/transform.js';
|
|
2
|
+
import { type Edit } from './types.js';
|
|
3
|
+
export declare class EditPipeline {
|
|
4
|
+
private gl;
|
|
5
|
+
private canvas;
|
|
6
|
+
private programs;
|
|
7
|
+
private quad;
|
|
8
|
+
private src;
|
|
9
|
+
private ping;
|
|
10
|
+
private pong;
|
|
11
|
+
private extra;
|
|
12
|
+
private imgW;
|
|
13
|
+
private imgH;
|
|
14
|
+
private outW;
|
|
15
|
+
private outH;
|
|
16
|
+
/** Working/native resolution ratio backing RenderContext.resolutionScale. */
|
|
17
|
+
private resScale;
|
|
18
|
+
private state;
|
|
19
|
+
private floatOK;
|
|
20
|
+
private highp;
|
|
21
|
+
/**
|
|
22
|
+
* Take over the canvas' WebGL context. preserveDrawingBuffer stays true
|
|
23
|
+
* so the demo can read pixels back; premultipliedAlpha stays false
|
|
24
|
+
* so alpha survives the passes unmodified. The canvas backing store is
|
|
25
|
+
* resized to the rendered output on every render — the caller owns layout
|
|
26
|
+
* and CSS only. Throws when WebGL is missing.
|
|
27
|
+
*/
|
|
28
|
+
constructor(canvas: HTMLCanvasElement);
|
|
29
|
+
/** Output image size (source size when no geometric edit applies). */
|
|
30
|
+
get width(): number;
|
|
31
|
+
get height(): number;
|
|
32
|
+
/** Ordered edit list (live reference — mutate via setEdits/addEdit/...). */
|
|
33
|
+
getEdits(): Edit[];
|
|
34
|
+
/** Replace the whole edit list (normalizing each edit) and re-render. */
|
|
35
|
+
setEdits(edits: Edit[]): void;
|
|
36
|
+
/** Append one edit (normalized) and re-render. */
|
|
37
|
+
addEdit(edit: Edit): void;
|
|
38
|
+
/** Drop the edit at `index` and re-render. */
|
|
39
|
+
removeEdit(index: number): void;
|
|
40
|
+
/** Reorder one edit and re-render. */
|
|
41
|
+
moveEdit(from: number, to: number): void;
|
|
42
|
+
/** Drop all edits (back to the bare source image) and re-render. */
|
|
43
|
+
clearEdits(): void;
|
|
44
|
+
/** Canonical JSON state for the VIPS side. */
|
|
45
|
+
toJSON(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Longest side of the working image. Camera JPEGs (12-50MP) would need
|
|
48
|
+
* hundreds of MB as float ping-pong targets and exceed
|
|
49
|
+
* MAX_TEXTURE_SIZE on weak GPUs — both failure modes render black with
|
|
50
|
+
* no exception. The preview is resolution-capped (reported via
|
|
51
|
+
* width/height); the VIPS side always renders full-res from the JSON.
|
|
52
|
+
*/
|
|
53
|
+
static readonly MAX_DIM = 2048;
|
|
54
|
+
/** Resolve the pixel size of any TexImageSource upload. */
|
|
55
|
+
private sourceDims;
|
|
56
|
+
/** Turn a sticky GL error flag into a thrown message naming the stage. */
|
|
57
|
+
private checkGLError;
|
|
58
|
+
/**
|
|
59
|
+
* Upload a new source image, (re)allocating all targets to it.
|
|
60
|
+
* Oversized sources are downscaled through a 2D canvas first (see
|
|
61
|
+
* MAX_DIM); old GL targets are deleted. Ends with a full render(),
|
|
62
|
+
* which resizes the canvas backing store to the output area.
|
|
63
|
+
* Throws with a message instead of rendering black on failure.
|
|
64
|
+
*/
|
|
65
|
+
setImage(source: TexImageSource): void;
|
|
66
|
+
/**
|
|
67
|
+
* Re-run all passes: copy source -> ping, then apply each edit in order,
|
|
68
|
+
* ping-ponging between the two working targets (`cur` holds the latest
|
|
69
|
+
* result, `nxt` is the scratch target; multi-pass edits may bounce
|
|
70
|
+
* between them internally and return either side). Geometric edits
|
|
71
|
+
* (crop/rotate) change dimensions: `nxt` is resized to the edit's
|
|
72
|
+
* outputDims before apply, `extra` is kept at the input size (sharpen
|
|
73
|
+
* scratch). Presents by resizing the canvas to the rendered area and
|
|
74
|
+
* blitting fullscreen 1:1. No-op when no image is loaded yet.
|
|
75
|
+
*/
|
|
76
|
+
render(): void;
|
|
77
|
+
/**
|
|
78
|
+
* RenderContext facade for Transform.apply(): exposes the pass/blit/gauss
|
|
79
|
+
* drawing primitives plus the scratch `extra` target, without handing
|
|
80
|
+
* out the raw WebGL context.
|
|
81
|
+
*/
|
|
82
|
+
private renderContext;
|
|
83
|
+
/** Resize a working target when geometry changed (returns live target). */
|
|
84
|
+
private ensureSize;
|
|
85
|
+
/**
|
|
86
|
+
* Decide float vs 8-bit ping-pong targets. Float needs both the
|
|
87
|
+
* renderable-float extension and float-linear filtering (every pass
|
|
88
|
+
* samples with LINEAR); either missing falls back to UNSIGNED_BYTE.
|
|
89
|
+
* Also verifies float renderability with a throwaway 4x4 target.
|
|
90
|
+
*/
|
|
91
|
+
private probeFloat;
|
|
92
|
+
/**
|
|
93
|
+
* Allocate one offscreen RGBA render target (texture + framebuffer) with
|
|
94
|
+
* linear filtering and clamp-to-edge (NPOT-safe: no mipmaps, no repeat).
|
|
95
|
+
*/
|
|
96
|
+
private makeTarget;
|
|
97
|
+
/**
|
|
98
|
+
* Compile one shader stage, throwing the info log on failure (a bad
|
|
99
|
+
* shader would otherwise render black with no indication why).
|
|
100
|
+
*/
|
|
101
|
+
private compile;
|
|
102
|
+
/** Compile+link the quad vertex shader with `frag`, cached by source. */
|
|
103
|
+
private program;
|
|
104
|
+
/**
|
|
105
|
+
* Draw one fullscreen pass: render `from` through `frag` into `to`.
|
|
106
|
+
* `from` is bound to unit 0 (`texture` uniform) unless the shader uses
|
|
107
|
+
* other sampler names; `extraTex` optionally binds a second texture
|
|
108
|
+
* (used by the sharpen mix pass). `setUniforms` fills the rest.
|
|
109
|
+
*/
|
|
110
|
+
pass(frag: string, from: Target, to: Target, setUniforms?: UniformSetter, extraTex?: ExtraTex): void;
|
|
111
|
+
/** Copy one target to another with the identity shader. */
|
|
112
|
+
blit(from: Target, to: Target): void;
|
|
113
|
+
/**
|
|
114
|
+
* One axis of the separable gaussian: `horizontal` picks the sample
|
|
115
|
+
* direction (offsets are in UV units, hence the 1/width division).
|
|
116
|
+
* The shader loops over a fixed 31-tap array; `kernel.length` tells it
|
|
117
|
+
* how many center taps carry real weight, the rest are zero-padded.
|
|
118
|
+
*/
|
|
119
|
+
gauss(from: Target, to: Target, horizontal: boolean, kernel: number[]): void;
|
|
120
|
+
/**
|
|
121
|
+
* Present the final result: resize the canvas backing store to the
|
|
122
|
+
* rendered output area (a no-op assignment when it already matches —
|
|
123
|
+
* setting width/height clears, so this only fires when geometry changed)
|
|
124
|
+
* and blit fullscreen 1:1. (The BLIT_FRAG flip still compensates the
|
|
125
|
+
* unflipped upload.)
|
|
126
|
+
*/
|
|
127
|
+
private toCanvas;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAiB,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAChG,OAAO,EAAc,KAAK,IAAI,EAAkB,MAAM,YAAY,CAAC;AAEnE,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAwB;IAClC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAmC;IAEnD,OAAO,CAAC,IAAI,CAA4B;IAIxC,OAAO,CAAC,GAAG,CAAuB;IAClC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IAEtB;;;;;;OAMG;gBACgB,MAAM,EAAE,iBAAiB;IA2B5C,sEAAsE;IACtE,IAAW,KAAK,IAAI,MAAM,CAEzB;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,4EAA4E;IACrE,QAAQ,IAAI,IAAI,EAAE;IAIzB,yEAAyE;IAClE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;IAKpC,kDAAkD;IAC3C,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAKhC,8CAA8C;IACvC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKtC,sCAAsC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAM/C,oEAAoE;IAC7D,UAAU,IAAI,IAAI;IAKzB,8CAA8C;IACvC,MAAM,IAAI,MAAM;IAIvB;;;;;;OAMG;IACH,gBAAuB,OAAO,QAAQ;IAEtC,2DAA2D;IAC3D,OAAO,CAAC,UAAU;IAelB,0EAA0E;IAC1E,OAAO,CAAC,YAAY;IAQpB;;;;;;OAMG;IACI,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAuD7C;;;;;;;;;OASG;IACI,MAAM,IAAI,IAAI;IAqCrB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAoBrB,2EAA2E;IAC3E,OAAO,CAAC,UAAU;IAelB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAqBlB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAiBlB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAcf,yEAAyE;IACzE,OAAO,CAAC,OAAO;IAoBf;;;;;OAKG;IACI,IAAI,CACT,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,WAAW,CAAC,EAAE,aAAa,EAC3B,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IA2BP,2DAA2D;IACpD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;;OAKG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAenF;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;CAsBjB"}
|