freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft-devel] [PATCH 1/2] Improve FT_Outline_Embolden for the unintended ar


From: Byeongsik Jeon
Subject: [ft-devel] [PATCH 1/2] Improve FT_Outline_Embolden for the unintended arfifacts problem (#45597).
Date: Fri, 5 Oct 2018 03:45:54 +0900
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.0

FreeType-Bugs: https://savannah.nongnu.org/bugs/?45596
---
 src/base/ftoutln.c | 172 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 172 insertions(+)

diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index 85a469737..97d6f2c08 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -892,6 +892,7 @@
    /* documentation is in ftoutln.h */
 +#if 0
   FT_EXPORT_DEF( FT_Error )
   FT_Outline_EmboldenXY( FT_Outline*  outline,
                          FT_Pos       xstrength,
@@ -1023,7 +1024,178 @@
      return FT_Err_Ok;
   }
+#endif
+
+
+  /*
+    --->----------------->------------>-----------> shift
+                A            /|\                  /
+                          di  |                  /
+                              |                 /
+                              |                /
+   ->------------>-----------> ----   do      /
+                     in      /     -----     /
+                            /           --->/
+                           /               /
+                      out /               /
+                         /               /
+                        /             B /
+                       /               /
+                      /               /
+                    |/_             |/_
+
+  assume one strength:
+    ( strength.x, strength.y ) = ( strength, strength )
+
+  normalized vector i, o :
+    i =  in /  |in| = ( i.x, i.y ) , i.x ^2 + i.y ^2 = 1
+    o = out / |out| = ( o.x, o.y ) , o.x ^2 + o.y ^2 = 1
+
+  vector di, do :
+    -90 degree rotate(truetype outline) from in, out vector.
+    and scale to strength.  |di| = |do| = strength.
+
+    di = ( -i.y * strength, i.x * strength )
+    do = ( -o.y * strength, o.x * strength )
+
+  line equation of A, B:
+    i.y * ( x - di.x ) = i.x * ( y - di.y )
+    o.y * ( x - do.x ) = o.x * ( y - do.y )
+
+  intersection of A, B == shift.
+
+  two coalition equation solution:
+    det = i.y * o.x - i.x * o.y , det != 0
+    shift.x = strength * ( i.x - o.x ) / det
+    shift.y = strength * ( i.y - o.y ) / det
+
+  two strength case:
+    introduced equation with a reasonable radical attempt.
+
+    det = i.y * o.x - i.x * o.y  , det != 0
+    shift.x = strength.x * ( i.x - o.x ) / det
+    shift.y = strength.y * ( i.y - o.y ) / det
+
+    This simple expression produces good results.
+    There is a more rigorous expression, but it is more complicated.
+
+  For postscript outline: ( -shift.x, -shift.y )
+
+  det == 0 case:
+     i.x == i.y == 0, or
+     o.x == o.y == 0, or
+     abs( gradient i ) == abs( gradient o )
+
+   */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_EmboldenXY( FT_Outline* outline,
+                         FT_Pos      xstrength,
+                         FT_Pos      ystrength )
+  {
+    FT_Vector*      points;
+    FT_Orientation  orientation;
+    FT_Vector       strength, shift, in, out, anchor;
+    FT_Int          c, n_first, n_last, n_head, n_prev, n_tail, n_anchor;
+    FT_Fixed        det;
+
+    if ( !outline ) return FT_THROW( Invalid_Outline );
+
+    strength.x = xstrength / 2;
+    strength.y = ystrength / 2;
+    if ( strength.x == 0 && strength.y == 0 ) return FT_Err_Ok;
+
+    orientation = FT_Outline_Get_Orientation( outline );
+    if ( orientation == FT_ORIENTATION_NONE )
+    {
+      if ( outline->n_contours ) return FT_THROW( Invalid_Argument );
+      else return FT_Err_Ok;
+    }
+
+    points = outline->points;
 +    for ( c = n_first = 0; c < outline->n_contours; c++, n_first = n_last + 1 
)
+    {
+      n_prev = n_last = outline->contours[c];
+      n_anchor = n_tail = -1;
+      in.x = in.y = anchor.x = anchor.y = 0;
+
+      /* Find the first corner type segment */
+      for ( n_head = n_first; n_head <= n_last; n_head++)
+      {
+        out.x = points[n_head].x - points[n_prev].x;
+        out.y = points[n_head].y - points[n_prev].y;
+        FT_Vector_NormLen( &out ); /* normalize */
+
+        det = FT_MulFix( in.y, out.x ) - FT_MulFix( in.x, out.y );
+        if ( det != 0 )
+        {
+          anchor = in = out;
+          n_anchor = n_tail = n_head;
+          break;
+        }
+
+        in = out;
+        n_prev = n_head;
+      }
+      if ( n_anchor == -1 ) continue;
+
+      do
+      {
+        n_prev = n_head;
+        n_head = ( n_head < n_last )? n_head + 1 : n_first;
+        if ( n_head != n_anchor )
+        {
+          out.x = points[n_head].x - points[n_prev].x;
+          out.y = points[n_head].y - points[n_prev].y;
+          FT_Vector_NormLen( &out ); /* normalize */
+        }
+        else
+          out = anchor;
+
+        /* The shift vector is only calculated from the corner type segment.
+           Other points -- zero length segment, forward straight segment,
+           wrong forward and backward mixed straight segment -- use this
+           shift vector as it is. Note the "in.x * out.y - in.y * out.x".
+
+           wrong forward and backward mixed straight segment:
+             one of the causes of unintended artifact generation.
+         */
+        det = FT_MulFix( in.y, out.x ) - FT_MulFix( in.x, out.y );
+        if ( det == 0 ) continue;
+
+        shift.x = FT_MulDiv( strength.x, in.x - out.x, det );
+        shift.y = FT_MulDiv( strength.y, in.y - out.y, det );
+
+        /* The large shift value creates a cross point, which appears
+           as one of the artifacts. The shift value limitation inhibits
+           the occurrence of artifacts. */
+        shift.x = FT_MAX( FT_MIN( shift.x, strength.x ), -strength.x );
+        shift.y = FT_MAX( FT_MIN( shift.y, strength.y ), -strength.y );
+
+        if ( orientation != FT_ORIENTATION_TRUETYPE )
+        {
+          shift.x = -shift.x;
+          shift.y = -shift.y;
+        }
+
+        while ( n_tail != n_head )
+        {
+          /* left and bottom side are unchanged.
+             grid aligned when using integer pixel {x,y}strength. */
+          points[n_tail].x += strength.x + shift.x;
+          points[n_tail].y += strength.y + shift.y;
+
+          n_tail = ( n_tail < n_last )? n_tail + 1 : n_first;
+        }
+
+        in = out;
+
+      } while ( n_head != n_anchor );
+    }
+
+    return FT_Err_Ok;
+  }
    /* documentation is in ftoutln.h */
 -- 2.19.0





reply via email to

[Prev in Thread] Current Thread [Next in Thread]