int test_get_cbox( btimer_t* timer, FT_Face face, void* user_data ) { FT_Glyph glyph; FT_BBox bbox; int i, done = 0; FT_UNUSED( user_data ); for ( i = 0; i < face->num_glyphs; i++ ) { if ( FT_Load_Glyph( face, i, load_flags ) ) continue; if ( FT_Get_Glyph( face->glyph, &glyph ) ) continue; TIMER_START( timer ); FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox ); TIMER_STOP( timer ); FT_Done_Glyph( glyph ); done++; } return done; }
Glyph::Glyph( const FT_Face& face, const FT_Glyph& glyph, size_t ind) : glyphInd(ind) { _VERBOSE("Glyph::Glyph"); FT_BBox bbox; FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_subpixels, &bbox ); setattr("width", Py::Int( face->glyph->metrics.width) ); setattr("height", Py::Int( face->glyph->metrics.height) ); setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX) ); setattr("horiBearingY", Py::Int( face->glyph->metrics.horiBearingY) ); setattr("horiAdvance", Py::Int( face->glyph->metrics.horiAdvance) ); setattr("vertBearingX", Py::Int( face->glyph->metrics.vertBearingX) ); setattr("vertBearingY", Py::Int( face->glyph->metrics.vertBearingY) ); setattr("vertAdvance", Py::Int( face->glyph->metrics.vertAdvance) ); Py::Tuple abbox(4); abbox[0] = Py::Int(bbox.xMin); abbox[1] = Py::Int(bbox.yMin); abbox[2] = Py::Int(bbox.xMax); abbox[3] = Py::Int(bbox.yMax); setattr("bbox", abbox); }
static FT_Error freetype2_get_glyph_size(PFontFreetype pf, FT_Face face, int glyph_index, int *padvance, int *pascent, int *pdescent) { FT_Error error; error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) return error; if (padvance) *padvance = ROUND_26_6_TO_INT(face->glyph->advance.x); if (pascent || pdescent) { FT_Glyph glyph; FT_BBox bbox; error = FT_Get_Glyph(face->glyph, &glyph); if (error) return error; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bbox); FT_Done_Glyph(glyph); if (pascent) *pascent = bbox.yMax; if (pdescent) *pdescent = -bbox.yMin; } return 0; }
bound_box bbox() const {//in 1/64th units FT_BBox bb; //FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_GRIDFIT, &bb ); //FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_TRUNCATE, &bb ); FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_PIXELS, &bb ); return bound_box(bb); }
bool font_face::glyph_dimensions(glyph_info & glyph) const { FT_Vector pen; pen.x = 0; pen.y = 0; FT_Set_Transform(face_, 0, &pen); if (FT_Load_Glyph(face_, glyph.glyph_index, FT_LOAD_NO_HINTING)) { MAPNIK_LOG_ERROR(font_face) << "FT_Load_Glyph failed"; return false; } FT_Glyph image; if (FT_Get_Glyph(face_->glyph, &image)) { MAPNIK_LOG_ERROR(font_face) << "FT_Get_Glyph failed"; return false; } FT_BBox glyph_bbox; FT_Glyph_Get_CBox(image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox); FT_Done_Glyph(image); glyph.unscaled_ymin = glyph_bbox.yMin; glyph.unscaled_ymax = glyph_bbox.yMax; glyph.unscaled_advance = face_->glyph->advance.x; glyph.unscaled_line_height = face_->size->metrics.height; glyph.unscaled_ascender = unscaled_ascender_; return true; }
//http://www.freetype.org/freetype2/docs/tutorial/step2.html FT_Error measure_string(FT_Face face, std::string text, int size, Vector2i* size_out) { int pos_x = 0; bool use_kerning = FT_HAS_KERNING(face) ? true : false; FT_UInt prev_glyph_index = 0; FT_BBox text_bb; text_bb.xMax = 0; text_bb.xMin = 0; text_bb.yMax = 0; text_bb.yMin = 0; FT_Error error; error = FT_Set_Char_Size(face, 0, size * 64, 72, 72); for(unsigned int i = 0; i < text.length(); i++) { FT_UInt glyph_index = FT_Get_Char_Index(face, text.c_str()[i]); if(use_kerning && prev_glyph_index) { FT_Vector delta; FT_Get_Kerning(face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta); pos_x += delta.x >> 6; } prev_glyph_index = glyph_index; if(error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) != FT_Err_Ok) { Log::Error(__FILE__, "Unable to load glyph %d", glyph_index); return error; } FT_Glyph glyph; if(error = FT_Get_Glyph(face->glyph, &glyph) != FT_Err_Ok) { Log::Error(__FILE__, "Unable to get glyph %d", glyph_index); } FT_BBox bb; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bb); bb.xMax += pos_x; bb.xMin += pos_x; pos_x += glyph->advance.x >> 16; //Grow overall bounding box if(bb.xMax > text_bb.xMax) text_bb.xMax = bb.xMax; if(bb.yMax > text_bb.yMax) text_bb.yMax = bb.yMax; if(bb.xMin < text_bb.xMin) text_bb.xMin = bb.xMin; if(bb.yMin < text_bb.yMin) text_bb.yMin = bb.yMin; FT_Done_Glyph(glyph); }
void CBitmapFont::generateGlyph(U32 ch){ S32 pad = 3; FT_GlyphSlot slot = mFace->glyph; FT_Glyph glyph; FT_UInt glyph_index; glyph_index = FT_Get_Char_Index( mFace, (FT_ULong)ch ); FT_Load_Glyph( mFace, glyph_index, FT_LOAD_DEFAULT); FT_Get_Glyph( slot, &glyph); FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0 ,1); FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; FT_Bitmap* source = &bitmap->bitmap; S32 srcWidth = source->width; S32 srcHeight = source->rows; S32 srcPitch = source->pitch; S32 dstWidth = srcWidth; S32 dstHeight = srcHeight; S32 dstPitch = srcPitch; FT_BBox bbox; FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_pixels, &bbox); unsigned char *src = source->buffer; if(pen.x + srcWidth >= mTextureSize){ pen.x = 0; pen.y += (getFontSize() * 64.0f / dpi) + pad; } glBindTexture(GL_TEXTURE_2D, curTex);checkGLError(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);checkGLError(); glTexSubImage2D(GL_TEXTURE_2D, 0, pen.x, pen.y, srcWidth, srcHeight, GL_ALPHA, GL_UNSIGNED_BYTE, src); checkGLError(); CTexCoord start(pen); start /= mTextureSize; CTexCoord end(pen.x + srcWidth, pen.y + srcHeight); end /= mTextureSize; //CVector2 pos(slot->bitmap_left, slot->bitmap_top); CVector2 pos(bitmap->left, srcHeight - bitmap->top); CVector2 size(srcWidth, srcHeight); CVector2 advance(slot->advance.x >> 6, slot->advance.y >> 6); mGlyphs[glyph_index] = new CBitmapGlyph(curTex, start, end, pos, size, advance); pen.x += srcWidth + pad; FT_Done_Glyph(glyph); }
void drawText(const char *string,float startx,float starty) { float PosArray[20][2]; float TexArray[20][2]; float ScaArray[20][2]; int count = 0; glUniform1i(TextUniform,1); glUniform2f(TextScaleUniform,width,height); glUniform2f(ScaleUniform,0.005,0.005); while(*string && count < 20) { FT_BBox bbox; FT_Glyph_Get_CBox( (FT_Glyph) glyphs[*string -32], FT_GLYPH_BBOX_PIXELS, &bbox ); PosArray[count][0] = startx; PosArray[count][1] = starty + (int) bbox.yMin/200.0; TexArray[count][0] = glyphsPos[*string -32].x; TexArray[count][1] = glyphsPos[*string -32].y; ScaArray[count][0] = glyphs[*string -32]->bitmap.width; ScaArray[count][1] = glyphs[*string -32]->bitmap.rows; startx += ((FT_Glyph) glyphs[*string -32])->advance.x/(65532.0) * 0.005; string++, count++; } glDisableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2 * sizeof(GLfloat),PosArray); glVertexAttribPointer((GLuint) 0,2,GL_FLOAT,GL_FALSE,0,0); glEnableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER,vbo[1]); glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2 * sizeof(GLfloat),TexArray); glVertexAttribPointer((GLuint) 1,2,GL_FLOAT,GL_FALSE,0,0); glEnableVertexAttribArray(1); glDisableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER,vbo[2]); glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2* sizeof(GLfloat),ScaArray); glVertexAttribPointer((GLuint) 2,2,GL_FLOAT,GL_FALSE,0,0); glEnableVertexAttribArray(2); glDrawElements(GL_POINTS,count,GL_UNSIGNED_BYTE,0); glUniform1i(TextUniform,0); }
void SubtitleRenderer:: initialize_fonts(const std::string& font_path, float font_size) { ENFORCE(!FT_Init_FreeType(&ft_library_)); ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_), "Unable to open font"); ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size*screen_height_)); auto get_bbox = [this](char32_t cp) { auto glyph_index = FT_Get_Char_Index(ft_face_, cp); ENFORCE(!FT_Load_Glyph(ft_face_, glyph_index, FT_LOAD_NO_HINTING)); FT_Glyph glyph; ENFORCE(!FT_Get_Glyph(ft_face_->glyph, &glyph)); SCOPE_EXIT {FT_Done_Glyph(glyph);}; FT_BBox bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); return bbox; }; constexpr float padding_factor = 0.05f; int y_min = get_bbox('g').yMin; int y_max = get_bbox('M').yMax; y_max += -y_min*0.7f; line_height_ = y_max - y_min; const int v_padding = line_height_*padding_factor + 0.5f; line_height_ += v_padding*2; box_offset_ = y_min-v_padding; box_h_padding_ = line_height_/5.0f + 0.5f; constexpr float border_thickness = 0.045f; ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_)); FT_Stroker_Set(ft_stroker_, line_height_*border_thickness*64.0f, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); vgSeti(VG_FILTER_FORMAT_LINEAR, VG_TRUE); assert(!vgGetError()); vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED); assert(!vgGetError()); auto create_vg_font = [](VGFont& font) { font = vgCreateFont(128); ENFORCE(font); }; create_vg_font(vg_font_); create_vg_font(vg_font_border_); }
/** * Load glyphs corresponding to the UTF-32 codepoint code. */ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code) { DrawTextContext *s = ctx->priv; Glyph *glyph; struct AVTreeNode *node = NULL; int ret; /* load glyph into s->face->glyph */ if (FT_Load_Char(s->face, code, s->ft_load_flags)) return AVERROR(EINVAL); /* save glyph */ if (!(glyph = av_mallocz(sizeof(*glyph))) || !(glyph->glyph = av_mallocz(sizeof(*glyph->glyph)))) { ret = AVERROR(ENOMEM); goto error; } glyph->code = code; if (FT_Get_Glyph(s->face->glyph, glyph->glyph)) { ret = AVERROR(EINVAL); goto error; } glyph->bitmap = s->face->glyph->bitmap; glyph->bitmap_left = s->face->glyph->bitmap_left; glyph->bitmap_top = s->face->glyph->bitmap_top; glyph->advance = s->face->glyph->advance.x >> 6; /* measure text height to calculate text_height (or the maximum text height) */ FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox); /* cache the newly created glyph */ if (!(node = av_tree_node_alloc())) { ret = AVERROR(ENOMEM); goto error; } av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node); if (glyph_ptr) *glyph_ptr = glyph; return 0; error: if (glyph) av_freep(&glyph->glyph); av_freep(&glyph); av_freep(&node); return ret; }
static int check_glyph_area(ASS_Library *library, FT_Glyph glyph) { FT_BBox bbox; long long dx, dy; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox); dx = bbox.xMax - bbox.xMin; dy = bbox.yMax - bbox.yMin; if (dx * dy > 8000000) { ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", (int) dx, (int) dy); return 1; } else return 0; }
Py::Object FT2Font::draw_glyphs_to_bitmap(const Py::Tuple & args) { _VERBOSE("FT2Font::draw_glyphs_to_bitmap"); args.verify_length(0); FT_BBox string_bbox = compute_string_bbox(); image.width = (string_bbox.xMax-string_bbox.xMin) / 64+2; image.height = (string_bbox.yMax-string_bbox.yMin) / 64+2; image.offsetx = (int)(string_bbox.xMin/64.0); if (angle==0) image.offsety = -image.height; else image.offsety = (int)(-string_bbox.yMax/64.0); size_t numBytes = image.width*image.height; delete [] image.buffer; image.buffer = new unsigned char [numBytes]; for (size_t n=0; n<numBytes; n++) image.buffer[n] = 0; for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox bbox; FT_Glyph_Get_CBox(glyphs[n], ft_glyph_bbox_pixels, &bbox); error = FT_Glyph_To_Bitmap(&glyphs[n], ft_render_mode_normal, 0, //&pos[n], 1 //destroy image; ); if (error) throw Py::RuntimeError("Could not convert glyph to bitmap"); FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n]; /* now, draw to our target surface (convert position) */ //bitmap left and top in pixel, string bbox in subpixel draw_bitmap( &bitmap->bitmap, bitmap->left-string_bbox.xMin/64, string_bbox.yMax/64-bitmap->top+1 ); } return Py::Object(); }
font_face_set::dimension_t font_face_set::character_dimensions(const unsigned c) { std::map<unsigned, dimension_t>::const_iterator itr; itr = dimension_cache_.find(c); if (itr != dimension_cache_.end()) { return itr->second; } FT_Matrix matrix; FT_Vector pen; FT_Error error; pen.x = 0; pen.y = 0; FT_BBox glyph_bbox; FT_Glyph image; glyph_ptr glyph = get_glyph(c); FT_Face face = glyph->get_face()->get_face(); matrix.xx = (FT_Fixed)( 1 * 0x10000L ); matrix.xy = (FT_Fixed)( 0 * 0x10000L ); matrix.yx = (FT_Fixed)( 0 * 0x10000L ); matrix.yy = (FT_Fixed)( 1 * 0x10000L ); FT_Set_Transform(face, &matrix, &pen); error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING); if ( error ) return dimension_t(0, 0, 0); error = FT_Get_Glyph(face->glyph, &image); if ( error ) return dimension_t(0, 0, 0); FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox); FT_Done_Glyph(image); unsigned tempx = face->glyph->advance.x >> 6; //std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl; dimension_t dim(tempx, glyph_bbox.yMax, glyph_bbox.yMin); //dimension_cache_[c] = dim; would need an default constructor for dimension_t dimension_cache_.insert(std::pair<unsigned, dimension_t>(c, dim)); return dim; }
char_info font_face_set::character_dimensions(const unsigned c) { //Check if char is already in cache std::map<unsigned, char_info>::const_iterator itr; itr = dimension_cache_.find(c); if (itr != dimension_cache_.end()) { return itr->second; } FT_Matrix matrix; FT_Vector pen; FT_Error error; pen.x = 0; pen.y = 0; FT_BBox glyph_bbox; FT_Glyph image; glyph_ptr glyph = get_glyph(c); FT_Face face = glyph->get_face()->get_face(); matrix.xx = (FT_Fixed)( 1 * 0x10000L ); matrix.xy = (FT_Fixed)( 0 * 0x10000L ); matrix.yx = (FT_Fixed)( 0 * 0x10000L ); matrix.yy = (FT_Fixed)( 1 * 0x10000L ); FT_Set_Transform(face, &matrix, &pen); error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING); if ( error ) return char_info(); error = FT_Get_Glyph(face->glyph, &image); if ( error ) return char_info(); FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox); FT_Done_Glyph(image); unsigned tempx = face->glyph->advance.x >> 6; char_info dim(c, tempx, glyph_bbox.yMax, glyph_bbox.yMin, face->size->metrics.height/64.0 /* >> 6 */); dimension_cache_.insert(std::pair<unsigned, char_info>(c, dim)); return dim; }
void SubtitleRenderer:: initialize_fonts(const std::string& font_path, const std::string& italic_font_path, unsigned int font_size) { ENFORCE(!FT_Init_FreeType(&ft_library_)); ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_), "Unable to open font"); ENFORCE2(!FT_New_Face(ft_library_, italic_font_path.c_str(), 0, &ft_face_italic_), "Unable to open italic font"); ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size)); ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size)); auto get_bbox = [this](char32_t cp) { auto glyph_index = FT_Get_Char_Index(ft_face_, cp); ENFORCE(!FT_Load_Glyph(ft_face_, glyph_index, FT_LOAD_NO_HINTING)); FT_Glyph glyph; ENFORCE(!FT_Get_Glyph(ft_face_->glyph, &glyph)); SCOPE_EXIT {FT_Done_Glyph(glyph);}; FT_BBox bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); return bbox; }; constexpr float padding_factor = 0.05f; int y_min = get_bbox('g').yMin; int y_max = get_bbox('M').yMax; y_max += -y_min*0.7f; line_height_ = y_max - y_min; const int v_padding = line_height_*padding_factor + 0.5f; line_height_ += v_padding*2; box_offset_ = y_min-v_padding; box_h_padding_ = line_height_/5.0f + 0.5f; constexpr float border_thickness = 0.044f; ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_)); FT_Stroker_Set(ft_stroker_, line_height_*border_thickness*64.0f, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); }
void ComputeStringBox( FT_BBox& Box, FT_Glyph* GlyphList,FT_Vector* PosList, const int GlyphCount ) { /* initialize string bbox to "empty" values */ Box.xMin = Box.yMin = 32000; Box.xMax = Box.yMax = -32000; /* for each glyph image, compute its bounding box, */ /* translate it, and grow the string bbox */ for ( int n = 0; n < GlyphCount; n++ ) { FT_BBox GlyphBox; FT_Glyph_Get_CBox( GlyphList[n], ft_glyph_bbox_pixels, &GlyphBox ); GlyphBox.xMin += PosList[n].x; GlyphBox.xMax += PosList[n].x; GlyphBox.yMin += PosList[n].y; GlyphBox.yMax += PosList[n].y; if ( GlyphBox.xMin < Box.xMin ) Box.xMin = GlyphBox.xMin; if ( GlyphBox.yMin < Box.yMin ) Box.yMin = GlyphBox.yMin; if ( GlyphBox.xMax > Box.xMax ) Box.xMax = GlyphBox.xMax; if ( GlyphBox.yMax > Box.yMax ) Box.yMax = GlyphBox.yMax; } /* check that we really grew the string bbox */ if ( Box.xMin > Box.xMax ) { Box.xMin = 0; Box.yMin = 0; Box.xMax = 0; Box.yMax = 0; } };
void XeTeXFontInst_FT2::getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox) { bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0; FT_Error err = FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE); if (err != 0) return; FT_Glyph glyph; err = FT_Get_Glyph(face->glyph, &glyph); if (err == 0) { FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox); bbox->xMin = ft_bbox.xMin * fPointSize / fUnitsPerEM; bbox->yMin = ft_bbox.yMin * fPointSize / fUnitsPerEM; bbox->xMax = ft_bbox.xMax * fPointSize / fUnitsPerEM; bbox->yMax = ft_bbox.yMax * fPointSize / fUnitsPerEM; FT_Done_Glyph(glyph); } }
void XeTeXFontInst::getGlyphBounds(GlyphID gid, GlyphBBox* bbox) { bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0; FT_Error error = FT_Load_Glyph(m_ftFace, gid, FT_LOAD_NO_SCALE); if (error) return; FT_Glyph glyph; error = FT_Get_Glyph(m_ftFace->glyph, &glyph); if (error == 0) { FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox); bbox->xMin = unitsToPoints(ft_bbox.xMin); bbox->yMin = unitsToPoints(ft_bbox.yMin); bbox->xMax = unitsToPoints(ft_bbox.xMax); bbox->yMax = unitsToPoints(ft_bbox.yMax); FT_Done_Glyph(glyph); } }
Size FontEngine_Freetype::get_size(const std::string &text, int pos) { FT_UInt glyph_index; // Get glyph index glyph_index = FT_Get_Char_Index(face, text[pos]); // Load glyph image FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT ); if (error) return Size(0,0); FT_Glyph glyph; FT_BBox bbox; FT_Get_Glyph(face->glyph, &glyph); FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox ); int y = bbox.yMax + bbox.yMin; // Include the whitespace, to match the windows GetTextExtentPoint32() int x = int(face->glyph->advance.x / 64.0f); return (Size(x,y)); }
static void compute_glyphstring_bbox(FT_Glyph *string, FT_Vector *pos, int len, FT_BBox *bbox) { FT_BBox glyph_bbox; int i; bbox->xMin = bbox->yMin = 32000; bbox->xMax = bbox->yMax = -32000; for (i = 0; i < len; i++) { FT_Glyph_Get_CBox(string[i], FT_GLYPH_BBOX_GRIDFIT, &glyph_bbox); glyph_bbox.xMin += pos[i].x; glyph_bbox.xMax += pos[i].x; glyph_bbox.yMin += pos[i].y; glyph_bbox.yMax += pos[i].y; 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; } if (bbox->xMin > bbox->xMax || bbox->yMin > bbox->yMax) { bbox->xMin = 0; bbox->xMax = 0; bbox->yMin = 0; bbox->yMax = 0; } }
void calculate_extents(box* b, hb_glyph_info_t glyph_info, hb_glyph_position_t glyph_pos, FT_Face ft_face, double point_size, hb_direction_t direction) { FT_Error error = FT_Load_Glyph(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE); if (error) return; FT_Glyph glyph; error = FT_Get_Glyph(ft_face->glyph, &glyph); if (error) return; FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox); FT_Fixed advance; FT_Get_Advance(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE, &advance); const FT_Glyph_Metrics *ftmetrics = &ft_face->glyph->metrics; b->width = advance * point_size / ft_face->units_per_EM; if (direction == HB_DIRECTION_TTB) { FT_Get_Advance(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE | FT_LOAD_VERTICAL_LAYOUT, &advance); b->height = advance * point_size / ft_face->units_per_EM; b->depth = 0; } else { b->height = ft_bbox.yMax * point_size / ft_face->units_per_EM; b->depth = -ft_bbox.yMin * point_size / ft_face->units_per_EM; } FT_Done_Glyph(glyph); }
FT_BBox FT2Font::compute_string_bbox( ) { _VERBOSE("FT2Font::compute_string_bbox"); FT_BBox bbox; /* initialize string bbox to "empty" values */ bbox.xMin = bbox.yMin = 32000; bbox.xMax = bbox.yMax = -32000; for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox glyph_bbox; FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_subpixels, &glyph_bbox ); if ( glyph_bbox.xMin < bbox.xMin ) bbox.xMin = glyph_bbox.xMin; if ( glyph_bbox.yMin < bbox.yMin ) bbox.yMin = glyph_bbox.yMin; if ( glyph_bbox.xMax > bbox.xMax ) bbox.xMax = glyph_bbox.xMax; if ( glyph_bbox.yMax > bbox.yMax ) bbox.yMax = glyph_bbox.yMax; } /* check that we really grew the string bbox */ if ( bbox.xMin > bbox.xMax ) { bbox.xMin = 0; bbox.yMin = 0; bbox.xMax = 0; bbox.yMax = 0; } /* return string bbox */ return bbox; }
// https://github.com/mapnik/mapnik/issues/2578 double font_face::get_ascender() { set_unscaled_character_sizes(); unsigned glyph_index = FT_Get_Char_Index(face_, 'X'); FT_Vector pen; pen.x = 0; pen.y = 0; FT_Set_Transform(face_, 0, &pen); int e = 0; if (!(e = FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_HINTING))) { FT_Glyph image; if (!FT_Get_Glyph(face_->glyph, &image)) { FT_BBox glyph_bbox; FT_Glyph_Get_CBox(image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox); FT_Done_Glyph(image); return 64.0 * (glyph_bbox.yMax - glyph_bbox.yMin); } } return face_->ascender; }
void FT::computeBBox(ft_string *string) { int n; /* initialize string bbox to "empty" values */ string->bbox.xMin = string->bbox.yMin = 32000; string->bbox.xMax = string->bbox.yMax = -32000; /* for each glyph image, compute its bounding box, */ /* translate it, and grow the string bbox */ for (n = 0; n < string->num_glyphs; n++) { FT_BBox glyph_bbox; FT_Glyph_Get_CBox(string->glyphs[n].image, ft_glyph_bbox_pixels, &glyph_bbox); if (glyph_bbox.xMin < string->bbox.xMin) string->bbox.xMin = glyph_bbox.xMin; if (glyph_bbox.yMin < string->bbox.yMin) string->bbox.yMin = glyph_bbox.yMin; if (glyph_bbox.xMax > string->bbox.xMax) string->bbox.xMax = glyph_bbox.xMax; if (glyph_bbox.yMax > string->bbox.yMax) string->bbox.yMax = glyph_bbox.yMax; } /* check that we really grew the string bbox */ if (string->bbox.xMin > string->bbox.xMax) { string->bbox.xMin = 0; string->bbox.yMin = 0; string->bbox.xMax = 0; string->bbox.yMax = 0; } }
static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name) { GF_Glyph *glyph; u32 glyph_idx; FT_BBox bbox; FT_OutlineGlyph outline; ft_outliner outl; FT_Outline_Funcs ft_outl_funcs; FTBuilder *ftpriv = (FTBuilder *)dr->udta; if (!ftpriv->active_face || !glyph_name) return NULL; FT_Select_Charmap(ftpriv->active_face, FT_ENCODING_UNICODE); glyph_idx = FT_Get_Char_Index(ftpriv->active_face, glyph_name); /*missing glyph*/ if (!glyph_idx) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FreeType] Glyph not found for char %d in font %s (style %s)\n", glyph_name, ftpriv->active_face->family_name, ftpriv->active_face->style_name)); return NULL; } /*work in design units*/ FT_Load_Glyph(ftpriv->active_face, glyph_idx, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); FT_Get_Glyph(ftpriv->active_face->glyph, (FT_Glyph*)&outline); #ifdef FT_GLYPH_FORMAT_OUTLINE /*oops not vectorial...*/ if (outline->root.format != FT_GLYPH_FORMAT_OUTLINE) return NULL; #endif GF_SAFEALLOC(glyph, GF_Glyph); GF_SAFEALLOC(glyph->path, GF_Path); /*setup outliner*/ ft_outl_funcs.shift = 0; ft_outl_funcs.delta = 0; ft_outl_funcs.move_to = ft_move_to; ft_outl_funcs.line_to = ft_line_to; ft_outl_funcs.conic_to = ft_conic_to; ft_outl_funcs.cubic_to = ft_cubic_to; outl.path = glyph->path; outl.ftpriv = ftpriv; /*FreeType is marvelous and gives back the right advance on space char !!!*/ FT_Outline_Decompose(&outline->outline, &ft_outl_funcs, &outl); FT_Glyph_Get_CBox((FT_Glyph) outline, ft_glyph_bbox_unscaled, &bbox); glyph->ID = glyph_name; glyph->utf_name = glyph_name; glyph->horiz_advance = ftpriv->active_face->glyph->metrics.horiAdvance; glyph->vert_advance = ftpriv->active_face->glyph->metrics.vertAdvance; /* glyph->x = bbox.xMin; glyph->y = bbox.yMax; */ glyph->width = ftpriv->active_face->glyph->metrics.width; glyph->height = ftpriv->active_face->glyph->metrics.height; FT_Done_Glyph((FT_Glyph) outline); return glyph; }
/** * Load glyphs corresponding to the UTF-32 codepoint code. */ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code) { DrawTextContext *s = ctx->priv; FT_BitmapGlyph bitmapglyph; Glyph *glyph; struct AVTreeNode *node = NULL; int ret; /* load glyph into s->face->glyph */ if (FT_Load_Char(s->face, code, s->ft_load_flags)) return AVERROR(EINVAL); glyph = av_mallocz(sizeof(*glyph)); if (!glyph) { ret = AVERROR(ENOMEM); goto error; } glyph->code = code; if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) { ret = AVERROR(EINVAL); goto error; } if (s->borderw) { glyph->border_glyph = glyph->glyph; if (FT_Glyph_StrokeBorder(&glyph->border_glyph, s->stroker, 0, 0) || FT_Glyph_To_Bitmap(&glyph->border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) { ret = AVERROR_EXTERNAL; goto error; } bitmapglyph = (FT_BitmapGlyph) glyph->border_glyph; glyph->border_bitmap = bitmapglyph->bitmap; } if (FT_Glyph_To_Bitmap(&glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) { ret = AVERROR_EXTERNAL; goto error; } bitmapglyph = (FT_BitmapGlyph) glyph->glyph; glyph->bitmap = bitmapglyph->bitmap; glyph->bitmap_left = bitmapglyph->left; glyph->bitmap_top = bitmapglyph->top; glyph->advance = s->face->glyph->advance.x >> 6; /* measure text height to calculate text_height (or the maximum text height) */ FT_Glyph_Get_CBox(glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox); /* cache the newly created glyph */ if (!(node = av_tree_node_alloc())) { ret = AVERROR(ENOMEM); goto error; } av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node); if (glyph_ptr) *glyph_ptr = glyph; return 0; error: if (glyph) av_freep(&glyph->glyph); av_freep(&glyph); av_freep(&node); return ret; }
SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype) { FT_Face face; FT_Error error; const char* name = 0; FT_ULong charcode; FT_UInt gindex; SWFFONT* font; int t; int*glyph2glyph; int max_unicode = 0; int charmap = -1; if(ftlibrary == 0) { if(FT_Init_FreeType(&ftlibrary)) { fprintf(stderr, "Couldn't init freetype library!\n"); exit(1); } } error = FT_New_Face(ftlibrary, filename, 0, &face); if(error || !face) { fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename); return 0; } int scale = flashtype?20:1; FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale); if(face->num_glyphs <= 0) { fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs); return 0; } font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT)); font->id = -1; font->version = flashtype?3:2; font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT)); font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT)); font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0); font->encoding = FONT_ENCODING_UNICODE; font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16)); font->maxascii = 0; font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH)); if(FT_HAS_GLYPH_NAMES(face)) { font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*)); } font->layout->kerningcount = 0; name = face->family_name; if(!(name && *name)) name = FT_Get_Postscript_Name(face); if(name && *name) font->name = (U8*)strdup(name); while(1) { /* // Map Glyphs to Unicode, version 1 (quick and dirty): int t; for(t=0;t<65536;t++) { int index = FT_Get_Char_Index(face, t); if(index>=0 && index<face->num_glyphs) { if(font->glyph2ascii[index]<0) font->glyph2ascii[index] = t; } }*/ // Map Glyphs to Unicode, version 2 (much nicer): // (The third way would be the AGL algorithm, as proposed // by Werner Lemberg on [email protected]) charcode = FT_Get_First_Char(face, &gindex); while(gindex != 0) { if(gindex >= 0 && gindex<face->num_glyphs) { if(!font->glyph2ascii[gindex]) { font->glyph2ascii[gindex] = charcode; if(charcode + 1 > font->maxascii) { font->maxascii = charcode + 1; } } } charcode = FT_Get_Next_Char(face, charcode, &gindex); } /* if we didn't find a single encoding character, try the font's charmaps instead. That usually means that the encoding is no longer unicode. TODO: find a way to convert the encoding to unicode */ if(font->maxascii == 0 && charmap < face->num_charmaps - 1) { charmap++; FT_Set_Charmap(face, face->charmaps[charmap]); font->encoding = 0;//anything but unicode FIXME } else break; } if(full_unicode) font->maxascii = 65535; font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int)); for(t=0;t<font->maxascii;t++) { int g = FT_Get_Char_Index(face, t); if(!g || g>=face->num_glyphs) g = -1; font->ascii2glyph[t] = g; if(g>=0) { max_unicode = t+1; if(!font->glyph2ascii[g]) { font->glyph2ascii[g] = t; } } } font->maxascii = max_unicode; font->numchars = 0; glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int)); SRECT fontbbox = {0,0,0,0}; for(t=0; t < face->num_glyphs; t++) { FT_Glyph glyph; FT_BBox bbox; char name[128]; drawer_t draw; char hasname = 0; name[0]=0; if(FT_HAS_GLYPH_NAMES(face)) { error = FT_Get_Glyph_Name(face, t, name, 127); if(!error && name[0] && !strstr(name, "notdef")) { font->glyphnames[font->numchars] = strdup(name); hasname = 1; } } if(!font->glyph2ascii[t] && !hasname && skip_unused) { continue; } error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP); if(error) { //tends to happen with some pdfs fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error); glyph=0; if(skip_unused) continue; } else { error = FT_Get_Glyph(face->glyph, &glyph); if(error) { fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error); glyph=0; if(skip_unused) continue; } } if(glyph) FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox); else memset(&bbox, 0, sizeof(bbox)); bbox.yMin = -bbox.yMin; bbox.yMax = -bbox.yMax; if(bbox.xMax < bbox.xMin) { // swap bbox.xMax ^= bbox.xMin; bbox.xMin ^= bbox.xMax; bbox.xMax ^= bbox.xMin; } if(bbox.yMax < bbox.yMin) { // swap bbox.yMax ^= bbox.yMin; bbox.yMin ^= bbox.yMax; bbox.yMax ^= bbox.yMin; } swf_Shape01DrawerInit(&draw, 0); //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw); if(glyph) error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw); else error = 0; draw.finish(&draw); if(error) { fprintf(stderr, "Couldn't decompose glyph %d\n", t); draw.dealloc(&draw); continue; } #if 0 if(bbox.xMin > 0) { font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS; } else { font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS; } #else if(glyph) font->glyph[font->numchars].advance = glyph->advance.x*20/65536; else font->glyph[font->numchars].advance = 0; #endif SRECT b = swf_ShapeDrawerGetBBox(&draw); //font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS; //font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS; font->layout->bounds[font->numchars] = b; font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw); swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]); draw.dealloc(&draw); if(glyph) FT_Done_Glyph(glyph); font->glyph2ascii[font->numchars] = font->glyph2ascii[t]; glyph2glyph[t] = font->numchars; font->numchars++; } //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin; //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax; //font->layout->leading = font->layout->ascent + font->layout->descent; if(-fontbbox.ymin < 0) font->layout->ascent = 0; else font->layout->ascent = -fontbbox.ymin; if(fontbbox.ymax < 0) font->layout->descent = 0; else font->layout->descent = fontbbox.ymax; int leading = fontbbox.ymax - fontbbox.ymin; font->layout->leading = leading>0x7fff?0x7fff:leading; /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will have more memory allocated than just font->numchars, but only the first font->numchars are used/valid */ for(t=0;t<font->maxascii;t++) { if(font->ascii2glyph[t]>=0) { font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]]; } } rfx_free(glyph2glyph); FT_Done_Face(face); FT_Done_FreeType(ftlibrary);ftlibrary=0; return font; }
static int LayoutLine( filter_t *p_filter, paragraph_t *p_paragraph, int i_start_offset, int i_end_offset, line_desc_t **pp_line ) { if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 || i_start_offset >= i_end_offset || i_start_offset < 0 || i_start_offset >= p_paragraph->i_size || i_end_offset <= 0 || i_end_offset > p_paragraph->i_size ) { msg_Err( p_filter, "LayoutLine() invalid parameters. " "Paragraph size: %d. Runs count: %d. " "Start offset: %d. End offset: %d", p_paragraph->i_size, p_paragraph->i_runs_count, i_start_offset, i_end_offset ); return VLC_EGENERIC; } line_desc_t *p_line = NewLine( i_end_offset - i_start_offset ); if( !p_line ) return VLC_ENOMEM; filter_sys_t *p_sys = p_filter->p_sys; int i_last_run = -1; run_desc_t *p_run = 0; text_style_t *p_style = 0; FT_Face p_face = 0; FT_Vector pen = { .x = 0, .y = 0 }; int i_line_index = 0; int i_font_width = 0; int i_ul_offset = 0; int i_ul_thickness = 0; #ifdef HAVE_FRIBIDI fribidi_reorder_line( 0, p_paragraph->p_types + i_start_offset, i_end_offset - i_start_offset, 0, p_paragraph->paragraph_type, p_paragraph->p_levels + i_start_offset, 0, p_paragraph->pi_reordered_indices + i_start_offset ); #endif for( int i = i_start_offset; i < i_end_offset; ++i, ++i_line_index ) { int i_paragraph_index; #ifdef HAVE_FRIBIDI i_paragraph_index = p_paragraph->pi_reordered_indices[ i ]; #else i_paragraph_index = i; #endif line_character_t *p_ch = p_line->p_character + i_line_index; glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + i_paragraph_index; if( !p_bitmaps->p_glyph ) { --i_line_index; continue; } if( i_last_run != p_paragraph->pi_run_ids[ i_paragraph_index ] ) { i_last_run = p_paragraph->pi_run_ids[ i_paragraph_index ]; p_run = p_paragraph->p_runs + i_last_run; p_style = p_run->p_style; p_face = p_run->p_face; i_font_width = p_style->i_style_flags & STYLE_HALFWIDTH ? p_style->i_font_size / 2 : p_style->i_font_size; } FT_Vector pen_new = { .x = pen.x + p_paragraph->p_glyph_bitmaps[ i_paragraph_index ].i_x_offset, .y = pen.y + p_paragraph->p_glyph_bitmaps[ i_paragraph_index ].i_y_offset }; FT_Vector pen_shadow = { .x = pen_new.x + p_sys->f_shadow_vector_x * ( i_font_width << 6 ), .y = pen_new.y + p_sys->f_shadow_vector_y * ( p_style->i_font_size << 6 ) }; if( p_bitmaps->p_shadow ) { if( FT_Glyph_To_Bitmap( &p_bitmaps->p_shadow, FT_RENDER_MODE_NORMAL, &pen_shadow, 0 ) ) p_bitmaps->p_shadow = 0; else FT_Glyph_Get_CBox( p_bitmaps->p_shadow, ft_glyph_bbox_pixels, &p_bitmaps->shadow_bbox ); } if( p_bitmaps->p_glyph ) { if( FT_Glyph_To_Bitmap( &p_bitmaps->p_glyph, FT_RENDER_MODE_NORMAL, &pen_new, 1 ) ) { FT_Done_Glyph( p_bitmaps->p_glyph ); if( p_bitmaps->p_outline ) FT_Done_Glyph( p_bitmaps->p_outline ); if( p_bitmaps->p_shadow ) FT_Done_Glyph( p_bitmaps->p_shadow ); --i_line_index; continue; } else FT_Glyph_Get_CBox( p_bitmaps->p_glyph, ft_glyph_bbox_pixels, &p_bitmaps->glyph_bbox ); } if( p_bitmaps->p_outline ) { if( FT_Glyph_To_Bitmap( &p_bitmaps->p_outline, FT_RENDER_MODE_NORMAL, &pen_new, 1 ) ) { FT_Done_Glyph( p_bitmaps->p_outline ); p_bitmaps->p_outline = 0; } else FT_Glyph_Get_CBox( p_bitmaps->p_outline, ft_glyph_bbox_pixels, &p_bitmaps->outline_bbox ); } FixGlyph( p_bitmaps->p_glyph, &p_bitmaps->glyph_bbox, p_bitmaps->i_x_advance, p_bitmaps->i_y_advance, &pen_new ); if( p_bitmaps->p_outline ) FixGlyph( p_bitmaps->p_outline, &p_bitmaps->outline_bbox, p_bitmaps->i_x_advance, p_bitmaps->i_y_advance, &pen_new ); if( p_bitmaps->p_shadow ) FixGlyph( p_bitmaps->p_shadow, &p_bitmaps->shadow_bbox, p_bitmaps->i_x_advance, p_bitmaps->i_y_advance, &pen_shadow ); int i_line_offset = 0; int i_line_thickness = 0; text_style_t *p_glyph_style = p_paragraph->pp_styles[ i_paragraph_index ]; if( p_glyph_style->i_style_flags & (STYLE_UNDERLINE | STYLE_STRIKEOUT) ) { i_line_offset = abs( FT_FLOOR( FT_MulFix( p_face->underline_position, p_face->size->metrics.y_scale ) ) ); i_line_thickness = abs( FT_CEIL( FT_MulFix( p_face->underline_thickness, p_face->size->metrics.y_scale ) ) ); if( p_glyph_style->i_style_flags & STYLE_STRIKEOUT ) { /* Move the baseline to make it strikethrough instead of * underline. That means that strikethrough takes precedence */ i_line_offset -= abs( FT_FLOOR( FT_MulFix( p_face->descender * 2, p_face->size->metrics.y_scale ) ) ); } else if( i_line_thickness > 0 ) { p_bitmaps->glyph_bbox.yMin = __MIN( p_bitmaps->glyph_bbox.yMin, - i_line_offset - i_line_thickness ); /* The real underline thickness and position are * updated once the whole line has been parsed */ i_ul_offset = __MAX( i_ul_offset, i_line_offset ); i_ul_thickness = __MAX( i_ul_thickness, i_line_thickness ); i_line_thickness = -1; } } p_ch->p_glyph = ( FT_BitmapGlyph ) p_bitmaps->p_glyph; p_ch->p_outline = ( FT_BitmapGlyph ) p_bitmaps->p_outline; p_ch->p_shadow = ( FT_BitmapGlyph ) p_bitmaps->p_shadow; bool b_karaoke = p_paragraph->pi_karaoke_bar[ i_paragraph_index ] != 0; p_ch->i_color = b_karaoke ? ( uint32_t ) p_glyph_style->i_karaoke_background_color | p_glyph_style->i_karaoke_background_alpha << 24 : ( uint32_t ) p_glyph_style->i_font_color | p_glyph_style->i_font_alpha << 24; p_ch->i_line_thickness = i_line_thickness; p_ch->i_line_offset = i_line_offset; BBoxEnlarge( &p_line->bbox, &p_bitmaps->glyph_bbox ); if( p_bitmaps->p_outline ) BBoxEnlarge( &p_line->bbox, &p_bitmaps->outline_bbox ); if( p_bitmaps->p_shadow ) BBoxEnlarge( &p_line->bbox, &p_bitmaps->shadow_bbox ); pen.x += p_bitmaps->i_x_advance; pen.y += p_bitmaps->i_y_advance; } p_line->i_width = __MAX( 0, p_line->bbox.xMax - p_line->bbox.xMin ); p_line->i_height = __MAX( 0, p_line->bbox.yMax - p_line->bbox.yMin ); p_line->i_character_count = i_line_index; if( i_ul_thickness > 0 ) { for( int i = 0; i < p_line->i_character_count; i++ ) { line_character_t *ch = &p_line->p_character[i]; if( ch->i_line_thickness < 0 ) { ch->i_line_offset = i_ul_offset; ch->i_line_thickness = i_ul_thickness; } } } *pp_line = p_line; return VLC_SUCCESS; } static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph, int i_max_pixel_width, line_desc_t **pp_lines ) { if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 ) { msg_Err( p_filter, "LayoutParagraph() invalid parameters. " "Paragraph size: %d. Runs count %d", p_paragraph->i_size, p_paragraph->i_runs_count ); return VLC_EGENERIC; } int i_line_start = 0; FT_Pos i_width = 0; FT_Pos i_max_width = i_max_pixel_width << 6; FT_Pos i_preferred_width = 0; FT_Pos i_total_width = 0; FT_Pos i_last_space_width = 0; int i_last_space = -1; line_desc_t *p_first_line = 0; line_desc_t **pp_line = &p_first_line; for( int i = 0; i < p_paragraph->i_size; ++i ) { #ifdef HAVE_FRIBIDI p_paragraph->pi_reordered_indices[ i ] = i; #endif i_total_width += p_paragraph->p_glyph_bitmaps[ i ].i_x_advance; } int i_line_count = i_total_width / i_max_width + 1; i_preferred_width = i_total_width / i_line_count; for( int i = 0; i <= p_paragraph->i_size; ++i ) { if( i == p_paragraph->i_size ) { if( i_line_start < i ) if( LayoutLine( p_filter, p_paragraph, i_line_start, i, pp_line ) ) goto error; break; } if( p_paragraph->p_code_points[ i ] == ' ' #ifdef HAVE_FRIBIDI || p_paragraph->p_types[ i ] == FRIBIDI_TYPE_WS #endif ) { if( i_line_start == i ) { /* * Free orphaned white space glyphs not belonging to any lines. * At this point p_shadow points to either p_glyph or p_outline, * so we should not free it explicitly. */ if( p_paragraph->p_glyph_bitmaps[ i ].p_glyph ) FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_glyph ); if( p_paragraph->p_glyph_bitmaps[ i ].p_outline ) FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_outline ); i_line_start = i + 1; continue; } if( i_last_space == i - 1 ) { p_paragraph->p_glyph_bitmaps[ i - 1 ].i_x_advance = 0; i_last_space = i; continue; } i_last_space = i; i_last_space_width = i_width; } i_width += p_paragraph->p_glyph_bitmaps[ i ].i_x_advance; if( i_last_space_width >= i_preferred_width || i_width >= i_max_width ) { if( i_line_start == i ) { msg_Err( p_filter, "LayoutParagraph(): Width of single glyph exceeds maximum" ); goto error; } int i_end_offset; if( i_last_space > i_line_start ) i_end_offset = i_last_space; else i_end_offset = i; if( LayoutLine( p_filter, p_paragraph, i_line_start, i_end_offset, pp_line ) ) goto error; pp_line = &( *pp_line )->p_next; i_line_start = i_end_offset; i = i_line_start - 1; i_width = 0; i_last_space_width = 0; } } *pp_lines = p_first_line; return VLC_SUCCESS; error: for( int i = i_line_start; i < p_paragraph->i_size; ++i ) { if( p_paragraph->p_glyph_bitmaps[ i ].p_glyph ) FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_glyph ); if( p_paragraph->p_glyph_bitmaps[ i ].p_outline ) FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_outline ); } if( p_first_line ) FreeLines( p_first_line ); return VLC_EGENERIC; } int LayoutText( filter_t *p_filter, line_desc_t **pp_lines, FT_BBox *p_bbox, int *pi_max_face_height, uni_char_t *psz_text, text_style_t **pp_styles, uint32_t *pi_k_dates, int i_len ) { line_desc_t *p_first_line = 0; line_desc_t **pp_line = &p_first_line; paragraph_t *p_paragraph = 0; int i_paragraph_start = 0; int i_max_height = 0; for( int i = 0; i <= i_len; ++i ) { if( i == i_len || psz_text[ i ] == '\n' ) { if( i_paragraph_start == i ) { i_paragraph_start = i + 1; continue; } p_paragraph = NewParagraph( p_filter, i - i_paragraph_start, psz_text + i_paragraph_start, pp_styles + i_paragraph_start, pi_k_dates ? pi_k_dates + i_paragraph_start : 0, 20 ); if( !p_paragraph ) { if( p_first_line ) FreeLines( p_first_line ); return VLC_ENOMEM; } #ifdef HAVE_FRIBIDI if( AnalyzeParagraph( p_paragraph ) ) goto error; #endif if( ItemizeParagraph( p_filter, p_paragraph ) ) goto error; #if defined HAVE_HARFBUZZ if( ShapeParagraphHarfBuzz( p_filter, &p_paragraph ) ) goto error; if( LoadGlyphs( p_filter, p_paragraph, true, false ) ) goto error; #elif defined HAVE_FRIBIDI if( ShapeParagraphFriBidi( p_filter, p_paragraph ) ) goto error; if( LoadGlyphs( p_filter, p_paragraph, false, true ) ) goto error; if( RemoveZeroWidthCharacters( p_paragraph ) ) goto error; if( ZeroNsmAdvance( p_paragraph ) ) goto error; #else if( LoadGlyphs( p_filter, p_paragraph, false, true ) ) goto error; #endif /* * Set max line width to allow for outline and shadow glyphs, * and any extra width caused by visual reordering */ int i_max_width = ( int ) p_filter->fmt_out.video.i_visible_width - 2 * p_filter->p_sys->style.i_font_size; if( LayoutParagraph( p_filter, p_paragraph, i_max_width, pp_line ) ) goto error; FreeParagraph( p_paragraph ); p_paragraph = 0; for( ; *pp_line; pp_line = &( *pp_line )->p_next ) i_max_height = __MAX( i_max_height, ( *pp_line )->i_height ); i_paragraph_start = i + 1; } } int i_base_line = 0; FT_BBox bbox = { .xMin = INT_MAX, .yMin = INT_MAX, .xMax = INT_MIN, .yMax = INT_MIN }; for( line_desc_t *p_line = p_first_line; p_line; p_line = p_line->p_next ) { p_line->i_base_line = i_base_line; p_line->bbox.yMin -= i_base_line; p_line->bbox.yMax -= i_base_line; BBoxEnlarge( &bbox, &p_line->bbox ); i_base_line += i_max_height; } *pp_lines = p_first_line; *p_bbox = bbox; *pi_max_face_height = i_max_height; return VLC_SUCCESS; error: if( p_first_line ) FreeLines( p_first_line ); if( p_paragraph ) FreeParagraph( p_paragraph ); return VLC_EGENERIC; }
box2d<double> text_renderer<T>::prepare_glyphs(text_path *path) { //clear glyphs glyphs_.clear(); FT_Matrix matrix; FT_Vector pen; FT_Error error; FT_BBox bbox; bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later for (int i = 0; i < path->num_nodes(); i++) { char_info_ptr c; double x, y, angle; path->vertex(&c, &x, &y, &angle); // TODO Enable when we have support for setting verbosity // MAPNIK_LOG_DEBUG(font_engine_freetype) << "text_renderer: prepare_glyphs=" // << c << "," << x << "," << y << "," << angle; FT_BBox glyph_bbox; FT_Glyph image; pen.x = int(x * 64); pen.y = int(y * 64); face_set_ptr faces = font_manager_.get_face_set(c->format->face_name, c->format->fontset); faces->set_character_sizes(c->format->text_size); glyph_ptr glyph = faces->get_glyph(unsigned(c->c)); FT_Face face = glyph->get_face()->get_face(); matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); FT_Set_Transform(face, &matrix, &pen); error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING); if ( error ) continue; error = FT_Get_Glyph(face->glyph, &image); if ( error ) continue; FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox); if (glyph_bbox.xMin < bbox.xMin) bbox.xMin = glyph_bbox.xMin; if (glyph_bbox.yMin < bbox.yMin) bbox.yMin = glyph_bbox.yMin; if (glyph_bbox.xMax > bbox.xMax) bbox.xMax = glyph_bbox.xMax; if (glyph_bbox.yMax > bbox.yMax) bbox.yMax = glyph_bbox.yMax; // Check if we properly grew the bbox if ( bbox.xMin > bbox.xMax ) { bbox.xMin = 0; bbox.yMin = 0; bbox.xMax = 0; bbox.yMax = 0; } // take ownership of the glyph glyphs_.push_back(new glyph_t(image, c->format)); } return box2d<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax); }
static int glnames( GLYPH *glyph_list ) { #define MAX_NAMELEN 1024 #ifdef XP_PSTEXT char buf[1024]; long i; FT_Error error; #ifdef XP_ONLY_BLOCKS extern unsigned long xp_font_block_offset; extern FTFontPtr xp_xtf; int bc; /* block counter */ /* FixMe: This code should use PsOut_Get_FreeType_Glyph_Name() instead of * duplicating the code */ for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) { /* Remap X11 font index to FreeType font index */ i = FTRemap(face, &xp_xtf->mapping, bc); if( i >= face->num_glyphs ) continue; #else for(i=0; i < face->num_glyphs; i++) { #endif /* XP_ONLY_BLOCKS */ if( FT_Has_PS_Glyph_Names(face) ) { error = FT_Get_Glyph_Name(face, i, buf, MAX_NAMELEN); } else { error = -1; } if( error ) { /* Check for unicode mapping * See Adobe document "Unicode and Glyph Names" * (http://partners.adobe.com/asn/tech/type/unicodegn.jsp) */ if( (xp_xtf->mapping.mapping->type == FONT_ENCODING_UNICODE) && (i < 0xFFFE) ) { sprintf(buf, "uni%04lx", i); } else { sprintf(buf, "ch%02lx", i); } } glyph_list[i].name = strdup(buf); if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, buf); if (glyph_list[i].name == NULL) { fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); exit(255); } } return 0; #else char bf[1024]; long i; if( ! FT_HAS_GLYPH_NAMES(face) ) { WARNING_1 fprintf(stderr, "Font has no glyph names\n"); return 1; } for(i=0; i < face->num_glyphs; i++) { if( FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0 ) { sprintf(bf, "_g_%d", i); WARNING_2 fprintf(stderr, "Glyph No. %d has no postscript name, becomes %s\n", i, bf); } glyph_list[i].name = strdup(bf); if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, bf); if (glyph_list[i].name == NULL) { fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); exit(255); } } return 0; #endif /* XP_PSTEXT */ } /* * Get the metrics of the glyphs. */ static void glmetrics( GLYPH *glyph_list ) { GLYPH *g; int i; FT_Glyph_Metrics *met; FT_BBox bbox; FT_Glyph gly; #ifdef XP_ONLY_BLOCKS extern unsigned long xp_font_block_offset; extern FTFontPtr xp_xtf; int bc; /* block counter */ for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) { /* Remap X11 font index to FreeType font index */ i = FTRemap(face, &xp_xtf->mapping, bc); if( i >= face->num_glyphs ) continue; #else for(i=0; i < face->num_glyphs; i++) { #endif /* XP_ONLY_BLOCKS */ g = &(glyph_list[i]); if( FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE) ) { fprintf(stderr, "Can't load glyph %s, skipped\n", g->name); continue; } met = &face->glyph->metrics; if(FT_HAS_HORIZONTAL(face)) { g->width = met->horiAdvance; g->lsb = met->horiBearingX; } else { WARNING_2 fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name); g->width = met->width; g->lsb = 0; } if( FT_Get_Glyph(face->glyph, &gly) ) { fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name); continue; } FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox); g->xMin = bbox.xMin; g->yMin = bbox.yMin; g->xMax = bbox.xMax; g->yMax = bbox.yMax; g->ttf_pathlen = face->glyph->outline.n_points; } } /* * Get the original encoding of the font. * Returns 1 for if the original encoding is Unicode, 2 if the * original encoding is other 16-bit, 0 if 8-bit. */ static int glenc( GLYPH *glyph_list, int *encoding, int *unimap ) { #ifdef XP_PSTEXT int i, e; unsigned code; extern FTFontPtr xp_xtf; extern unsigned long xp_font_block_offset; enc_found = 1; enc_type = 0; for(i=0; i<ENCTABSZ; i++) { if(encoding[i] != -1) continue; /* Remap X11 font index to FreeType font index */ code = FTRemap(face, &xp_xtf->mapping, xp_font_block_offset+i); if(code == 0) continue; /* .notdef */ encoding[i] = code; } return enc_type; #else int i, e; unsigned code; if(ISDBG(FT)) for(e=0; e < face->num_charmaps; e++) { fprintf(stderr, "found encoding pid=%d eid=%d\n", face->charmaps[e]->platform_id, face->charmaps[e]->encoding_id); } if(enc_found) goto populate_map; enc_type = 0; /* first check for an explicit PID/EID */ if(force_pid != -1) { for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->platform_id == force_pid && face->charmaps[e]->encoding_id == force_eid) { WARNING_1 fprintf(stderr, "Found Encoding PID=%d/EID=%d\n", force_pid, force_eid); if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } enc_type = 1; goto populate_map; } } fprintf(stderr, "*** TTF encoding table PID=%d/EID=%d not found\n", force_pid, force_eid); exit(1); } /* next check for a direct Adobe mapping */ if(!forcemap) { for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->encoding == ft_encoding_adobe_custom) { WARNING_1 fputs("Found Adobe Custom Encoding\n", stderr); if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } goto populate_map; } } } for(e=0; e < face->num_charmaps; e++) { if(face->charmaps[e]->platform_id == 3) { switch(face->charmaps[e]->encoding_id) { case 0: WARNING_1 fputs("Found Symbol Encoding\n", stderr); break; case 1: WARNING_1 fputs("Found Unicode Encoding\n", stderr); enc_type = 1; break; default: WARNING_1 { fprintf(stderr, "****MS Encoding ID %d not supported****\n", face->charmaps[e]->encoding_id); fputs("Treating it like Symbol encoding\n", stderr); } break; } break; } } if(e >= face->num_charmaps) { WARNING_1 fputs("No Microsoft encoding, using first encoding available\n", stderr); e = 0; } if( FT_Set_Charmap(face, face->charmaps[e]) ) { fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); exit(1); } populate_map: enc_found = 1; for(i=0; i<ENCTABSZ; i++) { if(encoding[i] != -1) continue; if(enc_type == 1 || forcemap) { code = unimap[i]; if(code == (unsigned) -1) continue; } else code = i; code = FT_Get_Char_Index(face, code); if(0 && ISDBG(FT)) fprintf(stderr, "code of %3d is %3d\n", i, code); if(code == 0) continue; /* .notdef */ encoding[i] = code; } return enc_type; #endif /* XP_PSTEXT */ }