@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/CHANGELOG.md +50 -0
- package/README.ja.md +55 -4
- package/README.md +57 -6
- package/dist/index.d.ts +222 -191
- package/dist/index.d.ts.map +1 -0
- package/dist/index.global.js +8 -8
- package/dist/index.js +4571 -3294
- package/dist/index.js.map +1 -1
- package/docs/types.ja.md +121 -42
- package/docs/types.md +121 -42
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,56 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.0] - 2026-06-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **C2PA Content Credentials detection** (#234): Detect AI provenance metadata
|
|
13
|
+
embedded by commercial tools (ChatGPT / OpenAI, Gemini / Google). When an
|
|
14
|
+
image carries no recognized generation parameters but has a signed C2PA
|
|
15
|
+
manifest, `read()` now returns a `c2pa` status with coarse vendor attribution
|
|
16
|
+
and the declared AI-generated flag.
|
|
17
|
+
- New `C2paMetadata` and `C2paVendor` types
|
|
18
|
+
- The manifest is read as declared; its cryptographic signature is **not**
|
|
19
|
+
verified, so presence is not proof of authenticity and absence is not proof
|
|
20
|
+
of human origin
|
|
21
|
+
|
|
22
|
+
### Potentially Breaking Changes
|
|
23
|
+
|
|
24
|
+
- **New `ParseResult` variant** (#234): `{ status: 'c2pa'; c2pa: C2paMetadata }`
|
|
25
|
+
added. TypeScript users with an exhaustive `switch` on `result.status` (or a
|
|
26
|
+
`Record<...>` keyed by the status union) will need to handle the new `'c2pa'`
|
|
27
|
+
case.
|
|
28
|
+
- **`read()` behavior change** (#234): images that carry a C2PA manifest but no
|
|
29
|
+
recognized generation metadata now return `{ status: 'c2pa' }` instead of
|
|
30
|
+
`{ status: 'unrecognized' }` or `{ status: 'empty' }`.
|
|
31
|
+
|
|
32
|
+
### Security
|
|
33
|
+
|
|
34
|
+
- **`read()` hardening** (#236): Fix two HIGH-severity issues when reading
|
|
35
|
+
malformed input — a ReDoS via unbounded regex backtracking in XMP parsing,
|
|
36
|
+
and an out-of-bounds `RangeError` while reading image dimensions.
|
|
37
|
+
|
|
38
|
+
### Maintenance
|
|
39
|
+
|
|
40
|
+
- Update development dependencies
|
|
41
|
+
|
|
42
|
+
## [2.3.0] - 2026-05-30
|
|
43
|
+
|
|
44
|
+
### Improved
|
|
45
|
+
|
|
46
|
+
- **ComfyUI metadata parsing** (#219): Improved accuracy and coverage for
|
|
47
|
+
non-standard workflow topologies and custom nodes (`ShowText|pysssss`,
|
|
48
|
+
`PromptStashSaver`). Several edge cases that previously caused parse failures
|
|
49
|
+
or incorrect results — including workflows with `NaN`-containing JSON, node
|
|
50
|
+
references in model fields, and workflow-only PNG files — are now handled
|
|
51
|
+
correctly.
|
|
52
|
+
|
|
53
|
+
### Maintenance
|
|
54
|
+
|
|
55
|
+
- Add `index.d.ts.map` (declaration sourcemaps) to the published output (#216)
|
|
56
|
+
- Update development dependencies
|
|
57
|
+
|
|
8
58
|
## [2.2.0] - 2026-02-27
|
|
9
59
|
|
|
10
60
|
### Added
|
package/README.ja.md
CHANGED
|
@@ -14,6 +14,7 @@ AI生成画像に埋め込まれたメタデータを読み書きするための
|
|
|
14
14
|
|
|
15
15
|
- **マルチフォーマット対応**: PNG (tEXt / iTXt)、JPEG (COM / Exif)、WebP (Exif)
|
|
16
16
|
- **シンプルAPI**: `read()`、`write()`、`embed()`、`stringify()` — 4つの関数で全ユースケースをカバー
|
|
17
|
+
- **AI生成元の検出**: C2PA Content Credentials を持つ画像(OpenAI ChatGPT、Google Gemini)を識別 — 検出のみ、署名検証なし
|
|
17
18
|
- **TypeScriptネイティブ**: TypeScriptで書かれており、型定義を完全同梱
|
|
18
19
|
- **ゼロ依存**: Node.jsとブラウザで外部依存なしで動作
|
|
19
20
|
- **フォーマット変換**: PNG、JPEG、WebP間でメタデータをシームレスに変換
|
|
@@ -148,7 +149,7 @@ fileInput.addEventListener('change', async (e) => {
|
|
|
148
149
|
// ==UserScript==
|
|
149
150
|
// @name My Script
|
|
150
151
|
// @namespace https://example.com
|
|
151
|
-
// @require https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@
|
|
152
|
+
// @require https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@3.0.0/dist/index.global.js
|
|
152
153
|
// ==/UserScript==
|
|
153
154
|
|
|
154
155
|
const response = await fetch(imageUrl);
|
|
@@ -211,6 +212,13 @@ switch (result.status) {
|
|
|
211
212
|
console.log(`Prompt: ${result.metadata.prompt}`);
|
|
212
213
|
break;
|
|
213
214
|
|
|
215
|
+
case 'c2pa':
|
|
216
|
+
// C2PA Content Credentials を検出(例:OpenAI ChatGPT、Google Gemini)。
|
|
217
|
+
// 検出のみ — 署名は検証されず、読み取れる生成パラメータ(プロンプト/シード/モデル)もありません。
|
|
218
|
+
console.log(`AI生成元(未検証): ${result.c2pa.vendor}`);
|
|
219
|
+
console.log(`Claim generator: ${result.c2pa.claimGenerator ?? 'unknown'}`);
|
|
220
|
+
break;
|
|
221
|
+
|
|
214
222
|
case 'unrecognized':
|
|
215
223
|
// メタデータは存在するがフォーマットが認識できない
|
|
216
224
|
console.log('不明なメタデータフォーマット');
|
|
@@ -258,6 +266,27 @@ if (result.ok) {
|
|
|
258
266
|
|
|
259
267
|
</details>
|
|
260
268
|
|
|
269
|
+
<details>
|
|
270
|
+
<summary>AI生成元の検出(C2PA Content Credentials)</summary>
|
|
271
|
+
|
|
272
|
+
一部の商用ツール(OpenAI ChatGPT、Google Gemini)は、生成パラメータの代わりに C2PA Content Credentials を埋め込みます。これらの画像に対して `read()` は `{ status: 'c2pa', c2pa }` を返します:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { read, c2paVendorLabels } from '@enslo/sd-metadata';
|
|
276
|
+
|
|
277
|
+
const result = read(imageData);
|
|
278
|
+
|
|
279
|
+
if (result.status === 'c2pa') {
|
|
280
|
+
console.log('Vendor:', c2paVendorLabels[result.c2pa.vendor]);
|
|
281
|
+
console.log('Declared AI-generated:', result.c2pa.aiGenerated);
|
|
282
|
+
console.log('Claim generator:', result.c2pa.claimGenerator ?? 'unknown');
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
> **検出のみ — 証明にはなりません。** C2PA署名を検証しないため、`c2pa` の結果は偽造可能で、真正性の証明にはなりません。また Content Credentials は再アップロードや再エンコードで失われやすいため、`c2pa` にならないことも「AI生成ではない」ことの証明にはなりません。
|
|
287
|
+
|
|
288
|
+
</details>
|
|
289
|
+
|
|
261
290
|
<details>
|
|
262
291
|
<summary>メタデータの削除</summary>
|
|
263
292
|
|
|
@@ -365,13 +394,16 @@ if (text) {
|
|
|
365
394
|
**パラメータ:**
|
|
366
395
|
|
|
367
396
|
- `input` - 画像ファイルデータ(PNG、JPEG、またはWebP)
|
|
368
|
-
- `options` -
|
|
397
|
+
- `options` - オプションの読み込み設定
|
|
398
|
+
- `strict?: boolean`(デフォルト: `false`)— `true` の場合、寸法(`width` / `height`)はメタデータからのみ取得します。`false` の場合、メタデータに寸法がなければ画像ヘッダーから取得します。
|
|
369
399
|
|
|
370
400
|
**戻り値:**
|
|
371
401
|
|
|
372
402
|
- `{ status: 'success', metadata, raw }` - パース成功
|
|
373
403
|
- `metadata`: 統一されたメタデータオブジェクト(`GenerationMetadata`を参照)
|
|
374
404
|
- `raw`: 元のフォーマット固有のデータ(chunks/segments)
|
|
405
|
+
- `{ status: 'c2pa', c2pa }` - 画像がC2PA Content Credentials(例:OpenAI ChatGPT、Google Gemini)を持つが、パース可能な生成メタデータがない
|
|
406
|
+
- `c2pa`: 未検証の Content Credentials(`C2paMetadata`を参照)。検出のみ — 署名は検証されません。
|
|
375
407
|
- `{ status: 'unrecognized', raw }` - 画像にメタデータがあるが既知のAIツールからではない
|
|
376
408
|
- `raw`: 変換用に保持された元のメタデータ
|
|
377
409
|
- `{ status: 'empty' }` - 画像にメタデータが見つからない
|
|
@@ -396,7 +428,7 @@ if (text) {
|
|
|
396
428
|
- `{ ok: false, error: { type, message? } }` - 失敗。`type` は以下のいずれか:
|
|
397
429
|
- `'unsupportedFormat'`: 対象画像がPNG、JPEG、WebP以外の場合
|
|
398
430
|
- `'conversionFailed'`: メタデータ変換に失敗(例:互換性のないフォーマット)
|
|
399
|
-
- `'writeFailed'`:
|
|
431
|
+
- `'writeFailed'`: 画像へのメタデータ埋め込みに失敗、または再書き込みが不可能な場合
|
|
400
432
|
|
|
401
433
|
### `embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult`
|
|
402
434
|
|
|
@@ -430,7 +462,11 @@ SD WebUI (A1111) フォーマットでカスタムメタデータを画像に埋
|
|
|
430
462
|
|
|
431
463
|
**戻り値:**
|
|
432
464
|
|
|
433
|
-
- `ParseResult` の場合:
|
|
465
|
+
- `ParseResult` の場合:
|
|
466
|
+
- `success` → WebUIフォーマット
|
|
467
|
+
- `c2pa` → claim generator 名(`claimGenerator ?? ''`)
|
|
468
|
+
- `unrecognized` → 生テキスト
|
|
469
|
+
- `empty` / `invalid` → 空文字列
|
|
434
470
|
- `EmbedMetadata` / `GenerationMetadata` の場合: WebUIフォーマットのテキスト
|
|
435
471
|
|
|
436
472
|
**ユースケース:**
|
|
@@ -454,6 +490,20 @@ if (result.status === 'success') {
|
|
|
454
490
|
}
|
|
455
491
|
```
|
|
456
492
|
|
|
493
|
+
### `c2paVendorLabels: Record<C2paVendor, string>`
|
|
494
|
+
|
|
495
|
+
`C2paVendor` の識別子から表示用の名前への読み取り専用マッピング。
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
import { c2paVendorLabels } from '@enslo/sd-metadata';
|
|
499
|
+
|
|
500
|
+
const result = read(imageData);
|
|
501
|
+
if (result.status === 'c2pa') {
|
|
502
|
+
console.log(c2paVendorLabels[result.c2pa.vendor]);
|
|
503
|
+
// => "OpenAI (ChatGPT)", "Google (Gemini)", "AI-generated (Content Credentials)"
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
457
507
|
## 型リファレンス
|
|
458
508
|
|
|
459
509
|
このセクションでは主要な型の概要を説明します。完全な型定義については[型ドキュメント](./docs/types.ja.md)を参照してください。
|
|
@@ -465,6 +515,7 @@ if (result.status === 'success') {
|
|
|
465
515
|
```typescript
|
|
466
516
|
type ParseResult =
|
|
467
517
|
| { status: 'success'; metadata: GenerationMetadata; raw: RawMetadata }
|
|
518
|
+
| { status: 'c2pa'; c2pa: C2paMetadata }
|
|
468
519
|
| { status: 'unrecognized'; raw: RawMetadata }
|
|
469
520
|
| { status: 'empty' }
|
|
470
521
|
| { status: 'invalid'; message?: string };
|
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ A TypeScript library to read and write metadata embedded in AI-generated images.
|
|
|
14
14
|
|
|
15
15
|
- **Multi-format Support**: PNG (tEXt / iTXt), JPEG (COM / Exif), WebP (Exif)
|
|
16
16
|
- **Simple API**: `read()`, `write()`, `embed()`, `stringify()` — four functions cover all use cases
|
|
17
|
+
- **AI Provenance Detection**: identifies images carrying C2PA Content Credentials (OpenAI ChatGPT, Google Gemini) — detection only, no signature verification
|
|
17
18
|
- **TypeScript Native**: Written in TypeScript with full type definitions included
|
|
18
19
|
- **Zero Dependencies**: Works in Node.js and browsers without any external dependencies
|
|
19
20
|
- **Format Conversion**: Seamlessly convert metadata between PNG, JPEG, and WebP
|
|
@@ -148,7 +149,7 @@ For userscripts (Tampermonkey, Violentmonkey, etc.), load the IIFE build via `@r
|
|
|
148
149
|
// ==UserScript==
|
|
149
150
|
// @name My Script
|
|
150
151
|
// @namespace https://example.com
|
|
151
|
-
// @require https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@
|
|
152
|
+
// @require https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@3.0.0/dist/index.global.js
|
|
152
153
|
// ==/UserScript==
|
|
153
154
|
|
|
154
155
|
const response = await fetch(imageUrl);
|
|
@@ -211,6 +212,14 @@ switch (result.status) {
|
|
|
211
212
|
console.log(`Prompt: ${result.metadata.prompt}`);
|
|
212
213
|
break;
|
|
213
214
|
|
|
215
|
+
case 'c2pa':
|
|
216
|
+
// C2PA Content Credentials detected (e.g. OpenAI ChatGPT, Google Gemini).
|
|
217
|
+
// Detection only — the signature is NOT verified, and there are no
|
|
218
|
+
// generation parameters (prompt/seed/model) to read.
|
|
219
|
+
console.log(`AI provenance: ${result.c2pa.vendor} (unverified)`);
|
|
220
|
+
console.log(`Claim generator: ${result.c2pa.claimGenerator ?? 'unknown'}`);
|
|
221
|
+
break;
|
|
222
|
+
|
|
214
223
|
case 'unrecognized':
|
|
215
224
|
// Metadata exists but format is not recognized
|
|
216
225
|
console.log('Unknown metadata format');
|
|
@@ -258,6 +267,27 @@ if (result.ok) {
|
|
|
258
267
|
|
|
259
268
|
</details>
|
|
260
269
|
|
|
270
|
+
<details>
|
|
271
|
+
<summary>AI Provenance Detection (C2PA Content Credentials)</summary>
|
|
272
|
+
|
|
273
|
+
Some commercial tools (OpenAI ChatGPT, Google Gemini) embed a signed C2PA "Content Credentials" provenance manifest instead of generation parameters. `read()` returns `{ status: 'c2pa', c2pa }` for these images:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { read, c2paVendorLabels } from '@enslo/sd-metadata';
|
|
277
|
+
|
|
278
|
+
const result = read(imageData);
|
|
279
|
+
|
|
280
|
+
if (result.status === 'c2pa') {
|
|
281
|
+
console.log('Vendor:', c2paVendorLabels[result.c2pa.vendor]);
|
|
282
|
+
console.log('Declared AI-generated:', result.c2pa.aiGenerated);
|
|
283
|
+
console.log('Claim generator:', result.c2pa.claimGenerator ?? 'unknown');
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
> **Detection only — not proof.** The C2PA signature is not verified, so a `c2pa` result is forgeable and cannot prove authenticity. Content Credentials are also easily stripped (screenshots, re-uploads, re-encoding), so the absence of a `c2pa` result does not prove an image is *not* AI-generated.
|
|
288
|
+
|
|
289
|
+
</details>
|
|
290
|
+
|
|
261
291
|
<details>
|
|
262
292
|
<summary>Removing Metadata</summary>
|
|
263
293
|
|
|
@@ -362,13 +392,16 @@ Reads and parses metadata from an image file.
|
|
|
362
392
|
**Parameters:**
|
|
363
393
|
|
|
364
394
|
- `input` - Image file data (PNG, JPEG, or WebP)
|
|
365
|
-
- `options` - Optional read options
|
|
395
|
+
- `options` - Optional read options
|
|
396
|
+
- `strict?: boolean` (default: `false`) — When `true`, dimensions (`width` / `height`) are taken strictly from metadata only. When `false`, missing dimensions are extracted from image headers.
|
|
366
397
|
|
|
367
398
|
**Returns:**
|
|
368
399
|
|
|
369
400
|
- `{ status: 'success', metadata, raw }` - Successfully parsed
|
|
370
401
|
- `metadata`: Unified metadata object (see `GenerationMetadata`)
|
|
371
402
|
- `raw`: Original format-specific data (chunks/segments)
|
|
403
|
+
- `{ status: 'c2pa', c2pa }` - Image carries C2PA Content Credentials (e.g. OpenAI ChatGPT, Google Gemini) but no parseable generation metadata
|
|
404
|
+
- `c2pa`: Declared (unverified) AI provenance (see `C2paMetadata`). Detection only — the signature is not verified.
|
|
372
405
|
- `{ status: 'unrecognized', raw }` - Image has metadata but not from a known AI tool
|
|
373
406
|
- `raw`: Original metadata preserved for conversion
|
|
374
407
|
- `{ status: 'empty' }` - No metadata found in the image
|
|
@@ -393,7 +426,7 @@ Writes metadata to an image file.
|
|
|
393
426
|
- `{ ok: false, error: { type, message? } }` - Failed. `type` is one of:
|
|
394
427
|
- `'unsupportedFormat'`: Target image is not PNG, JPEG, or WebP
|
|
395
428
|
- `'conversionFailed'`: Metadata conversion failed (e.g., incompatible format)
|
|
396
|
-
- `'writeFailed'`: Failed to embed metadata into the image
|
|
429
|
+
- `'writeFailed'`: Failed to embed metadata into the image, or the input cannot be written back
|
|
397
430
|
|
|
398
431
|
### `embed(input: Uint8Array | ArrayBuffer, metadata: EmbedMetadata | GenerationMetadata): WriteResult`
|
|
399
432
|
|
|
@@ -429,9 +462,11 @@ Converts metadata to a human-readable string.
|
|
|
429
462
|
|
|
430
463
|
**Returns:**
|
|
431
464
|
|
|
432
|
-
- `ParseResult
|
|
433
|
-
- `
|
|
434
|
-
- `
|
|
465
|
+
- `ParseResult`:
|
|
466
|
+
- `success` → Human-readable text in WebUI format
|
|
467
|
+
- `c2pa` → The claim generator name (`claimGenerator ?? ''`)
|
|
468
|
+
- `unrecognized` → Raw metadata as plain text
|
|
469
|
+
- `empty` / `invalid` → Empty string
|
|
435
470
|
- `EmbedMetadata` / `GenerationMetadata` → Human-readable text in WebUI format
|
|
436
471
|
|
|
437
472
|
**Use cases:**
|
|
@@ -439,6 +474,7 @@ Converts metadata to a human-readable string.
|
|
|
439
474
|
- Displaying generation parameters in image viewers or galleries
|
|
440
475
|
- Copying metadata to clipboard as readable text
|
|
441
476
|
- Logging or debugging parsed metadata
|
|
477
|
+
- Previewing `EmbedMetadata` before embedding
|
|
442
478
|
|
|
443
479
|
### `softwareLabels: Record<GenerationSoftware, string>`
|
|
444
480
|
|
|
@@ -454,6 +490,20 @@ if (result.status === 'success') {
|
|
|
454
490
|
}
|
|
455
491
|
```
|
|
456
492
|
|
|
493
|
+
### `c2paVendorLabels: Record<C2paVendor, string>`
|
|
494
|
+
|
|
495
|
+
A read-only mapping from `C2paVendor` identifiers to their human-readable display names.
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
import { c2paVendorLabels } from '@enslo/sd-metadata';
|
|
499
|
+
|
|
500
|
+
const result = read(imageData);
|
|
501
|
+
if (result.status === 'c2pa') {
|
|
502
|
+
console.log(c2paVendorLabels[result.c2pa.vendor]);
|
|
503
|
+
// => "OpenAI (ChatGPT)", "Google (Gemini)", "AI-generated (Content Credentials)"
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
457
507
|
## Type Reference
|
|
458
508
|
|
|
459
509
|
This section provides an overview of the main types. For complete type definitions, see [Type Documentation](./docs/types.md).
|
|
@@ -465,6 +515,7 @@ The result of the `read()` function. It uses a discriminated union with a `statu
|
|
|
465
515
|
```typescript
|
|
466
516
|
type ParseResult =
|
|
467
517
|
| { status: 'success'; metadata: GenerationMetadata; raw: RawMetadata }
|
|
518
|
+
| { status: 'c2pa'; c2pa: C2paMetadata }
|
|
468
519
|
| { status: 'unrecognized'; raw: RawMetadata }
|
|
469
520
|
| { status: 'empty' }
|
|
470
521
|
| { status: 'invalid'; message?: string };
|