PeachDrawing
PeachDrawing
RasterCanvas Class
An Canvas that paints into a RasterSurface instead of a PDF content stream. It exists for the effects PDF cannot express in vector form; the bitmap it produces is embedded back into the PDF by the graphics that asked for it (BeginRasterSurface(Rect, Nullable<double>)).
public sealed class RasterCanvas : PeachDrawing.Core.Canvas
Inheritance System.Object → Canvas → RasterCanvas
Remarks
Coordinates follow _sx/_sy then map points to surface pixels.
Pens, brushes, fonts and paths are the PDF adapter’s own objects: they are plain data and this backend runs in the same assembly, so it reads them directly rather than duplicating the adapter layer. That keeps text metrics identical to layout by construction.
| Constructors | |
|---|---|
| RasterCanvas(RenderContext, RasterSurface, double) | Builds a canvas that paints into surface. |
| Properties | |
|---|---|
| CurrentTransform | The accumulated transform of every PushTransform(Matrix3x2) in effect, mapping this graphics’ current user space to the layout space it started in (the space page content is laid out in). Identity for a graphics that does not track transforms. Bookkeeping only, read by callers (gradient/pattern objectBoundingBox math, an SVG backdrop repaint, context-fill/ context-stroke’s coordinate-space mapping) - it plays no part in what this graphics actually draws, which a concrete backend positions its own way. A tile this graphics hands out (CreateTile(double, double)’s Graphics, or BeginRasterSurface(Rect, Nullable<double>)’s) starts seeded from this value, not System.Numerics.Matrix3x2.Identity, precisely so a reader can still relate the tile’s own coordinate space back to whatever space content outside the tile is measured in. |
| IsOffscreenTile | Whether this instance paints into an offscreen tile (e.g. one returned by CreateTile(double, double), used for group opacity and SVG pattern/mask content) rather than directly into the real page’s own content stream. Tagged-PDF output does not emit marked-content sequences into tile content streams in the current implementation (doing so correctly needs /MCR with /Stm//StmOwn pointing at the tile’s own content stream, not yet wired up) - callers use this to skip MCID/BDC emission while still creating the struct element itself, so the tree shape stays well-formed even though this particular occurrence contributes no reachable MCID. Defaults to false. |
| PixelsPerPoint | The scale between this graphics context’s own coordinate space and true points (1/72 inch): a backend whose coordinates are inflated relative to a point (for example a layout space running at a higher pixels-per-inch than 72) reports that inflation here. 1.0 (the base, no-op default) is correct for any Canvas whose coordinate space is not inflated this way; a backend whose space is overrides this with its real value. A caller that needs to compute a transform matrix whose *linear* (scale/rotation) part won’t itself be divided by this factor before use - a backend may divide only a matrix’s translation, not M11/M12/M21/M22 - reads this to pre-divide that part itself (an SVG viewBox-to-viewport transform is such a case: its “scale” is a ratio of an inflated length to a never-inflated, dimensionless user unit, so it is not already scale-neutral the way an ordinary scale() transform is). |
| PrefersRasterGroups | Whether group effects (opacity, blend modes, colour functions) are best done by rendering the element into a tight bitmap and compositing that, rather than through CreateTile(double, double). True for a raster graphics, whose tile would otherwise span from the page origin; false for a PDF graphics, where a tile is a cheap vector Form XObject. |
| Surface | The pixel buffer this canvas paints into. |
| Methods | |
|---|---|
| BeginArtifact() | Begins an artifact marked-content sequence - marks the content that follows as not part of the document’s logical structure (e.g. a decorative <hr>). Must be paired with EndMarkedContent(). |
| BeginMarkedContent(string, int) | Begins a tagged marked-content sequence in the page content stream, associated with the given PDF structure type (e.g. “/H1”, “/P”) and marked-content identifier. Only called when tagged PDF output is enabled. Must be paired with EndMarkedContent(), wrapping a whole leaf box’s own paint calls - never part of one. |
| BeginRasterSurface(Rect, Nullable<double>) | A raster region inside a raster region (a filtered element within a filtered ancestor). It keeps this surface’s own pixel pitch and grid instead of going back to the document’s DPI, so compositing it back is an exact pixel copy rather than a resample, and it is cut to this surface: nothing outside it was painted to begin with. |
| BeginVariableText() | Begins the /Tx marked-content sequence ISO 32000-1 §12.7.3.3 requires around the value drawn into an interactive form field’s appearance stream, and EndVariableText() closes it. It is what tells a PDF reader which part of the generated appearance to replace when the user edits the field - without it the reader draws the new value over the generated one instead of in place of it. Deliberately a pair of its own rather than reusing EndMarkedContent(): these two must sit outside any text object, while that one has a caller that is legitimately inside one. |
| CountShapedGlyphs(string, Font, Nullable<ShapeSettings>) | The number of glyphs str shapes into once GSUB substitution is applied - always <= str’s character count, less whenever a ligature merges more than one character into a single glyph (single substitution never changes the count). Used to size the per-glyph letter-spacing gap count a word’s box must reserve (the PDF Tc operator adds one gap per glyph actually shown, not per source character), so it stays in sync with what DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>) paints for the same text/font/features. |
| CreateTile(double, double) | Creates a fresh, independent (width x height) drawing surface for tile-based content (e.g. an SVG <pattern>’s cell): draw into the returned Graphics using ordinary Canvas calls, then use the returned Image with DrawImage(Image, Rect) - repeated calls tile it, each one a real reference to the same underlying vector content (a PDF Form XObject), never rasterized. Null when creating one isn’t supported in the current rendering context (e.g. a measure-only pass with no real PDF page to own the new object). |
| Dispose() | Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. |
| DrawGlyphs(IReadOnlyList<GlyphPlacement>, Font, PaintColor) | Draws each of glyphs at its own explicit position, addressed directly by font glyph index rather than by Unicode character - unlike DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>), this never re-shapes/re-maps through cmap/GSUB, so it can draw a glyph with no Unicode mapping at all (e.g. an OpenType MATH table’s stretchy-operator assembly parts or pre-sized size variants, which are reached only via MathVariantsTable glyph ids, not through any character). Each GlyphPlacement’s X/Y is that glyph’s own baseline origin (not a bounding-box corner), in the same working unit space as DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>)’s own point parameter - unlike that method, there is no separate ascent-relative adjustment, since every glyph here already carries its own exact target baseline position. |
| DrawImage(Image, Rect) | Draws the specified Image at the specified location and with the specified size. |
| DrawImage(Image, Rect, ImageSampling) | Draws image into destRect, reading its pixels as sampling says. |
| DrawImage(Image, Rect, Rect) | Draws the specified portion of the specified Image at the specified location and with the specified size. |
| DrawImage(Image, Rect, Rect, ImageSampling) | Draws part of image into destRect, reading its pixels as sampling says. |
| DrawImageAlphaMasked(Image, Image, Rect, bool) | Draws image (a tile from CreateTile(double, double)) at destRect with maskImage (another same-adapter tile) attached as an /Alpha-subtype soft mask (ISO 32000-1 §11.6.4.3) - unlike DrawImageMasked(Image, Image, Rect)’s /Luminosity mask, which derives mask values from the mask tile’s rendered COLOR converted to grayscale, this derives them directly from the mask tile’s own computed ALPHA, disregarding whatever color it painted with. The motivating future use case is SVG’s SourceAlpha filter input and feComposite, both of which are defined in terms of a source’s alpha channel specifically, not a luminosity conversion of it. When invert is true, the mask’s /TR is set to 1 - x (a PDF Type 4 function), for a complemented alpha mask without needing a second tile painted with inverted alpha. A no-op if either image wasn’t created via CreateTile(double, double) on this same Canvas. |
| DrawImageBlendedOver(Image, Image, Rect, PaintBlendMode) | Paints bottom normally at destRect, then top on top of it at the same rect composited with blendMode - both same-adapter tiles from CreateTile(double, double), sized/positioned identically in their own local coordinate systems. The motivating future use case is SVG’s feBlend, which blends two independently-rendered filter inputs together inside a fresh tile rather than blending freshly-painted content against whatever the page already has underneath it (which is what PushBlendMode(PaintBlendMode)/PopBlendMode() do). A no-op if either image wasn’t created via CreateTile(double, double) on this same Canvas. |
| DrawImageMasked(Image, Image, Rect) | Draws image (a tile from CreateTile(double, double)) at destRect with maskImage (another same-adapter tile, sharing image’s own local width/height) applied as a luminosity soft mask, scoped to just this one placement. White areas of maskImage are fully visible, black fully transparent, matching PDF’s/SVG’s own <mask> semantics. Deliberately NOT a “push mask, draw normally, pop mask” pair (which an earlier version of this API was): a tile’s own content is Y-flipped relative to its own (small) size, not the page’s, so positioning it correctly requires the same explicit destRect placement DrawImage(Image, Rect) already uses for pattern tiles - relying on whatever transform happens to be ambient in the page’s own content stream at some arbitrary “push” point silently mispositions the mask relative to the content it’s meant to mask. A no-op if either image wasn’t created via CreateTile(double, double) on this same Canvas. |
| DrawImageWithColorMatrix(Image, Rect, ColorMatrix) | Draws image (a tile from CreateTile(double, double)) at destRect, composited through a CSS/SVG filter color-matrix transform (grayscale(), sepia(), saturate(), hue-rotate(), invert(), brightness(), contrast(), or feColorMatrix) expressed as matrix. Only representable when IsChannelIndependent is true - see ColorMatrix’s remarks for why a PDF ExtGState transfer function (the mechanism this goes through) cannot express a matrix that mixes color channels, and what a caller needs instead for one that does. A no-op if image wasn’t created via CreateTile(double, double) on this same Canvas. |
| DrawImageWithOpacity(Image, Rect, double, PaintBlendMode) | Draws image (a tile from CreateTile(double, double)) at destRect, composited as a single flattened result at constant opacity - the mechanism behind CSS/SVG group opacity. Unlike simply multiplying the alpha of each shape painted into the tile, this flattens the tile’s own (possibly overlapping) content once before applying opacity to the flattened result, so overlapping content doesn’t double-darken where it overlaps. A no-op if image wasn’t created via CreateTile(double, double) on this same Canvas. blendMode composites the flattened tile against the destination with a non-Normal PDF blend mode in the same gs as opacity - the mechanism behind CSS mix-blend-mode combined with group opacity, a single ExtGState rather than two nested ones. |
| DrawLine(Pen, double, double, double, double) | Draws a line connecting the two points specified by the coordinate pairs. |
| DrawPath(Brush, GraphicsPath) | Fills the interior of a GraphicsPath. |
| DrawPath(Pen, GraphicsPath) | Draws a GraphicsPath. |
| DrawPolygon(Brush, PaintPoint[]) | Fills the interior of a polygon defined by an array of points specified by PaintPoint structures. |
| DrawRaster(RasterSurface) | Draws a surface obtained from BeginRasterSurface(Rect, Nullable<double>) into this graphics at the rectangle the surface itself records, so its physical size is exact. Honours this graphics’ current transform, clip and blend mode. |
| DrawRectangle(Brush, double, double, double, double) | Fills the interior of a rectangle specified by a pair of coordinates, a width, and a height. |
| DrawRectangle(Pen, double, double, double, double) | Draws a rectangle specified by a coordinate pair, a width, and a height. |
| DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>) | Draw the given string using the given font and foreground color at given location. |
| EndMarkedContent() | Ends a marked-content sequence started by BeginMarkedContent(string, int) or BeginArtifact(). |
| EndVariableText() | Closes the sequence BeginVariableText() opened. |
| Erase(GraphicsPath) | Removes the pixels inside path (in user space, like every path this class draws): each pixel is scaled by one minus the path’s anti-aliased coverage, so an edge that is half inside keeps half its ink. This is the “destination-out” operation an outer box-shadow needs - the shadow is not painted under its own box (CSS Backgrounds 3 §7.1.1) - which no Canvas primitive expresses. |
| EraseRectangle(Rect) | Removes the pixels inside the layout-space rectangle rect (see Erase(GraphicsPath)). |
| GetGraphicsPath() | Get GraphicsPath object. |
| GetInkCrossings(string, Font, PaintPoint, double, double, double, Nullable<ShapeSettings>) | The horizontal ranges in which str’s glyph ink crosses the horizontal band between bandTop and bandBottom — what text-decoration-skip-ink ([CSS Text |
| Decoration 4 §2.5](https://www.w3.org/TR/css-text-decor-4/#text-decoration-skip-ink-property ‘https://www.w3.org/TR/css-text-decor-4/#text-decoration-skip-ink-property’)) removes from an underline or overline drawn through that band. | |
| GetTextOutline(string, Font, PaintPoint, double, Nullable<ShapeSettings>) | Builds the vector outline of a glyph run as a fillable/strokeable GraphicsPath, with the text baseline at baselineOrigin (user-space units) and glyphs advancing left-to-right. Unlike DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>) (a single-color PDF text show), the returned path can be filled with a gradient/pattern brush or stroked - used by the SVG renderer for gradient/pattern fill, stroke, and <textPath> on text. Returns null when the font produces no glyph outlines (a CID-keyed CFF font, or a bitmap font, neither of which this engine can decode outlines from) - the caller’s cue to fall back to DrawString(string, Font, PaintColor, PaintPoint, Size, double, FontPalette, Nullable<ShapeSettings>). |
| MeasureString(string, Font, double, int, double) | Measure the width of string under max width restriction calculating the number of characters that can fit and the width those characters take. Not relevant for platforms that don’t render HTML on UI element. |
| MeasureString(string, Font, Nullable<ShapeSettings>) | Measure the width and height of string str when drawn on device context HDC using the given font font. |
| PopAntiAlias() | Undoes the latest PushAntiAlias(bool). Does nothing when there is none to undo. |
| PopBlendMode() | Pop the most recent PushBlendMode(PaintBlendMode), restoring the prior blend mode. |
| PopClip() | Pop the latest clip push. |
| PopTransform() | Pop the most recent PushTransform(Matrix3x2), restoring the prior transform state. |
| PushAntiAlias(bool) | Turns anti-aliasing of the shapes drawn from now on on or off, until the matching PopAntiAlias(). Calls nest: each PushAntiAlias is undone by one PopAntiAlias, like PushClip(Rect) and PushTransform(Matrix3x2). This replaces the untyped SetAntiAliasSmoothingMode()/ReturnPreviousSmoothingMode(object) pair, which it is built on by default. |
| PushBlendMode(PaintBlendMode) | Push a PDF blend mode for subsequent drawing, saving state so it can later be undone by PopBlendMode() (stack-shaped, same convention as PushClip(Rect)/ PopClip()). Used e.g. to composite a fill against the content underneath it via Difference for a true color inversion (CSS outline-color: invert). |
| PushClip(GraphicsPath) | Push the clipping region of this Graphics to intersection of the current clip and the given (possibly non-rectangular) path. Used for SVG clip-path, where the clip region isn’t necessarily axis-aligned. |
| PushClip(Rect) | Push the clipping region of this Graphics to interception of current clipping rectangle and the given rectangle. |
| PushClipExclude(Rect) | Push the clipping region of this Graphics to exclude the given rectangle from the current clipping rectangle. |
| PushTransform(Matrix3x2) | Push a 2D affine transform (composed before/with the current transform), saving state so it can later be undone by PopTransform(). Used to implement the CSS transform property. |
| ReturnPreviousSmoothingMode(object) | Return to previous smooth mode before anti-alias was set as returned from SetAntiAliasSmoothingMode(). |
| Save(Stream, string, EncoderOptions) | Encodes this canvas’s pixels into stream in any format PeachImage supports (PNG, JPEG, WebP, ...), for a standalone canvas built through CreateCanvas(int, int, double). |
| SaveAsync(Stream, string, EncoderOptions, CancellationToken) | Encodes this canvas’s pixels into stream in any format PeachImage supports (PNG, JPEG, WebP, ...), for a standalone canvas built through CreateCanvas(int, int, double). |
| SetAntiAliasSmoothingMode() | Set the graphics smooth mode to use anti-alias. Use ReturnPreviousSmoothingMode(object) to return back the mode used. |
| ToPixelBuffer() | This canvas’s pixels as a premultiplied-RGBA8 PixelBuffer - the same contract GetPixels() uses, so a caller can sample a finished standalone canvas exactly the way it would sample any other Image. No copy: it wraps the surface’s own backing array. |