@enslo/sd-metadata 1.1.1 โ†’ 1.3.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.md CHANGED
@@ -4,6 +4,8 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@enslo/sd-metadata.svg)](https://www.npmjs.com/package/@enslo/sd-metadata)
5
5
  [![license](https://img.shields.io/npm/l/@enslo/sd-metadata.svg)](https://github.com/enslo/sd-metadata/blob/main/LICENSE)
6
6
 
7
+ ๐Ÿ‡ฏ๐Ÿ‡ต **[ๆ—ฅๆœฌ่ชž็‰ˆใฏใ“ใกใ‚‰](./README.ja.md)**
8
+
7
9
  A TypeScript library to read and write metadata embedded in AI-generated images.
8
10
 
9
11
  ## Features
@@ -88,7 +90,7 @@ const { read } = require('@enslo/sd-metadata');
88
90
  ### Node.js Usage
89
91
 
90
92
  ```typescript
91
- import { read, write } from 'sd-metadata';
93
+ import { read, write } from '@enslo/sd-metadata';
92
94
  import { readFileSync, writeFileSync } from 'fs';
93
95
 
94
96
  // Read metadata from any supported format
@@ -106,7 +108,7 @@ if (result.status === 'success') {
106
108
  ### Browser Usage
107
109
 
108
110
  ```typescript
109
- import { read } from 'sd-metadata';
111
+ import { read } from '@enslo/sd-metadata';
110
112
 
111
113
  // Handle file input
112
114
  const fileInput = document.querySelector('input[type="file"]');
@@ -151,15 +153,18 @@ if (result.status === 'success') {
151
153
  > For production use, pin to a specific version instead of `@latest`:
152
154
  >
153
155
  > ```text
154
- > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.1.1/dist/index.js
156
+ > https://cdn.jsdelivr.net/npm/@enslo/sd-metadata@1.3.0/dist/index.js
155
157
  > ```
156
158
 
157
- ### Format Conversion
159
+ ### Advanced Examples
160
+
161
+ <details>
162
+ <summary>Format Conversion</summary>
158
163
 
159
164
  Convert metadata between different image formats:
160
165
 
161
166
  ```typescript
162
- import { read, write } from 'sd-metadata';
167
+ import { read, write } from '@enslo/sd-metadata';
163
168
 
164
169
  // Read metadata from PNG
165
170
  const pngData = readFileSync('comfyui-output.png');
@@ -182,10 +187,13 @@ if (parseResult.status === 'success') {
182
187
  > [!TIP]
183
188
  > This library handles metadata read/write only. For actual image format conversion (decoding/encoding pixels), use image processing libraries like [sharp](https://www.npmjs.com/package/sharp), [jimp](https://www.npmjs.com/package/jimp), or browser Canvas API.
184
189
 
185
- ### Handling Different Result Types
190
+ </details>
191
+
192
+ <details>
193
+ <summary>Handling Different Result Types</summary>
186
194
 
187
195
  ```typescript
188
- import { read } from 'sd-metadata';
196
+ import { read } from '@enslo/sd-metadata';
189
197
 
190
198
  const result = read(imageData);
191
199
 
@@ -215,31 +223,37 @@ switch (result.status) {
215
223
  }
216
224
  ```
217
225
 
218
- ### Force Conversion for Unrecognized Formats
226
+ </details>
219
227
 
220
- When you have unrecognized metadata but still want to convert it:
228
+ <details>
229
+ <summary>Preserving Unrecognized Metadata</summary>
230
+
231
+ When converting images with metadata from unsupported tools, you can still preserve the original metadata:
221
232
 
222
233
  ```typescript
223
- import { read, write } from 'sd-metadata';
234
+ import { read, write } from '@enslo/sd-metadata';
224
235
 
225
236
  const source = read(unknownImage);
226
237
  // source.status === 'unrecognized'
227
238
 
228
- // Force blind conversion (preserves all metadata chunks/segments)
239
+ // Preserve all original metadata chunks/segments
229
240
  const result = write(targetImage, source, { force: true });
230
241
 
231
242
  if (result.ok) {
232
- // Metadata successfully converted even though format wasn't recognized
233
- console.log('Forced conversion succeeded');
243
+ // Original metadata preserved in the new image
244
+ console.log('Metadata preserved successfully');
234
245
  }
235
246
  ```
236
247
 
237
- ### Removing Metadata
248
+ </details>
249
+
250
+ <details>
251
+ <summary>Removing Metadata</summary>
238
252
 
239
253
  To strip all metadata from an image:
240
254
 
241
255
  ```typescript
242
- import { write } from 'sd-metadata';
256
+ import { write } from '@enslo/sd-metadata';
243
257
 
244
258
  const result = write(imageData, { status: 'empty' });
245
259
  if (result.ok) {
@@ -247,6 +261,74 @@ if (result.ok) {
247
261
  }
248
262
  ```
249
263
 
264
+ </details>
265
+
266
+ <details>
267
+ <summary>Writing Metadata in WebUI Format</summary>
268
+
269
+ Create and embed custom metadata in SD WebUI (A1111) format:
270
+
271
+ ```typescript
272
+ import { writeAsWebUI } from '@enslo/sd-metadata';
273
+
274
+ // Create custom metadata from scratch
275
+ const metadata = {
276
+ software: 'sd-webui',
277
+ prompt: 'masterpiece, best quality, 1girl',
278
+ negativePrompt: 'lowres, bad quality',
279
+ width: 512,
280
+ height: 768,
281
+ sampling: {
282
+ steps: 20,
283
+ sampler: 'Euler a',
284
+ cfg: 7,
285
+ seed: 12345,
286
+ },
287
+ model: { name: 'model.safetensors' },
288
+ };
289
+
290
+ // Write to any image format (PNG, JPEG, WebP)
291
+ const result = writeAsWebUI(imageData, metadata);
292
+ if (result.ok) {
293
+ writeFileSync('output.png', result.value);
294
+ }
295
+ ```
296
+
297
+ > [!TIP]
298
+ > `writeAsWebUI` is particularly useful when:
299
+ >
300
+ > - Creating images programmatically and want to embed generation parameters
301
+ > - Converting metadata from proprietary formats to WebUI-compatible format
302
+ > - Building tools that need to output WebUI-readable metadata
303
+
304
+ </details>
305
+
306
+ <details>
307
+ <summary>Formatting Metadata for Display</summary>
308
+
309
+ 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:
310
+
311
+ ```typescript
312
+ import { read, formatAsWebUI } from '@enslo/sd-metadata';
313
+
314
+ const result = read(imageData);
315
+ if (result.status === 'success') {
316
+ // Works with any tool: NovelAI, ComfyUI, Forge, InvokeAI, etc.
317
+ const text = formatAsWebUI(result.metadata);
318
+ console.log(text);
319
+
320
+ // Always outputs in consistent WebUI format:
321
+ // masterpiece, best quality, 1girl
322
+ // Negative prompt: lowres, bad quality
323
+ // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
324
+ }
325
+ ```
326
+
327
+ > [!NOTE]
328
+ > 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.
329
+
330
+ </details>
331
+
250
332
  ## API Reference
251
333
 
252
334
  ### `read(data: Uint8Array): ParseResult`
@@ -275,13 +357,101 @@ Writes metadata to an image file.
275
357
  - `status: 'success'` or `'empty'` - Can write directly
276
358
  - `status: 'unrecognized'` - Requires `force: true` option
277
359
  - `options` - Optional settings:
278
- - `force?: boolean` - Required when writing `status: 'unrecognized'` metadata (blind conversion)
360
+ - `force?: boolean` - Enables writing unrecognized metadata (preserves original data as-is)
361
+
362
+ **Returns:**
363
+
364
+ - `{ ok: true, value: Uint8Array }` - Successfully written (returns new image data)
365
+ - `{ ok: false, error: { type, message? } }` - Failed. `type` is one of:
366
+ - `'unsupportedFormat'`: Target image is not PNG, JPEG, or WebP
367
+ - `'conversionFailed'`: Metadata conversion failed (e.g., incompatible format)
368
+ - `'writeFailed'`: Failed to embed metadata into the image
369
+
370
+ ### `writeAsWebUI(data: Uint8Array, metadata: GenerationMetadata): WriteResult`
371
+
372
+ Writes metadata to an image in SD WebUI (A1111) format.
373
+
374
+ **Parameters:**
375
+
376
+ - `data` - Target image file data (PNG, JPEG, or WebP)
377
+ - `metadata` - Generation metadata to embed
378
+ - Can be from any tool or custom-created
379
+ - Automatically converted to WebUI format
279
380
 
280
381
  **Returns:**
281
382
 
282
383
  - `{ ok: true, value: Uint8Array }` - Successfully written (returns new image data)
283
- - `{ ok: false, error: { type: string, message?: string } }` - Failed
284
- - `type`: `'unsupportedFormat'`, `'conversionFailed'`, or `'writeFailed'`
384
+ - `{ ok: false, error: { type, message? } }` - Failed. `type` is one of:
385
+ - `'unsupportedFormat'`: Target image is not PNG, JPEG, or WebP
386
+ - `'writeFailed'`: Failed to embed metadata into the image
387
+
388
+ **Use cases:**
389
+
390
+ - Creating custom metadata for programmatically generated images
391
+ - Converting metadata from other tools to WebUI-compatible format
392
+ - Building applications that output WebUI-readable metadata
393
+
394
+ ### `formatAsWebUI(metadata: GenerationMetadata): string`
395
+
396
+ Formats metadata as human-readable text in SD WebUI (A1111) format.
397
+
398
+ **Parameters:**
399
+
400
+ - `metadata` - Generation metadata from any tool
401
+
402
+ **Returns:**
403
+
404
+ - Human-readable string in WebUI format (plain text)
405
+
406
+ **Output format:**
407
+
408
+ ```text
409
+ positive prompt
410
+ [character prompts for NovelAI]
411
+ Negative prompt: negative prompt
412
+ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, ...
413
+ ```
414
+
415
+ **Use cases:**
416
+
417
+ - Displaying metadata to users in a consistent format
418
+ - Copying generation parameters as text
419
+ - Logging or debugging generation settings
420
+
421
+ ### `formatRaw(raw: RawMetadata): string`
422
+
423
+ Formats raw metadata as plain text.
424
+
425
+ **Parameters:**
426
+
427
+ - `raw` - Raw metadata from `ParseResult` (`result.raw`)
428
+
429
+ **Returns:**
430
+
431
+ - Plain text content from the metadata (multiple entries separated by blank lines)
432
+
433
+ **Use cases:**
434
+
435
+ - Displaying unrecognized metadata to users
436
+ - Quick inspection of raw metadata content
437
+ - Fallback display when parsing fails
438
+
439
+ **Example:**
440
+
441
+ ```typescript
442
+ import { read, formatAsWebUI, formatRaw } from '@enslo/sd-metadata';
443
+
444
+ const result = read(imageData);
445
+
446
+ switch (result.status) {
447
+ case 'success':
448
+ console.log(formatAsWebUI(result.metadata));
449
+ break;
450
+ case 'unrecognized':
451
+ console.log(formatRaw(result.raw));
452
+ break;
453
+ }
454
+ ```
285
455
 
286
456
  ## Type Reference
287
457
 
@@ -401,7 +571,7 @@ type RawMetadata =
401
571
  >
402
572
  > Use your IDE's IntelliSense for auto-completion and inline documentation.
403
573
 
404
- For detailed documentation of all exported types including `BaseMetadata`, `ModelSettings`, `SamplingSettings`, and format-specific types, see the [Type Documentation](./docs/types.md).
574
+ For detailed documentation of all exported types including `ModelSettings`, `SamplingSettings`, and format-specific types, see the [Type Documentation](./docs/types.md).
405
575
 
406
576
  ## Development
407
577
 
package/dist/index.d.ts CHANGED
@@ -305,7 +305,28 @@ type ParseResult = {
305
305
  };
306
306
 
307
307
  /**
308
- * sd-metadata - Read and write AI-generated image metadata
308
+ * Read API for sd-metadata
309
+ *
310
+ * Handles reading and parsing metadata from images.
311
+ * Automatically detects image format and extracts embedded generation metadata.
312
+ */
313
+
314
+ /**
315
+ * Read and parse metadata from an image
316
+ *
317
+ * Automatically detects the image format (PNG, JPEG, WebP) and parses
318
+ * any embedded generation metadata.
319
+ *
320
+ * @param data - Image file data
321
+ * @returns Parse result containing metadata and raw data
322
+ */
323
+ declare function read(data: Uint8Array): ParseResult;
324
+
325
+ /**
326
+ * Write API for sd-metadata
327
+ *
328
+ * Handles writing metadata to images with automatic format conversion.
329
+ * Supports PNG, JPEG, and WebP formats.
309
330
  */
310
331
 
311
332
  /**
@@ -337,16 +358,6 @@ interface WriteOptions {
337
358
  */
338
359
  force?: boolean;
339
360
  }
340
- /**
341
- * Read and parse metadata from an image
342
- *
343
- * Automatically detects the image format (PNG, JPEG, WebP) and parses
344
- * any embedded generation metadata.
345
- *
346
- * @param data - Image file data
347
- * @returns Parse result containing metadata and raw data
348
- */
349
- declare function read(data: Uint8Array): ParseResult;
350
361
  /**
351
362
  * Write metadata to an image
352
363
  *
@@ -360,4 +371,124 @@ declare function read(data: Uint8Array): ParseResult;
360
371
  */
361
372
  declare function write(data: Uint8Array, metadata: ParseResult, options?: WriteOptions): WriteResult;
362
373
 
363
- export { type CharacterPrompt, type GenerationMetadata, type HiresSettings, type ITXtChunk, type MetadataSegment, type MetadataSegmentSource, type ModelSettings, type ParseResult, type PngTextChunk, type RawMetadata, type SamplingSettings, type TExtChunk, type UpscaleSettings, type WriteOptions, type WriteResult, read, write };
374
+ /**
375
+ * WebUI (A1111) format writer for sd-metadata
376
+ *
377
+ * Converts any GenerationMetadata to SD WebUI (A1111) plain text format
378
+ * and writes it to PNG, JPEG, or WebP images.
379
+ */
380
+
381
+ /**
382
+ * Write metadata to an image in SD WebUI format
383
+ *
384
+ * Converts the provided GenerationMetadata to SD WebUI (A1111) plain text
385
+ * format and embeds it into the image. This allows you to:
386
+ * - Create custom metadata from scratch
387
+ * - Modify existing metadata
388
+ * - Convert metadata from any tool to SD WebUI-compatible format
389
+ *
390
+ * The metadata is stored differently based on image format:
391
+ * - PNG: `parameters` tEXt/iTXt chunk (encoding auto-selected based on content)
392
+ * - JPEG/WebP: Exif UserComment field
393
+ *
394
+ * @param data - Target image file data (PNG, JPEG, or WebP)
395
+ * @param metadata - Generation metadata to embed
396
+ * @returns New image data with embedded metadata, or error
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * import { writeAsWebUI } from '@enslo/sd-metadata';
401
+ *
402
+ * // Create custom metadata
403
+ * const metadata = {
404
+ * software: 'sd-webui',
405
+ * prompt: 'masterpiece, 1girl',
406
+ * negativePrompt: 'lowres, bad quality',
407
+ * width: 512,
408
+ * height: 768,
409
+ * sampling: { steps: 20, sampler: 'Euler a', cfg: 7, seed: 12345 },
410
+ * model: { name: 'model.safetensors' },
411
+ * };
412
+ *
413
+ * // Embed into image
414
+ * const result = writeAsWebUI(imageData, metadata);
415
+ * if (result.ok) {
416
+ * writeFileSync('output.png', result.value);
417
+ * }
418
+ * ```
419
+ */
420
+ declare function writeAsWebUI(data: Uint8Array, metadata: GenerationMetadata): WriteResult;
421
+
422
+ /**
423
+ * A1111-format metadata serialization utilities
424
+ *
425
+ * Converts GenerationMetadata to A1111 (SD WebUI) plain text format.
426
+ */
427
+
428
+ /**
429
+ * Format metadata as SD WebUI (A1111) plain text
430
+ *
431
+ * Converts GenerationMetadata to human-readable text in the SD WebUI format.
432
+ * This provides a standard, tool-agnostic way to display generation metadata
433
+ * without needing to manually read individual properties.
434
+ *
435
+ * The output format follows the A1111/SD WebUI convention:
436
+ * ```
437
+ * positive prompt
438
+ * [character prompts for NovelAI]
439
+ * Negative prompt: negative prompt
440
+ * Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, ...
441
+ * ```
442
+ *
443
+ * @param metadata - Generation metadata from any tool
444
+ * @returns Human-readable text in SD WebUI format
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * import { read, formatAsWebUI } from '@enslo/sd-metadata';
449
+ *
450
+ * const result = read(imageData);
451
+ * if (result.status === 'success') {
452
+ * const text = formatAsWebUI(result.metadata);
453
+ * console.log(text);
454
+ * // Output:
455
+ * // masterpiece, 1girl
456
+ * // Negative prompt: low quality, bad anatomy
457
+ * // Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 12345, Size: 512x768, Model: model.safetensors
458
+ * }
459
+ * ```
460
+ */
461
+ declare function formatAsWebUI(metadata: GenerationMetadata): string;
462
+
463
+ /**
464
+ * Raw metadata serialization utilities
465
+ *
466
+ * Formats RawMetadata as human-readable plain text.
467
+ */
468
+
469
+ /**
470
+ * Format raw metadata as plain text
471
+ *
472
+ * Extracts text content from RawMetadata and returns it as a simple string.
473
+ * Multiple entries are separated by double newlines.
474
+ *
475
+ * This is useful for displaying unrecognized metadata to end users
476
+ * without needing to manually iterate over chunks or segments.
477
+ *
478
+ * @param raw - Raw metadata from ParseResult
479
+ * @returns Plain text content from the metadata
480
+ *
481
+ * @example
482
+ * ```typescript
483
+ * import { read, formatRaw } from '@enslo/sd-metadata';
484
+ *
485
+ * const result = read(imageData);
486
+ * if (result.status === 'unrecognized') {
487
+ * console.log(formatRaw(result.raw));
488
+ * // Output: the raw text content without prefixes
489
+ * }
490
+ * ```
491
+ */
492
+ declare function formatRaw(raw: RawMetadata): string;
493
+
494
+ export { type CharacterPrompt, type GenerationMetadata, type HiresSettings, type ITXtChunk, type MetadataSegment, type MetadataSegmentSource, type ModelSettings, type ParseResult, type PngTextChunk, type RawMetadata, type SamplingSettings, type TExtChunk, type UpscaleSettings, type WriteOptions, type WriteResult, formatAsWebUI, formatRaw, read, write, writeAsWebUI };