Class RasterEncoder<TPixel>
- Namespace
- Egami
- Assembly
- Egami.dll
An image being written a band of rows or a frame at a time, so a huge image never has to exist whole. The bytes are the ones Save(Stream, FormatInfo, WriterOptions?) writes for the same pixels and options, except where a format must write differently without seeking: top-down BMP and TGA rows, and run-length TGA, which is always top-down. Options that need every pixel before the first byte (automatic palettes, PNG's Reduce, automatic alpha) throw at Create instead of quietly writing something else.
public sealed class RasterEncoder<TPixel> : IDisposable where TPixel : unmanaged, IPixelType<TPixel>
Type Parameters
TPixelThe pixel type of the rows and frames.
- Inheritance
-
RasterEncoder<TPixel>
- Implements
- Inherited Members
Examples
// A huge image written a band at a time: only the band is ever in memory.
const int Width = 8_000, Height = 6_000;
using Raster<Rgb8> band = Raster.Create<Rgb8>(Width, 64);
using RasterEncoder<Rgb8> encoder = RasterEncoder.Create<Rgb8>("big.png", Width, Height);
for (int top = 0; top < Height; top += band.Height)
{
int rows = Math.Min(band.Height, Height - top);
for (int y = 0; y < rows; y++)
{
band.Row(y).Fill(new Rgb8((byte)(top + y), 128, 200));
}
encoder.WriteRows(band, rows);
}
encoder.Complete(); // writes IEND; without it the file is deleted on dispose
Remarks
Write a still image with WriteRows(Raster<TPixel>, int), top to bottom, or an animation with WriteFrame(Raster<TPixel>, FrameMetadata?); then call Complete(), which writes what follows the image data. An encoder is one caller's object and is not thread-safe. Formats from plugins that do not stream gather the image and write it at Complete.
Properties
Format
Gets the format being written.
public FormatInfo Format { get; }
Property Value
FramesWritten
Gets how many frames have been written.
public int FramesWritten { get; }
Property Value
Height
Gets the image height.
public int Height { get; }
Property Value
RowsWritten
Gets how many rows of the still image have been written.
public int RowsWritten { get; }
Property Value
Width
Gets the image width.
public int Width { get; }
Property Value
Methods
Complete()
Writes what follows the image data, such as PNG's IEND or a TGA footer, and the bytes still held. Without it the output is truncated.
public void Complete()
Exceptions
- InvalidOperationException
Fewer rows than Height, or no frame, were written.
- ObjectDisposedException
The encoder has been disposed.
CompleteAsync(CancellationToken)
Completes the image as Complete() does, writing the last bytes asynchronously.
public ValueTask CompleteAsync(CancellationToken cancellationToken = default)
Parameters
cancellationTokenCancellationTokenCancels the write.
Returns
- ValueTask
A task that completes when every byte is written.
Exceptions
- InvalidOperationException
Fewer rows than Height, or no frame, were written.
- ObjectDisposedException
The encoder has been disposed.
- OperationCanceledException
cancellationTokenwas canceled.
Dispose()
Releases the encoder. Disposing before Complete() leaves a truncated stream; a file the encoder created is deleted.
public void Dispose()
WriteFrame(Raster<TPixel>, FrameMetadata?)
Writes the next frame of an animation (GIF, APNG), with its delay from metadata. A format that holds one
image takes one frame, written as the still image.
public void WriteFrame(Raster<TPixel> frame, FrameMetadata? metadata = null)
Parameters
frameRaster<TPixel>metadataFrameMetadataThe frame's delay, or null for the frame's own metadata.
Examples
// An animation written a frame at a time, each frame from one reused canvas.
using Raster<Rgba8> canvas = Raster.Create<Rgba8>(120, 80);
using FileStream file = File.Create("spinner.gif");
using RasterEncoder<Rgba8> gif = RasterEncoder.Create<Rgba8>(file, GifFormat.Info, 120, 80);
for (int i = 0; i < 12; i++)
{
for (int y = 0; y < canvas.Height; y++)
{
canvas.Row(y).Fill(new Rgba8(255, 255, 255, 255));
}
canvas.Row(40)[(i * 10)..((i * 10) + 10)].Fill(new Rgba8(200, 0, 0, 255));
gif.WriteFrame(canvas, new Metadata.FrameMetadata { Delay = TimeSpan.FromMilliseconds(80) });
}
gif.Complete();
Exceptions
- ArgumentNullException
frameis null.- ArgumentException
- InvalidOperationException
Rows were written, the format holds one image and it was written, an APNG to a stream that cannot seek has no FrameCount, or the encoder is complete.
- ObjectDisposedException
The encoder has been disposed.
WriteFrameAsync(Raster<TPixel>, FrameMetadata?, CancellationToken)
Writes the next frame as WriteFrame(Raster<TPixel>, FrameMetadata?) does, then writes the encoded bytes asynchronously.
public ValueTask WriteFrameAsync(Raster<TPixel> frame, FrameMetadata? metadata = null, CancellationToken cancellationToken = default)
Parameters
frameRaster<TPixel>metadataFrameMetadataThe frame's delay, or null for the frame's own metadata.
cancellationTokenCancellationTokenCancels the write.
Returns
- ValueTask
A task that completes when the bytes are written.
Exceptions
- ArgumentNullException
frameis null.- ArgumentException
- InvalidOperationException
- ObjectDisposedException
The encoder has been disposed.
- OperationCanceledException
cancellationTokenwas canceled.
WriteRows(Raster<TPixel>)
Writes every row of band's first frame as the next rows of the still image.
public void WriteRows(Raster<TPixel> band)
Parameters
Exceptions
- ArgumentNullException
bandis null.- ArgumentException
bandis not Width wide.- ArgumentOutOfRangeException
The band holds more rows than are left.
- InvalidOperationException
Frames were written, or the encoder is complete.
- ObjectDisposedException
The encoder has been disposed.
WriteRows(Raster<TPixel>, int)
Writes the next rows rows of the still image, from the top of band's first frame. Rows
go top to bottom; together the calls write exactly Height rows.
public void WriteRows(Raster<TPixel> band, int rows)
Parameters
bandRaster<TPixel>The rows, Width wide.
rowsintHow many of the band's rows to write, from its top.
Examples
// A huge image written a band at a time: only the band is ever in memory.
const int Width = 8_000, Height = 6_000;
using Raster<Rgb8> band = Raster.Create<Rgb8>(Width, 64);
using RasterEncoder<Rgb8> encoder = RasterEncoder.Create<Rgb8>("big.png", Width, Height);
for (int top = 0; top < Height; top += band.Height)
{
int rows = Math.Min(band.Height, Height - top);
for (int y = 0; y < rows; y++)
{
band.Row(y).Fill(new Rgb8((byte)(top + y), 128, 200));
}
encoder.WriteRows(band, rows);
}
encoder.Complete(); // writes IEND; without it the file is deleted on dispose
Exceptions
- ArgumentNullException
bandis null.- ArgumentException
bandis not Width wide.- ArgumentOutOfRangeException
rowsis negative, more than the band holds, or more than are left.- InvalidOperationException
Frames were written, or the encoder is complete.
- ObjectDisposedException
The encoder has been disposed.
WriteRowsAsync(Raster<TPixel>, int, CancellationToken)
Writes the next rows as WriteRows(Raster<TPixel>, int) does, then writes the encoded bytes to the stream asynchronously. Encoding itself is synchronous, since it is CPU-bound.
public ValueTask WriteRowsAsync(Raster<TPixel> band, int rows, CancellationToken cancellationToken = default)
Parameters
bandRaster<TPixel>The rows, Width wide.
rowsintHow many of the band's rows to write, from its top.
cancellationTokenCancellationTokenCancels the write.
Returns
- ValueTask
A task that completes when the bytes are written.
Examples
// On a server: send each band as it is encoded, without holding the file.
using RasterDecoder source = RasterDecoder.Open("egret.png");
using Raster<Rgb8> band = Raster.Create<Rgb8>(source.Info.Width, 32);
using RasterEncoder<Rgb8> encoder = RasterEncoder.Create<Rgb8>(response, JpegFormat.Info, source.Info.Width, source.Info.Height);
int rows;
while ((rows = source.ReadRows(band)) > 0)
{
await encoder.WriteRowsAsync(band, rows, TestContext.Current.CancellationToken);
}
await encoder.CompleteAsync(TestContext.Current.CancellationToken);
Exceptions
- ArgumentNullException
bandis null.- ArgumentException
bandis not Width wide.- ArgumentOutOfRangeException
rowsis negative, more than the band holds, or more than are left.- InvalidOperationException
Frames were written, or the encoder is complete.
- ObjectDisposedException
The encoder has been disposed.
- OperationCanceledException
cancellationTokenwas canceled.