summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fscalc.cpp102
-rw-r--r--fscalc.h24
-rw-r--r--pykfx/__init__.py (renamed from pykfx.py)7
-rw-r--r--setup.py17
-rw-r--r--wrapper.cpp12
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);
+}