@enslo/sd-metadata 1.8.1 → 2.0.1

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
@@ -11,7 +11,7 @@ AI生成画像に埋め込まれたメタデータを読み書きするための
11
11
  ## 特徴
12
12
 
13
13
  - **マルチフォーマット対応**: PNG (tEXt / iTXt)、JPEG (COM / Exif)、WebP (Exif)
14
- - **統一API**: シンプルな `read()` と `write()` 関数で全フォーマットに対応
14
+ - **シンプルAPI**: `read()`、`write()`、`embed()`、`stringify()` — 4つの関数で全ユースケースをカバー
15
15
  - **TypeScriptネイティブ**: TypeScriptで書かれており、型定義を完全同梱
16
16
  - **ゼロ依存**: Node.jsとブラウザで外部依存なしで動作
17
17
  - **フォーマット変換**: PNG、JPEG、WebP間でメタデータをシームレスに変換
@@ -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
 
@@ -90,10 +95,9 @@ const { read } = require('@enslo/sd-metadata');
90
95
  ### Node.jsでの使用
91
96
 
92
97
  ```typescript
93
- import { read, write } from '@enslo/sd-metadata';
94
- import { readFileSync, writeFileSync } from 'fs';
98
+ import { read, stringify } from '@enslo/sd-metadata';
99
+ import { readFileSync } from 'fs';
95
100
 
96
- // サポートされている任意のフォーマットからメタデータを読み込み
97
101
  const imageData = readFileSync('image.png');
98
102
  const result = read(imageData);
99
103
 
@@ -103,24 +107,30 @@ if (result.status === 'success') {
103
107
  console.log('Model:', result.metadata.model?.name);
104
108
  console.log('Size:', result.metadata.width, 'x', result.metadata.height);
105
109
  }
110
+
111
+ // 読みやすいテキストにフォーマット(任意のstatusで動作)
112
+ const text = stringify(result);
113
+ if (text) {
114
+ console.log(text);
115
+ }
106
116
  ```
107
117
 
108
118
  ### ブラウザでの使用
109
119
 
110
120
  ```typescript
111
- import { read } from '@enslo/sd-metadata';
121
+ import { read, softwareLabels } from '@enslo/sd-metadata';
112
122
 
113
123
  // ファイル入力を処理
114
124
  const fileInput = document.querySelector('input[type="file"]');
115
125
  fileInput.addEventListener('change', async (e) => {
116
126
  const file = e.target.files[0];
117
127
  if (!file) return;
118
-
128
+
119
129
  const arrayBuffer = await file.arrayBuffer();
120
130
  const result = read(arrayBuffer);
121
-
131
+
122
132
  if (result.status === 'success') {
123
- document.getElementById('tool').textContent = result.metadata.software;
133
+ document.getElementById('tool').textContent = softwareLabels[result.metadata.software];
124
134
  document.getElementById('prompt').textContent = result.metadata.prompt;
125
135
  document.getElementById('model').textContent = result.metadata.model?.name || 'N/A';
126
136
  }
@@ -149,7 +159,7 @@ if (result.status === 'success') {
149
159
  > 本番環境では `@latest` の代わりに特定のバージョンを指定してください:
150
160
  >
151
161
  > ```text
152
- > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.8.1/dist/index.js
162
+ > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@2.0.1/dist/index.js
153
163
  > ```
154
164
 
155
165
  ### 応用例
@@ -180,8 +190,7 @@ if (parseResult.status === 'success') {
180
190
  }
181
191
  ```
182
192
 
183
- > [!TIP]
184
- > このライブラリはメタデータの読み書きのみを扱います。実際の画像フォーマット変換(ピクセルのデコード/エンコード)には、[sharp](https://www.npmjs.com/package/sharp)、[jimp](https://www.npmjs.com/package/jimp)、ブラウザCanvas APIなどの画像処理ライブラリを使用してください。
193
+ > **Tip:** このライブラリはメタデータの読み書きのみを扱います。実際の画像フォーマット変換(ピクセルのデコード/エンコード)には、[sharp](https://www.npmjs.com/package/sharp)、[jimp](https://www.npmjs.com/package/jimp)、ブラウザCanvas APIなどの画像処理ライブラリを使用してください。
185
194
 
186
195
  </details>
187
196
 
@@ -264,16 +273,14 @@ if (result.ok) {
264
273
  </details>
265
274
 
266
275
  <details>
267
- <summary>WebUIフォーマットでメタデータを書き込む</summary>
276
+ <summary>カスタムメタデータの埋め込み</summary>
268
277
 
269
- SD WebUI (A1111) フォーマットでカスタムメタデータを作成して埋め込み:
278
+ A1111フォーマットでカスタムメタデータを作成して埋め込み:
270
279
 
271
280
  ```typescript
272
- import { writeAsWebUI } from '@enslo/sd-metadata';
281
+ import { embed } from '@enslo/sd-metadata';
273
282
 
274
- // カスタムメタデータをゼロから作成
275
283
  const metadata = {
276
- software: 'sd-webui',
277
284
  prompt: 'masterpiece, best quality, 1girl',
278
285
  negativePrompt: 'lowres, bad quality',
279
286
  width: 512,
@@ -288,53 +295,76 @@ const metadata = {
288
295
  };
289
296
 
290
297
  // 任意の画像フォーマット(PNG、JPEG、WebP)に書き込み
291
- const result = writeAsWebUI(imageData, metadata);
298
+ const result = embed(imageData, metadata);
292
299
  if (result.ok) {
293
300
  writeFileSync('output.png', result.value);
294
301
  }
295
302
  ```
296
303
 
297
- > [!TIP]
298
- > `writeAsWebUI` は以下の場合に特に便利です:
299
- >
300
- > - プログラムで生成した画像に生成パラメータを埋め込みたい場合
301
- > - ツール固有フォーマットからWebUI互換フォーマットにメタデータを変換する場合
302
- > - WebUIで読み取り可能なメタデータを出力するツールを構築する場合
304
+ `extras` で設定行に任意のキーバリューを追加できます:
305
+
306
+ ```typescript
307
+ const result = embed(imageData, {
308
+ ...metadata,
309
+ extras: {
310
+ Version: 'v1.10.0',
311
+ 'Lora hashes': 'abc123',
312
+ },
313
+ });
314
+ ```
315
+
316
+ > **Tip:** extras のキーが構造化フィールド(例:`Steps`)と一致する場合、extras の値が元の位置で構造化フィールドを上書きします。新しいキーは末尾に追加されます。
317
+
318
+ `EmbedMetadata` はすべての `GenerationMetadata` バリアントのサブセットなので、パース結果のメタデータをそのまま渡せます — `characterPrompts` を持つ NovelAI も含めて:
319
+
320
+ ```typescript
321
+ import { read, embed } from '@enslo/sd-metadata';
322
+
323
+ const result = read(novelaiPng);
324
+ if (result.status === 'success') {
325
+ // NovelAI(や他のツール)のメタデータをそのまま利用可能
326
+ const output = embed(blankJpeg, result.metadata);
327
+ }
328
+ ```
303
329
 
304
330
  </details>
305
331
 
306
332
  <details>
307
333
  <summary>表示用にメタデータをフォーマット</summary>
308
334
 
309
- **どのツールのメタデータであっても**、統一されたWebUIフォーマットのテキストに変換できます。ツール間の差異(NovelAI、ComfyUI、Forgeなど)を吸収し、一貫したテキスト形式に正規化します:
335
+ `ParseResult` を読みやすい文字列に変換します。ステータスに応じて最適な表現を自動選択します:
310
336
 
311
337
  ```typescript
312
- import { read, formatAsWebUI } from '@enslo/sd-metadata';
338
+ import { read, stringify } from '@enslo/sd-metadata';
313
339
 
314
340
  const result = read(imageData);
315
- if (result.status === 'success') {
316
- // どのツールでもOK: NovelAI, ComfyUI, Forge, InvokeAI, etc.
317
- const text = formatAsWebUI(result.metadata);
341
+ const text = stringify(result);
342
+ if (text) {
318
343
  console.log(text);
319
-
320
- // 常に統一されたWebUIフォーマットで出力:
344
+
345
+ // 'success' の場合: WebUIフォーマットで出力:
321
346
  // masterpiece, best quality, 1girl
322
347
  // Negative prompt: lowres, bad quality
323
348
  // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
349
+ //
350
+ // 'unrecognized' の場合: 生のメタデータテキストを出力
351
+ // 'empty' / 'invalid' の場合: 空文字列を返す
324
352
  }
325
353
  ```
326
354
 
327
- > [!NOTE]
328
- > どのツールで生成された画像であっても、`formatAsWebUI` は共通の生成パラメータを抽出し、標準化された形式に整形します。ツール固有のフォーマットを意識することなく、ユーザーにメタデータを表示するのに最適です。
329
-
330
355
  </details>
331
356
 
332
357
  ## APIリファレンス
333
358
 
334
- ### `read(input: Uint8Array | ArrayBuffer): ParseResult`
359
+ ### `read(input: Uint8Array | ArrayBuffer, options?: ReadOptions): ParseResult`
335
360
 
336
361
  画像ファイルからメタデータを読み込み、パースします。
337
362
 
363
+ **パラメータ:**
364
+
365
+ - `input` - 画像ファイルデータ(PNG、JPEG、またはWebP)
366
+ - `options` - オプションの読み込み設定(詳細は[型ドキュメント](./docs/types.ja.md)を参照)
367
+
338
368
  **戻り値:**
339
369
 
340
370
  - `{ status: 'success', metadata, raw }` - パース成功
@@ -366,16 +396,14 @@ if (result.status === 'success') {
366
396
  - `'conversionFailed'`: メタデータ変換に失敗(例:互換性のないフォーマット)
367
397
  - `'writeFailed'`: 画像へのメタデータ埋め込みに失敗
368
398
 
369
- ### `writeAsWebUI(input: Uint8Array | ArrayBuffer, metadata: GenerationMetadata): WriteResult`
399
+ ### `embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult`
370
400
 
371
- SD WebUI (A1111) フォーマットで画像にメタデータを書き込みます。
401
+ SD WebUI (A1111) フォーマットでカスタムメタデータを画像に埋め込みます。
372
402
 
373
403
  **パラメータ:**
374
404
 
375
405
  - `input` - ターゲット画像ファイルデータ(PNG、JPEG、またはWebP)
376
- - `metadata` - 埋め込む生成メタデータ
377
- - 任意のツールからでも、カスタム作成でも可能
378
- - 自動的にWebUIフォーマットに変換される
406
+ - `metadata` - 埋め込む `EmbedMetadata` または `GenerationMetadata`(`extras` で任意のキーバリューを追加可能)
379
407
 
380
408
  **戻り値:**
381
409
 
@@ -390,65 +418,37 @@ SD WebUI (A1111) フォーマットで画像にメタデータを書き込みま
390
418
  - 他のツールからWebUI互換フォーマットにメタデータを変換
391
419
  - WebUIで読み取り可能なメタデータを出力するアプリケーションの構築
392
420
 
393
- ### `formatAsWebUI(metadata: GenerationMetadata): string`
421
+ ### `stringify(input: ParseResult | EmbedMetadata | GenerationMetadata): string`
394
422
 
395
- メタデータをSD WebUI (A1111) フォーマットのテキストにフォーマットします。
423
+ メタデータを読みやすい文字列に変換します。`ParseResult`、`EmbedMetadata`、`GenerationMetadata` のいずれも受け付けます。
396
424
 
397
425
  **パラメータ:**
398
426
 
399
- - `metadata` - 任意のツールからの生成メタデータ
427
+ - `input` - `ParseResult`、`EmbedMetadata`、または `GenerationMetadata`
400
428
 
401
429
  **戻り値:**
402
430
 
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
- ```
431
+ - `ParseResult` の場合: `success` → WebUIフォーマット、`unrecognized` → 生テキスト、`empty`/`invalid` → 空文字列
432
+ - `EmbedMetadata` / `GenerationMetadata` の場合: WebUIフォーマットのテキスト
413
433
 
414
434
  **ユースケース:**
415
435
 
416
- - ユーザーに一貫したフォーマットでメタデータを表示
417
- - 生成パラメータをテキストとしてコピー
418
- - 生成設定のログ出力やデバッグ
436
+ - 画像ビューアやギャラリーでの生成パラメータ表示
437
+ - メタデータをクリップボードに読みやすいテキストとしてコピー
438
+ - パース結果のログ出力やデバッグ
439
+ - `EmbedMetadata` の事前プレビュー(埋め込み前の確認用)
419
440
 
420
- ### `formatRaw(raw: RawMetadata): string`
441
+ ### `softwareLabels: Record<GenerationSoftware, string>`
421
442
 
422
- 生のメタデータをプレーンテキストとしてフォーマットします。
423
-
424
- **パラメータ:**
425
-
426
- - `raw` - `ParseResult` から得られた生のメタデータ(`result.raw`)
427
-
428
- **戻り値:**
429
-
430
- - メタデータのプレーンテキスト内容(複数エントリは空行で区切られる)
431
-
432
- **ユースケース:**
433
-
434
- - 認識できないメタデータをユーザーに表示
435
- - 生のメタデータ内容の素早い確認
436
- - パース失敗時のフォールバック表示
437
-
438
- **例:**
443
+ `GenerationSoftware` の識別子から表示用の名前への読み取り専用マッピング。
439
444
 
440
445
  ```typescript
441
- import { read, formatAsWebUI, formatRaw } from '@enslo/sd-metadata';
446
+ import { softwareLabels } from '@enslo/sd-metadata';
442
447
 
443
448
  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;
449
+ if (result.status === 'success') {
450
+ console.log(softwareLabels[result.metadata.software]);
451
+ // => "NovelAI", "ComfyUI", "Stable Diffusion WebUI", etc.
452
452
  }
453
453
  ```
454
454
 
@@ -468,22 +468,26 @@ type ParseResult =
468
468
  | { status: 'invalid'; message?: string };
469
469
  ```
470
470
 
471
- ### `GenerationMetadata`
471
+ ### `BaseMetadata`
472
472
 
473
- `read()` 関数が返す統一されたメタデータ構造。`software` フィールドで区別される3つのメタデータ型のユニオン型です。
473
+ 全メタデータ型で共有される共通フィールド。このインターフェースは `EmbedMetadata` の基盤でもあります。
474
474
 
475
- **共通フィールド(全タイプで利用可能):**
475
+ ```typescript
476
+ interface BaseMetadata {
477
+ prompt: string;
478
+ negativePrompt: string;
479
+ width: number;
480
+ height: number;
481
+ model?: ModelSettings;
482
+ sampling?: SamplingSettings;
483
+ hires?: HiresSettings;
484
+ upscale?: UpscaleSettings;
485
+ }
486
+ ```
476
487
 
477
- 全てのメタデータ型にはこれらの基本フィールドが含まれます:
488
+ ### `GenerationMetadata`
478
489
 
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` - アップスケール設定(適用されている場合)
490
+ `read()` 関数が返す統一されたメタデータ構造。`software` フィールドで区別される3つのメタデータ型のユニオン型です。全タイプが `BaseMetadata` を拡張しています。
487
491
 
488
492
  **メタデータ型のバリアント:**
489
493
 
@@ -498,7 +502,7 @@ type ParseResult =
498
502
  - `nodes: ComfyNodeGraph`(comfyui/tensorart/stability-matrixでは必須)
499
503
  - `nodes?: ComfyNodeGraph`(swarmuiではオプション - PNGフォーマットのみ)
500
504
 
501
- - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'invokeai' | 'civitai' | ...`)
505
+ - **`StandardMetadata`** (`software: 'sd-webui' | 'forge' | 'forge-classic' | 'reforge' | 'invokeai' | ...`)
502
506
  ツール固有の拡張なしのベースラインメタデータ。ほとんどのSD WebUIベースのツールで使用。
503
507
 
504
508
  **型定義:**
@@ -545,6 +549,29 @@ if (result.status === 'success') {
545
549
 
546
550
  各メタデータ型の詳細なインターフェース定義については[型ドキュメント](./docs/types.ja.md)を参照してください。
547
551
 
552
+ ### `GenerationSoftware`
553
+
554
+ サポートされている全ソフトウェア識別子の文字列リテラルユニオン型。`softwareLabels` のキー型として使用します。
555
+
556
+ ```typescript
557
+ type GenerationSoftware =
558
+ | 'novelai' | 'comfyui' | 'swarmui' | 'tensorart' | 'stability-matrix'
559
+ | 'sd-webui' | 'forge' | 'forge-classic' | 'forge-neo'
560
+ | 'reforge'| 'easy-reforge' | 'sd-next' | 'civitai' | 'hf-space'
561
+ | 'invokeai' | 'easydiffusion' | 'fooocus' | 'ruined-fooocus';
562
+ ```
563
+
564
+ ### `EmbedMetadata`
565
+
566
+ `embed()` と `stringify()` で使用するユーザー作成カスタムメタデータ型。`GenerationMetadata` が既知のAIツールからのパース結果を表すのに対し、`EmbedMetadata` はユーザーが独自にメタデータを組み立てるための型です。`BaseMetadata` にオプションのキャラクタープロンプトと設定行への任意キーバリュー(`extras`)を追加。
567
+
568
+ ```typescript
569
+ type EmbedMetadata = BaseMetadata &
570
+ Pick<NovelAIMetadata, 'characterPrompts'> & {
571
+ extras?: Record<string, string | number>;
572
+ };
573
+ ```
574
+
548
575
  ### `RawMetadata`
549
576
 
550
577
  ラウンドトリップ変換のために元のメタデータ構造を保持します。
@@ -556,42 +583,28 @@ type RawMetadata =
556
583
  | { format: 'webp'; segments: MetadataSegment[] };
557
584
  ```
558
585
 
559
- > [!TIP]
560
- > TypeScriptユーザー向け:全ての型はエクスポートされており、インポートして使用できます。
561
- >
562
- > ```typescript
563
- > import type {
564
- > ParseResult,
565
- > GenerationMetadata,
566
- > ModelSettings,
567
- > SamplingSettings
568
- > } from '@enslo/sd-metadata';
569
- > ```
570
- >
571
- > IDEのIntelliSenseを使用して自動補完とインラインドキュメントを活用してください。
572
-
573
586
  `ModelSettings`、`SamplingSettings`、フォーマット固有の型を含む全てのエクスポート型の詳細なドキュメントについては、[型ドキュメント](./docs/types.ja.md)を参照してください。
574
587
 
575
588
  ## 開発
576
589
 
577
590
  ```bash
578
591
  # 依存関係をインストール
579
- npm install
592
+ pnpm install
580
593
 
581
594
  # テストを実行
582
- npm test
583
-
584
- # ウォッチモード
585
- npm run test:watch
586
-
587
- # テストカバレッジ
588
- npm run test:coverage
595
+ pnpm test
589
596
 
590
597
  # ビルド
591
- npm run build
598
+ pnpm build
592
599
 
593
600
  # リント
594
- npm run lint
601
+ pnpm lint
602
+
603
+ # 型チェック
604
+ pnpm typecheck
605
+
606
+ # デモサイト起動
607
+ pnpm demo
595
608
  ```
596
609
 
597
610
  ## ライセンス