@ -25,7 +25,7 @@
static
const FT_Bitmap null_bitmap = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
const FT_Bitmap null_bitmap = { 0 , 0 , 0 , NULL , 0 , 0 , 0 , NULL } ;
/* documentation is in ftbitmap.h */
@ -783,6 +783,300 @@
}
/* documentation is in ftbitmap.h */
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 )
{
FT_Error error = FT_Err_Ok ;
FT_Memory memory ;
FT_Bitmap source_bitmap ;
const FT_Bitmap * source ;
FT_Vector source_offset ;
FT_Vector target_offset ;
FT_Vector frac_offset ;
FT_Bool free_source_bitmap = 0 ;
FT_Bool free_target_bitmap_on_error = 0 ;
FT_Pos source_llx , source_lly , source_urx , source_ury ;
FT_Pos target_llx , target_lly , target_urx , target_ury ;
FT_Pos final_llx , final_lly , final_urx , final_ury ;
unsigned int final_rows , final_width ;
long x , y ;
if ( ! library | | ! target | | ! source_ | | ! atarget_offset )
return FT_THROW ( Invalid_Argument ) ;
memory = library - > memory ;
if ( ! ( target - > pixel_mode = = FT_PIXEL_MODE_NONE | |
( target - > pixel_mode = = FT_PIXEL_MODE_BGRA & &
target - > buffer ) ) )
return FT_THROW ( Invalid_Argument ) ;
if ( source_ - > pixel_mode = = FT_PIXEL_MODE_NONE )
return FT_Err_Ok ; /* nothing to do */
/* pitches must have the same sign */
if ( target - > pixel_mode = = FT_PIXEL_MODE_BGRA & &
( source_ - > pitch ^ target - > pitch ) < 0 )
return FT_THROW ( Invalid_Argument ) ;
if ( ! ( source_ - > width & & source_ - > rows ) )
return FT_Err_Ok ; /* nothing to do */
/* we isolate a fractional shift of `source', */
/* to be less than one pixel and always positive; */
/* `source_offset' now holds full-pixel shift values */
source_offset . x = FT_PIX_FLOOR ( source_offset_ . x ) ;
frac_offset . x = source_offset_ . x - source_offset . x ;
source_offset . y = FT_PIX_FLOOR ( source_offset_ . y ) ;
frac_offset . y = source_offset_ . y - source_offset . y ;
/* assure integer pixel offset for target bitmap */
target_offset . x = FT_PIX_FLOOR ( atarget_offset - > x ) ;
target_offset . y = FT_PIX_FLOOR ( atarget_offset - > y ) ;
/* get source bitmap dimensions */
source_llx = source_offset . x ;
if ( FT_LONG_MIN + ( source_ - > rows < < 6 ) + 64 > source_offset . y )
return FT_THROW ( Invalid_Argument ) ;
source_lly = source_offset . y - ( source_ - > rows < < 6 ) ;
if ( FT_LONG_MAX - ( source_ - > width < < 6 ) - 64 < source_llx )
return FT_THROW ( Invalid_Argument ) ;
source_urx = source_llx + ( source_ - > width < < 6 ) ;
source_ury = source_offset . y ;
/* get target bitmap dimensions */
if ( target - > width & & target - > rows )
{
target_llx = target_offset . x ;
if ( FT_LONG_MIN + ( target - > rows < < 6 ) > target_offset . y )
return FT_THROW ( Invalid_Argument ) ;
target_lly = target_offset . y - ( target - > rows < < 6 ) ;
if ( FT_LONG_MAX - ( target - > width < < 6 ) < target_llx )
return FT_THROW ( Invalid_Argument ) ;
target_urx = target_llx + ( target - > width < < 6 ) ;
target_ury = target_offset . y ;
}
else
{
target_llx = FT_LONG_MAX ;
target_lly = FT_LONG_MAX ;
target_urx = FT_LONG_MIN ;
target_ury = FT_LONG_MIN ;
}
/* move upper right corner up and to the right */
/* if we have a fractional offset */
if ( source_urx > = target_urx & & frac_offset . x )
source_urx + = 64 ;
if ( source_ury > = target_ury & & frac_offset . y )
source_ury + = 64 ;
/* compute final bitmap dimensions */
final_llx = FT_MIN ( source_llx , target_llx ) ;
final_lly = FT_MIN ( source_lly , target_lly ) ;
final_urx = FT_MAX ( source_urx , target_urx ) ;
final_ury = FT_MAX ( source_ury , target_ury ) ;
final_width = ( final_urx - final_llx ) > > 6 ;
final_rows = ( final_ury - final_lly ) > > 6 ;
/* for blending, set offset vector of final bitmap */
/* temporarily to (0,0) */
source_llx - = final_llx ;
source_lly - = final_lly ;
target_llx - = final_llx ;
target_lly - = final_lly ;
/* set up target bitmap */
if ( target - > pixel_mode = = FT_PIXEL_MODE_NONE )
{
/* create new empty bitmap */
target - > width = final_width ;
target - > rows = final_rows ;
target - > pixel_mode = FT_PIXEL_MODE_BGRA ;
target - > pitch = ( int ) final_width * 4 ;
target - > num_grays = 256 ;
if ( FT_LONG_MAX / target - > pitch < target - > rows )
return FT_THROW ( Invalid_Argument ) ;
if ( FT_ALLOC ( target - > buffer , target - > pitch * ( int ) target - > rows ) )
return error ;
free_target_bitmap_on_error = 1 ;
}
else if ( target - > width ! = final_width | |
target - > rows ! = final_rows )
{
/* adjust old bitmap to enlarged size */
int pitch , new_pitch ;
unsigned char * buffer = NULL ;
pitch = target - > pitch ;
if ( pitch < 0 )
pitch = - pitch ;
new_pitch = ( int ) final_width * 4 ;
if ( FT_LONG_MAX / new_pitch < final_rows )
return FT_THROW ( Invalid_Argument ) ;
/* TODO: provide an in-buffer solution for large bitmaps */
/* to avoid allocation of a new buffer */
if ( FT_ALLOC ( buffer , new_pitch * ( int ) final_rows ) )
goto Error ;
/* copy data to new buffer */
x = target_llx > > 6 ;
y = target_lly > > 6 ;
/* the bitmap flow is from top to bottom, */
/* but y is measured from bottom to top */
if ( target - > pitch < 0 )
{
/* XXX */
}
else
{
unsigned char * p =
target - > buffer ;
unsigned char * q =
buffer +
( final_rows - y - target - > rows ) * new_pitch +
x * 4 ;
unsigned char * limit_p =
p + pitch * ( int ) target - > rows ;
while ( p < limit_p )
{
FT_MEM_COPY ( q , p , pitch ) ;
p + = pitch ;
q + = new_pitch ;
}
}
FT_FREE ( target - > buffer ) ;
target - > width = final_width ;
target - > rows = final_rows ;
if ( target - > pitch < 0 )
target - > pitch = - new_pitch ;
else
target - > pitch = new_pitch ;
target - > buffer = buffer ;
}
/* adjust source bitmap if necessary */
if ( source_ - > pixel_mode ! = FT_PIXEL_MODE_GRAY )
{
FT_Bitmap_Init ( & source_bitmap ) ;
error = FT_Bitmap_Convert ( library , source_ , & source_bitmap , 1 ) ;
if ( error )
goto Error ;
source = & source_bitmap ;
free_source_bitmap = 1 ;
}
else
source = source_ ;
/* do blending; the code below returns pre-multiplied channels, */
/* similar to what FreeType gets from `CBDT' tables */
x = source_llx > > 6 ;
y = source_lly > > 6 ;
/* XXX handle `frac_offset' */
/* the bitmap flow is from top to bottom, */
/* but y is measured from bottom to top */
if ( target - > pitch < 0 )
{
/* XXX */
}
else
{
unsigned char * p =
source - > buffer ;
unsigned char * q =
target - > buffer +
( target - > rows - y - source - > rows ) * target - > pitch +
x * 4 ;
unsigned char * limit_p =
p + source - > pitch * ( int ) source - > rows ;
while ( p < limit_p )
{
unsigned char * r = p ;
unsigned char * s = q ;
unsigned char * limit_r = r + source - > width ;
while ( r < limit_r )
{
int aa = * r + + ;
int fa = color . alpha * aa / 255 ;
int fb = color . blue * fa / 255 ;
int fg = color . green * fa / 255 ;
int fr = color . red * fa / 255 ;
int ba2 = 255 - fa ;
int bb = s [ 0 ] ;
int bg = s [ 1 ] ;
int br = s [ 2 ] ;
int ba = s [ 3 ] ;
* s + + = ( unsigned char ) ( bb * ba2 / 255 + fb ) ;
* s + + = ( unsigned char ) ( bg * ba2 / 255 + fg ) ;
* s + + = ( unsigned char ) ( br * ba2 / 255 + fr ) ;
* s + + = ( unsigned char ) ( ba * ba2 / 255 + fa ) ;
}
p + = source - > pitch ;
q + = target - > pitch ;
}
}
atarget_offset - > x = final_llx ;
atarget_offset - > y = final_lly + ( final_rows < < 6 ) ;
Error :
if ( error & & free_target_bitmap_on_error )
FT_Bitmap_Done ( library , target ) ;
if ( free_source_bitmap )
FT_Bitmap_Done ( library , & source_bitmap ) ;
return error ;
}
/* documentation is in ftbitmap.h */
FT_EXPORT_DEF ( FT_Error )