@radialapps/memories-vips-editor 0.1.2 → 0.1.5
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 +23 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/math.d.ts +25 -0
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +38 -4
- package/dist/math.js.map +1 -1
- package/dist/pipeline.d.ts +9 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +35 -23
- package/dist/pipeline.js.map +1 -1
- package/dist/shaders.d.ts +2 -3
- package/dist/shaders.d.ts.map +1 -1
- package/dist/shaders.js +9 -12
- package/dist/shaders.js.map +1 -1
- package/dist/smallPreview.d.ts +31 -0
- package/dist/smallPreview.d.ts.map +1 -0
- package/dist/smallPreview.js +118 -0
- package/dist/smallPreview.js.map +1 -0
- package/dist/transforms/crop.d.ts.map +1 -1
- package/dist/transforms/crop.js +7 -21
- package/dist/transforms/crop.js.map +1 -1
- package/dist/transforms/highlights.d.ts +17 -0
- package/dist/transforms/highlights.d.ts.map +1 -0
- package/dist/transforms/highlights.js +49 -0
- package/dist/transforms/highlights.js.map +1 -0
- package/dist/transforms/index.d.ts.map +1 -1
- package/dist/transforms/index.js +8 -2
- package/dist/transforms/index.js.map +1 -1
- package/dist/transforms/sepia.d.ts.map +1 -1
- package/dist/transforms/sepia.js +5 -4
- package/dist/transforms/sepia.js.map +1 -1
- package/dist/transforms/shadows.d.ts +17 -0
- package/dist/transforms/shadows.d.ts.map +1 -0
- package/dist/transforms/shadows.js +49 -0
- package/dist/transforms/shadows.js.map +1 -0
- package/dist/transforms/sharpen.js +1 -1
- package/dist/transforms/state.d.ts +1 -1
- package/dist/transforms/state.d.ts.map +1 -1
- package/dist/transforms/state.js +9 -9
- package/dist/transforms/state.js.map +1 -1
- package/dist/transforms/transform.d.ts +2 -2
- package/dist/transforms/transform.d.ts.map +1 -1
- package/dist/transforms/transform.js +4 -1
- package/dist/transforms/transform.js.map +1 -1
- package/dist/transforms/warmth.d.ts +17 -0
- package/dist/transforms/warmth.d.ts.map +1 -0
- package/dist/transforms/warmth.js +46 -0
- package/dist/transforms/warmth.js.map +1 -0
- package/dist/types.d.ts +5 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +4 -3
- package/src/math.ts +43 -4
- package/src/pipeline.ts +46 -22
- package/src/shaders.ts +9 -13
- package/src/smallPreview.ts +120 -0
- package/src/transforms/crop.ts +8 -17
- package/src/transforms/highlights.ts +67 -0
- package/src/transforms/index.ts +10 -4
- package/src/transforms/sepia.ts +5 -4
- package/src/transforms/shadows.ts +67 -0
- package/src/transforms/sharpen.ts +1 -1
- package/src/transforms/state.ts +7 -10
- package/src/transforms/transform.ts +8 -5
- package/src/transforms/warmth.ts +64 -0
- package/src/types.ts +9 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// smallPreview.ts — cheap small previews for an edit list.
|
|
2
|
+
//
|
|
3
|
+
// A SmallPreview owns one hidden WebGL canvas + EditPipeline plus a
|
|
4
|
+
// downscaled 2D copy of the source (longest side <= maxDim, default 512).
|
|
5
|
+
// setSource() downscales and uploads once; each render() then only re-runs
|
|
6
|
+
// the edit passes and snapshots the result into a fresh caller-owned 2D
|
|
7
|
+
// canvas — no re-upload, no shader recompile, no disturbance of any main
|
|
8
|
+
// preview canvas. Returning a snapshot (not the live canvas) keeps repeated
|
|
9
|
+
// renders safe to hold (e.g. a filmstrip of edit variants).
|
|
10
|
+
//
|
|
11
|
+
// Pixel radii (blur/sharpen) are in preview pixels here, so large radii look
|
|
12
|
+
// relatively stronger than at full res; everything else matches the main
|
|
13
|
+
// preview. Each instance holds one WebGL context: call dispose() when done
|
|
14
|
+
// (browsers cap live contexts at ~16 per page).
|
|
15
|
+
import { EditPipeline } from './pipeline.js';
|
|
16
|
+
export class SmallPreview {
|
|
17
|
+
constructor(maxDim = SmallPreview.MAX_DIM) {
|
|
18
|
+
this.pipe = null;
|
|
19
|
+
this.view = null;
|
|
20
|
+
this.hasSource = false;
|
|
21
|
+
if (!Number.isFinite(maxDim) || maxDim < 1)
|
|
22
|
+
throw new Error('SmallPreview: maxDim must be a number >= 1');
|
|
23
|
+
this.maxDim = Math.floor(maxDim);
|
|
24
|
+
}
|
|
25
|
+
/** Last render output size (downscaled source size when no geometric edit applies). */
|
|
26
|
+
get width() {
|
|
27
|
+
return this.pipe?.width ?? 0;
|
|
28
|
+
}
|
|
29
|
+
get height() {
|
|
30
|
+
return this.pipe?.height ?? 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Downscale `source` to <= maxDim (aspect-fit, never upscaled) through a
|
|
34
|
+
* 2D canvas and upload it once to the hidden pipeline. Replaces any
|
|
35
|
+
* previous source. Throws when WebGL/2D is unavailable.
|
|
36
|
+
*/
|
|
37
|
+
setSource(source) {
|
|
38
|
+
const dims = this.sourceDims(source);
|
|
39
|
+
if (!dims.w || !dims.h)
|
|
40
|
+
throw new Error('setSource: source has no width/height');
|
|
41
|
+
// drawImage() rejects ImageData: stage it through a 2D canvas first.
|
|
42
|
+
const drawable = EditPipeline.toDrawableSource(source);
|
|
43
|
+
const longest = Math.max(dims.w, dims.h);
|
|
44
|
+
const scale = longest > this.maxDim ? this.maxDim / longest : 1;
|
|
45
|
+
const w = Math.max(1, Math.round(dims.w * scale));
|
|
46
|
+
const h = Math.max(1, Math.round(dims.h * scale));
|
|
47
|
+
const base = document.createElement('canvas');
|
|
48
|
+
base.width = w;
|
|
49
|
+
base.height = h;
|
|
50
|
+
const g = base.getContext('2d');
|
|
51
|
+
if (!g)
|
|
52
|
+
throw new Error('setSource: 2D context unavailable for downscale');
|
|
53
|
+
g.imageSmoothingQuality = 'high';
|
|
54
|
+
g.drawImage(drawable, 0, 0, w, h);
|
|
55
|
+
if (!this.pipe || !this.view) {
|
|
56
|
+
const view = document.createElement('canvas');
|
|
57
|
+
this.view = view;
|
|
58
|
+
this.pipe = new EditPipeline(view);
|
|
59
|
+
}
|
|
60
|
+
this.pipe.setImage(base);
|
|
61
|
+
this.hasSource = true;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Render `edits` over the downscaled source and return the result as a
|
|
65
|
+
* fresh caller-owned 2D canvas (sized to the rendered output area).
|
|
66
|
+
* The hidden pipeline keeps its compiled programs between calls, so
|
|
67
|
+
* repeated renders only pay for the edit passes plus a small copy.
|
|
68
|
+
*/
|
|
69
|
+
render(edits) {
|
|
70
|
+
const pipe = this.pipe;
|
|
71
|
+
const view = this.view;
|
|
72
|
+
if (!pipe || !view || !this.hasSource)
|
|
73
|
+
throw new Error('render: no source (call setSource first)');
|
|
74
|
+
pipe.setEdits(edits);
|
|
75
|
+
const out = document.createElement('canvas');
|
|
76
|
+
out.width = pipe.width;
|
|
77
|
+
out.height = pipe.height;
|
|
78
|
+
const g = out.getContext('2d');
|
|
79
|
+
if (!g)
|
|
80
|
+
throw new Error('render: 2D context unavailable for snapshot');
|
|
81
|
+
// preserveDrawingBuffer (set by EditPipeline) keeps this reliable.
|
|
82
|
+
g.drawImage(view, 0, 0);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/** Release the hidden WebGL context; render() throws until setSource again. */
|
|
86
|
+
dispose() {
|
|
87
|
+
const view = this.view;
|
|
88
|
+
this.pipe = null;
|
|
89
|
+
this.view = null;
|
|
90
|
+
this.hasSource = false;
|
|
91
|
+
if (!view)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
// getContext('webgl') returns the existing context for this canvas.
|
|
95
|
+
view.getContext('webgl')?.getExtension('WEBGL_lose_context')?.loseContext();
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Context already gone — nothing to release.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Pixel size of any TexImageSource upload (mirrors EditPipeline). */
|
|
102
|
+
sourceDims(source) {
|
|
103
|
+
const anySrc = source;
|
|
104
|
+
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
105
|
+
const nw = num(anySrc['naturalWidth']);
|
|
106
|
+
const nh = num(anySrc['naturalHeight']);
|
|
107
|
+
if (nw > 0 && nh > 0)
|
|
108
|
+
return { w: nw, h: nh };
|
|
109
|
+
const vw = num(anySrc['videoWidth']);
|
|
110
|
+
const vh = num(anySrc['videoHeight']);
|
|
111
|
+
if (vw > 0 && vh > 0)
|
|
112
|
+
return { w: vw, h: vh };
|
|
113
|
+
return { w: num(anySrc['width']), h: num(anySrc['height']) };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Default longest side of the downscaled working copy. */
|
|
117
|
+
SmallPreview.MAX_DIM = 512;
|
|
118
|
+
//# sourceMappingURL=smallPreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smallPreview.js","sourceRoot":"","sources":["../src/smallPreview.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crop.d.ts","sourceRoot":"","sources":["../../src/transforms/crop.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"crop.d.ts","sourceRoot":"","sources":["../../src/transforms/crop.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAI/B,+EAA+E;AAC/E,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAMrD;AAaD,qBAAa,aAAc,YAAW,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC/D,SAAgB,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,EAAE,YAAY,EAAE,CAK7B;IAEK,QAAQ,IAAI,IAAI;IAIhB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE;IAsBpC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IASjC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAK5E,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM;CAUjF"}
|
package/dist/transforms/crop.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// [1px, remainder]; outputDims() shares it so the pipeline pre-sizes `to`.
|
|
7
7
|
import { clampf } from '../math.js';
|
|
8
8
|
import { isNumInRange, } from './transform.js';
|
|
9
|
+
const MIN_EXTENT = 1e-4;
|
|
9
10
|
/** Pixel rect for the given input size; identical to src/transforms/crop.h. */
|
|
10
11
|
export function cropRect(inW, inH, params) {
|
|
11
12
|
const left = Math.min(inW - 1, Math.max(0, Math.round(params.x * inW)));
|
|
@@ -61,27 +62,12 @@ export class CropTransform {
|
|
|
61
62
|
return errs;
|
|
62
63
|
}
|
|
63
64
|
normalize(params) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
else
|
|
71
|
-
w = Math.min(w, 1 - x);
|
|
72
|
-
if (!(h > 0))
|
|
73
|
-
h = Math.min(1, Math.max(1e-4, 1 - y));
|
|
74
|
-
else
|
|
75
|
-
h = Math.min(h, 1 - y);
|
|
76
|
-
if (!(w > 0)) {
|
|
77
|
-
w = 1e-4;
|
|
78
|
-
x = 1 - w;
|
|
79
|
-
}
|
|
80
|
-
if (!(h > 0)) {
|
|
81
|
-
h = 1e-4;
|
|
82
|
-
y = 1 - h;
|
|
83
|
-
}
|
|
84
|
-
return { edit: 'crop', x, y, width: w, height: h };
|
|
65
|
+
// Keep at least MIN_EXTENT of frame: the renderer rounds that to 1px.
|
|
66
|
+
const x = clampf(0, params.x ?? 0, 1 - MIN_EXTENT);
|
|
67
|
+
const y = clampf(0, params.y ?? 0, 1 - MIN_EXTENT);
|
|
68
|
+
const width = clampf(MIN_EXTENT, params.width ?? 1, 1 - x);
|
|
69
|
+
const height = clampf(MIN_EXTENT, params.height ?? 1, 1 - y);
|
|
70
|
+
return { edit: 'crop', x, y, width, height };
|
|
85
71
|
}
|
|
86
72
|
outputDims(inW, inH, params) {
|
|
87
73
|
const r = cropRect(inW, inH, params);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crop.js","sourceRoot":"","sources":["../../src/transforms/crop.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,mEAAmE;AACnE,2EAA2E;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,YAAY,GAKb,MAAM,gBAAgB,CAAC;AAgBxB,+EAA+E;AAC/E,MAAM,UAAU,QAAQ,CACtB,GAAW,EACX,GAAW,EACX,MAAY;IAEZ,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;CASZ,CAAC;AAEF,MAAM,OAAO,aAAa;IAA1B;QACkB,SAAI,GAAG,MAAe,CAAC;QAChC,aAAQ,GAAmB;YAChC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;YAC5D,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;YAC5D,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;YACpE,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;SACvE,CAAC;
|
|
1
|
+
{"version":3,"file":"crop.js","sourceRoot":"","sources":["../../src/transforms/crop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ParamControl, type RenderContext, type Target, type Transform } from './transform.js';
|
|
2
|
+
export interface HighlightsEdit {
|
|
3
|
+
edit: 'highlights';
|
|
4
|
+
/** -1 (recover highlights) .. 1 (boost highlights). Default 0. */
|
|
5
|
+
amount?: number;
|
|
6
|
+
}
|
|
7
|
+
type Full = Required<HighlightsEdit>;
|
|
8
|
+
export declare class HighlightsTransform implements Transform<'highlights', HighlightsEdit> {
|
|
9
|
+
readonly edit: "highlights";
|
|
10
|
+
controls: ParamControl[];
|
|
11
|
+
defaults(): Full;
|
|
12
|
+
validate(params: HighlightsEdit): string[];
|
|
13
|
+
normalize(params: HighlightsEdit): Full;
|
|
14
|
+
apply(ctx: RenderContext, from: Target, to: Target, params: Full): Target;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=highlights.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlights.d.ts","sourceRoot":"","sources":["../../src/transforms/highlights.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAiBrC,qBAAa,mBAAoB,YAAW,SAAS,CAAC,YAAY,EAAE,cAAc,CAAC;IACjF,SAAgB,IAAI,EAAG,YAAY,CAAU;IACtC,QAAQ,EAAE,YAAY,EAAE,CAE7B;IAEK,QAAQ,IAAI,IAAI;IAIhB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE;IAM1C,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIvC,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM;CAMjF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// highlights.ts — boost/recover the bright end, weighted by brightness.
|
|
2
|
+
//
|
|
3
|
+
// weight w = clamp(avg,0,1)^2 (0 in blacks, 1 in whites, quadratic falloff),
|
|
4
|
+
// then rgb += (amount * 0.5) * w. The 0.5 keeps the gray curve monotonic over
|
|
5
|
+
// the whole slider range (a full-strength recovery would push white below
|
|
6
|
+
// near-white). Same formula in src/transforms/highlights.h and
|
|
7
|
+
// math.ts applyHighlights, so the canvas preview is WYSIWYG.
|
|
8
|
+
import { clampf } from '../math.js';
|
|
9
|
+
import { isNumInRange, setFloatUniform, } from './transform.js';
|
|
10
|
+
const FRAG = `
|
|
11
|
+
precision mediump float;
|
|
12
|
+
uniform sampler2D texture;
|
|
13
|
+
uniform float amount;
|
|
14
|
+
varying vec2 texCoord;
|
|
15
|
+
void main() {
|
|
16
|
+
vec4 color = texture2D(texture, texCoord);
|
|
17
|
+
float avg = (color.r + color.g + color.b) / 3.0;
|
|
18
|
+
float l = clamp(avg, 0.0, 1.0);
|
|
19
|
+
float w = l * l;
|
|
20
|
+
color.rgb += (amount * 0.5) * w;
|
|
21
|
+
gl_FragColor = color;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
export class HighlightsTransform {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.edit = 'highlights';
|
|
27
|
+
this.controls = [
|
|
28
|
+
{ key: 'amount', label: 'amount', min: -1, max: 1, step: 0.01, def: 0 },
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
defaults() {
|
|
32
|
+
return { edit: 'highlights', amount: 0 };
|
|
33
|
+
}
|
|
34
|
+
validate(params) {
|
|
35
|
+
if (params.amount !== undefined && !isNumInRange(params.amount, -1, 1))
|
|
36
|
+
return ['amount must be a number in [-1,1]'];
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
normalize(params) {
|
|
40
|
+
return { edit: 'highlights', amount: clampf(-1, params.amount ?? 0, 1) };
|
|
41
|
+
}
|
|
42
|
+
apply(ctx, from, to, params) {
|
|
43
|
+
ctx.pass(FRAG, from, to, (gl, p) => {
|
|
44
|
+
setFloatUniform(gl, p, 'amount', params.amount);
|
|
45
|
+
});
|
|
46
|
+
return to;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=highlights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlights.js","sourceRoot":"","sources":["../../src/transforms/highlights.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,0EAA0E;AAC1E,+DAA+D;AAC/D,6DAA6D;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,YAAY,EACZ,eAAe,GAKhB,MAAM,gBAAgB,CAAC;AAUxB,MAAM,IAAI,GAAG;;;;;;;;;;;;;CAaZ,CAAC;AAEF,MAAM,OAAO,mBAAmB;IAAhC;QACkB,SAAI,GAAG,YAAqB,CAAC;QACtC,aAAQ,GAAmB;YAChC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;SACxE,CAAC;IAsBJ,CAAC;IApBQ,QAAQ;QACb,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC3C,CAAC;IAEM,QAAQ,CAAC,MAAsB;QACpC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,mCAAmC,CAAC,CAAC;QAC/C,OAAO,EAAE,CAAC;IACZ,CAAC;IAEM,SAAS,CAAC,MAAsB;QACrC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC3E,CAAC;IAEM,KAAK,CAAC,GAAkB,EAAE,IAAY,EAAE,EAAU,EAAE,MAAY;QACrE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YACjC,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAiBxD,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBlE,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAKjD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAI9C"}
|
package/dist/transforms/index.js
CHANGED
|
@@ -4,13 +4,16 @@ import { BrightnessContrastTransform } from './brightnessContrast.js';
|
|
|
4
4
|
import { CropTransform } from './crop.js';
|
|
5
5
|
import { ExposureTransform } from './exposure.js';
|
|
6
6
|
import { GrayscaleTransform } from './grayscale.js';
|
|
7
|
+
import { HighlightsTransform } from './highlights.js';
|
|
7
8
|
import { HueSaturationTransform } from './hueSaturation.js';
|
|
8
9
|
import { InvertTransform } from './invert.js';
|
|
9
10
|
import { RotateTransform } from './rotate.js';
|
|
10
11
|
import { SepiaTransform } from './sepia.js';
|
|
12
|
+
import { ShadowsTransform } from './shadows.js';
|
|
11
13
|
import { SharpenTransform } from './sharpen.js';
|
|
12
14
|
import { VibranceTransform } from './vibrance.js';
|
|
13
15
|
import { VignetteTransform } from './vignette.js';
|
|
16
|
+
import { WarmthTransform } from './warmth.js';
|
|
14
17
|
export const TRANSFORMS = {
|
|
15
18
|
brightnessContrast: new BrightnessContrastTransform(),
|
|
16
19
|
exposure: new ExposureTransform(),
|
|
@@ -20,6 +23,9 @@ export const TRANSFORMS = {
|
|
|
20
23
|
blur: new BlurTransform(),
|
|
21
24
|
sharpen: new SharpenTransform(),
|
|
22
25
|
vignette: new VignetteTransform(),
|
|
26
|
+
shadows: new ShadowsTransform(),
|
|
27
|
+
highlights: new HighlightsTransform(),
|
|
28
|
+
warmth: new WarmthTransform(),
|
|
23
29
|
invert: new InvertTransform(),
|
|
24
30
|
grayscale: new GrayscaleTransform(),
|
|
25
31
|
crop: new CropTransform(),
|
|
@@ -31,14 +37,14 @@ export function validateEdit(edit) {
|
|
|
31
37
|
return ['edit must be an object'];
|
|
32
38
|
const t = lookup(TRANSFORMS, edit.edit);
|
|
33
39
|
if (!t)
|
|
34
|
-
return [`unknown edit ${edit.edit}`];
|
|
40
|
+
return [`unknown edit ${String(edit.edit)}`];
|
|
35
41
|
return t.validate(edit);
|
|
36
42
|
}
|
|
37
43
|
/** Fill defaults + clamp, so serialized JSON always passes validateEdit. */
|
|
38
44
|
export function normalizeEdit(edit) {
|
|
39
45
|
const t = lookup(TRANSFORMS, edit.edit);
|
|
40
46
|
if (!t)
|
|
41
|
-
throw new Error(`unknown edit ${edit.edit}`);
|
|
47
|
+
throw new Error(`unknown edit ${String(edit.edit)}`);
|
|
42
48
|
return t.normalize(edit);
|
|
43
49
|
}
|
|
44
50
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAkB,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAkB,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,UAAU,GAAgD;IACrE,kBAAkB,EAAE,IAAI,2BAA2B,EAAE;IACrD,QAAQ,EAAE,IAAI,iBAAiB,EAAE;IACjC,aAAa,EAAE,IAAI,sBAAsB,EAAE;IAC3C,KAAK,EAAE,IAAI,cAAc,EAAE;IAC3B,QAAQ,EAAE,IAAI,iBAAiB,EAAE;IACjC,IAAI,EAAE,IAAI,aAAa,EAAE;IACzB,OAAO,EAAE,IAAI,gBAAgB,EAAE;IAC/B,QAAQ,EAAE,IAAI,iBAAiB,EAAE;IACjC,OAAO,EAAE,IAAI,gBAAgB,EAAE;IAC/B,UAAU,EAAE,IAAI,mBAAmB,EAAE;IACrC,MAAM,EAAE,IAAI,eAAe,EAAE;IAC7B,MAAM,EAAE,IAAI,eAAe,EAAE;IAC7B,SAAS,EAAE,IAAI,kBAAkB,EAAE;IACnC,IAAI,EAAE,IAAI,aAAa,EAAE;IACzB,MAAM,EAAE,IAAI,eAAe,EAAE;CAC9B,CAAC;AAEF,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACjF,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,CAAS,CAAC;AACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sepia.d.ts","sourceRoot":"","sources":["../../src/transforms/sepia.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sepia.d.ts","sourceRoot":"","sources":["../../src/transforms/sepia.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAmBhC,qBAAa,cAAe,YAAW,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;IAClE,SAAgB,IAAI,EAAG,OAAO,CAAU;IACjC,QAAQ,EAAE,YAAY,EAAE,CAE7B;IAEK,QAAQ,IAAI,IAAI;IAIhB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE;IAMrC,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIlC,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM;CAMjF"}
|
package/dist/transforms/sepia.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// sepia.ts — glfx.js sepia port.
|
|
1
|
+
// sepia.ts — glfx.js sepia port, minus its per-channel min(1.0): like the VIPS
|
|
2
|
+
// side, values stay unclipped until the end so later edits see the same input.
|
|
2
3
|
import { clampf } from '../math.js';
|
|
3
4
|
import { isNumInRange, setFloatUniform, } from './transform.js';
|
|
4
5
|
const FRAG = `
|
|
@@ -11,9 +12,9 @@ void main() {
|
|
|
11
12
|
float r = color.r;
|
|
12
13
|
float g = color.g;
|
|
13
14
|
float b = color.b;
|
|
14
|
-
color.r =
|
|
15
|
-
color.g =
|
|
16
|
-
color.b =
|
|
15
|
+
color.r = (r * (1.0 - (0.607 * amount))) + (g * (0.769 * amount)) + (b * (0.189 * amount));
|
|
16
|
+
color.g = (r * 0.349 * amount) + (g * (1.0 - (0.314 * amount))) + (b * 0.168 * amount);
|
|
17
|
+
color.b = (r * 0.272 * amount) + (g * 0.534 * amount) + (b * (1.0 - (0.869 * amount)));
|
|
17
18
|
gl_FragColor = color;
|
|
18
19
|
}
|
|
19
20
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sepia.js","sourceRoot":"","sources":["../../src/transforms/sepia.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sepia.js","sourceRoot":"","sources":["../../src/transforms/sepia.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,YAAY,EACZ,eAAe,GAKhB,MAAM,gBAAgB,CAAC;AAUxB,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;CAeZ,CAAC;AAEF,MAAM,OAAO,cAAc;IAA3B;QACkB,SAAI,GAAG,OAAgB,CAAC;QACjC,aAAQ,GAAmB;YAChC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;SACvE,CAAC;IAsBJ,CAAC;IApBQ,QAAQ;QACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtC,CAAC;IAEM,QAAQ,CAAC,MAAiB;QAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,kCAAkC,CAAC,CAAC;QAC9C,OAAO,EAAE,CAAC;IACZ,CAAC;IAEM,SAAS,CAAC,MAAiB;QAChC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC;IAEM,KAAK,CAAC,GAAkB,EAAE,IAAY,EAAE,EAAU,EAAE,MAAY;QACrE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YACjC,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ParamControl, type RenderContext, type Target, type Transform } from './transform.js';
|
|
2
|
+
export interface ShadowsEdit {
|
|
3
|
+
edit: 'shadows';
|
|
4
|
+
/** -1 (crush shadows) .. 1 (lift shadows). Default 0. */
|
|
5
|
+
amount?: number;
|
|
6
|
+
}
|
|
7
|
+
type Full = Required<ShadowsEdit>;
|
|
8
|
+
export declare class ShadowsTransform implements Transform<'shadows', ShadowsEdit> {
|
|
9
|
+
readonly edit: "shadows";
|
|
10
|
+
controls: ParamControl[];
|
|
11
|
+
defaults(): Full;
|
|
12
|
+
validate(params: ShadowsEdit): string[];
|
|
13
|
+
normalize(params: ShadowsEdit): Full;
|
|
14
|
+
apply(ctx: RenderContext, from: Target, to: Target, params: Full): Target;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=shadows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadows.d.ts","sourceRoot":"","sources":["../../src/transforms/shadows.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAiBlC,qBAAa,gBAAiB,YAAW,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC;IACxE,SAAgB,IAAI,EAAG,SAAS,CAAU;IACnC,QAAQ,EAAE,YAAY,EAAE,CAE7B;IAEK,QAAQ,IAAI,IAAI;IAIhB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE;IAMvC,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIpC,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM;CAMjF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// shadows.ts — lift/crush the dark end, weighted by darkness.
|
|
2
|
+
//
|
|
3
|
+
// weight w = (1 - clamp(avg,0,1))^2 (1 in blacks, 0 in whites, quadratic
|
|
4
|
+
// falloff), then rgb += (amount * 0.5) * w. The 0.5 keeps the gray curve
|
|
5
|
+
// monotonic over the whole slider range (a full-strength lift would reverse
|
|
6
|
+
// deep shadows past mid-gray). Same formula in src/transforms/shadows.h
|
|
7
|
+
// and math.ts applyShadows, so the canvas preview is WYSIWYG.
|
|
8
|
+
import { clampf } from '../math.js';
|
|
9
|
+
import { isNumInRange, setFloatUniform, } from './transform.js';
|
|
10
|
+
const FRAG = `
|
|
11
|
+
precision mediump float;
|
|
12
|
+
uniform sampler2D texture;
|
|
13
|
+
uniform float amount;
|
|
14
|
+
varying vec2 texCoord;
|
|
15
|
+
void main() {
|
|
16
|
+
vec4 color = texture2D(texture, texCoord);
|
|
17
|
+
float avg = (color.r + color.g + color.b) / 3.0;
|
|
18
|
+
float l = clamp(avg, 0.0, 1.0);
|
|
19
|
+
float w = (1.0 - l) * (1.0 - l);
|
|
20
|
+
color.rgb += (amount * 0.5) * w;
|
|
21
|
+
gl_FragColor = color;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
export class ShadowsTransform {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.edit = 'shadows';
|
|
27
|
+
this.controls = [
|
|
28
|
+
{ key: 'amount', label: 'amount', min: -1, max: 1, step: 0.01, def: 0 },
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
defaults() {
|
|
32
|
+
return { edit: 'shadows', amount: 0 };
|
|
33
|
+
}
|
|
34
|
+
validate(params) {
|
|
35
|
+
if (params.amount !== undefined && !isNumInRange(params.amount, -1, 1))
|
|
36
|
+
return ['amount must be a number in [-1,1]'];
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
normalize(params) {
|
|
40
|
+
return { edit: 'shadows', amount: clampf(-1, params.amount ?? 0, 1) };
|
|
41
|
+
}
|
|
42
|
+
apply(ctx, from, to, params) {
|
|
43
|
+
ctx.pass(FRAG, from, to, (gl, p) => {
|
|
44
|
+
setFloatUniform(gl, p, 'amount', params.amount);
|
|
45
|
+
});
|
|
46
|
+
return to;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=shadows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadows.js","sourceRoot":"","sources":["../../src/transforms/shadows.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AACxE,8DAA8D;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,YAAY,EACZ,eAAe,GAKhB,MAAM,gBAAgB,CAAC;AAUxB,MAAM,IAAI,GAAG;;;;;;;;;;;;;CAaZ,CAAC;AAEF,MAAM,OAAO,gBAAgB;IAA7B;QACkB,SAAI,GAAG,SAAkB,CAAC;QACnC,aAAQ,GAAmB;YAChC,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;SACxE,CAAC;IAsBJ,CAAC;IApBQ,QAAQ;QACb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACxC,CAAC;IAEM,QAAQ,CAAC,MAAmB;QACjC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,mCAAmC,CAAC,CAAC;QAC/C,OAAO,EAAE,CAAC;IACZ,CAAC;IAEM,SAAS,CAAC,MAAmB;QAClC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACxE,CAAC;IAEM,KAAK,CAAC,GAAkB,EAAE,IAAY,EAAE,EAAU,EAAE,MAAY;QACrE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YACjC,eAAe,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -10,7 +10,7 @@ varying vec2 texCoord;
|
|
|
10
10
|
void main() {
|
|
11
11
|
vec4 blurred = texture2D(blurredTexture, texCoord);
|
|
12
12
|
vec4 original = texture2D(originalTexture, texCoord);
|
|
13
|
-
gl_FragColor = mix(blurred, original, 1.0 + strength);
|
|
13
|
+
gl_FragColor = vec4(mix(blurred.rgb, original.rgb, 1.0 + strength), original.a);
|
|
14
14
|
}
|
|
15
15
|
`;
|
|
16
16
|
export class SharpenTransform {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EditState } from '../types.js';
|
|
2
2
|
export declare function validateState(state: EditState): string[];
|
|
3
3
|
export declare function stateToJSON(state: EditState): string;
|
|
4
4
|
/** Parse + normalize; throws on invalid shape. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/transforms/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/transforms/state.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjE,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CASxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEpD;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAKrD"}
|
package/dist/transforms/state.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
// transforms/state.ts — {version, edits} state validation/serialization.
|
|
2
|
+
import { EDIT_STATE_VERSION } from '../types.js';
|
|
1
3
|
import { normalizeEdit, validateEdit } from './index.js';
|
|
2
4
|
export function validateState(state) {
|
|
3
|
-
const errs = [];
|
|
4
5
|
if (typeof state !== 'object' || state === null)
|
|
5
6
|
return ['state must be an object'];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return errs;
|
|
11
|
-
}
|
|
7
|
+
const errs = [];
|
|
8
|
+
if (state.version !== EDIT_STATE_VERSION)
|
|
9
|
+
errs.push(`version must be ${EDIT_STATE_VERSION}`);
|
|
10
|
+
if (!Array.isArray(state.edits))
|
|
11
|
+
return [...errs, 'edits must be an array'];
|
|
12
12
|
state.edits.forEach((edit, i) => {
|
|
13
13
|
for (const e of validateEdit(edit))
|
|
14
14
|
errs.push(`edits[${i}]: ${e}`);
|
|
@@ -16,7 +16,7 @@ export function validateState(state) {
|
|
|
16
16
|
return errs;
|
|
17
17
|
}
|
|
18
18
|
export function stateToJSON(state) {
|
|
19
|
-
return JSON.stringify({ version:
|
|
19
|
+
return JSON.stringify({ version: EDIT_STATE_VERSION, edits: state.edits.map(normalizeEdit) });
|
|
20
20
|
}
|
|
21
21
|
/** Parse + normalize; throws on invalid shape. */
|
|
22
22
|
export function stateFromJSON(json) {
|
|
@@ -24,6 +24,6 @@ export function stateFromJSON(json) {
|
|
|
24
24
|
const errs = validateState(raw);
|
|
25
25
|
if (errs.length > 0)
|
|
26
26
|
throw new Error(`invalid edit state: ${errs.join('; ')}`);
|
|
27
|
-
return { version:
|
|
27
|
+
return { version: EDIT_STATE_VERSION, edits: raw.edits.map(normalizeEdit) };
|
|
28
28
|
}
|
|
29
29
|
//# sourceMappingURL=state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/transforms/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/transforms/state.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,OAAO,EAAE,kBAAkB,EAAkB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,UAAU,aAAa,CAAC,KAAgB;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACpF,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAAK,CAAC,OAAO,KAAK,kBAAkB;QAAE,IAAI,CAAC,IAAI,CAAC,mBAAmB,kBAAkB,EAAE,CAAC,CAAC;IAC7F,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC;IAC5E,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC9B,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAgB;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;AAChG,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IAC1C,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;AAC9E,CAAC"}
|
|
@@ -63,6 +63,6 @@ export interface Transform<Name extends string, P extends object> {
|
|
|
63
63
|
/** Number in [lo,hi], finite. Shared range check for validate(). */
|
|
64
64
|
export declare function isNumInRange(v: unknown, lo: number, hi: number): boolean;
|
|
65
65
|
export declare function setFloatUniform(gl: WebGLRenderingContext, prog: WebGLProgram, name: string, value: number): void;
|
|
66
|
-
/**
|
|
67
|
-
export declare function lookup(registry: Record<EditName, Transform<string, object>>, name:
|
|
66
|
+
/** Unknown runtime names (including Object.prototype keys) yield undefined. */
|
|
67
|
+
export declare function lookup(registry: Record<EditName, Transform<string, object>>, name: unknown): Transform<string, object> | undefined;
|
|
68
68
|
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/transforms/transform.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/transforms/transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,11 @@ export function setFloatUniform(gl, prog, name, value) {
|
|
|
7
7
|
if (u)
|
|
8
8
|
gl.uniform1f(u, value);
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
10
|
+
/** Unknown runtime names (including Object.prototype keys) yield undefined. */
|
|
11
11
|
export function lookup(registry, name) {
|
|
12
|
+
if (typeof name !== 'string' || !Object.prototype.hasOwnProperty.call(registry, name)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
12
15
|
return registry[name];
|
|
13
16
|
}
|
|
14
17
|
//# sourceMappingURL=transform.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/transforms/transform.ts"],"names":[],"mappings":"AA+EA,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,CAAU,EAAE,EAAU,EAAE,EAAU;IAC7D,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,EAAyB,EACzB,IAAkB,EAClB,IAAY,EACZ,KAAa;IAEb,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAChC,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/transforms/transform.ts"],"names":[],"mappings":"AA+EA,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,CAAU,EAAE,EAAU,EAAE,EAAU;IAC7D,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,EAAyB,EACzB,IAAkB,EAClB,IAAY,EACZ,KAAa;IAEb,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,MAAM,CACpB,QAAqD,EACrD,IAAa;IAEb,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;QACtF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,QAAQ,CAAC,IAAgB,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ParamControl, type RenderContext, type Target, type Transform } from './transform.js';
|
|
2
|
+
export interface WarmthEdit {
|
|
3
|
+
edit: 'warmth';
|
|
4
|
+
/** -1 (cool) .. 1 (warm). Default 0. */
|
|
5
|
+
amount?: number;
|
|
6
|
+
}
|
|
7
|
+
type Full = Required<WarmthEdit>;
|
|
8
|
+
export declare class WarmthTransform implements Transform<'warmth', WarmthEdit> {
|
|
9
|
+
readonly edit: "warmth";
|
|
10
|
+
controls: ParamControl[];
|
|
11
|
+
defaults(): Full;
|
|
12
|
+
validate(params: WarmthEdit): string[];
|
|
13
|
+
normalize(params: WarmthEdit): Full;
|
|
14
|
+
apply(ctx: RenderContext, from: Target, to: Target, params: Full): Target;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=warmth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmth.d.ts","sourceRoot":"","sources":["../../src/transforms/warmth.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAejC,qBAAa,eAAgB,YAAW,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC;IACrE,SAAgB,IAAI,EAAG,QAAQ,CAAU;IAClC,QAAQ,EAAE,YAAY,EAAE,CAE7B;IAEK,QAAQ,IAAI,IAAI;IAIhB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE;IAMtC,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAInC,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM;CAMjF"}
|