freetype-commit
[Top][All Lists]
Advanced

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

[Git][freetype/freetype][master] 3 commits: * include/freetype/freetype.


From: Werner Lemberg (@wl)
Subject: [Git][freetype/freetype][master] 3 commits: * include/freetype/freetype.h: Improve SDF documentation.
Date: Sat, 05 Mar 2022 16:07:47 +0000

Werner Lemberg pushed to branch master at FreeType / FreeType

Commits:

3 changed files:

Changes:

  • include/freetype/freetype.h
    ... ... @@ -3409,6 +3409,44 @@ FT_BEGIN_HEADER
    3409 3409
        *   }
    
    3410 3410
        *
    
    3411 3411
        *   ```
    
    3412
    +   *
    
    3413
    +   *   FreeType has two rasterizers for generating SDF, namely:
    
    3414
    +   *
    
    3415
    +   *   1. `sdf` for generating SDF directly from glyph's outline, and
    
    3416
    +   *
    
    3417
    +   *   2. `bsdf` for generating SDF from rasterized bitmaps.
    
    3418
    +   *
    
    3419
    +   *   Depending on the glyph type (i.e., outline or bitmap), one of the two
    
    3420
    +   *   rasterizers is chosen at runtime and used for generating SDFs.  To
    
    3421
    +   *   force the use of `bsdf` you should render the glyph with any of the
    
    3422
    +   *   FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and
    
    3423
    +   *   then re-render with `FT_RENDER_MODE_SDF`.
    
    3424
    +   *
    
    3425
    +   *   There are some issues with stability and possible failures of the SDF
    
    3426
    +   *   renderers (specifically `sdf`).
    
    3427
    +   *
    
    3428
    +   *   1. The `sdf` rasterizer is sensitive to really small features (e.g.,
    
    3429
    +   *      sharp turns that are less than 1~pixel) and imperfections in the
    
    3430
    +   *      glyph's outline, causing artifacts in the final output.
    
    3431
    +   *
    
    3432
    +   *   2. The `sdf` rasterizer has limited support for handling intersecting
    
    3433
    +   *      contours and *cannot* handle self-intersecting contours whatsoever.
    
    3434
    +   *      Self-intersection happens when a single connected contour intersect
    
    3435
    +   *      itself at some point; having these in your font definitely pose a
    
    3436
    +   *      problem to the rasterizer and cause artifacts, too.
    
    3437
    +   *
    
    3438
    +   *   3. Generating SDF for really small glyphs may result in undesirable
    
    3439
    +   *      output; the pixel grid (which stores distance information) becomes
    
    3440
    +   *      too coarse.
    
    3441
    +   *
    
    3442
    +   *   4. Since the output buffer is normalized, precision at smaller spreads
    
    3443
    +   *      is greater than precision at larger spread values because the
    
    3444
    +   *      output range of [0..255] gets mapped to a smaller SDF range.  A
    
    3445
    +   *      spread of~2 should be sufficient in most cases.
    
    3446
    +   *
    
    3447
    +   *   Points (1) and (2) can be avoided by using the `bsdf` rasterizer,
    
    3448
    +   *   which is more stable than the `sdf` rasterizer in general.
    
    3449
    +   *
    
    3412 3450
        */
    
    3413 3451
       typedef enum  FT_Render_Mode_
    
    3414 3452
       {
    

  • src/sdf/ftsdf.c
    ... ... @@ -738,6 +738,18 @@
    738 738
     
    
    739 739
         contour = shape->contours;
    
    740 740
     
    
    741
    +    /* If the control point coincides with any of the end points */
    
    742
    +    /* then it is a line and should be treated as one to avoid   */
    
    743
    +    /* unnecessary complexity later in the algorithm.            */
    
    744
    +    if ( ( contour->last_pos.x == control_1->x &&
    
    745
    +           contour->last_pos.y == control_1->y ) ||
    
    746
    +         ( control_1->x == to->x &&
    
    747
    +           control_1->y == to->y )               )
    
    748
    +    {
    
    749
    +      sdf_line_to( to, user );
    
    750
    +      goto Exit;
    
    751
    +    }
    
    752
    +
    
    741 753
         FT_CALL( sdf_edge_new( memory, &edge ) );
    
    742 754
     
    
    743 755
         edge->edge_type = SDF_EDGE_CONIC;
    
    ... ... @@ -764,9 +776,9 @@
    764 776
                     const FT_26D6_Vec*  to,
    
    765 777
                     void*               user )
    
    766 778
       {
    
    767
    -    SDF_Shape*    shape    = ( SDF_Shape* )user;
    
    768
    -    SDF_Edge*     edge     = NULL;
    
    769
    -    SDF_Contour*  contour  = NULL;
    
    779
    +    SDF_Shape*    shape   = ( SDF_Shape* )user;
    
    780
    +    SDF_Edge*     edge    = NULL;
    
    781
    +    SDF_Contour*  contour = NULL;
    
    770 782
     
    
    771 783
         FT_Error   error  = FT_Err_Ok;
    
    772 784
         FT_Memory  memory = shape->memory;
    
    ... ... @@ -1137,23 +1149,38 @@
    1137 1149
                        FT_Int        max_splits,
    
    1138 1150
                        SDF_Edge**    out )
    
    1139 1151
       {
    
    1140
    -    FT_Error     error = FT_Err_Ok;
    
    1141
    -    FT_26D6_Vec  cpos[7];
    
    1142
    -    SDF_Edge*    left,*  right;
    
    1152
    +    FT_Error       error = FT_Err_Ok;
    
    1153
    +    FT_26D6_Vec    cpos[7];
    
    1154
    +    SDF_Edge*      left, *right;
    
    1155
    +    const FT_26D6  threshold = ONE_PIXEL / 4;
    
    1143 1156
     
    
    1144 1157
     
    
    1145
    -    if ( !memory || !out  )
    
    1158
    +    if ( !memory || !out )
    
    1146 1159
         {
    
    1147 1160
           error = FT_THROW( Invalid_Argument );
    
    1148 1161
           goto Exit;
    
    1149 1162
         }
    
    1150 1163
     
    
    1151
    -    /* split the conic */
    
    1164
    +    /* split the cubic */
    
    1152 1165
         cpos[0] = control_points[0];
    
    1153 1166
         cpos[1] = control_points[1];
    
    1154 1167
         cpos[2] = control_points[2];
    
    1155 1168
         cpos[3] = control_points[3];
    
    1156 1169
     
    
    1170
    +    /* If the segment is flat enough we won't get any benefit by */
    
    1171
    +    /* splitting it further, so we can just stop splitting.      */
    
    1172
    +    /*                                                           */
    
    1173
    +    /* Check the deviation of the Bezier curve and stop if it is */
    
    1174
    +    /* smaller than the pre-defined `threshold` value.           */
    
    1175
    +    if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold &&
    
    1176
    +         FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold &&
    
    1177
    +         FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold &&
    
    1178
    +         FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold )
    
    1179
    +    {
    
    1180
    +      split_cubic( cpos );
    
    1181
    +      goto Append;
    
    1182
    +    }
    
    1183
    +
    
    1157 1184
         split_cubic( cpos );
    
    1158 1185
     
    
    1159 1186
         /* If max number of splits is done */
    
    ... ... @@ -1250,13 +1277,32 @@
    1250 1277
               /* Subdivide the curve and add it to the list. */
    
    1251 1278
               {
    
    1252 1279
                 FT_26D6_Vec  ctrls[3];
    
    1280
    +            FT_26D6      dx, dy;
    
    1281
    +            FT_UInt      num_splits;
    
    1253 1282
     
    
    1254 1283
     
    
    1255 1284
                 ctrls[0] = edge->start_pos;
    
    1256 1285
                 ctrls[1] = edge->control_a;
    
    1257 1286
                 ctrls[2] = edge->end_pos;
    
    1258 1287
     
    
    1259
    -            error = split_sdf_conic( memory, ctrls, 32, &new_edges );
    
    1288
    +            dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x );
    
    1289
    +            dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y );
    
    1290
    +            if ( dx < dy )
    
    1291
    +              dx = dy;
    
    1292
    +
    
    1293
    +            /* Calculate the number of necessary bisections.  Each      */
    
    1294
    +            /* bisection causes a four-fold reduction of the deviation, */
    
    1295
    +            /* hence we bisect the Bezier curve until the deviation     */
    
    1296
    +            /* becomes less than 1/8th of a pixel.  For more details    */
    
    1297
    +            /* check file `ftgrays.c`.                                  */
    
    1298
    +            num_splits = 1;
    
    1299
    +            while ( dx > ONE_PIXEL / 8 )
    
    1300
    +            {
    
    1301
    +              dx         >>= 2;
    
    1302
    +              num_splits <<= 1;
    
    1303
    +            }
    
    1304
    +
    
    1305
    +            error = split_sdf_conic( memory, ctrls, num_splits, &new_edges );
    
    1260 1306
               }
    
    1261 1307
               break;
    
    1262 1308
     
    
    ... ... @@ -3286,6 +3332,7 @@
    3286 3332
                 FT_26D6_Vec          grid_point = zero_vector;
    
    3287 3333
                 SDF_Signed_Distance  dist       = max_sdf;
    
    3288 3334
                 FT_UInt              index      = 0;
    
    3335
    +            FT_16D16             diff       = 0;
    
    3289 3336
     
    
    3290 3337
     
    
    3291 3338
                 if ( x < 0 || x >= width )
    
    ... ... @@ -3313,7 +3360,7 @@
    3313 3360
                 if ( dist.distance > sp_sq )
    
    3314 3361
                   continue;
    
    3315 3362
     
    
    3316
    -            /* square_root the values and fit in a 6.10 fixed-point */
    
    3363
    +            /* take the square root of the distance if required */
    
    3317 3364
                 if ( USE_SQUARED_DISTANCES )
    
    3318 3365
                   dist.distance = square_root( dist.distance );
    
    3319 3366
     
    
    ... ... @@ -3325,11 +3372,15 @@
    3325 3372
                 /* check whether the pixel is set or not */
    
    3326 3373
                 if ( dists[index].sign == 0 )
    
    3327 3374
                   dists[index] = dist;
    
    3328
    -            else if ( dists[index].distance > dist.distance )
    
    3329
    -              dists[index] = dist;
    
    3330
    -            else if ( FT_ABS( dists[index].distance - dist.distance )
    
    3331
    -                        < CORNER_CHECK_EPSILON )
    
    3332
    -              dists[index] = resolve_corner( dists[index], dist );
    
    3375
    +            else
    
    3376
    +            {
    
    3377
    +              diff = FT_ABS( dists[index].distance - dist.distance );
    
    3378
    +
    
    3379
    +              if ( diff <= CORNER_CHECK_EPSILON )
    
    3380
    +                dists[index] = resolve_corner( dists[index], dist );
    
    3381
    +              else if ( dists[index].distance > dist.distance )
    
    3382
    +                dists[index] = dist;
    
    3383
    +            }
    
    3333 3384
               }
    
    3334 3385
             }
    
    3335 3386
     
    

  • src/sdf/ftsdfcommon.h
    ... ... @@ -48,6 +48,8 @@ FT_BEGIN_HEADER
    48 48
     #define MIN_SPREAD      2
    
    49 49
       /* maximum spread supported by the renderer */
    
    50 50
     #define MAX_SPREAD      32
    
    51
    +  /* pixel size in 26.6 */
    
    52
    +#define ONE_PIXEL       ( 1 << 6 )
    
    51 53
     
    
    52 54
     
    
    53 55
       /**************************************************************************
    


  • reply via email to

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