Skip to content
/ naipng Public

Python library and command-line tool to read NovelAI data encoded in PNG files.

License

Notifications You must be signed in to change notification settings

Eta0/naipng

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

naipng ✒️🖼️

naipng is a Python library and command-line tool to read NovelAI data encoded in PNG files (like in Lorebook cards and generated images), with no dependencies.

Also check out my website pngmeta for a browser-based tool for viewing and copying PNG tEXt metadata.

Table of Contents

What Is This?

User-made content for the web service NovelAI is often shared off-platform in the form of files. These files take on multiple formats. Though most are simple JSON, some content can be shared embedded within PNGs, which is more complicated to extract.

Text Generation: NovelAI allows exporting certain settings and objects related to text generation AI as PNG images in place of regular JSON files, as a way of associating art with the descriptions of characters and places being shared. These are commonly known as Lorebook cards.

Image Generation: NovelAI encodes image generation settings within generated PNGs, including parameters such as prompt, steps, and so on, to make it easier to replicate and modify generated images.

Both domains use PNG metadata to encode this information, thus this tool allows the extraction of that metadata.

See more technical details in the Technical Background section.

Installation

naipng is available on PyPI, so it can be installed through pip:

python -m pip install naipng

Since naipng has no dependencies, you can also import or run it by simply adding the naipng directory to your source tree.

Usage

naipng may be used either as a library or a command-line tool.

Library

The primary function entrypoint provided by naipng is naipng.read(file: bytes | BinaryIO). This can be used to parse a PNG image for NovelAI metadata from either an open file or a bytes object in memory.

Two more specific variations of naipng.read() also exist:

  • naipng.read_text_gen(file: bytes | BinaryIO) only returns text generation data
    • E.g. Lorebooks
  • naipng.read_image_gen(file: bytes | BinaryIO) only returns image generation data
    • E.g. image prompts

naipng.read() Example

import naipng

# Using a file-like object
with open("image.png", "rb") as file:
    decoded = naipng.read(file)

if decoded is None:
    # No NovelAI data found encoded in the image
    print("N/A")
else:
    # naipng.read() returns a dict object representing the first data found
    for k, v in decoded.items():
        print(k, "->", v)

Another example, using bytes as input to naipng.read:

import naipng
import pathlib

data: bytes = pathlib.Path("image.png").read_bytes()
decoded = naipng.read(data)

# ...

Error Handling

naipng defines two error types for naipng.read() and its variants:

  • naipng.InvalidPNGError is raised when a PNG is invalid and cannot be parsed, such as when:
    • The PNG datastream ends prematurely (before IEND)
    • A tEXt chunk is corrupted (i.e. has an invalid CRC)
    • The PNG signature is missing
    • The PNG IHDR chunk is missing or misplaced
  • naipng.NAIDataError is raised when a PNG has a tEXt chunk designated as naidata, but it was unable to be decoded properly
    • This is never raised for naipng.read_image_gen()

Both error classes derive from ValueError.

This example shows the behaviour of naipng.read with an invalid PNG datastream (correct signature, but ends early).

import naipng

# Using a bytes object as input (a file-like object could be used too)
with open("image.png", "rb") as file:
    # The datastream is truncated, rendering it invalid
    data = file.read(10)

try:
    naipng.read(data)
except naipng.InvalidPNGError as e:
    raise SystemExit(f"Error: {e}") from e

This outputs:

Error: not a valid PNG file: ends prematurely

CLI

naipng may be invoked on the command line as either python -m naipng <file> or simply naipng <file>.

Help Text

usage: naipng [-h] [-q] [-c] [-t] [-i] file [outfile]

read NovelAI data encoded in a PNG file

positional arguments:
  file           PNG file to read, or - for stdin
  outfile        output file path, or - for stdout (default: -)

options:
  -h, --help     show this help message and exit
  -q, --quiet    don't print errors
  -c, --compact  don't pretty-print decoded JSON
  -t, --text     only check for text generation data
  -i, --image    only check for image generation data

Examples

  • Printing to stdout:
naipng image.png
  • Saving to a file:
naipng image.png naidata.json
  • Saving to a file by redirecting stdin and stdout:
naipng - < image.png > naidata.json
  • Downloading via curl and piping PNG data through stdin:
curl -fs https://files.catbox.moe/3b6dux.png | naipng -

naipng may be used in shell pipelines alongside JSON-parsing tools like jq in order to construct more complex scripts.

$ curl -fs https://files.catbox.moe/3b6dux.png | naipng -c - | jq -r ".[\"entries\"][][\"text\"]"

Everyone said that no man now living or ever after would be born who would be equal to him in strength, courage, and in all sorts of courtesy, as well as in boldness and generosity that he had above all men, and that his name would never perish in the German tongue, and the same was true with the Norsemen

Trivia

The linked file is the first Lorebook card shared as an example when PNG embedding was announced. Its art is by Tarmillustrates. The quote in it is from Þiðreks saga.

Technical Background

PNGs are made up of a sequence of data chunks. Beyond those used to store visual information (e.g. pixels, palettes), there are also several varieties of metadata chunks. See the official PNG specification for full details.

NovelAI uses tEXt metadata chunks to encode most metadata.

  • For text generation settings, NovelAI uses a tEXt chunk with a naidata keyword.
    • The contents are base64-encoded JSON.
    • naidata is a nonstandard tEXt keyword, so recognizing these chunks is unambiguous.
  • For image generation settings, NovelAI uses multiple tEXt chunks, each with different keywords.
    • Some of these include Title, Description, Software, Source, and Comment.
    • naipng only reads the Comment field among these, which is JSON-encoded and contains the most information.
    • Comment is a standard tEXt keyword, so recognizing these chunks is slightly ambiguous.
      • Other software may use the Comment tEXt chunk type for other purposes, and may or may not store JSON in it.
      • naipng assumes that the first JSON-encoded Comment tEXt chunk found is valid image generation metadata.

License

naipng is free and open-source software provided under the zlib license.

About

Python library and command-line tool to read NovelAI data encoded in PNG files.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages