コード例 #1
0
  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 ) );
  }
コード例 #2
0
ファイル: FreeTypeFont.cpp プロジェクト: crimzon/osg
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;
    }
}
コード例 #3
0
ファイル: outline.c プロジェクト: anthrotype/freetypy
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);
}
コード例 #4
0
ファイル: ttflib.c プロジェクト: MiKTeX/miktex
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;
}
コード例 #5
0
/*
 * 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;
}
コード例 #6
0
  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 ) );
  }
コード例 #7
0
ファイル: renderer.cpp プロジェクト: oviano/gdi2ft
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;
}
コード例 #8
0
ファイル: FreeTypeFont.cpp プロジェクト: nsmoooose/osg
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();
}
コード例 #9
0
ファイル: get_font.cpp プロジェクト: uygned/will-apps
//******************** 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;
    }
}
コード例 #10
0
ファイル: ttfaux.c プロジェクト: MiKTeX/miktex
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);
}