1 /***************************************************************************/ 2 /* */ 3 /* pngshim.c */ 4 /* */ 5 /* PNG Bitmap glyph support. */ 6 /* */ 7 /* Copyright 2013, 2014 by Google, Inc. */ 8 /* Written by Stuart Gill and Behdad Esfahbod. */ 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 #include FT_INTERNAL_STREAM_H 22 #include FT_TRUETYPE_TAGS_H 23 #include FT_CONFIG_STANDARD_LIBRARY_H 24 25 26 #ifdef FT_CONFIG_OPTION_USE_PNG 27 28 /* We always include <stjmp.h>, so make libpng shut up! */ 29 #define PNG_SKIP_SETJMP_CHECK 1 30 #include <png.h> 31 #include "pngshim.h" 32 33 #include "sferrors.h" 34 35 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. */ 38 39 static int 40 multiply_alpha( int alpha, 41 int color ) 42 { 43 int temp = ( alpha * color ) + 0x80; 44 45 46 return ( temp + ( temp >> 8 ) ) >> 8; 47 } 48 49 50 /* Premultiplies data and converts RGBA bytes => native endian. */ 51 static void 52 premultiply_data( png_structp png, 53 png_row_infop row_info, 54 png_bytep data ) 55 { 56 unsigned int i; 57 58 FT_UNUSED( png ); 59 60 61 for ( i = 0; i < row_info->rowbytes; i += 4 ) 62 { 63 unsigned char* base = &data[i]; 64 unsigned int alpha = base[3]; 65 66 67 if ( alpha == 0 ) 68 base[0] = base[1] = base[2] = base[3] = 0; 69 70 else 71 { 72 unsigned int red = base[0]; 73 unsigned int green = base[1]; 74 unsigned int blue = base[2]; 75 76 77 if ( alpha != 0xFF ) 78 { 79 red = multiply_alpha( alpha, red ); 80 green = multiply_alpha( alpha, green ); 81 blue = multiply_alpha( alpha, blue ); 82 } 83 84 base[0] = blue; 85 base[1] = green; 86 base[2] = red; 87 base[3] = alpha; 88 } 89 } 90 } 91 92 93 /* Converts RGBx bytes to BGRA. */ 94 static void 95 convert_bytes_to_data( png_structp png, 96 png_row_infop row_info, 97 png_bytep data ) 98 { 99 unsigned int i; 100 101 FT_UNUSED( png ); 102 103 104 for ( i = 0; i < row_info->rowbytes; i += 4 ) 105 { 106 unsigned char* base = &data[i]; 107 unsigned int red = base[0]; 108 unsigned int green = base[1]; 109 unsigned int blue = base[2]; 110 111 112 base[0] = blue; 113 base[1] = green; 114 base[2] = red; 115 base[3] = 0xFF; 116 } 117 } 118 119 120 /* Use error callback to avoid png writing to stderr. */ 121 static void 122 error_callback( png_structp png, 123 png_const_charp error_msg ) 124 { 125 FT_Error* error = (FT_Error*)png_get_error_ptr( png ); 126 127 FT_UNUSED( error_msg ); 128 129 130 *error = FT_THROW( Out_Of_Memory ); 131 #ifdef PNG_SETJMP_SUPPORTED 132 ft_longjmp( png_jmpbuf( png ), 1 ); 133 #endif 134 /* if we get here, then we have no choice but to abort ... */ 135 } 136 137 138 /* Use warning callback to avoid png writing to stderr. */ 139 static void 140 warning_callback( png_structp png, 141 png_const_charp error_msg ) 142 { 143 FT_UNUSED( png ); 144 FT_UNUSED( error_msg ); 145 146 /* Just ignore warnings. */ 147 } 148 149 150 static void 151 read_data_from_FT_Stream( png_structp png, 152 png_bytep data, 153 png_size_t length ) 154 { 155 FT_Error error; 156 png_voidp p = png_get_io_ptr( png ); 157 FT_Stream stream = (FT_Stream)p; 158 159 160 if ( FT_FRAME_ENTER( length ) ) 161 { 162 FT_Error* e = (FT_Error*)png_get_error_ptr( png ); 163 164 165 *e = FT_THROW( Invalid_Stream_Read ); 166 png_error( png, NULL ); 167 168 return; 169 } 170 171 memcpy( data, stream->cursor, length ); 172 173 FT_FRAME_EXIT(); 174 } 175 176 177 FT_LOCAL_DEF( FT_Error ) 178 Load_SBit_Png( FT_GlyphSlot slot, 179 FT_Int x_offset, 180 FT_Int y_offset, 181 FT_Int pix_bits, 182 TT_SBit_Metrics metrics, 183 FT_Memory memory, 184 FT_Byte* data, 185 FT_UInt png_len, 186 FT_Bool populate_map_and_metrics ) 187 { 188 FT_Bitmap *map = &slot->bitmap; 189 FT_Error error = FT_Err_Ok; 190 FT_StreamRec stream; 191 192 png_structp png; 193 png_infop info; 194 png_uint_32 imgWidth, imgHeight; 195 196 int bitdepth, color_type, interlace; 197 FT_Int i; 198 png_byte* *rows = NULL; /* pacify compiler */ 199 200 201 if ( x_offset < 0 || 202 y_offset < 0 ) 203 { 204 error = FT_THROW( Invalid_Argument ); 205 goto Exit; 206 } 207 208 if ( !populate_map_and_metrics && 209 ( x_offset + metrics->width > map->width || 210 y_offset + metrics->height > map->rows || 211 pix_bits != 32 || 212 map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) 213 { 214 error = FT_THROW( Invalid_Argument ); 215 goto Exit; 216 } 217 218 FT_Stream_OpenMemory( &stream, data, png_len ); 219 220 png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 221 &error, 222 error_callback, 223 warning_callback ); 224 if ( !png ) 225 { 226 error = FT_THROW( Out_Of_Memory ); 227 goto Exit; 228 } 229 230 info = png_create_info_struct( png ); 231 if ( !info ) 232 { 233 error = FT_THROW( Out_Of_Memory ); 234 png_destroy_read_struct( &png, NULL, NULL ); 235 goto Exit; 236 } 237 238 if ( ft_setjmp( png_jmpbuf( png ) ) ) 239 { 240 error = FT_THROW( Invalid_File_Format ); 241 goto DestroyExit; 242 } 243 244 png_set_read_fn( png, &stream, read_data_from_FT_Stream ); 245 246 png_read_info( png, info ); 247 png_get_IHDR( png, info, 248 &imgWidth, &imgHeight, 249 &bitdepth, &color_type, &interlace, 250 NULL, NULL ); 251 252 if ( error || 253 ( !populate_map_and_metrics && 254 ( (FT_Int)imgWidth != metrics->width || 255 (FT_Int)imgHeight != metrics->height ) ) ) 256 goto DestroyExit; 257 258 if ( populate_map_and_metrics ) 259 { 260 FT_Long size; 261 262 263 metrics->width = (FT_Int)imgWidth; 264 metrics->height = (FT_Int)imgHeight; 265 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; 271 272 size = map->rows * map->pitch; 273 274 error = ft_glyphslot_alloc_bitmap( slot, size ); 275 if ( error ) 276 goto DestroyExit; 277 } 278 279 /* convert palette/gray image to rgb */ 280 if ( color_type == PNG_COLOR_TYPE_PALETTE ) 281 png_set_palette_to_rgb( png ); 282 283 /* expand gray bit depth if needed */ 284 if ( color_type == PNG_COLOR_TYPE_GRAY ) 285 { 286 #if PNG_LIBPNG_VER >= 10209 287 png_set_expand_gray_1_2_4_to_8( png ); 288 #else 289 png_set_gray_1_2_4_to_8( png ); 290 #endif 291 } 292 293 /* transform transparency to alpha */ 294 if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) 295 png_set_tRNS_to_alpha( png ); 296 297 if ( bitdepth == 16 ) 298 png_set_strip_16( png ); 299 300 if ( bitdepth < 8 ) 301 png_set_packing( png ); 302 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 ); 307 308 if ( interlace != PNG_INTERLACE_NONE ) 309 png_set_interlace_handling( png ); 310 311 png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); 312 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, 318 NULL, NULL ); 319 320 if ( bitdepth != 8 || 321 !( color_type == PNG_COLOR_TYPE_RGB || 322 color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) 323 { 324 error = FT_THROW( Invalid_File_Format ); 325 goto DestroyExit; 326 } 327 328 switch ( color_type ) 329 { 330 default: 331 /* Shouldn't happen, but fall through. */ 332 333 case PNG_COLOR_TYPE_RGB_ALPHA: 334 png_set_read_user_transform_fn( png, premultiply_data ); 335 break; 336 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 ); 340 break; 341 } 342 343 if ( FT_NEW_ARRAY( rows, imgHeight ) ) 344 { 345 error = FT_THROW( Out_Of_Memory ); 346 goto DestroyExit; 347 } 348 349 for ( i = 0; i < (FT_Int)imgHeight; i++ ) 350 rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; 351 352 png_read_image( png, rows ); 353 354 FT_FREE( rows ); 355 356 png_read_end( png, info ); 357 358 DestroyExit: 359 png_destroy_read_struct( &png, &info, NULL ); 360 FT_Stream_Close( &stream ); 361 362 Exit: 363 return error; 364 } 365 366 #endif /* FT_CONFIG_OPTION_USE_PNG */ 367 368 369 /* END */ 370