Following the first tutorial example with FT_Render_Glyph to render into
slot and then bitwise-or into the image buffer, I get proper kerning.
However, when I follow the deferred rendering example in the tutorial page
that uses FT_Glyph_To_Bitmap, I don't get proper kerning anymore.
I have verified that the precomputed 'pen' positions are still correct, but
they don't seem to be respected by the FT_Glyph_To_Bitmap function. In my
first pass over the glyphs, if I make a call FT_Render_Glyph, then a later
call to FT_Glyph_To_Bitmap will work properly...but this means I've
rendered every glyph redundantly. Anyone know what's going on?
Here's my code:
template<class T>
void render_text(cimgl::CImg<T> &image, unsigned px, unsigned py,
const std::string &text, const T *color, static_matrix<2,2,float> *skew =
NULL)
{
FT_GlyphSlot slot = face->glyph;
FT_UInt glyph_index;
FT_Bool use_kerning = FT_HAS_KERNING( face );
FT_UInt previous =0;
std::vector< FT_Glyph > glyphs( text.size() );
std::vector< FT_Vector > pos( text.size() );
FT_Vector pen;
pen.x = 0;
pen.y = 0;
FT_Matrix *xform = NULL;
FT_Matrix matrix;
if (skew)
{
//convert from float into 16.16 fixed format
matrix.xx = round((*skew)(0, 0)*(1 << 16));
matrix.xy = round((*skew)(0, 1)*(1 << 16));
matrix.yx = round((*skew)(1, 0)*(1 << 16));
matrix.yy = round((*skew)(1, 1)*(1 << 16));
xform = &matrix;
}
//compute bounding box...
FT_BBox bbox;
bbox.xMin = 0;
bbox.yMin = 0;
bbox.xMax = 0;
bbox.yMax = 0;
//load all the glyphs without rendering...
unsigned count = 0;
for ( int n = 0; n < text.size(); n++ )
{
// convert character code to glyph index
glyph_index = FT_Get_Char_Index( face, text[n] );
// retrieve kerning distance and move pen position
if ( use_kerning && previous && glyph_index )
{
FT_Vector delta;
FT_Get_Kerning( face, previous, glyph_index,
FT_KERNING_DEFAULT, &delta );
pen.x += delta.x;
pen.y += delta.y;
}
//store current pen position
pos[count] = pen;
//set glyph transform...
FT_Set_Transform( face, xform, &pen );
// load glyph image into the slot without rendering
int error = FT_Load_Glyph( face, glyph_index,
FT_LOAD_DEFAULT );
if ( error ) continue; // ignore errors, jump to next glyph
//if we dont do this here, then when we render later, there
is way too much white space
// not sure WHY this fixes it...but should be able to
remove the double-render.
// seems we can't save this render because it goes directly
into a temporary slot?
error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL
);
if ( error ) continue; // ignore errors, jump to next glyph
// extract glyph image and store it in our table
error = FT_Get_Glyph( face->glyph, &glyphs[count] );
if ( error ) continue; // ignore errors, jump to next glyph
//increment bounding box...
FT_BBox glyph_bbox;
FT_Glyph_Get_CBox( glyphs[count], ft_glyph_bbox_pixels,
&glyph_bbox );
//std::cout << "glyph bbox: " << glyph_bbox.xMin <<"," <<
glyph_bbox.yMin << " to " << glyph_bbox.xMax <<","<<glyph_bbox.yMax << "\n";
if( glyph_bbox.xMin < bbox.xMin )
bbox.xMin = glyph_bbox.xMin;
if( glyph_bbox.xMax > bbox.xMax )
bbox.xMax = glyph_bbox.xMax;
if( glyph_bbox.yMin < bbox.yMin )
bbox.yMin = glyph_bbox.yMin;
if( glyph_bbox.yMax > bbox.yMax )
bbox.yMax = glyph_bbox.yMax;
// increment pen position
pen.x += slot->advance.x;
pen.y += slot->advance.y;
// record current glyph index
previous = glyph_index;
++count;
}
//render each glyph and bitwise-or the intensity values into a
buffer...
int buffer_width = bbox.xMax - bbox.xMin, buffer_height =
bbox.yMax - bbox.yMin;
//std::cout << "buffer size: " << buffer_width << " x " <<
buffer_height << "\n";
unsigned char *buffer = new unsigned char[ buffer_width *
buffer_height ];
memset( buffer, 0, sizeof( buffer_width * buffer_height ) );
for ( int n = 0; n < count; n++ )
{
FT_Glyph glyph = glyphs[n];
FT_Vector pen = pos[n];
int error = FT_Glyph_To_Bitmap( &glyph,
FT_RENDER_MODE_NORMAL, &pen, 0 );
if (error) continue;
FT_BitmapGlyph bit = (FT_BitmapGlyph) glyph;
FT_Bitmap *bitmap = &(bit->bitmap);
int ix_to_bx = bit->left - bbox.xMin,
iy_to_by = (buffer_height - bit->top) - bbox.yMin;
int ix_end = std::min(buffer_width, bitmap->width +
ix_to_bx) - ix_to_bx,
iy_end = std::min(buffer_height, bitmap->rows +
iy_to_by) - iy_to_by;
for (int ix = 0; ix < ix_end; ++ix)
{
for (int iy = 0; iy < iy_end; ++iy)
{
int bx = ix + ix_to_bx, by = iy + iy_to_by;
buffer[by * buffer_width + bx] |= bitmap->buffer[iy
* bitmap->width + ix];
}
}
FT_Done_Glyph( glyph );
}
//now draw the buffer onto the image, centered over target
point, as a colored overlay
int bx_to_x = (int)px - (int)(buffer_width>>1),
by_to_y = (int)py - (int)(buffer_height>>1);
int bx_end = std::min((int)image.width, buffer_width+bx_to_x) -
bx_to_x,
by_end = std::min((int)image.height, buffer_height+by_to_y)
- by_to_y;
for(unsigned bx=0; bx<bx_end; ++bx)
for(unsigned by=0; by<by_end; ++by)
image.draw_point(bx+bx_to_x, by+by_to_y, color,
buffer[by*buffer_width + bx]/255.0f );
//free the buffer...
delete [] buffer;
}
_______________________________________________
Freetype mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/freetype