Try font2openvg.cpp from the old hybrid site.
http://web.archive.org/web/200708081951 … vg.cpp.txt
/*
* Copyright (c) 2006, Hybrid Graphics, Ltd.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The name of Hybrid Graphics may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY HYBRID GRAPHICS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL HYBRID GRAPHICS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <float.h>
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#define OUTPUT_INTS
class Vector2
{
public:
Vector2() {}
Vector2(float px, float py) { x = px; y = py; }
float x;
float y;
};
Vector2 operator+(const Vector2& a, const Vector2& b) { return Vector2(a.x+b.x, a.y+b.y); }
Vector2 operator*(const Vector2& a, float b) { return Vector2(a.x*b, a.y*b); }
float convFTFixed( const FT_Pos &x )
{
return (float)x / 4096.0f;
}
Vector2 convFTVector( const FT_Vector &v )
{
return Vector2(convFTFixed(v.x),convFTFixed(v.y));
}
bool isOn( char b )
{
return b & 1 ? true : false;
}
int main (int argc, char * const argv[])
{
FT_Library library;
FT_Face face;
if(argc < 4)
{
printf("usage: font2openvg input_font_file output.c prefix
");
exit(-1);
}
if( FT_Init_FreeType( &library ) )
{
printf("couldn't initialize freetype
");
exit(-1);
}
int faceIndex = 0;
if( FT_New_Face( library, argv[1], faceIndex, &face ) )
{
printf("couldn't load new face
");
exit(-1);
}
FT_Set_Char_Size(
face, /* handle to face object */
0, /* char_width in 1/64th of points */
64*64, /* char_height in 1/64th of points */
96, /* horizontal device resolution */
96 ); /* vertical device resolution */
FILE* f = fopen(argv[2], "wt");
if(!f)
{
printf("couldn't open %s for writing
", argv[2]);
exit(-1);
}
std::vector<int> gpvecindices;
std::vector<int> givecindices;
std::vector<int> gpvecsizes;
std::vector<int> givecsizes;
std::vector<Vector2> gpvec;
std::vector<char> givec;
std::vector<float> gbbox;
std::vector<float> advances;
unsigned int characterMap[256];
int glyphs = 0;
for(int cc=0;cc<256;cc++)
{
characterMap[cc] = 0xffffffffu; //initially nonexistent
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 ) )
{
float advance = convFTFixed( face->glyph->advance.x );
if( cc == ' ' )
{ //space doesn't contain any data
gpvecindices.push_back( gpvec.size() );
givecindices.push_back( givec.size() );
gpvecsizes.push_back( 0 );
givecsizes.push_back( 0 );
gbbox.push_back(0);
gbbox.push_back(0);
gbbox.push_back(0);
gbbox.push_back(0);
advances.push_back(advance);
//write glyph index to character map
characterMap[cc] = glyphs++;
continue;
}
FT_Outline &outline = face->glyph->outline;
std::vector<Vector2> pvec;
std::vector<unsigned char> ivec;
float minx = 10000000.0f,miny = 100000000.0f,maxx = -10000000.0f,maxy = -10000000.0f;
int s = 0,e;
bool on;
Vector2 last,v,nv;
for(int con=0;con<outline.n_contours;++con)
{
int pnts = 1;
e = outline.contours[con]+1;
last = convFTVector(outline.points[s]);
//read the contour start point
ivec.push_back(2);
pvec.push_back(last);
int i=s+1;
while(i<=e)
{
int c = (i == e) ? s : i;
int n = (i == e-1) ? s : (i+1);
v = convFTVector(outline.points[c]);
on = isOn( outline.tags[c] );
if( on )
{ //line
++i;
ivec.push_back(4);
pvec.push_back(v);
pnts += 1;
}
else
{ //spline
if( isOn( outline.tags[n] ) )
{ //next on
nv = convFTVector( outline.points[n] );
i += 2;
}
else
{ //next off, use middle point
nv = (v + convFTVector( outline.points[n] )) * 0.5f;
++i;
}
ivec.push_back(10);
pvec.push_back(v);
pvec.push_back(nv);
pnts += 2;
}
last = nv;
}
ivec.push_back(0);
s = e;
}
for(int i=0;i<pvec.size();++i)
{
if( pvec[i].x < minx ) minx = pvec[i].x;
if( pvec[i].x > maxx ) maxx = pvec[i].x;
if( pvec[i].y < miny ) miny = pvec[i].y;
if( pvec[i].y > maxy ) maxy = pvec[i].y;
}
if(!pvec.size())
{
minx = 0.0f;
miny = 0.0f;
maxx = 0.0f;
maxy = 0.0f;
}
gpvecindices.push_back( gpvec.size() );
givecindices.push_back( givec.size() );
gpvecsizes.push_back( pvec.size() );
givecsizes.push_back( ivec.size() );
gbbox.push_back( minx );
gbbox.push_back( miny );
gbbox.push_back( maxx );
gbbox.push_back( maxy );
advances.push_back(advance);
int size;
size = gpvec.size();
gpvec.resize( size + pvec.size() );
memcpy( &(gpvec[size]), &(pvec[0]), pvec.size() * sizeof(Vector2) );
size = givec.size();
givec.resize( size + ivec.size() );
memcpy( &(givec[size]), &(ivec[0]), ivec.size() * sizeof(char) );
//write glyph index to character map
characterMap[cc] = glyphs++;
}
}
if(!glyphs)
printf("warning: no glyphs found
");
static const char* legalese = {"/* Generated by font2openvg. See http://developer.hybrid.fi for more information. */
"};
//print legalese
fprintf(f,"%s", legalese);
//print the name of the font file
fprintf (f,"/* converted from font file %s */
", argv[1]);
fprintf (f,"/* font family name: %s */
", face->family_name);
fprintf (f,"/* font style name: %s */
", face->style_name);
//print instructions
fprintf (f,"static const unsigned char %s_glyphInstructions[%d] = {", argv[3],givec.size());
for(int i=0;i<givec.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",givec[i],(i==(givec.size()-1))?' ':',');
}
fprintf (f,"};
");
fprintf (f,"static const int %s_glyphInstructionIndices[%d] = {", argv[3],givecindices.size());
for(int i=0;i<givecindices.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",givecindices[i],(i==(givecindices.size()-1))?' ':',');
}
fprintf (f,"};
");
fprintf (f,"static const int %s_glyphInstructionCounts[%d] = {", argv[3],givecsizes.size());
for(int i=0;i<givecsizes.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",givecsizes[i],(i==(givecsizes.size()-1))?' ':',');
}
fprintf (f,"};
");
fprintf (f,"static const int %s_glyphPointIndices[%d] = {", argv[3],gpvecindices.size());
for(int i=0;i<gpvecindices.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",gpvecindices[i],(i==(gpvecindices.size()-1))?' ':',');
}
fprintf (f,"};
");
#ifdef OUTPUT_INTS
//print points
fprintf (f,"static const int %s_glyphPoints[%d*2] = {", argv[3],gpvec.size());
for(int i=0;i<gpvec.size();i++)
{
if ((i % 10)==0)
fprintf (f,"
");
fprintf (f,"%d,%d%c",(int)(65536.0f*gpvec[i].x),(int)(65536.0f*gpvec[i].y),(i==(gpvec.size()-1))?' ':',');
}
fprintf (f,"};
");
//print the advances
fprintf (f,"static const int %s_glyphAdvances[%d] = {", argv[3],advances.size());
for(int i=0;i<advances.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",(int)(65536.0f*advances[i]),(i==(advances.size()-1))?' ':',');
}
fprintf (f,"};
");
//print the bounding boxes
fprintf (f,"static const int %s_glyphBBoxes[%d] = {", argv[3],gbbox.size());
for(int i=0;i<gbbox.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",(int)(65536.0f*gbbox[i]),(i==(gbbox.size()-1))?' ':',');
}
fprintf (f,"};
");
#else
//print points
fprintf (f,"static const float %s_glyphPoints[%d*2] = {", argv[3],gpvec.size());
for(int i=0;i<gpvec.size();i++)
{
if ((i % 10)==0)
fprintf (f,"
");
fprintf (f,"%f,%f%c",gpvec[i].x,gpvec[i].y,(i==(gpvec.size()-1))?' ':',');
}
fprintf (f,"};
");
//print the advances
fprintf (f,"static const float %s_glyphAdvances[%d] = {", argv[3],advances.size());
for(int i=0;i<advances.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%f%c",advances[i],(i==(advances.size()-1))?' ':',');
}
fprintf (f,"};
");
//print the bounding boxes
fprintf (f,"static const float %s_glyphBBoxes[%d] = {", argv[3],gbbox.size());
for(int i=0;i<gbbox.size();i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%f%c",gbbox[i],(i==(gbbox.size()-1))?' ':',');
}
fprintf (f,"};
");
#endif
//print the number of glyphs and the character map
fprintf (f,"static const int %s_glyphCount = %d;
",argv[3],glyphs);
fprintf (f,"static const short %s_characterMap[256] = {", argv[3]);
for(int i=0;i<256;i++)
{
if ((i % 20)==0)
fprintf (f,"
");
fprintf (f,"%d%c",characterMap[i],(i==(256-1))?' ':',');
}
fprintf (f,"};
");
fclose(f);
if(glyphs)
printf("%d glyphs written
", glyphs);
FT_Done_Face( face );
FT_Done_FreeType( library );
return 0;
}