inline FT_Error fontRenderClass::getGlyphImage(FTC_Image_Desc *font, FT_ULong glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize) #endif { FT_Glyph image; FT_Error err = FTC_ImageCache_Lookup(imageCache, font, glyph_index, &image, NULL); if (err) return err; if (glyph) { err = FT_Glyph_Copy(image, glyph); if (err) return err; } if (borderglyph && bordersize) { err = FT_Glyph_Copy(image, borderglyph); if (err) return err; if (bordersize != strokerRadius) { strokerRadius = bordersize; FT_Stroker_Set(stroker, strokerRadius, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); } err = FT_Glyph_Stroke(borderglyph, stroker, 1); } return err; }
void text_renderer<T>::render_id(int feature_id, pixel_position pos, double min_radius) { FT_Error error; FT_Vector start; unsigned height = pixmap_.height(); start.x = static_cast<FT_Pos>(pos.x * (1 << 6)); start.y = static_cast<FT_Pos>((height - pos.y) * (1 << 6)); // now render transformed glyphs typename glyphs_t::iterator itr; for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { stroker_.init(std::max(itr->properties->halo_radius, min_radius)); FT_Glyph g; error = FT_Glyph_Copy(itr->image, &g); if (!error) { FT_Glyph_Transform(g,0,&start); FT_Glyph_Stroke(&g,stroker_.get(),1); error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); //error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_MONO,0,1); if ( ! error ) { FT_BitmapGlyph bit = (FT_BitmapGlyph)g; render_bitmap_id(&bit->bitmap, feature_id, bit->left, height - bit->top); } } FT_Done_Glyph(g); } }
void text_renderer<T>::render(pixel_position pos) { FT_Error error; FT_Vector start; unsigned height = pixmap_.height(); start.x = static_cast<FT_Pos>(pos.x * (1 << 6)); start.y = static_cast<FT_Pos>((height - pos.y) * (1 << 6)); // now render transformed glyphs typename glyphs_t::iterator itr; for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { double halo_radius = itr->properties->halo_radius; //make sure we've got reasonable values. if (halo_radius <= 0.0 || halo_radius > 1024.0) continue; stroker_.init(halo_radius); FT_Glyph g; error = FT_Glyph_Copy(itr->image, &g); if (!error) { FT_Glyph_Transform(g,0,&start); FT_Glyph_Stroke(&g,stroker_.get(),1); error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); if ( ! error ) { FT_BitmapGlyph bit = (FT_BitmapGlyph)g; render_bitmap(&bit->bitmap, itr->properties->halo_fill.rgba(), bit->left, height - bit->top, itr->properties->text_opacity); } } FT_Done_Glyph(g); } //render actual text for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { FT_Glyph_Transform(itr->image,0,&start); error = FT_Glyph_To_Bitmap( &(itr->image),FT_RENDER_MODE_NORMAL,0,1); if ( ! error ) { FT_BitmapGlyph bit = (FT_BitmapGlyph)itr->image; render_bitmap(&bit->bitmap, itr->properties->fill.rgba(), bit->left, height - bit->top, itr->properties->text_opacity); } } }
std::vector<Handler<BitmapGlyph> > FreeType::lookupBitmap(Font& font, float size, std::vector<unsigned int> const& ucs4, float& ascent, float& descent, float& height) { Font::RawFaceSession rfs(font); FT_Face face = rfs.face(); FT_Face face__; FTC_ScalerRec scaler; { scaler.face_id = face; scaler.width = 0; scaler.height = FLOAT_TO_26_6( size ); scaler.pixel = 0; scaler.x_res=72; //XXX scaler.y_res=72; //XXX } FTC_Manager_LookupFace(this->cache_, face, &face__); { FT_Size size; FTC_Manager_LookupSize(this->cache_, &scaler, &size); ascent = FLOAT_FROM_26_6(size->metrics.ascender); descent = FLOAT_FROM_26_6(size->metrics.descender); height = FLOAT_FROM_26_6(size->metrics.height); } std::vector<Handler<BitmapGlyph> > ret; ret.reserve(ucs4.size()); for(unsigned int const& u : ucs4) { unsigned int const gindex = FTC_CMapCache_Lookup(this->cmap_, face, font.unicodeCharmapIndex(), u); FT_Glyph glyph; { FT_Glyph glyph_orig; FTC_ImageCache_LookupScaler(this->image_, &scaler, 0, gindex, &glyph_orig, nullptr); FT_Glyph_Copy(glyph_orig, &glyph); } if(glyph->format != FT_GLYPH_FORMAT_BITMAP ) { FT_Vector_ vec; vec.x = 0; vec.y = 0; FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, &vec, 1); } ret.push_back( Handler<BitmapGlyph>(new BitmapGlyph(reinterpret_cast<FT_BitmapGlyph>(glyph))) ); } return ret; }
const bool GDI2FT_RENDERER::generate_outline_glyph( FT_Glyph* glyph, WORD glyph_index, const FTC_Scaler scaler, FT_F26Dot6 embolden, bool is_italic ) const /* -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- */ { FT_Glyph cached_glyph; { GDI2FT_MUTEX mutex( GDI2FT_MUTEX::MUTEX_FREETYPE ); if( FTC_ImageCache_LookupScaler( ft_glyph_cache, scaler, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_CROP_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_TARGET_LIGHT, glyph_index, &cached_glyph, NULL ) != 0 ) return NULL; } if( cached_glyph->format != FT_GLYPH_FORMAT_OUTLINE ) return NULL; const bool oblique = ( ( context->outline_metrics->otmTextMetrics.tmItalic != 0 ) && !is_italic ); if( oblique || embolden ) { FT_Glyph_Copy( cached_glyph, glyph ); FT_Outline* glyph_outline = &( reinterpret_cast<FT_OutlineGlyph>( *glyph )->outline ); if( oblique ) { FT_Matrix oblique_mat = { static_cast<FT_Pos>( 65536 ), static_cast<FT_Pos>( 19661 ), 0, static_cast<FT_Pos>( 65536 ) }; FT_Outline_Transform( glyph_outline, &oblique_mat ); } if( embolden ) FT_Outline_Embolden( glyph_outline, embolden ); return true; } else *glyph = cached_glyph; return false; }
void FT::drawString(ft_pixmap *pixmap, ft_string *string) { FT_Vector where; ft_char *glyph; int n, error; where.x = -string->bbox.xMin + 1; where.y = string->bbox.yMax; glyph = string->glyphs; for (n = 0; n < string->num_glyphs; ++n, ++glyph) { FT_Glyph image; FT_Vector vec; /* 26.6 */ FT_BitmapGlyph bit; // make copy to transform if (!glyph->image) { fprintf(stderr, "no image\n"); continue; } error = FT_Glyph_Copy(glyph->image, &image); if (error) { fprintf(stderr, "couldn't copy image\n"); continue; } /* transform it */ vec = glyph->pos; FT_Vector_Transform(&vec, &string->transform); bit = (FT_BitmapGlyph)image; drawBitmap(pixmap, bit, where); FT_Done_Glyph(image); } }
void agg_text_renderer<T>::render(glyph_positions const& pos) { glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; FT_Vector start_halo; int height = pixmap_.height(); pixel_position const& base_point = pos.get_base_point(); start.x = static_cast<FT_Pos>(base_point.x * (1 << 6)); start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6)); start_halo = start; start.x += transform_.tx * 64; start.y += transform_.ty * 64; start_halo.x += halo_transform_.tx * 64; start_halo.y += halo_transform_.ty * 64; FT_Matrix halo_matrix; halo_matrix.xx = halo_transform_.sx * 0x10000L; halo_matrix.xy = halo_transform_.shx * 0x10000L; halo_matrix.yy = halo_transform_.sy * 0x10000L; halo_matrix.yx = halo_transform_.shy * 0x10000L; FT_Matrix matrix; matrix.xx = transform_.sx * 0x10000L; matrix.xy = transform_.shx * 0x10000L; matrix.yy = transform_.sy * 0x10000L; matrix.yx = transform_.shy * 0x10000L; // default formatting double halo_radius = 0; color black(0,0,0); unsigned fill = black.rgba(); unsigned halo_fill = black.rgba(); double text_opacity = 1.0; double halo_opacity = 1.0; for (auto const& glyph : glyphs_) { halo_fill = glyph.properties.halo_fill.rgba(); halo_opacity = glyph.properties.halo_opacity; halo_radius = glyph.properties.halo_radius * scale_factor_; // make sure we've got reasonable values. if (halo_radius <= 0.0 || halo_radius > 1024.0) continue; FT_Glyph g; error = FT_Glyph_Copy(glyph.image, &g); if (!error) { FT_Glyph_Transform(g, &halo_matrix, &start_halo); if (rasterizer_ == HALO_RASTERIZER_FULL) { stroker_->init(halo_radius); FT_Glyph_Stroke(&g, stroker_->get(), 1); error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); composite_bitmap(pixmap_, &bit->bitmap, halo_fill, bit->left, height - bit->top, halo_opacity, halo_comp_op_); } } else { error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); render_halo(&bit->bitmap, halo_fill, bit->left, height - bit->top, halo_radius, halo_opacity, halo_comp_op_); } } } FT_Done_Glyph(g); } // render actual text for (auto & glyph : glyphs_) { fill = glyph.properties.fill.rgba(); text_opacity = glyph.properties.text_opacity; FT_Glyph_Transform(glyph.image, &matrix, &start); error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image); composite_bitmap(pixmap_, &bit->bitmap, fill, bit->left, height - bit->top, text_opacity, comp_op_); } FT_Done_Glyph(glyph.image); } }
/* * Function : libaroma_font_glyph_draw * Return Value: byte * Descriptions: draw glyph into canvas */ byte libaroma_font_glyph_draw( LIBAROMA_CANVASP dest, LIBAROMA_GLYPH aglyph_param, int x, int y, word color, byte flags, byte opacity ) { _LIBAROMA_FONT_SLOT_CACHEP aglyph = (_LIBAROMA_FONT_SLOT_CACHEP) aglyph_param; if (!aglyph) { return 0; } if (aglyph->glyph==NULL) { return 0; } if (dest == NULL) { dest = libaroma_fb()->canvas; } /* thread safe lock */ _libaroma_font_lock(1); /* copy & render */ FT_Glyph fglyph=NULL; fglyph=NULL; int cnt=0; if (FT_Glyph_Copy(aglyph->glyph, &fglyph)!=0){ _libaroma_font_lock(0); return 0; } if (cnt>0){ printf("[FT] FC: %i %i\n",cnt,aglyph->codepoint); } /* italic transform */ if (flags & _LIBAROMA_TEXTCHUNK_ITALIC) { FT_Matrix matrix; matrix.xx = 0x10000L; matrix.xy = 0x5000L; matrix.yx = 0; matrix.yy = 0x10000L; FT_Glyph_Transform(fglyph, &matrix, NULL); } /* embolden */ if (flags & _LIBAROMA_TEXTCHUNK_BOLD) { FT_Outline_Embolden( &((FT_OutlineGlyph) fglyph)->outline, aglyph->size * 2 ); } /* convert glyph to bitmap glyph */ if (FT_Glyph_To_Bitmap(&fglyph, _LIBAROMA_FONT_RENDER_FLAG, 0, 1)!=0){ /* release glyph */ printf("[FT] FR:%i\n",aglyph->codepoint); FT_Done_Glyph(fglyph); _libaroma_font_lock(0); return 0; } /* as bitmap glyph */ FT_BitmapGlyph bit = (FT_BitmapGlyph) fglyph; /* prepare locations */ /*int yy;*/ typeof(bit->bitmap.rows) yy; int xpos = x + bit->left; int xstart = 0; if (xpos < 0) { xstart = 0 - xpos; xpos = 0; } /* loop */ #ifndef LIBAROMA_CONFIG_NOFONT_SUBPIXEL int draw_w = (bit->bitmap.width / 3) - xstart; if (draw_w + xpos > dest->w) { draw_w = dest->w - xpos; } if (draw_w > 0) { wordp tmp_dst = NULL; if (opacity != 0xff) { tmp_dst = (wordp) malloc(draw_w * 2); } for (yy = 0; yy < bit->bitmap.rows; yy++) { /* drawing positions */ int yglp = (yy - bit->top); int ypos = (y + yglp) * dest->l; /* check position */ if ((ypos+draw_w>(dest->l*dest->h)) || (ypos<0)) { continue; } /* source * destination pointers */ int ysrc = yy * bit->bitmap.pitch; bytep src_line = bit->bitmap.buffer + ysrc + (xstart * 3); wordp dest_line = dest->data + ypos + xpos; /* draw line */ if (opacity == 0xff) { libaroma_alpha_multi_line( draw_w, dest_line, dest_line, color, src_line); } else { libaroma_alpha_multi_line( draw_w, tmp_dst, dest_line, color, src_line); libaroma_alpha_const( draw_w, dest_line, dest_line, tmp_dst, opacity); } } if (tmp_dst) { free(tmp_dst); } } #else int draw_w = bit->bitmap.width - xstart; if (draw_w + xpos > dest->w) { draw_w = dest->w - xpos; } if (draw_w > 0) { wordp tmp_dst = NULL; if (opacity != 0xff) { tmp_dst = (wordp) malloc(draw_w * 2); } /* line */ for (yy = 0; yy < bit->bitmap.rows; yy++) { /* drawing positions */ int yglp = (yy - bit->top); int ypos = (y + yglp) * dest->l; /* check position */ if ((ypos+draw_w>(dest->l*dest->h)) || (ypos<0)) { continue; } /* source & destination pointers */ int ysrc = yy * bit->bitmap.pitch; bytep src_line = bit->bitmap.buffer + ysrc + xstart; wordp dest_line = dest->data + ypos + xpos; /* draw line */ if (opacity == 0xff) { libaroma_alpha_mono( draw_w, dest_line, dest_line, color, src_line); } else { libaroma_alpha_mono( draw_w, tmp_dst, dest_line, color, src_line); libaroma_alpha_const( draw_w, dest_line, dest_line, tmp_dst, opacity); } } if (tmp_dst) { free(tmp_dst); } } #endif /* release glyph */ FT_Done_Glyph(fglyph); _libaroma_font_lock(0); return 1; } /* End of libaroma_font_glyph_draw */
void agg_text_renderer<T>::render(glyph_positions const& pos) { glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; int height = pixmap_.height(); pixel_position const& base_point = pos.get_base_point(); start.x = static_cast<FT_Pos>(base_point.x * (1 << 6)); start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6)); //render halo double halo_radius = 0; char_properties_ptr format; for (auto const& glyph : glyphs_) { if (glyph.properties) { format = glyph.properties; // Settings have changed. halo_radius = glyph.properties->halo_radius * scale_factor_; } // make sure we've got reasonable values. if (halo_radius <= 0.0 || halo_radius > 1024.0) continue; FT_Glyph g; error = FT_Glyph_Copy(glyph.image, &g); if (!error) { FT_Glyph_Transform(g,0,&start); if (rasterizer_ == HALO_RASTERIZER_FULL) { stroker_->init(halo_radius); FT_Glyph_Stroke(&g, stroker_->get(), 1); error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); composite_bitmap(pixmap_, &bit->bitmap, format->halo_fill.rgba(), bit->left, height - bit->top, format->text_opacity, comp_op_); } } else { error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); render_halo(&bit->bitmap, format->halo_fill.rgba(), bit->left, height - bit->top, halo_radius, format->text_opacity, comp_op_); } } } FT_Done_Glyph(g); } // render actual text for (auto & glyph : glyphs_) { if (glyph.properties) { format = glyph.properties; } FT_Glyph_Transform(glyph.image, 0, &start); error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL,0,1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image); composite_bitmap(pixmap_, &bit->bitmap, format->fill.rgba(), bit->left, height - bit->top, format->text_opacity, comp_op_); } } }
static void _alfont_cache_glyph(ALFONT_FONT *f, int glyph_number) { /* if glyph not cached yet */ if (!f->cached_glyphs[glyph_number].is_cached) { FT_Glyph new_glyph; /* load the font glyph */ FT_Load_Glyph(f->face, glyph_number, FT_LOAD_DEFAULT); FT_Get_Glyph(f->face->glyph, &new_glyph); /* ok, this glyph is now cached */ f->cached_glyphs[glyph_number].is_cached = 1; f->cached_glyphs[glyph_number].mono_available = 0; f->cached_glyphs[glyph_number].aa_available = 0; /* render the mono bmp */ { FT_Bitmap *ft_bmp; FT_Glyph glyph; FT_BitmapGlyph bmp_glyph; FT_Glyph_Copy(new_glyph, &glyph); /* only render glyph if it is not already a bitmap */ if (glyph->format != ft_glyph_format_bitmap) FT_Glyph_To_Bitmap(&glyph, ft_render_mode_mono, NULL, 1); /* the FT rendered bitmap */ bmp_glyph = (FT_BitmapGlyph)glyph; ft_bmp = &bmp_glyph->bitmap; /* save only if the bitmap is really 1 bit */ if (ft_bmp->pixel_mode == ft_pixel_mode_mono) { int memsize; f->cached_glyphs[glyph_number].mono_available = 1; /* set width, height, left, top */ f->cached_glyphs[glyph_number].width = ft_bmp->width; f->cached_glyphs[glyph_number].height = ft_bmp->rows; f->cached_glyphs[glyph_number].left = bmp_glyph->left; f->cached_glyphs[glyph_number].top = bmp_glyph->top; /* allocate bitmap */ memsize = ft_bmp->width * ft_bmp->rows * sizeof(unsigned char); if (memsize > 0) f->cached_glyphs[glyph_number].bmp = malloc(memsize); else f->cached_glyphs[glyph_number].bmp = NULL; /* monochrome drawing */ if (memsize > 0) { unsigned char *outbmp_p = f->cached_glyphs[glyph_number].bmp; unsigned char *bmp_p; int bmp_x, bmp_y, bit; /* copy the FT character bitmap to ours */ bmp_p = ft_bmp->buffer; for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) { unsigned char *next_bmp_p; next_bmp_p = bmp_p + ft_bmp->pitch; bit = 7; for (bmp_x = 0; bmp_x < ft_bmp->width; bmp_x++) { *outbmp_p = *bmp_p & (1 << bit); outbmp_p++; if (bit == 0) { bit = 7; bmp_p++; } else bit--; } bmp_p = next_bmp_p; } } } FT_Done_Glyph(glyph); } /* render the aa bmp */ { FT_Bitmap *ft_bmp; FT_Glyph glyph; FT_BitmapGlyph bmp_glyph; FT_Glyph_Copy(new_glyph, &glyph); /* only render glyph if it is not already a bitmap */ if (glyph->format != ft_glyph_format_bitmap) FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, 1); /* the FT rendered bitmap */ bmp_glyph = (FT_BitmapGlyph)glyph; ft_bmp = &bmp_glyph->bitmap; /* save only if the bitmap is really 8 bit */ if (ft_bmp->pixel_mode == ft_pixel_mode_grays) { int memsize; f->cached_glyphs[glyph_number].aa_available = 1; /* set width, height, left, top */ f->cached_glyphs[glyph_number].aawidth = ft_bmp->width; f->cached_glyphs[glyph_number].aaheight = ft_bmp->rows; f->cached_glyphs[glyph_number].aaleft = bmp_glyph->left; f->cached_glyphs[glyph_number].aatop = bmp_glyph->top; /* allocate bitmap */ memsize = ft_bmp->width * ft_bmp->rows * sizeof(unsigned char); if (memsize > 0) f->cached_glyphs[glyph_number].aabmp = malloc(memsize); else f->cached_glyphs[glyph_number].aabmp = NULL; /* aa drawing */ if (memsize > 0) { unsigned char *outbmp_p = f->cached_glyphs[glyph_number].aabmp; unsigned char *bmp_p; int bmp_y; unsigned char mul = 256 / ft_bmp->num_grays; /* we set it to 0 because it is faster to test for false */ if (mul == 1) mul = 0; /* copy the FT character bitmap to ours */ bmp_p = ft_bmp->buffer; for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) { unsigned char *next_bmp_p; next_bmp_p = bmp_p + ft_bmp->pitch; memcpy(outbmp_p, bmp_p, ft_bmp->width * sizeof(unsigned char)); /* we have to change our pixels if the numgrays is not 256 */ if (mul) { unsigned char *p = outbmp_p; unsigned char *p_end = p + ft_bmp->width; for (; p < p_end; p++) *p *= mul; } outbmp_p += ft_bmp->width; bmp_p = next_bmp_p; } } } FT_Done_Glyph(glyph); } f->cached_glyphs[glyph_number].advancex = f->face->glyph->advance.x >> 6; f->cached_glyphs[glyph_number].advancey = f->face->glyph->advance.y >> 6; /* delete the glyph */ FT_Done_Glyph(new_glyph); }
void agg_text_renderer<T>::render(glyph_positions const& pos) { prepare_glyphs(pos); FT_Error error; FT_Vector start; FT_Vector start_halo; int height = pixmap_.height(); pixel_position const& base_point = pos.get_base_point(); start.x = static_cast<FT_Pos>(base_point.x * (1 << 6)); start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6)); start_halo = start; start.x += transform_.tx * 64; start.y += transform_.ty * 64; start_halo.x += halo_transform_.tx * 64; start_halo.y += halo_transform_.ty * 64; FT_Matrix halo_matrix; halo_matrix.xx = halo_transform_.sx * 0x10000L; halo_matrix.xy = halo_transform_.shx * 0x10000L; halo_matrix.yy = halo_transform_.sy * 0x10000L; halo_matrix.yx = halo_transform_.shy * 0x10000L; FT_Matrix matrix; matrix.xx = transform_.sx * 0x10000L; matrix.xy = transform_.shx * 0x10000L; matrix.yy = transform_.sy * 0x10000L; matrix.yx = transform_.shy * 0x10000L; // default formatting double halo_radius = 0; color black(0,0,0); unsigned fill = black.rgba(); unsigned halo_fill = black.rgba(); double text_opacity = 1.0; double halo_opacity = 1.0; for (auto const& glyph : glyphs_) { halo_fill = glyph.properties.halo_fill.rgba(); halo_opacity = glyph.properties.halo_opacity; halo_radius = glyph.properties.halo_radius * scale_factor_; // make sure we've got reasonable values. if (halo_radius <= 0.0 || halo_radius > 1024.0) continue; FT_Glyph g; error = FT_Glyph_Copy(glyph.image, &g); if (!error) { FT_Glyph_Transform(g, &halo_matrix, &start_halo); if (rasterizer_ == HALO_RASTERIZER_FULL) { stroker_->init(halo_radius); FT_Glyph_Stroke(&g, stroker_->get(), 1); error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (!error) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); if (bit->bitmap.pixel_mode != FT_PIXEL_MODE_BGRA) { composite_bitmap(pixmap_, &bit->bitmap, halo_fill, bit->left, height - bit->top, halo_opacity, halo_comp_op_); } } } else { error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1); if (error) { continue; } FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g); if (bit->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) { pixel_position render_pos(base_point); image_rgba8 glyph_image(render_glyph_image(glyph, bit->bitmap, transform_, render_pos)); const constexpr std::size_t pixel_size = sizeof(image_rgba8::pixel_type); render_halo<pixel_size>(glyph_image.bytes(), glyph_image.width(), glyph_image.height(), halo_fill, render_pos.x, render_pos.y, halo_radius, halo_opacity, halo_comp_op_); } else { render_halo<1>(bit->bitmap.buffer, bit->bitmap.width, bit->bitmap.rows, halo_fill, bit->left, height - bit->top, halo_radius, halo_opacity, halo_comp_op_); } } } FT_Done_Glyph(g); } // render actual text for (auto & glyph : glyphs_) { fill = glyph.properties.fill.rgba(); text_opacity = glyph.properties.text_opacity; FT_Glyph_Transform(glyph.image, &matrix, &start); error = 0; if ( glyph.image->format != FT_GLYPH_FORMAT_BITMAP ) { error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL, 0, 1); } if (error == 0) { FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image); int pixel_mode = bit->bitmap.pixel_mode; if (pixel_mode == FT_PIXEL_MODE_BGRA) { int x = base_point.x + glyph.pos.x; int y = base_point.y - glyph.pos.y; agg::trans_affine transform( glyph_transform(transform_, bit->bitmap.rows, x, y, -glyph.rot.angle(), glyph.bbox)); composite_color_glyph(pixmap_, bit->bitmap, transform, text_opacity, comp_op_); } else { composite_bitmap(pixmap_, &bit->bitmap, fill, bit->left, height - bit->top, text_opacity, comp_op_); } } FT_Done_Glyph(glyph.image); } }