Class CanvasOptions
Settings for a raster canvas.
public sealed record CanvasOptions : IEquatable<CanvasOptions>
- Inheritance
-
CanvasOptions
- Implements
- Inherited Members
Examples
// A canvas draws onto a raster. Calls draw when they are made; dispose the canvas when done.
using Raster<Rgba8> raster = Raster.Create(400, 300, Rgba8.White);
using (RasterCanvas<Rgba8> canvas = raster.CreateCanvas())
{
canvas.FillRect(new RectF(20, 20, 160, 100), new Rgba8(30, 90, 200, 255));
// Save and Restore bracket transform and clip changes.
canvas.Save();
canvas.Translate(260, 150);
canvas.Rotate(30);
canvas.FillRect(new RectF(-50, -30, 100, 60), new Rgba8(200, 60, 30, 200));
canvas.Restore();
canvas.FillCircle(new Vector2(100, 220), 50, Rgba8.Black);
}
// Blend edges in linear light, which keeps thin lines and translucent colors from darkening.
using RasterCanvas<Rgba8> linear = raster.CreateCanvas(new CanvasOptions { ColorSpace = ColorSpace.Linear });
Properties
Antialiasing
Gets how shapes are antialiased. Defaults to Exact; GdiPlus samples as GDI+ does and draws its thin pens. Text and images are not affected, nor are paints with Antialias off.
public Antialiasing Antialiasing { get; init; }
Property Value
Examples
// Shapes as System.Drawing draws them at its defaults (SmoothingMode.AntiAlias, PixelOffsetMode.None): whole coordinates on
// pixel centres, GDI+'s 8 by 4 samples a pixel, and pens up to 1.5 px drawn as its one-pixel thin lines.
// CanvasOptions.GdiPlus sets both too.
var options = new CanvasOptions { PixelOffset = PixelOffset.None, Antialiasing = Antialiasing.GdiPlus };
using (RasterCanvas<Rgb8> canvas = raster.CreateCanvas(options))
{
canvas.FillOval(new RectF(4, 4, 20, 20), new SolidPaint(new Rgba8(0, 90, 200, 255)));
canvas.DrawLine(new Vector2(30, 6), new Vector2(60, 26), new Stroke(0.5f), new SolidPaint(Rgba8.Black));
}
Exceptions
- ArgumentOutOfRangeException
The value is not defined.
ClearTypeLevel
Gets how much of the LCD mask Lcd text uses, from 0 (the grayscale coverage of the same samples, no colour fringes) to 1 (the default, the filtered subpixel coverage), as Windows' ClearType level. Values between mix the two, trading fringes for sharpness.
public float ClearTypeLevel { get; init; }
Property Value
Examples
// GDI+ ClearType's look: its filter (an even spread over three subpixels), no smoothing along the stripes, and the text
// gamma that then matched GDI+'s weight for a white Trebuchet MS label at 16 pixels.
var gdiPlus = new CanvasOptions
{
PixelGeometry = PixelGeometry.RgbHorizontal,
LcdFilter = LcdFilter.Gdi,
LcdSampling = LcdSampling.Gdi,
TextGamma = 1.25f,
};
var label = new Font(face, 16) { Hinting = FontHinting.Light, Edging = FontEdging.Lcd, Subpixel = false };
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(gdiPlus))
{
canvas.DrawText("Start the course", new Vector2(40, 26), label, Rgba8.White);
}
// Softer fringes: a balanced filter and half the colour of full ClearType.
var soft = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Balanced, ClearTypeLevel = 0.5f };
// Or weights of your own, normalised to add up to 256.
var custom = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Custom(1, 3, 4, 3, 1) };
Exceptions
- ArgumentOutOfRangeException
The value is not between 0 and 1.
ColorGlyphRenderer
Gets a renderer for color glyphs of formats Egami.Drawing does not draw itself (OpenType SVG with Egami.Svg's
SvgGlyphRenderer.Instance), or null (the default) to draw those glyphs as outlines.
public IColorGlyphRenderer? ColorGlyphRenderer { get; init; }
Property Value
Examples
// Emoji and other glyphs from an OpenType SVG table draw in color on a canvas given the renderer.
using (RasterCanvas<Rgba8> canvas = raster.CreateCanvas(new CanvasOptions { ColorGlyphRenderer = SvgGlyphRenderer.Instance }))
{
canvas.DrawText("Hello", new System.Numerics.Vector2(10, 35), font, new SolidPaint(new RgbaF32(0, 0, 0, 1)));
}
ColorSpace
Gets where edges and paints blend. Encoded (the default) blends the stored values, as Egami's other operations and SkiaSharp do; Linear blends in linear light, which keeps antialiased edges and translucent colors from darkening.
public ColorSpace ColorSpace { get; init; }
Property Value
Exceptions
- ArgumentOutOfRangeException
The value is not defined.
Default
Gets the options every canvas starts with.
public static CanvasOptions Default { get; }
Property Value
GdiPlus
Gets System.Drawing's canvas settings, as measured on Windows in 2.7.5 and 2.7.6. For ClearTypeGridFit text: an RGB stripe,
Gdi, Gdi (coverage in sixths, blended through GDI+'s 8-bit gamma tables) and
a TextGamma of 1.4 (GDI+'s 1 + Graphics.TextContrast / 10 at its default contrast of 4). For shapes and images:
GDI+'s default None and its GdiPlus. Use it with fonts from
WithGdiPlusLook(); the resample filter is each draw call's, such as ResampleFilter.GdiPlusBilinear.
public static CanvasOptions GdiPlus { get; }
Property Value
Examples
// Text that looks like System.Drawing's Graphics.DrawString with TextRenderingHint.ClearTypeGridFit: the font's own hints
// and grid-fitted advances, GDI+'s ClearType filter, sampling and gamma.
Font label = new Font(face, 16).WithGdiPlusLook();
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(CanvasOptions.GdiPlus))
{
float width = label.MeasureText("Start the course").Advance;
canvas.DrawText("Start the course", new Vector2(MathF.Round((200 - width) / 2), 26), label, Rgba8.White);
}
// A different Graphics.TextContrast (0 to 12) is a different text gamma: 1 + contrast / 10.
CanvasOptions contrast8 = CanvasOptions.GdiPlus with { TextGamma = 1 + (8 / 10f) };
LcdFilter
Gets the filter Lcd text spreads subpixel coverage with. Defaults to Default; Gdi is the one measured from GDI and GDI+.
public LcdFilter LcdFilter { get; init; }
Property Value
Examples
// GDI+ ClearType's look: its filter (an even spread over three subpixels), no smoothing along the stripes, and the text
// gamma that then matched GDI+'s weight for a white Trebuchet MS label at 16 pixels.
var gdiPlus = new CanvasOptions
{
PixelGeometry = PixelGeometry.RgbHorizontal,
LcdFilter = LcdFilter.Gdi,
LcdSampling = LcdSampling.Gdi,
TextGamma = 1.25f,
};
var label = new Font(face, 16) { Hinting = FontHinting.Light, Edging = FontEdging.Lcd, Subpixel = false };
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(gdiPlus))
{
canvas.DrawText("Start the course", new Vector2(40, 26), label, Rgba8.White);
}
// Softer fringes: a balanced filter and half the colour of full ClearType.
var soft = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Balanced, ClearTypeLevel = 0.5f };
// Or weights of your own, normalised to add up to 256.
var custom = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Custom(1, 3, 4, 3, 1) };
Exceptions
- ArgumentNullException
The value is null.
LcdSampling
Gets how Lcd text samples glyphs. Defaults to Smooth; Gdi leaves edges along the stripes unsmoothed, as GDI+ ClearType does.
public LcdSampling LcdSampling { get; init; }
Property Value
Examples
// GDI+ ClearType's look: its filter (an even spread over three subpixels), no smoothing along the stripes, and the text
// gamma that then matched GDI+'s weight for a white Trebuchet MS label at 16 pixels.
var gdiPlus = new CanvasOptions
{
PixelGeometry = PixelGeometry.RgbHorizontal,
LcdFilter = LcdFilter.Gdi,
LcdSampling = LcdSampling.Gdi,
TextGamma = 1.25f,
};
var label = new Font(face, 16) { Hinting = FontHinting.Light, Edging = FontEdging.Lcd, Subpixel = false };
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(gdiPlus))
{
canvas.DrawText("Start the course", new Vector2(40, 26), label, Rgba8.White);
}
// Softer fringes: a balanced filter and half the colour of full ClearType.
var soft = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Balanced, ClearTypeLevel = 0.5f };
// Or weights of your own, normalised to add up to 256.
var custom = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, LcdFilter = LcdFilter.Custom(1, 3, 4, 3, 1) };
Exceptions
- ArgumentOutOfRangeException
The value is not defined.
PixelGeometry
Gets the subpixel order of the display the image is for, which Lcd text needs. Defaults to Unknown, which draws LCD-edged text in grayscale.
public PixelGeometry PixelGeometry { get; init; }
Property Value
Exceptions
- ArgumentOutOfRangeException
The value is not defined.
PixelOffset
Gets where pixel centres are. Defaults to Half; None is GDI+'s default, which moves paths and unhinted text half a pixel.
public PixelOffset PixelOffset { get; init; }
Property Value
Examples
// Shapes as System.Drawing draws them at its defaults (SmoothingMode.AntiAlias, PixelOffsetMode.None): whole coordinates on
// pixel centres, GDI+'s 8 by 4 samples a pixel, and pens up to 1.5 px drawn as its one-pixel thin lines.
// CanvasOptions.GdiPlus sets both too.
var options = new CanvasOptions { PixelOffset = PixelOffset.None, Antialiasing = Antialiasing.GdiPlus };
using (RasterCanvas<Rgb8> canvas = raster.CreateCanvas(options))
{
canvas.FillOval(new RectF(4, 4, 20, 20), new SolidPaint(new Rgba8(0, 90, 200, 255)));
canvas.DrawLine(new Vector2(30, 6), new Vector2(60, 26), new Stroke(0.5f), new SolidPaint(Rgba8.Black));
}
Exceptions
- ArgumentOutOfRangeException
The value is not defined.
TextContrast
Gets how much thin glyph coverage is boosted before it blends, from 0 to 1. Defaults to 0, none. Coverage a becomes a + (1 − a)·c·a, the contrast boost of Skia and DirectWrite: it thickens antialiased edges and leaves full coverage alone. It applies to all cached glyphs, whatever the paint, canvas or ColorSpace.
public float TextContrast { get; init; }
Property Value
Examples
// A white label on a blue button, weighted like GDI+'s ClearTypeGridFit text: a text gamma of 1.15 matched the brightness
// GDI+ adds to within 1% for Trebuchet MS at 16 pixels. Shapes and images on this canvas blend as before.
var options = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, TextGamma = 1.15f };
var label = new Font(face, 16) { Hinting = FontHinting.Light, Edging = FontEdging.Lcd, Subpixel = false };
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(options))
{
canvas.DrawText("Start the course", new Vector2(40, 26), label, Rgba8.White);
}
// Thin dark text on a light page can take a contrast boost instead, as Skia and DirectWrite do.
var boosted = new CanvasOptions { TextContrast = 0.25f };
Exceptions
- ArgumentOutOfRangeException
The value is not between 0 and 1.
TextGamma
Gets the gamma of the blend that draws glyph coverage, from 0.5 to 3. Defaults to 1, today's blend. Each channel blends as (a·src^γ + (1 − a)·dst^γ)^(1/γ) on the stored values, as GDI ClearType does (its default is 1.4); above 1 light text on a dark ground gets heavier and dark text on a light ground lighter. Shapes and images never pass through it.
public float TextGamma { get; init; }
Property Value
Examples
// A white label on a blue button, weighted like GDI+'s ClearTypeGridFit text: a text gamma of 1.15 matched the brightness
// GDI+ adds to within 1% for Trebuchet MS at 16 pixels. Shapes and images on this canvas blend as before.
var options = new CanvasOptions { PixelGeometry = PixelGeometry.RgbHorizontal, TextGamma = 1.15f };
var label = new Font(face, 16) { Hinting = FontHinting.Light, Edging = FontEdging.Lcd, Subpixel = false };
using (RasterCanvas<Rgb8> canvas = button.CreateCanvas(options))
{
canvas.DrawText("Start the course", new Vector2(40, 26), label, Rgba8.White);
}
// Thin dark text on a light page can take a contrast boost instead, as Skia and DirectWrite do.
var boosted = new CanvasOptions { TextContrast = 0.25f };
Remarks
The gamma applies to solid source-over text on an 8-bit RGB canvas outside a layer, the text LCD edging can draw; other text takes TextContrast only. With Linear the gamma is ignored: that blend is already a gamma-correct one.
Exceptions
- ArgumentOutOfRangeException
The value is not between 0.5 and 3.
Tolerance
Gets how far, in device pixels, a curve's straight-line approximation may stray from it. Defaults to 0.1; smaller values cost more lines.
public float Tolerance { get; init; }
Property Value
Exceptions
- ArgumentOutOfRangeException
The value is not between 0.001 and 10.