Table of Contents

Class EgamiInput

Namespace
Egami.Formats
Assembly
Egami.dll

The data a reader decodes: the caller's stream behind a pooled 64 KB buffer, with exact-read helpers. It also carries the context, limits and cancellation token for the load, and is the only way a reader allocates pixel memory.

public sealed class EgamiInput : IDisposable
Inheritance
EgamiInput
Implements
Inherited Members

Examples

/// <summary>A minimal format: "RAW8", width and height as big-endian numbers, then RGBA rows.</summary>
public static class Raw8Format
{
    public static FormatInfo Info { get; } = new()
    {
        Name = "RAW8",
        Extensions = ["raw8"],
        SignatureLength = 4,
        Matches = header => header.StartsWith("RAW8"u8),
        Reader = new Reader(),
        Writer = new Writer(),
    };

    private sealed class Reader : IFormatReader
    {
        public RasterInfo ReadInfo(EgamiInput input, ReaderOptions options)
        {
            (int width, int height) = Header(input);
            return new RasterInfo { Format = Info, Width = width, Height = height, Layout = Rgba8.Layout, FrameCount = 1, EstimatedBytes = 4L * width * height };
        }

        public Raster<TPixel> Read<TPixel>(EgamiInput input, ReaderOptions options)
            where TPixel : unmanaged, IPixelType<TPixel>
        {
            (int width, int height) = Header(input);

            // CreateRaster checks the size against the safety limits before allocating.
            Raster<TPixel> raster = input.CreateRaster<TPixel>(width, height);
            using IMemoryOwner<byte> row = input.RentScratch(width * 4);
            for (int y = 0; y < height; y++)
            {
                input.ReadExactly(row.Memory.Span[..(width * 4)]);
                PixelConvert.Convert<Rgba8, TPixel>(MemoryMarshal.Cast<byte, Rgba8>(row.Memory.Span[..(width * 4)]), raster.Row(y));
            }

            return raster;
        }

        public Raster Read(EgamiInput input, ReaderOptions options) => Read<Rgba8>(input, options);

        private static (int Width, int Height) Header(EgamiInput input)
        {
            input.Skip(4);
            return ((int)input.ReadUInt32BigEndian(), (int)input.ReadUInt32BigEndian());
        }
    }

    private sealed class Writer : IFormatWriter
    {
        public void Write<TPixel>(Raster<TPixel> raster, Stream output, WriterOptions options)
            where TPixel : unmanaged, IPixelType<TPixel>
        {
            Span<byte> header = stackalloc byte[12];
            "RAW8"u8.CopyTo(header);
            BinaryPrimitives.WriteUInt32BigEndian(header[4..], (uint)raster.Width);
            BinaryPrimitives.WriteUInt32BigEndian(header[8..], (uint)raster.Height);
            output.Write(header);
            Rgba8[] row = new Rgba8[raster.Width];
            for (int y = 0; y < raster.Height; y++)
            {
                PixelConvert.Convert<TPixel, Rgba8>(raster.Row(y), row);
                output.Write(MemoryMarshal.AsBytes(row.AsSpan()));
            }
        }
    }
}

Remarks

Readers never call the stream directly. Egami never disposes the caller's stream.

Constructors

EgamiInput(Stream, EgamiContext, CancellationToken)

Creates the input of a load a plug-in runs itself, outside Load(Stream, EgamiContext?, ReaderOptions?): a format package that reads a file to convert it, say. Dispose it when the load ends.

public EgamiInput(Stream stream, EgamiContext context, CancellationToken cancellationToken)

Parameters

stream Stream

The data, from its current position. It is left open.

context EgamiContext

The context of the load: its limits, memory and diagnostics.

cancellationToken CancellationToken

Cancels the load.

Exceptions

ArgumentNullException

stream or context is null.

Properties

CancellationToken

Gets the token that cancels the load. Readers check it between rows.

public CancellationToken CancellationToken { get; }

Property Value

CancellationToken

Context

Gets the context of the load.

public EgamiContext Context { get; }

Property Value

EgamiContext

Diagnostics

Gets the load's link to Diagnostics, for a reader's Info and Debug events. Warnings go through Warn(Raster, string, string, long?), so they are also listed in Warnings.

public DiagnosticReporter Diagnostics { get; }

Property Value

DiagnosticReporter

FormatName

Gets the name of the format being read, used in CorruptDataException messages.

public string FormatName { get; }

Property Value

string

Limits

Gets the safety limits of the load.

public SafetyLimits Limits { get; }

Property Value

SafetyLimits

Position

Gets the number of bytes consumed since the start of the image.

public long Position { get; }

Property Value

long

Methods

AddFrame<TPixel>(Raster<TPixel>, ClearMode)

Appends a new frame the raster's size to a raster this load created with CreateRaster<TPixel>(long, long, ClearMode), for readers of animated formats. The frame counts against MaxFrames and the load's memory budget. Unless clear asks for it, its pixels are not cleared.

public Frame<TPixel> AddFrame<TPixel>(Raster<TPixel> raster, ClearMode clear = ClearMode.None) where TPixel : unmanaged, IPixelType<TPixel>

Parameters

raster Raster<TPixel>

The raster being read.

clear ClearMode

Whether to zero the pixels first.

Returns

Frame<TPixel>

The new frame, last in Frames.

Type Parameters

TPixel

The pixel type.

Exceptions

LimitExceededException

The frame count or the memory budget would be exceeded.

CheckFrameCount(long)

Checks a frame count against MaxFrames.

public void CheckFrameCount(long frames)

Parameters

frames long

The frames the file says it has, or will have.

Exceptions

LimitExceededException

There are too many.

CheckFrameSize(long, long)

Checks a frame size against MaxWidth, MaxHeight and MaxPixels, as CreateRaster<TPixel>(long, long, ClearMode) does, for a reader that allocates its own row buffers before it creates a raster, such as an IRowFormatReader.

public void CheckFrameSize(long width, long height)

Parameters

width long

The width the file says the image has.

height long

The height the file says the image has.

Exceptions

LimitExceededException

The size breaks a limit.

CheckMemory(long)

Checks that bytes more would fit the load's memory budget, without allocating.

public void CheckMemory(long bytes)

Parameters

bytes long

The bytes about to be needed.

Exceptions

LimitExceededException

They would not fit.

CheckMetadataBytes(long)

Checks a metadata size against MaxMetadataBytes.

public void CheckMetadataBytes(long bytes)

Parameters

bytes long

The metadata bytes kept so far, or about to be read.

Exceptions

LimitExceededException

They are too many.

Corrupt(long, string)

Creates a CorruptDataException for this format.

public CorruptDataException Corrupt(long offset, string problem)

Parameters

offset long

The byte offset of the problem, or -1 if unknown.

problem string

What is wrong, as a sentence.

Returns

CorruptDataException

The exception, for the reader to throw.

CreateRaster<TPixel>(long, long, ClearMode)

Creates the raster a reader decodes into, after checking the size against SafetyLimits and the memory budget. Unless clear asks for it, pixels are not cleared and the reader must write every one.

public Raster<TPixel> CreateRaster<TPixel>(long width, long height, ClearMode clear = ClearMode.None) where TPixel : unmanaged, IPixelType<TPixel>

Parameters

width long

The width from the header.

height long

The height from the header.

clear ClearMode

Whether to zero the pixels first. Readers that write every pixel skip it.

Returns

Raster<TPixel>

A one-frame raster. The reader owns it until it returns it, and must dispose it if decoding fails.

Type Parameters

TPixel

The pixel type.

Exceptions

LimitExceededException

The size breaks a safety limit.

CorruptDataException

The width or height is zero or negative.

Dispose()

Returns the buffer to the pool. Leaves the stream open.

public void Dispose()

Peek(int)

Returns up to count upcoming bytes without consuming them. The span is shorter only at the end of the data. It is valid until the next read.

public ReadOnlySpan<byte> Peek(int count)

Parameters

count int

How many bytes to look at, at most 64 KB.

Returns

ReadOnlySpan<byte>

The upcoming bytes.

Exceptions

ArgumentOutOfRangeException

count is negative or above 64 KB.

Read(Span<byte>)

Reads as many bytes as are available, up to the length of destination.

public int Read(Span<byte> destination)

Parameters

destination Span<byte>

Where to put the bytes.

Returns

int

The number of bytes read. Less than requested only at the end of the data.

ReadByte()

Reads one byte.

public byte ReadByte()

Returns

byte

The byte.

Exceptions

CorruptDataException

The data has ended.

ReadExactly(Span<byte>)

Reads exactly destination.Length bytes.

public void ReadExactly(Span<byte> destination)

Parameters

destination Span<byte>

Where to put the bytes.

Exceptions

CorruptDataException

The data ends first.

ReadUInt16BigEndian()

Reads a big-endian 16-bit unsigned integer.

public ushort ReadUInt16BigEndian()

Returns

ushort

The value.

Exceptions

CorruptDataException

The data ends first.

ReadUInt16LittleEndian()

Reads a little-endian 16-bit unsigned integer.

public ushort ReadUInt16LittleEndian()

Returns

ushort

The value.

Exceptions

CorruptDataException

The data ends first.

ReadUInt32BigEndian()

Reads a big-endian 32-bit unsigned integer.

public uint ReadUInt32BigEndian()

Returns

uint

The value.

Exceptions

CorruptDataException

The data ends first.

ReadUInt32LittleEndian()

Reads a little-endian 32-bit unsigned integer.

public uint ReadUInt32LittleEndian()

Returns

uint

The value.

Exceptions

CorruptDataException

The data ends first.

RentScratch(int, ClearMode)

Rents scratch memory (a canvas row, a previous frame, a decompression buffer) counted against the load's memory budget with the raster. Dispose it when done.

public IMemoryOwner<byte> RentScratch(int byteLength, ClearMode clear = ClearMode.None)

Parameters

byteLength int

The size in bytes.

clear ClearMode

Whether to zero it.

Returns

IMemoryOwner<byte>

The memory.

Exceptions

LimitExceededException

The memory budget would be exceeded.

Skip(long)

Skips count bytes.

public void Skip(long count)

Parameters

count long

How many bytes to skip.

Exceptions

CorruptDataException

The data ends first.

Warn(RasterMetadata, string, string, long?)

Notes a problem a lenient read recovered from in metadata's Warnings, for an IRowFormatReader's open image, which has its metadata but no raster. The decoder sends the warnings to Diagnostics as it does for Warn(Raster, string, string, long?).

public void Warn(RasterMetadata metadata, string id, string warning, long? offset = null)

Parameters

metadata RasterMetadata

The open image's Metadata.

id string

A stable id of the form Source.Name, such as "Pcx.PaletteMissing".

warning string

What was wrong and what the reader did, as a sentence.

offset long?

The byte offset in the input the problem is at, if known.

Exceptions

ArgumentException

id has no dot, or warning is empty.

Warn(Raster, string, string, long?)

Notes a problem a lenient read recovered from in the raster's Warnings, which also sends it to Diagnostics when the load ends.

public void Warn(Raster raster, string id, string warning, long? offset = null)

Parameters

raster Raster

The raster being read.

id string

A stable id of the form Source.Name, such as "Pcx.PaletteMissing"; Source is the part before the dot. Keep ids the same from version to version so apps can filter on them.

warning string

What was wrong and what the reader did, as a sentence.

offset long?

The byte offset in the input the problem is at, if known.

Exceptions

ArgumentException

id has no dot, or warning is empty.