/* -*- mode: c++; c-basic-offset: 4 -*- */ /* _ttconv.c Python wrapper for TrueType conversion library in ../ttconv. */ #include "mplutils.h" #include #include "ttconv/pprdrv.h" #include 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* result = (std::vector*)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 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) { PyObject* value = PyBytes_FromString(b); if (value) { 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 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