Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ image operations using `Span<T>`, and supports independent-copy cropping for loa
- 🖨️ **TIFF Codec** - Load/save 8-bit RGB/RGBA/Grayscale TIFF files
- 🗜️ **JPEG Codec** - Load baseline/progressive; save baseline JPEG
- 🎞️ **GIF Codec** - Decode-only load of first GIF frame; `GetInfo` reports the true frame count
- 📐 **SVG Codec** - Rasterize a common SVG subset to a surface
- 📐 **SVG Codec** - Rasterize a common SVG subset, including markers/filters and weight/style-aware
font matching, to a surface
- 🔍 **Header-Only Probing** - `GetInfo` reads headers without decoding pixels (GIF excepted)
- 🖌️ **Path Filling** - Antialiased nonzero/even-odd fill of vector paths
- 🖊️ **Stroke-to-Fill** - Convert stroked paths into fillable outlines
Expand Down
276 changes: 252 additions & 24 deletions docs/design/canvas-net/codecs/svg-codec.md

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions docs/reqstream/canvas-net.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,55 @@ sections:
tests:
- CanvasNet_SystemIntegration_SvgLoad_ReturnsExpectedPixel

- id: CanvasNet-Lib-SvgMarkerRendering
title: >-
The library shall rasterize marker elements referenced from a line, polyline, polygon,
or path element's marker-start/marker-mid/marker-end presentation attributes, at the
correct vertex, orientation, and scale, and shall reject an unbounded
marker-referencing-marker reference cycle the same way an unbounded use reference cycle
is already rejected.
tags: [system]
justification: |
Connector arrowheads and other per-vertex line decorations built via SVG's marker
mechanism are common in real-world diagrams and flowcharts; callers need these to
render rather than silently vanish, with the same bounded, predictable error-handling
behavior already established for use reference cycles.
children:
- CanvasNet-Codecs-SvgMarkerRendering
tests:
- SvgCodec_Load_MarkerEndOnLine_RendersArrowheadPastLineEnd
- SvgCodec_Load_MarkerStartMidEndOnPolyline_RendersDistinctMarkersAtEachVertex
- SvgCodec_Load_ArrowMarkersFixture_RendersArrowheadPastLineEnd
- SvgCodec_Load_MarkerSelfReferenceCycle_ThrowsInvalidDataException
- SvgCodec_Load_MarkerTwoElementReferenceCycle_ThrowsInvalidDataException

- id: CanvasNet-Lib-SvgFilterRendering
title: >-
The library shall rasterize filter elements referenced from any directly renderable
shape or text element's filter presentation attribute, evaluating a
feFlood/feGaussianBlur/feOffset/feComposite/feMerge primitive chain against that
element's own content within a bounded-size temporary offscreen surface, and shall
tolerate a dangling filter reference, an unsupported primitive type, and a
pathologically large filter region or blur radius without failing or hanging.
tags: [system]
justification: |
Solid-color halo/glow backgrounds behind text labels, built via SVG's filter
mechanism, are common in real-world diagrams (the reported real-world bug this feature
fixes: SvgRenderer's own midpoint line labels use exactly this pattern, and previously
lost their halo entirely, causing label text to overlap the line beneath it); callers
need this common pattern to render rather than silently vanish, with the same bounded,
predictable resource-safety behavior already established for this codec's other
reference-following and work-budget concerns.
children:
- CanvasNet-Codecs-SvgFilterRendering
tests:
- SvgCodec_Load_FeFloodFilter_RendersSolidColorBehindElement
- SvgCodec_Load_FeFloodFeGaussianBlurFeCompositeFilter_RendersBlurredHaloBehindContent
- SvgCodec_Load_LabelHaloFixture_RendersWhiteHaloBehindLineMidpointLabel
- SvgCodec_Load_FilterDanglingReference_RendersElementNormally
- SvgCodec_Load_FilterPathologicallyLargeRegion_SkipsFilterRatherThanUnboundedAllocation
- SvgCodec_Load_FilterPathologicallyLargeBlurStdDeviation_ClampsRatherThanUnboundedWork

- id: CanvasNet-Lib-SvgViewBoxFitting
title: >-
The library shall fit an SVG document's intrinsic viewBox into the requested raster size
Expand Down Expand Up @@ -1017,6 +1066,28 @@ sections:
- SvgCodec_Load_TextFontFamilyNoMatch_SkipsSilentlyWithoutThrowing
- SvgCodec_Load_TextFontFamilyCommaSeparatedList_MatchesFirstAvailableFont

- id: CanvasNet-Lib-SvgFontWeightStyleMatching
title: >-
The library shall register more than one font face (varying in font-weight/font-style)
per SVG text font-family and select the closest-matching registered face for each text
element's own cascaded font-weight/font-style, while preserving the pre-existing
single-font-per-family Load overload's behavior unchanged.
tags: [system]
justification: |
Callers commonly need bold titles and italic keywords rendered with the correct
distinct font face, rather than every element in a family always resolving to the
same single font regardless of its requested weight/style; existing callers of the
single-font-per-family overload must observe no behavior change.
children:
- CanvasNet-Codecs-SvgFontWeightStyleMatching
tests:
- SvgCodec_Load_TextFontWeightBold_SelectsBoldFaceOverNormalFace
- SvgCodec_Load_TextFontStyleItalic_SelectsItalicFaceOverNormalFace
- SvgCodec_Load_TextFontWeightAndStyleCombined_SelectsExactMatchAmongThreeFaces
- SvgCodec_Load_GroupFontWeightInheritance_AppliesToChildTextWithoutOwnFontWeight
- SvgCodec_Load_GroupFontStyleInheritance_AppliesToChildTextWithoutOwnFontStyle
- SvgCodec_Load_TextLegacySingleFontOverload_IgnoresRequestedWeightAndStyle

- id: CanvasNet-Lib-SvgValidationNull
title: >-
The library shall reject null stream/path arguments to SVG Load and GetInfo operations
Expand Down
73 changes: 73 additions & 0 deletions docs/reqstream/canvas-net/codecs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,55 @@ sections:
- CanvasNet_SystemIntegration_SvgLoad_ReturnsExpectedPixel
- SvgCodec_Load_NonPositiveWidth_PropagatesSurfaceArgumentOutOfRangeException

- id: CanvasNet-Codecs-SvgMarkerRendering
title: >-
The Codecs subsystem shall rasterize marker elements referenced from a line,
polyline, polygon, or path element's marker-start/marker-mid/marker-end
presentation attributes, at the correct vertex, orientation, and scale, and shall
reject an unbounded marker-referencing-marker reference cycle the same way an
unbounded use reference cycle is already rejected.
justification: |
Connector arrowheads and other per-vertex line decorations built via SVG's marker
mechanism are common in real-world diagrams and flowcharts; callers need these to
render rather than silently vanish, with the same bounded, predictable
error-handling behavior already established for use reference cycles.
children:
- CanvasNet-Codecs-SvgCodec-MarkerRendering
- CanvasNet-Codecs-SvgCodec-MarkerReferenceCycle
tests:
- SvgCodec_Load_MarkerEndOnLine_RendersArrowheadPastLineEnd
- SvgCodec_Load_MarkerStartMidEndOnPolyline_RendersDistinctMarkersAtEachVertex
- SvgCodec_Load_ArrowMarkersFixture_RendersArrowheadPastLineEnd
- SvgCodec_Load_MarkerSelfReferenceCycle_ThrowsInvalidDataException
- SvgCodec_Load_MarkerTwoElementReferenceCycle_ThrowsInvalidDataException

- id: CanvasNet-Codecs-SvgFilterRendering
title: >-
The Codecs subsystem shall rasterize filter elements referenced from any directly
renderable shape or text element's filter presentation attribute, evaluating a
feFlood/feGaussianBlur/feOffset/feComposite/feMerge primitive chain against that
element's own content within a bounded-size temporary offscreen surface, and shall
tolerate a dangling filter reference, an unsupported primitive type, and a
pathologically large filter region or blur radius without failing or hanging.
justification: |
Solid-color halo/glow backgrounds behind text labels, built via SVG's filter
mechanism, are common in real-world diagrams (the reported real-world bug this
feature fixes: SvgRenderer's own midpoint line labels use exactly this pattern, and
previously lost their halo entirely, causing label text to overlap the line
beneath it); callers need this common pattern to render rather than silently
vanish, with the same bounded, predictable resource-safety behavior already
established for this codec's other reference-following and work-budget concerns.
children:
- CanvasNet-Codecs-SvgCodec-FilterRendering
- CanvasNet-Codecs-SvgCodec-FilterResourceSafety
tests:
- SvgCodec_Load_FeFloodFilter_RendersSolidColorBehindElement
- SvgCodec_Load_FeFloodFeGaussianBlurFeCompositeFilter_RendersBlurredHaloBehindContent
- SvgCodec_Load_LabelHaloFixture_RendersWhiteHaloBehindLineMidpointLabel
- SvgCodec_Load_FilterDanglingReference_RendersElementNormally
- SvgCodec_Load_FilterPathologicallyLargeRegion_SkipsFilterRatherThanUnboundedAllocation
- SvgCodec_Load_FilterPathologicallyLargeBlurStdDeviation_ClampsRatherThanUnboundedWork

- id: CanvasNet-Codecs-SvgViewBoxFitting
title: >-
The Codecs subsystem shall fit an SVG document's intrinsic viewBox into the
Expand Down Expand Up @@ -982,6 +1031,30 @@ sections:
- SvgCodec_Load_TextFontFamilyNoMatch_SkipsSilentlyWithoutThrowing
- SvgCodec_Load_TextFontFamilyCommaSeparatedList_MatchesFirstAvailableFont

- id: CanvasNet-Codecs-SvgFontWeightStyleMatching
title: >-
The Codecs subsystem shall register more than one font face (varying in
font-weight/font-style) per SVG text font-family and select the closest-matching
registered face for each text element's own cascaded font-weight/font-style,
while preserving the pre-existing single-font-per-family Load overload's behavior
unchanged.
justification: |
Callers commonly need bold titles and italic keywords rendered with the correct
distinct font face, rather than every element in a family always resolving to the
same single font regardless of its requested weight/style; existing callers of the
single-font-per-family overload must observe no behavior change.
children:
- CanvasNet-Codecs-SvgCodec-FontWeightStyleCascade
- CanvasNet-Codecs-SvgCodec-FontFaceMatching
- CanvasNet-Codecs-SvgCodec-LegacySingleFontCompatibility
tests:
- SvgCodec_Load_TextFontWeightBold_SelectsBoldFaceOverNormalFace
- SvgCodec_Load_TextFontStyleItalic_SelectsItalicFaceOverNormalFace
- SvgCodec_Load_TextFontWeightAndStyleCombined_SelectsExactMatchAmongThreeFaces
- SvgCodec_Load_GroupFontWeightInheritance_AppliesToChildTextWithoutOwnFontWeight
- SvgCodec_Load_GroupFontStyleInheritance_AppliesToChildTextWithoutOwnFontStyle
- SvgCodec_Load_TextLegacySingleFontOverload_IgnoresRequestedWeightAndStyle

- id: CanvasNet-Codecs-SvgValidationNull
title: >-
The Codecs subsystem shall reject null stream/path arguments to SVG Load and
Expand Down
Loading
Loading