@magicpages/kalotyp-core 0.1.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 (81) hide show
  1. package/dist/canvas/bake-canvas.d.ts +25 -0
  2. package/dist/canvas/bake-canvas.d.ts.map +1 -0
  3. package/dist/canvas/load-image.d.ts +16 -0
  4. package/dist/canvas/load-image.d.ts.map +1 -0
  5. package/dist/canvas/viewport-controller.d.ts +46 -0
  6. package/dist/canvas/viewport-controller.d.ts.map +1 -0
  7. package/dist/canvas/viewport.d.ts +43 -0
  8. package/dist/canvas/viewport.d.ts.map +1 -0
  9. package/dist/events/event-bus.d.ts +10 -0
  10. package/dist/events/event-bus.d.ts.map +1 -0
  11. package/dist/geometry/rect.d.ts +35 -0
  12. package/dist/geometry/rect.d.ts.map +1 -0
  13. package/dist/history/history.d.ts +38 -0
  14. package/dist/history/history.d.ts.map +1 -0
  15. package/dist/index.d.ts +46 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +1976 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/output/state.d.ts +27 -0
  20. package/dist/output/state.d.ts.map +1 -0
  21. package/dist/pipeline/encode.d.ts +27 -0
  22. package/dist/pipeline/encode.d.ts.map +1 -0
  23. package/dist/pipeline/exif.d.ts +16 -0
  24. package/dist/pipeline/exif.d.ts.map +1 -0
  25. package/dist/pipeline/run-chain.d.ts +10 -0
  26. package/dist/pipeline/run-chain.d.ts.map +1 -0
  27. package/dist/plugins/annotate/bake.d.ts +16 -0
  28. package/dist/plugins/annotate/bake.d.ts.map +1 -0
  29. package/dist/plugins/annotate/geometry.d.ts +36 -0
  30. package/dist/plugins/annotate/geometry.d.ts.map +1 -0
  31. package/dist/plugins/annotate/hit-test.d.ts +8 -0
  32. package/dist/plugins/annotate/hit-test.d.ts.map +1 -0
  33. package/dist/plugins/annotate/smooth.d.ts +16 -0
  34. package/dist/plugins/annotate/smooth.d.ts.map +1 -0
  35. package/dist/plugins/annotate/state.d.ts +176 -0
  36. package/dist/plugins/annotate/state.d.ts.map +1 -0
  37. package/dist/plugins/crop/aspect-ratio.d.ts +15 -0
  38. package/dist/plugins/crop/aspect-ratio.d.ts.map +1 -0
  39. package/dist/plugins/crop/bake.d.ts +13 -0
  40. package/dist/plugins/crop/bake.d.ts.map +1 -0
  41. package/dist/plugins/crop/preset-filter.d.ts +10 -0
  42. package/dist/plugins/crop/preset-filter.d.ts.map +1 -0
  43. package/dist/plugins/crop/resize.d.ts +19 -0
  44. package/dist/plugins/crop/resize.d.ts.map +1 -0
  45. package/dist/plugins/crop/state.d.ts +23 -0
  46. package/dist/plugins/crop/state.d.ts.map +1 -0
  47. package/dist/plugins/filter/presets.d.ts +19 -0
  48. package/dist/plugins/filter/presets.d.ts.map +1 -0
  49. package/dist/plugins/finetune/bake.d.ts +5 -0
  50. package/dist/plugins/finetune/bake.d.ts.map +1 -0
  51. package/dist/plugins/finetune/math.d.ts +32 -0
  52. package/dist/plugins/finetune/math.d.ts.map +1 -0
  53. package/dist/plugins/finetune/state.d.ts +31 -0
  54. package/dist/plugins/finetune/state.d.ts.map +1 -0
  55. package/dist/plugins/flip/bake.d.ts +5 -0
  56. package/dist/plugins/flip/bake.d.ts.map +1 -0
  57. package/dist/plugins/flip/state.d.ts +9 -0
  58. package/dist/plugins/flip/state.d.ts.map +1 -0
  59. package/dist/plugins/frame/bake.d.ts +16 -0
  60. package/dist/plugins/frame/bake.d.ts.map +1 -0
  61. package/dist/plugins/frame/state.d.ts +29 -0
  62. package/dist/plugins/frame/state.d.ts.map +1 -0
  63. package/dist/plugins/redact/bake.d.ts +13 -0
  64. package/dist/plugins/redact/bake.d.ts.map +1 -0
  65. package/dist/plugins/redact/state.d.ts +112 -0
  66. package/dist/plugins/redact/state.d.ts.map +1 -0
  67. package/dist/plugins/resize/bake.d.ts +9 -0
  68. package/dist/plugins/resize/bake.d.ts.map +1 -0
  69. package/dist/plugins/resize/state.d.ts +37 -0
  70. package/dist/plugins/resize/state.d.ts.map +1 -0
  71. package/dist/plugins/rotate/bake.d.ts +9 -0
  72. package/dist/plugins/rotate/bake.d.ts.map +1 -0
  73. package/dist/plugins/rotate/inscribe.d.ts +14 -0
  74. package/dist/plugins/rotate/inscribe.d.ts.map +1 -0
  75. package/dist/plugins/rotate/state.d.ts +21 -0
  76. package/dist/plugins/rotate/state.d.ts.map +1 -0
  77. package/dist/plugins/utility.d.ts +59 -0
  78. package/dist/plugins/utility.d.ts.map +1 -0
  79. package/dist/state/store.d.ts +14 -0
  80. package/dist/state/store.d.ts.map +1 -0
  81. package/package.json +52 -0
@@ -0,0 +1,10 @@
1
+ import type { SourceImage, UtilityId, UtilityPlugin } from '../plugins/utility.js';
2
+ /** One link in the editor's transform pipeline, with the plugin state at Save time. */
3
+ export interface ChainLink<TState extends object = object> {
4
+ readonly id: UtilityId;
5
+ readonly plugin: UtilityPlugin<TState>;
6
+ readonly state: TState;
7
+ }
8
+ /** Apply each plugin's `bake` in sequence; result of each link feeds the next. */
9
+ export declare function runUtilityChain(links: readonly ChainLink[], source: SourceImage): Promise<SourceImage>;
10
+ //# sourceMappingURL=run-chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-chain.d.ts","sourceRoot":"","sources":["../../src/pipeline/run-chain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEnF,uFAAuF;AACvF,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACvD,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,kFAAkF;AAClF,wBAAsB,eAAe,CACnC,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAMtB"}
@@ -0,0 +1,16 @@
1
+ import type { SourceImage } from '../utility.js';
2
+ import { type Shape } from './state.js';
3
+ export interface AnnotateBakeInput {
4
+ readonly shapes: ReadonlyArray<Shape>;
5
+ }
6
+ /**
7
+ * System font stack used at bake; matches what the preview canvas renders.
8
+ * No web font is loaded — the bundle budget rules it out and the bake
9
+ * pipeline has no "wait for font" affordance.
10
+ */
11
+ export declare const SYSTEM_FONT_STACK = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif";
12
+ /** Paint every shape onto a fresh canvas at the source's dimensions. */
13
+ export declare function bakeAnnotate(state: AnnotateBakeInput, source: SourceImage): Promise<SourceImage>;
14
+ /** Paint one shape; caller positions the context for image-space coordinates. Shared by preview and bake. */
15
+ export declare function paintShape(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, shape: Shape): void;
16
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,mGACgE,CAAC;AAE/F,wEAAwE;AACxE,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAoBtB;AAED,6GAA6G;AAC7G,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,GAAG,iCAAiC,EACjE,KAAK,EAAE,KAAK,GACX,IAAI,CAuBN"}
@@ -0,0 +1,36 @@
1
+ import type { Rect } from '../../geometry/rect.js';
2
+ import { type Shape } from './state.js';
3
+ /**
4
+ * Axis-aligned bounding box in image-space pixels. Text uses a font-metric
5
+ * estimate because jsdom's `measureText` returns 0; the renderer measures
6
+ * real text at paint time.
7
+ */
8
+ export declare function boundingBoxOf(shape: Shape): Rect;
9
+ /**
10
+ * Eight-handle layout (corners + edges). Arrows reuse `tl`/`br` as
11
+ * endpoint handles; callers detect arrow handles by shape kind.
12
+ */
13
+ export type SelectionHandle = 'tl' | 'tr' | 'bl' | 'br' | 't' | 'r' | 'b' | 'l';
14
+ export declare const ALL_SELECTION_HANDLES: readonly SelectionHandle[];
15
+ /** Image-space coordinates for each handle; renderer projects to display. */
16
+ export declare function selectionHandlePositions(rect: Rect): Record<SelectionHandle, {
17
+ x: number;
18
+ y: number;
19
+ }>;
20
+ /** Apply a handle drag to a rect. Returns the new rect; the caller normalises. */
21
+ export declare function rectFromHandleDrag(initial: Rect, handle: SelectionHandle, pointer: {
22
+ x: number;
23
+ y: number;
24
+ }): Rect;
25
+ /**
26
+ * Estimate painted text size without `measureText` (jsdom returns 0).
27
+ * Uses 0.55em mean Latin char width and 1.2em line height — close enough
28
+ * for selection-handle placement.
29
+ */
30
+ export declare function estimateTextSize(text: string, fontSize: number): {
31
+ width: number;
32
+ height: number;
33
+ };
34
+ /** Convert a text shape's anchor to the bounding box's top-left given `textAlign`. */
35
+ export declare function alignToOrigin(anchorX: number, width: number, align: 'left' | 'center' | 'right'): number;
36
+ //# sourceMappingURL=geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,YAAY,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAuChD;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEhF,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAS3D,CAAC;AAEF,6EAA6E;AAC7E,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,IAAI,GACT,MAAM,CAAC,eAAe,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnD;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,IAAI,EACb,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CAYN;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CASnC;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GACjC,MAAM,CASR"}
@@ -0,0 +1,8 @@
1
+ import type { Point } from '../../geometry/rect.js';
2
+ import { type Shape } from './state.js';
3
+ /** Picking margin added to every stroked-shape hit-test, in image-space pixels. */
4
+ export declare const PICK_TOLERANCE = 4;
5
+ /** Find the topmost shape under `point` (image-space). Iterates back-to-front. */
6
+ export declare function pickShape(shapes: ReadonlyArray<Shape>, point: Point): Shape | undefined;
7
+ export declare function hitTest(shape: Shape, point: Point): boolean;
8
+ //# sourceMappingURL=hit-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,YAAY,CAAC;AAErD,mFAAmF;AACnF,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAMvF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAwD3D"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Freehand stroke decimation + midpoint-curve smoothing. Decimation drops
3
+ * sub-pixel samples from the raw pointer stream; the curve smoothing
4
+ * happens at draw time so stored points stay unchanged across edits.
5
+ */
6
+ import type { Point } from '../../geometry/rect.js';
7
+ export declare const MIN_SAMPLE_DISTANCE = 2;
8
+ /** Drop interior points closer than `MIN_SAMPLE_DISTANCE` to the previous kept point. */
9
+ export declare function decimatePoints(points: ReadonlyArray<Point>): Point[];
10
+ /**
11
+ * Trace a smoothed path through `points` using the midpoint-curve technique.
12
+ * Caller owns `beginPath`, stroke style, and `stroke()` so blend modes
13
+ * (highlight) can wrap this without re-implementing the curve math.
14
+ */
15
+ export declare function tracePath(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, points: ReadonlyArray<Point>): void;
16
+ //# sourceMappingURL=smooth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smooth.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/smooth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,KAAK,EAAE,CAoBpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,wBAAwB,GAAG,iCAAiC,EACjE,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAC3B,IAAI,CAqBN"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Annotation state and pure mutators. Shapes are a flat discriminated
3
+ * union keyed on `kind`; all coordinates are image-space pixels.
4
+ */
5
+ import type { Point } from '../../geometry/rect.js';
6
+ export type ShapeKind = 'text' | 'rect' | 'ellipse' | 'arrow' | 'freehand' | 'highlight';
7
+ /** Tools the annotation plugin exposes. `select` is the picker. */
8
+ export type AnnotateTool = ShapeKind | 'select';
9
+ interface ShapeBase {
10
+ /** Stable per-session id; survives undo/redo. */
11
+ readonly id: string;
12
+ readonly kind: ShapeKind;
13
+ }
14
+ export interface TextShape extends ShapeBase {
15
+ readonly kind: 'text';
16
+ /** Top-left anchor in image-space pixels. */
17
+ readonly x: number;
18
+ readonly y: number;
19
+ readonly text: string;
20
+ /** Font size in image-space pixels. */
21
+ readonly fontSize: number;
22
+ /** CSS colour string. */
23
+ readonly color: string;
24
+ readonly textAlign: 'left' | 'center' | 'right';
25
+ }
26
+ export interface RectShape extends ShapeBase {
27
+ readonly kind: 'rect';
28
+ readonly x: number;
29
+ readonly y: number;
30
+ /** Non-negative after gesture commit; may be negative mid-drag. */
31
+ readonly width: number;
32
+ readonly height: number;
33
+ readonly strokeColor: string;
34
+ readonly strokeWidth: number;
35
+ /** `null` means "no fill". */
36
+ readonly fillColor: string | null;
37
+ }
38
+ export interface EllipseShape extends ShapeBase {
39
+ readonly kind: 'ellipse';
40
+ /** Bounding-box top-left; the ellipse fits inside the box. */
41
+ readonly x: number;
42
+ readonly y: number;
43
+ readonly width: number;
44
+ readonly height: number;
45
+ readonly strokeColor: string;
46
+ readonly strokeWidth: number;
47
+ readonly fillColor: string | null;
48
+ }
49
+ export interface ArrowShape extends ShapeBase {
50
+ readonly kind: 'arrow';
51
+ readonly x1: number;
52
+ readonly y1: number;
53
+ /** Arrowhead is drawn at (x2, y2). */
54
+ readonly x2: number;
55
+ readonly y2: number;
56
+ readonly color: string;
57
+ readonly strokeWidth: number;
58
+ }
59
+ export interface FreehandShape extends ShapeBase {
60
+ readonly kind: 'freehand';
61
+ /** Decimated raw points in image-space; smoothing happens at render time. */
62
+ readonly points: ReadonlyArray<Point>;
63
+ readonly color: string;
64
+ readonly strokeWidth: number;
65
+ }
66
+ export interface HighlightShape extends ShapeBase {
67
+ readonly kind: 'highlight';
68
+ readonly points: ReadonlyArray<Point>;
69
+ /** Default semi-transparent yellow, drawn with `multiply` blend mode. */
70
+ readonly color: string;
71
+ readonly strokeWidth: number;
72
+ }
73
+ export type Shape = TextShape | RectShape | EllipseShape | ArrowShape | FreehandShape | HighlightShape;
74
+ export interface StylePalette {
75
+ readonly color: string;
76
+ readonly strokeWidth: number;
77
+ /** Used for new rect/ellipse fills; `null` = unfilled. */
78
+ readonly fillColor: string | null;
79
+ /** Used for new text shapes. In image-space pixels. */
80
+ readonly fontSize: number;
81
+ }
82
+ export interface AnnotateState {
83
+ readonly shapes: ReadonlyArray<Shape>;
84
+ readonly selectedId: string | null;
85
+ readonly activeTool: AnnotateTool;
86
+ readonly currentStyle: StylePalette;
87
+ /** Image-space dimensions of the upstream-baked source the plugin was mounted on. */
88
+ readonly imageSize: {
89
+ readonly width: number;
90
+ readonly height: number;
91
+ };
92
+ /** Monotonic counter used to mint shape ids. Never decreases. */
93
+ readonly nextShapeNumber: number;
94
+ }
95
+ /** Yellow @ 35% alpha; the highlight bake uses `multiply` blending. */
96
+ export declare const HIGHLIGHT_DEFAULT_COLOR = "rgba(255, 235, 59, 0.35)";
97
+ export declare const HIGHLIGHT_DEFAULT_STROKE = 18;
98
+ export declare const FREEHAND_DEFAULT_STROKE = 6;
99
+ export declare const TEXT_DEFAULT_FONT_SIZE = 32;
100
+ export declare const DEFAULT_PALETTE_COLOR = "#ff3b30";
101
+ export declare const DEFAULT_STROKE_WIDTH = 4;
102
+ export declare function defaultStylePalette(): StylePalette;
103
+ export interface InitialAnnotateStateInput {
104
+ readonly imageSize: {
105
+ readonly width: number;
106
+ readonly height: number;
107
+ };
108
+ }
109
+ export declare function initialAnnotateState(input: InitialAnnotateStateInput): AnnotateState;
110
+ /** Allocate a new shape id from the monotonic counter; caller threads `nextShapeNumber` back into state. */
111
+ export declare function mintShapeId(state: AnnotateState): {
112
+ id: string;
113
+ nextShapeNumber: number;
114
+ };
115
+ export declare function setActiveTool(state: AnnotateState, tool: AnnotateTool): AnnotateState;
116
+ export declare function setStyle(state: AnnotateState, partial: Partial<StylePalette>): AnnotateState;
117
+ export declare function selectShape(state: AnnotateState, id: string | null): AnnotateState;
118
+ export declare function addShape(state: AnnotateState, shape: Shape): AnnotateState;
119
+ export declare function replaceShape(state: AnnotateState, shape: Shape): AnnotateState;
120
+ export declare function deleteShape(state: AnnotateState, id: string): AnnotateState;
121
+ export declare function findShape(state: AnnotateState, id: string | null): Shape | undefined;
122
+ /** Normalise a rect extent so `width`/`height` are non-negative after a sign-flip drag. */
123
+ export declare function normaliseRectExtent(extent: {
124
+ x: number;
125
+ y: number;
126
+ width: number;
127
+ height: number;
128
+ }): {
129
+ x: number;
130
+ y: number;
131
+ width: number;
132
+ height: number;
133
+ };
134
+ export declare function translateShape(shape: Shape, dx: number, dy: number): Shape;
135
+ /** Type-narrowing helper for exhaustive switches over `Shape`. */
136
+ export declare function assertNever(value: never): never;
137
+ /**
138
+ * Mirror a shape across an axis of `dims`. Rect/ellipse top-left is
139
+ * remapped so the visible rectangle straddles the same pixels; arrow
140
+ * endpoints and freehand points mirror independently. Text uses its
141
+ * anchor only — the glyph rect walks slightly relative to centre.
142
+ */
143
+ export declare function mirrorShape(shape: Shape, axis: 'horizontal' | 'vertical', dims: {
144
+ readonly width: number;
145
+ readonly height: number;
146
+ }): Shape;
147
+ /**
148
+ * Rotate a shape `turns × 90°` CW around the centre of `oldDims`. Returns
149
+ * coordinates in the post-rotation image's coord space (dims swap on odd turns).
150
+ */
151
+ export declare function rotateShape(shape: Shape, turns: 0 | 1 | 2 | 3, oldDims: {
152
+ readonly width: number;
153
+ readonly height: number;
154
+ }): Shape;
155
+ /** Apply a transformation to every shape in `state.shapes`. */
156
+ export declare function transformShapes(state: AnnotateState, transformer: (shape: Shape) => Shape): AnnotateState;
157
+ /**
158
+ * Kinds placeable from the keyboard. Freehand / highlight are excluded;
159
+ * a "default at centre" instance has no honest shape for those.
160
+ */
161
+ export type KeyboardPlaceableKind = 'text' | 'rect' | 'ellipse' | 'arrow';
162
+ export declare const KEYBOARD_PLACEABLE_KINDS: ReadonlyArray<KeyboardPlaceableKind>;
163
+ export declare function isKeyboardPlaceableKind(kind: ShapeKind): kind is KeyboardPlaceableKind;
164
+ export interface CreateCenteredShapeContext {
165
+ readonly imageSize: {
166
+ readonly width: number;
167
+ readonly height: number;
168
+ };
169
+ readonly style: StylePalette;
170
+ readonly id: string;
171
+ }
172
+ /** A `Shape` whose kind is keyboard-placeable (rect / ellipse / arrow / text). */
173
+ export type KeyboardPlaceableShape = TextShape | RectShape | EllipseShape | ArrowShape;
174
+ export declare function createCenteredShape(kind: KeyboardPlaceableKind, ctx: CreateCenteredShapeContext): KeyboardPlaceableShape;
175
+ export {};
176
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type Rect } from '../../geometry/rect.js';
2
+ /**
3
+ * Compute the largest axis-aligned rectangle of `targetRatio` (= w/h) that
4
+ * fits inside `bounds`, centered. Used to seed the crop rectangle when the
5
+ * user picks an aspect-ratio preset before any drag.
6
+ */
7
+ export declare function fitRectToBoundsWithRatio(bounds: Rect, targetRatio: number): Rect;
8
+ /**
9
+ * Reshape `rect` to `targetRatio`, anchored at `anchor`, clamped inside
10
+ * `bounds`. If clamping breaks the ratio, falls back to the largest same-ratio
11
+ * sub-rect that fits, anchored identically.
12
+ */
13
+ export declare function applyAspectRatio(rect: Rect, targetRatio: number, anchor: AspectAnchor, bounds: Rect): Rect;
14
+ export type AspectAnchor = 'tl' | 'tr' | 'bl' | 'br' | 'center';
15
+ //# sourceMappingURL=aspect-ratio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aspect-ratio.d.ts","sourceRoot":"","sources":["../../../src/plugins/crop/aspect-ratio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAmB,MAAM,wBAAwB,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAsBhF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,IAAI,GACX,IAAI,CAuBN;AAID,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type Rect } from '../../geometry/rect.js';
2
+ import type { SourceImage } from '../utility.js';
3
+ export interface CropBakeInput {
4
+ /** The cropped region, in image-space pixels. */
5
+ readonly rect: Rect;
6
+ }
7
+ /**
8
+ * Apply a crop and return a SourceImage at the crop's pixel size. The
9
+ * rect is rounded and clamped against the source so an oversized rect
10
+ * doesn't crash — we draw what fits.
11
+ */
12
+ export declare function bakeCrop(source: SourceImage, input: CropBakeInput): SourceImage;
13
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/crop/bake.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,EAAa,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,WAAW,CAkB/E"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Filters crop presets by aspect-ratio relative to 1. `landscape` keeps
3
+ * ratio ≥ 1, `portrait` keeps ratio < 1; `undefined` ratios (Custom) and
4
+ * unknown tokens stay visible.
5
+ */
6
+ export type CropPresetFilter = 'landscape' | 'portrait';
7
+ export type CropPreset = readonly [number | undefined, string];
8
+ export declare function isPresetVisible(preset: CropPreset, filter: CropPresetFilter | undefined): boolean;
9
+ export declare function filterPresets(presets: readonly CropPreset[], filter: CropPresetFilter | undefined): readonly CropPreset[];
10
+ //# sourceMappingURL=preset-filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-filter.d.ts","sourceRoot":"","sources":["../../../src/plugins/crop/preset-filter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC;AAE/D,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAOjG;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,SAAS,UAAU,EAAE,CAEvB"}
@@ -0,0 +1,19 @@
1
+ import { type Point, type Rect } from '../../geometry/rect.js';
2
+ export type CornerHandle = 'tl' | 'tr' | 'bl' | 'br';
3
+ export type EdgeHandle = 't' | 'r' | 'b' | 'l';
4
+ export type HandleDirection = CornerHandle | EdgeHandle;
5
+ export interface ResizeOptions {
6
+ /** Image-space bounds the rect must stay inside. */
7
+ readonly bounds: Rect;
8
+ /** Aspect ratio to enforce, or `undefined` for free crop. */
9
+ readonly aspectRatio?: number;
10
+ /** Minimum size on either axis, in image-space units. Defaults to 1. */
11
+ readonly minSize?: number;
12
+ }
13
+ /**
14
+ * Resize a rect from one of its eight handles to `pointer`. Opposite
15
+ * corner/edge anchors; result clamped to `bounds` and reshaped to
16
+ * `aspectRatio` (anchored at the same opposite corner) when supplied.
17
+ */
18
+ export declare function resizeRectFromHandle(rect: Rect, handle: HandleDirection, pointer: Point, options: ResizeOptions): Rect;
19
+ //# sourceMappingURL=resize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize.d.ts","sourceRoot":"","sources":["../../../src/plugins/crop/resize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,IAAI,EAAmB,MAAM,wBAAwB,CAAC;AAGhF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACrD,MAAM,MAAM,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAC/C,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,KAAK,EACd,OAAO,EAAE,aAAa,GACrB,IAAI,CAiEN"}
@@ -0,0 +1,23 @@
1
+ import type { Rect, Size } from '../../geometry/rect.js';
2
+ import type { CropPreset, CropPresetFilter } from './preset-filter.js';
3
+ export interface CropState {
4
+ /** Crop rectangle in image-space pixels. */
5
+ readonly rect: Rect;
6
+ /** Active aspect-ratio constraint (image w/h), or `undefined` for free. */
7
+ readonly aspectRatio: number | undefined;
8
+ /** Index into `presets`, or `-1` if no preset is active. */
9
+ readonly activePresetIndex: number;
10
+ /** Visible presets after applying `cropSelectPresetFilter`. */
11
+ readonly presets: readonly CropPreset[];
12
+ /** Image dimensions, in pixels. The bounds the crop can move within. */
13
+ readonly imageSize: Size;
14
+ }
15
+ export interface InitialCropStateInput {
16
+ readonly imageSize: Size;
17
+ readonly presets: readonly CropPreset[];
18
+ readonly filter: CropPresetFilter | undefined;
19
+ }
20
+ /** Full-frame crop, "Custom" preset active. */
21
+ export declare function initialCropState(input: InitialCropStateInput): CropState;
22
+ export declare function applyPresetByIndex(state: CropState, presetIndex: number): CropState;
23
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/crop/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvE,MAAM,WAAW,SAAS;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC/C;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,CASxE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,CAenF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Curated `FinetuneState` shapes that one-click set the six tone numbers.
3
+ * The filter tab is a UI view over the finetune store: clicking a preset
4
+ * here is identical to dragging the matching sliders in finetune.
5
+ */
6
+ import { type FinetuneState } from '../finetune/state.js';
7
+ export type FilterPresetId = 'none' | 'vivid' | 'mono' | 'soft' | 'punch' | 'mute' | 'bright';
8
+ export interface FilterPreset {
9
+ readonly id: FilterPresetId;
10
+ readonly label: string;
11
+ readonly state: FinetuneState;
12
+ }
13
+ /** The seven presets in display order. `none` is the identity / off state. */
14
+ export declare const FILTER_PRESETS: readonly FilterPreset[];
15
+ /** Structural equality across the six finetune fields. */
16
+ export declare function finetuneStatesEqual(a: FinetuneState, b: FinetuneState): boolean;
17
+ /** Preset whose state matches `state` exactly, or `undefined` if between presets. */
18
+ export declare function findActivePreset(state: FinetuneState): FilterPreset | undefined;
19
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/plugins/filter/presets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAElF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE9F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;CAC/B;AAED,8EAA8E;AAC9E,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EA+EjD,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAS/E;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,GAAG,SAAS,CAK/E"}
@@ -0,0 +1,5 @@
1
+ import type { SourceImage } from '../utility.js';
2
+ import { type FinetuneState } from './state.js';
3
+ /** Apply the six finetune adjustments at full resolution. Shares the math with the live preview. */
4
+ export declare function bakeFinetune(state: FinetuneState, source: SourceImage): Promise<SourceImage>;
5
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/finetune/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,YAAY,CAAC;AAEhE,oGAAoG;AACpG,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CA+BtB"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Pure math for the finetune adjustments. Slider values arrive in
3
+ * [-100, +100] from `state.ts`. Shared by the bake (full-resolution)
4
+ * and the live preview (display-resolution).
5
+ */
6
+ import type { FinetuneState } from './state.js';
7
+ /**
8
+ * 256-entry LUT collapsing brightness + contrast + exposure + gamma into
9
+ * one per-byte mapping. Saturation and clarity run in separate passes.
10
+ */
11
+ export declare function buildFinetuneLut(state: FinetuneState): Uint8ClampedArray;
12
+ /**
13
+ * Apply the LUT and saturation in one pass. `src`/`dst` may be the same
14
+ * buffer. Saturation: -100 → grayscale (Rec. 709), 0 → identity, +100 → 2×.
15
+ */
16
+ export declare function applyFinetuneLutAndSaturation(src: Uint8ClampedArray, dst: Uint8ClampedArray, lut: Uint8ClampedArray, state: FinetuneState): void;
17
+ /**
18
+ * Unsharp-mask local contrast: `result = dst + (clarity/100) * (dst - blurred)`.
19
+ * `clarity === 0` is a no-op; caller is expected to skip the call.
20
+ */
21
+ export declare function applyClarity(dst: Uint8ClampedArray, blurred: Uint8ClampedArray, clarity: number): void;
22
+ /** Separable 3×3 box blur (clamp at edges). Used as the unsharp-mask reference. */
23
+ export declare function boxBlur3x3(src: Uint8ClampedArray, tmp: Uint8ClampedArray, dst: Uint8ClampedArray, width: number, height: number): void;
24
+ /** Structural raster shape so tests can pass a plain object (jsdom 25 lacks `ImageData`). */
25
+ export interface RasterImage {
26
+ readonly data: Uint8ClampedArray;
27
+ readonly width: number;
28
+ readonly height: number;
29
+ }
30
+ /** Apply the full pipeline (LUT + saturation + clarity); blur buffers allocate only when clarity ≠ 0. */
31
+ export declare function applyFinetuneToImageData(state: FinetuneState, baseline: RasterImage, dst: RasterImage): void;
32
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../../src/plugins/finetune/math.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,CA0BxE;AAQD;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,aAAa,GACnB,IAAI,CAuCN;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,MAAM,GACd,IAAI,CAwBN;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CACxB,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,CA8BN;AAED,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,yGAAyG;AACzG,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,WAAW,EACrB,GAAG,EAAE,WAAW,GACf,IAAI,CAoBN"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Six tone adjustments stored as slider values in [-100, +100]; math
3
+ * constants (gamma exponent, contrast multiplier, etc.) are computed
4
+ * from these in `math.ts` at LUT-build time.
5
+ */
6
+ export interface FinetuneState {
7
+ readonly brightness: number;
8
+ readonly contrast: number;
9
+ readonly saturation: number;
10
+ readonly exposure: number;
11
+ readonly clarity: number;
12
+ readonly gamma: number;
13
+ }
14
+ export declare const FINETUNE_MIN = -100;
15
+ export declare const FINETUNE_MAX = 100;
16
+ export declare const FINETUNE_STEP = 1;
17
+ export declare const DEFAULT_FINETUNE_STATE: FinetuneState;
18
+ export type FinetuneKey = keyof FinetuneState;
19
+ export declare const FINETUNE_ADJUSTMENTS: readonly {
20
+ readonly key: FinetuneKey;
21
+ readonly label: string;
22
+ }[];
23
+ export declare function initialFinetuneState(): FinetuneState;
24
+ export declare function isFinetuneNoOp(state: FinetuneState): boolean;
25
+ /** Update a single adjustment, clamped to the legal range. */
26
+ export declare function setFinetune(state: FinetuneState, key: FinetuneKey, value: number): FinetuneState;
27
+ /** Reset a single adjustment to its default of 0. */
28
+ export declare function resetFinetune(state: FinetuneState, key: FinetuneKey): FinetuneState;
29
+ /** Reset every adjustment to its default. */
30
+ export declare function resetAllFinetune(): FinetuneState;
31
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/finetune/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,eAAO,MAAM,sBAAsB,EAAE,aAOpC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,SAAS;IAC1C,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,EAOA,CAAC;AAEF,wBAAgB,oBAAoB,IAAI,aAAa,CAEpD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAS5D;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAIhG;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,WAAW,GAAG,aAAa,CAGnF;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD"}
@@ -0,0 +1,5 @@
1
+ import type { SourceImage } from '../utility.js';
2
+ import { type FlipState } from './state.js';
3
+ /** Apply horizontal / vertical flips via a sign-flipped scale on `drawImage`. */
4
+ export declare function bakeFlip(state: FlipState, source: SourceImage): Promise<SourceImage>;
5
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/flip/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,YAAY,CAAC;AAExD,iFAAiF;AACjF,wBAAsB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAqB1F"}
@@ -0,0 +1,9 @@
1
+ /** Two independent axis flips; their composition equals a 180° rotation. */
2
+ export interface FlipState {
3
+ readonly horizontal: boolean;
4
+ readonly vertical: boolean;
5
+ }
6
+ export declare function initialFlipState(): FlipState;
7
+ export declare function toggleFlip(state: FlipState, axis: 'horizontal' | 'vertical'): FlipState;
8
+ export declare function isFlipNoOp(state: FlipState): boolean;
9
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/flip/state.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,IAAI,SAAS,CAE5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,CAIvF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEpD"}
@@ -0,0 +1,16 @@
1
+ import type { SourceImage } from '../utility.js';
2
+ import { type FramePresetId, type FrameState } from './state.js';
3
+ /**
4
+ * Apply the active frame preset. Frame thickness scales with `source`
5
+ * so it stays consistent across resize choices. Output dimensions match
6
+ * the input except for Polaroid, which extends the canvas.
7
+ */
8
+ export declare function bakeFrame(state: FrameState, source: SourceImage): Promise<SourceImage>;
9
+ /** Paint a non-extending frame; caller has already drawn the source image. */
10
+ export declare function paintInsideFrame(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, presetId: Exclude<FramePresetId, 'none' | 'polaroid'>, color: string, width: number, height: number): void;
11
+ /** Output dimensions for a preset; equals input except for Polaroid. */
12
+ export declare function frameOutputSize(presetId: FramePresetId, inputWidth: number, inputHeight: number): {
13
+ width: number;
14
+ height: number;
15
+ };
16
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/frame/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAe,MAAM,YAAY,CAAC;AAE9E;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAQ5F;AAsBD,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,GAAG,iCAAiC,EACjE,QAAQ,EAAE,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,CAAC,EACrD,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,CAeN;AAiKD,wEAAwE;AACxE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAWnC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Frame preset ids match Ghost's `frameOptions` identifiers directly so
3
+ * a contract change is a state rename, not a translation table.
4
+ */
5
+ export type FramePresetId = 'none' | 'solidSharp' | 'solidRound' | 'lineSingle' | 'hook' | 'polaroid';
6
+ export declare const FRAME_PRESET_IDS: readonly FramePresetId[];
7
+ export interface FramePreset {
8
+ readonly id: FramePresetId;
9
+ /** UI label. The Ghost adapter overrides these from `frameOptions[i][1]`. */
10
+ readonly label: string;
11
+ /** Whether the preset's colour can be customised by the user. */
12
+ readonly acceptsColor: boolean;
13
+ /** Default colour when `acceptsColor`. Polaroid defaults to white. */
14
+ readonly defaultColor: string;
15
+ }
16
+ /** Six presets in Ghost's `frameOptions` order. Labels are English defaults; adapter localises. */
17
+ export declare const FRAME_PRESETS: readonly FramePreset[];
18
+ export interface FrameState {
19
+ readonly presetId: FramePresetId;
20
+ /** CSS hex colour. Used by every preset whose `acceptsColor` is true. */
21
+ readonly color: string;
22
+ }
23
+ export declare const DEFAULT_FRAME_STATE: FrameState;
24
+ export declare function initialFrameState(): FrameState;
25
+ export declare function isFrameNoOp(state: FrameState): boolean;
26
+ export declare function setFramePreset(state: FrameState, presetId: FramePresetId): FrameState;
27
+ export declare function setFrameColor(state: FrameState, color: string): FrameState;
28
+ export declare function findFramePreset(id: FramePresetId): FramePreset | undefined;
29
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/frame/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,MAAM,GACN,UAAU,CAAC;AAEf,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAOpD,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,mGAAmG;AACnG,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAqC/C,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE,UAGjC,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,UAAU,CAE9C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEtD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,GAAG,UAAU,CAUrF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAG1E;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS,CAE1E"}
@@ -0,0 +1,13 @@
1
+ import type { SourceImage } from '../utility.js';
2
+ import type { RedactRegion } from './state.js';
3
+ export interface RedactBakeInput {
4
+ readonly regions: ReadonlyArray<RedactRegion>;
5
+ }
6
+ /** Paint every redaction region onto a copy of `source` in creation order. */
7
+ export declare function bakeRedact(state: RedactBakeInput, source: SourceImage): Promise<SourceImage>;
8
+ /**
9
+ * Paint a single redaction region. `canvas` is needed because pixelate
10
+ * and blur read from it and redraw a transformed copy in place.
11
+ */
12
+ export declare function paintRegion(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, canvas: HTMLCanvasElement | OffscreenCanvas, region: RedactRegion, source: SourceImage): void;
13
+ //# sourceMappingURL=bake.d.ts.map