1 /***************************************************************************/
5 /* PNG Bitmap glyph support. */
7 /* Copyright 2013 by Google, Inc. */
8 /* Written by Stuart Gill and Behdad Esfahbod. */
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
21 #include FT_INTERNAL_STREAM_H
22 #include FT_TRUETYPE_TAGS_H
23 #include FT_CONFIG_STANDARD_LIBRARY_H
26 #ifdef FT_CONFIG_OPTION_USE_PNG
28 /* We always include <stjmp.h>, so make libpng shut up! */
29 #define PNG_SKIP_SETJMP_CHECK 1
36 /* This code is freely based on cairo-png.c. There's so many ways */
37 /* to call libpng, and the way cairo does it is defacto standard. */
40 multiply_alpha( int alpha
,
43 int temp
= ( alpha
* color
) + 0x80;
46 return ( temp
+ ( temp
>> 8 ) ) >> 8;
50 /* Premultiplies data and converts RGBA bytes => native endian. */
52 premultiply_data( png_structp png
,
53 png_row_infop row_info
,
61 for ( i
= 0; i
< row_info
->rowbytes
; i
+= 4 )
63 unsigned char* base
= &data
[i
];
64 unsigned int alpha
= base
[3];
68 base
[0] = base
[1] = base
[2] = base
[3] = 0;
72 unsigned int red
= base
[0];
73 unsigned int green
= base
[1];
74 unsigned int blue
= base
[2];
79 red
= multiply_alpha( alpha
, red
);
80 green
= multiply_alpha( alpha
, green
);
81 blue
= multiply_alpha( alpha
, blue
);
93 /* Converts RGBx bytes to BGRA. */
95 convert_bytes_to_data( png_structp png
,
96 png_row_infop row_info
,
104 for ( i
= 0; i
< row_info
->rowbytes
; i
+= 4 )
106 unsigned char* base
= &data
[i
];
107 unsigned int red
= base
[0];
108 unsigned int green
= base
[1];
109 unsigned int blue
= base
[2];
120 /* Use error callback to avoid png writing to stderr. */
122 error_callback( png_structp png
,
123 png_const_charp error_msg
)
125 FT_Error
* error
= (FT_Error
*)png_get_error_ptr( png
);
127 FT_UNUSED( error_msg
);
130 *error
= FT_THROW( Out_Of_Memory
);
131 #ifdef PNG_SETJMP_SUPPORTED
132 longjmp( png_jmpbuf( png
), 1 );
134 /* if we get here, then we have no choice but to abort ... */
138 /* Use warning callback to avoid png writing to stderr. */
140 warning_callback( png_structp png
,
141 png_const_charp error_msg
)
144 FT_UNUSED( error_msg
);
146 /* Just ignore warnings. */
151 read_data_from_FT_Stream( png_structp png
,
156 png_voidp p
= png_get_io_ptr( png
);
157 FT_Stream stream
= (FT_Stream
)p
;
160 if ( FT_FRAME_ENTER( length
) )
162 FT_Error
* e
= (FT_Error
*)png_get_error_ptr( png
);
165 *e
= FT_THROW( Invalid_Stream_Read
);
166 png_error( png
, NULL
);
171 memcpy( data
, stream
->cursor
, length
);
177 FT_LOCAL_DEF( FT_Error
)
178 Load_SBit_Png( FT_GlyphSlot slot
,
182 TT_SBit_Metrics metrics
,
186 FT_Bool populate_map_and_metrics
)
188 FT_Bitmap
*map
= &slot
->bitmap
;
189 FT_Error error
= FT_Err_Ok
;
194 png_uint_32 imgWidth
, imgHeight
;
196 int bitdepth
, color_type
, interlace
;
198 png_byte
* *rows
= NULL
; /* pacify compiler */
204 error
= FT_THROW( Invalid_Argument
);
208 if ( !populate_map_and_metrics
&&
209 ( x_offset
+ metrics
->width
> map
->width
||
210 y_offset
+ metrics
->height
> map
->rows
||
212 map
->pixel_mode
!= FT_PIXEL_MODE_BGRA
) )
214 error
= FT_THROW( Invalid_Argument
);
218 FT_Stream_OpenMemory( &stream
, data
, png_len
);
220 png
= png_create_read_struct( PNG_LIBPNG_VER_STRING
,
226 error
= FT_THROW( Out_Of_Memory
);
230 info
= png_create_info_struct( png
);
233 error
= FT_THROW( Out_Of_Memory
);
234 png_destroy_read_struct( &png
, NULL
, NULL
);
238 if ( ft_setjmp( png_jmpbuf( png
) ) )
240 error
= FT_THROW( Invalid_File_Format
);
244 png_set_read_fn( png
, &stream
, read_data_from_FT_Stream
);
246 png_read_info( png
, info
);
247 png_get_IHDR( png
, info
,
248 &imgWidth
, &imgHeight
,
249 &bitdepth
, &color_type
, &interlace
,
253 ( !populate_map_and_metrics
&&
254 ( (FT_Int
)imgWidth
!= metrics
->width
||
255 (FT_Int
)imgHeight
!= metrics
->height
) ) )
258 if ( populate_map_and_metrics
)
263 metrics
->width
= (FT_Int
)imgWidth
;
264 metrics
->height
= (FT_Int
)imgHeight
;
266 map
->width
= metrics
->width
;
267 map
->rows
= metrics
->height
;
268 map
->pixel_mode
= FT_PIXEL_MODE_BGRA
;
269 map
->pitch
= map
->width
* 4;
270 map
->num_grays
= 256;
272 size
= map
->rows
* map
->pitch
;
274 error
= ft_glyphslot_alloc_bitmap( slot
, size
);
279 /* convert palette/gray image to rgb */
280 if ( color_type
== PNG_COLOR_TYPE_PALETTE
)
281 png_set_palette_to_rgb( png
);
283 /* expand gray bit depth if needed */
284 if ( color_type
== PNG_COLOR_TYPE_GRAY
)
286 #if PNG_LIBPNG_VER >= 10209
287 png_set_expand_gray_1_2_4_to_8( png
);
289 png_set_gray_1_2_4_to_8( png
);
293 /* transform transparency to alpha */
294 if ( png_get_valid(png
, info
, PNG_INFO_tRNS
) )
295 png_set_tRNS_to_alpha( png
);
297 if ( bitdepth
== 16 )
298 png_set_strip_16( png
);
301 png_set_packing( png
);
303 /* convert grayscale to RGB */
304 if ( color_type
== PNG_COLOR_TYPE_GRAY
||
305 color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
306 png_set_gray_to_rgb( png
);
308 if ( interlace
!= PNG_INTERLACE_NONE
)
309 png_set_interlace_handling( png
);
311 png_set_filler( png
, 0xFF, PNG_FILLER_AFTER
);
313 /* recheck header after setting EXPAND options */
314 png_read_update_info(png
, info
);
315 png_get_IHDR( png
, info
,
316 &imgWidth
, &imgHeight
,
317 &bitdepth
, &color_type
, &interlace
,
320 if ( bitdepth
!= 8 ||
321 !( color_type
== PNG_COLOR_TYPE_RGB
||
322 color_type
== PNG_COLOR_TYPE_RGB_ALPHA
) )
324 error
= FT_THROW( Invalid_File_Format
);
328 switch ( color_type
)
331 /* Shouldn't happen, but fall through. */
333 case PNG_COLOR_TYPE_RGB_ALPHA
:
334 png_set_read_user_transform_fn( png
, premultiply_data
);
337 case PNG_COLOR_TYPE_RGB
:
338 /* Humm, this smells. Carry on though. */
339 png_set_read_user_transform_fn( png
, convert_bytes_to_data
);
343 if ( FT_NEW_ARRAY( rows
, imgHeight
) )
345 error
= FT_THROW( Out_Of_Memory
);
349 for ( i
= 0; i
< (FT_Int
)imgHeight
; i
++ )
350 rows
[i
] = map
->buffer
+ ( y_offset
+ i
) * map
->pitch
+ x_offset
* 4;
352 png_read_image( png
, rows
);
356 png_read_end( png
, info
);
359 png_destroy_read_struct( &png
, &info
, NULL
);
360 FT_Stream_Close( &stream
);
366 #endif /* FT_CONFIG_OPTION_USE_PNG */