@enslo/sd-metadata 1.8.0 → 2.0.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.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,34 @@
2
2
  * PNG text chunk (tEXt or iTXt)
3
3
  */
4
4
  type PngTextChunk = TExtChunk | ITXtChunk;
5
+ /**
6
+ * tEXt chunk (Latin-1 encoded text)
7
+ */
8
+ interface TExtChunk {
9
+ type: 'tEXt';
10
+ /** Chunk keyword (e.g., 'parameters', 'Comment') */
11
+ keyword: string;
12
+ /** Text content */
13
+ text: string;
14
+ }
15
+ /**
16
+ * iTXt chunk (UTF-8 encoded international text)
17
+ */
18
+ interface ITXtChunk {
19
+ type: 'iTXt';
20
+ /** Chunk keyword */
21
+ keyword: string;
22
+ /** Compression flag (0=uncompressed, 1=compressed) */
23
+ compressionFlag: number;
24
+ /** Compression method (0=zlib/deflate) */
25
+ compressionMethod: number;
26
+ /** Language tag (BCP 47) */
27
+ languageTag: string;
28
+ /** Translated keyword */
29
+ translatedKeyword: string;
30
+ /** Text content */
31
+ text: string;
32
+ }
5
33
  /**
6
34
  * Source location of a metadata segment.
7
35
  * Used for round-tripping: reading and writing back to the correct location.
@@ -40,33 +68,9 @@ type RawMetadata = {
40
68
  segments: MetadataSegment[];
41
69
  };
42
70
  /**
43
- * tEXt chunk (Latin-1 encoded text)
44
- */
45
- interface TExtChunk {
46
- type: 'tEXt';
47
- /** Chunk keyword (e.g., 'parameters', 'Comment') */
48
- keyword: string;
49
- /** Text content */
50
- text: string;
51
- }
52
- /**
53
- * iTXt chunk (UTF-8 encoded international text)
71
+ * Known AI image generation software
54
72
  */
55
- interface ITXtChunk {
56
- type: 'iTXt';
57
- /** Chunk keyword */
58
- keyword: string;
59
- /** Compression flag (0=uncompressed, 1=compressed) */
60
- compressionFlag: number;
61
- /** Compression method (0=zlib/deflate) */
62
- compressionMethod: number;
63
- /** Language tag (BCP 47) */
64
- languageTag: string;
65
- /** Translated keyword */
66
- translatedKeyword: string;
67
- /** Text content */
68
- text: string;
69
- }
73
+ type GenerationSoftware = 'novelai' | 'comfyui' | 'swarmui' | 'tensorart' | 'stability-matrix' | 'invokeai' | 'forge' | 'forge-classic' | 'forge-neo' | 'reforge' | 'easy-reforge' | 'sd-webui' | 'sd-next' | 'civitai' | 'hf-space' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
70
74
  /**
71
75
  * Base metadata fields shared by all tools
72
76
  */
@@ -196,7 +200,7 @@ type ComfyUIMetadata = BasicComfyUIMetadata | SwarmUIMetadata;
196
200
  * NovelAI's character prompts or ComfyUI's node graphs.
197
201
  */
198
202
  interface StandardMetadata extends BaseMetadata {
199
- software: 'sd-webui' | 'sd-next' | 'forge' | 'forge-neo' | 'invokeai' | 'civitai' | 'hf-space' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
203
+ software: 'sd-webui' | 'sd-next' | 'forge' | 'forge-classic' | 'forge-neo' | 'reforge' | 'easy-reforge' | 'invokeai' | 'civitai' | 'hf-space' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
200
204
  }
201
205
  /**
202
206
  * Unified generation metadata (discriminated union)
@@ -215,6 +219,18 @@ interface StandardMetadata extends BaseMetadata {
215
219
  * ```
216
220
  */
217
221
  type GenerationMetadata = NovelAIMetadata | ComfyUIMetadata | StandardMetadata;
222
+ /**
223
+ * User-created custom metadata for the embed() and stringify() APIs
224
+ *
225
+ * While {@link GenerationMetadata} represents parsed output from a known AI tool,
226
+ * EmbedMetadata is designed for users to compose their own metadata from
227
+ * scratch. Includes all base generation fields plus optional character
228
+ * prompts and extras for the settings line.
229
+ */
230
+ type EmbedMetadata = BaseMetadata & Pick<NovelAIMetadata, 'characterPrompts'> & {
231
+ /** Additional key-value pairs for the settings line */
232
+ extras?: Record<string, string | number>;
233
+ };
218
234
  /**
219
235
  * Model settings
220
236
  */
@@ -288,15 +304,9 @@ type ParseResult = {
288
304
  status: 'invalid';
289
305
  message?: string;
290
306
  };
291
-
292
307
  /**
293
- * Read API for sd-metadata
294
- *
295
- * Handles reading and parsing metadata from images.
296
- * Automatically detects image format and extracts embedded generation metadata.
308
+ * Options for the read function
297
309
  */
298
-
299
- /** Options for the read function */
300
310
  interface ReadOptions {
301
311
  /**
302
312
  * When true, dimensions are taken strictly from metadata only.
@@ -305,25 +315,6 @@ interface ReadOptions {
305
315
  */
306
316
  strict?: boolean;
307
317
  }
308
- /**
309
- * Read and parse metadata from an image
310
- *
311
- * Automatically detects the image format (PNG, JPEG, WebP) and parses
312
- * any embedded generation metadata.
313
- *
314
- * @param input - Image file data (Uint8Array or ArrayBuffer)
315
- * @param options - Read options
316
- * @returns Parse result containing metadata and raw data
317
- */
318
- declare function read(input: Uint8Array | ArrayBuffer, options?: ReadOptions): ParseResult;
319
-
320
- /**
321
- * Write API for sd-metadata
322
- *
323
- * Handles writing metadata to images with automatic format conversion.
324
- * Supports PNG, JPEG, and WebP formats.
325
- */
326
-
327
318
  /**
328
319
  * Warning types for write operations
329
320
  */
@@ -356,50 +347,39 @@ type WriteResult = {
356
347
  ok: false;
357
348
  error: WriteError;
358
349
  };
359
- /**
360
- * Write metadata to an image
361
- *
362
- * Automatically detects the target image format and converts the metadata
363
- * if necessary. For unrecognized metadata with cross-format conversion,
364
- * metadata is dropped and a warning is returned.
365
- *
366
- * @param input - Target image file data (Uint8Array or ArrayBuffer)
367
- * @param metadata - ParseResult from `read()`
368
- * @returns New image data with embedded metadata (or warning if metadata was dropped)
369
- */
370
- declare function write(input: Uint8Array | ArrayBuffer, metadata: ParseResult): WriteResult;
371
350
 
372
351
  /**
373
- * WebUI (A1111) format writer for sd-metadata
352
+ * Embed API for sd-metadata
374
353
  *
375
- * Converts any GenerationMetadata to SD WebUI (A1111) plain text format
376
- * and writes it to PNG, JPEG, or WebP images.
354
+ * Write user-created or parsed metadata in A1111 format to PNG, JPEG,
355
+ * or WebP images. Accepts both EmbedMetadata (custom metadata composed
356
+ * by the user) and GenerationMetadata (parsed output from AI tools).
377
357
  */
378
358
 
379
359
  /**
380
- * Write metadata to an image in SD WebUI format
360
+ * Embed metadata into an image
381
361
  *
382
- * Converts the provided GenerationMetadata to SD WebUI (A1111) plain text
383
- * format and embeds it into the image. This allows you to:
384
- * - Create custom metadata from scratch
385
- * - Modify existing metadata
386
- * - Convert metadata from any tool to SD WebUI-compatible format
362
+ * Converts the provided metadata to A1111 plain text format and embeds it
363
+ * into the image. Accepts {@link EmbedMetadata} for user-created custom metadata, or
364
+ * {@link GenerationMetadata} for re-embedding parsed output from any AI tool.
365
+ *
366
+ * Extras (`metadata.extras`) allow adding arbitrary key-value pairs to the
367
+ * settings line. If an extras key matches a structured field (e.g., "Steps"),
368
+ * the extras value overrides the structured value at its original position.
387
369
  *
388
370
  * The metadata is stored differently based on image format:
389
371
  * - PNG: `parameters` tEXt/iTXt chunk (encoding auto-selected based on content)
390
372
  * - JPEG/WebP: Exif UserComment field
391
373
  *
392
374
  * @param input - Target image file data (Uint8Array or ArrayBuffer)
393
- * @param metadata - Generation metadata to embed
375
+ * @param metadata - Metadata to embed (EmbedMetadata or GenerationMetadata)
394
376
  * @returns New image data with embedded metadata, or error
395
377
  *
396
378
  * @example
397
379
  * ```typescript
398
- * import { writeAsWebUI } from '@enslo/sd-metadata';
380
+ * import { embed } from '@enslo/sd-metadata';
399
381
  *
400
- * // Create custom metadata
401
382
  * const metadata = {
402
- * software: 'sd-webui',
403
383
  * prompt: 'masterpiece, 1girl',
404
384
  * negativePrompt: 'lowres, bad quality',
405
385
  * width: 512,
@@ -408,85 +388,139 @@ declare function write(input: Uint8Array | ArrayBuffer, metadata: ParseResult):
408
388
  * model: { name: 'model.safetensors' },
409
389
  * };
410
390
  *
411
- * // Embed into image
412
- * const result = writeAsWebUI(imageData, metadata);
391
+ * // Embed with custom extras
392
+ * const result = embed(imageData, {
393
+ * ...metadata,
394
+ * extras: { Version: 'v1.10.0', 'Lora hashes': 'abc123' },
395
+ * });
396
+ *
413
397
  * if (result.ok) {
414
398
  * writeFileSync('output.png', result.value);
415
399
  * }
416
400
  * ```
417
401
  */
418
- declare function writeAsWebUI(input: Uint8Array | ArrayBuffer, metadata: GenerationMetadata): WriteResult;
402
+ declare function embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult;
403
+
404
+ /**
405
+ * Read API for sd-metadata
406
+ *
407
+ * Handles reading and parsing metadata from images.
408
+ * Automatically detects image format and extracts embedded generation metadata.
409
+ */
419
410
 
420
411
  /**
421
- * A1111-format metadata serialization utilities
412
+ * Read and parse metadata from an image
422
413
  *
423
- * Converts GenerationMetadata to A1111 (SD WebUI) plain text format.
414
+ * Automatically detects the image format (PNG, JPEG, WebP) and parses
415
+ * any embedded generation metadata.
416
+ *
417
+ * @param input - Image file data (Uint8Array or ArrayBuffer)
418
+ * @param options - Read options
419
+ * @returns Parse result containing metadata and raw data
424
420
  */
421
+ declare function read(input: Uint8Array | ArrayBuffer, options?: ReadOptions): ParseResult;
425
422
 
426
423
  /**
427
- * Format metadata as SD WebUI (A1111) plain text
424
+ * Unified metadata stringification
428
425
  *
429
- * Converts GenerationMetadata to human-readable text in the SD WebUI format.
430
- * This provides a standard, tool-agnostic way to display generation metadata
431
- * without needing to manually read individual properties.
426
+ * Builds A1111-format plain text from metadata and provides the stringify()
427
+ * public API for converting any metadata type to a human-readable string.
428
+ */
429
+
430
+ /**
431
+ * Build A1111-format text from EmbedMetadata
432
432
  *
433
- * The output format follows the A1111/SD WebUI convention:
434
- * ```
435
- * positive prompt
436
- * [character prompts for NovelAI]
437
- * Negative prompt: negative prompt
438
- * Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, ...
439
- * ```
433
+ * Output structure:
434
+ * 1. Positive prompt (line-ending normalized)
435
+ * 2. Character prompts (if present)
436
+ * 3. Negative prompt (if non-empty)
437
+ * 4. Settings line (structured fields + extras)
440
438
  *
441
- * @param metadata - Generation metadata from any tool
442
- * @returns Human-readable text in SD WebUI format
439
+ * @param metadata - Embed metadata (extras included via `metadata.extras`)
440
+ * @returns A1111-format plain text
441
+ */
442
+ declare function buildEmbedText(metadata: EmbedMetadata): string;
443
+ /**
444
+ * Format raw metadata as plain text
445
+ *
446
+ * Extracts text content from RawMetadata and returns it as a simple string.
447
+ * Multiple entries are separated by double newlines.
448
+ *
449
+ * @param raw - Raw metadata from ParseResult
450
+ * @returns Plain text content from the metadata
451
+ */
452
+ declare function formatRaw(raw: RawMetadata): string;
453
+ /**
454
+ * Convert metadata to a human-readable string
455
+ *
456
+ * Accepts multiple input types:
457
+ * - `ParseResult`: Automatically selects the best representation based on status
458
+ * - `GenerationMetadata`: Formats as A1111 text (parsed metadata from any tool)
459
+ * - `EmbedMetadata`: Formats as A1111 text (user-created custom metadata)
460
+ *
461
+ * @param input - Parse result, generation metadata, or embed metadata
462
+ * @returns Human-readable text representation, or empty string if no data
443
463
  *
444
464
  * @example
445
465
  * ```typescript
446
- * import { read, formatAsWebUI } from '@enslo/sd-metadata';
466
+ * import { read, stringify } from '@enslo/sd-metadata';
447
467
  *
468
+ * // From parse result
448
469
  * const result = read(imageData);
470
+ * const text = stringify(result);
471
+ *
472
+ * // From GenerationMetadata (e.g. after parsing)
449
473
  * if (result.status === 'success') {
450
- * const text = formatAsWebUI(result.metadata);
451
- * console.log(text);
452
- * // Output:
453
- * // masterpiece, 1girl
454
- * // Negative prompt: low quality, bad anatomy
455
- * // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
474
+ * const text3 = stringify(result.metadata);
456
475
  * }
476
+ *
477
+ * // From EmbedMetadata (e.g. user-created)
478
+ * const text2 = stringify({
479
+ * prompt: 'masterpiece, 1girl',
480
+ * negativePrompt: '',
481
+ * width: 512,
482
+ * height: 768,
483
+ * sampling: { steps: 20, sampler: 'Euler a', cfg: 7, seed: 12345 },
484
+ * extras: { Version: 'v1.10.0' },
485
+ * });
457
486
  * ```
458
487
  */
459
- declare function formatAsWebUI(metadata: GenerationMetadata): string;
488
+ declare function stringify(input: ParseResult | EmbedMetadata | GenerationMetadata): string;
460
489
 
461
490
  /**
462
- * Raw metadata serialization utilities
491
+ * Write API for sd-metadata
463
492
  *
464
- * Formats RawMetadata as human-readable plain text.
493
+ * Handles writing metadata to images with automatic format conversion.
494
+ * Supports PNG, JPEG, and WebP formats.
465
495
  */
466
496
 
467
497
  /**
468
- * Format raw metadata as plain text
469
- *
470
- * Extracts text content from RawMetadata and returns it as a simple string.
471
- * Multiple entries are separated by double newlines.
498
+ * Write metadata to an image
472
499
  *
473
- * This is useful for displaying unrecognized metadata to end users
474
- * without needing to manually iterate over chunks or segments.
500
+ * Automatically detects the target image format and converts the metadata
501
+ * if necessary. For unrecognized metadata with cross-format conversion,
502
+ * metadata is dropped and a warning is returned.
475
503
  *
476
- * @param raw - Raw metadata from ParseResult
477
- * @returns Plain text content from the metadata
504
+ * @param input - Target image file data (Uint8Array or ArrayBuffer)
505
+ * @param metadata - ParseResult from `read()`
506
+ * @returns New image data with embedded metadata (or warning if metadata was dropped)
507
+ */
508
+ declare function write(input: Uint8Array | ArrayBuffer, metadata: ParseResult): WriteResult;
509
+
510
+ /**
511
+ * Human-readable display labels for each generation software identifier.
478
512
  *
479
513
  * @example
480
514
  * ```typescript
481
- * import { read, formatRaw } from '@enslo/sd-metadata';
515
+ * import { softwareLabels } from '@enslo/sd-metadata';
482
516
  *
483
517
  * const result = read(imageData);
484
- * if (result.status === 'unrecognized') {
485
- * console.log(formatRaw(result.raw));
486
- * // Output: the raw text content without prefixes
518
+ * if (result.status === 'success') {
519
+ * console.log(softwareLabels[result.metadata.software]);
520
+ * // => "NovelAI", "ComfyUI", "Stable Diffusion WebUI", etc.
487
521
  * }
488
522
  * ```
489
523
  */
490
- declare function formatRaw(raw: RawMetadata): string;
524
+ declare const softwareLabels: Readonly<Record<GenerationSoftware, string>>;
491
525
 
492
- export { type CharacterPrompt, type ComfyNode, type ComfyNodeGraph, type ComfyNodeInputValue, type ComfyNodeReference, type GenerationMetadata, type HiresSettings, type ITXtChunk, type MetadataSegment, type MetadataSegmentSource, type ModelSettings, type ParseResult, type PngTextChunk, type RawMetadata, type ReadOptions, type SamplingSettings, type TExtChunk, type UpscaleSettings, type WriteResult, type WriteWarning, formatAsWebUI, formatRaw, read, write, writeAsWebUI };
526
+ export { type BaseMetadata, type CharacterPrompt, type ComfyNode, type ComfyNodeGraph, type ComfyNodeInputValue, type ComfyNodeReference, type EmbedMetadata, type GenerationMetadata, type GenerationSoftware, type HiresSettings, type ITXtChunk, type MetadataSegment, type MetadataSegmentSource, type ModelSettings, type ParseResult, type PngTextChunk, type RawMetadata, type ReadOptions, type SamplingSettings, type TExtChunk, type UpscaleSettings, type WriteResult, type WriteWarning, embed, buildEmbedText as formatAsWebUI, formatRaw, read, softwareLabels, stringify, write, embed as writeAsWebUI };