static void profile_outline( FT_Outline* outline, long repeat ) { FT_BBox bbox; long count; long time0; time0 = get_time(); for ( count = repeat; count > 0; count-- ) FT_Outline_Get_CBox( outline, &bbox ); time0 = get_time() - time0; printf( "time = %5.2f cbox = [%.2f %.2f %.2f %.2f]\n", ((double)time0/10000.0), XVAL( bbox.xMin ), XVAL( bbox.yMin ), XVAL( bbox.xMax ), XVAL( bbox.yMax ) ); time0 = get_time(); for ( count = repeat; count > 0; count-- ) FT_Outline_Get_BBox( outline, &bbox ); time0 = get_time() - time0; printf( "time = %5.2f bbox = [%.2f %.2f %.2f %.2f]\n", ((double)time0/10000.0), XVAL( bbox.xMin ), XVAL( bbox.yMin ), XVAL( bbox.xMax ), XVAL( bbox.yMax ) ); }
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; } }
static PyObject* Py_Outline_get_bbox(Py_Outline* self, PyObject* args, PyObject* kwds) { FT_BBox bbox; if (ftpy_exc( FT_Outline_Get_BBox(&self->x, &bbox))) { return NULL; } return Py_BBox_cnew(&bbox, 1.0); }
static FT_Error LoadTrueTypeChar(Font *fnt, int idx, Boolean hint, Boolean quiet) { FT_Error error; int flags; flags = FT_LOAD_DEFAULT; if (hint) flags |= FT_LOAD_FORCE_AUTOHINT; error = FT_Load_Glyph(face, idx, flags); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) FT_Outline_Transform(&face->glyph->outline, &matrix1); if (fnt->rotate) { FT_Outline_Transform(&face->glyph->outline, &matrix2); error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); /* we need the non- grid-fitted bbox */ if (!error) FT_Outline_Translate(&face->glyph->outline, face->glyph->metrics.vertBearingY - bbox.xMin, -fnt->y_offset * ppem * 64); } } if (!error) error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); if (!error) { FT_Outline_Get_CBox(&face->glyph->outline, &bbox); /* for the case of BBox != CBox */ SetRasterArea(quiet); } return error; }
/* * Class: sun_font_FreetypeFontScaler * Method: getGlyphOutlineBoundsNative * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float; */ JNIEXPORT jobject JNICALL Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative( JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext, jlong pScaler, jint glyphCode) { FT_Outline *outline; FT_BBox bbox; int error; jobject bounds; FTScalerContext *context = (FTScalerContext*) jlong_to_ptr(pScalerContext); FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler); outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0); if (outline == NULL || outline->n_points == 0) { /* it is legal case, e.g. invisible glyph */ bounds = (*env)->NewObject(env, sunFontIDs.rect2DFloatClass, sunFontIDs.rect2DFloatCtr); return bounds; } error = FT_Outline_Get_BBox(outline, &bbox); //convert bbox if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) { bounds = (*env)->NewObject(env, sunFontIDs.rect2DFloatClass, sunFontIDs.rect2DFloatCtr); } else { bounds = (*env)->NewObject(env, sunFontIDs.rect2DFloatClass, sunFontIDs.rect2DFloatCtr4, F26Dot6ToFloat(bbox.xMin), F26Dot6ToFloat(-bbox.yMax), F26Dot6ToFloat(bbox.xMax-bbox.xMin), F26Dot6ToFloat(bbox.yMax-bbox.yMin)); } return bounds; }
static void dump_outline( FT_Outline* outline ) { FT_BBox bbox; /* compute and display cbox */ FT_Outline_Get_CBox( outline, &bbox ); printf( "cbox = [%.2f %.2f %.2f %.2f]\n", XVAL( bbox.xMin ), XVAL( bbox.yMin ), XVAL( bbox.xMax ), XVAL( bbox.yMax ) ); /* compute and display bbox */ FT_Outline_Get_BBox( outline, &bbox ); printf( "bbox = [%.2f %.2f %.2f %.2f]\n", XVAL( bbox.xMin ), XVAL( bbox.yMin ), XVAL( bbox.xMax ), XVAL( bbox.yMax ) ); }
bool GDI2FT_RENDERER::get_glyph_metrics( wchar_t glyph_char, bool is_glyph_index, LPGLYPHMETRICS lpgm ) /* -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- */ { GDI2FT_GLPYH_RUN new_glyph_run; if( generate_glyph_run( is_glyph_index, &glyph_char, 1, new_glyph_run, true ) ) { const FT_Glyph target_glyph = new_glyph_run.glyphs.front(); FT_BBox glyph_bbox; FT_Outline_Get_BBox( &( reinterpret_cast<FT_OutlineGlyph>( target_glyph )->outline ), &glyph_bbox ); lpgm->gmBlackBoxX = ( glyph_bbox.xMax - glyph_bbox.xMin ) >> 6; lpgm->gmBlackBoxY = ( glyph_bbox.yMax - glyph_bbox.yMin ) >> 6; lpgm->gmptGlyphOrigin.x = glyph_bbox.xMin >> 6; lpgm->gmptGlyphOrigin.y = glyph_bbox.yMax >> 6; lpgm->gmCellIncX = 0xF000 | ( ( (short)( (double)target_glyph->advance.x / 6553.6 ) ) & 0x0FFF ); lpgm->gmCellIncY = 0xF000 | ( ( (short)( (double)target_glyph->advance.y / 6553.6 ) ) & 0x0FFF ); return true; } return false; }
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(); }
//******************** 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; } }
void readttf(Font *fnt, Boolean quiet, Boolean only_range) { FT_Error error; ttfinfo *ti, *Ti; long Num, index; unsigned int i, j; long k, max_k; int index_array[257]; static Boolean initialized = False; /* * We allocate a placeholder boundary and the `.notdef' character. */ if (!only_range) { ti = newchar(fnt); ti->charcode = -1; ti->adobename = ".notdef"; ti = newchar(fnt); ti->charcode = -1; ti->adobename = "||"; /* boundary character name */ } /* * Initialize FreeType engine. */ if (!initialized) { /* * We use a dummy glyph size of 10pt. */ dpi = 92; ptsize = 10 * 64; real_ttfname = TeX_search_ttf_file(&(fnt->ttfname)); if (!real_ttfname) oops("Cannot find `%s'.", fnt->ttfname); FTopen(real_ttfname, fnt, True, True); initialized = True; } if (!quiet) { if (only_range) printf("\n\n%s:\n", fnt->fullname); printf("\n"); printf("Glyph Code Glyph Name "); printf("Width llx lly urx ury\n"); printf("----------------------------------------"); printf("---------------------------------\n"); } /* * We load only glyphs with a valid cmap entry. Nevertheless, for * the default mapping, we use the first 256 glyphs addressed by * ascending code points, followed by glyphs not in the cmap. * * If we compute a range, we take the character codes given in * the fnt->sf_code array. * * If the -N flag is set, no cmap is used at all. Instead, the * first 256 glyphs (with a valid PS name) are used for the default * mapping. */ if (!only_range) for (i = 0; i < 257; i++) index_array[i] = 0; else for (i = 0; i < 256; i++) fnt->inencptrs[i] = 0; j = 0; if (fnt->PSnames == Only) max_k = face->num_glyphs - 1; else max_k = only_range ? 0xFF : 0x16FFFF; for (k = 0; k <= max_k; k++) { char buff[128]; const char *an; if (fnt->PSnames != Only) { if (only_range) { index = fnt->sf_code[k]; if (index < 0) continue; j = k; } else index = k; Num = FT_Get_Char_Index(face, index); /* now we try to get a vertical glyph form */ if (has_gsub) Num = Get_Vert(Num); if (Num < 0) oops("Failure on cmap mapping from %s.", fnt->ttfname); if (Num == 0) continue; if (!only_range) if (Num <= 256) index_array[Num] = 1; } else { Num = k; index = 0; } error = FT_Load_Glyph(face, Num, flags); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) FT_Outline_Transform(&face->glyph->outline, &matrix1); if (fnt->rotate) FT_Outline_Transform(&face->glyph->outline, &matrix2); error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); /* we need the non- grid-fitted bbox */ } if (!error) { if (fnt->PSnames) { (void)FT_Get_Glyph_Name(face, Num, buff, 128); an = newstring(buff); } else an = code_to_adobename(index); /* ignore characters not usable for typesetting with TeX */ if (strcmp(an, ".notdef") == 0) continue; if (strcmp(an, ".null") == 0) continue; if (strcmp(an, "nonmarkingreturn") == 0) continue; ti = newchar(fnt); ti->charcode = index; ti->glyphindex = Num; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; ti->fntnum = fnt->subfont_num; /* * We must now shift the rotated character both horizontally * and vertically. The vertical amount is 25% by default. */ if (fnt->rotate) { ti->llx += (face->glyph->metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->lly -= 1000 * fnt->y_offset; ti->urx += (face->glyph->metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->ury -= 1000 * fnt->y_offset; } /* * We need to avoid negative heights or depths. They break accents * in math mode, among other things. */ if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; if (fnt->rotate) ti->width = face->glyph->metrics.vertAdvance * 1000 / fnt->units_per_em; else ti->width = transform(face->glyph->metrics.horiAdvance * 1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5ld %05lx %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", Num, index, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } j++; } } /* * Now we load glyphs without a cmap entry, provided some slots are * still free -- we skip this if we have to compute a range or use * PS names. */ if (!only_range && !fnt->PSnames) { for (i = 1; i <= face->num_glyphs; i++) { const char *an; if (index_array[i] == 0) { error = FT_Load_Glyph(face, i, flags); if (!error) error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); if (!error) { an = code_to_adobename(i | 0x1000000); ti = newchar(fnt); ti->charcode = i | 0x1000000; ti->glyphindex = i; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; ti->width = transform(face->glyph->metrics.horiAdvance*1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5d %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", i, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } else break; j++; } } } } /* Finally, we construct a `Germandbls' glyph if necessary */ if (!only_range) { if (NULL == findadobe("Germandbls", fnt->charlist) && NULL != (Ti = findadobe("S", fnt->charlist))) { pcc *np, *nq; ti = newchar(fnt); ti->charcode = face->num_glyphs | 0x1000000; ti->glyphindex = face->num_glyphs; ti->adobename = "Germandbls"; ti->width = Ti->width << 1; ti->llx = Ti->llx; ti->lly = Ti->lly; ti->urx = Ti->width + Ti->urx; ti->ury = Ti->ury; ti->kerns = Ti->kerns; np = newpcc(); np->partname = "S"; nq = newpcc(); nq->partname = "S"; nq->xoffset = Ti->width; np->next = nq; ti->pccs = np; ti->constructed = True; if (!quiet) printf("* %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); } } /* kerning between subfonts isn't available */ if (!only_range) readttf_kern(fnt); }