About Text rendering

According to the specifiction v 1.1, Glyphs in OpenVG can be represented either using VGPath or VGImage data.

However, I think, before assigning the given path to a glyph, we have to put some information such as vertex and edges on a path or an Image.

If so, how can I map the given characters to a glyph or path with a font type such as truetype and opentype…

In the Spec, I can’t figure it out.~~

Please help me.~~

It’s simple.

  • Create the path like normal populating then the right path data.
  • Create a Font object
  • Bind the indivual paths to the font object
  • Destroy the paths (recommended to do this now by the spec - can be done later)
    To render:
  • Set up your origin and glyph transformations
  • Render with vgDrawGlyph() or vgDrawGlyphs()
    To Clean up:
  • Destory the font

For example:


    VGFont  font;
    VGPath  fontpath1;
    VGImage fontimg1;

    font        = vgCreateFont(0);
    fontpath1   = vgCreatePath(VG_PATH_FORMAT_STANDARD,VG_PATH_DATATYPE_F, 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
    fontimg1    = vgCreateImage( VG_sRGBA_8888, IMAGE_WIDTH, IMAGE_HEIGHT, VG_IMAGE_QUALITY_FASTER );

    vguEllipse(fontpath1, 5.0f,5.0f,5.0f,5.0f);
    vgImageSubData( fontimg1, image_data, IMAGE_WIDTH*4, VG_sRGBA_8888, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT );

    vgSetGlyphToPath(font, 'a',fontpath1, 1, origin, escapement);
    vgDestroyPath(fontpath1);
    vgSetGlyphToImage(font, 'b',fontimg1, origin, escapement);

...
    // then to draw
    float origin[2];
    vgSetfv(VG_GLYPH_ORIGIN, 2, origin);
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
    vgLoadIdentity();

    vgDrawGlyph(font, 'a', VG_FILL_PATH, 1);
    {
        int glyphs[] = {'b','a','d'};
        vgDrawGlyphs(font, 3, glyphs, NULL, NULL, VG_FILL_PATH, 1);
    }


Thank you for giving me the example~
However I could not run the code.

When I ran the example with your code, I just saw the ellipse without font.

First, I can not understand what the fontimg1 should have to have with image_data. I would like to know the data of image_data.

Second, because I don’t know the relationship between image_data and font, I just leave the all of the image part out from the code, then I could see just one ellipse.

I think I need something more information about it with RI(reference implementation) 1.1.

I didn’t include the image data in the snippet - it can be any image data you want.

If you saw the ellipse, then you saw exactly what you were supposed to see. In this font, the ellipse path is associated with the
letter ‘a’ - and you asked it to print the letter ‘a’.

Remember, vguEllipse() can be substituded by vgAppendPathData() to use any path data you want.
Similarly, any number of characters may be added to the font with vgSetGlyphToPath() - meaning you can associate path1 with ‘a’, path2 to ‘b’, etc.

:lol: Thank you so much replying to my question…

Acutally I couldn’t understand what the concept of VGFont in OpenVG is… because I always wanted to see really ‘a’ or ‘b’ on the screen not the index…

If so, do you have any example font paths or images…

If you have, please let me have it from you… if not, please let me know How I can use Windows Font such as True Type Font…

I read the specifiction of TTF, then I knew it also consisted of several paths. So, please let me see real character on my screen.

You can simply extract font outlines (and kerning information) using the Freetype library, then you can convert them into OpenVG commands and data.
I’ve written my TTF -> OpenVG 1.1 converter in a couple of hours, it’s very easy (the dark side of the job is done by the Freetype library).

For bitmap fonts you can use a root VGImage and upload a font “texture” like http://www.fontriver.com/i/maps/gothic_ … ta_map.png
Then you can create child images from your root image, in order to “extract” each font character.

Happy coding :slight_smile:

Now I got the concept!;;

But, can you give me the very simple code to convert FreeType to OpenVG 1.1 path using FreeType Library.?~~

Please… I tried to figure out the problem… But it is difficult to me~

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;
}