pycairo: [PATCH] ImageSurface data

Jeremy Moles <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <1323797117.15160.3.camel@lv-426>
I don't know how/where to best submit patches to Pycairo, so I'll do it
here and perhaps someone can direct me.

The attached patch will add basic support back into Python3/pycairo for
using ImageSurface.create_for_data() and ImageSurface.get_data(). It may
not be 100% perfect, but the examples work and it's a step in the right
direction.

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
0001-Adds-basic-support-for-ImageSurface-data.patch (text/x-patch, 9.6 KB)
From 2859b634561dda182b237351aa621c82cf85b642 Mon Sep 17 00:00:00 2001
From: Jeremy Moles <[email protected]>
Date: Tue, 13 Dec 2011 12:13:03 -0500
Subject: [PATCH] Adds basic support for ImageSurface data.

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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.