Example #1
0
    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)
Example #2
0
    def write_to_memory(self):
        """Write the image to a large memory array.

        A large area of memory is allocated, the image is rendered to that
        memory array, and the array is returned as a buffer.

        For example, if you have a 2x2 uchar image containing the bytes 1, 2,
        3, 4, read left-to-right, top-to-bottom, then::

            buf = image.write_to_memory()

        will return a four byte buffer containing the values 1, 2, 3, 4.

        Returns:
            buffer

        Raises:
            :class:`.Error`

        """

        psize = ffi.new('size_t *')
        pointer = vips_lib.vips_image_write_to_memory(self.pointer, psize)
        if pointer == ffi.NULL:
            raise Error('unable to write to memory')
        pointer = ffi.gc(pointer, glib_lib.g_free)

        return ffi.buffer(pointer, psize[0])
Example #3
0
    def _get_pspec(self, name):
        # logger.debug('VipsObject.get_typeof: self = %s, name = %s',
        #              str(self), name)

        pspec = ffi.new('GParamSpec **')
        argument_class = ffi.new('VipsArgumentClass **')
        argument_instance = ffi.new('VipsArgumentInstance **')
        result = vips_lib.vips_object_get_argument(self.vobject,
                                                   _to_bytes(name), pspec,
                                                   argument_class,
                                                   argument_instance)

        if result != 0:
            return None

        return pspec[0]
Example #4
0
    def new_from_array(array, scale=1.0, offset=0.0):
        """Create an image from a 1D or 2D array.

        A new one-band image with :class:`BandFormat` ``'double'`` pixels is
        created from the array. These image are useful with the libvips
        convolution operator :meth:`Image.conv`.

        Args:
            array (list[list[float]]): Create the image from these values.
                1D arrays become a single row of pixels.
            scale (float): Default to 1.0. What to divide each pixel by after
                convolution.  Useful for integer convolution masks.
            offset (float): Default to 0.0. What to subtract from each pixel
                after convolution.  Useful for integer convolution masks.

        Returns:
            A new :class:`Image`.

        Raises:
            :class:`.Error`

        """
        if not _is_2D(array):
            array = [array]

        height = len(array)
        width = len(array[0])

        n = width * height
        a = ffi.new('double[]', n)
        for y in range(0, height):
            for x in range(0, width):
                a[x + y * width] = array[y][x]

        vi = vips_lib.vips_image_new_matrix_from_array(width, height, a, n)
        if vi == ffi.NULL:
            raise Error('unable to make image from matrix')
        image = pyvips.Image(vi)

        image.set_type(GValue.gdouble_type, 'scale', scale)
        image.set_type(GValue.gdouble_type, 'offset', offset)

        return image
Example #5
0
    def fetch(self, x, y, w, h):
        """Fill a region with pixel data.

        Pixels are filled with data!

        Returns:
            Pixel data.

        Raises:
            :class:`.Error`

        """

        if not at_least_libvips(8, 8):
            raise Error('libvips too old')

        psize = ffi.new('size_t *')
        pointer = vips_lib.vips_region_fetch(self.pointer, x, y, w, h, psize)
        if pointer == ffi.NULL:
            raise Error('unable to fetch from region')

        pointer = ffi.gc(pointer, glib_lib.g_free)
        return ffi.buffer(pointer, psize[0])
Example #6
0
    def __init__(self, operation_name):
        op = Operation.new_from_name(operation_name)

        self.description = op.get_description()
        self.flags = vips_lib.vips_operation_get_flags(op.pointer)

        # build a list of constructor arg [name, flags] pairs in arg order
        arguments = []

        def add_args(name, flags):
            if (flags & _CONSTRUCT) != 0:
                # libvips uses '-' to separate parts of arg names, but we
                # need '_' for Python
                name = name.replace('-', '_')
                arguments.append([name, flags])

        if at_least_libvips(8, 7):
            p_names = ffi.new('char**[1]')
            p_flags = ffi.new('int*[1]')
            p_n_args = ffi.new('int[1]')
            result = vips_lib.vips_object_get_args(op.vobject, p_names,
                                                   p_flags, p_n_args)
            if result != 0:
                raise Error('unable to get arguments from operation')
            p_names = p_names[0]
            p_flags = p_flags[0]
            n_args = p_n_args[0]

            for i in range(0, n_args):
                add_args(_to_string(p_names[i]), p_flags[i])
        else:

            def add_construct(self, pspec, argument_class, argument_instance,
                              a, b):
                add_args(_to_string(pspec.name), argument_class.flags)
                return ffi.NULL

            cb = ffi.callback('VipsArgumentMapFn', add_construct)
            vips_lib.vips_argument_map(op.vobject, cb, ffi.NULL, ffi.NULL)

        # logger.debug('arguments = %s', self.arguments)

        # build a hash from arg name to detailed arg information
        self.details = {}
        for name, flags in arguments:
            self.details[name] = {
                "name": name,
                "flags": flags,
                "blurb": op.get_blurb(name),
                "type": op.get_typeof(name)
            }

        # lists of arg names by category
        self.required_input = []
        self.optional_input = []
        self.required_output = []
        self.optional_output = []

        for name, flags in arguments:
            if ((flags & _INPUT) != 0 and (flags & _REQUIRED) != 0
                    and (flags & _DEPRECATED) == 0):
                self.required_input.append(name)

                # required inputs which we MODIFY are also required outputs
                if (flags & _MODIFY) != 0:
                    self.required_output.append(name)

            if ((flags & _OUTPUT) != 0 and (flags & _REQUIRED) != 0
                    and (flags & _DEPRECATED) == 0):
                self.required_output.append(name)

            # we let deprecated optional args through, but warn about them
            # if they get used, see below
            if ((flags & _INPUT) != 0 and (flags & _REQUIRED) == 0):
                self.optional_input.append(name)

            if ((flags & _OUTPUT) != 0 and (flags & _REQUIRED) == 0):
                self.optional_output.append(name)

        # find the first required input image arg, if any ... that will be self
        self.member_x = None
        for name in self.required_input:
            details = self.details[name]
            if details['type'] == GValue.image_type:
                self.member_x = name
                break

        # method args are required args, but without the image they are a
        # method on
        if self.member_x is not None:
            self.method_args = list(self.required_input)
            self.method_args.remove(self.member_x)
        else:
            self.method_args = self.required_input
Example #7
0
    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.g_type
        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:
            pointer = gobject_lib.g_value_get_string(self.gvalue)

            if pointer != ffi.NULL:
                result = _to_string(pointer)
        elif gtype == GValue.refstr_type:
            psize = ffi.new('size_t *')
            pointer = vips_lib.vips_value_get_ref_string(self.gvalue, psize)

            # psize[0] will be number of bytes in string, but just assume it's
            # NULL-terminated
            result = _to_string(pointer)
        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
Example #8
0
    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: value = %s', value)

        gtype = self.gvalue.g_type
        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:
            gobject_lib.g_value_set_string(self.gvalue, _to_bytes(value))
        elif gtype == GValue.refstr_type:
            vips_lib.vips_value_set_ref_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))

            # this is horrible!
            #
            # * in API mode, we must have 8.6+ and use set_blob_free to
            #   attach the metadata to avoid leaks
            # * pre-8.6, we just pass a NULL free pointer and live with the
            #   leak
            #
            # this is because in API mode you can't pass a builtin (what
            # vips_lib.g_free() becomes) as a parameter to ffi.callback(), and
            # vips_value_set_blob() needs a callback for arg 2
            #
            # additionally, you can't make a py def which calls g_free() and
            # then use the py def in the callback, since libvips will trigger
            # these functions during cleanup, and py will have shut down by
            # then and you'll get a segv

            if at_least_libvips(8, 6):
                vips_lib.vips_value_set_blob_free(self.gvalue, memory,
                                                  len(value))
            else:
                if pyvips.API_mode:
                    vips_lib.vips_value_set_blob(self.gvalue, ffi.NULL, memory,
                                                 len(value))
                else:
                    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)))
Example #9
0
    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: value = %s', 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)))