forked from minhngoc25a/freetype2
Add `FT_Bitmap_Blend' API.
Still missing: Support for negative bitmap pitch and subpixel offset of source bitmap. * include/freetype/ftbitmap.h, src/base/ftbitmap.c (FT_Bitmap_Blend): New function.
This commit is contained in:
parent
9b31c44620
commit
68bc56f864
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2018-06-16 Werner Lemberg <wl@gnu.org>
|
||||
|
||||
Add `FT_Bitmap_Blend' API.
|
||||
|
||||
Still missing: Support for negative bitmap pitch and subpixel offset
|
||||
of source bitmap.
|
||||
|
||||
* include/freetype/ftbitmap.h, src/base/ftbitmap.c
|
||||
(FT_Bitmap_Blend): New function.
|
||||
|
||||
2018-06-14 Werner Lemberg <wl@gnu.org>
|
||||
|
||||
Replace `FT_Get_GlyphLayers' with `FT_Get_Color_Glyph_Layer'.
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_COLOR_H
|
||||
|
||||
#ifdef FREETYPE_H
|
||||
#error "freetype.h of FreeType 1 has been loaded!"
|
||||
|
@ -194,6 +195,64 @@ FT_BEGIN_HEADER
|
|||
FT_Int alignment );
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
* FT_Bitmap_Blend
|
||||
*
|
||||
* @Description:
|
||||
* Blend a bitmap onto another bitmap, using a given color.
|
||||
*
|
||||
* @Input:
|
||||
* library ::
|
||||
* A handle to a library object.
|
||||
*
|
||||
* source ::
|
||||
* The source bitmap, which can have any @FT_Pixel_Mode format.
|
||||
*
|
||||
* source_offset ::
|
||||
* The offset vector to the upper left corner of the source bitmap in
|
||||
* 26.6 pixel format. This can be a fractional pixel value.
|
||||
*
|
||||
* color ::
|
||||
* The color used to draw `source' onto `target'.
|
||||
*
|
||||
* @InOut:
|
||||
* target ::
|
||||
* A handle to an `FT_Bitmap' object. It should be either initialized
|
||||
* as empty with a call to @FT_Bitmap_Init, or it should be of type
|
||||
* @FT_PIXEL_MODE_BGRA.
|
||||
*
|
||||
* atarget_offset ::
|
||||
* The offset vector to the upper left corner of the target bitmap in
|
||||
* 26.6 pixel format. It should represent an integer offset; the
|
||||
* function will set the lowest six bits to zero to enforce that.
|
||||
*
|
||||
* @Return:
|
||||
* FreeType error code. 0~means success.
|
||||
*
|
||||
* @Note:
|
||||
* This function doesn't perform clipping.
|
||||
*
|
||||
* The bitmap in `target' gets allocated or reallocated as needed; the
|
||||
* vector `atarget_offset' is updated accordingly.
|
||||
*
|
||||
* In case of allocation or reallocation, the bitmap's pitch is set to
|
||||
* `4~*~width'. Both `source' and `target' must have the same bitmap
|
||||
* flow (as indicated by the sign of the `pitch' field).
|
||||
*
|
||||
* @Since:
|
||||
* 2.10
|
||||
*/
|
||||
FT_EXPORT( 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 );
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue