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
|
||||
*.la
|
||||
*.pc
|
||||
*.pyc
|
||||
.deps
|
||||
.libs
|
||||
aclocal.m4
|
||||
|
6
TODO
6
TODO
@ -69,10 +69,6 @@
|
||||
|
||||
- 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()
|
||||
@ -93,7 +89,7 @@
|
||||
- get rid of a lot of the command-line programs, who wants to write a man page
|
||||
for batch_image_convert etc yuk
|
||||
|
||||
- can we make man pages for the API as well? probably not from googling a bit
|
||||
- can we make man pages for the API as well? probably not from googling a bit
|
||||
|
||||
|
||||
|
||||
|
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