freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] master 68bc56f 4/4: Add `FT_Bitmap_Blend' API.


From: Werner LEMBERG
Subject: [freetype2] master 68bc56f 4/4: Add `FT_Bitmap_Blend' API.
Date: Sat, 16 Jun 2018 03:39:54 -0400 (EDT)

branch: master
commit 68bc56f864e3e1acd00870ca04085f387b144494
Author: Werner Lemberg <address@hidden>
Commit: Werner Lemberg <address@hidden>

    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.
---
 ChangeLog                   |  10 ++
 include/freetype/ftbitmap.h |  59 +++++++++
 src/base/ftbitmap.c         | 296 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 364 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index d1559ac..00def31 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2018-06-16  Werner Lemberg  <address@hidden>
+
+       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  <address@hidden>
 
        Replace `FT_Get_GlyphLayers' with `FT_Get_Color_Glyph_Layer'.
diff --git a/include/freetype/ftbitmap.h b/include/freetype/ftbitmap.h
index 809e3bd..c2314b3 100644
--- a/include/freetype/ftbitmap.h
+++ b/include/freetype/ftbitmap.h
@@ -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!"
@@ -197,6 +198,64 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @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:
    *   FT_GlyphSlot_Own_Bitmap
    *
    * @Description:
diff --git a/src/base/ftbitmap.c b/src/base/ftbitmap.c
index 68647f8..e848e66 100644
--- a/src/base/ftbitmap.c
+++ b/src/base/ftbitmap.c
@@ -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 */
@@ -786,6 +786,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 )
   FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot  slot )
   {
     if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP   &&



reply via email to

[Prev in Thread] Current Thread [Next in Thread]