@enslo/sd-metadata 1.8.1 → 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/README.ja.md CHANGED
@@ -29,17 +29,22 @@ npm install @enslo/sd-metadata
29
29
  | ------ | :---: | :----: | :----: |
30
30
  | [NovelAI](https://novelai.net/) * | ✅ | 🔄️ | ✅ |
31
31
  | [ComfyUI](https://github.com/comfyanonymous/ComfyUI) * | ✅ | 🔄️ | 🔄️ |
32
- | [AUTOMATIC1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) | ⚠️ | ⚠️ | ⚠️ |
33
- | [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) / [Forge Neo](https://github.com/neggles/sd-webui-forge-neoforge) | ✅ | ✅ | ✅ |
32
+ | [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui) | | | |
33
+ | [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) | ✅ | ✅ | ✅ |
34
+ | [Forge Classic](https://github.com/Haoming02/sd-webui-forge-classic/tree/classic) | ✅ | ✅ | ✅ |
35
+ | [Forge Neo](https://github.com/Haoming02/sd-webui-forge-classic/tree/neo) | ✅ | ✅ | ✅ |
36
+ | [reForge](https://github.com/Panchovix/stable-diffusion-webui-reForge) | ✅ | ✅ | ✅ |
37
+ | [EasyReforge](https://github.com/Zuntan03/EasyReforge) | ✅ | ✅ | ✅ |
38
+ | [SD.Next](https://github.com/vladmandic/automatic) | ✅ | ✅ | ✅ |
34
39
  | [InvokeAI](https://github.com/invoke-ai/InvokeAI) | ✅ | 🔄️ | 🔄️ |
35
- | [SwarmUI](https://github.com/Stability-AI/StableSwarmUI) * | ✅ | ✅ | ✅ |
40
+ | [SwarmUI](https://github.com/mcmonkeyprojects/SwarmUI) * | ✅ | ✅ | ✅ |
36
41
  | [Civitai](https://civitai.com/) | ⚠️ | ✅ | ⚠️ |
37
42
  | [TensorArt](https://tensor.art/) | ✅ | 🔄️ | 🔄️ |
38
43
  | [Stability Matrix](https://github.com/LykosAI/StabilityMatrix) | ✅ | 🔄️ | 🔄️ |
39
44
  | [HuggingFace Space](https://huggingface.co/spaces) | ✅ | 🔄️ | 🔄️ |
45
+ | [Fooocus](https://github.com/lllyasviel/Fooocus) | ⚠️ | ⚠️ | ⚠️ |
40
46
  | [Ruined Fooocus](https://github.com/runew0lf/RuinedFooocus) | ✅ | 🔄️ | 🔄️ |
41
47
  | [Easy Diffusion](https://github.com/easydiffusion/easydiffusion) | ⚠️ | ⚠️ | ⚠️ |
42
- | [Fooocus](https://github.com/lllyasviel/Fooocus) | ⚠️ | ⚠️ | ⚠️ |
43
48
 
44
49
  **凡例:**
45
50
 
@@ -149,7 +154,7 @@ if (result.status === 'success') {
149
154
  > 本番環境では `@latest` の代わりに特定のバージョンを指定してください:
150
155
  >
151
156
  > ```text
152
- > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.8.1/dist/index.js
157
+ > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@2.0.0/dist/index.js
153
158
  > ```
154
159
 
155
160
  ### 応用例
@@ -264,16 +269,14 @@ if (result.ok) {
264
269
  </details>
265
270
 
266
271
  <details>
267
- <summary>WebUIフォーマットでメタデータを書き込む</summary>
272
+ <summary>カスタムメタデータの埋め込み</summary>
268
273
 
269
- SD WebUI (A1111) フォーマットでカスタムメタデータを作成して埋め込み:
274
+ A1111フォーマットでカスタムメタデータを作成して埋め込み:
270
275
 
271
276
  ```typescript
272
- import { writeAsWebUI } from '@enslo/sd-metadata';
277
+ import { embed } from '@enslo/sd-metadata';
273
278
 
274
- // カスタムメタデータをゼロから作成
275
279
  const metadata = {
276
- software: 'sd-webui',
277
280
  prompt: 'masterpiece, best quality, 1girl',
278
281
  negativePrompt: 'lowres, bad quality',
279
282
  width: 512,
@@ -288,45 +291,64 @@ const metadata = {
288
291
  };
289
292
 
290
293
  // 任意の画像フォーマット(PNG、JPEG、WebP)に書き込み
291
- const result = writeAsWebUI(imageData, metadata);
294
+ const result = embed(imageData, metadata);
292
295
  if (result.ok) {
293
296
  writeFileSync('output.png', result.value);
294
297
  }
295
298
  ```
296
299
 
300
+ `extras` で設定行に任意のキーバリューを追加できます:
301
+
302
+ ```typescript
303
+ const result = embed(imageData, {
304
+ ...metadata,
305
+ extras: {
306
+ Version: 'v1.10.0',
307
+ 'Lora hashes': 'abc123',
308
+ },
309
+ });
310
+ ```
311
+
297
312
  > [!TIP]
298
- > `writeAsWebUI` は以下の場合に特に便利です:
299
- >
300
- > - プログラムで生成した画像に生成パラメータを埋め込みたい場合
301
- > - ツール固有フォーマットからWebUI互換フォーマットにメタデータを変換する場合
302
- > - WebUIで読み取り可能なメタデータを出力するツールを構築する場合
313
+ > extras のキーが構造化フィールド(例:`Steps`)と一致する場合、extras の値が元の位置で構造化フィールドを上書きします。新しいキーは末尾に追加されます。
314
+
315
+ `EmbedMetadata` はすべての `GenerationMetadata` バリアントのサブセットなので、パース結果のメタデータをそのまま渡せます — `characterPrompts` を持つ NovelAI も含めて:
316
+
317
+ ```typescript
318
+ import { read, embed } from '@enslo/sd-metadata';
319
+
320
+ const result = read(novelaiPng);
321
+ if (result.status === 'success') {
322
+ // NovelAI(や他のツール)のメタデータをそのまま利用可能
323
+ const output = embed(blankJpeg, result.metadata);
324
+ }
325
+ ```
303
326
 
304
327
  </details>
305
328
 
306
329
  <details>
307
330
  <summary>表示用にメタデータをフォーマット</summary>
308
331
 
309
- **どのツールのメタデータであっても**、統一されたWebUIフォーマットのテキストに変換できます。ツール間の差異(NovelAI、ComfyUI、Forgeなど)を吸収し、一貫したテキスト形式に正規化します:
332
+ `ParseResult` を読みやすい文字列に変換します。ステータスに応じて最適な表現を自動選択します:
310
333
 
311
334
  ```typescript
312
- import { read, formatAsWebUI } from '@enslo/sd-metadata';
335
+ import { read, stringify } from '@enslo/sd-metadata';
313
336
 
314
337
  const result = read(imageData);
315
- if (result.status === 'success') {
316
- // どのツールでもOK: NovelAI, ComfyUI, Forge, InvokeAI, etc.
317
- const text = formatAsWebUI(result.metadata);
338
+ const text = stringify(result);
339
+ if (text) {
318
340
  console.log(text);
319
-
320
- // 常に統一されたWebUIフォーマットで出力:
341
+
342
+ // 'success' の場合: WebUIフォーマットで出力:
321
343
  // masterpiece, best quality, 1girl
322
344
  // Negative prompt: lowres, bad quality
323
345
  // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
346
+ //
347
+ // 'unrecognized' の場合: 生のメタデータテキストを出力
348
+ // 'empty' / 'invalid' の場合: 空文字列を返す
324
349
  }
325
350
  ```
326
351
 
327
- > [!NOTE]
328
- > どのツールで生成された画像であっても、`formatAsWebUI` は共通の生成パラメータを抽出し、標準化された形式に整形します。ツール固有のフォーマットを意識することなく、ユーザーにメタデータを表示するのに最適です。
329
-
330
352
  </details>
331
353
 
332
354
  ## APIリファレンス
@@ -366,16 +388,14 @@ if (result.status === 'success') {
366
388
  - `'conversionFailed'`: メタデータ変換に失敗(例:互換性のないフォーマット)
367
389
  - `'writeFailed'`: 画像へのメタデータ埋め込みに失敗
368
390
 
369
- ### `writeAsWebUI(input: Uint8Array | ArrayBuffer, metadata: GenerationMetadata): WriteResult`
391
+ ### `embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult`
370
392
 
371
- SD WebUI (A1111) フォーマットで画像にメタデータを書き込みます。
393
+ SD WebUI (A1111) フォーマットでカスタムメタデータを画像に埋め込みます。
372
394
 
373
395
  **パラメータ:**
374
396
 
375
397
  - `input` - ターゲット画像ファイルデータ(PNG、JPEG、またはWebP)
376
- - `metadata` - 埋め込む生成メタデータ
377
- - 任意のツールからでも、カスタム作成でも可能
378
- - 自動的にWebUIフォーマットに変換される
398
+ - `metadata` - 埋め込む `EmbedMetadata` または `GenerationMetadata`(`extras` で任意のキーバリューを追加可能)
379
399
 
380
400
  **戻り値:**
381
401
 
@@ -390,65 +410,37 @@ SD WebUI (A1111) フォーマットで画像にメタデータを書き込みま
390
410
  - 他のツールからWebUI互換フォーマットにメタデータを変換
391
411
  - WebUIで読み取り可能なメタデータを出力するアプリケーションの構築
392
412
 
393
- ### `formatAsWebUI(metadata: GenerationMetadata): string`
413
+ ### `stringify(input: ParseResult | EmbedMetadata | GenerationMetadata): string`
394
414
 
395
- メタデータをSD WebUI (A1111) フォーマットのテキストにフォーマットします。
415
+ メタデータを読みやすい文字列に変換します。`ParseResult`、`EmbedMetadata`、`GenerationMetadata` のいずれも受け付けます。
396
416
 
397
417
  **パラメータ:**
398
418
 
399
- - `metadata` - 任意のツールからの生成メタデータ
419
+ - `input` - `ParseResult`、`EmbedMetadata`、または `GenerationMetadata`
400
420
 
401
421
  **戻り値:**
402
422
 
403
- - WebUIフォーマットの文字列(プレーンテキスト)
404
-
405
- **出力フォーマット:**
406
-
407
- ```text
408
- positive prompt
409
- [NovelAIのキャラクタープロンプト]
410
- Negative prompt: negative prompt
411
- Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, ...
412
- ```
423
+ - `ParseResult` の場合: `success` → WebUIフォーマット、`unrecognized` → 生テキスト、`empty`/`invalid` → 空文字列
424
+ - `EmbedMetadata` / `GenerationMetadata` の場合: WebUIフォーマットのテキスト
413
425
 
414
426
  **ユースケース:**
415
427
 
416
- - ユーザーに一貫したフォーマットでメタデータを表示
417
- - 生成パラメータをテキストとしてコピー
418
- - 生成設定のログ出力やデバッグ
419
-
420
- ### `formatRaw(raw: RawMetadata): string`
421
-
422
- 生のメタデータをプレーンテキストとしてフォーマットします。
423
-
424
- **パラメータ:**
425
-
426
- - `raw` - `ParseResult` から得られた生のメタデータ(`result.raw`)
427
-
428
- **戻り値:**
428
+ - 画像ビューアやギャラリーでの生成パラメータ表示
429
+ - メタデータをクリップボードに読みやすいテキストとしてコピー
430
+ - パース結果のログ出力やデバッグ
431
+ - `EmbedMetadata` の事前プレビュー(埋め込み前の確認用)
429
432
 
430
- - メタデータのプレーンテキスト内容(複数エントリは空行で区切られる)
433
+ ### `softwareLabels: Record<GenerationSoftware, string>`
431
434
 
432
- **ユースケース:**
433
-
434
- - 認識できないメタデータをユーザーに表示
435
- - 生のメタデータ内容の素早い確認
436
- - パース失敗時のフォールバック表示
437
-
438
- **例:**
435
+ `GenerationSoftware` の識別子から表示用の名前への読み取り専用マッピング。
439
436
 
440
437
  ```typescript
441
- import { read, formatAsWebUI, formatRaw } from '@enslo/sd-metadata';
438
+ import { softwareLabels } from '@enslo/sd-metadata';
442
439
 
443
440
  const result = read(imageData);
444
-
445
- switch (result.status) {
446
- case 'success':
447
- console.log(formatAsWebUI(result.metadata));
448
- break;
449
- case 'unrecognized':
450
- console.log(formatRaw(result.raw));
451
- break;
441
+ if (result.status === 'success') {
442
+ console.log(softwareLabels[result.metadata.software]);
443
+ // => "NovelAI", "ComfyUI", "Stable Diffusion WebUI", etc.
452
444
  }
453
445
  ```
454
446
 
@@ -468,22 +460,26 @@ type ParseResult =
468
460
  | { status: 'invalid'; message?: string };
469
461
  ```
470
462
 
471
- ### `GenerationMetadata`
463
+ ### `BaseMetadata`
472
464
 
473
- `read()` 関数が返す統一されたメタデータ構造。`software` フィールドで区別される3つのメタデータ型のユニオン型です。
465
+ 全メタデータ型で共有される共通フィールド。このインターフェースは `EmbedMetadata` の基盤でもあります。
474
466
 
475
- **共通フィールド(全タイプで利用可能):**
467
+ ```typescript
468
+ interface BaseMetadata {
469
+ prompt: string;
470
+ negativePrompt: string;
471
+ width: number;
472
+ height: number;
473
+ model?: ModelSettings;
474
+ sampling?: SamplingSettings;
475
+ hires?: HiresSettings;
476
+ upscale?: UpscaleSettings;
477
+ }
478
+ ```
476
479
 
477
- 全てのメタデータ型にはこれらの基本フィールドが含まれます:
480
+ ### `GenerationMetadata`
478
481
 
479
- - `prompt: string` - ポジティブプロンプトテキスト
480
- - `negativePrompt: string` - ネガティブプロンプトテキスト
481
- - `width: number` - 画像の幅(ピクセル)
482
- - `height: number` - 画像の高さ(ピクセル)
483
- - `model?: ModelSettings` - モデル情報(name、hash、VAE)
484
- - `sampling?: SamplingSettings` - サンプリングパラメータ(seed、steps、CFG、sampler、scheduler、clipSkip)
485
- - `hires?: HiresSettings` - Hires.fix設定(適用されている場合)
486
- - `upscale?: UpscaleSettings` - アップスケール設定(適用されている場合)
482
+ `read()` 関数が返す統一されたメタデータ構造。`software` フィールドで区別される3つのメタデータ型のユニオン型です。全タイプが `BaseMetadata` を拡張しています。
487
483
 
488
484
  **メタデータ型のバリアント:**
489
485
 
@@ -498,7 +494,7 @@ type ParseResult =
498
494
  - `nodes: ComfyNodeGraph`(comfyui/tensorart/stability-matrixでは必須)
499
495
  - `nodes?: ComfyNodeGraph`(swarmuiではオプション - PNGフォーマットのみ)
500
496
 
501
- - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'invokeai' | 'civitai' | ...`)
497
+ - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'forge-classic' | 'reforge' | 'invokeai' | ...`)
502
498
  ツール固有の拡張なしのベースラインメタデータ。ほとんどのSD WebUIベースのツールで使用。
503
499
 
504
500
  **型定義:**
@@ -545,6 +541,29 @@ if (result.status === 'success') {
545
541
 
546
542
  各メタデータ型の詳細なインターフェース定義については[型ドキュメント](./docs/types.ja.md)を参照してください。
547
543
 
544
+ ### `GenerationSoftware`
545
+
546
+ サポートされている全ソフトウェア識別子の文字列リテラルユニオン型。`softwareLabels` のキー型として使用します。
547
+
548
+ ```typescript
549
+ type GenerationSoftware =
550
+ | 'novelai' | 'comfyui' | 'swarmui' | 'tensorart' | 'stability-matrix'
551
+ | 'sd-webui' | 'forge' | 'forge-classic' | 'forge-neo'
552
+ | 'reforge'| 'easy-reforge' | 'sd-next' | 'civitai' | 'hf-space'
553
+ | 'invokeai' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
554
+ ```
555
+
556
+ ### `EmbedMetadata`
557
+
558
+ `embed()` と `stringify()` で使用するユーザー作成カスタムメタデータ型。`GenerationMetadata` が既知のAIツールからのパース結果を表すのに対し、`EmbedMetadata` はユーザーが独自にメタデータを組み立てるための型です。`BaseMetadata` にオプションのキャラクタープロンプトと設定行への任意キーバリュー(`extras`)を追加。
559
+
560
+ ```typescript
561
+ type EmbedMetadata = BaseMetadata &
562
+ Pick<NovelAIMetadata, 'characterPrompts'> & {
563
+ extras?: Record<string, string | number>;
564
+ };
565
+ ```
566
+
548
567
  ### `RawMetadata`
549
568
 
550
569
  ラウンドトリップ変換のために元のメタデータ構造を保持します。
@@ -560,11 +579,14 @@ type RawMetadata =
560
579
  > TypeScriptユーザー向け:全ての型はエクスポートされており、インポートして使用できます。
561
580
  >
562
581
  > ```typescript
563
- > import type {
564
- > ParseResult,
565
- > GenerationMetadata,
566
- > ModelSettings,
567
- > SamplingSettings
582
+ > import type {
583
+ > BaseMetadata,
584
+ > EmbedMetadata,
585
+ > ParseResult,
586
+ > GenerationMetadata,
587
+ > GenerationSoftware,
588
+ > ModelSettings,
589
+ > SamplingSettings
568
590
  > } from '@enslo/sd-metadata';
569
591
  > ```
570
592
  >
package/README.md CHANGED
@@ -29,17 +29,22 @@ npm install @enslo/sd-metadata
29
29
  | ------ | :---: | :----: | :----: |
30
30
  | [NovelAI](https://novelai.net/) * | ✅ | 🔄️ | ✅ |
31
31
  | [ComfyUI](https://github.com/comfyanonymous/ComfyUI) * | ✅ | 🔄️ | 🔄️ |
32
- | [AUTOMATIC1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) | ⚠️ | ⚠️ | ⚠️ |
33
- | [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) / [Forge Neo](https://github.com/neggles/sd-webui-forge-neoforge) | ✅ | ✅ | ✅ |
32
+ | [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui) | | | |
33
+ | [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) | ✅ | ✅ | ✅ |
34
+ | [Forge Classic](https://github.com/Haoming02/sd-webui-forge-classic/tree/classic) | ✅ | ✅ | ✅ |
35
+ | [Forge Neo](https://github.com/Haoming02/sd-webui-forge-classic/tree/neo) | ✅ | ✅ | ✅ |
36
+ | [reForge](https://github.com/Panchovix/stable-diffusion-webui-reForge) | ✅ | ✅ | ✅ |
37
+ | [EasyReforge](https://github.com/Zuntan03/EasyReforge) | ✅ | ✅ | ✅ |
38
+ | [SD.Next](https://github.com/vladmandic/automatic) | ✅ | ✅ | ✅ |
34
39
  | [InvokeAI](https://github.com/invoke-ai/InvokeAI) | ✅ | 🔄️ | 🔄️ |
35
- | [SwarmUI](https://github.com/Stability-AI/StableSwarmUI) * | ✅ | ✅ | ✅ |
40
+ | [SwarmUI](https://github.com/mcmonkeyprojects/SwarmUI) * | ✅ | ✅ | ✅ |
36
41
  | [Civitai](https://civitai.com/) | ⚠️ | ✅ | ⚠️ |
37
42
  | [TensorArt](https://tensor.art/) | ✅ | 🔄️ | 🔄️ |
38
43
  | [Stability Matrix](https://github.com/LykosAI/StabilityMatrix) | ✅ | 🔄️ | 🔄️ |
39
44
  | [HuggingFace Space](https://huggingface.co/spaces) | ✅ | 🔄️ | 🔄️ |
45
+ | [Fooocus](https://github.com/lllyasviel/Fooocus) | ⚠️ | ⚠️ | ⚠️ |
40
46
  | [Ruined Fooocus](https://github.com/runew0lf/RuinedFooocus) | ✅ | 🔄️ | 🔄️ |
41
47
  | [Easy Diffusion](https://github.com/easydiffusion/easydiffusion) | ⚠️ | ⚠️ | ⚠️ |
42
- | [Fooocus](https://github.com/lllyasviel/Fooocus) | ⚠️ | ⚠️ | ⚠️ |
43
48
 
44
49
  **Legend:**
45
50
 
@@ -148,7 +153,7 @@ if (result.status === 'success') {
148
153
  > For production use, pin to a specific version instead of `@latest`:
149
154
  >
150
155
  > ```text
151
- > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.8.1/dist/index.js
156
+ > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@2.0.0/dist/index.js
152
157
  > ```
153
158
 
154
159
  ### Advanced Examples
@@ -263,16 +268,14 @@ if (result.ok) {
263
268
  </details>
264
269
 
265
270
  <details>
266
- <summary>Writing Metadata in WebUI Format</summary>
271
+ <summary>Embedding Custom Metadata</summary>
267
272
 
268
- Create and embed custom metadata in SD WebUI (A1111) format:
273
+ Create and embed custom metadata in A1111 format:
269
274
 
270
275
  ```typescript
271
- import { writeAsWebUI } from '@enslo/sd-metadata';
276
+ import { embed } from '@enslo/sd-metadata';
272
277
 
273
- // Create custom metadata from scratch
274
278
  const metadata = {
275
- software: 'sd-webui',
276
279
  prompt: 'masterpiece, best quality, 1girl',
277
280
  negativePrompt: 'lowres, bad quality',
278
281
  width: 512,
@@ -287,45 +290,61 @@ const metadata = {
287
290
  };
288
291
 
289
292
  // Write to any image format (PNG, JPEG, WebP)
290
- const result = writeAsWebUI(imageData, metadata);
293
+ const result = embed(imageData, metadata);
291
294
  if (result.ok) {
292
295
  writeFileSync('output.png', result.value);
293
296
  }
294
297
  ```
295
298
 
299
+ You can also add arbitrary key-value pairs to the settings line with `extras`:
300
+
301
+ ```typescript
302
+ const result = embed(imageData, {
303
+ ...metadata,
304
+ extras: { Version: 'v1.10.0', 'Lora hashes': 'abc123' },
305
+ });
306
+ ```
307
+
296
308
  > [!TIP]
297
- > `writeAsWebUI` is particularly useful when:
298
- >
299
- > - Creating images programmatically and want to embed generation parameters
300
- > - Converting metadata from proprietary formats to WebUI-compatible format
301
- > - Building tools that need to output WebUI-readable metadata
309
+ > If an extras key matches a structured field (e.g., `Steps`), the extras value overrides the structured value at its original position. New keys are appended at the end.
310
+
311
+ Since `EmbedMetadata` is a subset of all `GenerationMetadata` variants, you can pass parsed metadata directly — including NovelAI with its `characterPrompts`:
312
+
313
+ ```typescript
314
+ import { read, embed } from '@enslo/sd-metadata';
315
+
316
+ const result = read(novelaiPng);
317
+ if (result.status === 'success') {
318
+ // NovelAI metadata (or any other tool) works as-is
319
+ const output = embed(blankJpeg, result.metadata);
320
+ }
321
+ ```
302
322
 
303
323
  </details>
304
324
 
305
325
  <details>
306
326
  <summary>Formatting Metadata for Display</summary>
307
327
 
308
- Convert metadata from **any supported tool** to a unified, human-readable WebUI format. This normalizes the differences between tools (NovelAI, ComfyUI, Forge, etc.) into a consistent text format:
328
+ Convert a `ParseResult` to a human-readable string. Automatically selects the best representation based on status:
309
329
 
310
330
  ```typescript
311
- import { read, formatAsWebUI } from '@enslo/sd-metadata';
331
+ import { read, stringify } from '@enslo/sd-metadata';
312
332
 
313
333
  const result = read(imageData);
314
- if (result.status === 'success') {
315
- // Works with any tool: NovelAI, ComfyUI, Forge, InvokeAI, etc.
316
- const text = formatAsWebUI(result.metadata);
334
+ const text = stringify(result);
335
+ if (text) {
317
336
  console.log(text);
318
-
319
- // Always outputs in consistent WebUI format:
337
+
338
+ // For 'success': outputs in WebUI format:
320
339
  // masterpiece, best quality, 1girl
321
340
  // Negative prompt: lowres, bad quality
322
341
  // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
342
+ //
343
+ // For 'unrecognized': outputs raw metadata text
344
+ // For 'empty' / 'invalid': returns empty string
323
345
  }
324
346
  ```
325
347
 
326
- > [!NOTE]
327
- > Regardless of which tool generated the image, `formatAsWebUI` extracts the common generation parameters and formats them in a standardized way. This is ideal for displaying metadata to users without worrying about tool-specific formats.
328
-
329
348
  </details>
330
349
 
331
350
  ## API Reference
@@ -365,16 +384,14 @@ Writes metadata to an image file.
365
384
  - `'conversionFailed'`: Metadata conversion failed (e.g., incompatible format)
366
385
  - `'writeFailed'`: Failed to embed metadata into the image
367
386
 
368
- ### `writeAsWebUI(input: Uint8Array | ArrayBuffer, metadata: GenerationMetadata): WriteResult`
387
+ ### `embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult`
369
388
 
370
- Writes metadata to an image in SD WebUI (A1111) format.
389
+ Embeds custom metadata into an image in SD WebUI (A1111) format.
371
390
 
372
391
  **Parameters:**
373
392
 
374
393
  - `input` - Target image file data (PNG, JPEG, or WebP)
375
- - `metadata` - Generation metadata to embed
376
- - Can be from any tool or custom-created
377
- - Automatically converted to WebUI format
394
+ - `metadata` - `EmbedMetadata` or `GenerationMetadata` to embed (use `extras` field for custom settings)
378
395
 
379
396
  **Returns:**
380
397
 
@@ -389,65 +406,40 @@ Writes metadata to an image in SD WebUI (A1111) format.
389
406
  - Converting metadata from other tools to WebUI-compatible format
390
407
  - Building applications that output WebUI-readable metadata
391
408
 
392
- ### `formatAsWebUI(metadata: GenerationMetadata): string`
409
+ ### `stringify(input: ParseResult | EmbedMetadata | GenerationMetadata): string`
393
410
 
394
- Formats metadata as human-readable text in SD WebUI (A1111) format.
411
+ Converts metadata to a human-readable string.
395
412
 
396
413
  **Parameters:**
397
414
 
398
- - `metadata` - Generation metadata from any tool
415
+ - `input` - One of:
416
+ - `ParseResult` from `read()` — selects best representation based on status
417
+ - `EmbedMetadata` or `GenerationMetadata` — formats as A1111 text directly
399
418
 
400
419
  **Returns:**
401
420
 
402
- - Human-readable string in WebUI format (plain text)
403
-
404
- **Output format:**
405
-
406
- ```text
407
- positive prompt
408
- [character prompts for NovelAI]
409
- Negative prompt: negative prompt
410
- Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, ...
411
- ```
421
+ - `ParseResult` with `success` → Human-readable text in WebUI format
422
+ - `ParseResult` with `unrecognized` → Raw metadata as plain text
423
+ - `ParseResult` with `empty` / `invalid` → Empty string
424
+ - `EmbedMetadata` / `GenerationMetadata` → Human-readable text in WebUI format
412
425
 
413
426
  **Use cases:**
414
427
 
415
- - Displaying metadata to users in a consistent format
416
- - Copying generation parameters as text
417
- - Logging or debugging generation settings
428
+ - Displaying generation parameters in image viewers or galleries
429
+ - Copying metadata to clipboard as readable text
430
+ - Logging or debugging parsed metadata
418
431
 
419
- ### `formatRaw(raw: RawMetadata): string`
432
+ ### `softwareLabels: Record<GenerationSoftware, string>`
420
433
 
421
- Formats raw metadata as plain text.
422
-
423
- **Parameters:**
424
-
425
- - `raw` - Raw metadata from `ParseResult` (`result.raw`)
426
-
427
- **Returns:**
428
-
429
- - Plain text content from the metadata (multiple entries separated by blank lines)
430
-
431
- **Use cases:**
432
-
433
- - Displaying unrecognized metadata to users
434
- - Quick inspection of raw metadata content
435
- - Fallback display when parsing fails
436
-
437
- **Example:**
434
+ A read-only mapping from `GenerationSoftware` identifiers to their human-readable display names.
438
435
 
439
436
  ```typescript
440
- import { read, formatAsWebUI, formatRaw } from '@enslo/sd-metadata';
437
+ import { softwareLabels } from '@enslo/sd-metadata';
441
438
 
442
439
  const result = read(imageData);
443
-
444
- switch (result.status) {
445
- case 'success':
446
- console.log(formatAsWebUI(result.metadata));
447
- break;
448
- case 'unrecognized':
449
- console.log(formatRaw(result.raw));
450
- break;
440
+ if (result.status === 'success') {
441
+ console.log(softwareLabels[result.metadata.software]);
442
+ // => "NovelAI", "ComfyUI", "Stable Diffusion WebUI", etc.
451
443
  }
452
444
  ```
453
445
 
@@ -467,22 +459,26 @@ type ParseResult =
467
459
  | { status: 'invalid'; message?: string };
468
460
  ```
469
461
 
470
- ### `GenerationMetadata`
462
+ ### `BaseMetadata`
471
463
 
472
- Unified metadata structure returned by the `read()` function. This is a discriminated union of 3 specific metadata types, distinguished by the `software` field.
464
+ Common fields shared by all metadata types. This interface is also the foundation of `EmbedMetadata`.
473
465
 
474
- **Common Fields (Available in All Types):**
466
+ ```typescript
467
+ interface BaseMetadata {
468
+ prompt: string;
469
+ negativePrompt: string;
470
+ width: number;
471
+ height: number;
472
+ model?: ModelSettings;
473
+ sampling?: SamplingSettings;
474
+ hires?: HiresSettings;
475
+ upscale?: UpscaleSettings;
476
+ }
477
+ ```
475
478
 
476
- All metadata types include these base fields:
479
+ ### `GenerationMetadata`
477
480
 
478
- - `prompt: string` - Positive prompt text
479
- - `negativePrompt: string` - Negative prompt text
480
- - `width: number` - Image width in pixels
481
- - `height: number` - Image height in pixels
482
- - `model?: ModelSettings` - Model information (name, hash, VAE)
483
- - `sampling?: SamplingSettings` - Sampling parameters (seed, steps, CFG, sampler, scheduler, clipSkip)
484
- - `hires?: HiresSettings` - Hires.fix settings (if applied)
485
- - `upscale?: UpscaleSettings` - Upscale settings (if applied)
481
+ Unified metadata structure returned by the `read()` function. This is a discriminated union of 3 specific metadata types, distinguished by the `software` field. All types extend `BaseMetadata`.
486
482
 
487
483
  **Metadata Type Variants:**
488
484
 
@@ -497,7 +493,7 @@ All metadata types include these base fields:
497
493
  - `nodes: ComfyNodeGraph` (required for comfyui/tensorart/stability-matrix)
498
494
  - `nodes?: ComfyNodeGraph` (optional for swarmui - only in PNG format)
499
495
 
500
- - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'invokeai' | 'civitai' | ...`)
496
+ - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'forge-classic' | 'reforge' | 'invokeai' | ...`)
501
497
  Baseline metadata without tool-specific extensions. Used by most SD WebUI-based tools.
502
498
 
503
499
  **Type Definition:**
@@ -544,6 +540,29 @@ if (result.status === 'success') {
544
540
 
545
541
  See [Type Documentation](./docs/types.md) for detailed interface definitions of each metadata type.
546
542
 
543
+ ### `GenerationSoftware`
544
+
545
+ String literal union of all supported software identifiers. Used as the key type for `softwareLabels`.
546
+
547
+ ```typescript
548
+ type GenerationSoftware =
549
+ | 'novelai' | 'comfyui' | 'swarmui' | 'tensorart' | 'stability-matrix'
550
+ | 'sd-webui' | 'forge' | 'forge-classic' | 'forge-neo'
551
+ | 'reforge'| 'easy-reforge' | 'sd-next' | 'civitai' | 'hf-space'
552
+ | 'invokeai' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
553
+ ```
554
+
555
+ ### `EmbedMetadata`
556
+
557
+ User-created custom metadata for the `embed()` and `stringify()` functions. While `GenerationMetadata` represents parsed output from a known AI tool, `EmbedMetadata` is designed for composing metadata from scratch. Extends `BaseMetadata` with optional character prompts and extras.
558
+
559
+ ```typescript
560
+ type EmbedMetadata = BaseMetadata &
561
+ Pick<NovelAIMetadata, 'characterPrompts'> & {
562
+ extras?: Record<string, string | number>;
563
+ };
564
+ ```
565
+
547
566
  ### `RawMetadata`
548
567
 
549
568
  Preserves the original metadata structure for round-trip conversions.
@@ -559,11 +578,14 @@ type RawMetadata =
559
578
  > For TypeScript users: All types are exported and available for import.
560
579
  >
561
580
  > ```typescript
562
- > import type {
563
- > ParseResult,
564
- > GenerationMetadata,
565
- > ModelSettings,
566
- > SamplingSettings
581
+ > import type {
582
+ > BaseMetadata,
583
+ > EmbedMetadata,
584
+ > ParseResult,
585
+ > GenerationMetadata,
586
+ > GenerationSoftware,
587
+ > ModelSettings,
588
+ > SamplingSettings
567
589
  > } from '@enslo/sd-metadata';
568
590
  > ```
569
591
  >