The correct patch file.
On Fri, 5 Oct 2018 03:50:14 +0900, Byeongsik Jeon <[email protected]> wrote:
Hi.
Sorry. missed the attachments.
[PATCH 1/2] Improve FT_Outline_Embolden for the unintended arfifacts problem
(#45597):
- The mathematical background is clearly added to the patch.
- Some error situation processing is done naturally during the formula
processing.
- At the bauhaus_256px_win7_ie9.png file, you can see that Microsoft's embolden
did not properly inhibits the unintended artifacts. This patch will handled
properly.
- Because the strength value also affects the unintended artifacts creation, the
strength formula of [PATCH 2/2] should also be used.
[PATCH 2/2] Improve FT_GlyphSlot_Embolden to match more with Microsoft Windows
looks:
- The DirectWrite font rendering appears to have deleted the strange
transformation from the existing GDI. For reference, the GDI matching code has
not been deleted.
- "Advance" values are important to match text layouts.
- The strength value must be an integer pixel value to inhibits blurring the
hinted outline.
More details are commented on the patch.
Thanks.
---
src/base/ftoutln.c | 172 +++++++++++++++++++++++++++++++++++++++++++++
src/base/ftsynth.c | 92 ++++++++++++++++++------
2 files changed, 242 insertions(+), 22 deletions(-)
_______________________________________________
Freetype-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/freetype-devel
>From d66801cc5cdac37faa92d18ba7214f2828b14ee2 Mon Sep 17 00:00:00 2001
From: Byeongsik Jeon <[email protected]>
Date: Fri, 5 Oct 2018 02:14:42 +0900
Subject: [PATCH 1/2] Improve FT_Outline_Embolden for the unintended arfifacts
problem (#45597).
To: freetype-devel <[email protected]>
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
>From 4b27437b7f455cd0da0892b33357bf52e2eaa42d Mon Sep 17 00:00:00 2001
From: Byeongsik Jeon <[email protected]>
Date: Fri, 5 Oct 2018 02:19:02 +0900
Subject: [PATCH 2/2] Improve FT_GlyphSlot_Embolden to match more with
Microsoft Windows looks.
To: freetype-devel <[email protected]>
---
src/base/ftsynth.c | 92 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 70 insertions(+), 22 deletions(-)
diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c
index ec7b93510..7d599c118 100644
--- a/src/base/ftsynth.c
+++ b/src/base/ftsynth.c
@@ -22,6 +22,7 @@
#include FT_INTERNAL_OBJECTS_H
#include FT_OUTLINE_H
#include FT_BITMAP_H
+#include FT_TRUETYPE_TABLES_H
/**************************************************************************
@@ -92,7 +93,7 @@
FT_Library library;
FT_Face face;
FT_Error error;
- FT_Pos xstr, ystr;
+ FT_Pos xstr, ystr, ppem;
if ( !slot )
@@ -105,22 +106,68 @@
slot->format != FT_GLYPH_FORMAT_BITMAP )
return;
- /* some reasonable strength */
- xstr = FT_MulFix( face->units_per_EM,
- face->size->metrics.y_scale ) / 24;
- ystr = xstr;
+ /* the value that matches the MS Windows embolden looks.
+ the larger strength value, the more unintended artifacts increase.
+ using the integer pixel strength inhibits the blurred outlines.
+ */
+ ppem = face->size->metrics.y_ppem;
+ ystr = (( ppem - 1 ) / 50 ) << 6;
+ xstr = ystr + 64;
+
+ /* match to the MS.
+ the important factor that reduces the text layout difference. */
+ slot->metrics.horiAdvance += 1 << 6;
+ slot->linearHoriAdvance += 1 << 16;
if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
- FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
+ {
+ error = FT_Outline_EmboldenXY( &slot->outline, xstr, ystr);
+ if ( error )
+ return;
+#if 1
+ /* MS Windows DirectWrite looks. */
+
+ slot->metrics.width += xstr;
+ slot->metrics.height += ystr;
+ slot->metrics.horiBearingY += ystr;
+#else
+ /* MS Windows GDI looks. */
+ if ( ystr != 0 ) /* ppem > 50px */
+ {
+ TT_Header *head_table;
+ FT_Matrix scale = { 1 << 16, 0, 0, 1 << 16 };
+
+ /* Elboldened EM square box only increase the width of one pixel.
+ ( ppem, ppem ) -> embolden -> scale -> ( ppem + 1px, ppem )
+
+ ( ppem + xstr ) * scale.xx = ppem + 1px
+ ( ppem + ystr ) * scale.yy = ppem
+ */
+ ppem = ppem << 6;
+ scale.xx = FT_MulDiv( 1 << 16, ppem + 64, ppem + xstr );
+ scale.yy = FT_MulDiv( 1 << 16, ppem , ppem + ystr );
+ FT_Outline_Transform( &slot->outline, &scale );
+
+ /* Undocumented behavior in truetype spec. */
+ head_table = FT_Get_Sfnt_Table( face, FT_SFNT_HEAD );
+ if ( head_table && head_table->Flags & ( 1 << 4 | 1 << 2 ) )
+ slot->metrics.horiAdvance =
+ FT_MulFix( slot->metrics.horiAdvance, scale.xx );
+ }
+
+ {
+ FT_BBox bbox;
+ FT_Outline_Get_CBox( &slot->outline, &bbox );
+ slot->metrics.width = bbox.xMax - bbox.xMin;
+ slot->metrics.height = bbox.yMax - bbox.yMin;
+ slot->metrics.horiBearingX = bbox.xMin;
+ slot->metrics.horiBearingY = bbox.yMax;
+ }
+#endif
+ }
else /* slot->format == FT_GLYPH_FORMAT_BITMAP */
{
- /* round to full pixels */
- xstr &= ~63;
- if ( xstr == 0 )
- xstr = 1 << 6;
- ystr &= ~63;
-
/*
* XXX: overflow check for 16-bit system, for compatibility
* with FT_GlyphSlot_Embolden() since FreeType 2.1.10.
@@ -140,23 +187,24 @@
error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr );
if ( error )
return;
+
+ slot->metrics.width += xstr;
+ slot->metrics.height += ystr;
+ slot->metrics.horiBearingY += ystr;
+
+ /* XXX: 16-bit overflow case must be excluded before here */
+ slot->bitmap_top += (FT_Int)( ystr >> 6 );
}
+ /* XXX: FT_Set_Transform, FT_GlyphSlot_Embolden combination can
+ produce different results from intention. Recommend the
+ FT_Outline_Transform and a manual metrics modification.
+ */
if ( slot->advance.x )
slot->advance.x += xstr;
if ( slot->advance.y )
slot->advance.y += ystr;
-
- slot->metrics.width += xstr;
- slot->metrics.height += ystr;
- slot->metrics.horiAdvance += xstr;
- slot->metrics.vertAdvance += ystr;
- slot->metrics.horiBearingY += ystr;
-
- /* XXX: 16-bit overflow case must be excluded before here */
- if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
- slot->bitmap_top += (FT_Int)( ystr >> 6 );
}
--
2.19.0
_______________________________________________
Freetype-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/freetype-devel