1 /***************************************************************************/ 2 /* */ 3 /* ftbitmap.c */ 4 /* */ 5 /* FreeType utility functions for bitmaps (body). */ 6 /* */ 7 /* Copyright 2004-2018 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_BITMAP_H 23 #include FT_IMAGE_H 24 #include FT_INTERNAL_OBJECTS_H 25 26 27 static 28 const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 }; 29 30 31 /* documentation is in ftbitmap.h */ 32 33 FT_EXPORT_DEF( void ) FT_Bitmap_Init(FT_Bitmap * abitmap)34 FT_Bitmap_Init( FT_Bitmap *abitmap ) 35 { 36 if ( abitmap ) 37 *abitmap = null_bitmap; 38 } 39 40 41 /* deprecated function name; retained for ABI compatibility */ 42 43 FT_EXPORT_DEF( void ) FT_Bitmap_New(FT_Bitmap * abitmap)44 FT_Bitmap_New( FT_Bitmap *abitmap ) 45 { 46 if ( abitmap ) 47 *abitmap = null_bitmap; 48 } 49 50 51 /* documentation is in ftbitmap.h */ 52 53 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Copy(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target)54 FT_Bitmap_Copy( FT_Library library, 55 const FT_Bitmap *source, 56 FT_Bitmap *target) 57 { 58 FT_Memory memory; 59 FT_Error error = FT_Err_Ok; 60 61 FT_Int pitch; 62 FT_ULong size; 63 64 FT_Int source_pitch_sign, target_pitch_sign; 65 66 67 if ( !library ) 68 return FT_THROW( Invalid_Library_Handle ); 69 70 if ( !source || !target ) 71 return FT_THROW( Invalid_Argument ); 72 73 if ( source == target ) 74 return FT_Err_Ok; 75 76 source_pitch_sign = source->pitch < 0 ? -1 : 1; 77 target_pitch_sign = target->pitch < 0 ? -1 : 1; 78 79 if ( !source->buffer ) 80 { 81 *target = *source; 82 if ( source_pitch_sign != target_pitch_sign ) 83 target->pitch = -target->pitch; 84 85 return FT_Err_Ok; 86 } 87 88 memory = library->memory; 89 pitch = source->pitch; 90 91 if ( pitch < 0 ) 92 pitch = -pitch; 93 size = (FT_ULong)pitch * source->rows; 94 95 if ( target->buffer ) 96 { 97 FT_Int target_pitch = target->pitch; 98 FT_ULong target_size; 99 100 101 if ( target_pitch < 0 ) 102 target_pitch = -target_pitch; 103 target_size = (FT_ULong)target_pitch * target->rows; 104 105 if ( target_size != size ) 106 (void)FT_QREALLOC( target->buffer, target_size, size ); 107 } 108 else 109 (void)FT_QALLOC( target->buffer, size ); 110 111 if ( !error ) 112 { 113 unsigned char *p; 114 115 116 p = target->buffer; 117 *target = *source; 118 target->buffer = p; 119 120 if ( source_pitch_sign == target_pitch_sign ) 121 FT_MEM_COPY( target->buffer, source->buffer, size ); 122 else 123 { 124 /* take care of bitmap flow */ 125 FT_UInt i; 126 FT_Byte* s = source->buffer; 127 FT_Byte* t = target->buffer; 128 129 130 t += (FT_ULong)pitch * ( target->rows - 1 ); 131 132 for ( i = target->rows; i > 0; i-- ) 133 { 134 FT_ARRAY_COPY( t, s, pitch ); 135 136 s += pitch; 137 t -= pitch; 138 } 139 } 140 } 141 142 return error; 143 } 144 145 146 /* Enlarge `bitmap' horizontally and vertically by `xpixels' */ 147 /* and `ypixels', respectively. */ 148 149 static FT_Error ft_bitmap_assure_buffer(FT_Memory memory,FT_Bitmap * bitmap,FT_UInt xpixels,FT_UInt ypixels)150 ft_bitmap_assure_buffer( FT_Memory memory, 151 FT_Bitmap* bitmap, 152 FT_UInt xpixels, 153 FT_UInt ypixels ) 154 { 155 FT_Error error; 156 unsigned int pitch; 157 unsigned int new_pitch; 158 FT_UInt bpp; 159 FT_UInt width, height; 160 unsigned char* buffer = NULL; 161 162 163 width = bitmap->width; 164 height = bitmap->rows; 165 pitch = (unsigned int)FT_ABS( bitmap->pitch ); 166 167 switch ( bitmap->pixel_mode ) 168 { 169 case FT_PIXEL_MODE_MONO: 170 bpp = 1; 171 new_pitch = ( width + xpixels + 7 ) >> 3; 172 break; 173 case FT_PIXEL_MODE_GRAY2: 174 bpp = 2; 175 new_pitch = ( width + xpixels + 3 ) >> 2; 176 break; 177 case FT_PIXEL_MODE_GRAY4: 178 bpp = 4; 179 new_pitch = ( width + xpixels + 1 ) >> 1; 180 break; 181 case FT_PIXEL_MODE_GRAY: 182 case FT_PIXEL_MODE_LCD: 183 case FT_PIXEL_MODE_LCD_V: 184 bpp = 8; 185 new_pitch = width + xpixels; 186 break; 187 default: 188 return FT_THROW( Invalid_Glyph_Format ); 189 } 190 191 /* if no need to allocate memory */ 192 if ( ypixels == 0 && new_pitch <= pitch ) 193 { 194 /* zero the padding */ 195 FT_UInt bit_width = pitch * 8; 196 FT_UInt bit_last = ( width + xpixels ) * bpp; 197 198 199 if ( bit_last < bit_width ) 200 { 201 FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); 202 FT_Byte* end = bitmap->buffer + pitch; 203 FT_UInt shift = bit_last & 7; 204 FT_UInt mask = 0xFF00U >> shift; 205 FT_UInt count = height; 206 207 208 for ( ; count > 0; count--, line += pitch, end += pitch ) 209 { 210 FT_Byte* write = line; 211 212 213 if ( shift > 0 ) 214 { 215 write[0] = (FT_Byte)( write[0] & mask ); 216 write++; 217 } 218 if ( write < end ) 219 FT_MEM_ZERO( write, end - write ); 220 } 221 } 222 223 return FT_Err_Ok; 224 } 225 226 /* otherwise allocate new buffer */ 227 if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) ) 228 return error; 229 230 /* new rows get added at the top of the bitmap, */ 231 /* thus take care of the flow direction */ 232 if ( bitmap->pitch > 0 ) 233 { 234 FT_UInt len = ( width * bpp + 7 ) >> 3; 235 236 unsigned char* in = bitmap->buffer; 237 unsigned char* out = buffer; 238 239 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 240 unsigned int delta = new_pitch - pitch; 241 242 243 FT_MEM_ZERO( out, new_pitch * ypixels ); 244 out += new_pitch * ypixels; 245 246 while ( in < limit ) 247 { 248 FT_MEM_COPY( out, in, len ); 249 in += pitch; 250 out += pitch; 251 252 FT_MEM_ZERO( out, delta ); 253 out += delta; 254 } 255 } 256 else 257 { 258 FT_UInt len = ( width * bpp + 7 ) >> 3; 259 260 unsigned char* in = bitmap->buffer; 261 unsigned char* out = buffer; 262 263 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 264 unsigned int delta = new_pitch - pitch; 265 266 267 while ( in < limit ) 268 { 269 FT_MEM_COPY( out, in, len ); 270 in += pitch; 271 out += pitch; 272 273 FT_MEM_ZERO( out, delta ); 274 out += delta; 275 } 276 277 FT_MEM_ZERO( out, new_pitch * ypixels ); 278 } 279 280 FT_FREE( bitmap->buffer ); 281 bitmap->buffer = buffer; 282 283 /* set pitch only, width and height are left untouched */ 284 if ( bitmap->pitch < 0 ) 285 bitmap->pitch = -(int)new_pitch; 286 else 287 bitmap->pitch = (int)new_pitch; 288 289 return FT_Err_Ok; 290 } 291 292 293 /* documentation is in ftbitmap.h */ 294 295 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Embolden(FT_Library library,FT_Bitmap * bitmap,FT_Pos xStrength,FT_Pos yStrength)296 FT_Bitmap_Embolden( FT_Library library, 297 FT_Bitmap* bitmap, 298 FT_Pos xStrength, 299 FT_Pos yStrength ) 300 { 301 FT_Error error; 302 unsigned char* p; 303 FT_Int i, x, pitch; 304 FT_UInt y; 305 FT_Int xstr, ystr; 306 307 308 if ( !library ) 309 return FT_THROW( Invalid_Library_Handle ); 310 311 if ( !bitmap || !bitmap->buffer ) 312 return FT_THROW( Invalid_Argument ); 313 314 if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || 315 ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) 316 return FT_THROW( Invalid_Argument ); 317 318 xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; 319 ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; 320 321 if ( xstr == 0 && ystr == 0 ) 322 return FT_Err_Ok; 323 else if ( xstr < 0 || ystr < 0 ) 324 return FT_THROW( Invalid_Argument ); 325 326 switch ( bitmap->pixel_mode ) 327 { 328 case FT_PIXEL_MODE_GRAY2: 329 case FT_PIXEL_MODE_GRAY4: 330 { 331 FT_Bitmap tmp; 332 333 334 /* convert to 8bpp */ 335 FT_Bitmap_Init( &tmp ); 336 error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 ); 337 if ( error ) 338 return error; 339 340 FT_Bitmap_Done( library, bitmap ); 341 *bitmap = tmp; 342 } 343 break; 344 345 case FT_PIXEL_MODE_MONO: 346 if ( xstr > 8 ) 347 xstr = 8; 348 break; 349 350 case FT_PIXEL_MODE_LCD: 351 xstr *= 3; 352 break; 353 354 case FT_PIXEL_MODE_LCD_V: 355 ystr *= 3; 356 break; 357 358 case FT_PIXEL_MODE_BGRA: 359 /* We don't embolden color glyphs. */ 360 return FT_Err_Ok; 361 } 362 363 error = ft_bitmap_assure_buffer( library->memory, bitmap, 364 (FT_UInt)xstr, (FT_UInt)ystr ); 365 if ( error ) 366 return error; 367 368 /* take care of bitmap flow */ 369 pitch = bitmap->pitch; 370 if ( pitch > 0 ) 371 p = bitmap->buffer + pitch * ystr; 372 else 373 { 374 pitch = -pitch; 375 p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 ); 376 } 377 378 /* for each row */ 379 for ( y = 0; y < bitmap->rows; y++ ) 380 { 381 /* 382 * Horizontally: 383 * 384 * From the last pixel on, make each pixel or'ed with the 385 * `xstr' pixels before it. 386 */ 387 for ( x = pitch - 1; x >= 0; x-- ) 388 { 389 unsigned char tmp; 390 391 392 tmp = p[x]; 393 for ( i = 1; i <= xstr; i++ ) 394 { 395 if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) 396 { 397 p[x] |= tmp >> i; 398 399 /* the maximum value of 8 for `xstr' comes from here */ 400 if ( x > 0 ) 401 p[x] |= p[x - 1] << ( 8 - i ); 402 403 #if 0 404 if ( p[x] == 0xFF ) 405 break; 406 #endif 407 } 408 else 409 { 410 if ( x - i >= 0 ) 411 { 412 if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) 413 { 414 p[x] = (unsigned char)( bitmap->num_grays - 1 ); 415 break; 416 } 417 else 418 { 419 p[x] = (unsigned char)( p[x] + p[x - i] ); 420 if ( p[x] == bitmap->num_grays - 1 ) 421 break; 422 } 423 } 424 else 425 break; 426 } 427 } 428 } 429 430 /* 431 * Vertically: 432 * 433 * Make the above `ystr' rows or'ed with it. 434 */ 435 for ( x = 1; x <= ystr; x++ ) 436 { 437 unsigned char* q; 438 439 440 q = p - bitmap->pitch * x; 441 for ( i = 0; i < pitch; i++ ) 442 q[i] |= p[i]; 443 } 444 445 p += bitmap->pitch; 446 } 447 448 bitmap->width += (FT_UInt)xstr; 449 bitmap->rows += (FT_UInt)ystr; 450 451 return FT_Err_Ok; 452 } 453 454 455 static FT_Byte ft_gray_for_premultiplied_srgb_bgra(const FT_Byte * bgra)456 ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) 457 { 458 FT_UInt a = bgra[3]; 459 FT_UInt l; 460 461 462 /* Short-circuit transparent color to avoid division by zero. */ 463 if ( !a ) 464 return 0; 465 466 /* 467 * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 468 * coefficients for RGB channels *on the linear colors*. 469 * A gamma of 2.2 is fair to assume. And then, we need to 470 * undo the premultiplication too. 471 * 472 * https://accessibility.kde.org/hsl-adjusted.php 473 * 474 * We do the computation with integers only, applying a gamma of 2.0. 475 * We guarantee 32-bit arithmetic to avoid overflow but the resulting 476 * luminosity fits into 16 bits. 477 * 478 */ 479 480 l = ( 4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] + 481 46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] + 482 13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16; 483 484 /* 485 * Final transparency can be determined as follows. 486 * 487 * - If alpha is zero, we want 0. 488 * - If alpha is zero and luminosity is zero, we want 255. 489 * - If alpha is zero and luminosity is one, we want 0. 490 * 491 * So the formula is a * (1 - l) = a - l * a. 492 * 493 * We still need to undo premultiplication by dividing l by a*a. 494 * 495 */ 496 497 return (FT_Byte)( a - l / a ); 498 } 499 500 501 /* documentation is in ftbitmap.h */ 502 503 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Convert(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target,FT_Int alignment)504 FT_Bitmap_Convert( FT_Library library, 505 const FT_Bitmap *source, 506 FT_Bitmap *target, 507 FT_Int alignment ) 508 { 509 FT_Error error = FT_Err_Ok; 510 FT_Memory memory; 511 512 FT_Byte* s; 513 FT_Byte* t; 514 515 516 if ( !library ) 517 return FT_THROW( Invalid_Library_Handle ); 518 519 if ( !source || !target ) 520 return FT_THROW( Invalid_Argument ); 521 522 memory = library->memory; 523 524 switch ( source->pixel_mode ) 525 { 526 case FT_PIXEL_MODE_MONO: 527 case FT_PIXEL_MODE_GRAY: 528 case FT_PIXEL_MODE_GRAY2: 529 case FT_PIXEL_MODE_GRAY4: 530 case FT_PIXEL_MODE_LCD: 531 case FT_PIXEL_MODE_LCD_V: 532 case FT_PIXEL_MODE_BGRA: 533 { 534 FT_Int pad, old_target_pitch, target_pitch; 535 FT_ULong old_size; 536 537 538 old_target_pitch = target->pitch; 539 if ( old_target_pitch < 0 ) 540 old_target_pitch = -old_target_pitch; 541 542 old_size = target->rows * (FT_UInt)old_target_pitch; 543 544 target->pixel_mode = FT_PIXEL_MODE_GRAY; 545 target->rows = source->rows; 546 target->width = source->width; 547 548 pad = 0; 549 if ( alignment > 0 ) 550 { 551 pad = (FT_Int)source->width % alignment; 552 if ( pad != 0 ) 553 pad = alignment - pad; 554 } 555 556 target_pitch = (FT_Int)source->width + pad; 557 558 if ( target_pitch > 0 && 559 (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch ) 560 return FT_THROW( Invalid_Argument ); 561 562 if ( FT_QREALLOC( target->buffer, 563 old_size, target->rows * (FT_UInt)target_pitch ) ) 564 return error; 565 566 target->pitch = target->pitch < 0 ? -target_pitch : target_pitch; 567 } 568 break; 569 570 default: 571 error = FT_THROW( Invalid_Argument ); 572 } 573 574 s = source->buffer; 575 t = target->buffer; 576 577 /* take care of bitmap flow */ 578 if ( source->pitch < 0 ) 579 s -= source->pitch * (FT_Int)( source->rows - 1 ); 580 if ( target->pitch < 0 ) 581 t -= target->pitch * (FT_Int)( target->rows - 1 ); 582 583 switch ( source->pixel_mode ) 584 { 585 case FT_PIXEL_MODE_MONO: 586 { 587 FT_UInt i; 588 589 590 target->num_grays = 2; 591 592 for ( i = source->rows; i > 0; i-- ) 593 { 594 FT_Byte* ss = s; 595 FT_Byte* tt = t; 596 FT_UInt j; 597 598 599 /* get the full bytes */ 600 for ( j = source->width >> 3; j > 0; j-- ) 601 { 602 FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ 603 604 605 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); 606 tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); 607 tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); 608 tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); 609 tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); 610 tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); 611 tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); 612 tt[7] = (FT_Byte)( val & 0x01 ); 613 614 tt += 8; 615 ss += 1; 616 } 617 618 /* get remaining pixels (if any) */ 619 j = source->width & 7; 620 if ( j > 0 ) 621 { 622 FT_Int val = *ss; 623 624 625 for ( ; j > 0; j-- ) 626 { 627 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); 628 val <<= 1; 629 tt += 1; 630 } 631 } 632 633 s += source->pitch; 634 t += target->pitch; 635 } 636 } 637 break; 638 639 640 case FT_PIXEL_MODE_GRAY: 641 case FT_PIXEL_MODE_LCD: 642 case FT_PIXEL_MODE_LCD_V: 643 { 644 FT_UInt width = source->width; 645 FT_UInt i; 646 647 648 target->num_grays = 256; 649 650 for ( i = source->rows; i > 0; i-- ) 651 { 652 FT_ARRAY_COPY( t, s, width ); 653 654 s += source->pitch; 655 t += target->pitch; 656 } 657 } 658 break; 659 660 661 case FT_PIXEL_MODE_GRAY2: 662 { 663 FT_UInt i; 664 665 666 target->num_grays = 4; 667 668 for ( i = source->rows; i > 0; i-- ) 669 { 670 FT_Byte* ss = s; 671 FT_Byte* tt = t; 672 FT_UInt j; 673 674 675 /* get the full bytes */ 676 for ( j = source->width >> 2; j > 0; j-- ) 677 { 678 FT_Int val = ss[0]; 679 680 681 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 682 tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); 683 tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); 684 tt[3] = (FT_Byte)( ( val & 0x03 ) ); 685 686 ss += 1; 687 tt += 4; 688 } 689 690 j = source->width & 3; 691 if ( j > 0 ) 692 { 693 FT_Int val = ss[0]; 694 695 696 for ( ; j > 0; j-- ) 697 { 698 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 699 val <<= 2; 700 tt += 1; 701 } 702 } 703 704 s += source->pitch; 705 t += target->pitch; 706 } 707 } 708 break; 709 710 711 case FT_PIXEL_MODE_GRAY4: 712 { 713 FT_UInt i; 714 715 716 target->num_grays = 16; 717 718 for ( i = source->rows; i > 0; i-- ) 719 { 720 FT_Byte* ss = s; 721 FT_Byte* tt = t; 722 FT_UInt j; 723 724 725 /* get the full bytes */ 726 for ( j = source->width >> 1; j > 0; j-- ) 727 { 728 FT_Int val = ss[0]; 729 730 731 tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); 732 tt[1] = (FT_Byte)( ( val & 0x0F ) ); 733 734 ss += 1; 735 tt += 2; 736 } 737 738 if ( source->width & 1 ) 739 tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); 740 741 s += source->pitch; 742 t += target->pitch; 743 } 744 } 745 break; 746 747 748 case FT_PIXEL_MODE_BGRA: 749 { 750 FT_UInt i; 751 752 753 target->num_grays = 256; 754 755 for ( i = source->rows; i > 0; i-- ) 756 { 757 FT_Byte* ss = s; 758 FT_Byte* tt = t; 759 FT_UInt j; 760 761 762 for ( j = source->width; j > 0; j-- ) 763 { 764 tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); 765 766 ss += 4; 767 tt += 1; 768 } 769 770 s += source->pitch; 771 t += target->pitch; 772 } 773 } 774 break; 775 776 default: 777 ; 778 } 779 780 return error; 781 } 782 783 784 /* documentation is in ftbitmap.h */ 785 786 FT_EXPORT_DEF( FT_Error ) FT_GlyphSlot_Own_Bitmap(FT_GlyphSlot slot)787 FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) 788 { 789 if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && 790 !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 791 { 792 FT_Bitmap bitmap; 793 FT_Error error; 794 795 796 FT_Bitmap_Init( &bitmap ); 797 error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); 798 if ( error ) 799 return error; 800 801 slot->bitmap = bitmap; 802 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 803 } 804 805 return FT_Err_Ok; 806 } 807 808 809 /* documentation is in ftbitmap.h */ 810 811 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Done(FT_Library library,FT_Bitmap * bitmap)812 FT_Bitmap_Done( FT_Library library, 813 FT_Bitmap *bitmap ) 814 { 815 FT_Memory memory; 816 817 818 if ( !library ) 819 return FT_THROW( Invalid_Library_Handle ); 820 821 if ( !bitmap ) 822 return FT_THROW( Invalid_Argument ); 823 824 memory = library->memory; 825 826 FT_FREE( bitmap->buffer ); 827 *bitmap = null_bitmap; 828 829 return FT_Err_Ok; 830 } 831 832 833 /* END */ 834