[PATCH] Adds basic support for ImageSurface data.

Jeremy Moles cubicool at gmail.com
Tue Dec 13 09:13:03 PST 2011


Adds beginning support for get_data() and create_for_data()
back into the bindings. Also adds/cleans up tests to demonstrate
functionality.

Also modifies INSTALL to instruct users how to use different
versions of Python.
---
 INSTALL                           |    2 +
 src/surface.c                     |   25 ++++++++++--------
 test/isurface_create_for_data2.py |    2 +-
 test/isurface_create_from_png.py  |    8 +++---
 test/isurface_get_data.py         |   50 -------------------------------------
 test/isurface_get_data1.py        |   50 +++++++++++++++++++++++++++++++++++++
 test/isurface_get_data2.py        |   47 ++++++++++++++++++++++++++++++++++
 7 files changed, 118 insertions(+), 66 deletions(-)
 delete mode 100755 test/isurface_get_data.py
 create mode 100755 test/isurface_get_data1.py
 create mode 100755 test/isurface_get_data2.py

diff --git a/INSTALL b/INSTALL
index 14357b8..0b96f0c 100644
--- a/INSTALL
+++ b/INSTALL
@@ -9,7 +9,9 @@ $ ./waf install
 Use
 $ python3 ./waf ...
 if you have python2 and python3 installed, and the default is python 2.
+However, you specify a full path to the python binary using a command like:
 
+$ PYTHON=/usr/bin/python3 ./waf configure
 
 Testing
 -------
diff --git a/src/surface.c b/src/surface.c
index 35ca169..74d9dbc 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -418,20 +418,15 @@ static PyObject *
 image_surface_create_for_data (PyTypeObject *type, PyObject *args) {
   cairo_surface_t *surface;
   cairo_format_t format;
-  unsigned char *buffer;
   int width, height, stride = -1, res;
-  Py_ssize_t buffer_len;
   PyObject *obj;
-
-  // buffer function disabled
-  PyErr_SetString(PyExc_NotImplementedError, "Surface.create_for_data: Not Implemented yet.");
-  return NULL;
+  Py_buffer buffer;
 
   if (!PyArg_ParseTuple(args, "Oiii|i:Surface.create_for_data",
 			&obj, &format, &width, &height, &stride))
     return NULL;
 
-  res = PyObject_AsWriteBuffer (obj, (void **)&buffer, &buffer_len);
+  res = PyObject_GetBuffer (obj, &buffer, PyBUF_WRITABLE);
   if (res == -1)
     return NULL;
 
@@ -452,12 +447,12 @@ image_surface_create_for_data (PyTypeObject *type, PyObject *args) {
       return NULL;
     }
   }
-  if (height * stride > buffer_len) {
+  if (height * stride > buffer.len) {
     PyErr_SetString(PyExc_TypeError, "buffer is not long enough");
     return NULL;
   }
   Py_BEGIN_ALLOW_THREADS;
-  surface = cairo_image_surface_create_for_data (buffer, format, width,
+  surface = cairo_image_surface_create_for_data (buffer.buf, format, width,
 						 height, stride);
   Py_END_ALLOW_THREADS;
   return PycairoSurface_FromSurface(surface, obj);
@@ -546,9 +541,17 @@ image_surface_format_stride_for_width (PyObject *self, PyObject *args) {
 
 static PyObject *
 image_surface_get_data (PycairoImageSurface *o) {
-  PyErr_SetString(PyExc_NotImplementedError, "Surface.get_data: Not Implemented yet.");
+  Py_buffer buffer;
+  void *data;
+  int height, stride;
+
+  height = cairo_image_surface_get_height (o->surface);
+  stride = cairo_image_surface_get_stride (o->surface);
+  data = cairo_image_surface_get_data (o->surface);
+
+  if(!PyBuffer_FillInfo(&buffer, NULL, data, height * stride, 0, PyBUF_CONTIG))
+    return PyMemoryView_FromBuffer(&buffer);
   return NULL;
-  // return PyBuffer_FromReadWriteObject((PyObject *)o, 0, Py_END_OF_BUFFER);
 }
 
 static PyObject *
diff --git a/test/isurface_create_for_data2.py b/test/isurface_create_for_data2.py
index c4f290b..29a9984 100755
--- a/test/isurface_create_for_data2.py
+++ b/test/isurface_create_for_data2.py
@@ -27,4 +27,4 @@ surface = cairo.ImageSurface.create_for_data (data, cairo.FORMAT_ARGB32,
                                               width, height)
 ctx = cairo.Context(surface)
 surface.write_to_png(fileName)
-print "see %s output file" % fileName
+print("see %s output file" % fileName)
diff --git a/test/isurface_create_from_png.py b/test/isurface_create_from_png.py
index 8d1ce5d..ae8af18 100755
--- a/test/isurface_create_from_png.py
+++ b/test/isurface_create_from_png.py
@@ -18,7 +18,7 @@ surface = cairo.ImageSurface.create_from_png(inFileName)
 # write to filename
 _, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
 surface.write_to_png(outFileName)
-print "see %s output file" % outFileName
+print("see %s output file" % outFileName)
 
 # write to file object
 h, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
@@ -26,7 +26,7 @@ os.close(h)
 f=file(outFileName, "wb")
 surface.write_to_png(f)
 f.close()
-print "see %s output file" % outFileName
+print("see %s output file" % outFileName)
 
 # write to object that has a "write" method
 import StringIO
@@ -38,7 +38,7 @@ buf.close()
 f=file(outFileName, "wb")
 f.write(png_string)
 f.close()
-print "see %s output file" % outFileName
+print("see %s output file" % outFileName)
 
 # write to object that has a "write" method
 _, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
@@ -50,7 +50,7 @@ buf.close()
 f=file(outFileName, "wb")
 f.write(png_string)
 f.close()
-print "see %s output file" % outFileName
+print("see %s output file" % outFileName)
 
 # error test - to check the error message, should raise TypeError
 #surface.write_to_png(101)
diff --git a/test/isurface_get_data.py b/test/isurface_get_data.py
deleted file mode 100755
index f2662d4..0000000
--- a/test/isurface_get_data.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-"""
-Test ImageSurface.get_data()
-"""
-import tempfile
-
-import cairo
-import numpy
-
-if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
-  raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
-
-w, h = 128, 128
-
-surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
-ctx = cairo.Context(surface)
-
-ctx.set_source_rgb(1, 1, 1)  # white
-ctx.set_operator(cairo.OPERATOR_SOURCE)
-ctx.paint()
-
-# Draw out the triangle using absolute coordinates
-ctx.move_to(w/2, h/3)
-ctx.line_to(2*w/3, 2*h/3)
-ctx.rel_line_to(-1*w/3, 0)
-ctx.close_path()
-
-ctx.set_source_rgb(0, 0, 0)  # black
-ctx.set_line_width(15)
-ctx.stroke()
-_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
-surface.write_to_png(outFileName)
-print "see %s output file" % outFileName
-
-# modify surface using numpy
-buf = surface.get_data()
-# alternative which should work (?) but reports
-# TypeError: buffer is read-only
-# - is a Python bug?
-#buf = buffer (surface1)
-
-a = numpy.ndarray(shape=(w,h,4), dtype=numpy.uint8, buffer=buf)
-
-# draw a vertical line
-a[:,40,0] = 255  # byte 0 is blue on little-endian systems
-a[:,40,1] = 0
-a[:,40,2] = 0
-_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
-surface.write_to_png(outFileName)
-print "see %s output file" % outFileName
diff --git a/test/isurface_get_data1.py b/test/isurface_get_data1.py
new file mode 100755
index 0000000..92d25cf
--- /dev/null
+++ b/test/isurface_get_data1.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+"""
+Test ImageSurface.get_data()
+"""
+import tempfile
+
+import cairo
+import numpy
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+  raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+w, h = 128, 128
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ctx = cairo.Context(surface)
+
+ctx.set_source_rgb(1, 1, 1)  # white
+ctx.set_operator(cairo.OPERATOR_SOURCE)
+ctx.paint()
+
+# Draw out the triangle using absolute coordinates
+ctx.move_to(w/2, h/3)
+ctx.line_to(2*w/3, 2*h/3)
+ctx.rel_line_to(-1*w/3, 0)
+ctx.close_path()
+
+ctx.set_source_rgb(0, 0, 0)  # black
+ctx.set_line_width(15)
+ctx.stroke()
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print("see %s output file" % outFileName)
+
+# modify surface using numpy
+buf = surface.get_data()
+# alternative which should work (?) but reports
+# TypeError: buffer is read-only
+# - is a Python bug?
+#buf = buffer (surface1)
+
+a = numpy.ndarray(shape=(w,h,4), dtype=numpy.uint8, buffer=buf)
+
+# draw a vertical line
+a[:,40,0] = 255  # byte 0 is blue on little-endian systems
+a[:,40,1] = 0
+a[:,40,2] = 0
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print("see %s output file" % outFileName)
diff --git a/test/isurface_get_data2.py b/test/isurface_get_data2.py
new file mode 100755
index 0000000..f4c6e0e
--- /dev/null
+++ b/test/isurface_get_data2.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+"""
+Test ImageSurface.get_data()
+"""
+import tempfile
+
+import cairo
+
+import IPython
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+  raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+w, h = 128, 128
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ctx = cairo.Context(surface)
+
+ctx.set_source_rgb(1, 1, 1)  # white
+ctx.set_operator(cairo.OPERATOR_SOURCE)
+ctx.paint()
+
+# Draw out the triangle using absolute coordinates
+ctx.move_to(w/2, h/3)
+ctx.line_to(2*w/3, 2*h/3)
+ctx.rel_line_to(-1*w/3, 0)
+ctx.close_path()
+
+ctx.set_source_rgb(0, 0, 0)  # black
+ctx.set_line_width(15)
+ctx.stroke()
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print("see %s output file" % outFileName)
+
+buf = surface.get_data()
+
+for i in range(h):
+    offset = (i * surface.get_stride()) + 120
+    buf[offset] = b'\xFF'
+    buf[offset + 1] = b'\x00'
+    buf[offset + 2] = b'\x00'
+
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print("see %s output file" % outFileName)
+
-- 
1.7.7.3


--=-VelUTNKD6tfkL6HdnyrG--



More information about the cairo mailing list