#include
#include "ft2font.h"
#include "mplutils.h"
#define FIXED_MAJOR(val) (*((short *) &val+1))
#define FIXED_MINOR(val) (*((short *) &val+0))
/**
To improve the hinting of the fonts, this code uses a hack
presented here:
http://antigrain.com/research/font_rasterization/index.html
The idea is to limit the effect of hinting in the x-direction, while
preserving hinting in the y-direction. Since freetype does not
support this directly, the dpi in the x-direction is set higher than
in the y-direction, which affects the hinting grid. Then, a global
transform is placed on the font to shrink it back to the desired
size. While it is a bit surprising that the dpi setting affects
hinting, whereas the global transform does not, this is documented
behavior of freetype, and therefore hopefully unlikely to change.
The freetype 2 tutorial says:
NOTE: The transformation is applied to every glyph that is
loaded through FT_Load_Glyph and is completely independent of
any hinting process. This means that you won't get the same
results if you load a glyph at the size of 24 pixels, or a glyph
at the size at 12 pixels scaled by 2 through a transform,
because the hints will have been computed differently (except
you have disabled hints).
This hack is enabled only when VERTICAL_HINTING is defined, and will
only be effective when load_char and set_text are called with 'flags=
LOAD_DEFAULT', which is the default.
*/
#define VERTICAL_HINTING
#ifdef VERTICAL_HINTING
#define HORIZ_HINTING 8
#else
#define HORIZ_HINTING 1
#endif
FT_Library _ft2Library;
// FT2Image::FT2Image() :
// _isDirty(true),
// _buffer(NULL),
// _width(0), _height(0),
// _rgbCopy(NULL),
// _rgbaCopy(NULL) {
// _VERBOSE("FT2Image::FT2Image");
// }
FT2Image::FT2Image(unsigned long width, unsigned long height) :
_isDirty(true),
_buffer(NULL),
_width(0), _height(0),
_rgbCopy(NULL),
_rgbaCopy(NULL) {
_VERBOSE("FT2Image::FT2Image");
resize(width, height);
}
FT2Image::~FT2Image() {
_VERBOSE("FT2Image::~FT2Image");
delete [] _buffer;
_buffer=NULL;
delete _rgbCopy;
delete _rgbaCopy;
}
void FT2Image::resize(unsigned long width, unsigned long height) {
size_t numBytes = width*height;
if (width != _width || height != _height) {
if (numBytes > _width*_height) {
delete [] _buffer;
_buffer = NULL;
_buffer = new unsigned char [numBytes];
}
_width = width;
_height = height;
}
memset(_buffer, 0, numBytes);
_isDirty = true;
}
void
FT2Image::draw_bitmap( FT_Bitmap* bitmap,
FT_Int x,
FT_Int y) {
_VERBOSE("FT2Image::draw_bitmap");
FT_Int image_width = (FT_Int)_width;
FT_Int image_height = (FT_Int)_height;
FT_Int char_width = bitmap->width;
FT_Int char_height = bitmap->rows;
FT_Int x1 = CLAMP(x, 0, image_width);
FT_Int y1 = CLAMP(y, 0, image_height);
FT_Int x2 = CLAMP(x + char_width, 0, image_width);
FT_Int y2 = CLAMP(y + char_height, 0, image_height);
FT_Int x_start = MAX(0, -x);
FT_Int y_offset = y1 - MAX(0, -y);
for ( FT_Int i = y1; i < y2; ++i ) {
unsigned char* dst = _buffer + (i * image_width + x1);
unsigned char* src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start);
for ( FT_Int j = x1; j < x2; ++j, ++dst, ++src )
*dst |= *src;
}
_isDirty = true;
}
void FT2Image::write_bitmap(const char* filename) const {
FILE *fh = fopen(filename, "w");
for ( size_t i = 0; i< _height; i++) {
for ( size_t j = 0; j < _width; ++j) {
if (_buffer[j + i*_width])
fputc('#', fh);
else
fputc(' ', fh);
}
fputc('\n', fh);
}
fclose(fh);
}
char FT2Image::write_bitmap__doc__[] =
"write_bitmap(fname)\n"
"\n"
"Write the bitmap to file fname\n"
;
Py::Object
FT2Image::py_write_bitmap(const Py::Tuple & args) {
_VERBOSE("FT2Image::write_bitmap");
args.verify_length(1);
std::string filename = Py::String(args[0]);
write_bitmap(filename.c_str());
return Py::Object();
}
void
FT2Image::draw_rect(unsigned long x0, unsigned long y0,
unsigned long x1, unsigned long y1) {
if ( x0_height )
throw Py::ValueError("Rect coords outside image bounds");
size_t top = y0*_width;
size_t bottom = y1*_width;
for (size_t i=x0; iresize(_width * 4, _height);
}
unsigned char *src = _buffer;
unsigned char *src_end = src + (_width * _height);
unsigned char *dst = _rgbaCopy->_buffer;
while (src != src_end) {
// We know the array has already been zero'ed out in
// the resize method, so we just skip over the r, g and b.
dst += 3;
*dst++ = *src++;
}
}
char FT2Image::as_rgba_str__doc__[] =
"width, height, s = image_as_rgb_str()\n"
"\n"
"Return the image buffer as a 32-bit RGBA string.\n"
"\n"
;
Py::Object
FT2Image::py_as_rgba_str(const Py::Tuple & args) {
_VERBOSE("FT2Image::as_str_rgba");
args.verify_length(0);
makeRgbaCopy();
return _rgbaCopy->py_as_str(args);
}
Py::Object
FT2Image::py_get_width(const Py::Tuple & args) {
_VERBOSE("FT2Image::get_width");
args.verify_length(0);
return Py::Int((long)get_width());
}
Py::Object
FT2Image::py_get_height(const Py::Tuple & args) {
_VERBOSE("FT2Image::get_height");
args.verify_length(0);
return Py::Int((long)get_height());
}
Glyph::Glyph( const FT_Face& face, const FT_Glyph& glyph, size_t ind) :
glyphInd(ind) {
_VERBOSE("Glyph::Glyph");
FT_BBox bbox;
FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_subpixels, &bbox );
setattr("width", Py::Int( face->glyph->metrics.width / HORIZ_HINTING) );
setattr("height", Py::Int( face->glyph->metrics.height) );
setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX / HORIZ_HINTING) );
setattr("horiBearingY", Py::Int( face->glyph->metrics.horiBearingY) );
setattr("horiAdvance", Py::Int( face->glyph->metrics.horiAdvance) );
setattr("linearHoriAdvance", Py::Int( face->glyph->linearHoriAdvance / HORIZ_HINTING) );
setattr("vertBearingX", Py::Int( face->glyph->metrics.vertBearingX) );
setattr("vertBearingY", Py::Int( face->glyph->metrics.vertBearingY) );
setattr("vertAdvance", Py::Int( face->glyph->metrics.vertAdvance) );
//setattr("bitmap_left", Py::Int( face->glyph->bitmap_left) );
//setattr("bitmap_top", Py::Int( face->glyph->bitmap_top) );
Py::Tuple abbox(4);
abbox[0] = Py::Int(bbox.xMin);
abbox[1] = Py::Int(bbox.yMin);
abbox[2] = Py::Int(bbox.xMax);
abbox[3] = Py::Int(bbox.yMax);
setattr("bbox", abbox);
setattr("path", get_path(face));
}
Glyph::~Glyph() {
_VERBOSE("Glyph::~Glyph");
}
int
Glyph::setattr( const char *name, const Py::Object &value ) {
_VERBOSE("Glyph::setattr");
__dict__[name] = value;
return 0;
}
Py::Object
Glyph::getattr( const char *name ) {
_VERBOSE("Glyph::getattr");
if ( __dict__.hasKey(name) ) return __dict__[name];
else return getattr_default( name );
}
inline double conv(int v)
{
return double(v) / 64.0;
}
//see http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
Py::Object
Glyph::get_path( const FT_Face& face) {
//get the glyph as a path, a list of (COMMAND, *args) as desribed in matplotlib.path
// this code is from agg's decompose_ft_outline with minor modifications
enum {MOVETO, LINETO, CURVE3, CURVE4, ENDPOLY};
FT_Outline& outline = face->glyph->outline;
Py::List path;
bool flip_y= false; //todo, pass me as kwarg
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
FT_Vector* point;
FT_Vector* limit;
char* tags;
int n; // index of contour in outline
int first; // index of first point in contour
char tag; // current point's state
first = 0;
for(n = 0; n < outline.n_contours; n++)
{
int last; // index of last point in contour
last = outline.contours[n];
limit = outline.points + last;
v_start = outline.points[first];
v_last = outline.points[last];
v_control = v_start;
point = outline.points + first;
tags = outline.tags + first;
tag = FT_CURVE_TAG(tags[0]);
// A contour cannot start with a cubic control point!
if(tag == FT_CURVE_TAG_CUBIC) return Py::Object();
// check first point to determine origin
if( tag == FT_CURVE_TAG_CONIC)
{
// first point is conic control. Yes, this happens.
if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
{
// start at last point if it is on the curve
v_start = v_last;
limit--;
}
else
{
// if both first and last points are conic,
// start at their middle and record its position
// for closure
v_start.x = (v_start.x + v_last.x) / 2;
v_start.y = (v_start.y + v_last.y) / 2;
v_last = v_start;
}
point--;
tags--;
}
double x = conv(v_start.x);
double y = flip_y ? -conv(v_start.y) : conv(v_start.y);
Py::Tuple tup(3);
tup[0] = Py::Int(MOVETO);
tup[1] = Py::Float(x);
tup[2] = Py::Float(y);
path.append(tup);
Py::Tuple closepoly(2);
closepoly[0] = Py::Int(ENDPOLY);
closepoly[1] = Py::Int(0);
while(point < limit)
{
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
switch(tag)
{
case FT_CURVE_TAG_ON: // emit a single line_to
{
double x = conv(point->x);
double y = flip_y ? -conv(point->y) : conv(point->y);
Py::Tuple tup(3);
tup[0] = Py::Int(LINETO);
tup[1] = Py::Float(x);
tup[2] = Py::Float(y);
path.append(tup);
continue;
}
case FT_CURVE_TAG_CONIC: // consume conic arcs
{
v_control.x = point->x;
v_control.y = point->y;
Do_Conic:
if(point < limit)
{
FT_Vector vec;
FT_Vector v_middle;
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
vec.x = point->x;
vec.y = point->y;
if(tag == FT_CURVE_TAG_ON)
{
double xctl = conv(v_control.x);
double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y);
double xto = conv(vec.x);
double yto = flip_y ? -conv(vec.y) : conv(vec.y);
Py::Tuple tup(5);
tup[0] = Py::Int(CURVE3);
tup[1] = Py::Float(xctl);
tup[2] = Py::Float(yctl);
tup[3] = Py::Float(xto);
tup[4] = Py::Float(yto);
path.append(tup);
continue;
}
if(tag != FT_CURVE_TAG_CONIC) return Py::Object();
v_middle.x = (v_control.x + vec.x) / 2;
v_middle.y = (v_control.y + vec.y) / 2;
double xctl = conv(v_control.x);
double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y);
double xto = conv(v_middle.x);
double yto = flip_y ? -conv(v_middle.y) : conv(v_middle.y);
Py::Tuple tup(5);
tup[0] = Py::Int(CURVE3);
tup[1] = Py::Float(xctl);
tup[2] = Py::Float(yctl);
tup[3] = Py::Float(xto);
tup[4] = Py::Float(yto);
path.append(tup);
v_control = vec;
goto Do_Conic;
}
double xctl = conv(v_control.x);
double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y);
double xto = conv(v_start.x);
double yto = flip_y ? -conv(v_start.y) : conv(v_start.y);
Py::Tuple tup(5);
tup[0] = Py::Int(CURVE3);
tup[1] = Py::Float(xctl);
tup[2] = Py::Float(yctl);
tup[3] = Py::Float(xto);
tup[4] = Py::Float(yto);
path.append(tup);
goto Close;
}
default: // FT_CURVE_TAG_CUBIC
{
FT_Vector vec1, vec2;
if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
{
return Py::Object();
}
vec1.x = point[0].x;
vec1.y = point[0].y;
vec2.x = point[1].x;
vec2.y = point[1].y;
point += 2;
tags += 2;
if(point x;
vec.y = point->y;
double xctl1 = conv(vec1.x);
double yctl1 = flip_y ? -conv(vec1.y) : conv(vec1.y);
double xctl2 = conv(vec2.x);
double yctl2 = flip_y ? -conv(vec2.y) : conv(vec2.y);
double xto = conv(vec.x);
double yto = flip_y ? -conv(vec.y) : conv(vec.y);
Py::Tuple tup(7);
tup[0] = Py::Int(CURVE4);
tup[1] = Py::Float(xctl1);
tup[2] = Py::Float(yctl1);
tup[3] = Py::Float(xctl2);
tup[4] = Py::Float(yctl2);
tup[5] = Py::Float(xto);
tup[6] = Py::Float(yto);
path.append(tup);
continue;
}
double xctl1 = conv(vec1.x);
double yctl1 = flip_y ? -conv(vec1.y) : conv(vec1.y);
double xctl2 = conv(vec2.x);
double yctl2 = flip_y ? -conv(vec2.y) : conv(vec2.y);
double xto = conv(v_start.x);
double yto = flip_y ? -conv(v_start.y) : conv(v_start.y);
Py::Tuple tup(7);
tup[0] = Py::Int(CURVE4);
tup[1] = Py::Float(xctl1);
tup[2] = Py::Float(yctl1);
tup[3] = Py::Float(xctl2);
tup[4] = Py::Float(yctl2);
tup[5] = Py::Float(xto);
tup[6] = Py::Float(yto);
path.append(tup);
goto Close;
}
}
}
path.append(closepoly);
Close:
first = last + 1;
}
return path;
}
FT2Font::FT2Font(std::string facefile) :
image(NULL)
{
_VERBOSE(Printf("FT2Font::FT2Font %s", facefile.c_str()).str());
clear(Py::Tuple(0));
int error = FT_New_Face( _ft2Library, facefile.c_str(), 0, &face );
if (error == FT_Err_Unknown_File_Format ) {
std::ostringstream s;
s underline_thickness));
}
setattr("fname", Py::String(facefile));
_VERBOSE("FT2Font::FT2Font done");
}
FT2Font::~FT2Font()
{
_VERBOSE("FT2Font::~FT2Font");
Py_XDECREF(image);
FT_Done_Face ( face );
for (size_t i=0; i bbox.xMax ) bbox.xMax = glyph_bbox.xMax;
if ( glyph_bbox.yMax > bbox.yMax ) bbox.yMax = glyph_bbox.yMax;
}
/* check that we really grew the string bbox */
if ( bbox.xMin > bbox.xMax ) {
bbox.xMin = 0; bbox.yMin = 0; bbox.xMax = 0; bbox.yMax = 0;
}
return bbox;
}
char FT2Font::get_kerning__doc__[] =
"dx = get_kerning(left, right, mode)\n"
"\n"
"Get the kerning between left char and right glyph indices\n"
"mode is a kerning mode constant\n"
" KERNING_DEFAULT - Return scaled and grid-fitted kerning distances\n"
" KERNING_UNFITTED - Return scaled but un-grid-fitted kerning distances\n"
" KERNING_UNSCALED - Return the kerning vector in original font units\n"
;
Py::Object
FT2Font::get_kerning(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_kerning");
args.verify_length(3);
int left = Py::Int(args[0]);
int right = Py::Int(args[1]);
int mode = Py::Int(args[2]);
if (!FT_HAS_KERNING( face )) return Py::Int(0);
FT_Vector delta;
if (!FT_Get_Kerning( face, left, right, mode, &delta )) {
return Py::Int(delta.x / HORIZ_HINTING);
}
else {
return Py::Int(0);
}
}
char FT2Font::set_text__doc__[] =
"set_text(s, angle)\n"
"\n"
"Set the text string and angle.\n"
"You must call this before draw_glyphs_to_bitmap\n"
"A sequence of x,y positions is returned";
Py::Object
FT2Font::set_text(const Py::Tuple & args, const Py::Dict & kwargs) {
_VERBOSE("FT2Font::set_text");
args.verify_length(2);
Py::String text( args[0] );
std::string stdtext="";
Py_UNICODE* pcode=NULL;
size_t N = 0;
if (PyUnicode_Check(text.ptr())) {
pcode = PyUnicode_AsUnicode(text.ptr());
N = PyUnicode_GetSize(text.ptr());
}
else {
stdtext = text.as_std_string();
N = stdtext.size();
}
angle = Py::Float(args[1]);
angle = angle/360.0*2*3.14159;
long flags = FT_LOAD_FORCE_AUTOHINT;
if (kwargs.hasKey("flags"))
flags = Py::Long(kwargs["flags"]);
//this computes width and height in subpixels so we have to divide by 64
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
FT_Bool use_kerning = FT_HAS_KERNING( face );
FT_UInt previous = 0;
glyphs.resize(0);
pen.x = 0;
pen.y = 0;
Py::Tuple xys(N);
for ( unsigned int n = 0; n < N; n++ ) {
std::string thischar("?");
FT_UInt glyph_index;
if (pcode==NULL) {
// plain ol string
thischar = stdtext[n];
glyph_index = FT_Get_Char_Index( face, stdtext[n] );
}
else {
//unicode
glyph_index = FT_Get_Char_Index( face, pcode[n] );
}
// retrieve kerning distance and move pen position
if ( use_kerning && previous && glyph_index ) {
FT_Vector delta;
FT_Get_Kerning( face, previous, glyph_index,
FT_KERNING_DEFAULT, &delta );
pen.x += delta.x / HORIZ_HINTING;
}
error = FT_Load_Glyph( face, glyph_index, flags );
if ( error ) {
std::cerr top + 1);
image->draw_bitmap( &bitmap->bitmap, x, y);
}
return Py::Object();
}
char FT2Font::get_xys__doc__[] =
"get_xys()\n"
"\n"
"Get the xy locations of the current glyphs\n"
;
Py::Object
FT2Font::get_xys(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_xys");
args.verify_length(0);
FT_BBox string_bbox = compute_string_bbox();
Py::Tuple xys(glyphs.size());
for ( size_t n = 0; n < glyphs.size(); n++ )
{
FT_BBox bbox;
FT_Glyph_Get_CBox(glyphs[n], ft_glyph_bbox_pixels, &bbox);
error = FT_Glyph_To_Bitmap(&glyphs[n],
ft_render_mode_normal,
0,
1
);
if (error)
throw Py::RuntimeError("Could not convert glyph to bitmap");
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n];
//bitmap left and top in pixel, string bbox in subpixel
FT_Int x = (FT_Int)(bitmap->left-string_bbox.xMin/64.);
FT_Int y = (FT_Int)(string_bbox.yMax/64.-bitmap->top+1);
//make sure the index is non-neg
x = x= glyphs.size())
throw Py::ValueError("glyph num is out of range");
error = FT_Glyph_To_Bitmap(&glyphs[glyph->glyphInd],
ft_render_mode_normal,
0, //no additional translation
1 //destroy image;
);
if (error)
throw Py::RuntimeError("Could not convert glyph to bitmap");
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyph->glyphInd];
im->draw_bitmap( &bitmap->bitmap, x + bitmap->left, y);
return Py::Object();
}
char FT2Font::get_glyph_name__doc__[] =
"get_glyph_name(index)\n"
"\n"
"Retrieves the ASCII name of a given glyph in a face.\n"
;
Py::Object
FT2Font::get_glyph_name(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_glyph_name");
args.verify_length(1);
if (!FT_HAS_GLYPH_NAMES(face))
throw Py::RuntimeError("Face has no glyph names");
char buffer[128];
if (FT_Get_Glyph_Name(face, (FT_UInt) Py::Int(args[0]), buffer, 128))
throw Py::RuntimeError("Could not get glyph names.");
return Py::String(buffer);
}
char FT2Font::get_charmap__doc__[] =
"get_charmap()\n"
"\n"
"Returns a dictionary that maps the character codes of the selected charmap\n"
"(Unicode by default) to their corresponding glyph indices.\n"
;
Py::Object
FT2Font::get_charmap(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_charmap");
args.verify_length(0);
FT_UInt index;
Py::Dict charmap;
FT_ULong code = FT_Get_First_Char(face, &index);
while (index != 0) {
charmap[Py::Long((long) code)] = Py::Int((int) index);
code = FT_Get_Next_Char(face, code, &index);
}
return charmap;
}
// ID Platform Encoding
// 0 Unicode Reserved (set to 0)
// 1 Macintoch The Script Manager code
// 2 ISO ISO encoding
// 3 Microsoft Microsoft encoding
// 240-255 User-defined Reserved for all nonregistered platforms
// Code ISO encoding scheme
// 0 7-bit ASCII
// 1 ISO 10646
// 2 ISO 8859-1
// Code Language Code Language Code
// 0 English 10 Hebrew 20 Urdu
// 1 French 11 Japanese 21 Hindi
// 2 German 12 Arabic 22 Thai
// 3 Italian 13 Finnish
// 4 Dutch 14 Greek
// 5 Swedish 15 Icelandic
// 6 Spanish 16 Maltese
// 7 Danish 17 Turkish
// 8 Portuguese 18 Yugoslavian
// 9 Norwegian 19 Chinese
// Code Meaning Description
// 0 Copyright notice e.g. "Copyright Apple Computer, Inc. 1992
// 1 Font family name e.g. "New York"
// 2 Font style e.g. "Bold"
// 3 Font identification e.g. "Apple Computer New York Bold Ver 1"
// 4 Full font name e.g. "New York Bold"
// 5 Version string e.g. "August 10, 1991, 1.08d21"
// 6 Postscript name e.g. "Times-Bold"
// 7 Trademark
// 8 Designer e.g. "Apple Computer"
char FT2Font::get_sfnt__doc__[] =
"get_sfnt(name)\n"
"\n"
"Get all values from the SFNT names table. Result is a dictionary whose"
"key is the platform-ID, ISO-encoding-scheme, language-code, and"
"description.\n"
/*
"The font name identifier codes are:\n"
"\n"
" 0 Copyright notice e.g. Copyright Apple Computer, Inc. 1992\n"
" 1 Font family name e.g. New York\n"
" 2 Font style e.g. Bold\n"
" 3 Font identification e.g. Apple Computer New York Bold Ver 1\n"
" 4 Full font name e.g. New York Bold\n"
" 5 Version string e.g. August 10, 1991, 1.08d21\n"
" 6 Postscript name e.g. Times-Bold\n"
" 7 Trademark \n"
" 8 Designer e.g. Apple Computer\n"
" 11 URL e.g. http://www.apple.com\n"
" 13 Copyright license \n"
*/
;
Py::Object
FT2Font::get_sfnt(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_sfnt");
args.verify_length(0);
if (!(face->face_flags & FT_FACE_FLAG_SFNT))
throw Py::RuntimeError("No SFNT name table");
size_t count = FT_Get_Sfnt_Name_Count(face);
Py::Dict names;
for (size_t j = 0; j < count; j++) {
FT_SfntName sfnt;
FT_Error error = FT_Get_Sfnt_Name(face, j, &sfnt);
if (error)
throw Py::RuntimeError("Could not get SFNT name");
Py::Tuple key(4);
key[0] = Py::Int(sfnt.platform_id);
key[1] = Py::Int(sfnt.encoding_id);
key[2] = Py::Int(sfnt.language_id);
key[3] = Py::Int(sfnt.name_id);
names[key] = Py::String((char *) sfnt.string,
(int) sfnt.string_len);
}
return names;
}
char FT2Font::get_name_index__doc__[] =
"get_name_index(name)\n"
"\n"
"Returns the glyph index of a given glyph name.\n"
"The glyph index 0 means `undefined character code'.\n"
;
Py::Object
FT2Font::get_name_index(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_name_index");
args.verify_length(1);
std::string glyphname = Py::String(args[0]);
return Py::Long((long)
FT_Get_Name_Index(face, (FT_String *) glyphname.c_str()));
}
char FT2Font::get_ps_font_info__doc__[] =
"get_ps_font_info()\n"
"\n"
"Return the information in the PS Font Info structure.\n"
;
Py::Object
FT2Font::get_ps_font_info(const Py::Tuple & args)
{
_VERBOSE("FT2Font::get_ps_font_info");
args.verify_length(0);
PS_FontInfoRec fontinfo;
FT_Error error = FT_Get_PS_Font_Info(face, &fontinfo);
if (error) {
Py::RuntimeError("Could not get PS font info");
return Py::Object();
}
Py::Tuple info(9);
info[0] = Py::String(fontinfo.version ? fontinfo.version : "");
info[1] = Py::String(fontinfo.notice ? fontinfo.notice : "");
info[2] = Py::String(fontinfo.full_name ? fontinfo.full_name : "");
info[3] = Py::String(fontinfo.family_name ? fontinfo.family_name : "");
info[4] = Py::String(fontinfo.weight ? fontinfo.weight : "");
info[5] = Py::Long(fontinfo.italic_angle);
info[6] = Py::Int(fontinfo.is_fixed_pitch);
info[7] = Py::Int(fontinfo.underline_position);
info[8] = Py::Int(fontinfo.underline_thickness);
return info;
}
char FT2Font::get_sfnt_table__doc__[] =
"get_sfnt_table(name)\n"
"\n"
"Return one of the following SFNT tables: head, maxp, OS/2, hhea, "
"vhea, post, or pclt.\n"
;
Py::Object
FT2Font::get_sfnt_table(const Py::Tuple & args) {
_VERBOSE("FT2Font::get_sfnt_table");
args.verify_length(1);
std::string tagname = Py::String(args[0]);
int tag;
const char *tags[] = {"head", "maxp", "OS/2", "hhea",
"vhea", "post", "pclt", NULL};
for (tag=0; tags[tag] != NULL; tag++)
if (strcmp(tagname.c_str(), tags[tag]) == 0)
break;
void *table = FT_Get_Sfnt_Table(face, (FT_Sfnt_Tag) tag);
if (!table)
return Py::Object();
//throw Py::RuntimeError("Could not get SFNT table");
switch (tag) {
case 0:
{
char head_dict[] = "{s:(h,h), s:(h,h), s:l, s:l, s:i, s:i,"
"s:(l,l), s:(l,l), s:h, s:h, s:h, s:h, s:i, s:i, s:h, s:h, s:h}";
TT_Header *t = (TT_Header *)table;
return Py::asObject(Py_BuildValue(head_dict,
"version",
FIXED_MAJOR(t->Table_Version),
FIXED_MINOR(t->Table_Version),
"fontRevision",
FIXED_MAJOR(t->Font_Revision),
FIXED_MINOR(t->Font_Revision),
"checkSumAdjustment", t->CheckSum_Adjust,
"magicNumber" , t->Magic_Number,
"flags", (unsigned)t->Flags,
"unitsPerEm", (unsigned)t->Units_Per_EM,
"created", t->Created[0], t->Created[1],
"modified", t->Modified[0],t->Modified[1],
"xMin", t->xMin,
"yMin", t->yMin,
"xMax", t->xMax,
"yMax", t->yMax,
"macStyle", (unsigned)t->Mac_Style,
"lowestRecPPEM", (unsigned)t->Lowest_Rec_PPEM,
"fontDirectionHint", t->Font_Direction,
"indexToLocFormat", t->Index_To_Loc_Format,
"glyphDataFormat", t->Glyph_Data_Format));
}
case 1:
{
char maxp_dict[] = "{s:(h,h), s:i, s:i, s:i, s:i, s:i, s:i,"
"s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i}";
TT_MaxProfile *t = (TT_MaxProfile *)table;
return Py::asObject(Py_BuildValue(maxp_dict,
"version",
FIXED_MAJOR(t->version),
FIXED_MINOR(t->version),
"numGlyphs", (unsigned)t->numGlyphs,
"maxPoints", (unsigned)t->maxPoints,
"maxContours", (unsigned)t->maxContours,
"maxComponentPoints",
(unsigned)t->maxCompositePoints,
"maxComponentContours",
(unsigned)t->maxCompositeContours,
"maxZones", (unsigned)t->maxZones,
"maxTwilightPoints",(unsigned)t->maxTwilightPoints,
"maxStorage", (unsigned)t->maxStorage,
"maxFunctionDefs",(unsigned)t->maxFunctionDefs,
"maxInstructionDefs",
(unsigned)t->maxInstructionDefs,
"maxStackElements",(unsigned)t->maxStackElements,
"maxSizeOfInstructions",
(unsigned)t->maxSizeOfInstructions,
"maxComponentElements",
(unsigned)t->maxComponentElements,
"maxComponentDepth",
(unsigned)t->maxComponentDepth));
}
case 2:
{
char os_2_dict[] = "{s:h, s:h, s:h, s:h, s:h, s:h, s:h, s:h,"
"s:h, s:h, s:h, s:h, s:h, s:h, s:h, s:h, s:s#, s:(llll),"
"s:s#, s:h, s:h, s:h}";
TT_OS2 *t = (TT_OS2 *)table;
return Py::asObject(Py_BuildValue(os_2_dict,
"version", (unsigned)t->version,
"xAvgCharWidth", t->xAvgCharWidth,
"usWeightClass", (unsigned)t->usWeightClass,
"usWidthClass", (unsigned)t->usWidthClass,
"fsType", t->fsType,
"ySubscriptXSize", t->ySubscriptXSize,
"ySubscriptYSize", t->ySubscriptYSize,
"ySubscriptXOffset", t->ySubscriptXOffset,
"ySubscriptYOffset", t->ySubscriptYOffset,
"ySuperscriptXSize", t->ySuperscriptXSize,
"ySuperscriptYSize", t->ySuperscriptYSize,
"ySuperscriptXOffset", t->ySuperscriptXOffset,
"ySuperscriptYOffset", t->ySuperscriptYOffset,
"yStrikeoutSize", t->yStrikeoutSize,
"yStrikeoutPosition", t->yStrikeoutPosition,
"sFamilyClass", t->sFamilyClass,
"panose", t->panose, 10,
"ulCharRange",
(unsigned long) t->ulUnicodeRange1,
(unsigned long) t->ulUnicodeRange2,
(unsigned long) t->ulUnicodeRange3,
(unsigned long) t->ulUnicodeRange4,
"achVendID", t->achVendID, 4,
"fsSelection", (unsigned)t->fsSelection,
"fsFirstCharIndex",(unsigned)t->usFirstCharIndex,
"fsLastCharIndex",(unsigned)t->usLastCharIndex));
}
case 3:
{
char hhea_dict[] = "{s:(h,h), s:h, s:h, s:h, s:i, s:h, s:h, s:h,"
"s:h, s:h, s:h, s:h, s:i}";
TT_HoriHeader *t = (TT_HoriHeader *)table;
return Py::asObject(Py_BuildValue(hhea_dict,
"version",
FIXED_MAJOR(t->Version),
FIXED_MINOR(t->Version),
"ascent", t->Ascender,
"descent", t->Descender,
"lineGap", t->Line_Gap,
"advanceWidthMax",(unsigned)t->advance_Width_Max,
"minLeftBearing", t->min_Left_Side_Bearing,
"minRightBearing", t->min_Right_Side_Bearing,
"xMaxExtent", t->xMax_Extent,
"caretSlopeRise", t->caret_Slope_Rise,
"caretSlopeRun", t->caret_Slope_Run,
"caretOffset", t->caret_Offset,
"metricDataFormat", t->metric_Data_Format,
"numOfLongHorMetrics",
(unsigned)t->number_Of_HMetrics));
}
case 4:
{
char vhea_dict[] = "{s:(h,h), s:h, s:h, s:h, s:i, s:h, s:h, s:h,"
"s:h, s:h, s:h, s:h, s:i}";
TT_VertHeader *t = (TT_VertHeader *)table;
return Py::asObject(Py_BuildValue(vhea_dict,
"version",
FIXED_MAJOR(t->Version),
FIXED_MINOR(t->Version),
"vertTypoAscender", t->Ascender,
"vertTypoDescender", t->Descender,
"vertTypoLineGap", t->Line_Gap,
"advanceHeightMax",(unsigned)t->advance_Height_Max,
"minTopSideBearing", t->min_Top_Side_Bearing,
"minBottomSizeBearing", t->min_Bottom_Side_Bearing,
"yMaxExtent", t->yMax_Extent,
"caretSlopeRise", t->caret_Slope_Rise,
"caretSlopeRun", t->caret_Slope_Run,
"caretOffset", t->caret_Offset,
"metricDataFormat", t->metric_Data_Format,
"numOfLongVerMetrics",
(unsigned)t->number_Of_VMetrics));
}
case 5:
{
TT_Postscript *t = (TT_Postscript *)table;
Py::Dict post;
Py::Tuple format(2), angle(2);
format[0] = Py::Int(FIXED_MAJOR(t->FormatType));
format[1] = Py::Int(FIXED_MINOR(t->FormatType));
post["format"] = format;
angle[0] = Py::Int(FIXED_MAJOR(t->italicAngle));
angle[1] = Py::Int(FIXED_MINOR(t->italicAngle));
post["italicAngle"] = angle;
post["underlinePosition"] = Py::Int(t->underlinePosition);
post["underlineThickness"] = Py::Int(t->underlineThickness);
post["isFixedPitch"] = Py::Long((long) t->isFixedPitch);
post["minMemType42"] = Py::Long((long) t->minMemType42);
post["maxMemType42"] = Py::Long((long) t->maxMemType42);
post["minMemType1"] = Py::Long((long) t->minMemType1);
post["maxMemType1"] = Py::Long((long) t->maxMemType1);
return post;
}
case 6:
{
TT_PCLT *t = (TT_PCLT *)table;
Py::Dict pclt;
Py::Tuple version(2);
version[0] = Py::Int(FIXED_MAJOR(t->Version));
version[1] = Py::Int(FIXED_MINOR(t->Version));
pclt["version"] = version;
pclt["fontNumber"] = Py::Long((long) t->FontNumber);
pclt["pitch"] = Py::Int((short) t->Pitch);
pclt["xHeight"] = Py::Int((short) t->xHeight);
pclt["style"] = Py::Int((short) t->Style);
pclt["typeFamily"] = Py::Int((short) t->TypeFamily);
pclt["capHeight"] = Py::Int((short) t->CapHeight);
pclt["symbolSet"] = Py::Int((short) t->SymbolSet);
pclt["typeFace"] = Py::String((char *) t->TypeFace, 16);
pclt["characterComplement"] = Py::String((char *)
t->CharacterComplement, 8);
pclt["filename"] = Py::String((char *) t->FileName, 6);
pclt["strokeWeight"] = Py::Int((int) t->StrokeWeight);
pclt["widthType"] = Py::Int((int) t->WidthType);
pclt["serifStyle"] = Py::Int((int) t->SerifStyle);
return pclt;
}
default:
return Py::Object();
}
}
char FT2Font::get_image__doc__ [] =
"get_image()\n"
"\n"
"Returns the underlying image buffer for this font object.\n";
Py::Object
FT2Font::get_image (const Py::Tuple &args) {
args.verify_length(0);
if (image) {
Py_XINCREF(image);
return Py::asObject(image);
}
throw Py::RuntimeError("You must call .set_text() before .get_image()");
}
char FT2Font::attach_file__doc__ [] =
"attach_file(filename)\n"
"\n"
"Attach a file with extra information on the font\n"
"(in practice, an AFM file with the metrics of a Type 1 font).\n"
"Throws an exception if unsuccessful.\n";
Py::Object
FT2Font::attach_file (const Py::Tuple &args) {
args.verify_length(1);
std::string filename = Py::String(args[0]);
FT_Error error =
FT_Attach_File(face, filename.c_str());
if (error) {
std::ostringstream s;
s