/src/_ttconv.cpp
C++ | 328 lines | 279 code | 39 blank | 10 comment | 25 complexity | 3b12b1a72e82ec0b65b83a4a100a0368 MD5 | raw file
- /* -*- mode: c++; c-basic-offset: 4 -*- */
- /*
- _ttconv.c
- Python wrapper for TrueType conversion library in ../ttconv.
- */
- #include "mplutils.h"
- #include <Python.h>
- #include "ttconv/pprdrv.h"
- #include <vector>
- #include <cassert>
- class PythonExceptionOccurred
- {
- };
- /**
- * An implementation of TTStreamWriter that writes to a Python
- * file-like object.
- */
- class PythonFileWriter : public TTStreamWriter
- {
- PyObject* _write_method;
- public:
- PythonFileWriter()
- {
- _write_method = NULL;
- }
- ~PythonFileWriter()
- {
- Py_XDECREF(_write_method);
- }
- void set(PyObject* write_method)
- {
- Py_XDECREF(_write_method);
- _write_method = write_method;
- Py_XINCREF(_write_method);
- }
- virtual void write(const char* a)
- {
- PyObject* result = NULL;
- if (_write_method)
- {
- PyObject* decoded = NULL;
- decoded = PyUnicode_DecodeLatin1(a, strlen(a), "");
- if (decoded == NULL) {
- throw PythonExceptionOccurred();
- }
- result = PyObject_CallFunction(_write_method, "O", decoded);
- Py_DECREF(decoded);
- if (! result)
- {
- throw PythonExceptionOccurred();
- }
- Py_DECREF(result);
- }
- }
- };
- int fileobject_to_PythonFileWriter(PyObject* object, void* address)
- {
- PythonFileWriter* file_writer = (PythonFileWriter*)address;
- PyObject* write_method = PyObject_GetAttrString(object, "write");
- if (write_method == NULL || ! PyCallable_Check(write_method))
- {
- PyErr_SetString(PyExc_TypeError, "Expected a file-like object with a write method.");
- return 0;
- }
- file_writer->set(write_method);
- Py_DECREF(write_method);
- return 1;
- }
- int pyiterable_to_vector_int(PyObject* object, void* address)
- {
- std::vector<int>* result = (std::vector<int>*)address;
- PyObject* iterator = PyObject_GetIter(object);
- if (! iterator)
- {
- return 0;
- }
- PyObject* item;
- while ((item = PyIter_Next(iterator)))
- {
- #if PY3K
- long value = PyLong_AsLong(item);
- #else
- long value = PyInt_AsLong(item);
- #endif
- Py_DECREF(item);
- if (value == -1 && PyErr_Occurred())
- {
- return 0;
- }
- result->push_back(value);
- }
- Py_DECREF(iterator);
- return 1;
- }
- static PyObject*
- convert_ttf_to_ps(PyObject* self, PyObject* args, PyObject* kwds)
- {
- const char* filename;
- PythonFileWriter output;
- int fonttype;
- std::vector<int> glyph_ids;
- static const char *kwlist[] =
- {
- "filename", "output", "fonttype", "glyph_ids", NULL
- };
- if (! PyArg_ParseTupleAndKeywords
- (args, kwds,
- #if PY_MAJOR_VERSION == 3
- "yO&i|O&:convert_ttf_to_ps",
- #else
- "sO&i|O&:convert_ttf_to_ps",
- #endif
- (char**)kwlist,
- &filename,
- fileobject_to_PythonFileWriter,
- &output,
- &fonttype,
- pyiterable_to_vector_int,
- &glyph_ids))
- {
- return NULL;
- }
- if (fonttype != 3 && fonttype != 42)
- {
- PyErr_SetString(PyExc_ValueError,
- "fonttype must be either 3 (raw Postscript) or 42 "
- "(embedded Truetype)");
- return NULL;
- }
- try
- {
- insert_ttfont(filename, output, (font_type_enum)fonttype, glyph_ids);
- }
- catch (TTException& e)
- {
- PyErr_SetString(PyExc_RuntimeError, e.getMessage());
- return NULL;
- }
- catch (PythonExceptionOccurred&)
- {
- return NULL;
- }
- catch (...)
- {
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return NULL;
- }
- Py_INCREF(Py_None);
- return Py_None;
- }
- class PythonDictionaryCallback : public TTDictionaryCallback
- {
- PyObject* _dict;
- public:
- PythonDictionaryCallback(PyObject* dict)
- {
- _dict = dict;
- }
- virtual void add_pair(const char* a, const char* b)
- {
- assert(a != NULL);
- assert(b != NULL);
- PyObject* value = PyBytes_FromString(b);
- if (!value)
- {
- throw PythonExceptionOccurred();
- }
- if (PyDict_SetItemString(_dict, a, value))
- {
- Py_DECREF(value);
- throw PythonExceptionOccurred();
- }
- Py_DECREF(value);
- }
- };
- static PyObject*
- py_get_pdf_charprocs(PyObject* self, PyObject* args, PyObject* kwds)
- {
- const char* filename;
- std::vector<int> glyph_ids;
- PyObject* result;
- static const char *kwlist[] = { "filename", "glyph_ids", NULL };
- if (! PyArg_ParseTupleAndKeywords
- (args, kwds,
- #if PY_MAJOR_VERSION == 3
- "y|O&:get_pdf_charprocs",
- #else
- "s|O&:get_pdf_charprocs",
- #endif
- (char **)kwlist,
- &filename,
- pyiterable_to_vector_int,
- &glyph_ids))
- {
- return NULL;
- }
- result = PyDict_New();
- if (!result)
- {
- return NULL;
- }
- PythonDictionaryCallback dict(result);
- try
- {
- ::get_pdf_charprocs(filename, glyph_ids, dict);
- }
- catch (TTException& e)
- {
- Py_DECREF(result);
- PyErr_SetString(PyExc_RuntimeError, e.getMessage());
- return NULL;
- }
- catch (PythonExceptionOccurred&)
- {
- Py_DECREF(result);
- return NULL;
- }
- catch (...)
- {
- Py_DECREF(result);
- PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
- return NULL;
- }
- return result;
- }
- static PyMethodDef ttconv_methods[] =
- {
- {
- "convert_ttf_to_ps", (PyCFunction)convert_ttf_to_ps, METH_VARARGS | METH_KEYWORDS,
- "convert_ttf_to_ps(filename, output, fonttype, glyph_ids)\n"
- "\n"
- "Converts the Truetype font into a Type 3 or Type 42 Postscript font, "
- "optionally subsetting the font to only the desired set of characters.\n"
- "\n"
- "filename is the path to a TTF font file.\n"
- "output is a Python file-like object with a write method that the Postscript "
- "font data will be written to.\n"
- "fonttype may be either 3 or 42. Type 3 is a \"raw Postscript\" font. "
- "Type 42 is an embedded Truetype font. Glyph subsetting is not supported "
- "for Type 42 fonts.\n"
- "glyph_ids (optional) is a list of glyph ids (integers) to keep when "
- "subsetting to a Type 3 font. If glyph_ids is not provided or is None, "
- "then all glyphs will be included. If any of the glyphs specified are "
- "composite glyphs, then the component glyphs will also be included."
- },
- {
- "get_pdf_charprocs", (PyCFunction)py_get_pdf_charprocs, METH_VARARGS | METH_KEYWORDS,
- "get_pdf_charprocs(filename, glyph_ids)\n"
- "\n"
- "Given a Truetype font file, returns a dictionary containing the PDF Type 3\n"
- "representation of its paths. Useful for subsetting a Truetype font inside\n"
- "of a PDF file.\n"
- "\n"
- "filename is the path to a TTF font file.\n"
- "glyph_ids is a list of the numeric glyph ids to include.\n"
- "The return value is a dictionary where the keys are glyph names and\n"
- "the values are the stream content needed to render that glyph. This\n"
- "is useful to generate the CharProcs dictionary in a PDF Type 3 font.\n"
- },
- {0, 0, 0, 0} /* Sentinel */
- };
- static const char* module_docstring =
- "Module to handle converting and subsetting TrueType "
- "fonts to Postscript Type 3, Postscript Type 42 and "
- "Pdf Type 3 fonts.";
- #if PY3K
- static PyModuleDef ttconv_module = {
- PyModuleDef_HEAD_INIT,
- "ttconv",
- module_docstring,
- -1,
- ttconv_methods,
- NULL, NULL, NULL, NULL
- };
- PyMODINIT_FUNC
- PyInit_ttconv(void)
- {
- PyObject* m;
- m = PyModule_Create(&ttconv_module);
- return m;
- }
- #else
- PyMODINIT_FUNC
- initttconv(void)
- {
- Py_InitModule3("ttconv", ttconv_methods, module_docstring);
- }
- #endif