11// Copyright (c) Six Labors.
22// Licensed under the Six Labors Split License.
33
4+ using SixLabors . ImageSharp . Drawing . Text ;
5+
46namespace SixLabors . ImageSharp . Drawing . Processing ;
57
68/// <summary>
@@ -14,7 +16,7 @@ public static class FillPathCollectionExtensions
1416 /// <param name="source">The source image processing context.</param>
1517 /// <param name="options">The graphics options.</param>
1618 /// <param name="brush">The brush.</param>
17- /// <param name="paths">The shapes .</param>
19+ /// <param name="paths">The collection of paths .</param>
1820 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
1921 public static IImageProcessingContext Fill (
2022 this IImageProcessingContext source ,
@@ -30,12 +32,120 @@ public static IImageProcessingContext Fill(
3032 return source ;
3133 }
3234
35+ /// <summary>
36+ /// Flood fills the image in the shape of the provided glyphs with the specified brush and pen.
37+ /// For multi-layer glyphs, a heuristic is used to decide whether to fill or stroke each layer.
38+ /// </summary>
39+ /// <param name="source">The source image processing context.</param>
40+ /// <param name="options">The graphics options.</param>
41+ /// <param name="brush">The brush.</param>
42+ /// <param name="pen">The pen.</param>
43+ /// <param name="paths">The collection of glyph paths.</param>
44+ /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
45+ public static IImageProcessingContext Fill (
46+ this IImageProcessingContext source ,
47+ DrawingOptions options ,
48+ Brush brush ,
49+ Pen pen ,
50+ IReadOnlyList < GlyphPathCollection > paths )
51+ => source . Fill ( options , brush , pen , paths , static ( gp , layer , path ) =>
52+ {
53+ if ( layer . Kind == GlyphLayerKind . Decoration )
54+ {
55+ // Decorations (underlines, strikethroughs, etc) are always filled.
56+ return true ;
57+ }
58+
59+ if ( layer . Kind == GlyphLayerKind . Glyph )
60+ {
61+ // Standard glyph layers are filled by default.
62+ return true ;
63+ }
64+
65+ // Default heuristic: stroke "background-like" layers (large coverage), fill others.
66+ // Use the bounding box area as an approximation of the glyph area as it is cheaper to compute.
67+ float glyphArea = gp . Bounds . Width * gp . Bounds . Height ;
68+ float layerArea = path . ComputeArea ( ) ;
69+
70+ if ( layerArea <= 0 || glyphArea <= 0 )
71+ {
72+ return false ; // degenerate glyph, don't fill
73+ }
74+
75+ float coverage = layerArea / glyphArea ;
76+
77+ // <50% coverage, fill. Otherwise, stroke.
78+ return coverage < 0.50F ;
79+ } ) ;
80+
81+ /// <summary>
82+ /// Flood fills the image in the shape of the provided glyphs with the specified brush and pen.
83+ /// For multi-layer glyphs, a heuristic is used to decide whether to fill or stroke each layer.
84+ /// </summary>
85+ /// <param name="source">The source image processing context.</param>
86+ /// <param name="options">The graphics options.</param>
87+ /// <param name="brush">The brush.</param>
88+ /// <param name="pen">The pen.</param>
89+ /// <param name="paths">The collection of glyph paths.</param>
90+ /// <param name="shouldFillLayer">
91+ /// A function that decides whether to fill or stroke a given layer within a multi-layer (painted) glyph.
92+ /// </param>
93+ /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
94+ public static IImageProcessingContext Fill (
95+ this IImageProcessingContext source ,
96+ DrawingOptions options ,
97+ Brush brush ,
98+ Pen pen ,
99+ IReadOnlyList < GlyphPathCollection > paths ,
100+ Func < GlyphPathCollection , GlyphLayerInfo , IPath , bool > shouldFillLayer )
101+ {
102+ foreach ( GlyphPathCollection gp in paths )
103+ {
104+ if ( gp . LayerCount == 0 )
105+ {
106+ continue ;
107+ }
108+
109+ if ( gp . LayerCount == 1 )
110+ {
111+ // Single-layer glyph: just fill with the supplied brush.
112+ source . Fill ( options , brush , gp . Paths ) ;
113+ continue ;
114+ }
115+
116+ // Multi-layer: decide per layer whether to fill or stroke.
117+ for ( int i = 0 ; i < gp . Layers . Count ; i ++ )
118+ {
119+ GlyphLayerInfo layer = gp . Layers [ i ] ;
120+ IPath path = gp . PathList [ i ] ;
121+
122+ if ( shouldFillLayer ( gp , layer , path ) )
123+ {
124+ // Respect the layer's fill rule if different to the drawing options.
125+ DrawingOptions o = options . CloneOrReturnForRules (
126+ layer . IntersectionRule ,
127+ layer . PixelAlphaCompositionMode ,
128+ layer . PixelColorBlendingMode ) ;
129+
130+ source . Fill ( o , brush , path ) ;
131+ }
132+ else
133+ {
134+ // Outline only to preserve interior detail.
135+ source . Draw ( options , pen , path ) ;
136+ }
137+ }
138+ }
139+
140+ return source ;
141+ }
142+
33143 /// <summary>
34144 /// Flood fills the image in the shape of the provided polygon with the specified brush.
35145 /// </summary>
36146 /// <param name="source">The source image processing context.</param>
37147 /// <param name="brush">The brush.</param>
38- /// <param name="paths">The paths.</param>
148+ /// <param name="paths">The collection of paths.</param>
39149 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
40150 public static IImageProcessingContext Fill (
41151 this IImageProcessingContext source ,
@@ -44,7 +154,23 @@ public static IImageProcessingContext Fill(
44154 source . Fill ( source . GetDrawingOptions ( ) , brush , paths ) ;
45155
46156 /// <summary>
47- /// Flood fills the image in the shape of the provided polygon with the specified brush.
157+ /// Flood fills the image in the shape of the provided glyphs with the specified brush and pen.
158+ /// For multi-layer glyphs, a heuristic is used to decide whether to fill or stroke each layer.
159+ /// </summary>
160+ /// <param name="source">The source image processing context.</param>
161+ /// <param name="brush">The brush.</param>
162+ /// <param name="pen">The pen.</param>
163+ /// <param name="paths">The collection of glyph paths.</param>
164+ /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
165+ public static IImageProcessingContext Fill (
166+ this IImageProcessingContext source ,
167+ Brush brush ,
168+ Pen pen ,
169+ IReadOnlyList < GlyphPathCollection > paths ) =>
170+ source . Fill ( source . GetDrawingOptions ( ) , brush , pen , paths ) ;
171+
172+ /// <summary>
173+ /// Flood fills the image in the shape of the provided polygon with the specified color.
48174 /// </summary>
49175 /// <param name="source">The source image processing context.</param>
50176 /// <param name="options">The options.</param>
@@ -59,15 +185,29 @@ public static IImageProcessingContext Fill(
59185 source . Fill ( options , new SolidBrush ( color ) , paths ) ;
60186
61187 /// <summary>
62- /// Flood fills the image in the shape of the provided polygon with the specified brush .
188+ /// Flood fills the image in the shape of the provided polygon with the specified color .
63189 /// </summary>
64190 /// <param name="source">The source image processing context.</param>
65191 /// <param name="color">The color.</param>
66- /// <param name="paths">The paths.</param>
192+ /// <param name="paths">The collection of paths.</param>
67193 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
68194 public static IImageProcessingContext Fill (
69195 this IImageProcessingContext source ,
70196 Color color ,
71197 IPathCollection paths ) =>
72198 source . Fill ( new SolidBrush ( color ) , paths ) ;
199+
200+ /// <summary>
201+ /// Flood fills the image in the shape of the provided glyphs with the specified color.
202+ /// For multi-layer glyphs, a heuristic is used to decide whether to fill or stroke each layer.
203+ /// </summary>
204+ /// <param name="source">The source image processing context.</param>
205+ /// <param name="color">The color.</param>
206+ /// <param name="paths">The collection of glyph paths.</param>
207+ /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
208+ public static IImageProcessingContext Fill (
209+ this IImageProcessingContext source ,
210+ Color color ,
211+ IReadOnlyList < GlyphPathCollection > paths ) =>
212+ source . Fill ( new SolidBrush ( color ) , new SolidPen ( color ) , paths ) ;
73213}
0 commit comments