@enslo/sd-metadata 2.2.0 → 3.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/docs/types.ja.md CHANGED
@@ -8,13 +8,15 @@
8
8
 
9
9
  - [コア型](#コア型)
10
10
  - [`ParseResult`](#parseresult)
11
- - [`BaseMetadata`](#basemetadata)
12
11
  - [`GenerationMetadata`](#generationmetadata)
13
12
  - [`GenerationSoftware`](#generationsoftware)
13
+ - [`C2paMetadata`](#c2pametadata)
14
+ - [`C2paVendor`](#c2pavendor)
14
15
  - [`EmbedMetadata`](#embedmetadata)
15
16
  - [`RawMetadata`](#rawmetadata)
16
17
  - [`WriteResult`](#writeresult)
17
18
  - [メタデータ型](#メタデータ型)
19
+ - [`BaseMetadata`](#basemetadata)
18
20
  - [`StandardMetadata`](#standardmetadata)
19
21
  - [`NovelAIMetadata`](#novelaimetadata)
20
22
  - [`ComfyUIMetadata`](#comfyuimetadata)
@@ -47,6 +49,7 @@
47
49
  ```typescript
48
50
  type ParseResult =
49
51
  | { status: 'success'; metadata: GenerationMetadata; raw: RawMetadata }
52
+ | { status: 'c2pa'; c2pa: C2paMetadata }
50
53
  | { status: 'unrecognized'; raw: RawMetadata }
51
54
  | { status: 'empty' }
52
55
  | { status: 'invalid'; message?: string };
@@ -57,6 +60,8 @@ type ParseResult =
57
60
  - **`success`**: メタデータのパースに成功
58
61
  - `metadata`: 統一されたメタデータオブジェクト
59
62
  - `raw`: ラウンドトリップ変換用の元のフォーマット固有データ
63
+ - **`c2pa`**: 画像が C2PA Content Credentials を持つが、パース可能な生成メタデータがない
64
+ - `c2pa`: 未検証の Content Credentials を表す `C2paMetadata`。`raw` フィールドは存在しません — 署名済みマニフェストはラウンドトリップ書き込み用に公開されません。
60
65
  - **`unrecognized`**: 画像にメタデータがあるがフォーマットが認識できない
61
66
  - `raw`: 元のメタデータが保持される
62
67
  - **`empty`**: 画像にメタデータが見つからない
@@ -75,7 +80,14 @@ switch (result.status) {
75
80
  console.log(`Generated by ${result.metadata.software}`);
76
81
  console.log(`Prompt: ${result.metadata.prompt}`);
77
82
  break;
78
-
83
+
84
+ case 'c2pa':
85
+ // Content Credentials を検出(例:OpenAI ChatGPT、Google Gemini)。
86
+ // 検出のみ — 署名は検証されません。
87
+ console.log(`生成元(未検証): ${result.c2pa.vendor}`);
88
+ console.log(`Claim generator: ${result.c2pa.claimGenerator ?? 'unknown'}`);
89
+ break;
90
+
79
91
  case 'unrecognized':
80
92
  console.log('不明なメタデータフォーマット');
81
93
  break;
@@ -92,46 +104,6 @@ switch (result.status) {
92
104
 
93
105
  ---
94
106
 
95
- ### `BaseMetadata`
96
-
97
- 全メタデータ型で共有される共通フィールド。`GenerationMetadata` の各バリアントと `EmbedMetadata` の基盤です。
98
-
99
- ```typescript
100
- export interface BaseMetadata {
101
- /** ポジティブプロンプト */
102
- prompt: string;
103
- /** ネガティブプロンプト */
104
- negativePrompt: string;
105
- /** 画像の幅(ピクセル) */
106
- width: number;
107
- /** 画像の高さ(ピクセル) */
108
- height: number;
109
- /** モデル設定 */
110
- model?: ModelSettings;
111
- /** サンプリング設定 */
112
- sampling?: SamplingSettings;
113
- /** Hires.fix設定(適用されている場合) */
114
- hires?: HiresSettings;
115
- /** アップスケール設定(適用されている場合) */
116
- upscale?: UpscaleSettings;
117
- }
118
- ```
119
-
120
- **例:**
121
-
122
- ```typescript
123
- import type { BaseMetadata } from '@enslo/sd-metadata';
124
-
125
- // 共通の生成フィールドのみ必要な場合にBaseMetadataを使用
126
- function displayMetadata(meta: BaseMetadata) {
127
- console.log('Prompt:', meta.prompt);
128
- console.log('Size:', meta.width, 'x', meta.height);
129
- console.log('Model:', meta.model?.name);
130
- }
131
- ```
132
-
133
- ---
134
-
135
107
  ### `GenerationMetadata`
136
108
 
137
109
  統一されたメタデータ構造。サポートされている全てのメタデータ型のユニオン型。全バリアントが `BaseMetadata` を拡張しています。
@@ -212,6 +184,73 @@ function displaySoftware(software: GenerationSoftware): string {
212
184
 
213
185
  ---
214
186
 
187
+ ### `C2paMetadata`
188
+
189
+ 画像に埋め込まれた C2PA Content Credentials から読み取った内容。
190
+
191
+ C2PAマニフェストを持つ画像(現在は **OpenAI ChatGPT** と **Google Gemini**)で、パース可能な生成メタデータがない場合に `read()` が `{ status: 'c2pa', c2pa }` として返します。`GenerationMetadata` とは異なり、**プロンプト・シード・モデル・サイズを一切持ちません**: これらのツールは生成パラメータではなく Content Credentials を埋め込むためです。`C2paMetadata` は `BaseMetadata` を**拡張しません**。
192
+
193
+ ```typescript
194
+ export interface C2paMetadata {
195
+ /** マニフェストの claim generator/署名者から特定した粗いベンダー。 */
196
+ vendor: C2paVendor;
197
+ /**
198
+ * マニフェストが学習アルゴリズム由来(AI生成)の IPTC DigitalSourceType を
199
+ * 宣言している場合に `true`。カメラ/スキャンのソースタイプはフラグされません。
200
+ */
201
+ aiGenerated: boolean;
202
+ /** 生の IPTC DigitalSourceType URI。存在する場合はそのまま提供されます。 */
203
+ digitalSourceType?: string;
204
+ /** C2PA の `claim_generator_info.name`(存在する場合)。 */
205
+ claimGenerator?: string;
206
+ }
207
+ ```
208
+
209
+ > **重要 — 検証ではなく検出のみ。** Content Credentials の存在は真正性の証明にはなりません(文字列は偽造可能)。不在も人間由来の証明にはなりません: Content Credentials はスクリーンショット、SNSへの再アップロード、再エンコードによって日常的に剥奪されます。
210
+ >
211
+ > **現時点ではPNGのみ。** マニフェストはPNGの `caBX` チャンクから読み取られます。JPEG/WebP対応は予定されています。
212
+
213
+ **例:**
214
+
215
+ ```typescript
216
+ import { read, c2paVendorLabels } from '@enslo/sd-metadata';
217
+
218
+ const result = read(imageData);
219
+
220
+ if (result.status === 'c2pa') {
221
+ const { vendor, aiGenerated, claimGenerator } = result.c2pa;
222
+ console.log('Vendor:', c2paVendorLabels[vendor]);
223
+ console.log('Declared AI-generated:', aiGenerated);
224
+ console.log('Claim generator:', claimGenerator ?? 'unknown');
225
+ }
226
+ ```
227
+
228
+ ---
229
+
230
+ ### `C2paVendor`
231
+
232
+ 画像の C2PA Content Credentials の粗いベンダー特定。[`C2paMetadata`](#c2pametadata) の `vendor` 判別子として、また `c2paVendorLabels` のキー型として使用します。
233
+
234
+ ```typescript
235
+ export type C2paVendor = 'openai' | 'google' | 'unknown';
236
+ ```
237
+
238
+ 設計上、これは粗い特定です: C2PAマニフェストは生成元ベンダー(`'openai'` → ChatGPT、`'google'` → Gemini、`'unknown'` → ベンダーが具体的に認識されないAI生成マニフェスト)を特定しますが、具体的なモデルは特定**しません**。
239
+
240
+ **例:**
241
+
242
+ ```typescript
243
+ import { c2paVendorLabels } from '@enslo/sd-metadata';
244
+ import type { C2paVendor } from '@enslo/sd-metadata';
245
+
246
+ function displayVendor(vendor: C2paVendor): string {
247
+ return c2paVendorLabels[vendor];
248
+ // => "OpenAI (ChatGPT)", "Google (Gemini)", "AI-generated (Content Credentials)"
249
+ }
250
+ ```
251
+
252
+ ---
253
+
215
254
  ### `EmbedMetadata`
216
255
 
217
256
  `embed()` と `stringify()` で使用するユーザー作成カスタムメタデータ型。`GenerationMetadata` が既知のAIツールからのパース結果を表すのに対し、`EmbedMetadata` はユーザーが独自にメタデータを組み立てるための型です。`BaseMetadata` にオプションのNovelAIキャラクタープロンプトと設定行への任意キーバリュー(`extras`)を追加。
@@ -343,6 +382,46 @@ export type WriteWarning = {
343
382
 
344
383
  ## メタデータ型
345
384
 
385
+ ### `BaseMetadata`
386
+
387
+ 全メタデータ型で共有される共通フィールド。`GenerationMetadata` の各バリアントと `EmbedMetadata` の基盤です。
388
+
389
+ ```typescript
390
+ export interface BaseMetadata {
391
+ /** ポジティブプロンプト */
392
+ prompt: string;
393
+ /** ネガティブプロンプト */
394
+ negativePrompt: string;
395
+ /** 画像の幅(ピクセル) */
396
+ width: number;
397
+ /** 画像の高さ(ピクセル) */
398
+ height: number;
399
+ /** モデル設定 */
400
+ model?: ModelSettings;
401
+ /** サンプリング設定 */
402
+ sampling?: SamplingSettings;
403
+ /** Hires.fix設定(適用されている場合) */
404
+ hires?: HiresSettings;
405
+ /** アップスケール設定(適用されている場合) */
406
+ upscale?: UpscaleSettings;
407
+ }
408
+ ```
409
+
410
+ **例:**
411
+
412
+ ```typescript
413
+ import type { BaseMetadata } from '@enslo/sd-metadata';
414
+
415
+ // 共通の生成フィールドのみ必要な場合にBaseMetadataを使用
416
+ function displayMetadata(meta: BaseMetadata) {
417
+ console.log('Prompt:', meta.prompt);
418
+ console.log('Size:', meta.width, 'x', meta.height);
419
+ console.log('Model:', meta.model?.name);
420
+ }
421
+ ```
422
+
423
+ ---
424
+
346
425
  ### `StandardMetadata`
347
426
 
348
427
  ほとんどのSDツールで使用される標準パラメータフォーマット。
package/docs/types.md CHANGED
@@ -8,13 +8,15 @@ Complete type reference for `@enslo/sd-metadata`.
8
8
 
9
9
  - [Core Types](#core-types)
10
10
  - [`ParseResult`](#parseresult)
11
- - [`BaseMetadata`](#basemetadata)
12
11
  - [`GenerationMetadata`](#generationmetadata)
13
12
  - [`GenerationSoftware`](#generationsoftware)
13
+ - [`C2paMetadata`](#c2pametadata)
14
+ - [`C2paVendor`](#c2pavendor)
14
15
  - [`EmbedMetadata`](#embedmetadata)
15
16
  - [`RawMetadata`](#rawmetadata)
16
17
  - [`WriteResult`](#writeresult)
17
18
  - [Metadata Types](#metadata-types)
19
+ - [`BaseMetadata`](#basemetadata)
18
20
  - [`StandardMetadata`](#standardmetadata)
19
21
  - [`NovelAIMetadata`](#novelaimetadata)
20
22
  - [`ComfyUIMetadata`](#comfyuimetadata)
@@ -47,6 +49,7 @@ The result type returned by the `read()` function.
47
49
  ```typescript
48
50
  type ParseResult =
49
51
  | { status: 'success'; metadata: GenerationMetadata; raw: RawMetadata }
52
+ | { status: 'c2pa'; c2pa: C2paMetadata }
50
53
  | { status: 'unrecognized'; raw: RawMetadata }
51
54
  | { status: 'empty' }
52
55
  | { status: 'invalid'; message?: string };
@@ -57,6 +60,8 @@ type ParseResult =
57
60
  - **`success`**: Metadata was successfully parsed
58
61
  - `metadata`: Unified metadata object
59
62
  - `raw`: Original format-specific data for round-trip conversion
63
+ - **`c2pa`**: Image carries C2PA Content Credentials (AI provenance) but no parseable generation metadata
64
+ - `c2pa`: `C2paMetadata` describing the declared (unverified) provenance. There is no `raw` field — the signed manifest is not exposed for round-trip writing.
60
65
  - **`unrecognized`**: Image has metadata but format is not recognized
61
66
  - `raw`: Original metadata is preserved
62
67
  - **`empty`**: No metadata found in the image
@@ -75,7 +80,14 @@ switch (result.status) {
75
80
  console.log(`Generated by ${result.metadata.software}`);
76
81
  console.log(`Prompt: ${result.metadata.prompt}`);
77
82
  break;
78
-
83
+
84
+ case 'c2pa':
85
+ // Content Credentials detected (e.g. OpenAI ChatGPT, Google Gemini).
86
+ // Detection only — the signature is NOT verified.
87
+ console.log(`Provenance vendor: ${result.c2pa.vendor} (unverified)`);
88
+ console.log(`Claim generator: ${result.c2pa.claimGenerator ?? 'unknown'}`);
89
+ break;
90
+
79
91
  case 'unrecognized':
80
92
  console.log('Unknown metadata format');
81
93
  break;
@@ -92,46 +104,6 @@ switch (result.status) {
92
104
 
93
105
  ---
94
106
 
95
- ### `BaseMetadata`
96
-
97
- Common fields shared by all metadata types. This is the foundation for both `GenerationMetadata` variants and `EmbedMetadata`.
98
-
99
- ```typescript
100
- export interface BaseMetadata {
101
- /** Positive prompt */
102
- prompt: string;
103
- /** Negative prompt */
104
- negativePrompt: string;
105
- /** Image width in pixels */
106
- width: number;
107
- /** Image height in pixels */
108
- height: number;
109
- /** Model settings */
110
- model?: ModelSettings;
111
- /** Sampling settings */
112
- sampling?: SamplingSettings;
113
- /** Hires.fix settings (if applied) */
114
- hires?: HiresSettings;
115
- /** Upscale settings (if applied) */
116
- upscale?: UpscaleSettings;
117
- }
118
- ```
119
-
120
- **Example:**
121
-
122
- ```typescript
123
- import type { BaseMetadata } from '@enslo/sd-metadata';
124
-
125
- // Use BaseMetadata when you only need common generation fields
126
- function displayMetadata(meta: BaseMetadata) {
127
- console.log('Prompt:', meta.prompt);
128
- console.log('Size:', meta.width, 'x', meta.height);
129
- console.log('Model:', meta.model?.name);
130
- }
131
- ```
132
-
133
- ---
134
-
135
107
  ### `GenerationMetadata`
136
108
 
137
109
  Unified metadata structure. Discriminated union of all supported metadata types. All variants extend `BaseMetadata`.
@@ -212,6 +184,73 @@ function displaySoftware(software: GenerationSoftware): string {
212
184
 
213
185
  ---
214
186
 
187
+ ### `C2paMetadata`
188
+
189
+ Content Credentials (C2PA) read from an image's signed provenance manifest.
190
+
191
+ This is returned by `read()` as `{ status: 'c2pa', c2pa }` for images that carry a C2PA manifest — currently **OpenAI ChatGPT** and **Google Gemini** — but no parseable generation metadata. Unlike `GenerationMetadata`, it carries **no prompt, seed, model, or size**: these tools embed provenance, not generation parameters. `C2paMetadata` does **not** extend `BaseMetadata`.
192
+
193
+ ```typescript
194
+ export interface C2paMetadata {
195
+ /** Coarse vendor attribution from the manifest's claim generator / signer. */
196
+ vendor: C2paVendor;
197
+ /**
198
+ * `true` when the manifest declares a trained-algorithmic (AI-generated)
199
+ * IPTC DigitalSourceType. Camera/scan source types are not flagged.
200
+ */
201
+ aiGenerated: boolean;
202
+ /** Raw IPTC DigitalSourceType URI, surfaced verbatim when present. */
203
+ digitalSourceType?: string;
204
+ /** C2PA `claim_generator_info.name`, when present. */
205
+ claimGenerator?: string;
206
+ }
207
+ ```
208
+
209
+ > **Important — detection only, not verification.** Presence of Content Credentials is not proof of authenticity (the strings are forgeable). Absence is not proof of human origin either: Content Credentials are routinely stripped by screenshots, social-media re-uploads, and re-encoding.
210
+ >
211
+ > **PNG only today.** The manifest is read from the PNG `caBX` chunk; JPEG/WebP support is planned.
212
+
213
+ **Example:**
214
+
215
+ ```typescript
216
+ import { read, c2paVendorLabels } from '@enslo/sd-metadata';
217
+
218
+ const result = read(imageData);
219
+
220
+ if (result.status === 'c2pa') {
221
+ const { vendor, aiGenerated, claimGenerator } = result.c2pa;
222
+ console.log('Vendor:', c2paVendorLabels[vendor]);
223
+ console.log('Declared AI-generated:', aiGenerated);
224
+ console.log('Claim generator:', claimGenerator ?? 'unknown');
225
+ }
226
+ ```
227
+
228
+ ---
229
+
230
+ ### `C2paVendor`
231
+
232
+ Coarse vendor attribution for an image's C2PA Content Credentials. Used as the `vendor` discriminator on [`C2paMetadata`](#c2pametadata) and as the key type for `c2paVendorLabels`.
233
+
234
+ ```typescript
235
+ export type C2paVendor = 'openai' | 'google' | 'unknown';
236
+ ```
237
+
238
+ By design this is coarse: a C2PA manifest identifies the producing vendor (`'openai'` → ChatGPT, `'google'` → Gemini, `'unknown'` → an AI-generated manifest whose vendor is not specifically recognized) but **not** the specific model.
239
+
240
+ **Example:**
241
+
242
+ ```typescript
243
+ import { c2paVendorLabels } from '@enslo/sd-metadata';
244
+ import type { C2paVendor } from '@enslo/sd-metadata';
245
+
246
+ function displayVendor(vendor: C2paVendor): string {
247
+ return c2paVendorLabels[vendor];
248
+ // => "OpenAI (ChatGPT)", "Google (Gemini)", "AI-generated (Content Credentials)"
249
+ }
250
+ ```
251
+
252
+ ---
253
+
215
254
  ### `EmbedMetadata`
216
255
 
217
256
  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 NovelAI character prompts and arbitrary key-value extras for the settings line.
@@ -343,6 +382,46 @@ Returned when metadata was intentionally dropped during a write operation (e.g.,
343
382
 
344
383
  ## Metadata Types
345
384
 
385
+ ### `BaseMetadata`
386
+
387
+ Common fields shared by all metadata types. This is the foundation for both `GenerationMetadata` variants and `EmbedMetadata`.
388
+
389
+ ```typescript
390
+ export interface BaseMetadata {
391
+ /** Positive prompt */
392
+ prompt: string;
393
+ /** Negative prompt */
394
+ negativePrompt: string;
395
+ /** Image width in pixels */
396
+ width: number;
397
+ /** Image height in pixels */
398
+ height: number;
399
+ /** Model settings */
400
+ model?: ModelSettings;
401
+ /** Sampling settings */
402
+ sampling?: SamplingSettings;
403
+ /** Hires.fix settings (if applied) */
404
+ hires?: HiresSettings;
405
+ /** Upscale settings (if applied) */
406
+ upscale?: UpscaleSettings;
407
+ }
408
+ ```
409
+
410
+ **Example:**
411
+
412
+ ```typescript
413
+ import type { BaseMetadata } from '@enslo/sd-metadata';
414
+
415
+ // Use BaseMetadata when you only need common generation fields
416
+ function displayMetadata(meta: BaseMetadata) {
417
+ console.log('Prompt:', meta.prompt);
418
+ console.log('Size:', meta.width, 'x', meta.height);
419
+ console.log('Model:', meta.model?.name);
420
+ }
421
+ ```
422
+
423
+ ---
424
+
346
425
  ### `StandardMetadata`
347
426
 
348
427
  Standard parameters format used by most SD tools.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enslo/sd-metadata",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "description": "Read and write AI-generated image metadata",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,7 +19,7 @@
19
19
  "CHANGELOG.md"
20
20
  ],
21
21
  "scripts": {
22
- "build": "tsup",
22
+ "build": "tsdown",
23
23
  "test": "vitest run",
24
24
  "test:watch": "vitest",
25
25
  "test:coverage": "vitest run --coverage",
@@ -53,11 +53,11 @@
53
53
  },
54
54
  "homepage": "https://sd-metadata.pages.dev",
55
55
  "devDependencies": {
56
- "@biomejs/biome": "^2.4.4",
57
- "@types/node": "^25.3.1",
58
- "@vitest/coverage-v8": "^4.0.18",
59
- "tsup": "^8.5.1",
60
- "typescript": "^5.9.3",
61
- "vitest": "^4.0.18"
56
+ "@biomejs/biome": "catalog:",
57
+ "@types/node": "catalog:",
58
+ "@vitest/coverage-v8": "^4.1.8",
59
+ "tsdown": "catalog:",
60
+ "typescript": "catalog:",
61
+ "vitest": "catalog:"
62
62
  }
63
63
  }