add experimental ctypes Python binding
start hacking on a new Python interface
This commit is contained in:
parent
3920f5dc7e
commit
3628692799
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@ TAGS
|
|||||||
*.lo
|
*.lo
|
||||||
*.la
|
*.la
|
||||||
*.pc
|
*.pc
|
||||||
|
*.pyc
|
||||||
.deps
|
.deps
|
||||||
.libs
|
.libs
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
|
4
TODO
4
TODO
@ -69,10 +69,6 @@
|
|||||||
|
|
||||||
- some way for nip2 to get the vips bin area
|
- some way for nip2 to get the vips bin area
|
||||||
|
|
||||||
- some way for nip2 to get EXEEXT
|
|
||||||
|
|
||||||
- wrap a basic set of Magick filters
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- need vips_image_invalidate_area()
|
- need vips_image_invalidate_area()
|
||||||
|
11
python/README
Normal file
11
python/README
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Experimental Python binding using ctypes
|
||||||
|
|
||||||
|
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
|
||||||
|
the various python binaries is painful, and makes the bainding very large.
|
||||||
|
|
||||||
|
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,
|
||||||
|
plus we can reuse parts of the gobject binding, so this should be possible.
|
||||||
|
|
||||||
|
|
41
python/finalize.py
Normal file
41
python/finalize.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Finalization with weakrefs
|
||||||
|
# This is designed for avoiding __del__.
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
import weakref
|
||||||
|
|
||||||
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
|
|
||||||
|
class OwnerRef(weakref.ref):
|
||||||
|
"""A simple weakref.ref subclass, so attributes can be added."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _run_finalizer(ref):
|
||||||
|
"""Internal weakref callback to run finalizers"""
|
||||||
|
del _finalize_refs[id(ref)]
|
||||||
|
finalizer = ref.finalizer
|
||||||
|
item = ref.item
|
||||||
|
try:
|
||||||
|
finalizer(item)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Exception %s running %s", repr(e), format(finalizer))
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
_finalize_refs = {}
|
||||||
|
|
||||||
|
def track(owner, item, finalizer):
|
||||||
|
"""Register an object for finalization.
|
||||||
|
|
||||||
|
``owner`` is the the object which is responsible for ``item``.
|
||||||
|
``finalizer`` will be called with ``item`` as its only argument when
|
||||||
|
``owner`` is destroyed by the garbage collector.
|
||||||
|
"""
|
||||||
|
ref = OwnerRef(owner, _run_finalizer)
|
||||||
|
ref.item = item
|
||||||
|
ref.finalizer = finalizer
|
||||||
|
_finalize_refs[id(ref)] = ref
|
14
python/test.py
Executable file
14
python/test.py
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import vipsimage
|
||||||
|
|
||||||
|
logging.basicConfig(level = logging.DEBUG)
|
||||||
|
|
||||||
|
# should work
|
||||||
|
a = vipsimage.VipsImage('/home/john/pics/healthygirl.jpg')
|
||||||
|
a.write('x.png')
|
||||||
|
|
||||||
|
# should raise an error
|
||||||
|
a = vipsimage.VipsImage('banana')
|
50
python/vipsimage.py
Normal file
50
python/vipsimage.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/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 vipsobject
|
||||||
|
|
||||||
|
libvips = vipsobject.libvips
|
||||||
|
|
||||||
|
vips_image_new = libvips.vips_image_new
|
||||||
|
vips_image_new.restype = vipsobject.check_pointer_return
|
||||||
|
|
||||||
|
vips_image_new_from_file = libvips.vips_image_new_from_file
|
||||||
|
vips_image_new_from_file.restype = vipsobject.check_pointer_return
|
||||||
|
vips_image_new_from_file.argtypes = [ctypes.c_char_p]
|
||||||
|
|
||||||
|
vips_image_new_mode = libvips.vips_image_new_mode
|
||||||
|
vips_image_new_mode.restype = vipsobject.check_pointer_return
|
||||||
|
vips_image_new_mode.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
|
||||||
|
|
||||||
|
vips_image_write = libvips.vips_image_write
|
||||||
|
vips_image_write.restype = vipsobject.check_int_return
|
||||||
|
vips_image_write.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
||||||
|
|
||||||
|
class VipsImage(vipsobject.VipsObject):
|
||||||
|
"""Manipulate a libvips image."""
|
||||||
|
|
||||||
|
def __init__(self, filename = None, mode = None):
|
||||||
|
logging.debug('vipsimage: init')
|
||||||
|
|
||||||
|
vipsobject.VipsObject.__init__(self)
|
||||||
|
|
||||||
|
if filename == None and mode == None:
|
||||||
|
self.vipsobject = vips_image_new()
|
||||||
|
elif filename != None and mode == None:
|
||||||
|
self.vipsobject = vips_image_new_from_file(filename)
|
||||||
|
else:
|
||||||
|
self.vipsobject = vips_image_new_mode(filename, mode)
|
||||||
|
|
||||||
|
def write(self, filename):
|
||||||
|
vips_image_write(self.vipsobject, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
66
python/vipsobject.py
Normal file
66
python/vipsobject.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
"""This module wraps up libvips in a less awful interface.
|
||||||
|
|
||||||
|
Wrap VipsObject.
|
||||||
|
|
||||||
|
Author: J.Cupitt
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
import finalize
|
||||||
|
|
||||||
|
# .15 is 7.25+ with the new vips8 API
|
||||||
|
libvips = ctypes.CDLL('libvips.so.15')
|
||||||
|
libvips.vips_init(sys.argv[0])
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
|
||||||
|
"""An error from libvips.
|
||||||
|
|
||||||
|
message -- a high-level description of the error
|
||||||
|
detail -- a string with some detailed diagnostics
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
self.message = message
|
||||||
|
self.detail = vips_error_buffer()
|
||||||
|
libvips.vips_error_clear()
|
||||||
|
|
||||||
|
logging.debug('vipsobject: Error %s %s', self.message, self.detail)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s - %s' %(self.message, self.detail)
|
||||||
|
|
||||||
|
def check_int_return(value):
|
||||||
|
if value != 0:
|
||||||
|
raise Error('Error calling vips function.')
|
||||||
|
return value
|
||||||
|
|
||||||
|
def check_pointer_return(value):
|
||||||
|
if value == None:
|
||||||
|
raise Error('Error calling vips function.')
|
||||||
|
return value
|
||||||
|
|
||||||
|
vips_error_buffer = libvips.vips_error_buffer
|
||||||
|
vips_error_buffer.restype = ctypes.c_char_p
|
||||||
|
|
||||||
|
class VipsObject:
|
||||||
|
"""Abstract base class for libvips."""
|
||||||
|
|
||||||
|
def unref_vips(self):
|
||||||
|
if self.vipsobject != None:
|
||||||
|
libvips.g_object_unref(self.vipsobject)
|
||||||
|
self.vipsobject = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
logging.debug('vipsobject: init')
|
||||||
|
|
||||||
|
self.vipsobject = None
|
||||||
|
finalize.track(self, self, self.unref_vips)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user