Class EncodeStart<TPixel>
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
TPixelThe 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
Height
Gets the image height.
public int Height { get; }
Property Value
Metadata
Gets the metadata to write.
public RasterMetadata Metadata { get; }
Property Value
Options
Gets the options, which may be the base WriterOptions or the format's own.
public WriterOptions Options { get; }
Property Value
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
Streaming
Gets whether this is a streamed encode, without the whole image.
public bool Streaming { get; }
Property Value
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
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
formatstringThe format's name, which starts the message.
whatstringWhat needs every pixel, such as "Building a palette".
insteadstringWhat 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)