Giter Site home page Giter Site logo

pycairo's Introduction


Pycairo is a Python module providing bindings for the cairo graphics library. It depends on cairo >= 1.15.10 and works with Python 3.9+ and PyPy3. Pycairo, including this documentation, is licensed under the LGPL-2.1-only OR MPL-1.1.

The Pycairo bindings are designed to match the cairo C API as closely as possible, and to deviate only in cases which are clearly better implemented in a more ‘Pythonic’ way.

pip install pycairo

Installing Pycairo requires cairo including its headers. For more info see "Getting Started".


import cairo

with cairo.SVGSurface("example.svg", 200, 200) as surface:
    context = cairo.Context(surface)
    x, y, x1, y1 = 0.1, 0.5, 0.4, 0.9
    x2, y2, x3, y3 = 0.6, 0.1, 0.9, 0.5
    context.scale(200, 200)
    context.set_line_width(0.04)
    context.move_to(x, y)
    context.curve_to(x1, y1, x2, y2, x3, y3)
    context.stroke()
    context.set_source_rgba(1, 0.2, 0.2, 0.6)
    context.set_line_width(0.02)
    context.move_to(x, y)
    context.line_to(x1, y1)
    context.move_to(x2, y2)
    context.line_to(x3, y3)
    context.stroke()


Features of the Pycairo bindings:

  • Provides an object oriented interface to cairo.
  • Queries the error status of objects and translates them to exceptions.
  • Provides a C API that can be used by other Python extensions.
  • Fully typed and documented API.

For more information visit https://pycairo.readthedocs.io

pycairo's People

Contributors

aaronhendry avatar alexhenrie avatar andriyor avatar cjmayo avatar cvtsi2sd avatar danyeaw avatar einarf avatar fanc999-1 avatar heirecka avatar hintak avatar hroncok avatar infirit avatar isidroas avatar jd avatar kolibril13 avatar lazka avatar lovetox avatar mgorny avatar naveen521kk avatar nedbat avatar nikolas avatar rougier avatar sir-sigurd avatar sitic avatar stuaxo avatar tijssen avatar tp-m avatar tych0 avatar ulidtko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pycairo's Issues

fatal error: Python.h: File or folder not found

No idea why this happens. Help?

Collecting pycryptodome
  Downloading pycryptodome-3.4.8.tar.gz (6.7MB)
    100% |████████████████████████████████| 6.7MB 9.9kB/s
Collecting pycryptodomex
  Downloading pycryptodomex-3.4.8.tar.gz (6.7MB)
    100% |████████████████████████████████| 6.7MB 10kB/s
Collecting pygobject
  Using cached PyGObject-3.27.1.tar.gz
Collecting pycairo>=1.11.1 (from pygobject)
  Downloading pycairo-1.15.5.tar.gz (179kB)
    100% |████████████████████████████████| 184kB 336kB/s
Installing collected packages: pycryptodome, pycryptodomex, pycairo, pygobject
  Found existing installation: pycryptodome 3.4.7
    Uninstalling pycryptodome-3.4.7:
      Successfully uninstalled pycryptodome-3.4.7
  Running setup.py install for pycryptodome ... done
  Found existing installation: pycryptodomex 3.4.7
    Uninstalling pycryptodomex-3.4.7:
      Successfully uninstalled pycryptodomex-3.4.7
  Running setup.py install for pycryptodomex ... done
  Running setup.py install for pycairo ... error
    Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-nH00sA/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-lmO8vr-record/install-record.txt --single-version-externally-managed --compile:
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-armv6l-2.7
    creating build/lib.linux-armv6l-2.7/cairo
    copying cairo/__init__.py -> build/lib.linux-armv6l-2.7/cairo
    running build_ext
    building 'cairo._cairo' extension
    creating build/temp.linux-armv6l-2.7
    creating build/temp.linux-armv6l-2.7/cairo
    arm-linux-gnueabihf-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-kKRR4y/python2.7-2.7.13=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -DPYCAIRO_VERSION_MAJOR=1 -DPYCAIRO_VERSION_MINOR=15 -DPYCAIRO_VERSION_MICRO=5 -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/arm-linux-gnueabihf/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/python2.7 -c cairo/device.c -o build/temp.linux-armv6l-2.7/cairo/device.o -fno-strict-aliasing
    cairo/device.c:30:20: fatal error: Python.h: File or folder not found
     #include <Python.h>
                        ^
    compilation terminated.
    error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1

Work through fd.o bug list

There are 32 bugs open on fd.o: https://bugs.freedesktop.org/buglist.cgi?component=general&list_id=611898&product=pycairo&resolution=---

We should look through them and see which ones are still relevant and should be imported.

assertion error on invalid value for Surface.set_device_scale

Rather than an exception.

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
surface.set_device_scale(1, 0)
python: /build/buildd/cairo-1.13.0~20140204/src/cairo-surface.c:1700: cairo_surface_set_device_scale: Assertion `status == CAIRO_STATUS_SUCCESS' failed.

device crasher

This crashes, I guess the surface needs to explicitly keep the device alive:

f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10)
surface.get_device()

the docs are not clear..

UnicodeDecodeError while installing pycairo with pip on win10

Python 3.6
pip (9.0.1)
setuptools (38.5.1)

Exception:
Traceback (most recent call last):
  File "c:\program files\python36\lib\site-packages\pip\compat\__init__.py", line 73, in console_to_str
    return s.decode(sys.__stdout__.encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d in position 101: invalid start byte

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\program files\python36\lib\site-packages\pip\basecommand.py", line 215, in main
    status = self.run(options, args)
  File "c:\program files\python36\lib\site-packages\pip\commands\install.py", line 342, in run
    prefix=options.prefix_path,
  File "c:\program files\python36\lib\site-packages\pip\req\req_set.py", line 784, in install
    **kwargs
  File "c:\program files\python36\lib\site-packages\pip\req\req_install.py", line 878, in install
    spinner=spinner,
  File "c:\program files\python36\lib\site-packages\pip\utils\__init__.py", line 676, in call_subprocess
    line = console_to_str(proc.stdout.readline())
  File "c:\program files\python36\lib\site-packages\pip\compat\__init__.py", line 75, in console_to_str
    return s.decode('utf_8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d in position 101: invalid start byte

Don't throw MemoryError/IOError

Currently some cairo error codes are translated to to MemoryError and IOError. Imo this makes error handling hard, since we don't really know for which functions this is possible and where to document it.

The only nice thing about it is that one can differentiate the different error causes, but we do have a status attribute on the exception now, so that is no longer needed.

Proposal: raise some internal CairoMemoryError(cairo.Error, MemoryError) instead, so that catching cairo.Error works always while not breaking existing code

Trying to install cairo's bindings to python

I obtain this error that certain files are not found.

`justins-mbp:Downloads justinthong$ pip install pycairo-1.15.0.tar.gz
Processing ./pycairo-1.15.0.tar.gz
Complete output from command python setup.py egg_info:
'pkg-config' not found.
Command ['pkg-config', '--cflags-only-I', 'cairo']

----------------------------------------

Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/xb/n20n792n5zn0xpyhpdcn4chm0000gn/T/pip-QlD9gj-build/`

updating pygobject

When updating pygobject via pip in LinuxMint ("sudo pip install -U pygobject" or "sudo -H pip install -U pygobject"), I get this error:

Collecting pygobject
  Using cached pygobject-3.27.0.tar.gz
Requirement already up-to-date: pycairo>=1.11.1 in /usr/local/lib/python2.7/dist-packages (from pygobject)
Installing collected packages: pygobject
  Found existing installation: pygobject 3.20.0
    DEPRECATION: Uninstalling a distutils installed project (pygobject) has been deprecated and will be removed in a future version. This is due to the fact that uninstalling a distutils project will only partially uninstall the project.
    Uninstalling pygobject-3.20.0:
      Successfully uninstalled pygobject-3.20.0
  Running setup.py install for pygobject ... error
...
gi/pygi-foreign-cairo.c:28:21: fatal error: pycairo.h: Arquivo ou diretório não encontrado
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

How can I solve this?
"pip list" show pycairo (1.15.4) and pygobject (3.20.0)

IOError when installing on Python 2.7 environment

When I try to install matplotlib into my Python 2.7 environment, pycairo gives me the following error:

$ conda install matplotlib
Fetching package metadata .........
Solving package specifications: .

Package plan for installation in environment /home/takaya/.conda/envs/createbin:

The following NEW packages will be INSTALLED:

    cairo:        1.14.8-0         
    cycler:       0.10.0-py27_0    
    matplotlib:   2.0.2-np113py27_0
    pixman:       0.34.0-0         
    pycairo:      1.10.0-py27_0    
    pyparsing:    2.2.0-py27_0     
    subprocess32: 3.2.7-py27_0     

Proceed ([y]/n)? y

ERROR conda.core.link:_execute_actions(337): An error occurred while installing package 'defaults::pycairo-1.10.0-py27_0'.
IOError(13, 'Permission denied')
Attempting to roll back.


IOError(13, 'Permission denied')

The packages installed in the enviroment are:

# packages in environment at /home/takaya/.conda/envs/createbin:
#
backports                 1.0                      py27_0  
backports_abc             0.5                      py27_0  
bkcharts                  0.2                      py27_0  
bleach                    1.5.0                    py27_0  
bokeh                     0.12.7                   py27_0  
certifi                   2016.2.28                py27_0  
cloudpickle               0.4.0                    py27_0  
configparser              3.5.0                    py27_0  
dask                      0.15.2                   py27_0  
dbus                      1.10.20                       0  
decorator                 4.1.2                    py27_0  
entrypoints               0.2.3                    py27_0  
enum34                    1.1.6                    py27_0  
expat                     2.1.0                         0  
fontconfig                2.12.1                        3  
freetype                  2.5.5                         2  
functools32               3.2.3.2                  py27_0  
futures                   3.1.1                    py27_0  
get_terminal_size         1.0.0                    py27_0  
glib                      2.50.2                        1  
gst-plugins-base          1.8.0                         0  
gstreamer                 1.8.0                         0  
html5lib                  0.9999999                py27_0  
icu                       54.1                          0  
ipykernel                 4.6.1                    py27_0  
ipython                   5.3.0                    py27_0  
ipython_genutils          0.2.0                    py27_0  
ipywidgets                6.0.0                    py27_0  
jinja2                    2.9.6                    py27_0  
jpeg                      9b                            0  
jsonschema                2.6.0                    py27_0  
jupyter                   1.0.0                    py27_3  
jupyter_client            5.1.0                    py27_0  
jupyter_console           5.2.0                    py27_0  
jupyter_core              4.3.0                    py27_0  
libffi                    3.2.1                         1  
libgcc                    5.2.0                         0  
libgfortran               3.0.0                         1  
libiconv                  1.14                          0  
libpng                    1.6.30                        1  
libsodium                 1.0.10                        0  
libxcb                    1.12                          1  
libxml2                   2.9.4                         0  
locket                    0.2.0                    py27_1  
markupsafe                1.0                      py27_0  
mistune                   0.7.4                    py27_0  
mkl                       2017.0.3                      0  
nbconvert                 5.2.1                    py27_0  
nbformat                  4.4.0                    py27_0  
notebook                  5.0.0                    py27_0  
numpy                     1.13.1                   py27_0  
openssl                   1.0.2l                        0  
pandas                    0.20.3                   py27_0  
pandocfilters             1.4.2                    py27_0  
partd                     0.3.8                    py27_0  
path.py                   10.3.1                   py27_0  
pathlib2                  2.3.0                    py27_0  
pcre                      8.39                          1  
pexpect                   4.2.1                    py27_0  
pickleshare               0.7.4                    py27_0  
pip                       9.0.1                    py27_1  
prompt_toolkit            1.0.15                   py27_0  
ptyprocess                0.5.2                    py27_0  
pygments                  2.2.0                    py27_0  
pyqt                      5.6.0                    py27_2  
python                    2.7.13                        0  
python-dateutil           2.6.1                    py27_0  
pytz                      2017.2                   py27_0  
pyyaml                    3.12                     py27_0  
pyzmq                     16.0.2                   py27_0  
qt                        5.6.2                         5  
qtconsole                 4.3.1                    py27_0  
readline                  6.2                           2  
requests                  2.14.2                   py27_0  
scandir                   1.5                      py27_0  
scipy                     0.19.1              np113py27_0  
setuptools                36.4.0                   py27_1  
simplegeneric             0.8.1                    py27_1  
singledispatch            3.4.0.3                  py27_0  
sip                       4.18                     py27_0  
six                       1.10.0                   py27_0  
sqlite                    3.13.0                        0  
ssl_match_hostname        3.5.0.1                  py27_0  
terminado                 0.6                      py27_0  
testpath                  0.3.1                    py27_0  
tk                        8.5.18                        0  
toolz                     0.8.2                    py27_0  
tornado                   4.5.2                    py27_0  
traitlets                 4.3.2                    py27_0  
wcwidth                   0.1.7                    py27_0  
wheel                     0.29.0                   py27_0  
widgetsnbextension        3.0.2                    py27_0  
xarray                    0.9.6                    py27_0  
yaml                      0.1.6                         0  
zeromq                    4.1.5                         0  
zlib                      1.2.11                        0 

Could you tell me how to resolve this issue?

Add cairo.TextExtents

  • cairo_scaled_font_glyph_extents
  • cairo_scaled_font_text_extents
  • cairo_glyph_extents
  • cairo_text_extents

Document the C API

Lots of things are missing, regarding memory management, error handling etc.

py3cairo.h not included with latest version of pycairo

I am attempting to compile pygobject release 3.26.0. It is breaking because it can't find the include files for py3cairo... even though I have installed the latest pycairo. If I revert back to the latest version of pycairo that includes py3cairo.h, this is pycairo version 1.10.1. Pygobject will not compile with pycairo 1.10.1, as it requires pycairo >= 1.11.

Add RasterSourcePattern

We can track the lifetime of the callbacks set there through set_user_data.
We can ignore the callback data imo. It's not per callback which rules out passing *args through and python closures should work fine.

PyPy support

I tried to install pygobject via pip3 inside a pypy3 venv and this is what happened:

(env) alex@smartalex-pc:~/.repos/codelib/.personal/pythonide/pythonide$ pip3 install pygobject
Collecting pygobject
  Using cached PyGObject-3.27.1.tar.gz
Collecting pycairo>=1.11.1 (from pygobject)
  Using cached pycairo-1.15.4.tar.gz
Installing collected packages: pycairo, pygobject
  Running setup.py install for pycairo ... error
    Complete output from command /home/alex/.repos/codelib/.personal/pythonide/env/bin/pypy3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-s4v7b2ex/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-1811lh13-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/alex/.repos/codelib/.personal/pythonide/env/include/site/python3.5/pycairo:
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-x86_64-3.5
    creating build/lib.linux-x86_64-3.5/cairo
    copying cairo/__init__.py -> build/lib.linux-x86_64-3.5/cairo
    running build_ext
    building 'cairo._cairo' extension
    creating build/temp.linux-x86_64-3.5
    creating build/temp.linux-x86_64-3.5/cairo
    cc -pthread -DNDEBUG -O2 -fPIC -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/home/alex/.repos/codelib/.personal/pythonide/env/include -I/usr/lib/pypy3/pypy3-v5.10.1-linux64/include -c cairo/device.c -o build/temp.linux-x86_64-3.5/cairo/device.o
    cc -pthread -DNDEBUG -O2 -fPIC -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/home/alex/.repos/codelib/.personal/pythonide/env/include -I/usr/lib/pypy3/pypy3-v5.10.1-linux64/include -c cairo/bufferproxy.c -o build/temp.linux-x86_64-3.5/cairo/bufferproxy.o
    cc -pthread -DNDEBUG -O2 -fPIC -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/home/alex/.repos/codelib/.personal/pythonide/env/include -I/usr/lib/pypy3/pypy3-v5.10.1-linux64/include -c cairo/error.c -o build/temp.linux-x86_64-3.5/cairo/error.o
    In file included from /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/Python.h:86:0,
                     from cairo/error.c:32:
    cairo/error.c: In function ‘error_init’:
    cairo/error.c:111:35: error: ‘PyBaseExceptionObject {aka struct <anonymous>}’ has no member named ‘args’
         if(PyTuple_GET_SIZE(self->base.args) >= 2) {
                                       ^
    /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/object.h:88:39: note: in definition of macro ‘Py_SIZE’
     #define Py_SIZE(ob)  (((PyVarObject*)(ob))->ob_size)
                                           ^~
    cairo/error.c:111:8: note: in expansion of macro ‘PyTuple_GET_SIZE’
         if(PyTuple_GET_SIZE(self->base.args) >= 2) {
            ^~~~~~~~~~~~~~~~
    In file included from /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/Python.h:115:0,
                     from cairo/error.c:32:
    cairo/error.c:112:49: error: ‘PyBaseExceptionObject {aka struct <anonymous>}’ has no member named ‘args’
             status_obj = PyTuple_GET_ITEM(self->base.args, 1);
                                                     ^
    /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/tupleobject.h:23:53: note: in definition of macro ‘PyTuple_GET_ITEM’
     #define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i])
                                                         ^~
    In file included from /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/Python.h:86:0,
                     from cairo/error.c:32:
    cairo/error.c: In function ‘error_str’:
    cairo/error.c:152:36: error: ‘PyBaseExceptionObject {aka struct <anonymous>}’ has no member named ‘args’
         if (PyTuple_GET_SIZE(self->base.args) >= 1) {
                                        ^
    /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/object.h:88:39: note: in definition of macro ‘Py_SIZE’
     #define Py_SIZE(ob)  (((PyVarObject*)(ob))->ob_size)
                                           ^~
    cairo/error.c:152:9: note: in expansion of macro ‘PyTuple_GET_SIZE’
         if (PyTuple_GET_SIZE(self->base.args) >= 1) {
             ^~~~~~~~~~~~~~~~
    In file included from /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/Python.h:115:0,
                     from cairo/error.c:32:
    cairo/error.c:153:56: error: ‘PyBaseExceptionObject {aka struct <anonymous>}’ has no member named ‘args’
             return PyObject_Str(PyTuple_GET_ITEM(self->base.args, 0));
                                                            ^
    /usr/lib/pypy3/pypy3-v5.10.1-linux64/include/tupleobject.h:23:53: note: in definition of macro ‘PyTuple_GET_ITEM’
     #define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i])
                                                         ^~
    error: command 'cc' failed with exit status 1
    
    ----------------------------------------
Command "/home/alex/.repos/codelib/.personal/pythonide/env/bin/pypy3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-s4v7b2ex/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-1811lh13-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/alex/.repos/codelib/.personal/pythonide/env/include/site/python3.5/pycairo" failed with error code 1 in /tmp/pip-build-s4v7b2ex/pycairo/

...so I talked to PyPy developers and asked them whether it is possible to make GTK and PyPy work together. Their answer, in a nutshell, was that this is an unofficial Python C APi usage, and that this should be a 5 minute fix. PyPy developers agreed that I include the relevant parts of original conversation in the issue:

[...]
<arigato> there's basically only one error.  it could be fixed by editing cairo to not dig inside PyBaseExceptionObject like this
<arigato> or we could support it, with a bit more effort, inside pypy
<arigato> the proper fix to cairo would be to call PyObject_GetAttributeString(self, "args") instead of self->base.args
<arigato> PyObject_GetAttrString(self, "args")
<xqb> well it's nice to hear it could be (easily?) done
<xqb> this might sound selfish but might we expect this to happen in the near future?
<xqb> a month, two?
<fijal> xqb: on its own - a bit unlikely
<fijal> someone has to either be interested in fixing pycairo etc or pay someone else to do it
<xqb> yeah I see
<xqb> that's a pity I wanted to use PyPy badly :)
<arigato> it's really a 5-minutes change, but then it needs to be tested again and maybe we'll see more issues
<arigato> from our point of view, we're more likely to fix pypy
<xqb> well I'd be happy to do it myself it's just I'm far from competent to do so 
<xqb> :)
<arigato> but you can try to tell the pycairo developers what I just said and they may try
<xqb> okay, will do
[...]
<fijal> well there is a chance it's not the only one
<fijal> but it's also likely that a lot of them are like this (maybe all)
[...]
<fijal> xqb: feel free to use our names if it's helpful - the general problem is "this is not an official use of CPython C API and as such does not work on pypy - here is how to use it in a more official way"

Thanks in advance if anything can be done.

Question about the C API

I had an issue with a while back CairoCFFI, which seemed to come back to how pycairo exports things from it's .so.

PycairoContext_FromContext seems to be exported on some (but not all) distros and windows.

I noticed that PyCairo changed to the capsule API from something else previously, could this have changed how the C API is exported in it's .so ?

(And so the distros where I could access PycairoContext_FromContext be using the other mechanism) ?

No package 'cairo' found

How to fix this please?

Linux-4.9.29-13-osmc-armv7l-with-debian-9.3
Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2

Collecting pygobject
  Using cached PyGObject-3.27.1.tar.gz
Collecting pycairo>=1.11.1 (from pygobject)
  Using cached pycairo-1.15.4.tar.gz
Installing collected packages: pycairo, pygobject
  Running setup.py install for pycairo ... error
    Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-aNZaJA/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-nItI09-record/install-record.txt --single-version-externally-managed --compile:
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-armv7l-2.7
    creating build/lib.linux-armv7l-2.7/cairo
    copying cairo/__init__.py -> build/lib.linux-armv7l-2.7/cairo
    running build_ext
    Package cairo was not found in the pkg-config search path.
    Perhaps you should add the directory containing `cairo.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'cairo' found
    Command '['pkg-config', '--print-errors', '--exists', 'cairo >= 1.13.1']' returned non-zero exit status 1

    ----------------------------------------
Command "/usr/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-aNZaJA/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-nItI09-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-aNZaJA/pycairo/

Find the correct libdir in setup.py

OS: Slackware64-current

The 64 bit version of Slackware installs libraries to /usr/lib64 while the 32 bit version uses /usr/lib. The problem is that in setup.py the library directory is hardcoded to lib and this results in the pkgconfig file being installed to the wrong directory in Slackware64.

libdir = os.path.join(self.install_data, "lib")

While other library files will be correctly installed to /usr/lib64/python3.6/site-packages/ since python itself was configured to use that lib64. Can this be made so that it will use the same directory as the other library files as configured in python?

This commit for the six-library shows an example of how this is done, but I do not know python at all so I am having difficulty in implementing it. Any help would be appreciated, thanks!
ngageoint/six-library@98f6397

Surface.map_to_image

https://cairographics.org/manual/cairo-cairo-surface-t.html#cairo-surface-map-to-image

Not sure about the API here with all the restrictions. Either just provide as is, or handle the unmap ourself and let the user specify a callback in which the image surface can be edited. That would make it harder to modify the source surface by accident and tie the lifetime to the callback:

def map_function(image_surface):
    ...

surface.map_to_image(extends, map_function)

There are still ways to make it crash.

repeated ScriptDevice output from RecordingSurface

I'm not sure if there's a bug here, and if it's in pycairo.

Take this code which produces the same image at two different device scales, and works as expected.

# A
for scale in (1, 2):
    device = cairo.ScriptDevice('A.%ix.txt' % scale)
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100 * scale, 100 * scale)
    script_surface = cairo.ScriptSurface.create_for_target(device, surface)
    script_surface.set_device_scale(scale, scale)
    ctx = cairo.Context(script_surface)
    ctx.set_source_rgb(0.1, 0.2, 0.3)
    ctx.arc(50, 50, 25, 0, 360 * math.pi / 180)
    ctx.fill()
    script_surface.write_to_png('A.%ix.png' % scale)

Now for complex operations, it's more efficient to record and replay the surface. Strangely, this produces marginally different files at scale > 1. I added ScriptSurface precisely to debug this, but it doesn't quite work as expected here.

# B
recording_surface = cairo.RecordingSurface(cairo.Content.COLOR_ALPHA, 
    (0, 0, 100, 100))
ctx = cairo.Context(recording_surface)
ctx.set_source_rgb(0.1, 0.2, 0.3)
ctx.arc(50, 50, 25, 0, 360 * math.pi / 180)
ctx.fill()

for scale in (1, 2):
    device = cairo.ScriptDevice('B.%ix.txt' % scale)
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100 * scale, 100 * scale)
    script_surface = cairo.ScriptSurface.create_for_target(device, surface)
    script_surface.set_device_scale(scale, scale)
    ctx = cairo.Context(script_surface)
    ctx.set_source_surface(recording_surface, 0, 0)
    ctx.paint()
    script_surface.write_to_png('B.%ix.png' % scale)

And the recorded scripts.

(A.1x.txt)

%!CairoScript
<< /content //COLOR_ALPHA /width 100 /height 100 >> surface context
0.1 0.2 0.3 rgb set-source
n 75 50 m 75 63.808594 63.808594 75 50 75 c 36.191406 75 25 63.808594 25 50 c 25 36.191406 36.191406 25 50 25 c 63.808594 25 75 36.191406 75 50 c
fill+
pop
(A.2x.txt)

%!CairoScript
<< /content //COLOR_ALPHA /width 200 /height 200 >> surface context
0.1 0.2 0.3 rgb set-source
n 150 100 m 150 127.613281 127.613281 150 100 150 c 72.386719 150 50 127.613281 50 100 c 50 72.386719 72.386719 50 100 50 c 127.613281 50 150 72.386719 150 100 c
fill+
pop
(B.1x.txt)

%!CairoScript
<< /content //COLOR_ALPHA /width 100 /height 100 >> surface context
//COLOR_ALPHA [0 0 100 100] record
dup /s9 exch def dup context
0.1 0.2 0.3 rgb set-source
n 75 50 m 75 63.808594 63.808594 75 50 75 c 36.191406 75 25 63.808594 25 50 c 25 36.191406 36.191406 25 50 25 c 63.808594 25 75 36.191406 75 50 c
fill+
pop pattern
  set-source
paint
pop
/s9 undef
(B.2x.txt)

%!CairoScript
<< /content //COLOR_ALPHA /width 200 /height 200 >> surface context
s9pattern
  [0.5 0 0 0.5 0 0] set-matrix
  set-source
paint
pop

I haven't tried to replay any, but B.2x.txt does obviously not have enough information to be successfully replayed, nor does it help in debugging. I expected numbers to compare.

Robust access to py3cairo.h

Now that installs from wheels don't include pkg-config data anymore, but still include the py3cairo header, it would be useful to still have a way to include that header in a robust fashion (when py3cairo is installed from a wheel). (Obviously we still need to include pkg-config --cflags cairo but that's not a problem.)

A few options include

  • add a cairo.get_include() function, similarly to how numpy.get_include() does it.
  • make sure that pycairo/py3cairo.h is always available from the default include path set by distutils when building an extension (even when in a venv), and document it as the new way to include the header (this is currently the case afaict, just not documented as such).

Memory leak in ImageSurface.get_data

When creating an ImageSurface in a loop and calling get_data() on it, memory leaks.
It's about 5KB in resident memory, shown by the mem function, and about 1MB of virtual memory, observable in htop, which is about the size of the surface.

Calling get_data in the loop on the same SurfaceImage does not allocate more memory.

#!/usr/bin/env python3

import cairo
import resource

def mem():
    print("Memory usage: {:.0f}M".format(
        resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024))

mem()

for i in range(10000):
    s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 500, 500)
    s.get_data()

mem()
#input()

I'm using Python 3.6.1 and the latest commit from master as well as 1.13.2+5+gcd6b840-1 (from the ArchLinux repos).

Add types for constants

Some thoughts:

  • cairo.OPERATOR_CLEAR should be an alias for cairo.Operator.CLEAR which should be a cairo.Operator
  • cairo.Operator should be an int subclass
  • it should pickle to int for compat
  • it should have a nice repr
  • I don't think there is a need to expose these in the C API

utf8 decode error running snippets in python2

On Ubuntu 16.10 64 bit, in a venv

Seems like these files may ended up encoded in latin1, not utf8..

python snippets_svg.py 
Traceback (most recent call last):
  File "snippets_svg.py", line 48, in <module>
    snippets = get_snippets()
  File "/mnt/data/home/stu/projects/external/pycairo-projects/pycairo/pygobject-pycairo/examples/cairo_snippets/snippets/__init__.py", line 34, in get_snippets
    s.code = h.read().decode("utf-8")
  File "/mnt/data/home/stu/.virtualenvs/tmp-3a44fab5a6b060ee/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xf3 in position 1: invalid continuation byte

test_image_surface_get_data fails on ppc64 and s390x

I'm building pycairo 1.15.2 for Fedora and running into the following error when running tests on ppc64 and s390x. The tests pass on other arches.

=================================== FAILURES ===================================
_________________________ test_image_surface_get_data __________________________
    def test_image_surface_get_data():
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 3, 3)
        ctx = cairo.Context(surface)
        ctx.paint()
        surface.flush()
        buf = surface.get_data()
        assert buf
        assert len(buf) == 4 * 3 * 3
        assert len(bytes(buf)) == len(buf)
        buf[0:1] = b"\x42"
    
        newbuf = surface.get_data()
        assert newbuf[0:1] == b"\x42"
        ctx.paint()
        surface.flush()
>       assert newbuf[0:1] == b"\x00"
E       AssertionError: assert '\xff' == '\x00'
E         - \xff
E         + \x00
tests/test_api.py:140: AssertionError
=============== 1 failed, 245 passed, 3 skipped in 1.99 seconds ================

debian issues

Debian pybuild has some problems with the new installation layout because it moves the files after installation, proposed fix:

  • Install the header to /usr/include again
  • The header in the package_data uses a relative include to /usr/include
  • The .pc file again refers to /usr/include

This gets rid of relative paths containing "/dist-packages/python3.6/"... and the .pc file and header file are not containing python version information, so no conflicts with multiple py3 versions.

Merge parts of CairoCFFI into PyCairo

This is a bit speculative... and I'm not going to have time to do anything for a while, but thought I'd write this here in the meantime -

CFFI vs CPython bindings background

CFFI has an advantage, in that code runs in pypy more permanently, and had better chance of working on alternate implementations.

CPython bindings such as pycairo have other advantages, like the C-API.

History of PyCairo vs CairoCFFI

PyCairo was not supported for a long time, and also could not work on Pypy because it is based on Pythons CAPI.

CairoCFFI was built on the CFFI bindings, to run (performantly) on Pypy.

In the meantime PyCairo was unsupported for so long that CairoCFFI started to support newer Cairo features such as Recording Surfaces.

However some features were hard to get into CairoCFFI without support from PyCairo, around Gtk integration

At that point there were two choices for a developer -

  • Use PyCairo, and only have support for Cairo features up to 1.10, have good integration with Gtk, but not Pypy support.
  • Use CairoCFFI and enjoy Pypy support, but have trouble later on when it comes to Gtk and (it will be different to PyCairo at the very least).

Current status

@lazka has triaged patches and released an up to date PyCairo, the project is healthy... lots of historical things sorted, like installation.

PyCairo is probably ahead of CairoCFFI when it comes to features, but still - CairoCFFI works better under Pypy.

What are analogous projects doing ?

  • Pypy
    originally was going to reimplement Numpy, with Numpypy. Now, Pypy has changed strategy and are going to try and implement enough on the low level for numpy to just work.

  • Servo
    Is a proof of concept web browser written in Rust. Instead of replacing the Firefox with servo, they are taking parts Servo and integating them into firefox.

Looking ahead

Having two projects it's inevitable that one will fall ahead while the other lags.
Further into the future it might be an idea to follow the lead of firefox and servo and try and integrate bits of CairoCFFI into PyCairo.

There are things that can't be done in CFFI, like the Cairo CAPI - but these could just not be supported - the possibly the bindings part of PyCairo could be done in CFFI, like it is in CairoCFFI (I believe the code should be license compatible).

Apologies if any of this is incorrect, some of it I'm recalling from mailing list conversations quite a while ago.

Not expecting anything to happens on this, and not going to have any time for quite a while, but it would be good to get some feedback.

Add cairo.Glyph

Used here:

  • cairo_show_glyphs
  • cairo_show_text_glyphs
  • cairo_glyph_path
  • cairo_glyph_extents
  • cairo_scaled_font_glyph_extents

Probably best to make it a tuple subclass for backwards compat.

(index: int, x: float, y: float)

Add cairo.Rectangle

  • cairo_recording_surface_create
  • cairo_recording_surface_ink_extents
  • cairo_recording_surface_get_extents
  • cairo_copy_clip_rectangle_list

Probably best to make it a tuple subclass for backwards compat

(x: float, y: float, width: float, height: float)

incorrect pkg-config file written for user-installed build

$ python setup.py install -O2 --user

This makes file $HOME/.local/lib/pkgconfig/pycairo.pc with the following content.

prefix=None

Name: Pycairo
Description: Python 2 bindings for cairo
Version: 1.13.0
Requires: cairo
Cflags: -I${prefix}/include/pycairo
Libs:

Which does not work for obvious reasons.

base object life time tied to wrapper instead of cairo object

This crashes.

def test_surface_destroy_before_context():
    surface = cairo.PDFSurface(io.BytesIO(), 1, 1)
    ctx = cairo.Context(surface)
    del surface
    ctx.paint()

the file object gets destroyed when the surface wrapper dies. The wrapped surface is still alive through the ref taken by the context. Calling paint invokes the write callback which crashes with the dead file object.

Solutions:

  • Keep a ref on the wrapper when creating a context
  • Stop using the base object thing and use set_user_data to keep things alive.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.