Hawkynt.FileFormats.Images 1.0.0.17

dotnet add package Hawkynt.FileFormats.Images --version 1.0.0.17
                    
NuGet\Install-Package Hawkynt.FileFormats.Images -Version 1.0.0.17
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hawkynt.FileFormats.Images" Version="1.0.0.17" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hawkynt.FileFormats.Images" Version="1.0.0.17" />
                    
Directory.Packages.props
<PackageReference Include="Hawkynt.FileFormats.Images" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hawkynt.FileFormats.Images --version 1.0.0.17
                    
#r "nuget: Hawkynt.FileFormats.Images, 1.0.0.17"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hawkynt.FileFormats.Images@1.0.0.17
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hawkynt.FileFormats.Images&version=1.0.0.17
                    
Install as a Cake Addin
#tool nuget:?package=Hawkynt.FileFormats.Images&version=1.0.0.17
                    
Install as a Cake Tool

Hawkynt.FileFormats.Images

NuGet NuGet downloads License CI Target Formats Reflection

One drop-in NuGet package for reading and detecting 540+ image formats — 344 of them writable — pure C#, zero runtime reflection, single static API.

Why?

System.Drawing.Common ships with PNG/JPEG/GIF/BMP/TIFF; ImageSharp adds WebP and a handful more. Everything else — every retro computing format, every fax encoding, every GPU texture container, every obscure scientific or professional format — is left to the consumer to glue together format-by-format.

This package is the union of every format implementation in PNGCrushCS — one folder and one FileFormat.<Name> namespace apiece, all compiled into this one assembly — exposed behind a single static registry generated at compile time. Each format is a fully native C# implementation — no native bindings, no platform restrictions (except TIFF via LibTiff.NET and JPEG via LibJpeg.NET, both managed wrappers).

Use it when you need to detect what an arbitrary stream contains and decode it to a RawImage without caring about the codec details.

Install

dotnet add package Hawkynt.FileFormats.Images

All 582 formats live in one assembly in lib/net8.0/, alongside the three support libraries it builds on (FileFormat.Core, Compression.Core, FileFormat.TextMode). Total size ≈ 4.9 MB.

Quick start

using FileFormat.Core;
using Hawkynt.FileFormats.Images;

// Detect → decode → re-encode in 4 lines
var format = FormatRegistry.DetectFromFile(new FileInfo("mystery.bin"));
var raw    = FormatRegistry.Read(new FileInfo("mystery.bin"));
var bytes  = FormatRegistry.Write(raw!, ImageFormat.Png);
File.WriteAllBytes("out.png", bytes!);

Common scenarios

Detect a format

// From a file (magic-byte detection, falls back to extension)
ImageFormat fmt = FormatRegistry.DetectFromFile(new FileInfo("photo.tga"));

// From raw bytes (e.g. the first 64 bytes of an HTTP response)
ImageFormat fmt = FormatRegistry.DetectFromBytes(headerBuffer);

// From a seekable stream — position is restored on return
using var fs = File.OpenRead("photo.bin");
ImageFormat fmt = FormatRegistry.DetectFromStream(fs);
// fs.Position == 0 here

// From a non-seekable stream (network, pipe) — get a buffered wrapper back
var (fmt, replay) = FormatRegistry.DetectFromStreamRewound(networkStream);
RawImage? img = FormatRegistry.Read(replay);  // replay re-emits the consumed prefix

// From a file extension (with or without leading dot)
ImageFormat fmt = FormatRegistry.DetectFromExtension(".webp");

// From a MIME type (case-insensitive, accepts aliases)
ImageFormat fmt = FormatRegistry.DetectFromMimeType("IMAGE/X-PNG");

Read any format to RawImage

RawImage? img = FormatRegistry.Read(new FileInfo("anything.tga"));
if (img != null) {
  Console.WriteLine($"{img.Width}x{img.Height} {img.Format} HasAlpha={img.HasAlpha}");
  byte[] rgba = img.ToRgba32();   // normalize for consumption
}

Read accepts FileInfo, byte[], or Stream. All three auto-detect the format first, then dispatch to the matching decoder.

Encode a RawImage

var raw = new RawImage {
  Width = 256, Height = 256,
  Format = PixelFormat.Rgba32,
  PixelData = pixelBytes,                 // 256 * 256 * 4 = 262144 bytes
};

byte[]? png  = FormatRegistry.Write(raw, ImageFormat.Png);
byte[]? webp = FormatRegistry.Write(raw, ImageFormat.WebP);
byte[]? qoi  = FormatRegistry.Write(raw, ImageFormat.Qoi);

// Write straight into a stream (returns false if the format is read-only)
using var output = File.Create("out.bmp");
bool ok = FormatRegistry.Write(raw, ImageFormat.Bmp, output);

Write returns null for read-only formats. Check entry.SupportsWrite first if you need to validate at runtime.

Look up extensions and MIME types

string ext  = FormatRegistry.PrimaryExtension(ImageFormat.Jpeg);    // ".jpg"
var aliases = FormatRegistry.AllExtensions(ImageFormat.Jpeg);       // [".jpg", ".jpeg", ".jfif", ".jpe", ".thm"]

string mime = FormatRegistry.PrimaryMimeType(ImageFormat.WebP);     // "image/webp"
var mimes   = FormatRegistry.AllMimeTypes(ImageFormat.Png);         // ["image/png", "image/x-png"]

Multi-image formats (animated GIF, multi-page TIFF, ICO sets, APNG, MNG)

var entry = FormatRegistry.GetEntry(ImageFormat.Tiff);

if (entry?.SupportsMultiImage == true) {
  int pages = entry.GetImageCount!(new FileInfo("multi.tif"));
  for (int i = 0; i < pages; i++) {
    RawImage? page = entry.LoadRawImageAtIndex!(new FileInfo("multi.tif"), i);
    // ...
  }

  // Or load them all at once
  var allPages = entry.LoadAllRawImages!(new FileInfo("multi.tif"));
}

Enumerate formats with capability filtering

// All formats that can both read and write
var roundTrippable = FormatRegistry.AllFormats
  .Where(e => e.SupportsRead && e.SupportsWrite)
  .OrderBy(e => e.Name);

// All formats containing multiple sub-images
var multiImage = FormatRegistry.AllFormats
  .Where(e => e.SupportsMultiImage);

// All formats with a registered MIME type (for content-type negotiation)
var mimed = FormatRegistry.AllFormats
  .Where(e => e.MimeTypes.Length > 0);

// Build a UI picker for "Save as..."
foreach (var entry in FormatRegistry.SupportedWriteFormats.OrderBy(e => e.Name))
  Console.WriteLine($"{entry.Name,-25} {entry.PrimaryExtension,-10} {entry.PrimaryMimeType}");

Cross-format conversion

// One-liner: read whatever, write as PNG
File.WriteAllBytes("out.png",
  FormatRegistry.Write(FormatRegistry.Read(new FileInfo("in.tga"))!, ImageFormat.Png)!);

// Convert a directory of mixed formats to QOI
foreach (var src in Directory.EnumerateFiles("photos")) {
  var raw = FormatRegistry.Read(new FileInfo(src));
  if (raw == null) continue;
  var dst = Path.ChangeExtension(src, ".qoi");
  File.WriteAllBytes(dst, FormatRegistry.Write(raw, ImageFormat.Qoi)!);
}

Read metadata without decoding pixels

var entry = FormatRegistry.GetEntry(ImageFormat.Jpeg);
ImageInfo? info = entry?.ReadImageInfo?.Invoke(File.ReadAllBytes("photo.jpg"));
if (info is { } meta)
  Console.WriteLine($"{meta.Width}x{meta.Height} @ {meta.BitsPerPixel}bpp ({meta.ColorMode})");

ReadImageInfo is null for formats that don't have a fast metadata path; fall back to Read and inspect the resulting RawImage.

API reference

FormatRegistry (static class)

The single entry point. All members are static.

Detection
Member Description
ImageFormat DetectFromExtension(string extension) Map a file extension (with or without leading dot) to a format. Returns Unknown if not registered.
ImageFormat DetectFromMimeType(string mimeType) Map a MIME type string (case-insensitive) to a format. Aliases are accepted.
ImageFormat DetectFromBytes(ReadOnlySpan<byte> header) Walk the priority-sorted magic-byte table against header bytes. 64 bytes is enough for every known format.
ImageFormat DetectFromStream(Stream stream, int peekBytes = 64) Peek peekBytes from the stream and detect. For seekable streams the position is restored.
(ImageFormat, Stream) DetectFromStreamRewound(Stream stream, int peekBytes = 64) Detect AND return a stream positioned at the original start. For non-seekable streams a buffered wrapper is returned.
ImageFormat DetectFromFile(FileInfo file) Magic-byte detection first; falls back to extension if magic detection returns Unknown.
Lookup
Member Description
FormatEntry? GetEntry(ImageFormat format) Full entry for a format (null if unknown).
string PrimaryExtension(ImageFormat format) Canonical extension like ".png". Empty string if unknown.
IReadOnlyList<string> AllExtensions(ImageFormat format) Every recognized alias (e.g. .tif/.tiff).
string PrimaryMimeType(ImageFormat format) Preferred IANA MIME type. "application/octet-stream" if not annotated.
IReadOnlyList<string> AllMimeTypes(ImageFormat format) All registered MIME types in declaration order.
Read / write
Member Description
RawImage? Read(FileInfo file) Detect + decode a file. Returns null if format unrecognized or decode fails.
RawImage? Read(byte[] data) Detect + decode a byte buffer.
RawImage? Read(Stream stream) Reads the stream into memory, then detects + decodes.
byte[]? Write(RawImage image, ImageFormat format) Encode. Returns null if the target format is read-only.
bool Write(RawImage image, ImageFormat format, Stream output) Encode straight into a stream. Returns false if read-only.
Enumeration
Member Description
IEnumerable<FormatEntry> AllFormats Every registered format.
IEnumerable<FormatEntry> SupportedReadFormats Formats with a working decoder.
IEnumerable<FormatEntry> SupportedWriteFormats Formats with a working encoder.

FormatEntry (sealed record)

Returned by GetEntry and produced by the source-generated RegisterAll(). All function-pointer fields are typed (no reflection); they trim cleanly under PublishTrimmed/AOT.

public sealed record FormatEntry(
  ImageFormat Format,
  string Name,
  string PrimaryExtension,
  string[] AllExtensions,
  string[] MimeTypes,
  FormatCapability Capabilities,
  MagicSignature[] MagicSignatures,
  Func<byte[], bool?>? MatchesSignature,
  int DetectionPriority,
  Func<FileInfo, RawImage?> LoadRawImage,
  Func<byte[], RawImage?> LoadRawImageFromBytes,
  Func<RawImage, byte[]>? ConvertFromRawImage,
  Func<byte[], ImageInfo?>? ReadImageInfo = null,
  Func<FileInfo, int>? GetImageCount = null,
  Func<FileInfo, int, RawImage?>? LoadRawImageAtIndex = null,
  Func<FileInfo, IReadOnlyList<RawImage>?>? LoadAllRawImages = null
);
Computed property Description
string PrimaryMimeType First MIME type, or "application/octet-stream".
bool SupportsRead True if a reader is registered (always true for entries that exist).
bool SupportsWrite True if ConvertFromRawImage != null.
bool SupportsMultiImage True if GetImageCount != null (animated GIF, multi-page TIFF, ICO sets, APNG, MNG, FLI, DCX, MPO, ICNS).

MagicSignature (readonly record struct)

public readonly record struct MagicSignature(
  byte[] Signature,
  int Offset,
  int MinHeaderLength);

Emitted at compile time from [FormatMagicBytes(...)] attributes. MinHeaderLength is always Offset + Signature.Length and lets the detector skip signatures whose required header range is longer than the bytes it has.

ImageFormat (auto-generated enum)

Compile-time enumeration of every registered format. The first member is Unknown = 0. Entries are stable across builds within the same set of referenced format libraries; adding a new FileFormat.<Name> library extends the enum but does not renumber existing entries.

public enum ImageFormat {
  Unknown = 0,
  Png, Jpeg, Gif, Bmp, Tiff, WebP, Avif, Apng, Mng, Qoi,
  Tga, Pcx, Ico, Cur, Ani, Sgi, Wbmp, Aai, Hrz, Cmu,
  // ... ~530 more
}

RawImage (from FileFormat.Core)

The platform-independent pixel buffer used for all reads/writes.

public sealed class RawImage {
  public required int         Width    { get; init; }
  public required int         Height   { get; init; }
  public required PixelFormat Format   { get; init; }
  public required byte[]      PixelData { get; init; }   // layout determined by Format

  public byte[]? Palette      { get; init; }   // RGB triplets, 3 bytes/entry, for indexed formats
  public int     PaletteCount { get; init; }
  public byte[]? AlphaTable   { get; init; }   // optional per-palette alpha (PNG tRNS-style)

  public bool IsIndexed { get; }                     // computed
  public bool HasAlpha  { get; }                     // computed (alpha-table aware)

  public byte[] ToBgra32();                          // normalize to 32bpp BGRA
  public byte[] ToRgba32();                          // normalize to 32bpp RGBA
  public byte[] ToRgb24();                           // normalize to 24bpp RGB

  public static int BytesPerPixel(PixelFormat format);
  public static int BitsPerPixel (PixelFormat format);
}

PixelFormat (enum)

Value Layout Bits
Bgra32 B, G, R, A 32
Rgba32 R, G, B, A 32
Argb32 A, R, G, B 32
Rgb24 R, G, B 24
Bgr24 B, G, R 24
Gray8 G 8
Gray16 G (big-endian) 16
GrayAlpha16 G, A 16
Indexed8 palette index 8
Indexed4 sub-byte 4
Indexed1 sub-byte 1
Rgba64 R, G, B, A (16bit each) 64
Rgb48 R, G, B (16bit each) 48
Rgb565 RRRRR-GGGGGG-BBBBB 16

FormatCapability ([Flags] enum)

Flag Meaning
None Default.
HasDedicatedOptimizer A Crush.<Format> optimizer exists in the parent repo.
MultiImage Multiple sub-images per file (TIFF pages, ICO entries, animated GIF/APNG, etc.).

Per-format constraints on dimensions, palette sizes, fixed palettes, pixel aspect ratio, and display filters live inside VideoMode rather than on the capability enum. The Save-As flow asks the user to pick one of the format's declared VideoModes, then derives the resize/colour-reduction prompts from the chosen mode.

VideoMode (record)

public sealed record VideoMode(
  string Name,
  (IntegerRange Width, IntegerRange Height)[] Dimensions,  // coupled (W, H) tuples
  IntegerRange[]? AllowedPaletteRanges = null,             // null = full-colour
  FixedPalette[]? AvailablePalettes    = null,             // CGA variants, NES master, …
  PixelAspectRatio? PixelAspectRatio   = null,             // null = square 1:1
  DisplayFilter DisplayFilter          = DisplayFilter.None,
  string? Description                  = null);

A format declares static virtual VideoMode[] VideoModes on IImageFormatMetadata<TSelf>. Each entry is one user-pickable choice. Examples:

// PNG, BMP, QOI: single arbitrary-resolution full-colour mode (this is the default).
static VideoMode[] VideoModes => [new("Default", [(IntegerRange.Any, IntegerRange.Any)])];

// Neochrome (Atari ST): three coupled modes with different colour depths.
static VideoMode[] VideoModes => [
  new("Low resolution",    [(320, 200)], [16]),
  new("Medium resolution", [(640, 200)], [ 4]),
  new("High resolution",   [(640, 400)], [ 2]),
];

// VGA Mode 13h / Mode X: multiple resolutions share one 256-colour palette profile.
static VideoMode[] VideoModes => [
  new("256-colour modes", [(320, 200), (320, 240), (360, 480)], [256]),
  new("16-colour modes",  [(640, 400), (640, 480)],             [16]),
];

// CGA: 4-colour mode exposes four palette variants — handled as AvailablePalettes (not separate modes).
static VideoMode[] VideoModes => [
  new("4-colour",   [(320, 200)], [4], [_LowIntensity0, _HighIntensity0, _LowIntensity1, _HighIntensity1]),
  new("Monochrome", [(640, 200)], [2], [_MonochromePalette]),
];

// NES CHR: master palette pool + NTSC composite display filter.
static VideoMode[] VideoModes => [
  new("Tilesheet (2bpp)",
      dimensions: [(128, new IntegerRange(8, 8192, step: 8))],
      allowedPaletteRanges: [new IntegerRange(2, 4)],
      availablePalettes: [_NesMaster64],
      pixelAspectRatio: (8, 7),
      displayFilter: DisplayFilter.NtscComposite),
];

Convention: multiple (W, H) pairs that share the same palette profile go in one mode's Dimensions array; multiple palette variants for the same dimensions go in AvailablePalettes. Fan out into separate modes only when dimensions OR palette-size profile actually differ.

ImageInfo (readonly record struct)

public readonly record struct ImageInfo(
  int Width,
  int Height,
  int BitsPerPixel,
  string? ColorMode  = null,
  string? Compression = null,
  int FrameCount     = 1
);

Lightweight metadata returned by FormatEntry.ReadImageInfo for formats that expose a fast metadata path. Avoids decoding pixel data when you only need dimensions.

How auto-discovery works

The FileFormat.Registry.Generator Roslyn source generator scans the compilation and every referenced assembly at compile time for types implementing IImageFormatReader<TSelf>, IImageFormatWriter<TSelf>, IImageToRawImage<TSelf>, IImageFromRawImage<TSelf>, and IMultiImageFileFormat<TSelf>. It reads the type's [FormatMagicBytes], [FormatDetectionPriority], and [FormatMimeType] attributes, then emits:

  1. The ImageFormat enum (one entry per discovered format).
  2. A FormatRegistration.RegisterAll() partial method that wires up function pointers to the format's FromBytes/FromSpan/ToBytes/ToRawImage/FromRawImage static methods.

There is no runtime reflection. Adding a new format is purely additive: drop a new folder under Formats/, and the next build extends the enum and registers the format with no code changes elsewhere — not even a build file to edit.

Stream detection internals

DetectFromBytes walks a single priority-sorted table where:

  1. Formats with custom MatchesSignature(ReadOnlySpan<byte>) logic run first (they can return true/false/null; null means "not enough info, try other matchers"). Used for JPEG (0xFF 0xD8 0xFF followed by a marker from a specific set), AVIF (ftyp brand inside an MP4 box), JPEG 2000, etc.
  2. Magic-byte signatures are checked in (DetectionPriority, Format-name) order. Lower numeric priority wins (so [FormatDetectionPriority(0)] runs before the default 100).

MIME types

MIME types come from [FormatMimeType("image/png", "image/x-png", ...)] attributes on each FileFormat.<Name>.<Name>File type. The first entry is the primary; subsequent entries are aliases (case-insensitive on lookup). Annotations are additive — long-tail formats without [FormatMimeType] simply have an empty MimeTypes array and PrimaryMimeType == "application/octet-stream". Contributions adding more annotations are welcome.

Supported formats

547 formats, all readable; 344 also writable. The tables below cover formats most consumers will care about; the complete list is enumerable at runtime via FormatRegistry.AllFormats, and SupportsWrite tells you whether a given format can encode.

Modern / web

Format Read Write Multi-image MIME Reference
PNG image/png W3C PNG
JPEG image/jpeg ITU T.81
GIF image/gif GIF89a spec
BMP image/bmp MS DIB ref
TIFF image/tiff TIFF 6.0
WebP image/webp WebP spec
AVIF image/avif AV1 Image File Format
HEIF/HEIC image/heic ISO/IEC 23008-12
APNG image/apng W3C APNG
MNG video/x-mng MNG spec
QOI image/qoi QOI spec
BPG BPG
FLIF FLIF
JPEG XL image/jxl ISO/IEC 18181
JPEG 2000 image/jp2 ISO/IEC 15444
JPEG XR image/jxr ITU T.832
JPEG-LS ITU T.87
JBIG / JBIG2 ISO/IEC 14492
DjVu image/vnd.djvu DjVu spec

Lossless / scientific / HDR

Format Read Write MIME Reference
Farbfeld image/x-farbfeld Farbfeld
Netpbm (PBM/PGM/PPM/PAM/P7) image/x-portable-anymap Netpbm
PFM (Portable FloatMap) image/x-portable-floatmap PFM
HDR (Radiance .hdr / RGBE) image/vnd.radiance Radiance
OpenEXR image/x-exr OpenEXR
DPX SMPTE 268M
Cineon Cineon
FITS NASA FITS
Analyze 7.5 Mayo Clinic Analyze
NIfTI / Nifti NIfTI
MetaImage (.mhd/.mha) ITK MetaImage
NRRD NRRD
MRC2014 CCP-EM MRC
DICOM application/dicom DICOM
ENVI ENVI hdr
VICAR VICAR
PDS (NASA Planetary) PDS

Professional / authoring

Format Read Write MIME Reference
Photoshop PSD image/vnd.adobe.photoshop Adobe PSD
Photoshop PSB (large PSD variant)
Krita KRA application/x-krita Krita file format
OpenRaster ORA image/openraster OpenRaster
GIMP XCF XCF
MagicaVoxel VOX VOX
WMF / EMF image/wmf / image/emf WMF
EPS application/postscript Adobe EPS
PDF (image extraction) application/pdf PDF 1.7
PE EXE/DLL (resource extraction) PE/COFF
VIPS libvips
SoftImage / Maya IFF (3D renderer outputs)

GPU textures / 3D

Format Read Write Reference
DDS (DirectDraw Surface) DDS file ref
KTX / KTX2 Khronos KTX
PVR (PowerVR) Imagination PVR
ASTC ARM ASTC
PKM (ETC1/ETC2) PKM
VTF (Valve Texture) VDC: VTF
BLP (Blizzard) (WoW/SC2 textures)
FSH (EA Sports) FSH
WAD / WAD2 / WAD3 Quake WAD
MipTex (Quake/HL MDL) (Quake1, HL1 BSP)
Block decoders included BC1–BC7, ETC1/ETC2, ASTC LDR, PVRTC

Animation / multi-image

Format Read Write Multi-image Reference
Animated GIF GIF89a
APNG APNG
MNG MNG
FLI / FLC FLIC
Multi-page TIFF TIFF 6.0
BigTIFF BigTIFF
DCX (multi-page PCX) (Intel WinFax archive)
MPO (multi-pic JPEG) CIPA DC-007
ICNS (Apple icons) Apple icns

Icons / cursors / fonts

Format Read Write MIME Reference
ICO (Windows icon) image/vnd.microsoft.icon ICO file ref
CUR (Windows cursor) image/vnd.microsoft.icon CUR file ref
ANI (animated cursor) ANI
ICNS (Apple) (see above)
Xcursor (X11) Xcursor
SunIcon (X bitmap variant)
MS FONT .FNT format

Document / fax

Pure raster + CCITT G3/G4 codecs. 44 fax variant formats are supported (see FormatRegistry.AllFormats for the full list).

Format Read Write Reference
Fax G3 / Fax G4 ITU T.4 / T.6
WSQ (FBI fingerprint) WSQ
Common fax containers AccessFax, AdTechFax, BfxBitware, BrotherFax, CanonNavFax, EverexFax, FaxMan, FremontFax, GammaFax, HayesJtfax, ImagingFax, KofaxKfx, MobileFax, OazFax, OlicomFax, RicohFax, SciFax, SmartFax, TeliFax, Tg4, VentaFax, WinFax, WorldportFax, BrooktroutFax, EdmicsC4, AttGroup4
Symbian MBM (Symbian OS multi-bitmap)

RAW camera

Format Read Write Reference
Adobe DNG DNG spec
Canon CR2 (lossless JPEG, slice reassembly)
Canon CR3 (partial) (HEIF container)
Nikon NEF (compressed, dual Huffman)
Sony ARW2 (7-bit delta)
Olympus ORF
Panasonic RW2

Other notable

TGA / Targa, PCX, SGI / Iris, Sun Raster, X PixMap (XPM), X BitMap (XBM), Wireless Bitmap (WBMP), AAI (DuneHD), HRZ (slow-scan TV), CMU bitmap, GEM/GTM (Atari), ALDUS PageMaker, Macromedia FreeHand, Pixar PXR, AldusPagemaker, GD2 (libgd), DPX (motion picture), MIFF (ImageMagick), ECW (Enhanced Compression Wavelet), JNG (JPEG Network Graphics), VIFF (Khoros), RLA / RPF (Wavefront), ART (PFS), AliasPix.

Vintage computing (~ 200 formats)

The package supports virtually every screen-dump and paint-program output ever shipped on a home/personal computer. Discoverable via FormatRegistry.AllFormats; selection of platforms below.

  • Apple: Apple II / IIgs SHR / DHR / 16-color, AppleICN, AppleColorSPF, AppleSPF, MacPaint, PICT
  • Atari: Degas / Degas Elite, NeoChrome, AtariPaintworks, CrackArt, Spectrum 512 (& Compressed/Smoosh), QuantumPaint, Sinbad Slideshow, FullscreenKit, PabloPaint, Stad, Calamus, ArtDirector, MegaPaint, GfaRaytrace, plus IFF and ZX0/ZXSP variants — 30+ formats
  • Commodore: C64 (Koala, Doodle, Multicolor, Hires, AdvancedArt, AmicaPaint, GunPaint, FunPainter, DrazPaint, GigaPaint, Artist64, FacePainter, FunGraphicsMachine, GoDot, HiresC64, EggPaint, CDU-Paint, RainbowPainter, KoalaCompressed, Bfli, Vidcom64, Picasso64, MicroIllustrator, AdvancedArtStudio, RunPaint, InterPaint, PrintfoxPagefox, Spectrum512), C128, Plus/4, VIC-20, Amiga IFF / ILBM / ANIM / ACBM / DEEP / RGB8 / RGBN / PBM
  • Sinclair Spectrum: ZxSpectrum (SCR), ZxNext, ZxTimex, ZxUlaPlus, ZxMulticolor, ZxBorderMulticolor, ZxPaintbrush, ZxArtStudio, Spectrum512Smoosh — 25+ formats
  • MSX: MsxScreen2/5/7/8/10/12, MsxSc4, MsxSc8, MsxView — 15+ formats
  • Amstrad CPC: AmstradCpc, AmstradCpcPlus, AmstradOcp, FontasyGrafik
  • Sharp: SharpMz, X1Pal, SharpX68k
  • Acorn / BBC: Acorn (Sprite), BbcMicroBeeb, BbcMicroAdvanced, RiscOsSprite
  • Sega: Genesis/Mega Drive tile, Master System tile, Game Gear, Genesis SJ1
  • Nintendo: GameBoy tile, GameBoyColor, GbaTile, NesChr, SnesTile, NintendoDsT (NDS texture), N64 SAI/TM, NeoGeoSprite, NeoGeoPocket, VirtualBoyTile
  • Other 8/16-bit: TI bitmap, HP Grob, EpaBios (calculator), CiscoIp, PocketPc2bp, Thomson, Commodore PET, FM Towns, PC-88, Enterprise128, Atari 7800, Atari 2600, TRS-80, Dragon, Jupiter Ace, ZX81, Electronika, Vector06c, Vidcom64, Picasso64
  • Japanese formats: Mag, Pi, Q0, MakichanGraph
  • Mobile/embedded: NokiaLogo, NokiaNlm, NokiaGroupGraphics, SiemensBmx, PsionPic
  • HP: HpBufImage, HpForth (HP48), HpGrob

Get the complete list at runtime

foreach (var entry in FormatRegistry.AllFormats.OrderBy(e => e.Name))
  Console.WriteLine(
    $"{entry.Name,-30} {entry.PrimaryExtension,-10} " +
    $"R={(entry.SupportsRead?'Y':'-')} W={(entry.SupportsWrite?'Y':'-')} " +
    $"M={(entry.SupportsMultiImage?'Y':'-')} {entry.PrimaryMimeType}");

Limitations

  • Lossy advanced features — VP8 lossy is keyframe-only; multi-pass rate control and token-partition threading are not implemented yet. Alpha IS preserved (the encoder writes an ALPH chunk on RGBA input; uncompressed method 0 — VP8L-encoded alpha is a future optimization).
  • Codec subsets — HEIF/AVIF/BPG decoders are I-frame only, single tile, YCbCr 4:2:0 8-bit. JPEG XL: container + SizeHeader + ImageMetadata + FrameHeader (ISO/IEC 18181-1 §3.6.2 / §3.6.3 / §3.6.5) are spec-conformant — the all_default fast path that most libjxl-encoded files use is fully supported, and the non-default conditional plumbing (orientation, bit_depth, num_extra_channels, extra_channel_info, color_encoding, tone_mapping, frame_type, encoding flag) is in place. Pixel codec (modular sub-codec body and VarDCT) is the remaining workstream — arbitrary real-world .jxl files will not decode their pixels yet, but signature, dimensions, and image-level metadata are extracted correctly. Camera RAW supports DNG lossless JPEG, Canon CR2, Nikon NEF, Sony ARW2; other manufacturer-specific compressions are future work.
  • Write coverage — 344 of 547 formats implement FromRawImage and can encode an arbitrary image; FormatRegistry.Write returns null for the other 203. Those parse and re-serialize a file they read, but cannot author one from pixel data — this includes the authoring formats (PSD, XCF, PSB, ICNS, Xcursor, ECW, DjVu, JBIG2, FLIF) and most vintage/8-bit formats. Filter on FormatEntry.SupportsWrite rather than assuming.
  • PDF / PE — image extraction only. PDF rendering, page composition, vector graphics, and PE writing are out of scope.
  • Bundle size~4.9 MB, four assemblies. There is no way to take only the formats you need; if that matters, per-format NuGet packages may be published in future.
  • TFM — targets net8.0. Older runtimes are not supported.

License

LGPL-3.0-or-later. See LICENSE.

Contributing

Issues and PRs welcome at https://github.com/Hawkynt/PNGCrushCS. Adding a new format is straightforward — see existing folders under Formats/ as templates. Adding a [FormatMimeType("image/...")] annotation to an existing format is a one-line PR.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Hawkynt.FileFormats.Images:

Package Downloads
Hawkynt.PhotoManager.Core

Core library for photo organization and management with metadata-driven sorting, duplicate handling, and flexible import strategies.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0.17 0 7/29/2026
1.0.0.8 0 7/29/2026