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
_ft_lcd_filter_fir(FT_Bitmap * bitmap,FT_Render_Mode mode,FT_Library library)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
_ft_lcd_filter_legacy(FT_Bitmap * bitmap,FT_Render_Mode mode,FT_Library library)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 )
FT_Library_SetLcdFilterWeights(FT_Library library,unsigned char * weights)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 )
FT_Library_SetLcdFilter(FT_Library library,FT_LcdFilter filter)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 )
FT_Library_SetLcdFilterWeights(FT_Library library,unsigned char * weights)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 )
FT_Library_SetLcdFilter(FT_Library library,FT_LcdFilter filter)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