@dilemmagx/orchestra 1.2.1 → 1.2.2

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 CHANGED
@@ -1,7 +1,8 @@
1
1
  # @dilemmagx/orchestra
2
2
 
3
3
  Orchestra is a programmable, node-based image synthesis and processing toolkit.
4
- It focuses on deterministic, pixel-accurate workflows with simple composable nodes.
4
+ The engine is centered around a flexible node state, so every built-in node is created through
5
+ the same custom node API that you use in your own projects.
5
6
 
6
7
  ## Install
7
8
 
@@ -15,29 +16,150 @@ npm i @dilemmagx/orchestra
15
16
  import { Pipeline, createNoiseNode, createInvertNode, sourceFromEmpty } from '@dilemmagx/orchestra';
16
17
 
17
18
  const pipeline = new Pipeline().add(createNoiseNode({ grayscale: true })).add(createInvertNode());
18
-
19
19
  const image = await pipeline.run(sourceFromEmpty(256, 256, 'rgba8'), { seed: 42 });
20
20
  ```
21
21
 
22
- ## Resize & Palette Mapping
22
+ ## Core Concepts
23
+
24
+ - A pipeline runs nodes sequentially.
25
+ - Each node receives a shared context and a mutable state object.
26
+ - The default image key is "image", but nodes may read and write additional image keys.
27
+
28
+ ## Simplified Node API
29
+
30
+ ```ts
31
+ import { node, pipeline, sourceFromEmpty } from '@dilemmagx/orchestra';
32
+
33
+ const gradient = node({
34
+ name: 'gradient',
35
+ params: { from: '#22d3ee', to: '#0f172a' },
36
+ run: (pixels, { params }) => {
37
+ const height = pixels.length;
38
+ const width = pixels[0]?.length ?? 0;
39
+ return pixels.map((row, y) =>
40
+ row.map((_pixel, x) => {
41
+ const t = x / Math.max(1, width - 1);
42
+ return {
43
+ r: Math.round(34 + (15 - 34) * t),
44
+ g: Math.round(211 + (23 - 211) * t),
45
+ b: Math.round(238 + (42 - 238) * t),
46
+ a: 255,
47
+ };
48
+ })
49
+ );
50
+ },
51
+ });
52
+
53
+ const image = await pipeline(gradient).run(sourceFromEmpty(512, 256, 'rgba8'));
54
+ ```
55
+
56
+ Nodes created with `node()` receive a 2D pixel matrix by default. Node names are optional;
57
+ if omitted, Orchestra assigns incremental names like `node-1` to improve traceability.
58
+
59
+ ## Noise Suite
60
+
61
+ ```ts
62
+ import {
63
+ pipeline,
64
+ sourceFromEmpty,
65
+ createValueNoiseNode,
66
+ createVoronoiNoiseNode,
67
+ createFractalNoiseNode,
68
+ } from '@dilemmagx/orchestra';
69
+
70
+ const image = await pipeline(
71
+ createValueNoiseNode({ scale: 32, octaves: 2, min: 20, max: 220 }),
72
+ createVoronoiNoiseNode({ scale: 28, jitter: 0.8, mode: 'edge' }),
73
+ createFractalNoiseNode({ scale: 40, octaves: 4, persistence: 0.55 })
74
+ ).run(sourceFromEmpty(512, 512, 'rgba8'), { seed: 42 });
75
+ ```
76
+
77
+ ```ts
78
+ import {
79
+ pipeline,
80
+ sourceFromEmpty,
81
+ createPerlinNoiseNode,
82
+ createTurbulenceNoiseNode,
83
+ createRidgedNoiseNode,
84
+ } from '@dilemmagx/orchestra';
85
+
86
+ const image = await pipeline(
87
+ createPerlinNoiseNode({ scale: 48, octaves: 3 }),
88
+ createTurbulenceNoiseNode({ scale: 36, octaves: 4, persistence: 0.6 }),
89
+ createRidgedNoiseNode({ scale: 40, octaves: 5, persistence: 0.55 })
90
+ ).run(sourceFromEmpty(512, 512, 'rgba8'), { seed: 'detail' });
91
+ ```
92
+
93
+ ## Text Tool
94
+
95
+ ```ts
96
+ import { createTextNode, pipeline, sourceFromEmpty } from '@dilemmagx/orchestra';
97
+
98
+ const text = createTextNode({
99
+ text: 'HELLO ORCHESTRA',
100
+ font: {
101
+ family: 'Inter',
102
+ source: { filePath: './fonts/Inter-SemiBold.ttf' },
103
+ weight: 600,
104
+ },
105
+ layout: { x: 64, y: 64, maxWidth: 640, align: 'left' },
106
+ style: { fontSize: 48, bold: true, underline: true },
107
+ });
108
+
109
+ const image = await pipeline(text).run(sourceFromEmpty(800, 450, 'rgba8'));
110
+ ```
111
+
112
+ Provide a font file to keep output identical across machines. If a font source is not supplied,
113
+ the system font family is used when available.
114
+
115
+ ## Custom Node
116
+
117
+ ```ts
118
+ import { Pipeline, createImageNode, sourceFromEmpty } from '@dilemmagx/orchestra';
119
+
120
+ const posterize = createImageNode(
121
+ 'posterize',
122
+ { step: 32 },
123
+ (_context, image, params) =>
124
+ image.mapPixels((pixel) => {
125
+ const next = Math.round(pixel.r / params.step) * params.step;
126
+ return { r: next, g: next, b: next, a: pixel.a };
127
+ })
128
+ );
129
+
130
+ const pipeline = new Pipeline().add(posterize);
131
+ const image = await pipeline.run(sourceFromEmpty(512, 512, 'rgba8'));
132
+ ```
133
+
134
+ ## Advanced Node State
23
135
 
24
136
  ```ts
25
137
  import {
26
138
  Pipeline,
27
- createResizeNode,
28
- createPaletteMapNode,
29
- saveImage,
30
- sourceFromUrl,
139
+ defineNode,
140
+ getImage,
141
+ sourceFromEmpty,
142
+ DEFAULT_IMAGE_KEY,
31
143
  } from '@dilemmagx/orchestra';
32
144
 
33
- const palette = ['#9bbc0f', '#8bac0f', '#306230', '#0f380f'];
34
- const pipeline = new Pipeline().add(createResizeNode(128, 85)).add(createPaletteMapNode(palette));
145
+ const stashStats = defineNode({
146
+ name: 'stash-stats',
147
+ run: (_context, state) => {
148
+ const image = getImage(state, DEFAULT_IMAGE_KEY);
149
+ return {
150
+ data: {
151
+ pixelCount: image.width * image.height,
152
+ },
153
+ };
154
+ },
155
+ });
35
156
 
36
- const image = await pipeline.run(sourceFromUrl('https://example.com/image.jpg'));
37
- await saveImage(image, './gameboy.png');
157
+ const pipeline = new Pipeline().add(stashStats);
158
+ const state = await pipeline.runState(sourceFromEmpty(256, 256, 'rgba8'));
159
+ console.log(state.data.pixelCount);
38
160
  ```
39
161
 
40
- ## Color Mask Mapping
162
+ ## Mask Mapping
41
163
 
42
164
  ```ts
43
165
  import {
@@ -46,13 +168,14 @@ import {
46
168
  createGaussianBlurNode,
47
169
  createMapNode,
48
170
  sourceFromUrl,
171
+ toRgba,
49
172
  } from '@dilemmagx/orchestra';
50
173
 
51
174
  const mask = createMapNode('mask', (_pixel, x, y) => {
52
175
  const dx = x - 128;
53
176
  const dy = y - 128;
54
177
  const inside = dx * dx + dy * dy <= 96 * 96;
55
- return inside ? '#ffffff' : '#000000';
178
+ return inside ? toRgba('#ffffff') : toRgba('#000000');
56
179
  });
57
180
 
58
181
  const mapped = createMaskMapNode(mask, [
@@ -63,35 +186,7 @@ const pipeline = new Pipeline().add(mapped);
63
186
  const image = await pipeline.run(sourceFromUrl('https://example.com/image.jpg'));
64
187
  ```
65
188
 
66
- Mask mapping uses color keys to stitch multiple image results. Each entry maps a mask
67
- color to a source image or node output, with optional tolerance.
68
-
69
- You can also use a dedicated crop node:
70
-
71
- ```ts
72
- import { createSelectionCropNode } from '@dilemmagx/orchestra';
73
-
74
- const crop = createSelectionCropNode(selector, { outsideColor: '#00000000' });
75
- ```
76
-
77
- ## Color Formats
78
-
79
- ```ts
80
- import { toRgba, hsvaToRgba } from '@dilemmagx/orchestra';
81
-
82
- const rgba = toRgba('#ffcc00');
83
- const other = hsvaToRgba({ h: 120, s: 50, v: 90, a: 1 });
84
- ```
85
-
86
- ## Common Nodes
87
-
88
- ```ts
89
- import { Pipeline, createGrayscaleNode, createGammaNode } from '@dilemmagx/orchestra';
90
-
91
- const pipeline = new Pipeline().add(createGrayscaleNode()).add(createGammaNode(1.2));
92
- ```
93
-
94
- Built-in nodes:
189
+ ## Built-in Nodes
95
190
 
96
191
  - createBrightnessNode
97
192
  - createCheckerboardNode
@@ -106,6 +201,12 @@ Built-in nodes:
106
201
  - createGrayscaleNode
107
202
  - createInvertNode
108
203
  - createNoiseNode
204
+ - createFractalNoiseNode
205
+ - createPerlinNoiseNode
206
+ - createRidgedNoiseNode
207
+ - createTurbulenceNoiseNode
208
+ - createValueNoiseNode
209
+ - createVoronoiNoiseNode
109
210
  - createPaletteMapNode
110
211
  - createRandomFillNode
111
212
  - createRectNode
@@ -113,8 +214,9 @@ Built-in nodes:
113
214
  - createSaltPepperNoiseNode
114
215
  - createSharpenNode
115
216
  - createThresholdNode
217
+ - createTextNode
116
218
 
117
- Selectors and masking:
219
+ Selectors and masking helpers:
118
220
 
119
221
  - createAlphaSelector
120
222
  - createCircleSelector
@@ -124,23 +226,6 @@ Selectors and masking:
124
226
  - createRectSelector
125
227
  - createSelectionCropNode
126
228
 
127
- ## Custom Node
128
-
129
- ```ts
130
- import { Pipeline, createParamNode, sourceFromEmpty } from '@dilemmagx/orchestra';
131
-
132
- const posterize = createParamNode('posterize', { step: 32 }, (_context, image, params) =>
133
- image.mapPixels((pixel) => {
134
- const next = Math.round(pixel.r / params.step) * params.step;
135
- return { r: next, g: next, b: next, a: pixel.a };
136
- })
137
- );
138
-
139
- const pipeline = new Pipeline().add(posterize);
140
- const image = await pipeline.run(sourceFromEmpty(512, 512, 'rgba8'));
141
- ```
142
-
143
229
  ## License
144
230
 
145
231
  GPL-3.0
146
-
@@ -17,6 +17,10 @@ export declare class ImageBuffer {
17
17
  * Creates a new ImageBuffer and optionally fills it with a color.
18
18
  */
19
19
  static create(width: number, height: number, format: PixelFormat, fill?: PixelLike): ImageBuffer;
20
+ /**
21
+ * Creates an ImageBuffer from a 2D pixel matrix.
22
+ */
23
+ static fromMatrix(matrix: Pixel[][], format?: PixelFormat): ImageBuffer;
20
24
  /**
21
25
  * Clones the buffer and its pixel data.
22
26
  */
@@ -2,21 +2,120 @@ import { ImageBuffer } from './image';
2
2
  import { ColorInput } from './color';
3
3
  import { ImageSource, Pixel, PixelLike } from './types';
4
4
  import { SeededRandom } from './random';
5
- import { ResizeOptions } from './sources';
5
+ import { ResizeOptions, type TextOptions } from './sources';
6
+ export declare const DEFAULT_IMAGE_KEY = "image";
6
7
  /**
7
8
  * Runtime context shared across nodes in a pipeline run.
8
9
  */
9
10
  export type NodeContext = {
10
11
  random: SeededRandom;
12
+ stash: Map<string, unknown>;
11
13
  };
14
+ /**
15
+ * State passed between nodes in a pipeline run.
16
+ */
17
+ export type NodeState = {
18
+ images: Record<string, ImageBuffer>;
19
+ data: Record<string, unknown>;
20
+ };
21
+ /**
22
+ * Result returned by a node execution.
23
+ */
24
+ export type NodeResult = {
25
+ images?: Record<string, ImageBuffer>;
26
+ data?: Record<string, unknown>;
27
+ };
28
+ type NodeRunner<TParams> = {
29
+ bivarianceHack(context: NodeContext, state: NodeState, params: TParams): Promise<NodeResult> | NodeResult;
30
+ }['bivarianceHack'];
12
31
  /**
13
32
  * Pipeline node definition.
14
33
  */
15
- export type ImageNode = {
34
+ export type NodeDefinition<TParams = unknown> = {
16
35
  name: string;
17
- params?: unknown;
18
- run: (context: NodeContext, image: ImageBuffer) => Promise<ImageBuffer> | ImageBuffer;
36
+ params?: TParams;
37
+ inputs?: string[];
38
+ outputs?: string[];
39
+ run: NodeRunner<TParams>;
40
+ };
41
+ /**
42
+ * Alias for image-focused nodes.
43
+ */
44
+ export type ImageNode<TParams = unknown> = NodeDefinition<TParams>;
45
+ /**
46
+ * Image node with typed parameters metadata.
47
+ */
48
+ export type ParametricNode<TParams> = ImageNode<TParams> & {
49
+ params: TParams;
50
+ };
51
+ /**
52
+ * Definition for a reusable node.
53
+ */
54
+ export declare function defineNode<TParams>(definition: NodeDefinition<TParams>): NodeDefinition<TParams>;
55
+ /**
56
+ * Image node input definition.
57
+ */
58
+ export type ImageNodeOptions = {
59
+ input?: string;
60
+ output?: string;
61
+ };
62
+ /**
63
+ * 2D pixel matrix representation.
64
+ */
65
+ export type PixelMatrix = Pixel[][];
66
+ /**
67
+ * Context provided to pixel-based node handlers.
68
+ */
69
+ export type PixelNodeInfo<TParams> = {
70
+ context: NodeContext;
71
+ image: ImageBuffer;
72
+ state: NodeState;
73
+ params: TParams;
74
+ width: number;
75
+ height: number;
19
76
  };
77
+ /**
78
+ * Handler signature for pixel-based nodes.
79
+ */
80
+ export type PixelNodeRunner<TParams> = (pixels: PixelMatrix, info: PixelNodeInfo<TParams>) => PixelMatrix | ImageBuffer | Promise<PixelMatrix | ImageBuffer>;
81
+ /**
82
+ * Simplified node definition.
83
+ */
84
+ export type SimpleNodeDefinition<TParams> = {
85
+ name?: string;
86
+ params?: TParams;
87
+ input?: string;
88
+ output?: string;
89
+ run: PixelNodeRunner<TParams>;
90
+ };
91
+ /**
92
+ * Creates a node that reads a single image key and writes a single image key.
93
+ */
94
+ export declare function createImageNode<TParams>(name: string, params: TParams, run: (context: NodeContext, image: ImageBuffer, params: TParams, state: NodeState) => Promise<ImageBuffer> | ImageBuffer, options?: ImageNodeOptions): ImageNode<TParams>;
95
+ /**
96
+ * Creates a node that operates on a 2D pixel matrix.
97
+ */
98
+ export declare function createPixelNode<TParams>(name: string, params: TParams, run: PixelNodeRunner<TParams>, options?: ImageNodeOptions): ImageNode<TParams>;
99
+ /**
100
+ * Creates a simplified pixel-based node with optional name and parameters.
101
+ */
102
+ export declare function node<TParams>(definition: SimpleNodeDefinition<TParams>): ImageNode<TParams>;
103
+ /**
104
+ * Returns the image associated with the given key.
105
+ */
106
+ export declare function getImage(state: NodeState, key?: string): ImageBuffer;
107
+ /**
108
+ * Merges a node result into a state snapshot.
109
+ */
110
+ export declare function mergeNodeState(state: NodeState, result: NodeResult): NodeState;
111
+ /**
112
+ * Runs a node and returns its raw result.
113
+ */
114
+ export declare function runNode(node: ImageNode, context: NodeContext, state: NodeState): Promise<NodeResult>;
115
+ /**
116
+ * Runs a node and returns a single image output.
117
+ */
118
+ export declare function runNodeImage(node: ImageNode, context: NodeContext, state: NodeState, outputKey?: string): Promise<ImageBuffer>;
20
119
  /**
21
120
  * Selector used to choose pixels for masked execution.
22
121
  */
@@ -25,24 +124,21 @@ export type PixelSelector = (pixel: Pixel, x: number, y: number, context: NodeCo
25
124
  * Masking options for nodes.
26
125
  */
27
126
  export type SelectionOptions = {
28
- /**
29
- * preserve: keep non-selected pixels from the original image.
30
- * clip: replace non-selected pixels with outsideColor.
31
- */
32
127
  mode?: SelectionMode;
33
- /**
34
- * Color used for clip mode. Defaults to transparent black.
35
- */
36
128
  outsideColor?: ColorInput;
37
129
  };
38
130
  /**
39
131
  * Masking mode for selection.
40
132
  */
41
133
  export type SelectionMode = 'preserve' | 'clip';
134
+ /**
135
+ * Image source input accepted by nodes.
136
+ */
137
+ export type ImageInput = ImageSource | ImageBuffer | ImageNode;
42
138
  /**
43
139
  * Mask source for color mapping.
44
140
  */
45
- export type MaskMapSource = ImageSource | ImageBuffer | ImageNode;
141
+ export type MaskMapSource = ImageInput;
46
142
  /**
47
143
  * Color-to-source mapping entry.
48
144
  */
@@ -91,12 +187,6 @@ export declare function createLumaSelector(threshold: number): PixelSelector;
91
187
  * Creates an alpha-based selector.
92
188
  */
93
189
  export declare function createAlphaSelector(threshold: number): PixelSelector;
94
- /**
95
- * Image node with typed parameters metadata.
96
- */
97
- export type ParametricNode<TParams> = ImageNode & {
98
- params: TParams;
99
- };
100
190
  /**
101
191
  * Creates a node with typed parameters stored in the node metadata.
102
192
  */
@@ -104,7 +194,7 @@ export declare function createParamNode<TParams>(name: string, params: TParams,
104
194
  /**
105
195
  * Creates a masked node that only processes selected pixels.
106
196
  */
107
- export declare function createMaskedNode(node: ImageNode, selector: PixelSelector, options?: SelectionOptions): ImageNode;
197
+ export declare function createMaskedNode(node: ImageNode, selector: PixelSelector, options?: SelectionOptions, io?: ImageNodeOptions): ImageNode;
108
198
  /**
109
199
  * Creates a node that composites sources based on a color mask.
110
200
  */
@@ -130,10 +220,105 @@ export type NoiseOptions = {
130
220
  alpha?: number;
131
221
  grayscale?: boolean;
132
222
  };
223
+ /**
224
+ * Options for creating a value noise node.
225
+ */
226
+ export type ValueNoiseOptions = {
227
+ scale?: number;
228
+ octaves?: number;
229
+ persistence?: number;
230
+ lacunarity?: number;
231
+ min?: number;
232
+ max?: number;
233
+ alpha?: number;
234
+ };
235
+ /**
236
+ * Options for creating a Voronoi noise node.
237
+ */
238
+ export type VoronoiNoiseOptions = {
239
+ scale?: number;
240
+ jitter?: number;
241
+ min?: number;
242
+ max?: number;
243
+ alpha?: number;
244
+ mode?: 'distance' | 'edge';
245
+ };
246
+ /**
247
+ * Options for creating a fractal noise node.
248
+ */
249
+ export type FractalNoiseOptions = {
250
+ scale?: number;
251
+ octaves?: number;
252
+ persistence?: number;
253
+ lacunarity?: number;
254
+ min?: number;
255
+ max?: number;
256
+ alpha?: number;
257
+ };
258
+ /**
259
+ * Options for creating a Perlin noise node.
260
+ */
261
+ export type PerlinNoiseOptions = {
262
+ scale?: number;
263
+ octaves?: number;
264
+ persistence?: number;
265
+ lacunarity?: number;
266
+ min?: number;
267
+ max?: number;
268
+ alpha?: number;
269
+ };
270
+ /**
271
+ * Options for creating a turbulence noise node.
272
+ */
273
+ export type TurbulenceNoiseOptions = {
274
+ scale?: number;
275
+ octaves?: number;
276
+ persistence?: number;
277
+ lacunarity?: number;
278
+ min?: number;
279
+ max?: number;
280
+ alpha?: number;
281
+ };
282
+ /**
283
+ * Options for creating a ridged noise node.
284
+ */
285
+ export type RidgedNoiseOptions = {
286
+ scale?: number;
287
+ octaves?: number;
288
+ persistence?: number;
289
+ lacunarity?: number;
290
+ min?: number;
291
+ max?: number;
292
+ alpha?: number;
293
+ };
133
294
  /**
134
295
  * Creates a node that applies seeded noise to every pixel.
135
296
  */
136
297
  export declare function createNoiseNode(options?: NoiseOptions): ImageNode;
298
+ /**
299
+ * Creates a node that generates value noise.
300
+ */
301
+ export declare function createValueNoiseNode(options?: ValueNoiseOptions): ImageNode;
302
+ /**
303
+ * Creates a node that generates Voronoi noise.
304
+ */
305
+ export declare function createVoronoiNoiseNode(options?: VoronoiNoiseOptions): ImageNode;
306
+ /**
307
+ * Creates a node that generates fractal value noise.
308
+ */
309
+ export declare function createFractalNoiseNode(options?: FractalNoiseOptions): ImageNode;
310
+ /**
311
+ * Creates a node that generates Perlin noise.
312
+ */
313
+ export declare function createPerlinNoiseNode(options?: PerlinNoiseOptions): ImageNode;
314
+ /**
315
+ * Creates a node that generates turbulence noise.
316
+ */
317
+ export declare function createTurbulenceNoiseNode(options?: TurbulenceNoiseOptions): ImageNode;
318
+ /**
319
+ * Creates a node that generates ridged noise.
320
+ */
321
+ export declare function createRidgedNoiseNode(options?: RidgedNoiseOptions): ImageNode;
137
322
  /**
138
323
  * Options for convolution nodes.
139
324
  */
@@ -239,3 +424,8 @@ export declare function createEdgeDetectNode(): ImageNode;
239
424
  * Creates a node that resizes the image to the target dimensions.
240
425
  */
241
426
  export declare function createResizeNode(width: number, height: number, options?: ResizeOptions): ImageNode;
427
+ /**
428
+ * Creates a node that renders text onto an image.
429
+ */
430
+ export declare function createTextNode(options: TextOptions): ImageNode<TextOptions>;
431
+ export {};
@@ -1,14 +1,19 @@
1
1
  import { ImageBuffer } from './image';
2
2
  import { ImageSource } from './types';
3
3
  import { SeededRandom } from './random';
4
- import { ImageNode } from './nodes';
4
+ import { ImageNode, NodeState } from './nodes';
5
5
  /**
6
6
  * Options for running a pipeline.
7
7
  */
8
8
  export type PipelineOptions = {
9
9
  seed?: number | string;
10
10
  random?: SeededRandom;
11
+ data?: Record<string, unknown>;
11
12
  };
13
+ /**
14
+ * Supported inputs for running a pipeline.
15
+ */
16
+ export type PipelineInput = ImageSource | ImageBuffer | NodeState;
12
17
  /**
13
18
  * Sequential pipeline that runs image nodes in order.
14
19
  */
@@ -25,9 +30,17 @@ export declare class Pipeline {
25
30
  /**
26
31
  * Executes the pipeline against an input source or buffer.
27
32
  */
28
- run(input: ImageSource | ImageBuffer, options?: PipelineOptions): Promise<ImageBuffer>;
33
+ run(input: PipelineInput, options?: PipelineOptions): Promise<ImageBuffer>;
34
+ /**
35
+ * Executes the pipeline and returns the full node state.
36
+ */
37
+ runState(input: PipelineInput, options?: PipelineOptions): Promise<NodeState>;
29
38
  }
30
39
  /**
31
40
  * Creates a small example pipeline for quick sanity checks.
32
41
  */
33
42
  export declare function createExamplePipeline(): Pipeline;
43
+ /**
44
+ * Creates a pipeline with the provided nodes.
45
+ */
46
+ export declare function pipeline(...nodes: ImageNode[]): Pipeline;
@@ -1,4 +1,5 @@
1
1
  import { ImageBuffer } from './image';
2
+ import { ColorInput } from './color';
2
3
  import { ImageSource, PixelLike, PixelFormat } from './types';
3
4
  /**
4
5
  * Creates an ImageSource from a local file path.
@@ -38,6 +39,56 @@ export type ResizeOptions = {
38
39
  fit?: 'contain' | 'cover' | 'fill' | 'inside' | 'outside';
39
40
  withoutEnlargement?: boolean;
40
41
  };
42
+ /**
43
+ * Text font source configuration.
44
+ */
45
+ export type TextFontSource = {
46
+ filePath?: string;
47
+ data?: Buffer;
48
+ mime?: string;
49
+ };
50
+ /**
51
+ * Text font configuration.
52
+ */
53
+ export type TextFont = {
54
+ family: string;
55
+ source?: TextFontSource;
56
+ weight?: number | string;
57
+ style?: 'normal' | 'italic' | 'oblique';
58
+ };
59
+ /**
60
+ * Text layout options.
61
+ */
62
+ export type TextLayout = {
63
+ x: number;
64
+ y: number;
65
+ maxWidth?: number;
66
+ maxLines?: number;
67
+ align?: 'left' | 'center' | 'right';
68
+ lineHeight?: number;
69
+ letterSpacing?: number;
70
+ };
71
+ /**
72
+ * Text style options.
73
+ */
74
+ export type TextStyle = {
75
+ fontSize?: number;
76
+ color?: ColorInput;
77
+ bold?: boolean;
78
+ italic?: boolean;
79
+ underline?: boolean;
80
+ strikethrough?: boolean;
81
+ opacity?: number;
82
+ };
83
+ /**
84
+ * Text rendering options.
85
+ */
86
+ export type TextOptions = {
87
+ text: string;
88
+ font: TextFont;
89
+ layout: TextLayout;
90
+ style?: TextStyle;
91
+ };
41
92
  /**
42
93
  * Serializes an ImageBuffer to an encoded image buffer.
43
94
  */
@@ -50,3 +101,7 @@ export declare function saveImage(image: ImageBuffer, outputPath: string, option
50
101
  * Resizes an ImageBuffer and returns a new buffer.
51
102
  */
52
103
  export declare function resizeImage(image: ImageBuffer, width: number, height: number, options?: ResizeOptions): Promise<ImageBuffer>;
104
+ /**
105
+ * Renders text onto an ImageBuffer.
106
+ */
107
+ export declare function renderText(image: ImageBuffer, options: TextOptions): Promise<ImageBuffer>;
package/dist/index.d.ts CHANGED
@@ -3,8 +3,9 @@ export { colorDistance, hexToRgba, hslaToRgba, hsvaToRgba, rgbaToHex, rgbaToHsla
3
3
  export type { Pixel, PixelFormat, PixelLike, ImageSource } from './core/types';
4
4
  export { ImageBuffer } from './core/image';
5
5
  export { SeededRandom, createRandom } from './core/random';
6
- export type { ResizeOptions, SaveImageOptions } from './core/sources';
7
- export { imageToBuffer, loadImage, resizeImage, saveImage, sourceFromBuffer, sourceFromDataUri, sourceFromEmpty, sourceFromPath, sourceFromUrl, } from './core/sources';
8
- export type { CircleSelectorOptions, ImageNode, MaskMapEntry, MaskMapOptions, MaskMapSource, NodeContext, ParametricNode, PixelSelector, RectSelectorOptions, SelectionMode, SelectionOptions, } from './core/nodes';
9
- export { createBrightnessNode, createCircleSelector, createCheckerboardNode, createCircleNode, createConvolutionNode, createContrastNode, createAlphaSelector, createEdgeDetectNode, createFillNode, createGammaNode, createGaussianBlurNode, createGaussianNoiseNode, createGrayscaleNode, createInvertNode, createLumaSelector, createMapNode, createMaskMapNode, createMaskedNode, createNoiseNode, createPaletteMapNode, createParamNode, createRandomFillNode, createRectSelector, createResizeNode, createSelectionCropNode, createRectNode, createSaltPepperNoiseNode, createSharpenNode, createThresholdNode, buildBoxKernel, buildGaussianKernel, } from './core/nodes';
10
- export { Pipeline, createExamplePipeline } from './core/pipeline';
6
+ export type { ResizeOptions, SaveImageOptions, TextFont, TextFontSource, TextLayout, TextOptions, TextStyle, } from './core/sources';
7
+ export { imageToBuffer, loadImage, renderText, resizeImage, saveImage, sourceFromBuffer, sourceFromDataUri, sourceFromEmpty, sourceFromPath, sourceFromUrl, } from './core/sources';
8
+ export type { CircleSelectorOptions, ImageInput, ImageNode, ImageNodeOptions, MaskMapEntry, MaskMapOptions, MaskMapSource, NodeDefinition, NodeContext, NodeResult, NodeState, ParametricNode, PixelMatrix, PixelNodeInfo, PixelNodeRunner, PixelSelector, FractalNoiseOptions, PerlinNoiseOptions, RectSelectorOptions, SelectionMode, SelectionOptions, SimpleNodeDefinition, ValueNoiseOptions, RidgedNoiseOptions, TurbulenceNoiseOptions, VoronoiNoiseOptions, } from './core/nodes';
9
+ export { DEFAULT_IMAGE_KEY, createBrightnessNode, createCircleSelector, createCheckerboardNode, createCircleNode, createConvolutionNode, createContrastNode, createAlphaSelector, createEdgeDetectNode, createFillNode, createGammaNode, createGaussianBlurNode, createGaussianNoiseNode, createGrayscaleNode, createInvertNode, createImageNode, createPixelNode, createLumaSelector, createMapNode, createMaskMapNode, createMaskedNode, createNoiseNode, createFractalNoiseNode, createPerlinNoiseNode, createRidgedNoiseNode, createTurbulenceNoiseNode, createValueNoiseNode, createVoronoiNoiseNode, createPaletteMapNode, createParamNode, createRandomFillNode, createRectSelector, createResizeNode, createSelectionCropNode, createRectNode, createSaltPepperNoiseNode, createSharpenNode, createThresholdNode, createTextNode, defineNode, getImage, mergeNodeState, node, runNode, runNodeImage, buildBoxKernel, buildGaussianKernel, } from './core/nodes';
10
+ export type { PipelineInput, PipelineOptions } from './core/pipeline';
11
+ export { Pipeline, createExamplePipeline, pipeline } from './core/pipeline';