From 9576b3d77034d91f456a5b199a9fc9cc2fde3c08 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 12 Jul 2012 20:16:06 +0800 Subject: setup.py: add extra error messages. SVGSurface: Change from bytes-mode to text-mode, so SVG files can be written to sys.stdout. Fixes bug #50989. --- doc/reference/surfaces.rst | 25 +++++++++++---------- setup.py | 5 +++++ src/surface.c | 46 ++++++++++++++++++++++++++++----------- test/surface_create_for_stream.py | 28 ++++++++++++++---------- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/doc/reference/surfaces.rst b/doc/reference/surfaces.rst index 0ba51c9..949b05e 100644 --- a/doc/reference/surfaces.rst +++ b/doc/reference/surfaces.rst @@ -227,7 +227,7 @@ class Surface() .. method:: write_to_png(fobj) :param fobj: the file to write to - :type fobj: str, file or file-like object + :type fobj: filename (str), file or a file-like bytes-mode object :raises: *MemoryError* if memory could not be allocated for the operation *IOError* if an I/O error occurs while attempting to write the file @@ -341,7 +341,7 @@ multi-page vector surface backend. .. class:: PDFSurface(fobj, width_in_points, height_in_points) :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PDFSurface* that may be queried and used as a source, without generating a temporary file. - :type fobj: None, str, file or file-like object + :type fobj: None, filename (str), file or a file-like bytes-mode object :param width_in_points: width of the surface, in points (1 point == 1/72.0 inch) :type width_in_points: float @@ -383,7 +383,7 @@ is a multi-page vector surface backend. .. class:: PSSurface(fobj, width_in_points, height_in_points) :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PSSurface* that may be queried and used as a source, without generating a temporary file. - :type fobj: None, str, file or file-like object + :type fobj: None, filename (str), file or a file-like bytes-mode object :param width_in_points: width of the surface, in points (1 point == 1/72.0 inch) :type width_in_points: float @@ -646,8 +646,10 @@ multi-page vector surface backend .. class:: SVGSurface(fobj, width_in_points, height_in_points) - :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *SVGSurface* that may be queried and used as a source, without generating a temporary file. - :type fobj: None, str, file or file-like object + :param fobj: a filename or writable file object. None may be used to + specify no output. This will generate a *SVGSurface* that may be queried + and used as a source, without generating a temporary file. + :type fobj: None, filename (str), file or a file-like text-mode object :param width_in_points: width of the surface, in points (1 point == 1/72.0 inch) :type width_in_points: float :param height_in_points: height of the surface, in points (1 point == 1/72.0 inch) @@ -735,13 +737,14 @@ extension if it is available. :param width: The width of the surface :param height: The height of the surface - Informs cairo of the new size of the X Drawable underlying the surface. For a surface created - for a Window (rather than a Pixmap), this function must be called each time the size of the - window changes. (For a subwindow, you are normally resizing the window yourself, but for a - toplevel window, it is necessary to listen for ConfigureNotify events.) + Informs cairo of the new size of the X Drawable underlying the surface. For + a surface created for a Window (rather than a Pixmap), this function must + be called each time the size of the window changes. (For a subwindow, you + are normally resizing the window yourself, but for a toplevel window, it is + necessary to listen for ConfigureNotify events.) - A Pixmap can never change size, so it is never necessary to call this function on a surface - created for a Pixmap. + A Pixmap can never change size, so it is never necessary to call this + function on a surface created for a Pixmap. class XlibSurface(:class:`Surface`) diff --git a/setup.py b/setup.py index 808e34a..a93a650 100755 --- a/setup.py +++ b/setup.py @@ -33,7 +33,12 @@ def pkg_config_version_check(pkg, version): raise SystemExit(pipe.stderr.read().decode()) def pkg_config_parse(opt, pkg): + check = "pkg-config %s %s" % (opt, pkg) pipe = call("pkg-config %s %s" % (opt, pkg)) + if pipe.returncode != 0: + print(check, ' Failed') + raise SystemExit(pipe.stderr.read().decode()) + output = pipe.stdout.read() output = output.decode() # get the str opt = opt[-2:] diff --git a/src/surface.c b/src/surface.c index d98c498..4701a4b 100644 --- a/src/surface.c +++ b/src/surface.c @@ -121,10 +121,10 @@ PycairoSurface_FromSurface (cairo_surface_t *surface, PyObject *base) { /* for use with * cairo_surface_write_to_png_stream() - * cairo_pdf/ps/svg_surface_create_for_stream() + * cairo_pdf/ps_surface_create_for_stream() */ static cairo_status_t -_write_func (void *closure, const unsigned char *data, unsigned int length) { +_write_bytes_func (void *closure, const unsigned char *data, unsigned int length) { PyGILState_STATE gstate = PyGILState_Ensure(); PyObject *res = PyObject_CallMethod ((PyObject *)closure, "write", "(y#)", data, (Py_ssize_t)length); @@ -140,6 +140,26 @@ _write_func (void *closure, const unsigned char *data, unsigned int length) { return CAIRO_STATUS_SUCCESS; } +/* for use with + * cairo_svg_surface_create_for_stream() + */ +static cairo_status_t +_write_str_func (void *closure, const unsigned char *data, unsigned int length) { + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject *res = PyObject_CallMethod ((PyObject *)closure, "write", "(s#)", + data, (Py_ssize_t)length); + if (res == NULL) { + /* an exception has occurred, it will be picked up later by + * Pycairo_Check_Status() + */ + PyGILState_Release(gstate); + return CAIRO_STATUS_WRITE_ERROR; + } + Py_DECREF(res); + PyGILState_Release(gstate); + return CAIRO_STATUS_SUCCESS; +} + static void surface_dealloc (PycairoSurface *o) { if (o->surface) { @@ -307,12 +327,12 @@ surface_write_to_png (PycairoSurface *o, PyObject *args) { Py_XDECREF(writer); PyErr_SetString(PyExc_TypeError, "Surface.write_to_png takes one argument which must be a filename (str), file " -"object, or a file-like object which has a \"write\" method (like StringIO)"); +"object, or a file-like bytes-mode object which has a \"write\" method"); return NULL; } Py_DECREF(writer); Py_BEGIN_ALLOW_THREADS; - status = cairo_surface_write_to_png_stream (o->surface, _write_func, + status = cairo_surface_write_to_png_stream (o->surface, _write_bytes_func, file); Py_END_ALLOW_THREADS; } @@ -462,7 +482,7 @@ image_surface_create_for_data (PyTypeObject *type, PyObject *args) { #ifdef CAIRO_HAS_PNG_FUNCTIONS static cairo_status_t -_read_func (void *closure, unsigned char *data, unsigned int length) { +_read_bytes_func (void *closure, unsigned char *data, unsigned int length) { char *buffer; Py_ssize_t str_length; cairo_status_t status = CAIRO_STATUS_READ_ERROR; @@ -518,13 +538,13 @@ image_surface_create_from_png (PyTypeObject *type, PyObject *args) { Py_XDECREF(reader); PyErr_SetString(PyExc_TypeError, "ImageSurface.create_from_png argument must be a filename (str), file object, " -"or an object that has a \"read\" method (like StringIO)"); +"or a file-like bytes-mode object which has a \"read\" method"); return NULL; } Py_DECREF(reader); Py_BEGIN_ALLOW_THREADS; - is = cairo_image_surface_create_from_png_stream (_read_func, file); + is = cairo_image_surface_create_from_png_stream (_read_bytes_func, file); Py_END_ALLOW_THREADS; return PycairoSurface_FromSurface (is, NULL); } @@ -708,14 +728,14 @@ pdf_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { " None, or\n" " a filename (str), or\n" " a file object, or\n" -" an object that has a \"write\" method (like StringIO)." +" a file-like bytes-mode object which has a \"write\" method." ); return NULL; } Py_DECREF(writer); Py_BEGIN_ALLOW_THREADS; - sfc = cairo_pdf_surface_create_for_stream (_write_func, obj, + sfc = cairo_pdf_surface_create_for_stream (_write_bytes_func, obj, width_in_points, height_in_points); Py_END_ALLOW_THREADS; return PycairoSurface_FromSurface (sfc, obj); @@ -829,14 +849,14 @@ ps_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { " None, or\n" " a filename (str), or\n" " a file object, or\n" -" an object that has a \"write\" method (like StringIO)." +" a file-like bytes-mode object which has a \"write\" method." ); return NULL; } Py_DECREF(writer); Py_BEGIN_ALLOW_THREADS; - sfc = cairo_ps_surface_create_for_stream (_write_func, obj, + sfc = cairo_ps_surface_create_for_stream (_write_bytes_func, obj, width_in_points, height_in_points); Py_END_ALLOW_THREADS; return PycairoSurface_FromSurface (sfc, obj); @@ -1121,14 +1141,14 @@ svg_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { " None, or\n" " a filename (str), or\n" " a file object, or\n" -" an object that has a \"write\" method (like StringIO)." +" a file-like text-mode object which has a \"write\" method." ); return NULL; } Py_DECREF(writer); Py_BEGIN_ALLOW_THREADS; - sfc = cairo_svg_surface_create_for_stream (_write_func, obj, + sfc = cairo_svg_surface_create_for_stream (_write_str_func, obj, width_in_points, height_in_points); Py_END_ALLOW_THREADS; return PycairoSurface_FromSurface (sfc, obj); diff --git a/test/surface_create_for_stream.py b/test/surface_create_for_stream.py index da543f2..b6ad225 100755 --- a/test/surface_create_for_stream.py +++ b/test/surface_create_for_stream.py @@ -3,11 +3,10 @@ Test PDF/PS/SVG constructors (using streams) """ -import cStringIO import gc import math import sys -import StringIO +#import io.Bytes import cairo @@ -28,22 +27,27 @@ class C(object): self.closed = True +WIDTH, HEIGHT = 256, 256 + # a selection of possible args to surface.write_to_png() -#fo = '/tmp/f.ps' -fo = file('/tmp/f.svg', 'wb') -#fo = StringIO.StringIO() -#fo = cStringIO.StringIO() -#fo = sys.stdout +fo = sys.stdout # only compatible with str/text objects - SVG #fo = C() -#fo.close() # this should cause: ValueError: I/O operation on closed file - -WIDTH, HEIGHT = 256, 256 - +#fo = '/tmp/f.pdf' +#fo = open('/tmp/f.pdf', 'wb') #surface = cairo.PDFSurface(fo, WIDTH, HEIGHT) + +#fo = '/tmp/f.ps' +#fo = open('/tmp/f.ps', 'wb') #surface = cairo.PSSurface(fo, WIDTH, HEIGHT) + +#fo = '/tmp/f.svg' +#fo = open('/tmp/f.svg', 'wt') surface = cairo.SVGSurface(fo, WIDTH, HEIGHT) +#fo.close() # this should cause: ValueError: I/O operation on closed file + + #sys.stdout.write ('1\n'); sys.stdout.flush() ctx = cairo.Context(surface) @@ -74,7 +78,7 @@ ctx.fill() ctx.show_page() surface.finish() -# for testing StringIO: get data and write to file +# for testing io.Bytes: get data and write to file #string = fo.getvalue() #f2 = file('/tmp/f.ps', 'wb') #f2.write(string) -- cgit v1.2.1