summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnuj Verma <anujv@iitbhilai.ac.in>2021-06-08 08:29:34 +0530
committerAnuj Verma <anujv@iitbhilai.ac.in>2021-06-08 08:29:34 +0530
commit2b1d5562694ef29f1819e1a5046226076a0deede (patch)
treebc11550808d139017f7ea41d6ac860f118c5e86e
parent2a6665a4c04913bbe088af48db4eb293d498043c (diff)
downloadfreetype2-2b1d5562694ef29f1819e1a5046226076a0deede.tar.gz
[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.
-rw-r--r--ChangeLog32
-rw-r--r--include/freetype/freetype.h35
-rw-r--r--include/freetype/ftimage.h8
-rw-r--r--include/freetype/fttypes.h12
-rw-r--r--src/sdf/ftbsdf.c29
-rw-r--r--src/sdf/ftsdf.c64
-rw-r--r--src/sdf/ftsdfcommon.h71
-rw-r--r--src/sdf/ftsdfrend.c12
8 files changed, 192 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 0d0e8f3bc..09f468fa0 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 03438b531..ebb129f71 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 e3cc68f6c..66a8b89aa 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 3e4a474bd..d5ca1c4f4 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 97e043835..659e0de89 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 f9b16bc6f..335b800e5 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 925a4dc3e..7ce49bb98 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 fa2fd6d27..aedc5bbec 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;