freetype-commit
[Top][All Lists]
Advanced

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

[freetype2] master 2b1d556: [sdf] Use 8 bits for final SDF output instea


From: Werner Lemberg
Subject: [freetype2] master 2b1d556: [sdf] Use 8 bits for final SDF output instead of 16bits.
Date: Mon, 7 Jun 2021 23:00:11 -0400 (EDT)

branch: master
commit 2b1d5562694ef29f1819e1a5046226076a0deede
Author: Anuj Verma <anujv@iitbhilai.ac.in>
Commit: Anuj Verma <anujv@iitbhilai.ac.in>

    [sdf] Use 8 bits for final SDF output instead of 16bits.
    
    Since 8-bits is enough to represent SDF data we no longer require
    16-bits for  this purpose. Also, we now normalize the output data
    to use the entire 8-bit range efficiently. For example: if we use
    3.5 format with a spread of 1 we basically only use the starting
    5-bits. By normalizing we can use the entire 8-bit range.
    
    * include/freetype/freetype.h (FT_Render_Mode): Updated description
    for `FT_RENDER_MODE_SDF` regarding this change.
    
    * include/freetype/ftimage.h (FT_Pixel_Mode): Removed
    `FT_PIXEL_MODE_GRAY16` since no longer required.
    
    * include/freetype/fttypes.h (FT_F6Dot10): Removed since no longer
    required.
    
    * src/sdf/ftsdfrend.c (ft_sdf_render, ft_bsdf_render): Allocate 8-bit
    bitmap instead of 16-bit buffer.
    
    * src/sdf/ftsdfcommon.h (map_fixed_to_sdf): Added function to convert
    16.16 distance value to our desired format.
    
    * src/sdf/ftsdf.c (sdf_generate_with_overlaps,
    sdf_generate_bounding_box): Use the new `map_fixed_to_sdf` function
    and also use 8-bit output buffer.
    
    * src/sdf/ftbsdf.c (finalize_sdf): Output to a 8-bit buffer instead
    of 16-bit buffer.
---
 ChangeLog                   | 32 ++++++++++++++++++++
 include/freetype/freetype.h | 35 +++++++++++++++++++---
 include/freetype/ftimage.h  |  8 -----
 include/freetype/fttypes.h  | 12 --------
 src/sdf/ftbsdf.c            | 29 +++++++++---------
 src/sdf/ftsdf.c             | 64 ++++++++++++++++++++++++----------------
 src/sdf/ftsdfcommon.h       | 71 ++++++++++++++++++++++++++++++++++++++++++++-
 src/sdf/ftsdfrend.c         | 12 ++++----
 8 files changed, 192 insertions(+), 71 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0d0e8f3..09f468f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2021-06-08  Anuj Verma  <anujv@iitbhilai.ac.in>
+
+       [sdf] Use 8 bits for final SDF output instead of 16bits.
+
+       Since 8-bits is enough to represent SDF data we no longer require
+       16-bits for  this purpose. Also, we now normalize the output data
+       to use the entire 8-bit range efficiently. For example: if we use
+       3.5 format with a spread of 1 we basically only use the starting
+       5-bits. By normalizing we can use the entire 8-bit range.
+
+       * include/freetype/freetype.h (FT_Render_Mode): Updated description
+       for `FT_RENDER_MODE_SDF` regarding this change.
+
+       * include/freetype/ftimage.h (FT_Pixel_Mode): Removed
+       `FT_PIXEL_MODE_GRAY16` since no longer required.
+
+       * include/freetype/fttypes.h (FT_F6Dot10): Removed since no longer
+       required.
+
+       * src/sdf/ftsdfrend.c (ft_sdf_render, ft_bsdf_render): Allocate 8-bit
+       bitmap instead of 16-bit buffer.
+
+       * src/sdf/ftsdfcommon.h (map_fixed_to_sdf): Added function to convert
+       16.16 distance value to our desired format.
+
+       * src/sdf/ftsdf.c (sdf_generate_with_overlaps,
+       sdf_generate_bounding_box): Use the new `map_fixed_to_sdf` function
+       and also use 8-bit output buffer.
+
+       * src/sdf/ftbsdf.c (finalize_sdf): Output to a 8-bit buffer instead
+       of 16-bit buffer.
+
 2021-06-02  Ben Wagner  <bungeman@chromium.org>
            Werner Lemberg  <wl@gnu.org>
 
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index 03438b5..ebb129f 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3302,19 +3302,46 @@ FT_BEGIN_HEADER
    *     pixels and use the @FT_PIXEL_MODE_LCD_V mode.
    *
    *   FT_RENDER_MODE_SDF ::
-   *     This mode corresponds to 16-bit signed distance fields (SDF)
+   *     This mode corresponds to 8-bit signed distance fields (SDF)
    *     bitmaps.  Each pixel in a SDF bitmap contains information about the
    *     nearest edge of the glyph outline.  The distances are calculated
    *     from the center of the pixel and are positive if they are filled by
-   *     the outline (i.e., inside the outline) and negative otherwise.  The
-   *     output bitmap buffer is represented as 6.10 fixed-point values; use
-   *     @FT_F6Dot10 and convert accordingly.
+   *     the outline (i.e., inside the outline) and negative otherwise. Check
+   *     the note below on how to convert the output values to usable data.
    *
    * @note:
    *   The selected render mode only affects vector glyphs of a font.
    *   Embedded bitmaps often have a different pixel mode like
    *   @FT_PIXEL_MODE_MONO.  You can use @FT_Bitmap_Convert to transform them
    *   into 8-bit pixmaps.
+   *
+   *   For @FT_RENDER_MODE_SDF output bitmap buffer contains normalized
+   *   distance values that are packed into unsigned 8-bit buffer.  To get
+   *   pixel values in floating point representation use the following
+   *   conversion:
+   *
+   *   ```
+   *   <load glyph and render using @FT_RENDER_MODE_SDF, then use the
+   *    output buffer as follows>
+   *
+   *   ...
+   *   FT_Byte buffer = glyph->bitmap->buffer;
+   *
+   *   for pixel in buffer
+   *   {
+   *     <`sd` is the signed distance and spread is the current `spread`,
+   *      the default spread is 2 and can be changed>
+   *
+   *     float sd = (float)pixel - 128.0f;
+   *
+   *     <convert the to pixel values>
+   *
+   *     sd = ( sd / 128.0f ) * spread;
+   *
+   *     <store `sd` in a buffer or use as required>
+   *   }
+   *
+   *   ```
    */
   typedef enum  FT_Render_Mode_
   {
diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h
index e3cc68f..66a8b89 100644
--- a/include/freetype/ftimage.h
+++ b/include/freetype/ftimage.h
@@ -157,13 +157,6 @@ FT_BEGIN_HEADER
    *     in font files according to the OpenType specification.  We haven't
    *     found a single font using this format, however.
    *
-   *   FT_PIXEL_MODE_GRAY16 ::
-   *     A 16-bit per pixel bitmap used to represent signed distances in a
-   *     signed distance field bitmap as needed by @FT_RENDER_MODE_SDF.
-   *     Values are represented in a 6.10 fixed-point format; this means
-   *     that you have to divide by 1024 to get the actual data generated by
-   *     the SDF rasterizers.
-   *
    *   FT_PIXEL_MODE_LCD ::
    *     An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    *     for display on LCD displays; the bitmap is three times wider than
@@ -194,7 +187,6 @@ FT_BEGIN_HEADER
     FT_PIXEL_MODE_LCD,
     FT_PIXEL_MODE_LCD_V,
     FT_PIXEL_MODE_BGRA,
-    FT_PIXEL_MODE_GRAY16,
 
     FT_PIXEL_MODE_MAX      /* do not remove */
 
diff --git a/include/freetype/fttypes.h b/include/freetype/fttypes.h
index 3e4a474..d5ca1c4 100644
--- a/include/freetype/fttypes.h
+++ b/include/freetype/fttypes.h
@@ -78,7 +78,6 @@ FT_BEGIN_HEADER
    *   FT_FWord
    *   FT_UFWord
    *   FT_F2Dot14
-   *   FT_F6Dot10
    *   FT_UnitVector
    *   FT_F26Dot6
    *   FT_Data
@@ -268,17 +267,6 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @type:
-   *   FT_F6Dot10
-   *
-   * @description:
-   *   A signed 6.10 fixed-point type used for signed distance values.
-   */
-  typedef signed short  FT_F6Dot10;
-
-
-  /**************************************************************************
-   *
-   * @type:
    *   FT_F26Dot6
    *
    * @description:
diff --git a/src/sdf/ftbsdf.c b/src/sdf/ftbsdf.c
index 97e0438..659e0de 100644
--- a/src/sdf/ftbsdf.c
+++ b/src/sdf/ftbsdf.c
@@ -1092,12 +1092,12 @@
   finalize_sdf( BSDF_Worker*      worker,
                 const FT_Bitmap*  target )
   {
-    FT_Error  error = FT_Err_Ok;
+    FT_Error      error = FT_Err_Ok;
 
-    FT_Int    w, r;
-    FT_Int    i, j;
-    FT_6D10*  t_buffer;
-    FT_16D16  spread;
+    FT_Int        w, r;
+    FT_Int        i, j;
+    FT_SDFFormat* t_buffer;
+    FT_16D16      spread;
 
 
     if ( !worker || !target )
@@ -1108,7 +1108,7 @@
 
     w        = (int)target->width;
     r        = (int)target->rows;
-    t_buffer = (FT_6D10*)target->buffer;
+    t_buffer = (FT_SDFFormat*)target->buffer;
 
     if ( w != worker->width ||
          r != worker->rows  )
@@ -1128,10 +1128,10 @@
     {
       for ( i = 0; i < w; i++ )
       {
-        FT_Int    index;
-        FT_16D16  dist;
-        FT_6D10   final_dist;
-        FT_Char   sign;
+        FT_Int       index;
+        FT_16D16     dist;
+        FT_SDFFormat final_dist;
+        FT_Char      sign;
 
 
         index = j * w + i;
@@ -1144,10 +1144,6 @@
         dist = square_root( dist );
 #endif
 
-        /* convert from 16.16 to 6.10 */
-        dist      /= 64;
-        final_dist = (FT_6D10)(dist & 0x0000FFFF);
-
         /* We assume that if the pixel is inside a contour */
         /* its coverage value must be > 127.               */
         sign = worker->distance_map[index].alpha < 127 ? -1 : 1;
@@ -1156,7 +1152,10 @@
         if ( worker->params.flip_sign )
           sign = -sign;
 
-        t_buffer[index] = final_dist * sign;
+        /* concatenate from 16.16 to appropriate format */
+        final_dist = map_fixed_to_sdf( dist * sign, spread );
+
+        t_buffer[index] = final_dist;
       }
     }
 
diff --git a/src/sdf/ftsdf.c b/src/sdf/ftsdf.c
index f9b16bc..335b800 100644
--- a/src/sdf/ftsdf.c
+++ b/src/sdf/ftsdf.c
@@ -2897,6 +2897,10 @@
   /* `sdf_generate' is not used at the moment */
 #if 0
 
+  #error "DO NOT USE THIS!"
+  #error "The function still output 16-bit data which might cause memory"
+  #error "corruption.  If required I will add this later."
+
   /**************************************************************************
    *
    * @Function:
@@ -3193,7 +3197,7 @@
     FT_Int  sp_sq;            /* max value to check   */
 
     SDF_Contour*  contours;   /* list of all contours */
-    FT_Short*     buffer;     /* the bitmap buffer    */
+    FT_SDFFormat* buffer;     /* the bitmap buffer    */
 
     /* This buffer has the same size in indices as the    */
     /* bitmap buffer.  When we check a pixel position for */
@@ -3202,6 +3206,8 @@
     /* and also determine the signs properly.             */
     SDF_Signed_Distance*  dists = NULL;
 
+    const FT_16D16 fixed_spread = FT_INT_16D16( spread );
+
 
     if ( !shape || !bitmap )
     {
@@ -3229,12 +3235,12 @@
     contours = shape->contours;
     width    = (FT_Int)bitmap->width;
     rows     = (FT_Int)bitmap->rows;
-    buffer   = (FT_Short*)bitmap->buffer;
+    buffer   = (FT_SDFFormat*)bitmap->buffer;
 
     if ( USE_SQUARED_DISTANCES )
-      sp_sq = (FT_Int)FT_INT_16D16( spread * spread );
+      sp_sq = fixed_spread * fixed_spread;
     else
-      sp_sq = (FT_Int)FT_INT_16D16( spread );
+      sp_sq = fixed_spread;
 
     if ( width == 0 || rows == 0 )
     {
@@ -3347,21 +3353,23 @@
         /* if the pixel is not set                     */
         /* its shortest distance is more than `spread` */
         if ( dists[index].sign == 0 )
-          dists[index].distance = FT_INT_16D16( spread );
+          dists[index].distance = fixed_spread;
         else
           current_sign = dists[index].sign;
 
         /* clamp the values */
-        if ( dists[index].distance > (FT_Int)FT_INT_16D16( spread ) )
-          dists[index].distance = FT_INT_16D16( spread );
-
-        /* convert from 16.16 to 6.10 */
-        dists[index].distance /= 64;
-
-        if ( internal_params.flip_sign )
-          buffer[index] = (FT_Short)dists[index].distance * -current_sign;
-        else
-          buffer[index] = (FT_Short)dists[index].distance * current_sign;
+        if ( dists[index].distance > fixed_spread )
+          dists[index].distance = fixed_spread;
+
+        /* flip sign if required */
+        dists[index].distance *= internal_params.flip_sign ?
+                                   -current_sign :
+                                    current_sign;
+
+        /* concatenate to appropriate format */
+        buffer[index] = map_fixed_to_sdf(
+                          dists[index].distance,
+                          fixed_spread );
       }
     }
 
@@ -3498,9 +3506,9 @@
     SDF_Contour*  head;              /* head of the contour list      */
     SDF_Shape     temp_shape;        /* temporary shape               */
 
-    FT_Memory  memory;               /* to allocate memory            */
-    FT_6D10*   t;                    /* target bitmap buffer          */
-    FT_Bool    flip_sign;            /* filp sign?                    */
+    FT_Memory     memory;            /* to allocate memory            */
+    FT_SDFFormat* t;                 /* target bitmap buffer          */
+    FT_Bool       flip_sign;         /* filp sign?                    */
 
     /* orientation of all the separate contours */
     SDF_Contour_Orientation*  orientations;
@@ -3621,7 +3629,7 @@
     shape->contours = head;
 
     /* cast the output bitmap buffer */
-    t = (FT_6D10*)bitmap->buffer;
+    t = (FT_SDFFormat*)bitmap->buffer;
 
     /* Iterate over all pixels and combine all separate    */
     /* contours.  These are the rules for combining:       */
@@ -3636,18 +3644,18 @@
     {
       for ( i = 0; i < width; i++ )
       {
-        FT_Int   id = j * width + i;         /* index of current pixel    */
-        FT_Int   c;                          /* contour iterator          */
+        FT_Int   id = j * width + i;     /* index of current pixel    */
+        FT_Int   c;                      /* contour iterator          */
 
-        FT_6D10  val_c  = SHRT_MIN;          /* max clockwise value       */
-        FT_6D10  val_ac = SHRT_MAX;          /* min counter-clockwise val */
+        FT_SDFFormat val_c  = 0;         /* max clockwise value       */
+        FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */
 
 
         /* iterate through all the contours */
         for ( c = 0; c < num_contours; c++ )
         {
           /* current contour value */
-          FT_6D10  temp = ((FT_6D10*)bitmaps[c].buffer)[id];
+          FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id];
 
 
           if ( orientations[c] == SDF_ORIENTATION_CW )
@@ -3658,7 +3666,10 @@
 
         /* Finally find the smaller of the two and assign to output. */
         /* Also apply `flip_sign` if set.                            */
-        t[id] = FT_MIN( val_c, val_ac ) * ( flip_sign ? -1 : 1 );
+        t[id] = FT_MIN( val_c, val_ac );
+
+        if ( flip_sign )
+          t[id] = invert_sign( t[id] );
       }
     }
 
@@ -3681,6 +3692,9 @@
       }
     }
 
+    /* restore the `flip_sign` property */
+    internal_params.flip_sign = flip_sign;
+
     return error;
   }
 
diff --git a/src/sdf/ftsdfcommon.h b/src/sdf/ftsdfcommon.h
index 925a4dc..7ce49bb 100644
--- a/src/sdf/ftsdfcommon.h
+++ b/src/sdf/ftsdfcommon.h
@@ -115,7 +115,7 @@ FT_BEGIN_HEADER
 
   typedef FT_Fixed  FT_16D16;      /* 16.16 fixed-point representation  */
   typedef FT_Fixed  FT_26D6;       /* 26.6 fixed-point representation   */
-  typedef FT_Short  FT_6D10;       /* 6.10 fixed-point representation   */
+  typedef FT_Byte   FT_SDFFormat;  /* format to represent SDF data      */
 
   typedef FT_BBox   FT_CBox;       /* control box of a curve            */
 
@@ -162,6 +162,75 @@ FT_BEGIN_HEADER
     return (FT_16D16)q;
   }
 
+  /**************************************************************************
+   *
+   * format and sign manipulating functions
+   *
+   */
+
+  /*
+   * Convert 16.16 fixed point value to the desired output format.
+   * In this case we reduce 16.16 fixed point value to normalized
+   * 8-bit values.
+   * The `max_value` in the parameter is the maximum value in the
+   * distance field map and is equal to the spread.  We normalize
+   * the distances using this value instead of computing the maximum
+   * value for the entire bitmap.
+   * You can use this function to map the 16.16 signed values to any
+   * format required. Do note that the output buffer is 8-bit, so only
+   * use 8-bit format for `FT_SDFFormat`, or increase buffer size in
+   * `ftsdfrend.c`.
+   */
+  static FT_SDFFormat
+  map_fixed_to_sdf( FT_16D16 dist, FT_16D16 max_value )
+  {
+    FT_SDFFormat out;
+    FT_16D16     udist;
+
+
+    /* normalize the distance values */
+    dist = FT_DivFix( dist, max_value );
+
+    udist = dist < 0 ? -dist : dist;
+
+    /* Reduce the distance values to 8 bits, +1/-1 in   */
+    /* 16.16 takes the 16th bit.  So we right shift the */
+    /* number by 9 to make it fit in the 7 bit range.   */
+    /* 1 bit is reserved for the sign.                  */
+    udist >>= 9;
+
+    /* Since char can only store max positive value */
+    /* of 127 we need to make sure it does not wrap */
+    /* around and give a negative value.            */
+    if ( dist > 0 && udist > 127 )
+      udist = 127;
+    if ( dist < 0 && udist > 128 )
+      udist = 128;
+
+    /* Output the data; negative values are from [0, 127] and positive    */
+    /* from [128, 255].  One important thing is that negative values      */
+    /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */
+    /* More on that in `freetype.h` near `FT_RENDER_MODE_SDF`             */
+    out = dist < 0 ? 128 - (FT_SDFFormat)udist :
+                     (FT_SDFFormat)udist + 128;
+    return out;
+  }
+
+  /*
+   * Invert the signed distance packed into the corresponding format.
+   * So if the values are negative they will become positive in the
+   * chosen format.
+   *
+   * [Note]: This function should only be used after converting the
+   *         16.16 signed distance values to `FT_SDFFormat`, if that
+   *         conversion has not been done, then simply invert the sign
+   *         and use the above function to pack the values.
+   */
+  static FT_SDFFormat
+  invert_sign( FT_SDFFormat dist ) {
+    return 255 - dist;
+  }
+
 
 FT_END_HEADER
 
diff --git a/src/sdf/ftsdfrend.c b/src/sdf/ftsdfrend.c
index fa2fd6d..aedc5bb 100644
--- a/src/sdf/ftsdfrend.c
+++ b/src/sdf/ftsdfrend.c
@@ -313,9 +313,9 @@
     bitmap->width += x_pad * 2;
 
     /* ignore the pitch, pixel mode and set custom */
-    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY16;
-    bitmap->pitch      = (int)( bitmap->width * 2 );
-    bitmap->num_grays  = 65535;
+    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+    bitmap->pitch      = (int)( bitmap->width );
+    bitmap->num_grays  = 255;
 
     /* allocate new buffer */
     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
@@ -524,9 +524,9 @@
     target.width = bitmap->width + x_pad * 2;
 
     /* set up the target bitmap */
-    target.pixel_mode = FT_PIXEL_MODE_GRAY16;
-    target.pitch      = (int)( target.width * 2 );
-    target.num_grays  = 65535;
+    target.pixel_mode = FT_PIXEL_MODE_GRAY;
+    target.pitch      = (int)( target.width );
+    target.num_grays  = 255;
 
     if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
       goto Exit;



reply via email to

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