1 /**************************************************************************** 2 * 3 * ftbitmap.c 4 * 5 * FreeType utility functions for bitmaps (body). 6 * 7 * Copyright (C) 2004-2023 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 <freetype/internal/ftdebug.h> 20 21 #include <freetype/ftbitmap.h> 22 #include <freetype/ftimage.h> 23 #include <freetype/internal/ftobjs.h> 24 25 26 /************************************************************************** 27 * 28 * The macro FT_COMPONENT is used in trace mode. It is an implicit 29 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 30 * messages during execution. 31 */ 32 #undef FT_COMPONENT 33 #define FT_COMPONENT bitmap 34 35 36 static 37 const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL }; 38 39 40 /* documentation is in ftbitmap.h */ 41 42 FT_EXPORT_DEF( void ) FT_Bitmap_Init(FT_Bitmap * abitmap)43 FT_Bitmap_Init( FT_Bitmap *abitmap ) 44 { 45 if ( abitmap ) 46 *abitmap = null_bitmap; 47 } 48 49 50 /* deprecated function name; retained for ABI compatibility */ 51 52 FT_EXPORT_DEF( void ) FT_Bitmap_New(FT_Bitmap * abitmap)53 FT_Bitmap_New( FT_Bitmap *abitmap ) 54 { 55 if ( abitmap ) 56 *abitmap = null_bitmap; 57 } 58 59 60 /* documentation is in ftbitmap.h */ 61 62 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Copy(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target)63 FT_Bitmap_Copy( FT_Library library, 64 const FT_Bitmap *source, 65 FT_Bitmap *target) 66 { 67 FT_Memory memory; 68 FT_Error error = FT_Err_Ok; 69 FT_Int pitch; 70 FT_Int flip; 71 72 73 if ( !library ) 74 return FT_THROW( Invalid_Library_Handle ); 75 76 if ( !source || !target ) 77 return FT_THROW( Invalid_Argument ); 78 79 if ( source == target ) 80 return FT_Err_Ok; 81 82 flip = ( source->pitch < 0 && target->pitch > 0 ) || 83 ( source->pitch > 0 && target->pitch < 0 ); 84 85 memory = library->memory; 86 FT_FREE( target->buffer ); 87 88 *target = *source; 89 90 if ( flip ) 91 target->pitch = -target->pitch; 92 93 if ( !source->buffer ) 94 return FT_Err_Ok; 95 96 pitch = source->pitch; 97 if ( pitch < 0 ) 98 pitch = -pitch; 99 100 FT_MEM_QALLOC_MULT( target->buffer, target->rows, pitch ); 101 102 if ( !error ) 103 { 104 if ( flip ) 105 { 106 /* take care of bitmap flow */ 107 FT_UInt i; 108 FT_Byte* s = source->buffer; 109 FT_Byte* t = target->buffer; 110 111 112 t += (FT_ULong)pitch * ( target->rows - 1 ); 113 114 for ( i = target->rows; i > 0; i-- ) 115 { 116 FT_ARRAY_COPY( t, s, pitch ); 117 118 s += pitch; 119 t -= pitch; 120 } 121 } 122 else 123 FT_MEM_COPY( target->buffer, source->buffer, 124 (FT_Long)source->rows * pitch ); 125 } 126 127 return error; 128 } 129 130 131 /* Enlarge `bitmap' horizontally and vertically by `xpixels' */ 132 /* and `ypixels', respectively. */ 133 134 static FT_Error ft_bitmap_assure_buffer(FT_Memory memory,FT_Bitmap * bitmap,FT_UInt xpixels,FT_UInt ypixels)135 ft_bitmap_assure_buffer( FT_Memory memory, 136 FT_Bitmap* bitmap, 137 FT_UInt xpixels, 138 FT_UInt ypixels ) 139 { 140 FT_Error error; 141 unsigned int pitch; 142 unsigned int new_pitch; 143 FT_UInt bpp; 144 FT_UInt width, height; 145 unsigned char* buffer = NULL; 146 147 148 width = bitmap->width; 149 height = bitmap->rows; 150 pitch = (unsigned int)FT_ABS( bitmap->pitch ); 151 152 switch ( bitmap->pixel_mode ) 153 { 154 case FT_PIXEL_MODE_MONO: 155 bpp = 1; 156 new_pitch = ( width + xpixels + 7 ) >> 3; 157 break; 158 case FT_PIXEL_MODE_GRAY2: 159 bpp = 2; 160 new_pitch = ( width + xpixels + 3 ) >> 2; 161 break; 162 case FT_PIXEL_MODE_GRAY4: 163 bpp = 4; 164 new_pitch = ( width + xpixels + 1 ) >> 1; 165 break; 166 case FT_PIXEL_MODE_GRAY: 167 case FT_PIXEL_MODE_LCD: 168 case FT_PIXEL_MODE_LCD_V: 169 bpp = 8; 170 new_pitch = width + xpixels; 171 break; 172 default: 173 return FT_THROW( Invalid_Glyph_Format ); 174 } 175 176 /* if no need to allocate memory */ 177 if ( ypixels == 0 && new_pitch <= pitch ) 178 { 179 /* zero the padding */ 180 FT_UInt bit_width = pitch * 8; 181 FT_UInt bit_last = ( width + xpixels ) * bpp; 182 183 184 if ( bit_last < bit_width ) 185 { 186 FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); 187 FT_Byte* end = bitmap->buffer + pitch; 188 FT_UInt shift = bit_last & 7; 189 FT_UInt mask = 0xFF00U >> shift; 190 FT_UInt count = height; 191 192 193 for ( ; count > 0; count--, line += pitch, end += pitch ) 194 { 195 FT_Byte* write = line; 196 197 198 if ( shift > 0 ) 199 { 200 write[0] = (FT_Byte)( write[0] & mask ); 201 write++; 202 } 203 if ( write < end ) 204 FT_MEM_ZERO( write, end - write ); 205 } 206 } 207 208 return FT_Err_Ok; 209 } 210 211 /* otherwise allocate new buffer */ 212 if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) ) 213 return error; 214 215 /* new rows get added at the top of the bitmap, */ 216 /* thus take care of the flow direction */ 217 if ( bitmap->pitch > 0 ) 218 { 219 FT_UInt len = ( width * bpp + 7 ) >> 3; 220 221 unsigned char* in = bitmap->buffer; 222 unsigned char* out = buffer; 223 224 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 225 unsigned int delta = new_pitch - len; 226 227 228 FT_MEM_ZERO( out, new_pitch * ypixels ); 229 out += new_pitch * ypixels; 230 231 while ( in < limit ) 232 { 233 FT_MEM_COPY( out, in, len ); 234 in += pitch; 235 out += len; 236 237 /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */ 238 /* consequently, we have to manually zero out the remaining bytes */ 239 FT_MEM_ZERO( out, delta ); 240 out += delta; 241 } 242 } 243 else 244 { 245 FT_UInt len = ( width * bpp + 7 ) >> 3; 246 247 unsigned char* in = bitmap->buffer; 248 unsigned char* out = buffer; 249 250 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 251 unsigned int delta = new_pitch - len; 252 253 254 while ( in < limit ) 255 { 256 FT_MEM_COPY( out, in, len ); 257 in += pitch; 258 out += len; 259 260 FT_MEM_ZERO( out, delta ); 261 out += delta; 262 } 263 264 FT_MEM_ZERO( out, new_pitch * ypixels ); 265 } 266 267 FT_FREE( bitmap->buffer ); 268 bitmap->buffer = buffer; 269 270 /* set pitch only, width and height are left untouched */ 271 if ( bitmap->pitch < 0 ) 272 bitmap->pitch = -(int)new_pitch; 273 else 274 bitmap->pitch = (int)new_pitch; 275 276 return FT_Err_Ok; 277 } 278 279 280 /* documentation is in ftbitmap.h */ 281 282 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Embolden(FT_Library library,FT_Bitmap * bitmap,FT_Pos xStrength,FT_Pos yStrength)283 FT_Bitmap_Embolden( FT_Library library, 284 FT_Bitmap* bitmap, 285 FT_Pos xStrength, 286 FT_Pos yStrength ) 287 { 288 FT_Error error; 289 unsigned char* p; 290 FT_Int i, x, pitch; 291 FT_UInt y; 292 FT_Int xstr, ystr; 293 294 295 if ( !library ) 296 return FT_THROW( Invalid_Library_Handle ); 297 298 if ( !bitmap || !bitmap->buffer ) 299 return FT_THROW( Invalid_Argument ); 300 301 if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || 302 ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) 303 return FT_THROW( Invalid_Argument ); 304 305 xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; 306 ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; 307 308 if ( xstr == 0 && ystr == 0 ) 309 return FT_Err_Ok; 310 else if ( xstr < 0 || ystr < 0 ) 311 return FT_THROW( Invalid_Argument ); 312 313 switch ( bitmap->pixel_mode ) 314 { 315 case FT_PIXEL_MODE_GRAY2: 316 case FT_PIXEL_MODE_GRAY4: 317 { 318 FT_Bitmap tmp; 319 320 321 /* convert to 8bpp */ 322 FT_Bitmap_Init( &tmp ); 323 error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 ); 324 if ( error ) 325 return error; 326 327 FT_Bitmap_Done( library, bitmap ); 328 *bitmap = tmp; 329 } 330 break; 331 332 case FT_PIXEL_MODE_MONO: 333 if ( xstr > 8 ) 334 xstr = 8; 335 break; 336 337 case FT_PIXEL_MODE_LCD: 338 xstr *= 3; 339 break; 340 341 case FT_PIXEL_MODE_LCD_V: 342 ystr *= 3; 343 break; 344 345 case FT_PIXEL_MODE_BGRA: 346 /* We don't embolden color glyphs. */ 347 return FT_Err_Ok; 348 } 349 350 error = ft_bitmap_assure_buffer( library->memory, bitmap, 351 (FT_UInt)xstr, (FT_UInt)ystr ); 352 if ( error ) 353 return error; 354 355 /* take care of bitmap flow */ 356 pitch = bitmap->pitch; 357 if ( pitch > 0 ) 358 p = bitmap->buffer + pitch * ystr; 359 else 360 { 361 pitch = -pitch; 362 p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 ); 363 } 364 365 /* for each row */ 366 for ( y = 0; y < bitmap->rows; y++ ) 367 { 368 /* 369 * Horizontally: 370 * 371 * From the last pixel on, make each pixel or'ed with the 372 * `xstr' pixels before it. 373 */ 374 for ( x = pitch - 1; x >= 0; x-- ) 375 { 376 unsigned char tmp; 377 378 379 tmp = p[x]; 380 for ( i = 1; i <= xstr; i++ ) 381 { 382 if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) 383 { 384 p[x] |= tmp >> i; 385 386 /* the maximum value of 8 for `xstr' comes from here */ 387 if ( x > 0 ) 388 p[x] |= p[x - 1] << ( 8 - i ); 389 390 #if 0 391 if ( p[x] == 0xFF ) 392 break; 393 #endif 394 } 395 else 396 { 397 if ( x - i >= 0 ) 398 { 399 if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) 400 { 401 p[x] = (unsigned char)( bitmap->num_grays - 1 ); 402 break; 403 } 404 else 405 { 406 p[x] = (unsigned char)( p[x] + p[x - i] ); 407 if ( p[x] == bitmap->num_grays - 1 ) 408 break; 409 } 410 } 411 else 412 break; 413 } 414 } 415 } 416 417 /* 418 * Vertically: 419 * 420 * Make the above `ystr' rows or'ed with it. 421 */ 422 for ( x = 1; x <= ystr; x++ ) 423 { 424 unsigned char* q; 425 426 427 q = p - bitmap->pitch * x; 428 for ( i = 0; i < pitch; i++ ) 429 q[i] |= p[i]; 430 } 431 432 p += bitmap->pitch; 433 } 434 435 bitmap->width += (FT_UInt)xstr; 436 bitmap->rows += (FT_UInt)ystr; 437 438 return FT_Err_Ok; 439 } 440 441 442 static FT_Byte ft_gray_for_premultiplied_srgb_bgra(const FT_Byte * bgra)443 ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) 444 { 445 FT_UInt a = bgra[3]; 446 FT_UInt l; 447 448 449 /* Short-circuit transparent color to avoid division by zero. */ 450 if ( !a ) 451 return 0; 452 453 /* 454 * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 455 * coefficients for RGB channels *on the linear colors*. 456 * A gamma of 2.2 is fair to assume. And then, we need to 457 * undo the premultiplication too. 458 * 459 * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes 460 * 461 * We do the computation with integers only, applying a gamma of 2.0. 462 * We guarantee 32-bit arithmetic to avoid overflow but the resulting 463 * luminosity fits into 16 bits. 464 * 465 */ 466 467 l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] + 468 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] + 469 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16; 470 471 /* 472 * Final transparency can be determined as follows. 473 * 474 * - If alpha is zero, we want 0. 475 * - If alpha is zero and luminosity is zero, we want 255. 476 * - If alpha is zero and luminosity is one, we want 0. 477 * 478 * So the formula is a * (1 - l) = a - l * a. 479 * 480 * We still need to undo premultiplication by dividing l by a*a. 481 * 482 */ 483 484 return (FT_Byte)( a - l / a ); 485 } 486 487 488 /* documentation is in ftbitmap.h */ 489 490 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Convert(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target,FT_Int alignment)491 FT_Bitmap_Convert( FT_Library library, 492 const FT_Bitmap *source, 493 FT_Bitmap *target, 494 FT_Int alignment ) 495 { 496 FT_Error error = FT_Err_Ok; 497 FT_Memory memory; 498 499 FT_Byte* s; 500 FT_Byte* t; 501 502 503 if ( !library ) 504 return FT_THROW( Invalid_Library_Handle ); 505 506 if ( !source || !target ) 507 return FT_THROW( Invalid_Argument ); 508 509 memory = library->memory; 510 511 switch ( source->pixel_mode ) 512 { 513 case FT_PIXEL_MODE_MONO: 514 case FT_PIXEL_MODE_GRAY: 515 case FT_PIXEL_MODE_GRAY2: 516 case FT_PIXEL_MODE_GRAY4: 517 case FT_PIXEL_MODE_LCD: 518 case FT_PIXEL_MODE_LCD_V: 519 case FT_PIXEL_MODE_BGRA: 520 { 521 FT_Int width = (FT_Int)source->width; 522 FT_Int neg = ( target->pitch == 0 && source->pitch < 0 ) || 523 target->pitch < 0; 524 525 526 FT_Bitmap_Done( library, target ); 527 528 target->pixel_mode = FT_PIXEL_MODE_GRAY; 529 target->rows = source->rows; 530 target->width = source->width; 531 532 if ( alignment ) 533 { 534 FT_Int rem = width % alignment; 535 536 537 if ( rem ) 538 width = alignment > 0 ? width - rem + alignment 539 : width - rem - alignment; 540 } 541 542 if ( FT_QALLOC_MULT( target->buffer, target->rows, width ) ) 543 return error; 544 545 target->pitch = neg ? -width : width; 546 } 547 break; 548 549 default: 550 error = FT_THROW( Invalid_Argument ); 551 } 552 553 s = source->buffer; 554 t = target->buffer; 555 556 /* take care of bitmap flow */ 557 if ( source->pitch < 0 ) 558 s -= source->pitch * (FT_Int)( source->rows - 1 ); 559 if ( target->pitch < 0 ) 560 t -= target->pitch * (FT_Int)( target->rows - 1 ); 561 562 switch ( source->pixel_mode ) 563 { 564 case FT_PIXEL_MODE_MONO: 565 { 566 FT_UInt i; 567 568 569 target->num_grays = 2; 570 571 for ( i = source->rows; i > 0; i-- ) 572 { 573 FT_Byte* ss = s; 574 FT_Byte* tt = t; 575 FT_UInt j; 576 577 578 /* get the full bytes */ 579 for ( j = source->width >> 3; j > 0; j-- ) 580 { 581 FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ 582 583 584 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); 585 tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); 586 tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); 587 tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); 588 tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); 589 tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); 590 tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); 591 tt[7] = (FT_Byte)( val & 0x01 ); 592 593 tt += 8; 594 ss += 1; 595 } 596 597 /* get remaining pixels (if any) */ 598 j = source->width & 7; 599 if ( j > 0 ) 600 { 601 FT_Int val = *ss; 602 603 604 for ( ; j > 0; j-- ) 605 { 606 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); 607 val <<= 1; 608 tt += 1; 609 } 610 } 611 612 s += source->pitch; 613 t += target->pitch; 614 } 615 } 616 break; 617 618 619 case FT_PIXEL_MODE_GRAY: 620 case FT_PIXEL_MODE_LCD: 621 case FT_PIXEL_MODE_LCD_V: 622 { 623 FT_UInt width = source->width; 624 FT_UInt i; 625 626 627 target->num_grays = 256; 628 629 for ( i = source->rows; i > 0; i-- ) 630 { 631 FT_ARRAY_COPY( t, s, width ); 632 633 s += source->pitch; 634 t += target->pitch; 635 } 636 } 637 break; 638 639 640 case FT_PIXEL_MODE_GRAY2: 641 { 642 FT_UInt i; 643 644 645 target->num_grays = 4; 646 647 for ( i = source->rows; i > 0; i-- ) 648 { 649 FT_Byte* ss = s; 650 FT_Byte* tt = t; 651 FT_UInt j; 652 653 654 /* get the full bytes */ 655 for ( j = source->width >> 2; j > 0; j-- ) 656 { 657 FT_Int val = ss[0]; 658 659 660 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 661 tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); 662 tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); 663 tt[3] = (FT_Byte)( ( val & 0x03 ) ); 664 665 ss += 1; 666 tt += 4; 667 } 668 669 j = source->width & 3; 670 if ( j > 0 ) 671 { 672 FT_Int val = ss[0]; 673 674 675 for ( ; j > 0; j-- ) 676 { 677 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 678 val <<= 2; 679 tt += 1; 680 } 681 } 682 683 s += source->pitch; 684 t += target->pitch; 685 } 686 } 687 break; 688 689 690 case FT_PIXEL_MODE_GRAY4: 691 { 692 FT_UInt i; 693 694 695 target->num_grays = 16; 696 697 for ( i = source->rows; i > 0; i-- ) 698 { 699 FT_Byte* ss = s; 700 FT_Byte* tt = t; 701 FT_UInt j; 702 703 704 /* get the full bytes */ 705 for ( j = source->width >> 1; j > 0; j-- ) 706 { 707 FT_Int val = ss[0]; 708 709 710 tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); 711 tt[1] = (FT_Byte)( ( val & 0x0F ) ); 712 713 ss += 1; 714 tt += 2; 715 } 716 717 if ( source->width & 1 ) 718 tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); 719 720 s += source->pitch; 721 t += target->pitch; 722 } 723 } 724 break; 725 726 727 case FT_PIXEL_MODE_BGRA: 728 { 729 FT_UInt i; 730 731 732 target->num_grays = 256; 733 734 for ( i = source->rows; i > 0; i-- ) 735 { 736 FT_Byte* ss = s; 737 FT_Byte* tt = t; 738 FT_UInt j; 739 740 741 for ( j = source->width; j > 0; j-- ) 742 { 743 tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); 744 745 ss += 4; 746 tt += 1; 747 } 748 749 s += source->pitch; 750 t += target->pitch; 751 } 752 } 753 break; 754 755 default: 756 ; 757 } 758 759 return error; 760 } 761 762 763 /* documentation is in ftbitmap.h */ 764 765 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Blend(FT_Library library,const FT_Bitmap * source_,const FT_Vector source_offset_,FT_Bitmap * target,FT_Vector * atarget_offset,FT_Color color)766 FT_Bitmap_Blend( FT_Library library, 767 const FT_Bitmap* source_, 768 const FT_Vector source_offset_, 769 FT_Bitmap* target, 770 FT_Vector *atarget_offset, 771 FT_Color color ) 772 { 773 FT_Error error = FT_Err_Ok; 774 FT_Memory memory; 775 776 FT_Bitmap source_bitmap; 777 const FT_Bitmap* source; 778 779 FT_Vector source_offset; 780 FT_Vector target_offset; 781 782 FT_Bool free_source_bitmap = 0; 783 FT_Bool free_target_bitmap_on_error = 0; 784 785 FT_Pos source_llx, source_lly, source_urx, source_ury; 786 FT_Pos target_llx, target_lly, target_urx, target_ury; 787 FT_Pos final_llx, final_lly, final_urx, final_ury; 788 789 unsigned int final_rows, final_width; 790 long x, y; 791 792 793 if ( !library || !target || !source_ || !atarget_offset ) 794 return FT_THROW( Invalid_Argument ); 795 796 memory = library->memory; 797 798 if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE || 799 ( target->pixel_mode == FT_PIXEL_MODE_BGRA && 800 target->buffer ) ) ) 801 return FT_THROW( Invalid_Argument ); 802 803 if ( source_->pixel_mode == FT_PIXEL_MODE_NONE ) 804 return FT_Err_Ok; /* nothing to do */ 805 806 /* pitches must have the same sign */ 807 if ( target->pixel_mode == FT_PIXEL_MODE_BGRA && 808 ( source_->pitch ^ target->pitch ) < 0 ) 809 return FT_THROW( Invalid_Argument ); 810 811 if ( !( source_->width && source_->rows ) ) 812 return FT_Err_Ok; /* nothing to do */ 813 814 /* assure integer pixel offsets */ 815 source_offset.x = FT_PIX_FLOOR( source_offset_.x ); 816 source_offset.y = FT_PIX_FLOOR( source_offset_.y ); 817 target_offset.x = FT_PIX_FLOOR( atarget_offset->x ); 818 target_offset.y = FT_PIX_FLOOR( atarget_offset->y ); 819 820 /* get source bitmap dimensions */ 821 source_llx = source_offset.x; 822 if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y ) 823 { 824 FT_TRACE5(( 825 "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" )); 826 return FT_THROW( Invalid_Argument ); 827 } 828 source_lly = source_offset.y - ( source_->rows << 6 ); 829 830 if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx ) 831 { 832 FT_TRACE5(( 833 "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" )); 834 return FT_THROW( Invalid_Argument ); 835 } 836 source_urx = source_llx + ( source_->width << 6 ); 837 source_ury = source_offset.y; 838 839 /* get target bitmap dimensions */ 840 if ( target->width && target->rows ) 841 { 842 target_llx = target_offset.x; 843 if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y ) 844 { 845 FT_TRACE5(( 846 "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" )); 847 return FT_THROW( Invalid_Argument ); 848 } 849 target_lly = target_offset.y - ( target->rows << 6 ); 850 851 if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx ) 852 { 853 FT_TRACE5(( 854 "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" )); 855 return FT_THROW( Invalid_Argument ); 856 } 857 target_urx = target_llx + ( target->width << 6 ); 858 target_ury = target_offset.y; 859 } 860 else 861 { 862 target_llx = FT_LONG_MAX; 863 target_lly = FT_LONG_MAX; 864 target_urx = FT_LONG_MIN; 865 target_ury = FT_LONG_MIN; 866 } 867 868 /* compute final bitmap dimensions */ 869 final_llx = FT_MIN( source_llx, target_llx ); 870 final_lly = FT_MIN( source_lly, target_lly ); 871 final_urx = FT_MAX( source_urx, target_urx ); 872 final_ury = FT_MAX( source_ury, target_ury ); 873 874 final_width = ( final_urx - final_llx ) >> 6; 875 final_rows = ( final_ury - final_lly ) >> 6; 876 877 #ifdef FT_DEBUG_LEVEL_TRACE 878 FT_TRACE5(( "FT_Bitmap_Blend:\n" )); 879 FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 880 source_llx / 64, source_lly / 64, 881 source_urx / 64, source_ury / 64, 882 source_->width, source_->rows )); 883 884 if ( target->width && target->rows ) 885 FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 886 target_llx / 64, target_lly / 64, 887 target_urx / 64, target_ury / 64, 888 target->width, target->rows )); 889 else 890 FT_TRACE5(( " target bitmap: empty\n" )); 891 892 if ( final_width && final_rows ) 893 FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 894 final_llx / 64, final_lly / 64, 895 final_urx / 64, final_ury / 64, 896 final_width, final_rows )); 897 else 898 FT_TRACE5(( " final bitmap: empty\n" )); 899 #endif /* FT_DEBUG_LEVEL_TRACE */ 900 901 if ( !( final_width && final_rows ) ) 902 return FT_Err_Ok; /* nothing to do */ 903 904 /* for blending, set offset vector of final bitmap */ 905 /* temporarily to (0,0) */ 906 source_llx -= final_llx; 907 source_lly -= final_lly; 908 909 if ( target->width && target->rows ) 910 { 911 target_llx -= final_llx; 912 target_lly -= final_lly; 913 } 914 915 /* set up target bitmap */ 916 if ( target->pixel_mode == FT_PIXEL_MODE_NONE ) 917 { 918 /* create new empty bitmap */ 919 target->width = final_width; 920 target->rows = final_rows; 921 target->pixel_mode = FT_PIXEL_MODE_BGRA; 922 target->pitch = (int)final_width * 4; 923 target->num_grays = 256; 924 925 if ( FT_LONG_MAX / target->pitch < (int)target->rows ) 926 { 927 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", 928 final_width, final_rows )); 929 return FT_THROW( Invalid_Argument ); 930 } 931 932 if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) ) 933 return error; 934 935 free_target_bitmap_on_error = 1; 936 } 937 else if ( target->width != final_width || 938 target->rows != final_rows ) 939 { 940 /* adjust old bitmap to enlarged size */ 941 int pitch, new_pitch; 942 943 unsigned char* buffer = NULL; 944 945 946 pitch = target->pitch; 947 948 if ( pitch < 0 ) 949 pitch = -pitch; 950 951 new_pitch = (int)final_width * 4; 952 953 if ( FT_LONG_MAX / new_pitch < (int)final_rows ) 954 { 955 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", 956 final_width, final_rows )); 957 return FT_THROW( Invalid_Argument ); 958 } 959 960 /* TODO: provide an in-buffer solution for large bitmaps */ 961 /* to avoid allocation of a new buffer */ 962 if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) ) 963 goto Error; 964 965 /* copy data to new buffer */ 966 x = target_llx >> 6; 967 y = target_lly >> 6; 968 969 /* the bitmap flow is from top to bottom, */ 970 /* but y is measured from bottom to top */ 971 if ( target->pitch < 0 ) 972 { 973 /* XXX */ 974 } 975 else 976 { 977 unsigned char* p = 978 target->buffer; 979 unsigned char* q = 980 buffer + 981 ( final_rows - y - target->rows ) * new_pitch + 982 x * 4; 983 unsigned char* limit_p = 984 p + pitch * (int)target->rows; 985 986 987 while ( p < limit_p ) 988 { 989 FT_MEM_COPY( q, p, pitch ); 990 991 p += pitch; 992 q += new_pitch; 993 } 994 } 995 996 FT_FREE( target->buffer ); 997 998 target->width = final_width; 999 target->rows = final_rows; 1000 1001 if ( target->pitch < 0 ) 1002 target->pitch = -new_pitch; 1003 else 1004 target->pitch = new_pitch; 1005 1006 target->buffer = buffer; 1007 } 1008 1009 /* adjust source bitmap if necessary */ 1010 if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY ) 1011 { 1012 FT_Bitmap_Init( &source_bitmap ); 1013 error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 ); 1014 if ( error ) 1015 goto Error; 1016 1017 source = &source_bitmap; 1018 free_source_bitmap = 1; 1019 } 1020 else 1021 source = source_; 1022 1023 /* do blending; the code below returns pre-multiplied channels, */ 1024 /* similar to what FreeType gets from `CBDT' tables */ 1025 x = source_llx >> 6; 1026 y = source_lly >> 6; 1027 1028 /* the bitmap flow is from top to bottom, */ 1029 /* but y is measured from bottom to top */ 1030 if ( target->pitch < 0 ) 1031 { 1032 /* XXX */ 1033 } 1034 else 1035 { 1036 unsigned char* p = 1037 source->buffer; 1038 unsigned char* q = 1039 target->buffer + 1040 ( target->rows - y - source->rows ) * target->pitch + 1041 x * 4; 1042 unsigned char* limit_p = 1043 p + source->pitch * (int)source->rows; 1044 1045 1046 while ( p < limit_p ) 1047 { 1048 unsigned char* r = p; 1049 unsigned char* s = q; 1050 unsigned char* limit_r = r + source->width; 1051 1052 1053 while ( r < limit_r ) 1054 { 1055 int aa = *r++; 1056 int fa = color.alpha * aa / 255; 1057 1058 int fb = color.blue * fa / 255; 1059 int fg = color.green * fa / 255; 1060 int fr = color.red * fa / 255; 1061 1062 int ba2 = 255 - fa; 1063 1064 int bb = s[0]; 1065 int bg = s[1]; 1066 int br = s[2]; 1067 int ba = s[3]; 1068 1069 1070 *s++ = (unsigned char)( bb * ba2 / 255 + fb ); 1071 *s++ = (unsigned char)( bg * ba2 / 255 + fg ); 1072 *s++ = (unsigned char)( br * ba2 / 255 + fr ); 1073 *s++ = (unsigned char)( ba * ba2 / 255 + fa ); 1074 } 1075 1076 p += source->pitch; 1077 q += target->pitch; 1078 } 1079 } 1080 1081 atarget_offset->x = final_llx; 1082 atarget_offset->y = final_lly + ( final_rows << 6 ); 1083 1084 Error: 1085 if ( error && free_target_bitmap_on_error ) 1086 FT_Bitmap_Done( library, target ); 1087 1088 if ( free_source_bitmap ) 1089 FT_Bitmap_Done( library, &source_bitmap ); 1090 1091 return error; 1092 } 1093 1094 1095 /* documentation is in ftbitmap.h */ 1096 1097 FT_EXPORT_DEF( FT_Error ) FT_GlyphSlot_Own_Bitmap(FT_GlyphSlot slot)1098 FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) 1099 { 1100 if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && 1101 !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 1102 { 1103 FT_Bitmap bitmap; 1104 FT_Error error; 1105 1106 1107 FT_Bitmap_Init( &bitmap ); 1108 error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); 1109 if ( error ) 1110 return error; 1111 1112 slot->bitmap = bitmap; 1113 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 1114 } 1115 1116 return FT_Err_Ok; 1117 } 1118 1119 1120 /* documentation is in ftbitmap.h */ 1121 1122 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Done(FT_Library library,FT_Bitmap * bitmap)1123 FT_Bitmap_Done( FT_Library library, 1124 FT_Bitmap *bitmap ) 1125 { 1126 FT_Memory memory; 1127 1128 1129 if ( !library ) 1130 return FT_THROW( Invalid_Library_Handle ); 1131 1132 if ( !bitmap ) 1133 return FT_THROW( Invalid_Argument ); 1134 1135 memory = library->memory; 1136 1137 FT_FREE( bitmap->buffer ); 1138 *bitmap = null_bitmap; 1139 1140 return FT_Err_Ok; 1141 } 1142 1143 1144 /* END */ 1145