Table of Contents

Class RowReader<TNatural>

Namespace
Egami.Formats
Assembly
Egami.dll

An open image whose natural pixel type is TNatural, as Load(Stream, EgamiContext?, ReaderOptions?) would give it.

public abstract class RowReader<TNatural> : RowReader, IDisposable where TNatural : unmanaged, IPixelType<TNatural>

Type Parameters

TNatural

The pixel type that best fits the file.

Inheritance
RowReader<TNatural>
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

Layout

Gets the layout of the natural pixel type.

public override PixelLayoutInfo Layout { get; }

Property Value

PixelLayoutInfo