1 /***************************************************************************/
5 /* FreeType API for color filtering of subpixel bitmap glyphs (body). */
7 /* Copyright 2006-2016 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
22 #include FT_LCD_FILTER_H
24 #include FT_INTERNAL_OBJECTS_H
27 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
29 /* define USE_LEGACY to implement the legacy filter */
32 /* FIR filter used by the default and light filters */
34 _ft_lcd_filter_fir( FT_Bitmap
* bitmap
,
38 FT_Byte
* weights
= library
->lcd_weights
;
39 FT_UInt width
= (FT_UInt
)bitmap
->width
;
40 FT_UInt height
= (FT_UInt
)bitmap
->rows
;
43 /* horizontal in-place FIR filter */
44 if ( mode
== FT_RENDER_MODE_LCD
&& width
>= 4 )
46 FT_Byte
* line
= bitmap
->buffer
;
49 /* take care of bitmap flow */
50 if ( bitmap
->pitch
< 0 )
51 line
-= bitmap
->pitch
* (FT_Int
)( bitmap
->rows
- 1 );
53 /* `fir' and `pix' must be at least 32 bit wide, since the sum of */
54 /* the values in `weights' can exceed 0xFF */
56 for ( ; height
> 0; height
--, line
+= bitmap
->pitch
)
58 FT_UInt fir
[4]; /* below, `pix' is used as the 5th element */
63 fir
[0] = weights
[2] * val1
;
64 fir
[1] = weights
[3] * val1
;
65 fir
[2] = weights
[4] * val1
;
69 fir
[0] += weights
[1] * val1
;
70 fir
[1] += weights
[2] * val1
;
71 fir
[2] += weights
[3] * val1
;
72 fir
[3] += weights
[4] * val1
;
74 for ( xx
= 2; xx
< width
; xx
++ )
80 pix
= fir
[0] + weights
[0] * val
;
81 fir
[0] = fir
[1] + weights
[1] * val
;
82 fir
[1] = fir
[2] + weights
[2] * val
;
83 fir
[2] = fir
[3] + weights
[3] * val
;
84 fir
[3] = weights
[4] * val
;
87 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
88 line
[xx
- 2] = (FT_Byte
)pix
;
96 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
97 line
[xx
- 2] = (FT_Byte
)pix
;
100 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
101 line
[xx
- 1] = (FT_Byte
)pix
;
106 /* vertical in-place FIR filter */
107 else if ( mode
== FT_RENDER_MODE_LCD_V
&& height
>= 4 )
109 FT_Byte
* column
= bitmap
->buffer
;
110 FT_Int pitch
= bitmap
->pitch
;
113 /* take care of bitmap flow */
114 if ( bitmap
->pitch
< 0 )
115 column
-= bitmap
->pitch
* (FT_Int
)( bitmap
->rows
- 1 );
117 for ( ; width
> 0; width
--, column
++ )
119 FT_Byte
* col
= column
;
120 FT_UInt fir
[4]; /* below, `pix' is used as the 5th element */
125 fir
[0] = weights
[2] * val1
;
126 fir
[1] = weights
[3] * val1
;
127 fir
[2] = weights
[4] * val1
;
132 fir
[0] += weights
[1] * val1
;
133 fir
[1] += weights
[2] * val1
;
134 fir
[2] += weights
[3] * val1
;
135 fir
[3] += weights
[4] * val1
;
138 for ( yy
= 2; yy
< height
; yy
++ )
144 pix
= fir
[0] + weights
[0] * val
;
145 fir
[0] = fir
[1] + weights
[1] * val
;
146 fir
[1] = fir
[2] + weights
[2] * val
;
147 fir
[2] = fir
[3] + weights
[3] * val
;
148 fir
[3] = weights
[4] * val
;
151 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
152 col
[-2 * pitch
] = (FT_Byte
)pix
;
161 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
162 col
[-2 * pitch
] = (FT_Byte
)pix
;
165 pix
|= (FT_UInt
)-(FT_Int
)( pix
>> 8 );
166 col
[-pitch
] = (FT_Byte
)pix
;
175 /* intra-pixel filter used by the legacy filter */
177 _ft_lcd_filter_legacy( FT_Bitmap
* bitmap
,
181 FT_UInt width
= (FT_UInt
)bitmap
->width
;
182 FT_UInt height
= (FT_UInt
)bitmap
->rows
;
183 FT_Int pitch
= bitmap
->pitch
;
185 static const unsigned int filters
[3][3] =
187 { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
188 { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
189 { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
192 FT_UNUSED( library
);
195 /* horizontal in-place intra-pixel filter */
196 if ( mode
== FT_RENDER_MODE_LCD
&& width
>= 3 )
198 FT_Byte
* line
= bitmap
->buffer
;
201 /* take care of bitmap flow */
202 if ( bitmap
->pitch
< 0 )
203 line
-= bitmap
->pitch
* (FT_Int
)( bitmap
->rows
- 1 );
205 for ( ; height
> 0; height
--, line
+= pitch
)
210 for ( xx
= 0; xx
< width
; xx
+= 3 )
219 r
+= filters
[0][0] * p
;
220 g
+= filters
[0][1] * p
;
221 b
+= filters
[0][2] * p
;
224 r
+= filters
[1][0] * p
;
225 g
+= filters
[1][1] * p
;
226 b
+= filters
[1][2] * p
;
229 r
+= filters
[2][0] * p
;
230 g
+= filters
[2][1] * p
;
231 b
+= filters
[2][2] * p
;
233 line
[xx
] = (FT_Byte
)( r
/ 65536 );
234 line
[xx
+ 1] = (FT_Byte
)( g
/ 65536 );
235 line
[xx
+ 2] = (FT_Byte
)( b
/ 65536 );
239 else if ( mode
== FT_RENDER_MODE_LCD_V
&& height
>= 3 )
241 FT_Byte
* column
= bitmap
->buffer
;
244 /* take care of bitmap flow */
245 if ( bitmap
->pitch
< 0 )
246 column
-= bitmap
->pitch
* (FT_Int
)( bitmap
->rows
- 1 );
248 for ( ; width
> 0; width
--, column
++ )
250 FT_Byte
* col
= column
;
251 FT_Byte
* col_end
= col
+ (FT_Int
)height
* pitch
;
254 for ( ; col
< col_end
; col
+= 3 * pitch
)
263 r
+= filters
[0][0] * p
;
264 g
+= filters
[0][1] * p
;
265 b
+= filters
[0][2] * p
;
268 r
+= filters
[1][0] * p
;
269 g
+= filters
[1][1] * p
;
270 b
+= filters
[1][2] * p
;
273 r
+= filters
[2][0] * p
;
274 g
+= filters
[2][1] * p
;
275 b
+= filters
[2][2] * p
;
277 col
[0] = (FT_Byte
)( r
/ 65536 );
278 col
[pitch
] = (FT_Byte
)( g
/ 65536 );
279 col
[2 * pitch
] = (FT_Byte
)( b
/ 65536 );
285 #endif /* USE_LEGACY */
288 FT_EXPORT_DEF( FT_Error
)
289 FT_Library_SetLcdFilterWeights( FT_Library library
,
290 unsigned char *weights
)
293 return FT_THROW( Invalid_Library_Handle
);
296 return FT_THROW( Invalid_Argument
);
298 ft_memcpy( library
->lcd_weights
, weights
, 5 );
299 library
->lcd_filter_func
= _ft_lcd_filter_fir
;
300 library
->lcd_extra
= 2;
306 FT_EXPORT_DEF( FT_Error
)
307 FT_Library_SetLcdFilter( FT_Library library
,
308 FT_LcdFilter filter
)
310 static const FT_Byte default_filter
[5] =
311 { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
312 static const FT_Byte light_filter
[5] =
313 { 0x00, 0x55, 0x56, 0x55, 0x00 };
317 return FT_THROW( Invalid_Library_Handle
);
321 case FT_LCD_FILTER_NONE
:
322 library
->lcd_filter_func
= NULL
;
323 library
->lcd_extra
= 0;
326 case FT_LCD_FILTER_DEFAULT
:
327 ft_memcpy( library
->lcd_weights
, default_filter
, 5 );
328 library
->lcd_filter_func
= _ft_lcd_filter_fir
;
329 library
->lcd_extra
= 2;
332 case FT_LCD_FILTER_LIGHT
:
333 ft_memcpy( library
->lcd_weights
, light_filter
, 5 );
334 library
->lcd_filter_func
= _ft_lcd_filter_fir
;
335 library
->lcd_extra
= 2;
340 case FT_LCD_FILTER_LEGACY
:
341 case FT_LCD_FILTER_LEGACY1
:
342 library
->lcd_filter_func
= _ft_lcd_filter_legacy
;
343 library
->lcd_extra
= 0;
349 return FT_THROW( Invalid_Argument
);
352 library
->lcd_filter
= filter
;
357 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
359 FT_EXPORT_DEF( FT_Error
)
360 FT_Library_SetLcdFilterWeights( FT_Library library
,
361 unsigned char *weights
)
363 FT_UNUSED( library
);
364 FT_UNUSED( weights
);
366 return FT_THROW( Unimplemented_Feature
);
370 FT_EXPORT_DEF( FT_Error
)
371 FT_Library_SetLcdFilter( FT_Library library
,
372 FT_LcdFilter filter
)
374 FT_UNUSED( library
);
377 return FT_THROW( Unimplemented_Feature
);
380 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */