Table of Contents

Class EncodeStart<TPixel>

Namespace
Egami.Formats
Assembly
Egami.dll

What an encode starts from: the size, metadata and options, and the whole image when Save has one.

public sealed class EncodeStart<TPixel> where TPixel : unmanaged, IPixelType<TPixel>

Type Parameters

TPixel

The pixel type of the rows and frames.

Inheritance
EncodeStart<TPixel>
Inherited Members

Examples

/// <summary>The same RAW8 format, streaming: rows go in and out one at a time, so RasterDecoder, RasterEncoder and Transcode stream it.</summary>
public static class StreamingRaw8Format
{
    public static FormatInfo Info { get; } = Raw8Format.Info with { Reader = new Reader(), Writer = new Writer() };

    private sealed class Reader : IFormatReader, IRowFormatReader
    {
        private static readonly IFormatReader Whole = Raw8Format.Info.Reader!;

        public RasterInfo ReadInfo(EgamiInput input, ReaderOptions options) => Whole.ReadInfo(input, options) with { Access = RasterAccess.Streamed };

        public Raster<TPixel> Read<TPixel>(EgamiInput input, ReaderOptions options)
            where TPixel : unmanaged, IPixelType<TPixel> => Whole.Read<TPixel>(input, options);

        public Raster Read(EgamiInput input, ReaderOptions options) => Whole.Read(input, options);

        // The open image reads each row when it is asked for; the decoder crops, reduces and converts after it.
        public RowReader Open(EgamiInput input, ReaderOptions options)
        {
            input.Skip(4);
            int width = (int)input.ReadUInt32BigEndian();
            int height = (int)input.ReadUInt32BigEndian();

            // No raster checks the size here, so check it before the row buffer is allocated.
            input.CheckFrameSize(width, height);
            return new Rows(input, width, height);
        }
    }

    private sealed class Rows(EgamiInput input, int width, int height) : RowReader<Rgba8>
    {
        private readonly Rgba8[] _row = new Rgba8[width];
        private int _next;
        private bool _started;

        public override int Width => width;

        public override int Height => height;

        public override Metadata.RasterMetadata Metadata { get; } = new();

        public override Metadata.FrameMetadata? NextFrame()
        {
            if (_started)
            {
                return null;
            }

            _started = true;
            return new Metadata.FrameMetadata();
        }

        public override void ReadRow<TPixel>(int y, int x, Span<TPixel> destination)
        {
            for (; _next <= y; _next++)
            {
                input.ReadExactly(MemoryMarshal.AsBytes(_row.AsSpan()));
            }

            PixelConvert.Convert<Rgba8, TPixel>(_row.AsSpan(x, destination.Length), destination);
        }
    }

    private sealed class Writer : IFormatWriter, IRowFormatWriter
    {
        public void Write<TPixel>(Raster<TPixel> raster, Stream output, WriterOptions options)
            where TPixel : unmanaged, IPixelType<TPixel> => Raw8Format.Info.Writer!.Write(raster, output, options);

        // Save, SaveAsync, RasterEncoder and Transcode all write through the encoder.
        public RowEncoder<TPixel> Start<TPixel>(Stream output, EncodeStart<TPixel> start)
            where TPixel : unmanaged, IPixelType<TPixel>
        {
            // RAW8 keeps 8-bit RGBA and nothing else: deeper samples or metadata are reported as lost.
            start.ReportLosses("RAW8", SaveKeeps.Alpha);
            return new Encoder<TPixel>(output, start.Width, start.Height);
        }
    }

    private sealed class Encoder<TPixel> : RowEncoder<TPixel>
        where TPixel : unmanaged, IPixelType<TPixel>
    {
        private readonly Stream _output;
        private readonly Rgba8[] _row;

        public Encoder(Stream output, int width, int height)
        {
            _output = output;
            _row = new Rgba8[width];
            Span<byte> header = stackalloc byte[12];
            "RAW8"u8.CopyTo(header);
            BinaryPrimitives.WriteUInt32BigEndian(header[4..], (uint)width);
            BinaryPrimitives.WriteUInt32BigEndian(header[8..], (uint)height);
            output.Write(header);
        }

        public override void WriteRow(ReadOnlySpan<TPixel> row)
        {
            PixelConvert.Convert<TPixel, Rgba8>(row, _row);
            _output.Write(MemoryMarshal.AsBytes(_row.AsSpan()));
        }

        public override void Complete()
        {
        }
    }
}

Properties

Context

Gets the context, for its memory and parallelism.

public EgamiContext Context { get; }

Property Value

EgamiContext

Height

Gets the image height.

public int Height { get; }

Property Value

int

Metadata

Gets the metadata to write.

public RasterMetadata Metadata { get; }

Property Value

RasterMetadata

Options

Gets the options, which may be the base WriterOptions or the format's own.

public WriterOptions Options { get; }

Property Value

WriterOptions

Seekable

Gets whether the output can seek back: when streaming, bottom-up rows can then land in place and counts be patched at the end.

public bool Seekable { get; }

Property Value

bool

Streaming

Gets whether this is a streamed encode, without the whole image.

public bool Streaming { get; }

Property Value

bool

Whole

Gets the whole image when Save writes one: choices may then look at every pixel, and WriteWhole(Raster<TPixel>) takes the rows in the file's order. null when streaming, where rows come top-down as the caller has them.

public Raster<TPixel>? Whole { get; }

Property Value

Raster<TPixel>

Width

Gets the image width.

public int Width { get; }

Property Value

int

Methods

Refuse(string, string, string)

Throws NotSupportedException, for a streamed encode, that what needs every pixel before the first byte, and says what to set instead. Does nothing for Save.

public void Refuse(string format, string what, string instead)

Parameters

format string

The format's name, which starts the message.

what string

What needs every pixel, such as "Building a palette".

instead string

What to set instead.

Exceptions

NotSupportedException

The encode is streamed.

ReportLosses(string, SaveKeeps)

Reports, as Warnings to Diagnostics, what this encode loses without being asked: alpha, depth, CMYK inks, frames or metadata that keeps does not name. Nothing is examined unless a handler takes Warnings. Core Egami's writers call it as they start; a format plugin calls it from Start<TPixel>(Stream, EncodeStart<TPixel>).

public void ReportLosses(string format, SaveKeeps keeps)

Parameters

format string

The format's name, which starts each message.

keeps SaveKeeps

What the writer keeps, as it will write this image.