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
<PackageReference Include="Hawkynt.FileFormats.Images" Version="1.0.0.17" />
<PackageVersion Include="Hawkynt.FileFormats.Images" Version="1.0.0.17" />
<PackageReference Include="Hawkynt.FileFormats.Images" />
paket add Hawkynt.FileFormats.Images --version 1.0.0.17
#r "nuget: Hawkynt.FileFormats.Images, 1.0.0.17"
#:package Hawkynt.FileFormats.Images@1.0.0.17
#addin nuget:?package=Hawkynt.FileFormats.Images&version=1.0.0.17
#tool nuget:?package=Hawkynt.FileFormats.Images&version=1.0.0.17
Hawkynt.FileFormats.Images
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:
- The
ImageFormatenum (one entry per discovered format). - A
FormatRegistration.RegisterAll()partial method that wires up function pointers to the format'sFromBytes/FromSpan/ToBytes/ToRawImage/FromRawImagestatic 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:
- Formats with custom
MatchesSignature(ReadOnlySpan<byte>)logic run first (they can returntrue/false/null;nullmeans "not enough info, try other matchers"). Used for JPEG (0xFF 0xD8 0xFFfollowed by a marker from a specific set), AVIF (ftypbrand inside an MP4 box), JPEG 2000, etc. - Magic-byte signatures are checked in
(DetectionPriority, Format-name)order. Lower numeric priority wins (so[FormatDetectionPriority(0)]runs before the default100).
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
.jxlfiles 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
FromRawImageand can encode an arbitrary image;FormatRegistry.Writereturnsnullfor 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 onFormatEntry.SupportsWriterather 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 | Versions 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. |
-
net8.0
- BitMiracle.LibJpeg.NET (>= 1.5.324)
- BitMiracle.LibTiff.NET (>= 2.4.649)
- FrameworkExtensions.Backports (>= 1.0.0.256)
- System.IO.Hashing (>= 10.0.3)
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.