some work on the new Python binding

This commit is contained in:
John Cupitt 2011-12-23 15:20:54 +00:00
parent 73465109b7
commit 39e92f8f1b
6 changed files with 99 additions and 12 deletions

8
TODO
View File

@ -1,3 +1,11 @@
- python/* is too old, keep for reference, but we need to use the
introspection stuff to get current gobject bindings
look at that brancg again
- foreign docs come up as "VipsForeignSave", annoying, why? - foreign docs come up as "VipsForeignSave", annoying, why?
- we can no longer have round brackets in filenames, argh - we can no longer have round brackets in filenames, argh

View File

@ -2,7 +2,7 @@ Experimental Python binding using ctypes
The current Python binding uses swig to wrap the C++ interface. This causes The current Python binding uses swig to wrap the C++ interface. This causes
problems on Windows, since compiling all of the DLLs correctly to work with problems on Windows, since compiling all of the DLLs correctly to work with
the various python binaries is painful, and makes the bainding very large. the various python binaries is painful, and makes the binding very large.
The idea here is to use ctypes to make a binding that's just Python and which The idea here is to use ctypes to make a binding that's just Python and which
directly wraps the C API. The new vips8 C API is much more wrapper-friendly, directly wraps the C API. The new vips8 C API is much more wrapper-friendly,

View File

@ -5,6 +5,7 @@ import gc
import gobject import gobject
import vipsobject
import vipsimage import vipsimage
logging.basicConfig(level = logging.DEBUG) logging.basicConfig(level = logging.DEBUG)
@ -21,22 +22,34 @@ a = vipsimage.VipsImage('/home/john/pics/healthygirl.jpg')
print 'width =', a.width() print 'width =', a.width()
print 'height =', a.height() print 'height =', a.height()
print 'bands =', a.bands() print 'bands =', a.bands()
print 'format =', vipsimage.VipsBandFormat.name(a.format()) print 'format = %d - %s' % (a.format(),
print 'coding =', vipsimage.VipsCoding.name(a.coding()) vipsimage.VipsBandFormat.name(a.format()))
print 'interpretation =', vipsimage.VipsInterpretation.name(a.interpretation()) print 'coding = %d - %s' % (a.coding(),
vipsimage.VipsCoding.name(a.coding()))
print 'interpretation = %d - %s' % (a.interpretation(),
vipsimage.VipsInterpretation.name(a.interpretation()))
print 'xres =', a.xres() print 'xres =', a.xres()
print 'yres =', a.yres() print 'yres =', a.yres()
print 'xoffset =', a.xoffset() print 'xoffset =', a.xoffset()
print 'yoffset =', a.yoffset() print 'yoffset =', a.yoffset()
# should raise an error # should raise an error
a = vipsimage.VipsImage('banana') try:
a = vipsimage.VipsImage('banana')
except vipsobject.VipsError, e:
print 'caught VipsError'
print '\tmessage =', e.message
print '\tdetail =', e.detail
# try calling a vips8 method # try calling a vips8 method
a = vipsimage.VipsImage('/home/john/pics/healthygirl.jpg') a = vipsimage.VipsImage('/home/john/pics/healthygirl.jpg')
b = vipsimage.VipsImage('/home/john/pics/babe.jpg') b = vipsimage.VipsImage('/home/john/pics/babe.jpg')
c = a.add(b) c = a.add(b)
print 'c = ', c
c.write('/home/john/pics/x.v')
print 'starting shutdown ...' print 'starting shutdown ...'
del a del a
del b del b

View File

@ -9,6 +9,8 @@ GNU LESSER GENERAL PUBLIC LICENSE
import logging import logging
import ctypes import ctypes
import gobject
import vipsobject import vipsobject
# image enums # image enums
@ -45,7 +47,6 @@ class VipsInterpretation:
@staticmethod @staticmethod
def name(value): def name(value):
print currentclass
return vipsobject.class_value(VipsInterpretation, value) return vipsobject.class_value(VipsInterpretation, value)
class VipsBandFormat: class VipsBandFormat:
@ -102,15 +103,14 @@ vips_image_get_xres.restype = ctypes.c_double;
vips_image_get_yres = libvips.vips_image_get_yres vips_image_get_yres = libvips.vips_image_get_yres
vips_image_get_yres.restype = ctypes.c_double; vips_image_get_yres.restype = ctypes.c_double;
vips_operation_new = libvips.vips_operation_new
vips_operation_new.argtypes = [ctypes.c_char_p]
vips_operation_new.restype = ctypes.c_void_p
vips_operation_new.errcheck = vipsobject.check_pointer_return
def vips_call_instance(self, name, args): def vips_call_instance(self, name, args):
logging.debug('vipsimage: vips_call_instance name=%s, self=%s, args=%s' % logging.debug('vipsimage: vips_call_instance name=%s, self=%s, args=%s' %
(name, self, args)) (name, self, args))
operation = vipsoperation.VipsOperation(name)
operation = vips_operation_new(name) operation = vips_operation_new(name)
vipsobject.vips_object_print(operation)
vipsobject.vips_argument_map(operation,
vipsobject.VipsArgumentMapFn(show_args),None, None)
class VipsImage(vipsobject.VipsObject): class VipsImage(vipsobject.VipsObject):
"""Manipulate a libvips image.""" """Manipulate a libvips image."""

View File

@ -20,6 +20,26 @@ import finalizable
libvips = ctypes.CDLL('libvips.so.15') libvips = ctypes.CDLL('libvips.so.15')
libvips.vips_init(sys.argv[0]) libvips.vips_init(sys.argv[0])
vips_object_print = libvips.vips_object_print
vips_object_print.argtypes = [ctypes.c_void_p]
vips_object_print.restype = None
# in C:
# typedef void *(*VipsArgumentMapFn)( VipsObject *,
# GParamSpec *, VipsArgumentClass *, VipsArgumentInstance *,
# void *a, void *b );
VipsArgumentMapFn = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_void_p)
vips_argument_map = libvips.vips_argument_map
vips_argument_map.argtypes = [ctypes.c_void_p, VipsArgumentMapFn,
ctypes.c_void_p, ctypes.c_void_p]
vips_argument_map.restype = ctypes.c_void_p
g_param_spec_get_name = libvips.g_param_spec_get_name
g_param_spec_get_name.argtypes = [ctypes.c_void_p]
g_param_spec_get_name.restype = ctypes.c_char_p
# given a class and value, search for a class member with that value # given a class and value, search for a class member with that value
# handy for enum classes, use to turn numbers to strings # handy for enum classes, use to turn numbers to strings
def class_value(classobject, value): def class_value(classobject, value):
@ -45,7 +65,7 @@ class VipsError(Exception):
logging.debug('vipsobject: Error: %s %s', self.message, self.detail) logging.debug('vipsobject: Error: %s %s', self.message, self.detail)
def __str__(self): def __str__(self):
return '%s %s' %(self.message, self.detail) return '%s %s' % (self.message, self.detail)
# handy checkers, assign to errcheck # handy checkers, assign to errcheck
def check_int_return(result, func, args): def check_int_return(result, func, args):

46
python/vipsoperation.py Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/python
"""This module wraps up libvips in a less awful interface.
Author: J.Cupitt
GNU LESSER GENERAL PUBLIC LICENSE
"""
import logging
import ctypes
import gobject
import vipsobject
libvips = vipsobject.libvips
vips_operation_new = libvips.vips_operation_new
vips_operation_new.argtypes = [ctypes.c_char_p]
vips_operation_new.restype = ctypes.c_void_p
vips_operation_new.errcheck = vipsobject.check_pointer_return
def show_args(operation, pspec, arg_class, arg_instance, a, b):
name = vipsobject.g_param_spec_get_name(pspec)
def vips_call_instance(self, name, args):
logging.debug('vipsimage: vips_call_instance name=%s, self=%s, args=%s' %
(name, self, args))
operation = vips_operation_new(name)
vipsobject.vips_object_print(operation)
vipsobject.vips_argument_map(operation,
vipsobject.VipsArgumentMapFn(show_args),None, None)
class VipsOperation(vipsobject.VipsObject):
"""Call a libvips operation."""
def __init__(self, name):
logging.debug('vipsoperation: init %s', name)
vipsobject.VipsObject.__init__(self)
self.vipsobject = vips_operation_new(name)
self.enable_finalize()
def call