[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

python-cairo+python-pygame work with default python in lenny?



tag 481506 patch

Hi,

apologies for lobbying for my pet peeves to be fixed in lenny, but the
attached python script (taking from upstream python-cairo 1.6.4[1],
needing python-pygame and python-cairo to be installed) works with
python 2.4 as is but not with the default python (2.5). Applying the
attached diff improves the situation making this also work with python
2.5. Some gory details below.

While the bug severity is set to "normal", the error message is somewhat
opaque and searching the internet only reveals some "maybe we should fix
this" comment, so the Debian user's experience might be improved by
eliminating the need for the search. If this is interesting enough for
people to upload and later unblock...

And here the promised gory details:
- The signature changes (insofar as they are changes) to Py_ssize_t are
  from the python 2.5 documentation. For python 2.4 they are actually
  no changes thanks to the cairo-private.h compatibility typedefs that
  seem to be based on PEP 353[2].
- python-pygame uses PyObject_AsCharBuffer from the abstract buffer
  protocol to get hold of the image buffer. This function seems to exist
  since Python 1.6 (certainly does in 2.4), but only python 2.5 changes
  is to actually use the charbufferproc that is now missing in
  python-cairo.
- I don't know why pycairo upstream does not seem to have implemented
  this despite adding tests that fail on python 2.5. Maybe they still
  use python 2.4 only?

Kind regards

T.

1. http://webcvs.cairographics.org/pycairo/test/pygame-test1.py
2. http://www.python.org/dev/peps/pep-0353/
-- 
Thomas Viehmann, http://thomas.viehmann.net/
#!/usr/bin/env python
"""demonstrate pycairo and pygame
method1: use a pycairo and pygame directly
"""

import array
import math
import sys

import cairo
import pygame

def draw(surface):
    x,y, radius = (250,250, 200)
    ctx = cairo.Context(surface)
    ctx.set_line_width(15)
    ctx.arc(x, y, radius, 0, 2.0 * math.pi)
    ctx.set_source_rgb(0.8, 0.8, 0.8)
    ctx.fill_preserve()
    ctx.set_source_rgb(1, 1, 1)
    ctx.stroke()

def input(events):
   for event in events:
      if event.type == pygame.QUIT:
         sys.exit(0)
      else:
         print event


Width, Height = 512, 512
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, Width, Height)

pygame.init()
window = pygame.display.set_mode( (Width,Height) )
screen = pygame.display.get_surface()

draw(surface)

#Create PyGame surface from Cairo Surface
buf = surface.get_data()
image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
#Tranfer to Screen
screen.blit(image, (0,0))
pygame.display.flip()

while True:
   input(pygame.event.get())


"""
with pycairo 1.4.12 and pygame 1.7.1 you get the error message:

Traceback (most recent call last):
  File "./pygame-test1.py", line 42, in <module>
    image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
TypeError: char buffer type not available

This is because with
    buf = surface.get_data()
pycairo provides a binary image buffer,
whereas with
    image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
pygame is expecting a text-based character buffer!
"""
diff -u pycairo-1.4.12/debian/changelog pycairo-1.4.12/debian/changelog
--- pycairo-1.4.12/debian/changelog
+++ pycairo-1.4.12/debian/changelog
@@ -1,3 +1,12 @@
+pycairo (1.4.12-1.2) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * Python 2.5 compatibility of Image buffer interface.
+    (needed e.g. for interaction with python-pygame).
+    Closes: #481506
+
+ -- Thomas Viehmann <tv@beamnet.de>  Tue, 13 Jan 2009 22:51:49 +0100
+
 pycairo (1.4.12-1.1) unstable; urgency=low
 
   * NMU.
only in patch2:
unchanged:
--- pycairo-1.4.12.orig/cairo/pycairo-surface.c
+++ pycairo-1.4.12/cairo/pycairo-surface.c
@@ -504,8 +504,8 @@
 
 
 /* Buffer interface functions, used by ImageSurface.get_data() */
-static int
-image_surface_buffer_getreadbuf (PycairoImageSurface *o, int segment,
+static Py_ssize_t
+image_surface_buffer_getreadbuf (PycairoImageSurface *o, Py_ssize_t segment,
 				 const void **ptr)
 {
     cairo_surface_t *surface = o->surface;
@@ -522,8 +522,8 @@
     return height * stride;
 }
 
-static int
-image_surface_buffer_getwritebuf (PycairoImageSurface *o, int segment,
+static Py_ssize_t
+image_surface_buffer_getwritebuf (PycairoImageSurface *o, Py_ssize_t segment,
 				  const void **ptr)
 {
     cairo_surface_t *surface = o->surface;
@@ -540,25 +540,43 @@
     return height * stride;
 }
 
-static int
-image_surface_buffer_getsegcount (PycairoImageSurface *o, int *lenp)
+static Py_ssize_t
+image_surface_buffer_getsegcount (PycairoImageSurface *o, Py_ssize_t *lenp)
 {
     if (lenp) {
 	/* report the sum of the sizes (in bytes) of all segments */
 	cairo_surface_t *surface = o->surface;
 	int height = cairo_image_surface_get_height (surface);
 	int stride = cairo_image_surface_get_stride (surface);
-	*lenp = height * stride;
+	*lenp = (Py_ssize_t) height * stride;
     }
     return 1;  /* surface data is all in one segment */
 }
 
+static Py_ssize_t
+image_surface_buffer_getcharbuf (PycairoImageSurface *o, Py_ssize_t segment,
+				  const char **ptr)
+{
+    cairo_surface_t *surface = o->surface;
+    int height, stride;
+
+    if (segment != 0) {
+	PyErr_SetString(PyExc_SystemError,
+			"accessing non-existent ImageSurface segment");
+	return -1;
+    }
+    height = cairo_image_surface_get_height (surface);
+    stride = cairo_image_surface_get_stride (surface);
+    *ptr = (char *) cairo_image_surface_get_data (surface);
+    return height * stride;
+}
+
 /* See Python C API Manual 10.7 */
 static PyBufferProcs image_surface_as_buffer = {
     (readbufferproc) image_surface_buffer_getreadbuf,
     (writebufferproc)image_surface_buffer_getwritebuf,
     (segcountproc)   image_surface_buffer_getsegcount,
-    (charbufferproc) NULL,
+    (charbufferproc) image_surface_buffer_getcharbuf,
 };
 
 static PyMethodDef image_surface_methods[] = {

Reply to: