void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, const SkGlyph& glyph, SkPath* path) { if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) { emboldenOutline(face, &face->glyph->outline); } FT_Outline_Funcs funcs; funcs.move_to = move_proc; funcs.line_to = line_proc; funcs.conic_to = quad_proc; funcs.cubic_to = cubic_proc; funcs.shift = 0; funcs.delta = 0; FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path); if (err != 0) { path->reset(); return; } path->close(); }
bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance) { if (!font) return false; FT_Error error = FT_Load_Char(font->face, unicode, FT_LOAD_NO_SCALE); if (error) return false; output.contours.clear(); output.inverseYAxis = false; if (advance) *advance = font->face->glyph->advance.x/64.; FtContext context = { }; context.shape = &output; FT_Outline_Funcs ftFunctions; ftFunctions.move_to = &ftMoveTo; ftFunctions.line_to = &ftLineTo; ftFunctions.conic_to = &ftConicTo; ftFunctions.cubic_to = &ftCubicTo; ftFunctions.shift = 0; ftFunctions.delta = 0; error = FT_Outline_Decompose(&font->face->glyph->outline, &ftFunctions, &context); if (error) return false; return true; }
static void TestFace( FT_Face face ) { unsigned int gid; int load_flags = FT_LOAD_DEFAULT; if ( check_outlines && FT_IS_SCALABLE( face ) ) load_flags = FT_LOAD_NO_BITMAP; if ( nohints ) load_flags |= FT_LOAD_NO_HINTING; FT_Set_Char_Size( face, 0, font_size, 72, 72 ); for ( gid = 0; gid < face->num_glyphs; gid++ ) { if ( check_outlines && FT_IS_SCALABLE( face ) ) { if ( !FT_Load_Glyph( face, gid, load_flags ) ) FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL ); } else FT_Load_Glyph( face, gid, load_flags ); if ( rasterize ) FT_Render_Glyph( face->glyph, ft_render_mode_normal ); } FT_Done_Face( face ); }
status_t ServerFont::GetGlyphShapes(const char charArray[], int32 numChars, BShape* shapeArray[]) const { if (!charArray || numChars <= 0 || !shapeArray) return B_BAD_DATA; FT_Face face = GetTransformedFace(true, true); if (!face) return B_ERROR; FT_Outline_Funcs funcs; funcs.move_to = MoveToFunc; funcs.line_to = LineToFunc; funcs.conic_to = ConicToFunc; funcs.cubic_to = CubicToFunc; funcs.shift = 0; funcs.delta = 0; const char* string = charArray; for (int i = 0; i < numChars; i++) { shapeArray[i] = new (std::nothrow) BShape(); if (shapeArray[i] == NULL) { PutTransformedFace(face); return B_NO_MEMORY; } FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); FT_Outline outline = face->glyph->outline; FT_Outline_Decompose(&outline, &funcs, shapeArray[i]); shapeArray[i]->Close(); } PutTransformedFace(face); return B_OK; }
static void glpath( int glyphno, GLYPH *glyf_list ) { FT_Outline *ol; curg = &glyf_list[glyphno]; if( FT_Load_Glyph(face, glyphno, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE|FT_LOAD_NO_HINTING) || face->glyph->format != ft_glyph_format_outline ) { fprintf(stderr, "Can't load glyph %s, skipped\n", curg->name); return; } ol = &face->glyph->outline; lastx = 0.0; lasty = 0.0; if( FT_Outline_Decompose(ol, &ft_outl_funcs, NULL) ) { fprintf(stderr, "Can't decompose outline of glyph %s, skipped\n", curg->name); return; } /* FreeType does not do explicit closepath() */ if(curg->lastentry) { g_closepath(curg); } if(ol->flags & ft_outline_reverse_fill) { assertpath(curg->entries, __FILE__, __LINE__, curg->name); reversepaths(curg); } }
Object* Font::getGlyph (char code, const Vec2 &offset) { FT_Error ftErr; FT_Glyph ftGlyph; FT_OutlineGlyph ftOutlineGlyph; //Set glyph size FT_F26Dot6 sz = ftFloatTo266( size ); ftErr = FT_Set_Char_Size( ftFace, sz, sz, 72, 72 ); if (ftErr) { std::cout << "Error while setting char size!" << std::endl; return NULL; } //Load glyph data into font face FT_UInt ftGlyphIndex = FT_Get_Char_Index( ftFace, (FT_ULong)code ); ftErr = FT_Load_Glyph( ftFace, ftGlyphIndex, FT_LOAD_DEFAULT ); if (ftErr) { std::cout << "Error while loading glyph!" << std::endl; return NULL; } //Get glyph from glyph slot of font face ftErr = FT_Get_Glyph( ftFace->glyph, &ftGlyph ); if (ftErr) { std::cout << "Error while getting glyph from slot!" << std::endl; return NULL; } //Cast glyph to outline glyph ftOutlineGlyph = (FT_OutlineGlyph) ftGlyph; if (ftGlyph->format != FT_GLYPH_FORMAT_OUTLINE) { std::cout << "Error while casting glyph to outline glyph!" << std::endl; return NULL; } //Construct outline FT_Outline_Funcs ftFuncs; ftFuncs.move_to = ftMoveTo; ftFuncs.line_to = ftLineTo; ftFuncs.conic_to = ftQuadTo; ftFuncs.cubic_to = ftCubicTo; ftFuncs.shift = 0; ftFuncs.delta = 0; Object *object = new Object; this->object = object; this->offset = offset; ftErr = FT_Outline_Decompose( &ftOutlineGlyph->outline, &ftFuncs, this ); //Cleanup FT_Done_Glyph( ftGlyph ); return object; }
void FreeTypeFont::init() { FT_Error _error; #if 0 _error = FT_Set_Pixel_Sizes(_face, 32, 32); if (_error) { OSG_NOTICE << "FreeTypeFont3D: set pixel sizes failed ..." << std::endl; return; } #endif FT_Set_Char_Size( _face, 64*64, 64*64, 600, 600); int glyphIndex = FT_Get_Char_Index( _face, 'M' ); _error = FT_Load_Glyph( _face, glyphIndex, FT_LOAD_DEFAULT ); if (_error) { OSG_NOTICE << "FreeTypeFont3D: initial glyph load failed ..." << std::endl; return; } if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { OSG_NOTICE << "FreeTypeFont3D: not a vector font" << std::endl; return; } { FreeType::Char3DInfo char3d(10); FT_Outline outline = _face->glyph->outline; FT_Outline_Funcs funcs; funcs.conic_to = (FT_Outline_ConicToFunc)&FreeType::conicTo; funcs.line_to = (FT_Outline_LineToFunc)&FreeType::lineTo; funcs.cubic_to = (FT_Outline_CubicToFunc)&FreeType::cubicTo; funcs.move_to = (FT_Outline_MoveToFunc)&FreeType::moveTo; funcs.shift = 0; funcs.delta = 0; _error = FT_Outline_Decompose(&outline,&funcs,&char3d); if (_error) { OSG_NOTICE << "FreeTypeFont3D: - outline decompose failed ..." << std::endl; return; } FT_BBox bb; FT_Outline_Get_BBox(&outline,&bb); long ymin = ft_floor( bb.yMin ); long ymax = ft_ceiling( bb.yMax ); double height = double(ymax - ymin)/64.0; // long xmin = ft_floor( bb.xMin ); // long xmax = ft_ceiling( bb.xMax ); // double width = (xmax - xmin)/64.0; _freetype_scale = 1.0f/height; } }
void draw_bezier_outline(DiaPsRenderer *renderer, int dpi_x, FT_Face face, FT_UInt glyph_index, double pos_x, double pos_y ) { FT_Int load_flags = FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP; FT_Glyph glyph; FT_Error error; gchar px_buf[G_ASCII_DTOSTR_BUF_SIZE]; gchar py_buf[G_ASCII_DTOSTR_BUF_SIZE]; gchar d1_buf[G_ASCII_DTOSTR_BUF_SIZE]; gchar d2_buf[G_ASCII_DTOSTR_BUF_SIZE]; /* Need to transform */ /* Output outline */ FT_Outline_Funcs outlinefunc = { paps_move_to, paps_line_to, paps_conic_to, paps_cubic_to }; OutlineInfo outline_info; outline_info.glyph_origin.x = pos_x; outline_info.glyph_origin.y = pos_y; outline_info.dpi = dpi_x; outline_info.OUT = renderer->file; fprintf(renderer->file, "gsave %s %s translate %s %s scale\n", g_ascii_formatd(px_buf, sizeof(px_buf), "%f", pos_x), g_ascii_formatd(py_buf, sizeof(py_buf), "%f", pos_y), g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", 2.54/72.0), g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", -2.54/72.0) ); fprintf(renderer->file, "start_ol\n"); if ((error=FT_Load_Glyph(face, glyph_index, load_flags))) { fprintf(stderr, "Can't load glyph: %d\n", error); return; } if ((error=FT_Get_Glyph (face->glyph, &glyph))) { fprintf(stderr, "Can't get glyph: %d\n", error); FT_Done_Glyph (glyph); return; } if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline), &outlinefunc, &outline_info); fprintf(renderer->file, "end_ol grestore \n"); FT_Done_Glyph (glyph); }
/** * Converts one single glyph (character, sign) into CXF. */ FT_Error convertGlyph(FT_ULong charcode) { FT_Error error; FT_Glyph glyph; // load glyph error = FT_Load_Glyph(face, FT_Get_Char_Index(face, charcode), FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE); if (error) { std::cout << "FT_Load_Glyph: error\n"; } FT_Get_Glyph(face->glyph, &glyph); FT_OutlineGlyph og = (FT_OutlineGlyph)glyph; if (face->glyph->format != ft_glyph_format_outline) { std::cout << "not an outline font\n"; } // write glyph header if (fpLff!=NULL) { fprintf(fpLff, "\n[#%04X]\n", (uint)charcode); } // trace outline of the glyph xMin = 1000.0; firstpass = true; error = FT_Outline_Decompose(&(og->outline), &funcs, fpLff); firstpass = false; startcontour = true; error = FT_Outline_Decompose(&(og->outline), &funcs, fpLff); if (fpLff!=NULL) { fprintf(fpLff, "\n"); } if (error==FT_Err_Invalid_Outline) { std::cout << "FT_Outline_Decompose: FT_Err_Invalid_Outline\n"; } else if (error==FT_Err_Invalid_Argument) { std::cout << "FT_Outline_Decompose: FT_Err_Invalid_Argument\n"; } else if (error) { std::cout << "FT_Outline_Decompose: error: " << error << "\n"; } return error; }
/** * Converts one single glyph (character, sign) into LFF. */ FT_Error convertGlyph(FT_ULong charcode) { FT_Error error; FT_Glyph glyph; // load glyph error = FT_Load_Glyph(face, FT_Get_Char_Index(face, charcode), FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE); if (error) { std::cerr << "FT_Load_Glyph: " << FT_StrError(error) << std::endl; return error; } FT_Get_Glyph(face->glyph, &glyph); FT_OutlineGlyph og = (FT_OutlineGlyph)glyph; if (face->glyph->format != ft_glyph_format_outline) { std::cerr << "Not an outline font\n"; } // write glyph header if (fpLff) { fprintf(fpLff, "\n[#%04X]\n", (unsigned)charcode); } // trace outline of the glyph xMin = 1000.0; firstpass = true; error = FT_Outline_Decompose(&(og->outline), &funcs, fpLff); firstpass = false; startcontour = true; error = FT_Outline_Decompose(&(og->outline), &funcs, fpLff); if (fpLff) { fprintf(fpLff, "\n"); } if (error) { std::cerr << "FT_Outline_Decompose: " << FT_StrError(error) << std::endl; } return error; }
void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) { FT_Outline_Funcs funcs; funcs.move_to = move_proc; funcs.line_to = line_proc; funcs.conic_to = quad_proc; funcs.cubic_to = cubic_proc; funcs.shift = 0; funcs.delta = 0; FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path); if (err != 0) { path->reset(); return; } path->close(); }
static void addToGP(GPData* gpdata, FT_Outline*outline) { static const FT_Outline_Funcs outline_funcs = { (FT_Outline_MoveToFunc) moveTo, (FT_Outline_LineToFunc) lineTo, (FT_Outline_ConicToFunc) conicTo, (FT_Outline_CubicToFunc) cubicTo, 0, /* shift */ 0, /* delta */ }; FT_Outline_Decompose(outline, &outline_funcs, gpdata); if (gpdata->numCoords) addSeg(gpdata, SEG_CLOSE); /* If set to 1, the outline will be filled using the even-odd fill rule */ if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) { gpdata->wr = WIND_EVEN_ODD; } }
static void gimp_text_render_vectors (PangoFont *font, PangoGlyph pango_glyph, FT_Int32 flags, FT_Matrix *trafo, gint x, gint y, RenderContext *context) { const FT_Outline_Funcs outline_funcs = { moveto, lineto, conicto, cubicto, 0, 0 }; FT_Face face; FT_Glyph glyph; face = pango_fc_font_lock_face (PANGO_FC_FONT (font)); FT_Load_Glyph (face, (FT_UInt) pango_glyph, flags); FT_Get_Glyph (face->glyph, &glyph); if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_OutlineGlyph outline_glyph = (FT_OutlineGlyph) glyph; context->offset_x = (gdouble) x / PANGO_SCALE; context->offset_y = (gdouble) y / PANGO_SCALE; FT_Outline_Decompose (&outline_glyph->outline, &outline_funcs, context); } FT_Done_Glyph (glyph); pango_fc_font_unlock_face (PANGO_FC_FONT (font)); }
void SWFShape_addString(SWFShape shape, const wchar_t* str, size_t nchar, double fontSize, FT_Face face, FT_Outline_Funcs *funs) { OutlineData data; FT_Outline outline; FT_Error err; int i; data.shape = shape; data.ratio_EM = fontSize / face->units_per_EM; data.deltax = 0.0; for(i = 0; i < nchar; i++) { /* str should be Unicode */ err = FT_Load_Char(face, str[i], FT_LOAD_NO_SCALE); if(err) { errorcode(err); continue; } outline = face->glyph->outline; err = FT_Outline_Decompose(&outline, funs, &data); if(err) { errorcode(err); continue; } /* After we draw a character, we move the pen right to a distance of the advance */ /* See the picture in http://www.freetype.org/freetype2/docs/tutorial/step2.html */ data.deltax += face->glyph->metrics.horiAdvance * data.ratio_EM; } }
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; }
void draw_bezier_outline(paps_private_t *paps, GString *layout_str, FT_Face face, PangoGlyphInfo *glyph_info, double pos_x, double pos_y) { static gchar glyph_hash_string[100]; double scale = 72.0 / PANGO_SCALE / PAPS_DPI; double epsilon = 1e-2; double glyph_width = glyph_info->geometry.width * scale * paps->scale_x; gchar *id = NULL; /* Output outline */ static FT_Outline_Funcs ps_outlinefunc = { (FT_Outline_MoveToFunc)paps_ps_move_to, (FT_Outline_LineToFunc )paps_ps_line_to, (FT_Outline_ConicToFunc)paps_ps_conic_to, (FT_Outline_CubicToFunc)paps_ps_cubic_to }; FT_Outline_Funcs *outlinefunc; OutlineInfo outline_info; get_glyph_hash_string(face, glyph_info, // output glyph_hash_string); // Look up the key in the hash table if (!(id = g_hash_table_lookup(paps->glyph_cache, glyph_hash_string))) { FT_Int load_flags = FT_LOAD_DEFAULT; FT_Glyph glyph; GString *glyph_def_string; FT_Error ft_ret; ft_ret = FT_Load_Glyph(face, glyph_info->glyph, load_flags); if (ft_ret != 0 // Sorry - No support for bitmap glyphs at the moment. :-( || face->glyph->format == FT_GLYPH_FORMAT_BITMAP) ; else { glyph_def_string = g_string_new(""); // The key doesn't exist. Define the outline id = get_next_char_id_strdup(paps); // Create the outline outlinefunc = &ps_outlinefunc; outline_info.paps = paps; outline_info.glyph_origin.x = pos_x; outline_info.is_empty = 1; outline_info.glyph_origin.y = pos_y; outline_info.out_string = glyph_def_string; g_string_append(glyph_def_string, "start_ol\n"); FT_Get_Glyph (face->glyph, &glyph); FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline), outlinefunc, &outline_info); g_string_append_printf(glyph_def_string, "%.0f fwd_x\n" "end_ol\n", glyph_info->geometry.width * scale * paps->scale_x * PAPS_DPI ); // TBD - Check if the glyph_def_string is empty. If so, set the // id to the character to "" and don't draw it. if (outline_info.is_empty || glyph_info->glyph == 0) id[0] = '*'; else // Put the font in the font def dictionary g_string_append_printf(paps->header, "/%s { %s } def\n", id, glyph_def_string->str); g_hash_table_insert(paps->glyph_cache, g_strdup(glyph_hash_string), id); g_string_free(glyph_def_string, TRUE); FT_Done_Glyph (glyph); } } if (id && id[0] != '*') { glyph_width *= PAPS_DPI; pos_x *=PAPS_DPI; pos_y *= PAPS_DPI; // Output codes according to the ps_exec string encoding! if (fabs (pos_y - paps->last_pos_y ) > epsilon) { g_string_append_printf(layout_str, "+%8.0f%8.0f", pos_x, pos_y ); } else if (fabs(pos_x - paps->last_pos_x) > epsilon) { int dx = (int)(pos_x - paps->last_pos_x+0.5); // The extra 2 factor makes the small dx encoding trigger // more often... if (dx > 0 && dx < 20000) g_string_append_printf(layout_str, ">%4d", dx/2 ); else if (dx < 0 && dx > -20000) g_string_append_printf(layout_str, "-%4d", abs(dx)/2 ); else if (dx != 0) g_string_append_printf(layout_str, "*%8.0f", pos_x ); } // Put character on page g_string_append_printf(layout_str, "%s", id ); } paps->last_pos_y = pos_y; paps->last_pos_x = pos_x+glyph_width; // glyph_with is added by the outline def }
osgText::Glyph3D * FreeTypeFont::getGlyph3D(unsigned int charcode) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex()); // // GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being // returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct // values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect. // Microsoft uses a private field for its symbol fonts // unsigned int charindex = charcode; if (_face->charmap != NULL) { if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL) { charindex |= 0xF000; } } FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_DEFAULT|_flags ); if (error) { OSG_WARN << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl; return 0; } if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { OSG_WARN << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl; return 0; } float coord_scale = _freetype_scale/64.0f; // ** init FreeType to describe the glyph FreeType::Char3DInfo char3d(_facade->getNumberCurveSamples()); char3d._coord_scale = coord_scale; FT_Outline outline = _face->glyph->outline; FT_Outline_Funcs funcs; funcs.conic_to = (FT_Outline_ConicToFunc)&FreeType::conicTo; funcs.line_to = (FT_Outline_LineToFunc)&FreeType::lineTo; funcs.cubic_to = (FT_Outline_CubicToFunc)&FreeType::cubicTo; funcs.move_to = (FT_Outline_MoveToFunc)&FreeType::moveTo; funcs.shift = 0; funcs.delta = 0; // ** record description FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d); if (_error) { OSG_WARN << "FreeTypeFont3D::getGlyph : - outline decompose failed ..." << std::endl; return 0; } // ** create geometry for each part of the glyph osg::ref_ptr<osg::Geometry> frontGeo(new osg::Geometry); osg::ref_ptr<osg::Vec3Array> rawVertices = new osg::Vec3Array(*(char3d._verts)); osg::Geometry::PrimitiveSetList rawPrimitives; for(osg::Geometry::PrimitiveSetList::iterator itr = char3d.get()->getPrimitiveSetList().begin(); itr != char3d.get()->getPrimitiveSetList().end(); ++itr) { rawPrimitives.push_back(dynamic_cast<osg::PrimitiveSet*>((*itr)->clone(osg::CopyOp::DEEP_COPY_ALL))); } // ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list osg::ref_ptr<osgText::Glyph3D> glyph3D = new osgText::Glyph3D(_facade, charcode); // copy the raw primitive set list before we tessellate it. glyph3D->getRawFacePrimitiveSetList() = rawPrimitives; glyph3D->setRawVertexArray(rawVertices.get()); FT_Glyph_Metrics* metrics = &(_face->glyph->metrics); glyph3D->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX * coord_scale,(float)(metrics->horiBearingY-metrics->height) * coord_scale)); // bottom left. glyph3D->setHorizontalAdvance((float)metrics->horiAdvance * coord_scale); glyph3D->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX * coord_scale,(float)(metrics->vertBearingY-metrics->height) * coord_scale)); // top middle. glyph3D->setVerticalAdvance((float)metrics->vertAdvance * coord_scale); glyph3D->setWidth((float)metrics->width * coord_scale); glyph3D->setHeight((float)metrics->height * coord_scale); FT_BBox ftbb; FT_Outline_Get_BBox(&outline, &ftbb); long xmin = ft_floor( ftbb.xMin ); long xmax = ft_ceiling( ftbb.xMax ); long ymin = ft_floor( ftbb.yMin ); long ymax = ft_ceiling( ftbb.yMax ); osg::BoundingBox bb(xmin * coord_scale, ymin * coord_scale, 0.0f, xmax * coord_scale, ymax * coord_scale, 0.0f); glyph3D->setBoundingBox(bb); return glyph3D.release(); }
void font_instance::LoadGlyph(int glyph_id) { if ( pFont == NULL ) { return; } InitTheFace(); #ifndef USE_PANGO_WIN32 if ( !FT_IS_SCALABLE(theFace) ) { return; // bitmap font } #endif if ( id_to_no.find(glyph_id) == id_to_no.end() ) { Geom::PathBuilder path_builder; if ( nbGlyph >= maxGlyph ) { maxGlyph=2*nbGlyph+1; glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph)); } font_glyph n_g; n_g.pathvector=NULL; n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0; n_g.h_advance = 0; n_g.v_advance = 0; n_g.h_width = 0; n_g.v_width = 0; bool doAdd=false; #ifdef USE_PANGO_WIN32 #ifndef GGO_UNHINTED // For compatibility with old SDKs. #define GGO_UNHINTED 0x0100 #endif MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; OUTLINETEXTMETRIC otm; GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm); GLYPHMETRICS metrics; DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); double scale=1.0/daddy->fontSize; n_g.h_advance=metrics.gmCellIncX*scale; n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; n_g.h_width=metrics.gmBlackBoxX*scale; n_g.v_width=metrics.gmBlackBoxY*scale; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { // character has no visual representation, but is valid (eg whitespace) doAdd=true; } else { char *buffer = new char[bufferSize]; if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer, &identity) <= 0 ) { // shit happened } else { // Platform SDK is rubbish, read KB87115 instead DWORD polyOffset=0; while ( polyOffset < bufferSize ) { TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset); if (polyOffset+polyHeader->cb > bufferSize) break; if (polyHeader->dwType == TT_POLYGON_TYPE) { path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER); while ( curveOffset < polyOffset+polyHeader->cb ) { TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer+curveOffset); POINTFX const *p=polyCurve->apfx; POINTFX const *endp=p+polyCurve->cpfx; switch (polyCurve->wType) { case TT_PRIM_LINE: while ( p != endp ) path_builder.lineTo(pointfx_to_nrpoint(*p++, scale)); break; case TT_PRIM_QSPLINE: { g_assert(polyCurve->cpfx >= 2); // The list of points specifies one or more control points and ends with the end point. // The intermediate points (on the curve) are the points between the control points. Geom::Point this_control = pointfx_to_nrpoint(*p++, scale); while ( p+1 != endp ) { // Process all "midpoints" (all points except the last) Geom::Point new_control = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, (new_control+this_control)/2); this_control = new_control; } Geom::Point end = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, end); } break; case 3: // TT_PRIM_CSPLINE g_assert(polyCurve->cpfx % 3 == 0); while ( p != endp ) { path_builder.curveTo(pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale), pointfx_to_nrpoint(p[2], scale)); p += 3; } break; } curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1); } } polyOffset += polyHeader->cb; } doAdd=true; } delete [] buffer; } #else if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) { // shit happened } else { if ( FT_HAS_HORIZONTAL(theFace) ) { n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM); n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM); } else { n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM); } if ( FT_HAS_VERTICAL(theFace) ) { n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM); n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM); } else { n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM); } if ( theFace->glyph->format == ft_glyph_format_outline ) { FT_Outline_Funcs ft2_outline_funcs = { ft2_move_to, ft2_line_to, ft2_conic_to, ft2_cubic_to, 0, 0 }; FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM)); FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user); } doAdd=true; } #endif path_builder.finish(); if ( doAdd ) { Geom::PathVector pv = path_builder.peek(); // close all paths for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { i->close(); } if ( !pv.empty() ) { n_g.pathvector = new Geom::PathVector(pv); Geom::OptRect bounds = bounds_exact(*n_g.pathvector); if (bounds) { n_g.bbox[0] = bounds->left(); n_g.bbox[1] = bounds->top(); n_g.bbox[2] = bounds->right(); n_g.bbox[3] = bounds->bottom(); } } glyphs[nbGlyph]=n_g; id_to_no[glyph_id]=nbGlyph; nbGlyph++; } } else { } }
//******************** M A I N ************************ void get_font(string FontName_base, char letter, int ptsize, vect2d *times) { _mkdir("font_rasters"); std::string FontName = "fonts/" + FontName_base + ".ttf"; char buf[256]; string letter_name; letter_name += letter; if (letter >= 'A' && letter <= 'Z') letter_name += letter; //----------------------------------------- // Load contour of glyph //----------------------------------------- lines.clear(); bez2s.clear(); FT_Face face; FT_Library library; FT_Error error; error = FT_Init_FreeType( &library ); Check(error, "", "error initializing FT lib"); error = FT_New_Face( library, FontName.c_str(), 0, &face ); Check(error, "", "error loading font"); FT_F26Dot6 font_size = ptsize*64; error = FT_Set_Char_Size( face, font_size, font_size, 72, 72 ); Check(error, "", "error setting char size"); FT_UInt glyph_index = FT_Get_Char_Index( face, letter ); FT_Int32 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; error = FT_Load_Glyph( face, glyph_index, load_flags ); Check(error, "", "error loading glyph"); FT_Glyph glyph; error = FT_Get_Glyph( face->glyph, &glyph ); Check(error, "", "error getting glyph"); FT_OutlineGlyph Outg; error = GetOutLine(glyph, &Outg); Check(error,"", "error getting outline"); // use my own callcacks to walk over the contour FT_Outline_Funcs func_interface; func_interface.shift = 0; func_interface.delta = 0; func_interface.move_to = move_to; func_interface.line_to = line_to; func_interface.conic_to = conic_to; func_interface.cubic_to = cubic_to; FT_Outline_Decompose(&Outg->outline, &func_interface, 0); //----------------------------------------- // Rasterize using FreeType //----------------------------------------- // rasterize using FreeType so that a comparison to my code can be made double t_ft_start = get_time(); FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); double t_ft_stop = get_time(); // save timing FILE *fa = fopen("timings.txt", "a"); fprintf(fa, "time FreeType = %f\n", t_ft_stop - t_ft_start); fclose(fa); // create grid / calculate resolution g.max_depth = 0; g.grid_res = 2; int maxsize = max(face->glyph->bitmap.width, face->glyph->bitmap.rows); while (g.grid_res < maxsize) { g.grid_res *= 2; g.max_depth++; } vect2i offset; offset.set((g.grid_res - face->glyph->bitmap.width) / 2, (g.grid_res - face->glyph->bitmap.rows) / 2); // copy bitmap into a buffer Array2D<vect3ub> ftgrid; ftgrid.resize(g.grid_res, g.grid_res); for (int k = 0; k < g.grid_res*g.grid_res; k++) ftgrid.data[k].set(0); for (int j = 0; j < face->glyph->bitmap.rows; j++) { unsigned char *row = face->glyph->bitmap.buffer + (face->glyph->bitmap.rows-j-1)*face->glyph->bitmap.pitch; for (int i = 0; i < face->glyph->bitmap.width; i++) { ftgrid(i + offset[0], j + offset[1]) = row[i]; } } sprintf(buf, "font_rasters/%s_%04d_%s_1_ft.png", FontName_base.c_str(), ptsize, letter_name.c_str()); save_png(buf, ftgrid); //----------------------------------------- // Rasterize using our method //----------------------------------------- // get bbox FT_BBox bbox; FT_Outline_Get_BBox(&Outg->outline, &bbox); //printf("bbox = (%f, %f), (%f, %f)\n", bbox.xMin/64., bbox.yMin/64., bbox.xMax/64., bbox.yMax/64.); // fit in box vect2f ext; ext.set(bbox.xMax/64. - bbox.xMin/64., bbox.yMax/64. - bbox.yMin/64.); float maxext = std::max(ext[0], ext[1]) * 1.1; for (int i = 0; i < lines.s; i++) { //printf("line\n"); for (int j = 0; j < 2; j++) { lines[i][j][0] = (lines[i][j][0] - floor(bbox.xMin/64.) + offset[0]) / g.grid_res; lines[i][j][1] = (lines[i][j][1] - floor(bbox.yMin/64.) + offset[1]) / g.grid_res; //printf("%f %f\n", lines[i][j][0], lines[i][j][1]); } } for (int i = 0; i < bez2s.s; i++) { //printf("bez2\n"); for (int j = 0; j < 3; j++) { bez2s[i][j][0] = (bez2s[i][j][0] - floor(bbox.xMin/64.) + offset[0]) / g.grid_res; bez2s[i][j][1] = (bez2s[i][j][1] - floor(bbox.yMin/64.) + offset[1]) / g.grid_res; //printf("%f %f\n", bez2s[i][j][0], bez2s[i][j][1]); } } //vect3ub *grid = new vect3ub [g.grid_res*g.grid_res]; Array2D<float> grid; Array2D<vect3ub> ourgrid; grid.resize(g.grid_res, g.grid_res); ourgrid.resize(g.grid_res, g.grid_res); // rasterize for (int k = 0; k < g.grid_res*g.grid_res; k++) grid.data[k] = 0; double t_ours_start = get_time(); raster_poly(lines, bez2s, grid.data); double t_ours_stop = get_time(); // save timing FILE *f = fopen("timings.txt", "a"); fprintf(f, "time wavelet = %f\n", (t_ours_stop - t_ours_start)); fclose(f); // copy into color image and save for (int k = 0; k < g.grid_res*g.grid_res; k++) { if (grid.data[k] >= 1) ourgrid.data[k] = 255; else if (grid.data[k] <= 0) ourgrid.data[k] = 0; else ourgrid.data[k] = grid.data[k]*255; } sprintf(buf, "font_rasters/%s_%04d_%s_2_ours.png", FontName_base.c_str(), ptsize, letter_name.c_str()); save_png(buf, ourgrid); //----------------------------------------- // Calculate difference between renders //----------------------------------------- Array2D<vect3ub> grid_dif; grid_dif.resize(g.grid_res, g.grid_res); for (int i = 0; i < grid_dif.data_size; i++) { int dif = (grid.data[i]*255 - ftgrid.data[i][0]) * 10; if (dif > 255) dif = 255; else if (dif < -255) dif = -255; #if 1 grid_dif.data[i] = 255; if (dif < 0) { grid_dif.data[i][0] += dif; grid_dif.data[i][1] += dif; } else { grid_dif.data[i][1] -= dif; grid_dif.data[i][2] -= dif; } #else grid_dif.data[i] = 0; if (dif < 0) grid_dif.data[i][2] -= dif; else grid_dif.data[i][0] += dif; #endif } sprintf(buf, "font_rasters/%s_%04d_%s_3_dif.png", FontName_base.c_str(), ptsize, letter_name.c_str()); save_png(buf, grid_dif); //printf("--== timing comparison ==--\n"); //printf("time freetype = %f\n", t_ft_stop - t_ft_start); //printf("time wavelets = %f\n", t_ours_stop - t_ours_start); //printf("times slower = %f\n", (t_ours_stop - t_ours_start) / (t_ft_stop - t_ft_start) ); if (times) { times->v[0] += t_ft_stop - t_ft_start; times->v[1] += t_ours_stop - t_ours_start; } }
JNIEXPORT jobject JNICALL Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphOutlineNative (JNIEnv *env, jobject obj __attribute__((unused)), jint glyphIndex, jlong fnt) { generalpath *path; jobject gp; FT_Outline_Funcs ftCallbacks = { (FT_Outline_MoveToFunc) _moveTo, (FT_Outline_LineToFunc) _lineTo, (FT_Outline_ConicToFunc) _quadTo, (FT_Outline_CubicToFunc) _curveTo, 0, 0 }; PangoFcFont *font; FT_Face ft_face; FT_Glyph glyph; font = JLONG_TO_PTR(PangoFcFont, fnt); ft_face = pango_fc_font_lock_face( font ); g_assert (ft_face != NULL); path = g_malloc0 (sizeof (generalpath)); g_assert(path != NULL); path->env = env; path->px = path->py = 0.0; path->sx = 1.0/64.0; path->sy = -1.0/64.0; { /* create a GeneralPath instance */ jclass cls; jmethodID method; cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath"); method = (*env)->GetMethodID (env, cls, "<init>", "()V"); gp = path->obj = (*env)->NewObject (env, cls, method); } if(FT_Load_Glyph(ft_face, (FT_UInt)(glyphIndex), FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP) != 0) { pango_fc_font_unlock_face( font ); g_free(path); return NULL; } FT_Get_Glyph( ft_face->glyph, &glyph ); if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline), &ftCallbacks, path); } else { char format[5]; format[0] = (glyph->format & 0xFF000000) >> 24; format[1] = (glyph->format & 0x00FF0000) >> 16; format[2] = (glyph->format & 0x0000FF00) >> 8; format[3] = (glyph->format & 0x000000FF); format[4] = '\0'; printf("WARNING: Unable to create outline for font %s %s of format %s\n", ft_face->family_name, ft_face->style_name, format); } FT_Done_Glyph( glyph ); pango_fc_font_unlock_face( font ); g_free(path); return gp; }
// lookup glyph and extract all the shapes required to draw the outline long int Ttt::render_char(FT_Face face, wchar_t c, long int offset, int linescale) { int error; int glyph_index; FT_Outline outline; FT_Outline_Funcs func_interface; error = FT_Set_Pixel_Sizes(face, 4096, linescale ? linescale : 64); if(error) handle_ft_error("FT_Set_Pixel_Sizes", error, __LINE__); /* lookup glyph */ glyph_index = FT_Get_Char_Index(face, (FT_ULong)c); if(!glyph_index) handle_ft_error("FT_Get_Char_Index", 0, __LINE__); /* load glyph */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if(error) handle_ft_error("FT_Load_Glyph", error, __LINE__); error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); if(error) handle_ft_error("FT_Render_Glyph", error, __LINE__); if(linescale > 0) // this is for the "zigzag" fill of letters? my_draw_bitmap(&face->glyph->bitmap, face->glyph->bitmap_left + offset, face->glyph->bitmap_top, linescale); error = FT_Set_Pixel_Sizes(face, 0, 64); if(error) handle_ft_error("FT_Set_Pixel_Sizes", error, __LINE__); error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if(error) handle_ft_error("FT_Load_Glyph", error, __LINE__); /* shortcut to the outline for our desired character */ outline = face->glyph->outline; /* set up entries in the interface used by FT_Outline_Decompose() */ func_interface.shift = 0; func_interface.delta = 0; func_interface.move_to = move_to_wrapper; func_interface.line_to = line_to_wrapper; func_interface.conic_to = conic_to_wrapper; func_interface.cubic_to = cubic_to_wrapper; /* offset the outline to the correct position in x */ FT_Outline_Translate( &outline, offset, 0L ); /* plot the current character */ error = FT_Outline_Decompose( &outline, &func_interface, NULL); if(error) handle_ft_error("FT_Outline_Decompose", error, __LINE__); /* save advance in a global */ advance.x = face->glyph->advance.x; advance.y = face->glyph->advance.y; /* FT_Bool use_kerning = FT_HAS_KERNING( face ); std::cout << " not using kerning \n"; if ( use_kerning && previous ) { FT_Vector kerning; error = FT_Get_Kerning( face, // handle to face object previous_glyph_index, // left glyph index glyph_index, // right glyph index FT_KERNING_DEFAULT, // kerning mode FT_KERNING_DEFAULT , FT_KERNING_UNFITTED , FT_KERNING_UNSCALED &kerning ); // target vector std::cout << " kerning x-advance: " << kerning.x << "\n"; } */ /* FT_Vector kerning; error = FT_Get_Kerning( face, // handle to face object left, // left glyph index right, // right glyph index kerning_mode, // kerning mode FT_KERNING_DEFAULT , FT_KERNING_UNFITTED , FT_KERNING_UNSCALED &kerning ); // target vector */ // delete glyph with FT_Done_Glyph? previous = true; // we have a prev glyph, for kerning previous_glyph_index = glyph_index; /* offset will get bumped up by the x size of the char just plotted */ return face->glyph->advance.x; }
void TtfFont::PlotString(const std::string &str, SBezierList *sbl, Vector origin, Vector u, Vector v) { ssassert(fontFace != NULL, "Expected font face to be loaded"); FT_Pos dx = 0; for(char32_t chr : ReadUTF8(str)) { uint32_t gid = FT_Get_Char_Index(fontFace, chr); if (gid == 0) { dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID", chr, ft_error_string(gid)); } FT_F26Dot6 scale = fontFace->units_per_EM; if(int fterr = FT_Set_Char_Size(fontFace, scale, scale, 72, 72)) { dbp("freetype: cannot set character size: %s", ft_error_string(fterr)); return; } /* * Stupid hacks: * - if we want fake-bold, use FT_Outline_Embolden(). This actually looks * quite good. * - if we want fake-italic, apply a shear transform [1 s s 1 0 0] here using * FT_Set_Transform. This looks decent at small font sizes and bad at larger * ones, antialiasing mitigates this considerably though. */ if(int fterr = FT_Load_Glyph(fontFace, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) { dbp("freetype: cannot load glyph (gid %d): %s", gid, ft_error_string(fterr)); return; } /* A point that has x = xMin should be plotted at (dx0 + lsb); fix up * our x-position so that the curve-generating code will put stuff * at the right place. * * There's no point in getting the glyph BBox here - not only can it be * needlessly slow sometimes, but because we're about to render a single glyph, * what we want actually *is* the CBox. * * This is notwithstanding that this makes extremely little sense, this * looks like a workaround for either mishandling the start glyph on a line, * or as a really hacky pseudo-track-kerning (in which case it works better than * one would expect! especially since most fonts don't set track kerning). */ FT_BBox cbox; FT_Outline_Get_CBox(&fontFace->glyph->outline, &cbox); FT_Pos bx = dx - cbox.xMin; // Yes, this is what FreeType calls left-side bearing. // Then interchangeably uses that with "left-side bearing". Sigh. bx += fontFace->glyph->metrics.horiBearingX; OutlineData data = {}; data.origin = origin; data.u = u; data.v = v; data.beziers = sbl; data.factor = 1.0f/(float)scale; data.bx = bx; if(int fterr = FT_Outline_Decompose(&fontFace->glyph->outline, &outline_funcs, &data)) { dbp("freetype: bezier decomposition failed (gid %d): %s", gid, ft_error_string(fterr)); } // And we're done, so advance our position by the requested advance // width, plus the user-requested extra advance. dx += fontFace->glyph->advance.x; } }
bool FontParser::parseFontFile(GXFont *font , const std::string &filename ) { if ( font == nullptr) return false; if (!FileSystem::fileExists( filename )) return false; FT_Face face; int faceIndex = 0; if( FT_New_Face( _library, filename.c_str(), faceIndex, &face ) != 0 ) { Log::log("couldn't load new face\n"); return false; } font->m_fileName = filename; if (face->family_name != NULL) font->m_fontName = face->family_name; else font->m_fontName = "No Name"; font->m_fontName += " "; if (face->style_name != NULL) font->m_fontName += face->style_name; else font->m_fontName += " No Style"; FT_Set_Char_Size( face, 0 , /* char_width in 1/64th of points */ 64*64, /* char_height in 1/64th of points */ HorizontalDeviceResolution , /* horizontal device resolution */ VerticalDeviceResolution /* vertical device resolution */ ); int num_glyphs = 0; int descent = face->descender; if (descent <0) descent *= -1; font->m_lineSpace = face->ascender + descent + face->height; for(int cc = 0 ; cc<256 ; cc++ ) { if( cc < 32 ) continue; //discard the first 32 characters int glyphIndex = FT_Get_Char_Index( face, cc ); if( !FT_Load_Glyph( face, glyphIndex, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM ) ) { GXGlyph *glyph = new GXGlyph(); // empty glyph->m_advanceX = (float) ( face->glyph->advance.x ); glyph->m_advanceY = (float) ( face->glyph->advance.y ); if( cc == ' ' ) { } else { _functions.delta = 0; _functions.shift = 0; FT_Outline_Decompose( &face->glyph->outline, &_functions , glyph ); } font->addChar(cc, glyph); num_glyphs++; } } if(! num_glyphs ) Log::log("warning: no glyphs found\n"); FT_Done_Face( face ); return true; }
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 PyObject* Py_Outline_to_points_and_codes(Py_Outline* self, PyObject* args, PyObject* kwds) { PyObject *result = NULL; PyObject *points = NULL; PyObject *codes = NULL; DecomposeToPointsAndCodesData data; const FT_Outline_Funcs funcs = { .move_to = Py_Outline_to_points_and_codes_moveto_func, .line_to = Py_Outline_to_points_and_codes_lineto_func, .conic_to = Py_Outline_to_points_and_codes_conicto_func, .cubic_to = Py_Outline_to_points_and_codes_cubicto_func, .shift = 0, .delta = 0 }; int error; if (!self->points || !self->codes) { memset(&data, 0, sizeof(DecomposeToPointsAndCodesData)); error = FT_Outline_Decompose(&self->x, &funcs, &data); if (PyErr_Occurred()) { PyMem_Free(data.points); PyMem_Free(data.codes); goto exit; } else if (ftpy_exc(error)) { PyMem_Free(data.points); PyMem_Free(data.codes); goto exit; } self->points = data.points; self->codes = data.codes; self->n_points = data.cursor; } points = Py_Outline_Decomposed_Points_Buffer_cnew((PyObject *)self); if (points == NULL) { goto exit; } codes = Py_Outline_Codes_Buffer_cnew((PyObject *)self); if (codes == NULL) { Py_DECREF(points); goto exit; } result = Py_BuildValue("(OO)", points, codes); if (result == NULL) { Py_DECREF(points); Py_DECREF(codes); goto exit; } exit: return result; } static PyObject* Py_Outline_to_string(Py_Outline* self, PyObject* args, PyObject* kwds) { PyObject *result = NULL; DecomposeToStringData data; const FT_Outline_Funcs funcs = { .move_to = Py_Outline_to_string_moveto_func, .line_to = Py_Outline_to_string_lineto_func, .conic_to = Py_Outline_to_string_conicto_func, .cubic_to = Py_Outline_to_string_cubicto_func, .shift = 0, .delta = 0 }; int error; const char* keywords[] = { "move_command", "line_command", "cubic_command", "conic_command", "prefix", NULL}; data.prefix = 0; data.conic_command = NULL; if (!PyArg_ParseTupleAndKeywords( args, kwds, "sss|si:to_string", (char **)keywords, &data.move_command, &data.line_command, &data.cubic_command, &data.conic_command, &data.prefix)) { return NULL; } data.buffer = PyMem_Malloc(BUFFER_CHUNK_SIZE); if (data.buffer == NULL) { return NULL; } data.buffer[0] = 0; data.buffer_size = BUFFER_CHUNK_SIZE; data.cursor = 0; data.last_x = 0; data.last_y = 0; error = FT_Outline_Decompose(&self->x, &funcs, &data); if (PyErr_Occurred()) { goto exit; } else if (ftpy_exc(error)) { goto exit; } result = PyBytes_FromStringAndSize(data.buffer, data.cursor); if (result == NULL) { goto exit; } exit: PyMem_Free(data.buffer); return result; } static PyObject* Py_Outline_translate(Py_Outline* self, PyObject* args, PyObject* kwds) { long xOffset; long yOffset; /* TODO: What is the scale of these arguments? */ const char* keywords[] = {"x_offset", "y_offset", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwds, "ll:translate", (char **)keywords, &xOffset, &yOffset)) { return NULL; } FT_Outline_Translate(&self->x, xOffset, yOffset); Py_RETURN_NONE; };
static PyObject* Py_Outline_decompose(Py_Outline* self, PyObject* args, PyObject* kwds) { /* TODO: Also implement this as an iterator */ DecomposeData data; PyObject *obj; const FT_Outline_Funcs funcs = { .move_to = Py_Outline_moveto_func, .line_to = Py_Outline_lineto_func, .conic_to = Py_Outline_conicto_func, .cubic_to = Py_Outline_cubicto_func, .shift = 0, .delta = 0 }; int error; const char* keywords[] = {"obj", "shift", "delta", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|ii:decompose", (char **)keywords, &obj, &funcs.shift, &funcs.delta)) { return NULL; } if (!PyObject_HasAttrString(obj, "move_to")) { PyErr_SetString(PyExc_AttributeError, "obj has no move_to method"); return NULL; } if (!PyObject_HasAttrString(obj, "line_to")) { PyErr_SetString(PyExc_AttributeError, "obj has no line_to method"); return NULL; } if (!PyObject_HasAttrString(obj, "cubic_to")) { PyErr_SetString(PyExc_AttributeError, "obj has no cubic_to method"); return NULL; } data.has_conic_to = PyObject_HasAttrString(obj, "conic_to"); data.callback = obj; data.last_x = 0; data.last_y = 0; error = FT_Outline_Decompose(&self->x, &funcs, &data); if (PyErr_Occurred()) { return NULL; } else if (ftpy_exc(error)) { return NULL; } Py_RETURN_NONE; }; static PyObject* Py_Outline_embolden(Py_Outline* self, PyObject* args, PyObject* kwds) { double strength; const char* keywords[] = {"strength", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwds, "d:embolden", (char **)keywords, &strength)) { return NULL; } if (ftpy_exc( FT_Outline_Embolden(&self->x, TO_F26DOT6(strength)))) { return NULL; } Py_RETURN_NONE; };