Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .reviewmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,46 @@ reviews:
- "test/DemaConsulting.CanvasNet.Tests/Drawing/ScanlineRasterizerTests.cs" # gradient rasterization tests
- "test/DemaConsulting.CanvasNet.Tests/Canvas/SurfaceTests.cs" # per-pixel-color CompositeOverSpan tests

# CanvasNet-Fonts Review (one per subsystem)
- id: CanvasNet-Fonts
title: Review that CanvasNet Fonts Subsystem Implementation is Correct
context:
- "docs/design/canvas-net.md"
- "docs/reqstream/canvas-net.yaml"
paths:
- "docs/reqstream/canvas-net/fonts.yaml" # subsystem requirements
- "docs/design/canvas-net/fonts.md" # subsystem design
- "docs/verification/canvas-net/fonts.md" # subsystem verification
- "test/DemaConsulting.CanvasNet.Tests/TestSupport/SyntheticFontBuilder.cs" # shared test helper

# CanvasNet-Fonts-TrueTypeFont Review (one per unit)
- id: CanvasNet-Fonts-TrueTypeFont
title: Review that CanvasNet Fonts TrueTypeFont Implementation is Correct
context:
- "docs/design/canvas-net.md"
- "docs/reqstream/canvas-net.yaml"
- "docs/design/canvas-net/fonts.md"
- "docs/reqstream/canvas-net/fonts.yaml"
paths:
- "docs/reqstream/canvas-net/fonts/true-type-font.yaml" # unit requirements
- "docs/design/canvas-net/fonts/true-type-font.md" # unit design
- "docs/verification/canvas-net/fonts/true-type-font.md" # unit verification
- "src/DemaConsulting.CanvasNet/Fonts/TrueTypeFont.cs" # unit source
- "src/DemaConsulting.CanvasNet/Fonts/SfntContainer.cs" # internal helper source
- "src/DemaConsulting.CanvasNet/Fonts/CmapTable.cs" # internal helper source
- "src/DemaConsulting.CanvasNet/Fonts/GlyfLocaReader.cs" # internal helper source
- "src/DemaConsulting.CanvasNet/Fonts/HmtxHheaReader.cs" # internal helper source
- "src/DemaConsulting.CanvasNet/Fonts/KernTable.cs" # internal helper source
- "src/DemaConsulting.CanvasNet/Fonts/NamespaceDoc.cs" # Fonts namespace documentation
- "test/DemaConsulting.CanvasNet.Tests/Fonts/SfntContainerTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/CmapTableTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/GlyfLocaReaderTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/HmtxHheaReaderTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/KernTableTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/TrueTypeFontTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/Fonts/TrueTypeFontRealFontIntegrationTests.cs" # unit tests
- "test/DemaConsulting.CanvasNet.Tests/TestSupport/SyntheticFontBuilder.cs" # shared test helper

# OTS-BuildMark Review (one per OTS item)
- id: OTS-BuildMark
title: Review that BuildMark Provides Required Functionality
Expand Down
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# CanvasNet

<!-- cspell:ignore SFNT codepoints -->
<!-- IMPORTANT: All links in this file must be absolute URLs.
This file is distributed in packages and relative links will not resolve. -->

Expand Down Expand Up @@ -37,6 +38,8 @@ image operations using `Span<T>`, and supports independent-copy cropping for loa
fillable outline geometry and render them through the same antialiased fill pipeline
- 🌅 **Gradient Paint** - Fill a path with a linear or two-circle radial gradient color ramp,
with pad/reflect/repeat spread and premultiplied-alpha color interpolation
- 🔤 **TrueType Fonts** - Load glyph-based TrueType SFNT fonts, map Unicode codepoints to glyph
indices, extract glyph outlines as `Geometry.Path`, and query advance widths and basic kerning
- ⚡ **Span-Based** - Fast, allocation-conscious row and pixel access
- 🔄 **Multi-Target** - Supports .NET 8, 9, and 10
- 📦 **NuGet Ready** - Easy integration via NuGet package
Expand Down Expand Up @@ -161,6 +164,56 @@ var gradient = new LinearGradient(
PathFiller.Fill(canvas, rectangle, gradient, FillRule.NonZero, 1f); // red-to-blue ramp
```

Loading a TrueType font and filling a glyph outline:

```csharp
using DemaConsulting.CanvasNet.Canvas;
using DemaConsulting.CanvasNet.Drawing;
using DemaConsulting.CanvasNet.Fonts;
using DemaConsulting.CanvasNet.Geometry;
using System.Numerics;

static Path TransformGlyph(Path glyph, float scale, float baselineY)
{
var builder = new PathBuilder();

Vector2 ToCanvas(Vector2 point) => new(point.X * scale, baselineY - point.Y * scale);

foreach (var subpath in glyph.Subpaths)
{
builder.MoveTo(ToCanvas(subpath.Start));
foreach (var command in subpath.Commands)
{
switch (command.Type)
{
case PathCommandType.LineTo:
builder.LineTo(ToCanvas(command.EndPoint));
break;
case PathCommandType.QuadraticBezierTo:
builder.QuadraticBezierTo(
ToCanvas(command.Control1),
ToCanvas(command.EndPoint));
break;
case PathCommandType.Close:
builder.Close();
break;
}
}
}

return builder.Build();
}

var font = TrueTypeFont.Load("font.ttf");
var glyphIndex = font.GetGlyphIndex('A');
var glyphOutline = font.GetGlyphOutline(glyphIndex); // raw font-design-unit coordinates (Y up)
var scale = 48f / font.UnitsPerEm;
var canvasOutline = TransformGlyph(glyphOutline, scale, baselineY: 56f);

var surface = new Surface(64, 64);
PathFiller.Fill(surface, canvasOutline, new Rgba32(20, 120, 255, 255));
```

## Building

```pwsh
Expand Down
Loading
Loading