Class Picture
Recorded canvas calls, from a PictureRecorder or Load(Stream, EgamiContext?): replay them on any canvas with DrawPicture(Picture, Matrix3x2?, Paint?, bool) or Playback(Canvas), fill shapes with them through a PicturePaint, render them with ToRaster<TPixel>(float, CanvasOptions?, EgamiContext?), or keep them in an .egdr file with Save(Stream). Replay is always vector, so a picture stays sharp at any scale. Immutable, and safe to replay on several threads and canvases at once.
public sealed class Picture
- Inheritance
-
Picture
- Inherited Members
Examples
// Record any picture code once...
PictureRecorder recorder = new(new RectF(0, 0, 40, 40));
DrawLogo(recorder);
Picture logo = recorder.Finish();
using (RasterCanvas<Rgba8> canvas = raster.CreateCanvas())
{
// ...and replay it anywhere, at any scale, still sharp: replay is vector.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(10, 10));
canvas.DrawPicture(logo, Matrix3x2.CreateScale(4) * Matrix3x2.CreateTranslation(60, 10));
// A paint with an opacity merges the whole picture as one layer.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(240, 10), new SolidPaint(Rgba8.White) { Opacity = 0.4f });
// Drawn many times at one scale, a cached image is cheaper than replaying.
for (int i = 0; i < 6; i++)
{
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(230 + (i * 25), 150), cacheAsImage: true);
}
}
using Raster<Rgba8> icon = logo.ToRaster<Rgba8>(scale: 2);
Properties
Bounds
Gets the picture's bounds in its own coordinates, as the recorder was given them.
public RectF Bounds { get; }
Property Value
CallCount
Gets the number of recorded calls, saves and transforms included; nested pictures count as one.
public int CallCount { get; }
Property Value
Methods
Load(Stream, EgamiContext?)
Reads an Egami picture file. The file is untrusted input: its images go through the PNG reader with the context's SafetyLimits, what it decodes counts toward MaxTotalBytes, and pictures may nest 64 deep and replay at most 50 million calls with nested pictures expanded.
public static Picture Load(Stream stream, EgamiContext? context = null)
Parameters
streamStreamThe stream to read from, to its end.
contextEgamiContextThe context whose limits apply, or null for the default.
Returns
- Picture
The picture.
Examples
// Keep a picture in Egami's own documented format, and load it later; a loaded file is untrusted, so the context's
// safety limits apply.
using (FileStream file = File.Create("logo.egdr"))
{
logo.Save(file);
}
Picture loaded;
using (FileStream file = File.OpenRead("logo.egdr"))
{
loaded = Picture.Load(file);
}
Exceptions
- UnsupportedFormatException
The data is not an .egdr file, or is a major version this reader does not know.
- CorruptDataException
The file is damaged.
- LimitExceededException
The file is larger, or nests deeper, than the limits allow.
Playback(Canvas)
Replays the calls on a canvas through its public calls, between a Save() and a Restore(); recorded transforms apply after the canvas's transform at the start.
public void Playback(Canvas canvas)
Parameters
canvasCanvasThe canvas.
Examples
// Record any picture code once...
PictureRecorder recorder = new(new RectF(0, 0, 40, 40));
DrawLogo(recorder);
Picture logo = recorder.Finish();
using (RasterCanvas<Rgba8> canvas = raster.CreateCanvas())
{
// ...and replay it anywhere, at any scale, still sharp: replay is vector.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(10, 10));
canvas.DrawPicture(logo, Matrix3x2.CreateScale(4) * Matrix3x2.CreateTranslation(60, 10));
// A paint with an opacity merges the whole picture as one layer.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(240, 10), new SolidPaint(Rgba8.White) { Opacity = 0.4f });
// Drawn many times at one scale, a cached image is cheaper than replaying.
for (int i = 0; i < 6; i++)
{
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(230 + (i * 25), 150), cacheAsImage: true);
}
}
using Raster<Rgba8> icon = logo.ToRaster<Rgba8>(scale: 2);
Save(Stream)
Writes the picture as an Egami picture file (.egdr), Egami's own documented binary format: a signature and version, then chunks that a reader skips when it does not know them. Images are kept as PNG (so a float image is kept at 16 bits), paths and numbers as 32-bit floats, nested pictures once however often they are used, and text as its outlines, since a file holds no fonts. A picture that loads back replays the same calls and draws the same pixels, except that text comes back as outline fills, which the raster backend draws as paths rather than from its glyph cache.
public void Save(Stream stream)
Parameters
streamStreamThe stream to write to.
Examples
// Keep a picture in Egami's own documented format, and load it later; a loaded file is untrusted, so the context's
// safety limits apply.
using (FileStream file = File.Create("logo.egdr"))
{
logo.Save(file);
}
Picture loaded;
using (FileStream file = File.OpenRead("logo.egdr"))
{
loaded = Picture.Load(file);
}
Exceptions
- NotSupportedException
A call holds C# code a file cannot: a CustomPaint, or a layer's filter, backdrop or soft mask. The message gives the call's index. Nothing is written in that case.
ToRaster<TPixel>(float, CanvasOptions?, EgamiContext?)
Renders the picture's Bounds into a new raster, over transparency.
public Raster<TPixel> ToRaster<TPixel>(float scale = 1, CanvasOptions? options = null, EgamiContext? context = null) where TPixel : unmanaged, IPixelType<TPixel>
Parameters
scalefloatRaster pixels per picture unit.
optionsCanvasOptionsThe canvas settings, or null for the defaults.
contextEgamiContextThe context the raster is made in, or null for the default.
Returns
- Raster<TPixel>
A raster of the bounds' size times the scale, rounded up.
Type Parameters
TPixelThe raster's pixel type.
Examples
// Record any picture code once...
PictureRecorder recorder = new(new RectF(0, 0, 40, 40));
DrawLogo(recorder);
Picture logo = recorder.Finish();
using (RasterCanvas<Rgba8> canvas = raster.CreateCanvas())
{
// ...and replay it anywhere, at any scale, still sharp: replay is vector.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(10, 10));
canvas.DrawPicture(logo, Matrix3x2.CreateScale(4) * Matrix3x2.CreateTranslation(60, 10));
// A paint with an opacity merges the whole picture as one layer.
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(240, 10), new SolidPaint(Rgba8.White) { Opacity = 0.4f });
// Drawn many times at one scale, a cached image is cheaper than replaying.
for (int i = 0; i < 6; i++)
{
canvas.DrawPicture(logo, Matrix3x2.CreateTranslation(230 + (i * 25), 150), cacheAsImage: true);
}
}
using Raster<Rgba8> icon = logo.ToRaster<Rgba8>(scale: 2);
Exceptions
- ArgumentOutOfRangeException
scaleis not positive and finite, or the raster would be too large.