Source code for pyvips.gvalue

from __future__ import division
from __future__ import unicode_literals

import logging
import numbers
import sys

import pyvips
from pyvips import ffi, vips_lib, gobject_lib, \
    glib_lib, Error, _to_bytes, _to_string, type_name, type_from_name

logger = logging.getLogger(__name__)

_is_PY2 = sys.version_info.major == 2

ffi.cdef('''
    typedef struct _GValue {
        GType gtype;
        uint64_t data[2];
    } GValue;

    void g_value_init (GValue* value, GType gtype);
    void g_value_unset (GValue* value);
    GType g_type_fundamental (GType gtype);

    int vips_enum_from_nick (const char* domain,
        GType gtype, const char* str);
    const char *vips_enum_nick (GType gtype, int value);

    void g_value_set_boolean (GValue* value, int v_boolean);
    void g_value_set_int (GValue* value, int i);
    void g_value_set_double (GValue* value, double d);
    void g_value_set_enum (GValue* value, int e);
    void g_value_set_flags (GValue* value, unsigned int f);
    void g_value_set_string (GValue* value, const char *str);
    void g_value_set_object (GValue* value, void* object);
    void vips_value_set_array_double (GValue* value,
        const double* array, int n );
    void vips_value_set_array_int (GValue* value,
        const int* array, int n );
    void vips_value_set_array_image (GValue *value, int n);
    void vips_value_set_blob (GValue* value,
        void (*free_fn)(void* data), void* data, size_t length);

    int g_value_get_boolean (const GValue* value);
    int g_value_get_int (GValue* value);
    double g_value_get_double (GValue* value);
    int g_value_get_enum (GValue* value);
    unsigned int g_value_get_flags (GValue* value);
    const char* g_value_get_string (GValue* value);
    const char* vips_value_get_ref_string (const GValue* value,
        size_t* length);
    void* g_value_get_object (GValue* value);
    double* vips_value_get_array_double (const GValue* value, int* n);
    int* vips_value_get_array_int (const GValue* value, int* n);
    VipsImage** vips_value_get_array_image (const GValue* value, int* n);
    void* vips_value_get_blob (const GValue* value, size_t* length);

    // need to make some of these by hand
    GType vips_interpretation_get_type (void);
    GType vips_operation_flags_get_type (void);
    GType vips_band_format_get_type (void);

''')


[docs]class GValue(object): """Wrap GValue in a Python class. This class wraps :class:`.GValue` in a convenient interface. You can use instances of this class to get and set :class:`.GObject` properties. On construction, :class:`.GValue` is all zero (empty). You can pass it to a get function to have it filled by :class:`.GObject`, or use init to set a type, set to set a value, then use it to set an object property. GValue lifetime is managed automatically. """ # look up some common gtypes at init for speed gbool_type = type_from_name('gboolean') gint_type = type_from_name('gint') gdouble_type = type_from_name('gdouble') gstr_type = type_from_name('gchararray') genum_type = type_from_name('GEnum') gflags_type = type_from_name('GFlags') gobject_type = type_from_name('GObject') image_type = type_from_name('VipsImage') array_int_type = type_from_name('VipsArrayInt') array_double_type = type_from_name('VipsArrayDouble') array_image_type = type_from_name('VipsArrayImage') refstr_type = type_from_name('VipsRefString') blob_type = type_from_name('VipsBlob') pyvips.vips_lib.vips_band_format_get_type() format_type = type_from_name('VipsBandFormat') # map a gtype to the name of the corresponding Python type _gtype_to_python = { gbool_type: 'bool', gint_type: 'int', gdouble_type: 'float', gstr_type: 'str', refstr_type: 'str', genum_type: 'str', gflags_type: 'int', gobject_type: 'GObject', image_type: 'Image', array_int_type: 'list[int]', array_double_type: 'list[float]', array_image_type: 'list[Image]', blob_type: 'str' }
[docs] @staticmethod def gtype_to_python(gtype): """Map a gtype to the name of the Python type we use to represent it. """ fundamental = gobject_lib.g_type_fundamental(gtype) if gtype in GValue._gtype_to_python: return GValue._gtype_to_python[gtype] if fundamental in GValue._gtype_to_python: return GValue._gtype_to_python[fundamental] return '<unknown type>'
[docs] @staticmethod def to_enum(gtype, value): """Turn a string into an enum value ready to be passed into libvips. """ if isinstance(value, basestring if _is_PY2 else str): enum_value = vips_lib.vips_enum_from_nick(b'pyvips', gtype, _to_bytes(value)) if enum_value < 0: raise Error('no value {0} in gtype {1} ({2})'. format(value, type_name(gtype), gtype)) else: enum_value = value return enum_value
[docs] @staticmethod def from_enum(gtype, enum_value): """Turn an int back into an enum string. """ cstr = vips_lib.vips_enum_nick(gtype, enum_value) if cstr == 0: raise Error('value not in enum') return _to_string(ffi.string(cstr))
def __init__(self): # allocate memory for the gvalue which will be freed on GC self.pointer = ffi.new('GValue *') # logger.debug('GValue.__init__: pointer = %s', self.pointer) # and tag it to be unset on GC as well self.gvalue = ffi.gc(self.pointer, gobject_lib.g_value_unset) # logger.debug('GValue.__init__: gvalue = %s', self.gvalue)
[docs] def set_type(self, gtype): """Set the type of a GValue. GValues have a set type, fixed at creation time. Use set_type to set the type of a GValue before assigning to it. GTypes are 32 or 64-bit integers (depending on the platform). See type_find. """ gobject_lib.g_value_init(self.gvalue, gtype)
[docs] def set(self, value): """Set a GValue. The value is converted to the type of the GValue, if possible, and assigned. """ # logger.debug('GValue.set: self = %s, value = %s', self, value) gtype = self.gvalue.gtype fundamental = gobject_lib.g_type_fundamental(gtype) if gtype == GValue.gbool_type: gobject_lib.g_value_set_boolean(self.gvalue, value) elif gtype == GValue.gint_type: gobject_lib.g_value_set_int(self.gvalue, int(value)) elif gtype == GValue.gdouble_type: gobject_lib.g_value_set_double(self.gvalue, value) elif fundamental == GValue.genum_type: gobject_lib.g_value_set_enum(self.gvalue, GValue.to_enum(gtype, value)) elif fundamental == GValue.gflags_type: gobject_lib.g_value_set_flags(self.gvalue, value) elif gtype == GValue.gstr_type or gtype == GValue.refstr_type: gobject_lib.g_value_set_string(self.gvalue, _to_bytes(value)) elif fundamental == GValue.gobject_type: gobject_lib.g_value_set_object(self.gvalue, value.pointer) elif gtype == GValue.array_int_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('int[]', value) vips_lib.vips_value_set_array_int(self.gvalue, array, len(value)) elif gtype == GValue.array_double_type: if isinstance(value, numbers.Number): value = [value] array = ffi.new('double[]', value) vips_lib.vips_value_set_array_double(self.gvalue, array, len(value)) elif gtype == GValue.array_image_type: if isinstance(value, pyvips.Image): value = [value] vips_lib.vips_value_set_array_image(self.gvalue, len(value)) array = vips_lib.vips_value_get_array_image(self.gvalue, ffi.NULL) for i, image in enumerate(value): gobject_lib.g_object_ref(image.pointer) array[i] = image.pointer elif gtype == GValue.blob_type: # we need to set the blob to a copy of the string that vips_lib # can own memory = glib_lib.g_malloc(len(value)) ffi.memmove(memory, value, len(value)) vips_lib.vips_value_set_blob(self.gvalue, glib_lib.g_free, memory, len(value)) else: raise Error('unsupported gtype for set {0}, fundamental {1}'. format(type_name(gtype), type_name(fundamental)))
[docs] def get(self): """Get the contents of a GValue. The contents of the GValue are read out as a Python type. """ # logger.debug('GValue.get: self = %s', self) gtype = self.gvalue.gtype fundamental = gobject_lib.g_type_fundamental(gtype) result = None if gtype == GValue.gbool_type: result = bool(gobject_lib.g_value_get_boolean(self.gvalue)) elif gtype == GValue.gint_type: result = gobject_lib.g_value_get_int(self.gvalue) elif gtype == GValue.gdouble_type: result = gobject_lib.g_value_get_double(self.gvalue) elif fundamental == GValue.genum_type: return GValue.from_enum(gtype, gobject_lib.g_value_get_enum(self.gvalue)) elif fundamental == GValue.gflags_type: result = gobject_lib.g_value_get_flags(self.gvalue) elif gtype == GValue.gstr_type: cstr = gobject_lib.g_value_get_string(self.gvalue) if cstr != ffi.NULL: result = _to_string(ffi.string(cstr)) elif gtype == GValue.refstr_type: psize = ffi.new('size_t *') cstr = vips_lib.vips_value_get_ref_string(self.gvalue, psize) result = _to_string(ffi.string(cstr, psize[0])) elif gtype == GValue.image_type: # g_value_get_object() will not add a ref ... that is # held by the gvalue go = gobject_lib.g_value_get_object(self.gvalue) vi = ffi.cast('VipsImage *', go) # we want a ref that will last with the life of the vimage: # this ref is matched by the unref that's attached to finalize # by Image() gobject_lib.g_object_ref(go) result = pyvips.Image(vi) elif gtype == GValue.array_int_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_int(self.gvalue, pint) result = [] for i in range(0, pint[0]): result.append(array[i]) elif gtype == GValue.array_double_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_double(self.gvalue, pint) result = [] for i in range(0, pint[0]): result.append(array[i]) elif gtype == GValue.array_image_type: pint = ffi.new('int *') array = vips_lib.vips_value_get_array_image(self.gvalue, pint) result = [] for i in range(0, pint[0]): vi = array[i] gobject_lib.g_object_ref(vi) image = pyvips.Image(vi) result.append(image) elif gtype == GValue.blob_type: psize = ffi.new('size_t *') array = vips_lib.vips_value_get_blob(self.gvalue, psize) buf = ffi.cast("char*", array) result = ffi.unpack(buf, psize[0]) else: raise Error('unsupported gtype for get {0}'. format(type_name(gtype))) return result
__all__ = ['GValue']