misc/libfreetype/src/base/ftlcdfil.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftlcdfil.c                                                             */
       
     4 /*                                                                         */
       
     5 /*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2006, 2008, 2009, 2010 by                                    */
       
     8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
     9 /*                                                                         */
       
    10 /*  This file is part of the FreeType project, and may only be used,       */
       
    11 /*  modified, and distributed under the terms of the FreeType project      */
       
    12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    13 /*  this file you indicate that you have read the license and              */
       
    14 /*  understand and accept it fully.                                        */
       
    15 /*                                                                         */
       
    16 /***************************************************************************/
       
    17 
       
    18 
       
    19 #include <ft2build.h>
       
    20 #include FT_LCD_FILTER_H
       
    21 #include FT_IMAGE_H
       
    22 #include FT_INTERNAL_OBJECTS_H
       
    23 
       
    24 
       
    25 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
       
    26 
       
    27 /* define USE_LEGACY to implement the legacy filter */
       
    28 #define  USE_LEGACY
       
    29 
       
    30   /* FIR filter used by the default and light filters */
       
    31   static void
       
    32   _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
       
    33                       FT_Render_Mode  mode,
       
    34                       FT_Library      library )
       
    35   {
       
    36     FT_Byte*  weights = library->lcd_weights;
       
    37     FT_UInt   width   = (FT_UInt)bitmap->width;
       
    38     FT_UInt   height  = (FT_UInt)bitmap->rows;
       
    39 
       
    40 
       
    41     /* horizontal in-place FIR filter */
       
    42     if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
       
    43     {
       
    44       FT_Byte*  line = bitmap->buffer;
       
    45 
       
    46 
       
    47       for ( ; height > 0; height--, line += bitmap->pitch )
       
    48       {
       
    49         FT_UInt  fir[5];
       
    50         FT_UInt  val1, xx;
       
    51 
       
    52 
       
    53         val1   = line[0];
       
    54         fir[0] = weights[2] * val1;
       
    55         fir[1] = weights[3] * val1;
       
    56         fir[2] = weights[4] * val1;
       
    57         fir[3] = 0;
       
    58         fir[4] = 0;
       
    59 
       
    60         val1    = line[1];
       
    61         fir[0] += weights[1] * val1;
       
    62         fir[1] += weights[2] * val1;
       
    63         fir[2] += weights[3] * val1;
       
    64         fir[3] += weights[4] * val1;
       
    65 
       
    66         for ( xx = 2; xx < width; xx++ )
       
    67         {
       
    68           FT_UInt  val, pix;
       
    69 
       
    70 
       
    71           val    = line[xx];
       
    72           pix    = fir[0] + weights[0] * val;
       
    73           fir[0] = fir[1] + weights[1] * val;
       
    74           fir[1] = fir[2] + weights[2] * val;
       
    75           fir[2] = fir[3] + weights[3] * val;
       
    76           fir[3] =          weights[4] * val;
       
    77 
       
    78           pix        >>= 8;
       
    79           pix         |= -( pix >> 8 );
       
    80           line[xx - 2] = (FT_Byte)pix;
       
    81         }
       
    82 
       
    83         {
       
    84           FT_UInt  pix;
       
    85 
       
    86 
       
    87           pix          = fir[0] >> 8;
       
    88           pix         |= -( pix >> 8 );
       
    89           line[xx - 2] = (FT_Byte)pix;
       
    90 
       
    91           pix          = fir[1] >> 8;
       
    92           pix         |= -( pix >> 8 );
       
    93           line[xx - 1] = (FT_Byte)pix;
       
    94         }
       
    95       }
       
    96     }
       
    97 
       
    98     /* vertical in-place FIR filter */
       
    99     else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
       
   100     {
       
   101       FT_Byte*  column = bitmap->buffer;
       
   102       FT_Int    pitch  = bitmap->pitch;
       
   103 
       
   104 
       
   105       for ( ; width > 0; width--, column++ )
       
   106       {
       
   107         FT_Byte*  col = column;
       
   108         FT_UInt   fir[5];
       
   109         FT_UInt   val1, yy;
       
   110 
       
   111 
       
   112         val1   = col[0];
       
   113         fir[0] = weights[2] * val1;
       
   114         fir[1] = weights[3] * val1;
       
   115         fir[2] = weights[4] * val1;
       
   116         fir[3] = 0;
       
   117         fir[4] = 0;
       
   118         col   += pitch;
       
   119 
       
   120         val1    = col[0];
       
   121         fir[0] += weights[1] * val1;
       
   122         fir[1] += weights[2] * val1;
       
   123         fir[2] += weights[3] * val1;
       
   124         fir[3] += weights[4] * val1;
       
   125         col    += pitch;
       
   126 
       
   127         for ( yy = 2; yy < height; yy++ )
       
   128         {
       
   129           FT_UInt  val, pix;
       
   130 
       
   131 
       
   132           val    = col[0];
       
   133           pix    = fir[0] + weights[0] * val;
       
   134           fir[0] = fir[1] + weights[1] * val;
       
   135           fir[1] = fir[2] + weights[2] * val;
       
   136           fir[2] = fir[3] + weights[3] * val;
       
   137           fir[3] =          weights[4] * val;
       
   138 
       
   139           pix           >>= 8;
       
   140           pix            |= -( pix >> 8 );
       
   141           col[-2 * pitch] = (FT_Byte)pix;
       
   142           col            += pitch;
       
   143         }
       
   144 
       
   145         {
       
   146           FT_UInt  pix;
       
   147 
       
   148 
       
   149           pix             = fir[0] >> 8;
       
   150           pix            |= -( pix >> 8 );
       
   151           col[-2 * pitch] = (FT_Byte)pix;
       
   152 
       
   153           pix         = fir[1] >> 8;
       
   154           pix        |= -( pix >> 8 );
       
   155           col[-pitch] = (FT_Byte)pix;
       
   156         }
       
   157       }
       
   158     }
       
   159   }
       
   160 
       
   161 
       
   162 #ifdef USE_LEGACY
       
   163 
       
   164   /* intra-pixel filter used by the legacy filter */
       
   165   static void
       
   166   _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
       
   167                          FT_Render_Mode  mode,
       
   168                          FT_Library      library )
       
   169   {
       
   170     FT_UInt  width  = (FT_UInt)bitmap->width;
       
   171     FT_UInt  height = (FT_UInt)bitmap->rows;
       
   172     FT_Int   pitch  = bitmap->pitch;
       
   173 
       
   174     static const int  filters[3][3] =
       
   175     {
       
   176       { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
       
   177       { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
       
   178       { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
       
   179     };
       
   180 
       
   181     FT_UNUSED( library );
       
   182 
       
   183 
       
   184     /* horizontal in-place intra-pixel filter */
       
   185     if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
       
   186     {
       
   187       FT_Byte*  line = bitmap->buffer;
       
   188 
       
   189 
       
   190       for ( ; height > 0; height--, line += pitch )
       
   191       {
       
   192         FT_UInt  xx;
       
   193 
       
   194 
       
   195         for ( xx = 0; xx < width; xx += 3 )
       
   196         {
       
   197           FT_UInt  r = 0;
       
   198           FT_UInt  g = 0;
       
   199           FT_UInt  b = 0;
       
   200           FT_UInt  p;
       
   201 
       
   202 
       
   203           p  = line[xx];
       
   204           r += filters[0][0] * p;
       
   205           g += filters[0][1] * p;
       
   206           b += filters[0][2] * p;
       
   207 
       
   208           p  = line[xx + 1];
       
   209           r += filters[1][0] * p;
       
   210           g += filters[1][1] * p;
       
   211           b += filters[1][2] * p;
       
   212 
       
   213           p  = line[xx + 2];
       
   214           r += filters[2][0] * p;
       
   215           g += filters[2][1] * p;
       
   216           b += filters[2][2] * p;
       
   217 
       
   218           line[xx]     = (FT_Byte)( r / 65536 );
       
   219           line[xx + 1] = (FT_Byte)( g / 65536 );
       
   220           line[xx + 2] = (FT_Byte)( b / 65536 );
       
   221         }
       
   222       }
       
   223     }
       
   224     else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
       
   225     {
       
   226       FT_Byte*  column = bitmap->buffer;
       
   227 
       
   228 
       
   229       for ( ; width > 0; width--, column++ )
       
   230       {
       
   231         FT_Byte*  col     = column;
       
   232         FT_Byte*  col_end = col + height * pitch;
       
   233 
       
   234 
       
   235         for ( ; col < col_end; col += 3 * pitch )
       
   236         {
       
   237           FT_UInt  r = 0;
       
   238           FT_UInt  g = 0;
       
   239           FT_UInt  b = 0;
       
   240           FT_UInt  p;
       
   241 
       
   242 
       
   243           p  = col[0];
       
   244           r += filters[0][0] * p;
       
   245           g += filters[0][1] * p;
       
   246           b += filters[0][2] * p;
       
   247 
       
   248           p  = col[pitch];
       
   249           r += filters[1][0] * p;
       
   250           g += filters[1][1] * p;
       
   251           b += filters[1][2] * p;
       
   252 
       
   253           p  = col[pitch * 2];
       
   254           r += filters[2][0] * p;
       
   255           g += filters[2][1] * p;
       
   256           b += filters[2][2] * p;
       
   257 
       
   258           col[0]         = (FT_Byte)( r / 65536 );
       
   259           col[pitch]     = (FT_Byte)( g / 65536 );
       
   260           col[2 * pitch] = (FT_Byte)( b / 65536 );
       
   261         }
       
   262       }
       
   263     }
       
   264   }
       
   265 
       
   266 #endif /* USE_LEGACY */
       
   267 
       
   268 
       
   269   FT_EXPORT_DEF( FT_Error )
       
   270   FT_Library_SetLcdFilterWeights( FT_Library      library,
       
   271                                   unsigned char  *weights )
       
   272   {
       
   273     if ( !library || !weights )
       
   274       return FT_Err_Invalid_Argument;
       
   275 
       
   276     ft_memcpy( library->lcd_weights, weights, 5 );
       
   277 
       
   278     return FT_Err_Ok;
       
   279   }
       
   280 
       
   281 
       
   282   FT_EXPORT_DEF( FT_Error )
       
   283   FT_Library_SetLcdFilter( FT_Library    library,
       
   284                            FT_LcdFilter  filter )
       
   285   {
       
   286     static const FT_Byte  light_filter[5] =
       
   287                             { 0x00, 0x55, 0x56, 0x55, 0x00 };
       
   288     /* the values here sum up to a value larger than 256, */
       
   289     /* providing a cheap gamma correction                 */
       
   290     static const FT_Byte  default_filter[5] =
       
   291                             { 0x10, 0x40, 0x70, 0x40, 0x10 };
       
   292 
       
   293 
       
   294     if ( !library )
       
   295       return FT_Err_Invalid_Argument;
       
   296 
       
   297     switch ( filter )
       
   298     {
       
   299     case FT_LCD_FILTER_NONE:
       
   300       library->lcd_filter_func = NULL;
       
   301       library->lcd_extra       = 0;
       
   302       break;
       
   303 
       
   304     case FT_LCD_FILTER_DEFAULT:
       
   305 #if defined( FT_FORCE_LEGACY_LCD_FILTER )
       
   306 
       
   307       library->lcd_filter_func = _ft_lcd_filter_legacy;
       
   308       library->lcd_extra       = 0;
       
   309 
       
   310 #elif defined( FT_FORCE_LIGHT_LCD_FILTER )
       
   311 
       
   312       ft_memcpy( library->lcd_weights, light_filter, 5 );
       
   313       library->lcd_filter_func = _ft_lcd_filter_fir;
       
   314       library->lcd_extra       = 2;
       
   315 
       
   316 #else
       
   317 
       
   318       ft_memcpy( library->lcd_weights, default_filter, 5 );
       
   319       library->lcd_filter_func = _ft_lcd_filter_fir;
       
   320       library->lcd_extra       = 2;
       
   321 
       
   322 #endif
       
   323 
       
   324       break;
       
   325 
       
   326     case FT_LCD_FILTER_LIGHT:
       
   327       ft_memcpy( library->lcd_weights, light_filter, 5 );
       
   328       library->lcd_filter_func = _ft_lcd_filter_fir;
       
   329       library->lcd_extra       = 2;
       
   330       break;
       
   331 
       
   332 #ifdef USE_LEGACY
       
   333 
       
   334     case FT_LCD_FILTER_LEGACY:
       
   335       library->lcd_filter_func = _ft_lcd_filter_legacy;
       
   336       library->lcd_extra       = 0;
       
   337       break;
       
   338 
       
   339 #endif
       
   340 
       
   341     default:
       
   342       return FT_Err_Invalid_Argument;
       
   343     }
       
   344 
       
   345     library->lcd_filter = filter;
       
   346 
       
   347     return FT_Err_Ok;
       
   348   }
       
   349 
       
   350 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
       
   351 
       
   352   FT_EXPORT_DEF( FT_Error )
       
   353   FT_Library_SetLcdFilterWeights( FT_Library      library,
       
   354                                   unsigned char  *weights )
       
   355   {
       
   356     FT_UNUSED( library );
       
   357     FT_UNUSED( weights );
       
   358 
       
   359     return FT_Err_Unimplemented_Feature;
       
   360   }
       
   361 
       
   362 
       
   363   FT_EXPORT_DEF( FT_Error )
       
   364   FT_Library_SetLcdFilter( FT_Library    library,
       
   365                            FT_LcdFilter  filter )
       
   366   {
       
   367     FT_UNUSED( library );
       
   368     FT_UNUSED( filter );
       
   369 
       
   370     return FT_Err_Unimplemented_Feature;
       
   371   }
       
   372 
       
   373 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
       
   374 
       
   375 
       
   376 /* END */