Package: naipng
naipng ✒️🖼️naipngis a Python library and command-line tool to readNovelAIdata encoded in PNG files (like in Lorebook cards and generated images), with no dependencies.Also check out my websitepngmetafor a browser-based tool forviewingandcopyingPNGtEXtmetadata.Table of ContentsWhat Is This?InstallationUsageLibraryExampleError HandlingCLIHelp TextExamplesTechnical BackgroundLicenseWhat Is This?User-made content for the web serviceNovelAIis 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 asprompt,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 theTechnical Backgroundsection.Installationnaipngis available on PyPI, so it can be installed throughpip:python-mpipinstallnaipngSincenaipnghas no dependencies, you can also import or run it by simply adding thenaipngdirectory
to your source tree.Usagenaipngmay be used either as alibraryor acommand-line tool.LibraryThe primary function entrypoint provided bynaipngisnaipng.read(file: bytes | BinaryIO).
This can be used to parse a PNG image for NovelAI metadata from either an open file or abytesobject in memory.Two more specific variations ofnaipng.read()also exist:naipng.read_text_gen(file: bytes | BinaryIO)only returns text generation dataE.g. Lorebooksnaipng.read_image_gen(file: bytes | BinaryIO)only returns image generation dataE.g. image promptsnaipng.read()Exampleimportnaipng# Using a file-like objectwithopen("image.png","rb")asfile:decoded=naipng.read(file)ifdecodedisNone:# No NovelAI data found encoded in the imageprint("N/A")else:# naipng.read() returns a dict object representing the first data foundfork,vindecoded.items():print(k,"->",v)Another example, usingbytesas input tonaipng.read:importnaipngimportpathlibdata:bytes=pathlib.Path("image.png").read_bytes()decoded=naipng.read(data)# ...Error Handlingnaipngdefines two error types fornaipng.read()and its variants:naipng.InvalidPNGErroris raised when a PNG is invalid and cannot be parsed, such as when:The PNG datastream ends prematurely (beforeIEND)AtEXtchunk is corrupted(i.e. has an invalid CRC)The PNG signature is missingThe PNGIHDRchunk is missing or misplacednaipng.NAIDataErroris raised when a PNG has atEXtchunk designated asnaidata,
but it was unable to be decoded properlyThis is never raised fornaipng.read_image_gen()Both error classes derive fromValueError.This example shows the behaviour ofnaipng.readwith an invalid PNG datastream
(correct signature, but ends early).importnaipng# Using a bytes object as input (a file-like object could be used too)withopen("image.png","rb")asfile:# The datastream is truncated, rendering it invaliddata=file.read(10)try:naipng.read(data)exceptnaipng.InvalidPNGErrorase:raiseSystemExit(f"Error:{e}")fromeThis outputs:Error: not a valid PNG file: ends prematurelyCLInaipngmay be invoked on the command line as eitherpython -m naipng <file>or simplynaipng <file>.Help Textusage: 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 dataExamplesPrinting to stdout:naipngimage.pngSaving to a file:naipngimage.pngnaidata.jsonSaving to a file by redirectingstdinandstdout:naipng-<image.png>naidata.jsonDownloading viacurland piping PNG data throughstdin:curl-fshttps://files.catbox.moe/3b6dux.png|naipng-naipngmay be used in shell pipelines alongside JSON-parsing tools likejqin order to construct more complex scripts.$curl-fshttps://files.catbox.moe/3b6dux.png|naipng-c-|jq-r".[\"entries\"][][\"text\"]"Everyonesaidthatnomannowlivingoreverafterwouldbebornwhowouldbeequaltohiminstrength,courage,andinallsortsofcourtesy,aswellasinboldnessandgenerositythathehadaboveallmen,andthathisnamewouldneverperishintheGermantongue,andthesamewastruewiththeNorsemenTriviaThe 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 BackgroundPNGs 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.
Seethe official PNG specificationfor full details.NovelAI usestEXtmetadata chunksto encode most metadata.For text generation settings, NovelAI uses atEXtchunk with anaidatakeyword.The contents are base64-encoded JSON.naidatais a nonstandardtEXtkeyword, so recognizing these chunks is unambiguous.For image generation settings, NovelAI uses multipletEXtchunks, each with different keywords.Some of these includeTitle,Description,Software,Source, andComment.naipngonly reads theCommentfield among these, which is JSON-encoded and contains the most information.Commentis a standardtEXtkeyword, so recognizing these chunks is slightly ambiguous.Other software may use theCommenttEXtchunk type for other purposes, and may or may not store JSON in it.naipngassumes that the first JSON-encodedCommenttEXtchunk found is valid image generation metadata.Licensenaipngis free and open-source software provided under thezlib license.