npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@enslo/sd-metadata

v1.0.2

Published

Read and write AI-generated image metadata

Readme

sd-metadata

npm version npm downloads license

A TypeScript library to read and write metadata embedded in AI-generated images.

Features

  • Multi-format Support: PNG (tEXt / iTXt), JPEG (COM / Exif), WebP (Exif)
  • Unified API: Simple read() and write() functions work across all formats
  • TypeScript Native: Written in TypeScript with full type definitions included
  • Zero Dependencies: Works in Node.js and browsers without any external dependencies
  • Format Conversion: Seamlessly convert metadata between PNG, JPEG, and WebP
  • Lossless Round-trip: Preserves original metadata structure when converting back to native format

Installation

npm install @enslo/sd-metadata

Tool Support

| Tool | PNG | JPEG | WebP | | ------ | :---: | :----: | :----: | | NovelAI * | ✅ | 🔄️ | ✅ | | ComfyUI * | ✅ | 🔄️ | 🔄️ | | AUTOMATIC1111 | ⚠️ | ⚠️ | ⚠️ | | Forge / Forge Neo | ✅ | ✅ | ✅ | | InvokeAI | ✅ | 🔄️ | 🔄️ | | SwarmUI * | ✅ | ✅ | ✅ | | Civitai | ⚠️ | ✅ | ⚠️ | | TensorArt | ✅ | 🔄️ | 🔄️ | | Stability Matrix | ✅ | 🔄️ | 🔄️ | | HuggingFace Space | ✅ | 🔄️ | 🔄️ | | Ruined Fooocus | ✅ | 🔄️ | 🔄️ | | Easy Diffusion | ⚠️ | ⚠️ | ⚠️ | | Fooocus | ⚠️ | ⚠️ | ⚠️ |

Legend:

  • Fully Supported - Formats natively supported by the tool, verified with sample files
  • 🔄️ Extended Support - sd-metadata specific parsers, cross-format conversion supported
  • ⚠️ Experimental - Implemented from reference code, not verified with samples

[!NOTE] * Tools with known limitations. See Known Limitations for details.

[!TIP] Help us expand tool support! We're actively collecting sample images from experimental tools (Easy Diffusion, Fooocus) and unsupported tools. If you have sample images generated by these or other AI tools, please consider contributing them! See CONTRIBUTING.md for details.

Usage

Node.js Usage

import { read, write } from 'sd-metadata';
import { readFileSync, writeFileSync } from 'fs';

// Read metadata from any supported format
const imageData = readFileSync('image.png');
const result = read(imageData);

if (result.status === 'success') {
  console.log('Tool:', result.tool);           // 'novelai', 'comfyui', etc.
  console.log('Prompt:', result.prompt);
  console.log('Model:', result.parameters?.model);
  console.log('Size:', result.width, 'x', result.height);
}

Browser Usage

import { read } from 'sd-metadata';

// Handle file input
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const arrayBuffer = await file.arrayBuffer();
  const imageData = new Uint8Array(arrayBuffer);
  
  const result = read(imageData);
  
  if (result.status === 'success') {
    document.getElementById('tool').textContent = result.tool;
    document.getElementById('prompt').textContent = result.prompt;
    document.getElementById('model').textContent = result.parameters?.model || 'N/A';
  }
});

Format Conversion

Convert metadata between different image formats:

import { read, write } from 'sd-metadata';

// Read from PNG
const pngData = readFileSync('comfyui-output.png');
const metadata = read(pngData);

// Write to JPEG
const jpegData = readFileSync('target.jpg');
const result = write(jpegData, metadata);

if (result.type === 'success') {
  writeFileSync('output.jpg', result.data);
  console.log('Metadata converted from PNG to JPEG');
}

Handling Different Result Types

import { read } from 'sd-metadata';

const result = read(imageData);

switch (result.status) {
  case 'success':
    // Metadata successfully parsed
    console.log(`Generated by ${result.tool}`);
    console.log(`Prompt: ${result.prompt}`);
    break;

  case 'unrecognized':
    // Format detected but not recognized as AI-generated
    console.log('Not an AI-generated image');
    // You can still access raw metadata for debugging:
    console.log('Raw chunks:', result.raw);
    break;

  case 'empty':
    // No metadata found
    console.log('No metadata in this image');
    break;

  case 'unsupportedFormat':
    // Not a PNG, JPEG, or WebP file
    console.log('Unsupported image format');
    break;

  case 'invalid':
    // Corrupted or invalid image data
    console.log('Error:', result.message);
    break;
}

Force Conversion for Unrecognized Formats

When you have unrecognized metadata but still want to convert it:

import { read, write } from 'sd-metadata';

const source = read(unknownImage);
// source.status === 'unrecognized'

// Force blind conversion (preserves all metadata chunks/segments)
const result = write(targetImage, source, { force: true });

if (result.type === 'success') {
  // Metadata successfully converted even though format wasn't recognized
  console.log('Forced conversion succeeded');
}

Removing Metadata

To strip all metadata from an image:

import { write } from 'sd-metadata';

const result = write(imageData, { status: 'empty' });
if (result.type === 'success') {
  writeFileSync('clean-image.png', result.data);
}

API Reference

read(data: Uint8Array): ParseResult

Reads and parses metadata from an image file.

Returns:

  • { status: 'success', tool, prompt, parameters, width, height, raw } - Successfully parsed
  • { status: 'unrecognized', raw } - Image has metadata but not from a known AI tool
  • { status: 'empty' } - No metadata found
  • { status: 'unsupportedFormat' } - Not a PNG, JPEG, or WebP file
  • { status: 'invalid', message } - Corrupted or invalid image data

write(data: Uint8Array, metadata: ParseResult, options?: WriteOptions): WriteResult

Writes metadata to an image file.

Parameters:

  • data - Target image file data (PNG, JPEG, or WebP)
  • metadata - ParseResult from read()
    • status: 'success' or 'empty' - Can write directly
    • status: 'unrecognized' - Requires force: true option
  • options - Optional settings:
    • force?: boolean - Required when writing status: 'unrecognized' metadata

Returns:

  • { type: 'success', data } - Successfully written
  • { type: 'unsupportedFormat' } - Target is not PNG, JPEG, or WebP
  • { type: 'conversionFailed', message } - Metadata conversion failed
  • { type: 'writeFailed', message } - Failed to write metadata to image

Known Limitations

[!WARNING] ComfyUI JPEG/WebP: While reading supports major custom node formats (e.g., save-image-extended), writing always uses the comfyui-saveimage-plus format. This format provides the best information preservation and is compatible with ComfyUI's native drag-and-drop workflow loading.

[!WARNING] NovelAI WebP: Auto-corrects corrupted UTF-8 in the Description field, which means WebP → PNG → WebP round-trip is not content-equivalent (but provides valid, readable metadata).

[!WARNING] SwarmUI PNG→JPEG/WebP: PNG files contain both ComfyUI workflow and SwarmUI parameters. When converting to JPEG/WebP, only parameters are preserved to match the native format. Metadata is fully preserved, but the ComfyUI workflow in the prompt chunk is lost.

Development

# Install dependencies
npm install

# Run tests
npm test

# Watch mode
npm run test:watch

# Test coverage
npm run test:coverage

# Build
npm run build

# Lint
npm run lint

License

MIT