From 5e235e53ef38df9fb75b4d15c372d8be2b0ae05b Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Tue, 29 Oct 2013 20:41:39 -0400 Subject: Initial commit. --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70af57f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +* +!.gitignore +!*/ +!debian/* diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000..9559d13 --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,9 @@ +!.gitignore +!* +files +*.debhelper.log +*.substvars +tmp/ +python-cairocffi/ +python3-cairocffi/ +cairocffi-doc/ diff --git a/debian/cairocffi-doc.doc-base b/debian/cairocffi-doc.doc-base new file mode 100644 index 0000000..98795b1 --- /dev/null +++ b/debian/cairocffi-doc.doc-base @@ -0,0 +1,10 @@ +Document: cairocffi +Title: cairocffi manual +Author: Simon Sapin +Abstract: cairocffi is a CFFI-based drop-in replacement for Pycairo, a set of + Python bindings and object-oriented API for cairo. +Section: Text + +Format: HTML +Index: /usr/share/doc/cairocffi-doc/html/index.html +Files: /usr/share/doc/cairocffi-doc/html/*.html diff --git a/debian/cairocffi-doc.docs b/debian/cairocffi-doc.docs new file mode 100644 index 0000000..dd2636a --- /dev/null +++ b/debian/cairocffi-doc.docs @@ -0,0 +1 @@ +docs/_build/html/ diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..2b3b964 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +cairocffi (0.5.1-1) unstable; urgency=low + + * Initial release + + -- "P. J. McDermott" Tue, 29 Oct 2013 15:32:33 -0400 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..ceb0a95 --- /dev/null +++ b/debian/control @@ -0,0 +1,64 @@ +Source: cairocffi +Section: python +Priority: optional +Maintainer: "P. J. McDermott" +Build-Depends: debhelper (>= 9), +# Needed to build Python 2 modules: + python-all (>= 2.6.6-3~), + python-setuptools, +# Needed to build Python 3 modules: + python3-all (>= 3.1.2-7~), + python3-setuptools, +# Needed to build documenation: + python-sphinx, +# Needed to build documentation with sphinx.ext.autodoc: + python-cffi, +# Needed to build documentation with sphinx.ext.intersphinx: + python-cairo-dev, +Standards-Version: 3.9.4 +Homepage: http://pythonhosted.org/cairocffi/ +X-Python-Version: >= 2.6 +X-Python3-Version: >= 3.1 + +Package: python-cairocffi +Architecture: all +Depends: ${misc:Depends}, ${python:Depends}, +Description: CFFI-based Python bindings for cairo (Python 2) + cairocffi is a CFFI-based drop-in replacement for Pycairo, a set of Python + bindings and object-oriented API for cairo. Cairo is a 2D vector graphics + library with support for multiple backends including image buffers, PNG, + PostScript, PDF, and SVG file output. + . + Additionally, the cairocffi.pixbuf module uses GDK-PixBuf to decode various + image formats for use in cairo. + . + This package provides the Python 2 modules for the cairocffi bindings. + +Package: python3-cairocffi +Architecture: all +Depends: ${misc:Depends}, ${python3:Depends}, +Description: CFFI-based Python bindings for cairo (Python 3) + cairocffi is a CFFI-based drop-in replacement for Pycairo, a set of Python + bindings and object-oriented API for cairo. Cairo is a 2D vector graphics + library with support for multiple backends including image buffers, PNG, + PostScript, PDF, and SVG file output. + . + Additionally, the cairocffi.pixbuf module uses GDK-PixBuf to decode various + image formats for use in cairo. + . + This package provides the Python 3 modules for the cairocffi bindings. + +Package: cairocffi-doc +Section: doc +Architecture: all +Depends: ${misc:Depends}, ${sphinxdoc:Depends}, +Description: Rendering engine to convert HTML/CSS to PDF - documentation + cairocffi is a CFFI-based drop-in replacement for Pycairo, a set of Python + bindings and object-oriented API for cairo. Cairo is a 2D vector graphics + library with support for multiple backends including image buffers, PNG, + PostScript, PDF, and SVG file output. + . + Additionally, the cairocffi.pixbuf module uses GDK-PixBuf to decode various + image formats for use in cairo. + . + This package provides the documentation for the cairocffi bindings. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7229646 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,40 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: cairocffi +Source: https://pypi.python.org/pypi/cairocffi + +Files: * +Copyright: 2013 Simon Sapin +License: BSD-3-Clause + +Files: debian/* +Copyright: 2013 Patrick "P. J." McDermott +License: BSD-3-Clause + +License: BSD-3-Clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + . + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..a1320b1 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +README.rst diff --git a/debian/patches/add-missing-utils.patch b/debian/patches/add-missing-utils.patch new file mode 100644 index 0000000..5772bd7 --- /dev/null +++ b/debian/patches/add-missing-utils.patch @@ -0,0 +1,209 @@ +From: "P. J. McDermott" +Origin: upstream, https://github.com/SimonSapin/cairocffi/tree/master/utils +Subject: Add missing utils/ directory + +--- a/utils/cairocffi_to_pycairo.py ++++ b/utils/cairocffi_to_pycairo.py +@@ -0,0 +1,32 @@ ++import ctypes ++import cairo # pycairo ++import cairocffi ++ ++pycairo = ctypes.PyDLL(cairo._cairo.__file__) ++pycairo.PycairoContext_FromContext.restype = ctypes.c_void_p ++pycairo.PycairoContext_FromContext.argtypes = 3 * [ctypes.c_void_p] ++ctypes.pythonapi.PyList_Append.argtypes = 2 * [ctypes.c_void_p] ++ ++ ++def _UNSAFE_cairocffi_context_to_pycairo(cairocffi_context): ++ # Sanity check. Continuing with another type would probably segfault. ++ if not isinstance(cairocffi_context, cairocffi.Context): ++ raise TypeError('Expected a cairocffi.Context, got %r' ++ % cairocffi_context) ++ ++ # Create a reference for PycairoContext_FromContext to take ownership of. ++ cairocffi.cairo.cairo_reference(cairocffi_context._pointer) ++ # Casting the pointer to uintptr_t (the integer type as wide as a pointer) ++ # gets the context’s integer address. ++ # On CPython id(cairo.Context) gives the address to the Context type, ++ # as expected by PycairoContext_FromContext. ++ address = pycairo.PycairoContext_FromContext( ++ int(cairocffi.ffi.cast('uintptr_t', cairocffi_context._pointer)), ++ id(cairo.Context), ++ None) ++ assert address ++ # This trick uses Python’s C API ++ # to get a reference to a Python object from its address. ++ temp_list = [] ++ assert ctypes.pythonapi.PyList_Append(id(temp_list), address) == 0 ++ return temp_list[0] +--- a/utils/cairo_coverage.py ++++ b/utils/cairo_coverage.py +@@ -0,0 +1,23 @@ ++import inspect ++import pycparser ++import cairocffi ++ ++ALL_THE_CODE = ''.join( ++ line ++ for module in [ ++ cairocffi, cairocffi.surfaces, cairocffi.patterns, ++ cairocffi.fonts, cairocffi.context, cairocffi.matrix] ++ for line in inspect.getsourcelines(module)[0]) ++ ++ ++class Visitor(pycparser.c_ast.NodeVisitor): ++ def visit_Decl(self, node): ++ for _, child in node.children(): ++ if isinstance(child, pycparser.c_ast.FuncDecl): ++ if ('cairo.' + node.name) not in ALL_THE_CODE and not ( ++ node.name.endswith('user_data')): ++ print(node.name) ++ break ++ ++print('cairo functions never used in cairocffi:\n') ++Visitor().visit(pycparser.CParser().parse(cairocffi.constants._CAIRO_HEADERS)) +--- a/utils/compare_pycairo.py ++++ b/utils/compare_pycairo.py +@@ -0,0 +1,24 @@ ++import cairo as pycairo ++import cairocffi ++ ++# We want the real pycairo ++assert pycairo is not cairocffi ++ ++ ++print('Missing pycairo API:\n') ++ ++for name in dir(pycairo): ++ pycairo_obj = getattr(pycairo, name) ++ cairocffi_obj = getattr(cairocffi, name, None) ++ if name.startswith(('_', 'version', 'CAPI')): ++ continue ++ if cairocffi_obj is None: ++ print(name) ++ elif isinstance(pycairo_obj, type): ++ for method_name in dir(pycairo_obj): ++ if method_name.startswith('__'): ++ continue ++ pycairo_method = getattr(pycairo_obj, method_name) ++ cairocffi_method = getattr(cairocffi_obj, method_name, None) ++ if cairocffi_method is None: ++ print('%s.%s' % (name, method_name)) +--- a/utils/pango_example.py ++++ b/utils/pango_example.py +@@ -0,0 +1,56 @@ ++# coding: utf8 ++import cairocffi ++import cffi ++ ++ ++ffi = cffi.FFI() ++ffi.include(cairocffi.ffi) ++ffi.cdef(''' ++ /* GLib */ ++ typedef void* gpointer; ++ void g_object_unref (gpointer object); ++ ++ /* Pango and PangoCairo */ ++ typedef ... PangoLayout; ++ typedef enum { ++ PANGO_ALIGN_LEFT, ++ PANGO_ALIGN_CENTER, ++ PANGO_ALIGN_RIGHT ++ } PangoAlignment; ++ int pango_units_from_double (double d); ++ PangoLayout * pango_cairo_create_layout (cairo_t *cr); ++ void pango_cairo_show_layout (cairo_t *cr, PangoLayout *layout); ++ void pango_layout_set_width (PangoLayout *layout, int width); ++ void pango_layout_set_alignment ( ++ PangoLayout *layout, PangoAlignment alignment); ++ void pango_layout_set_markup ( ++ PangoLayout *layout, const char *text, int length); ++''') ++gobject = ffi.dlopen('gobject-2.0') ++pango = ffi.dlopen('pango-1.0') ++pangocairo = ffi.dlopen('pangocairo-1.0') ++ ++gobject_ref = lambda pointer: ffi.gc(pointer, gobject.g_object_unref) ++units_from_double = pango.pango_units_from_double ++ ++ ++def write_example_pdf(target): ++ pt_per_mm = 72 / 25.4 ++ width, height = 210 * pt_per_mm, 297 * pt_per_mm # A4 portrait ++ surface = cairocffi.PDFSurface(target, width, height) ++ context = cairocffi.Context(surface) ++ context.translate(0, 300) ++ context.rotate(-0.2) ++ ++ layout = gobject_ref( ++ pangocairo.pango_cairo_create_layout(context._pointer)) ++ pango.pango_layout_set_width(layout, units_from_double(width)) ++ pango.pango_layout_set_alignment(layout, pango.PANGO_ALIGN_CENTER) ++ markup = u'Hi from Παν語!' ++ markup = ffi.new('char[]', markup.encode('utf8')) ++ pango.pango_layout_set_markup(layout, markup, -1) ++ pangocairo.pango_cairo_show_layout(context._pointer, layout) ++ ++ ++if __name__ == '__main__': ++ write_example_pdf(target='pango_example.pdf') +--- a/utils/pycairo_to_cairocffi.py ++++ b/utils/pycairo_to_cairocffi.py +@@ -0,0 +1,25 @@ ++import cairo # pycairo ++import cairocffi ++ ++ ++def _UNSAFE_pycairo_context_to_cairocffi(pycairo_context): ++ # Sanity check. Continuing with another type would probably segfault. ++ if not isinstance(pycairo_context, cairo.Context): ++ raise TypeError('Expected a cairo.Context, got %r' % pycairo_context) ++ ++ # On CPython, id() gives the memory address of a Python object. ++ # pycairo implements Context as a C struct: ++ # typedef struct { ++ # PyObject_HEAD ++ # cairo_t *ctx; ++ # PyObject *base; ++ # } PycairoContext; ++ # Still on CPython, object.__basicsize__ is the size of PyObject_HEAD, ++ # ie. the offset to the ctx field. ++ # ffi.cast() converts the integer address to a cairo_t** pointer. ++ # [0] dereferences that pointer, ie. read the ctx field. ++ # The result is a cairo_t* pointer that cairocffi can use. ++ return cairocffi.Context._from_pointer( ++ cairocffi.ffi.cast('cairo_t **', ++ id(pycairo_context) + object.__basicsize__)[0], ++ incref=True) +--- a/utils/tests.py ++++ b/utils/tests.py +@@ -0,0 +1,27 @@ ++import io ++import cairo # pycairo ++import cairocffi ++ ++from pycairo_to_cairocffi import _UNSAFE_pycairo_context_to_cairocffi ++from cairocffi_to_pycairo import _UNSAFE_cairocffi_context_to_pycairo ++import pango_example ++ ++ ++def test(): ++ cairocffi_context = cairocffi.Context(cairocffi.PDFSurface(None, 10, 20)) ++ cairocffi_context.scale(2, 3) ++ pycairo_context = _UNSAFE_cairocffi_context_to_pycairo(cairocffi_context) ++ cairocffi_context2 = _UNSAFE_pycairo_context_to_cairocffi(pycairo_context) ++ assert tuple(cairocffi_context.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert tuple(cairocffi_context2.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert tuple(pycairo_context.get_matrix()) == (2, 0, 0, 3, 0, 0) ++ assert cairocffi_context2._pointer == cairocffi_context._pointer ++ ++ file_obj = io.BytesIO() ++ # Mostly test that this runs without raising. ++ pango_example.write_example_pdf(file_obj) ++ assert file_obj.getvalue().startswith(b'%PDF') ++ ++ ++if __name__ == '__main__': ++ test() diff --git a/debian/patches/intersphinx_mapping.patch b/debian/patches/intersphinx_mapping.patch new file mode 100644 index 0000000..130dc8e --- /dev/null +++ b/debian/patches/intersphinx_mapping.patch @@ -0,0 +1,25 @@ +Author: "P. J. McDermott" +Forwarded: not-needed +Subject: Use non-None object inventory values in intersphinx_mapping + +--- a/docs/conf.py ++++ b/docs/conf.py +@@ -1,5 +1,6 @@ + import re + import os ++import sys + + extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', + 'sphinx.ext.coverage'] +@@ -15,5 +16,9 @@ + autodoc_member_order = 'bysource' + autodoc_default_flags = ['members'] + intersphinx_mapping = { +- 'http://docs.python.org/': None, +- 'http://cairographics.org/documentation/pycairo/2/': None} ++ 'http://docs.python.org/': ++ '/usr/share/doc/python' + ++ '.'.join([str(x) for x in sys.version_info[0:2]]) + ++ '/html/objects.inv', ++ 'http://cairographics.org/documentation/pycairo/2/': ++ '/usr/share/doc/python-cairo-dev/html/objects.inv'} diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..c21edd7 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,2 @@ +add-missing-utils.patch +intersphinx_mapping.patch diff --git a/debian/python-cairocffi.install b/debian/python-cairocffi.install new file mode 100644 index 0000000..0105c59 --- /dev/null +++ b/debian/python-cairocffi.install @@ -0,0 +1 @@ +usr/lib/python2.*/ diff --git a/debian/python3-cairocffi.install b/debian/python3-cairocffi.install new file mode 100644 index 0000000..eae3930 --- /dev/null +++ b/debian/python3-cairocffi.install @@ -0,0 +1 @@ +usr/lib/python3/ diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..cf33004 --- /dev/null +++ b/debian/rules @@ -0,0 +1,63 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +%: + dh $@ --with python2,python3,sphinxdoc + +override_dh_auto_build: + set -ex; for python in $$(py3versions -r); do \ + $$python setup.py build; \ + done + dh_auto_build + +override_dh_auto_install: + set -ex; for python in $$(py3versions -r); do \ + $$python setup.py install --root=$$(pwd)/debian/tmp \ + --install-layout=deb; \ + done + dh_auto_install + +override_dh_installdocs: + python setup.py build_sphinx + dh_installdocs + +override_dh_compress: + dh_compress -X.rst + +override_dh_auto_clean: + dh_auto_clean + rm -Rf build/ docs/_build/ *.egg-info/ + +get-orig-source: + uscan --noconf --verbose --rename --force-download \ + --download-current-version + +unpack-orig-source: get-orig-source + # Remove currently unpacked source. + for f in * .[!.] .??*; do \ + if [ -e $${f} ] && [ $${f} != debian ] && \ + [ $${f} != .gitignore ]; then \ + rm -Rf $${f}; \ + fi; \ + done + # Unpack source archive. + set -e; \ + source=$$(dpkg-parsechangelog | sed -n 's/^Source: //p'); \ + version=$$(dpkg-parsechangelog | \ + sed -n 's/^Version: \([^-]*\).*$$/\1/p'); \ + tar -xzf ../$${source}_$${version}.orig.tar.gz + # Find directory containing unpacked source files. Move source files + # into the top-level directory. + set -e; \ + for f in */ .[!.]/ .??*/; do \ + if [ -d $${f} ] && [ $${f} != debian ]; then \ + for ff in $${f}/* $${f}/.[!.] $${f}/.??*; do \ + if [ -e $${ff} ]; then \ + mv $${ff} .; \ + fi; \ + done; \ + rmdir $${f}/; \ + fi; \ + done diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..b183d6d --- /dev/null +++ b/debian/watch @@ -0,0 +1,3 @@ +version=3 + +https://pypi.python.org/packages/source/c/cairocffi/cairocffi-(.*)\.tar\.gz -- cgit v0.9.1