Table of Contents

Class RowEncoder<TPixel>

Namespace
Egami.Formats
Assembly
Egami.dll

One encode in progress: a still image's rows top-down with WriteRow(ReadOnlySpan<TPixel>), or whole frames with WriteFrame(Frame<TPixel>), then Complete().

public abstract class RowEncoder<TPixel> : IDisposable where TPixel : unmanaged, IPixelType<TPixel>

Type Parameters

TPixel

The pixel type of the rows and frames.

Inheritance
RowEncoder<TPixel>
Implements
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

Animates

Gets whether the format holds more than one frame, so WriteFrame(Frame<TPixel>) takes them all. Otherwise one frame is written as the still image, through WriteRow(ReadOnlySpan<TPixel>).

public virtual bool Animates { get; }

Property Value

bool

Methods

Complete()

Writes what follows the image data. Every row or frame has been written.

public abstract void Complete()

Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

Dispose(bool)

Returns the encoder's buffers.

protected virtual void Dispose(bool disposing)

Parameters

disposing bool

true when called from Dispose().

WriteFrame(Frame<TPixel>)

Writes the next frame of an animation. Only called when Animates.

public virtual void WriteFrame(Frame<TPixel> frame)

Parameters

frame Frame<TPixel>

The frame and its metadata; the encoder may not keep it after returning.

Exceptions

NotSupportedException

The format does not animate.

WriteRow(ReadOnlySpan<TPixel>)

Writes the next row of the still image, top-down.

public abstract void WriteRow(ReadOnlySpan<TPixel> row)

Parameters

row ReadOnlySpan<TPixel>

The row, Width wide.

WriteWhole(Raster<TPixel>)

Writes the whole image Save was given, in steps: SaveAsync writes out the bytes so far at each one. By default the rows of the first frame, top-down, 64 at a time; a format with bottom-up rows or frames overrides it.

public virtual IEnumerable<int> WriteWhole(Raster<TPixel> raster)

Parameters

raster Raster<TPixel>

The image, which is also Whole.

Returns

IEnumerable<int>

A step after each band or frame; the values only count steps.