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