1+ using System ;
2+ using System . Linq ;
3+
4+ namespace LunarLabs . Fonts {
5+ public static class DistanceFieldUtils {
6+ /*
7+ Computes a distance field transform of a high resolution binary source channel and returns the result as a low resolution channel.
8+
9+ scale_down : The amount the source channel will be scaled down.
10+ A value of 8 means the destination image will be 1/8th the size of the source
11+
12+ spread: The spread in pixels before the distance field clamps to (zero/one).
13+ The valueis specified in units of the destination image. The spread in the source image will be spread*scale_down.
14+ */
15+ public static GlyphBitmap CreateDistanceField ( GlyphBitmap source , int scale , float spread ) {
16+ var result = new GlyphBitmap ( source . Width / scale , source . Height / scale ) ;
17+
18+ var values = source . Pixels . Select ( x => ( x / 255.0f ) - 0.5f ) . ToArray ( ) ;
19+
20+ for ( int y = 0 ; y < result . Height ; y ++ ) {
21+ for ( int x = 0 ; x < result . Width ; x ++ ) {
22+ var sd = SignedDistance ( values , source . Width , source . Height , x * scale , y * scale , spread ) ;
23+ var n = ( sd + spread ) / ( spread * 2.0f ) ;
24+
25+ var c = ( byte ) ( n * 255 ) ;
26+ var offset = x + y * result . Width ;
27+ result . Pixels [ offset ] = c ;
28+ }
29+ }
30+
31+ return result ;
32+ }
33+
34+ private static float SignedDistance ( float [ ] source , int w , int h , int cx , int cy , float clamp ) {
35+ var cd = source [ cx + cy * w ] ;
36+
37+ int min_x = cx - ( int ) ( Math . Floor ( clamp ) - 1 ) ;
38+ if ( min_x < 0 ) {
39+ min_x = 0 ;
40+ }
41+
42+ int max_x = cx + ( int ) ( Math . Floor ( clamp ) + 1 ) ;
43+ if ( max_x >= w ) {
44+ max_x = w - 1 ;
45+ }
46+
47+ float distance = clamp ;
48+ for ( int dy = 0 ; dy < ( int ) ( Math . Floor ( clamp ) + 1 ) ; dy ++ ) {
49+ if ( dy > distance ) {
50+ continue ;
51+ }
52+
53+ if ( cy - dy >= 0 ) {
54+ int y1 = cy - dy ;
55+ for ( int x = min_x ; x <= max_x ; x ++ ) {
56+ if ( x - cx > distance ) {
57+ continue ;
58+ }
59+
60+ float d = source [ x + y1 * w ] ;
61+ if ( cd * d < 0 ) {
62+ float d2 = ( y1 - cy ) * ( y1 - cy ) + ( x - cx ) * ( x - cx ) ;
63+ if ( d2 < ( distance * distance ) ) { distance = ( float ) Math . Sqrt ( d2 ) ; }
64+ }
65+ }
66+ }
67+
68+ if ( dy != 0 && cy + dy < h ) {
69+ int y2 = cy + dy ;
70+
71+ for ( int x = min_x ; x < max_x ; x ++ ) {
72+ if ( x - cx > distance ) {
73+ continue ;
74+ }
75+
76+ float d = source [ x + y2 * w ] ;
77+ if ( cd * d < 0 ) {
78+ float d2 = ( y2 - cy ) * ( y2 - cy ) + ( x - cx ) * ( x - cx ) ;
79+ if ( d2 < distance * distance ) {
80+ distance = ( float ) Math . Sqrt ( d2 ) ;
81+ }
82+ }
83+ }
84+ }
85+
86+
87+ }
88+
89+ if ( cd > 0 )
90+ return distance ;
91+ else
92+ return - distance ;
93+ }
94+ }
95+ }
0 commit comments