diff options
-rw-r--r-- | fscalc.cpp | 102 | ||||
-rw-r--r-- | fscalc.h | 24 | ||||
-rw-r--r-- | pykfx/__init__.py (renamed from pykfx.py) | 7 | ||||
-rw-r--r-- | setup.py | 17 | ||||
-rw-r--r-- | wrapper.cpp | 12 |
5 files changed, 160 insertions, 2 deletions
diff --git a/fscalc.cpp b/fscalc.cpp new file mode 100644 index 0000000..6842a65 --- /dev/null +++ b/fscalc.cpp @@ -0,0 +1,102 @@ +#include <stdexcept> +#include "fscalc.h" + +Font::Font(std::string s, int slant, int weight) { + FcPattern *tmp1, *tmp2, *final; + FcResult res; + FcChar8 *filename; + int fontindex; + + if(!(fc = FcInitLoadConfigAndFonts())) + throw(std::runtime_error("failed to initialize fontconfig")); + + if(FT_Init_FreeType(&library)) + throw(std::runtime_error("failed to initialize freetype")); + + aux = FcPatternCreate(); + + tmp1 = FcPatternBuild(NULL, + FC_FAMILY, FcTypeString, s.c_str(), + FC_SLANT, FcTypeInteger, slant, + FC_WEIGHT, FcTypeInteger, weight ? 300 : 100, + NULL); + if(!tmp1) + throw(std::runtime_error("failed to load font")); + + tmp2 = FcFontRenderPrepare(fc, tmp1, aux); + FcPatternDestroy(tmp1); + final = FcFontMatch(fc, tmp2, &res); + FcPatternDestroy(tmp2); + if(!final) + throw(std::runtime_error("failed to load font")); + + if(FcPatternGetString(final, FC_FILE, 0, &filename) != FcResultMatch || FcPatternGetInteger(final, FC_INDEX, 0, &fontindex) != FcResultMatch) { + FcPatternDestroy(final); + throw(std::runtime_error("failed to locate font")); + } + + if(FT_New_Face(library, (char*)filename, fontindex, &face)) { + FcPatternDestroy(final); + throw(std::runtime_error("failed to create new face")); + } + + FcPatternDestroy(final); + FcPatternDestroy(aux); +// FcFini(); +} + +Font::~Font() { + FT_Done_Face(face); + FT_Done_FreeType(library); +} + +void Font::set_font_size(int size) { + FT_Size_RequestRec req; + TT_OS2 *os2; + TT_HoriHeader *hori; + float scale = 1.0; + + FT_Size_Metrics *m = &face->size->metrics; + + os2 = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2); + hori = (TT_HoriHeader*)FT_Get_Sfnt_Table(face, ft_sfnt_hhea); + if(os2 && hori) { + int horisum = hori->Ascender - hori->Descender; + unsigned int winsum = os2->usWinAscent + os2->usWinDescent; + scale = (float)horisum / (float)winsum; + } + + req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.width = 0; + req.height = (FT_F26Dot6)(size * 64 * scale); + req.horiResolution = 0; + req.vertResolution = 0; + FT_Request_Size(face, &req); +} + +double Font::get_kerning(FT_UInt left, FT_UInt right) { + if(FT_HAS_KERNING(face)) { + FT_Vector d; + FT_Get_Kerning(face, left, right, 0, &d); + return (double)d.x / 64.0; + } else return 0; +} + +unsigned int Font::get_text_width(std::string s) { + FT_UInt prev = 0; + bool kerning = FT_HAS_KERNING(face); + double width = 0; + for(std::string::iterator c = s.begin(); c < s.end(); c++) { + int i = FT_Get_Char_Index(face, *c); + if(kerning && prev && i) + width += get_kerning(prev, i); + if(FT_Load_Char(face, *c, 0)) + throw(std::runtime_error("failed to load char")); + width += (double)face->glyph->advance.x / 64.0; + } + return int(width); +} + +unsigned int Font::get_line_height() { + return face->bbox.yMax - face->bbox.yMin; +} diff --git a/fscalc.h b/fscalc.h new file mode 100644 index 0000000..5046b8f --- /dev/null +++ b/fscalc.h @@ -0,0 +1,24 @@ +#ifndef _FSCALC_H_ +#define _FSCALC_H_ + +#include <string> +#include <fontconfig/fontconfig.h> +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +class Font { + FcConfig *fc; + FcPattern *aux; + FT_Library library; + FT_Face face; + public: + Font(std::string, int, int); + ~Font(); + void set_font_size(int); + double get_kerning(FT_UInt, FT_UInt); + unsigned int get_text_width(std::string); + unsigned int get_line_height(); +}; + +#endif diff --git a/pykfx.py b/pykfx/__init__.py index b2cbff6..4ef55f1 100644 --- a/pykfx.py +++ b/pykfx/__init__.py @@ -50,12 +50,14 @@ class Style: class Styles: def __init__(self, f = None): - self.format, self.styles = [], {} + self.format, self.styles, self.names = [], {}, [] if f: self.read(f) def __getitem__(self, key): - if self.styles.has_key(key.lower()): + if type(key) == int: + return self.styles[self.names[key]] + elif self.styles.has_key(key.lower()): return self.styles[key.lower()] else: raise KeyError('style "%s" not found' % key) @@ -71,6 +73,7 @@ class Styles: while s: s = Style(self.format, s) self.styles[s.name.lower()] = s + self.names.append(s.name.lower()) s = f.readline().split() def write(self, f): diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c131572 --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +import subprocess, re +from distutils.core import setup, Extension + +freetype_config = subprocess.Popen('freetype-config --cflags --libs', shell = True, stdout = subprocess.PIPE).stdout.read() + +setup( + name = 'pykfx', + version = '0.1', + description = 'pykfx is a collection of classes for parsing ASS-scripts.', + author = 'Jon Bergli Heier', + author_email = 'jonheier@start.no', + packages = ['pykfx'], + ext_modules = [Extension('pykfx.fscalc', ['fscalc.cpp', 'wrapper.cpp'], + include_dirs = re.findall('-I[^\/\w]*([\w\/]+)', freetype_config), + libraries = ['boost_python', 'fontconfig'] + re.findall('-l\W*(\w+)', freetype_config), + )], +) diff --git a/wrapper.cpp b/wrapper.cpp new file mode 100644 index 0000000..9991b24 --- /dev/null +++ b/wrapper.cpp @@ -0,0 +1,12 @@ +#include <boost/python.hpp> +#include "fscalc.h" + +using namespace boost::python; + +BOOST_PYTHON_MODULE(fscalc) { + class_<Font>("Font", init<std::string, int, int>()) + .def("set_font_size", &Font::set_font_size) + .def("get_kerning", &Font::get_kerning) + .def("get_text_width", &Font::get_text_width) + .def("get_line_height", &Font::get_line_height); +} |