vips 8.6.3.2 → 8.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +27 -22
- data/CHANGELOG.md +273 -0
- data/example/annotate.rb +2 -2
- data/example/daltonize8.rb +26 -28
- data/example/example1.rb +1 -2
- data/example/example2.rb +6 -6
- data/example/example3.rb +5 -5
- data/example/example4.rb +6 -6
- data/example/example5.rb +6 -7
- data/example/inheritance_with_refcount.rb +201 -218
- data/example/thumb.rb +10 -12
- data/example/trim8.rb +6 -6
- data/example/watermark.rb +14 -35
- data/example/wobble.rb +24 -24
- data/lib/vips.rb +335 -312
- data/lib/vips/access.rb +9 -9
- data/lib/vips/align.rb +7 -8
- data/lib/vips/angle.rb +8 -9
- data/lib/vips/angle45.rb +12 -13
- data/lib/vips/bandformat.rb +16 -18
- data/lib/vips/blend_mode.rb +32 -0
- data/lib/vips/coding.rb +11 -12
- data/lib/vips/compass_direction.rb +13 -14
- data/lib/vips/direction.rb +7 -8
- data/lib/vips/extend.rb +13 -14
- data/lib/vips/gobject.rb +92 -96
- data/lib/vips/gvalue.rb +231 -237
- data/lib/vips/image.rb +1329 -1330
- data/lib/vips/interesting.rb +10 -11
- data/lib/vips/interpolate.rb +49 -54
- data/lib/vips/interpretation.rb +25 -26
- data/lib/vips/kernel.rb +18 -19
- data/lib/vips/methods.rb +2319 -2141
- data/lib/vips/object.rb +204 -213
- data/lib/vips/operation.rb +317 -323
- data/lib/vips/operationboolean.rb +10 -11
- data/lib/vips/operationcomplex.rb +8 -9
- data/lib/vips/operationcomplex2.rb +6 -7
- data/lib/vips/operationcomplexget.rb +7 -8
- data/lib/vips/operationmath.rb +14 -15
- data/lib/vips/operationmath2.rb +6 -7
- data/lib/vips/operationrelational.rb +11 -12
- data/lib/vips/operationround.rb +7 -8
- data/lib/vips/size.rb +9 -10
- data/lib/vips/version.rb +1 -1
- data/vips.gemspec +1 -1
- metadata +9 -8
data/lib/vips/object.rb
CHANGED
@@ -7,238 +7,229 @@
|
|
7
7
|
require 'ffi'
|
8
8
|
|
9
9
|
module Vips
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
10
|
+
private
|
11
|
+
|
12
|
+
# debugging support
|
13
|
+
attach_function :vips_object_print_all, [], :void
|
14
|
+
|
15
|
+
# we must init these by hand, since they are usually made on first image
|
16
|
+
# create
|
17
|
+
attach_function :vips_band_format_get_type, [], :GType
|
18
|
+
attach_function :vips_interpretation_get_type, [], :GType
|
19
|
+
attach_function :vips_coding_get_type, [], :GType
|
20
|
+
|
21
|
+
public
|
22
|
+
|
23
|
+
# some handy gtypes
|
24
|
+
IMAGE_TYPE = GObject::g_type_from_name "VipsImage"
|
25
|
+
ARRAY_INT_TYPE = GObject::g_type_from_name "VipsArrayInt"
|
26
|
+
ARRAY_DOUBLE_TYPE = GObject::g_type_from_name "VipsArrayDouble"
|
27
|
+
ARRAY_IMAGE_TYPE = GObject::g_type_from_name "VipsArrayImage"
|
28
|
+
REFSTR_TYPE = GObject::g_type_from_name "VipsRefString"
|
29
|
+
BLOB_TYPE = GObject::g_type_from_name "VipsBlob"
|
30
|
+
|
31
|
+
BAND_FORMAT_TYPE = Vips::vips_band_format_get_type
|
32
|
+
INTERPRETATION_TYPE = Vips::vips_interpretation_get_type
|
33
|
+
CODING_TYPE = Vips::vips_coding_get_type
|
34
|
+
|
35
|
+
if Vips::at_least_libvips?(8, 6)
|
36
|
+
attach_function :vips_blend_mode_get_type, [], :GType
|
37
|
+
BLEND_MODE_TYPE = Vips::vips_blend_mode_get_type
|
38
|
+
else
|
39
|
+
BLEND_MODE_TYPE = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
|
45
|
+
attach_function :vips_enum_nick, [:GType, :int], :string
|
46
|
+
|
47
|
+
attach_function :vips_value_set_ref_string,
|
48
|
+
[GObject::GValue.ptr, :string], :void
|
49
|
+
attach_function :vips_value_set_array_double,
|
50
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
51
|
+
attach_function :vips_value_set_array_int,
|
52
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
53
|
+
attach_function :vips_value_set_array_image,
|
54
|
+
[GObject::GValue.ptr, :int], :void
|
55
|
+
callback :free_fn, [:pointer], :void
|
56
|
+
attach_function :vips_value_set_blob,
|
57
|
+
[GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void
|
58
|
+
|
59
|
+
class SizeStruct < FFI::Struct
|
60
|
+
layout :value, :size_t
|
61
|
+
end
|
62
|
+
|
63
|
+
class IntStruct < FFI::Struct
|
64
|
+
layout :value, :int
|
65
|
+
end
|
66
|
+
|
67
|
+
attach_function :vips_value_get_ref_string,
|
68
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :string
|
69
|
+
attach_function :vips_value_get_array_double,
|
70
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
71
|
+
attach_function :vips_value_get_array_int,
|
72
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
73
|
+
attach_function :vips_value_get_array_image,
|
74
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
75
|
+
attach_function :vips_value_get_blob,
|
76
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :pointer
|
77
|
+
|
78
|
+
attach_function :type_find, :vips_type_find, [:string, :string], :GType
|
79
|
+
|
80
|
+
class Object < GObject::GObject
|
81
|
+
# print all active VipsObjects, with their reference counts. Handy for
|
82
|
+
# debugging ruby-vips.
|
83
|
+
def self.print_all
|
84
|
+
GC.start
|
85
|
+
Vips::vips_object_print_all
|
40
86
|
end
|
41
87
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
class SizeStruct < FFI::Struct
|
60
|
-
layout :value, :size_t
|
88
|
+
# the layout of the VipsObject struct
|
89
|
+
module ObjectLayout
|
90
|
+
def self.included base
|
91
|
+
base.class_eval do
|
92
|
+
# don't actually need most of these
|
93
|
+
layout :parent, GObject::GObject::Struct,
|
94
|
+
:constructed, :int,
|
95
|
+
:static_object, :int,
|
96
|
+
:argument_table, :pointer,
|
97
|
+
:nickname, :string,
|
98
|
+
:description, :string,
|
99
|
+
:preclose, :int,
|
100
|
+
:close, :int,
|
101
|
+
:postclose, :int,
|
102
|
+
:local_memory, :size_t
|
103
|
+
end
|
104
|
+
end
|
61
105
|
end
|
62
106
|
|
63
|
-
class
|
64
|
-
|
107
|
+
class Struct < GObject::GObject::Struct
|
108
|
+
include ObjectLayout
|
65
109
|
end
|
66
110
|
|
67
|
-
|
68
|
-
|
69
|
-
attach_function :vips_value_get_array_double,
|
70
|
-
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
71
|
-
attach_function :vips_value_get_array_int,
|
72
|
-
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
73
|
-
attach_function :vips_value_get_array_image,
|
74
|
-
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
75
|
-
attach_function :vips_value_get_blob,
|
76
|
-
[GObject::GValue.ptr, SizeStruct.ptr], :pointer
|
77
|
-
|
78
|
-
attach_function :type_find, :vips_type_find, [:string, :string], :GType
|
79
|
-
|
80
|
-
class Object < GObject::GObject
|
81
|
-
|
82
|
-
# print all active VipsObjects, with their reference counts. Handy for
|
83
|
-
# debugging ruby-vips.
|
84
|
-
def self.print_all
|
85
|
-
GC.start
|
86
|
-
Vips::vips_object_print_all
|
87
|
-
end
|
88
|
-
|
89
|
-
# the layout of the VipsObject struct
|
90
|
-
module ObjectLayout
|
91
|
-
def self.included base
|
92
|
-
base.class_eval do
|
93
|
-
# don't actually need most of these
|
94
|
-
layout :parent, GObject::GObject::Struct,
|
95
|
-
:constructed, :int,
|
96
|
-
:static_object, :int,
|
97
|
-
:argument_table, :pointer,
|
98
|
-
:nickname, :string,
|
99
|
-
:description, :string,
|
100
|
-
:preclose, :int,
|
101
|
-
:close, :int,
|
102
|
-
:postclose, :int,
|
103
|
-
:local_memory, :size_t
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
class Struct < GObject::GObject::Struct
|
109
|
-
include ObjectLayout
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
class ManagedStruct < GObject::GObject::ManagedStruct
|
114
|
-
include ObjectLayout
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
# return a pspec, or nil ... nil wil leave a message in the error log
|
119
|
-
# which you must clear
|
120
|
-
def get_pspec name
|
121
|
-
pspec = GObject::GParamSpecPtr.new
|
122
|
-
argument_class = Vips::ArgumentClassPtr.new
|
123
|
-
argument_instance = Vips::ArgumentInstancePtr.new
|
124
|
-
|
125
|
-
result = Vips::vips_object_get_argument self, name,
|
126
|
-
pspec, argument_class, argument_instance
|
127
|
-
return nil if result != 0
|
128
|
-
|
129
|
-
pspec
|
130
|
-
end
|
131
|
-
|
132
|
-
# return a gtype, raise an error on not found
|
133
|
-
def get_typeof_error name
|
134
|
-
pspec = get_pspec name
|
135
|
-
raise Vips::Error unless pspec
|
136
|
-
|
137
|
-
pspec[:value][:value_type]
|
138
|
-
end
|
139
|
-
|
140
|
-
# return a gtype, 0 on not found
|
141
|
-
def get_typeof name
|
142
|
-
pspec = get_pspec name
|
143
|
-
unless pspec
|
144
|
-
Vips::vips_error_clear
|
145
|
-
return 0
|
146
|
-
end
|
147
|
-
|
148
|
-
pspec[:value][:value_type]
|
149
|
-
end
|
150
|
-
|
151
|
-
def get name
|
152
|
-
gtype = get_typeof_error name
|
153
|
-
gvalue = GObject::GValue.alloc
|
154
|
-
gvalue.init gtype
|
155
|
-
GObject::g_object_get_property self, name, gvalue
|
156
|
-
result = gvalue.get
|
157
|
-
|
158
|
-
GLib::logger.debug("Vips::Object.get") {"#{name} == #{result}"}
|
159
|
-
|
160
|
-
return result
|
161
|
-
end
|
162
|
-
|
163
|
-
def set name, value
|
164
|
-
GLib::logger.debug("Vips::Object.set") {"#{name} = #{value}"}
|
165
|
-
|
166
|
-
gtype = get_typeof_error name
|
167
|
-
gvalue = GObject::GValue.alloc
|
168
|
-
gvalue.init gtype
|
169
|
-
gvalue.set value
|
170
|
-
GObject::g_object_set_property self, name, gvalue
|
171
|
-
end
|
172
|
-
|
111
|
+
class ManagedStruct < GObject::GObject::ManagedStruct
|
112
|
+
include ObjectLayout
|
173
113
|
end
|
174
114
|
|
175
|
-
|
176
|
-
|
177
|
-
|
115
|
+
# return a pspec, or nil ... nil wil leave a message in the error log
|
116
|
+
# which you must clear
|
117
|
+
def get_pspec name
|
118
|
+
pspec = GObject::GParamSpecPtr.new
|
119
|
+
argument_class = Vips::ArgumentClassPtr.new
|
120
|
+
argument_instance = Vips::ArgumentInstancePtr.new
|
178
121
|
|
179
|
-
|
180
|
-
|
181
|
-
|
122
|
+
result = Vips::vips_object_get_argument self, name,
|
123
|
+
pspec, argument_class, argument_instance
|
124
|
+
return nil if result != 0
|
182
125
|
|
183
|
-
|
184
|
-
layout :parent, Argument
|
185
|
-
# rest opaque
|
126
|
+
pspec
|
186
127
|
end
|
187
128
|
|
188
|
-
#
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
ARGUMENT_SET_ALWAYS = 8
|
193
|
-
ARGUMENT_INPUT = 16
|
194
|
-
ARGUMENT_OUTPUT = 32
|
195
|
-
ARGUMENT_DEPRECATED = 64
|
196
|
-
ARGUMENT_MODIFY = 128
|
197
|
-
|
198
|
-
ARGUMENT_FLAGS = {
|
199
|
-
:required => ARGUMENT_REQUIRED,
|
200
|
-
:construct => ARGUMENT_CONSTRUCT,
|
201
|
-
:set_once => ARGUMENT_SET_ONCE,
|
202
|
-
:set_always => ARGUMENT_SET_ALWAYS,
|
203
|
-
:input => ARGUMENT_INPUT,
|
204
|
-
:output => ARGUMENT_OUTPUT,
|
205
|
-
:deprecated => ARGUMENT_DEPRECATED,
|
206
|
-
:modify => ARGUMENT_MODIFY
|
207
|
-
}
|
208
|
-
|
209
|
-
class ArgumentClass < Argument
|
210
|
-
layout :parent, Argument,
|
211
|
-
:object_class, ObjectClass.ptr,
|
212
|
-
:flags, :uint,
|
213
|
-
:priority, :int,
|
214
|
-
:offset, :ulong_long
|
215
|
-
end
|
129
|
+
# return a gtype, raise an error on not found
|
130
|
+
def get_typeof_error name
|
131
|
+
pspec = get_pspec name
|
132
|
+
raise Vips::Error unless pspec
|
216
133
|
|
217
|
-
|
218
|
-
layout :value, ArgumentClass.ptr
|
134
|
+
pspec[:value][:value_type]
|
219
135
|
end
|
220
136
|
|
221
|
-
|
222
|
-
|
223
|
-
|
137
|
+
# return a gtype, 0 on not found
|
138
|
+
def get_typeof name
|
139
|
+
pspec = get_pspec name
|
140
|
+
unless pspec
|
141
|
+
Vips::vips_error_clear
|
142
|
+
return 0
|
143
|
+
end
|
224
144
|
|
225
|
-
|
226
|
-
|
227
|
-
attach_function :vips_object_get_argument,
|
228
|
-
[:pointer, :string,
|
229
|
-
GObject::GParamSpecPtr.ptr,
|
230
|
-
ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
|
231
|
-
:int
|
145
|
+
pspec[:value][:value_type]
|
146
|
+
end
|
232
147
|
|
233
|
-
|
148
|
+
def get name
|
149
|
+
gtype = get_typeof_error name
|
150
|
+
gvalue = GObject::GValue.alloc
|
151
|
+
gvalue.init gtype
|
152
|
+
GObject::g_object_get_property self, name, gvalue
|
153
|
+
result = gvalue.get
|
234
154
|
|
235
|
-
|
155
|
+
GLib::logger.debug("Vips::Object.get") { "#{name} == #{result}" }
|
236
156
|
|
237
|
-
|
238
|
-
|
157
|
+
return result
|
158
|
+
end
|
239
159
|
|
240
|
-
|
160
|
+
def set name, value
|
161
|
+
GLib::logger.debug("Vips::Object.set") { "#{name} = #{value}" }
|
241
162
|
|
163
|
+
gtype = get_typeof_error name
|
164
|
+
gvalue = GObject::GValue.alloc
|
165
|
+
gvalue.init gtype
|
166
|
+
gvalue.set value
|
167
|
+
GObject::g_object_set_property self, name, gvalue
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class ObjectClass < FFI::Struct
|
172
|
+
# opaque
|
173
|
+
end
|
174
|
+
|
175
|
+
class Argument < FFI::Struct
|
176
|
+
layout :pspec, GObject::GParamSpec.ptr
|
177
|
+
end
|
178
|
+
|
179
|
+
class ArgumentInstance < Argument
|
180
|
+
layout :parent, Argument
|
181
|
+
# rest opaque
|
182
|
+
end
|
183
|
+
|
184
|
+
# enum VipsArgumentFlags
|
185
|
+
ARGUMENT_REQUIRED = 1
|
186
|
+
ARGUMENT_CONSTRUCT = 2
|
187
|
+
ARGUMENT_SET_ONCE = 4
|
188
|
+
ARGUMENT_SET_ALWAYS = 8
|
189
|
+
ARGUMENT_INPUT = 16
|
190
|
+
ARGUMENT_OUTPUT = 32
|
191
|
+
ARGUMENT_DEPRECATED = 64
|
192
|
+
ARGUMENT_MODIFY = 128
|
193
|
+
|
194
|
+
ARGUMENT_FLAGS = {
|
195
|
+
required: ARGUMENT_REQUIRED,
|
196
|
+
construct: ARGUMENT_CONSTRUCT,
|
197
|
+
set_once: ARGUMENT_SET_ONCE,
|
198
|
+
set_always: ARGUMENT_SET_ALWAYS,
|
199
|
+
input: ARGUMENT_INPUT,
|
200
|
+
output: ARGUMENT_OUTPUT,
|
201
|
+
deprecated: ARGUMENT_DEPRECATED,
|
202
|
+
modify: ARGUMENT_MODIFY
|
203
|
+
}
|
204
|
+
|
205
|
+
class ArgumentClass < Argument
|
206
|
+
layout :parent, Argument,
|
207
|
+
:object_class, ObjectClass.ptr,
|
208
|
+
:flags, :uint,
|
209
|
+
:priority, :int,
|
210
|
+
:offset, :ulong_long
|
211
|
+
end
|
212
|
+
|
213
|
+
class ArgumentClassPtr < FFI::Struct
|
214
|
+
layout :value, ArgumentClass.ptr
|
215
|
+
end
|
216
|
+
|
217
|
+
class ArgumentInstancePtr < FFI::Struct
|
218
|
+
layout :value, ArgumentInstance.ptr
|
219
|
+
end
|
220
|
+
|
221
|
+
# just use :pointer, not VipsObject.ptr, to avoid casting gobject
|
222
|
+
# subclasses
|
223
|
+
attach_function :vips_object_get_argument,
|
224
|
+
[:pointer, :string,
|
225
|
+
GObject::GParamSpecPtr.ptr,
|
226
|
+
ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
|
227
|
+
:int
|
228
|
+
|
229
|
+
attach_function :vips_object_set_from_string, [:pointer, :string], :int
|
230
|
+
|
231
|
+
callback :type_map_fn, [:GType, :pointer], :pointer
|
232
|
+
attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
|
233
|
+
|
234
|
+
attach_function :vips_object_get_description, [:pointer], :string
|
242
235
|
end
|
243
|
-
|
244
|
-
|
data/lib/vips/operation.rb
CHANGED
@@ -7,359 +7,353 @@
|
|
7
7
|
require 'ffi'
|
8
8
|
|
9
9
|
module Vips
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
# rest opaque
|
46
|
-
end
|
47
|
-
end
|
10
|
+
private
|
11
|
+
|
12
|
+
attach_function :vips_operation_new, [:string], :pointer
|
13
|
+
|
14
|
+
attach_function :vips_cache_operation_build, [:pointer], :pointer
|
15
|
+
attach_function :vips_object_unref_outputs, [:pointer], :void
|
16
|
+
|
17
|
+
callback :argument_map_fn, [:pointer,
|
18
|
+
GObject::GParamSpec.ptr,
|
19
|
+
ArgumentClass.ptr,
|
20
|
+
ArgumentInstance.ptr,
|
21
|
+
:pointer, :pointer], :pointer
|
22
|
+
attach_function :vips_argument_map, [:pointer,
|
23
|
+
:argument_map_fn,
|
24
|
+
:pointer, :pointer], :pointer
|
25
|
+
|
26
|
+
OPERATION_SEQUENTIAL = 1
|
27
|
+
OPERATION_NOCACHE = 4
|
28
|
+
OPERATION_DEPRECATED = 8
|
29
|
+
|
30
|
+
OPERATION_FLAGS = {
|
31
|
+
sequential: OPERATION_SEQUENTIAL,
|
32
|
+
nocache: OPERATION_NOCACHE,
|
33
|
+
deprecated: OPERATION_DEPRECATED
|
34
|
+
}
|
35
|
+
|
36
|
+
attach_function :vips_operation_get_flags, [:pointer], :int
|
37
|
+
|
38
|
+
class Operation < Object
|
39
|
+
# the layout of the VipsOperation struct
|
40
|
+
module OperationLayout
|
41
|
+
def self.included base
|
42
|
+
base.class_eval do
|
43
|
+
layout :parent, Object::Struct
|
44
|
+
# rest opaque
|
48
45
|
end
|
46
|
+
end
|
47
|
+
end
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
class Struct < Object::Struct
|
50
|
+
include OperationLayout
|
51
|
+
end
|
52
52
|
|
53
|
-
|
53
|
+
class ManagedStruct < Object::ManagedStruct
|
54
|
+
include OperationLayout
|
55
|
+
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
+
def initialize value
|
58
|
+
# allow init with a pointer so we can wrap the return values from
|
59
|
+
# things like _build
|
60
|
+
if value.is_a? String
|
61
|
+
value = Vips::vips_operation_new value
|
62
|
+
raise Vips::Error if value == nil
|
63
|
+
end
|
57
64
|
|
58
|
-
|
65
|
+
super value
|
66
|
+
end
|
59
67
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
raise Vips::Error if value == nil
|
66
|
-
end
|
68
|
+
def build
|
69
|
+
op = Vips::vips_cache_operation_build self
|
70
|
+
if op == nil
|
71
|
+
raise Vips::Error
|
72
|
+
end
|
67
73
|
|
68
|
-
|
69
|
-
|
74
|
+
return Operation.new op
|
75
|
+
end
|
70
76
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
77
|
+
def argument_map &block
|
78
|
+
fn = Proc.new do |_op, pspec, argument_class, argument_instance, _a, _b|
|
79
|
+
block.call pspec, argument_class, argument_instance
|
80
|
+
end
|
76
81
|
|
77
|
-
|
78
|
-
|
82
|
+
Vips::vips_argument_map self, fn, nil, nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_flags
|
86
|
+
Vips::vips_operation_get_flags self
|
87
|
+
end
|
79
88
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
89
|
+
# not quick! try to call this infrequently
|
90
|
+
def get_construct_args
|
91
|
+
args = []
|
84
92
|
|
85
|
-
|
86
|
-
|
93
|
+
argument_map do |pspec, argument_class, _argument_instance|
|
94
|
+
flags = argument_class[:flags]
|
95
|
+
if (flags & ARGUMENT_CONSTRUCT) != 0
|
96
|
+
# names can include - as punctuation, but we always use _ in
|
97
|
+
# Ruby
|
98
|
+
name = pspec[:name].tr("-", "_")
|
87
99
|
|
88
|
-
|
89
|
-
Vips::vips_operation_get_flags self
|
100
|
+
args << [name, flags]
|
90
101
|
end
|
102
|
+
end
|
91
103
|
|
92
|
-
|
93
|
-
|
94
|
-
args = []
|
104
|
+
return args
|
105
|
+
end
|
95
106
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
# Ruby
|
101
|
-
name = pspec[:name].tr("-", "_")
|
107
|
+
# search array for the first element to match a predicate ...
|
108
|
+
# search inside subarrays and sub-hashes
|
109
|
+
def self.find_inside object, &block
|
110
|
+
return object if block.call object
|
102
111
|
|
103
|
-
|
104
|
-
|
105
|
-
|
112
|
+
if object.is_a? Enumerable
|
113
|
+
object.find { |value| block.call value, block }
|
114
|
+
end
|
106
115
|
|
107
|
-
|
108
|
-
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
|
119
|
+
# expand a constant into an image
|
120
|
+
def self.imageize match_image, value
|
121
|
+
return value if value.is_a? Image
|
122
|
+
|
123
|
+
# 2D array values become tiny 2D images
|
124
|
+
# if there's nothing to match to, we also make a 2D image
|
125
|
+
if (value.is_a?(Array) && value[0].is_a?(Array)) ||
|
126
|
+
match_image == nil
|
127
|
+
return Image.new_from_array value
|
128
|
+
else
|
129
|
+
# we have a 1D array ... use that as a pixel constant and
|
130
|
+
# expand to match match_image
|
131
|
+
return match_image.new_from_image value
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# set an operation argument, expanding constants and copying images as
|
136
|
+
# required
|
137
|
+
def set name, value, match_image = nil, flags = 0
|
138
|
+
gtype = get_typeof name
|
109
139
|
|
110
|
-
|
111
|
-
|
112
|
-
def self.find_inside object, &block
|
113
|
-
return object if block.call object
|
140
|
+
if gtype == IMAGE_TYPE
|
141
|
+
value = Operation::imageize match_image, value
|
114
142
|
|
115
|
-
|
116
|
-
|
117
|
-
|
143
|
+
if (flags & ARGUMENT_MODIFY) != 0
|
144
|
+
# make sure we have a unique copy
|
145
|
+
value = value.copy.copy_memory
|
146
|
+
end
|
147
|
+
elsif gtype == ARRAY_IMAGE_TYPE
|
148
|
+
value = value.map { |x| Operation::imageize match_image, x }
|
149
|
+
end
|
150
|
+
|
151
|
+
super name, value
|
152
|
+
end
|
118
153
|
|
119
|
-
|
154
|
+
public
|
155
|
+
|
156
|
+
# This is the public entry point for the vips binding. {call} will run
|
157
|
+
# any vips operation, for example:
|
158
|
+
#
|
159
|
+
# ```ruby
|
160
|
+
# out = Vips::Operation.call "black", [100, 100], {:bands => 12}
|
161
|
+
# ```
|
162
|
+
#
|
163
|
+
# will call the C function
|
164
|
+
#
|
165
|
+
# ```C
|
166
|
+
# vips_black( &out, 100, 100, "bands", 12, NULL );
|
167
|
+
# ```
|
168
|
+
#
|
169
|
+
# There are {Image#method_missing} hooks which will run {call} for you
|
170
|
+
# on {Image} for undefined instance or class methods. So you can also
|
171
|
+
# write:
|
172
|
+
#
|
173
|
+
# ```ruby
|
174
|
+
# out = Vips::Image.black 100, 100, bands: 12
|
175
|
+
# ```
|
176
|
+
#
|
177
|
+
# Or perhaps:
|
178
|
+
#
|
179
|
+
# ```ruby
|
180
|
+
# x = Vips::Image.black 100, 100
|
181
|
+
# y = x.invert
|
182
|
+
# ```
|
183
|
+
#
|
184
|
+
# to run the `vips_invert()` operator.
|
185
|
+
#
|
186
|
+
# There are also a set of operator overloads and some convenience
|
187
|
+
# functions, see {Image}.
|
188
|
+
#
|
189
|
+
# If the operator needs a vector constant, {call} will turn a scalar
|
190
|
+
# into a
|
191
|
+
# vector for you. So for `x.linear a, b`, which calculates
|
192
|
+
# `x * a + b` where `a` and `b` are vector constants, you can write:
|
193
|
+
#
|
194
|
+
# ```ruby
|
195
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
196
|
+
# y = x.linear 1, 2
|
197
|
+
# y = x.linear [1], 4
|
198
|
+
# y = x.linear [1, 2, 3], 4
|
199
|
+
# ```
|
200
|
+
#
|
201
|
+
# or any other combination. The operator overloads use this facility to
|
202
|
+
# support all the variations on:
|
203
|
+
#
|
204
|
+
# ```ruby
|
205
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
206
|
+
# y = x * 2
|
207
|
+
# y = x + [1,2,3]
|
208
|
+
# y = x % [1]
|
209
|
+
# ```
|
210
|
+
#
|
211
|
+
# Similarly, wherever an image is required, you can use a constant. The
|
212
|
+
# constant will be expanded to an image matching the first input image
|
213
|
+
# argument. For example, you can write:
|
214
|
+
#
|
215
|
+
# ```
|
216
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
217
|
+
# y = x.bandjoin 255
|
218
|
+
# ```
|
219
|
+
#
|
220
|
+
# to add an extra band to the image where each pixel in the new band has
|
221
|
+
# the constant value 255.
|
222
|
+
|
223
|
+
def self.call name, supplied, optional = {}, option_string = ""
|
224
|
+
GLib::logger.debug("Vips::VipsOperation.call") {
|
225
|
+
"name = #{name}, supplied = #{supplied}, " +
|
226
|
+
"optional = #{optional}, option_string = #{option_string}"
|
227
|
+
}
|
228
|
+
|
229
|
+
op = Operation.new name
|
230
|
+
|
231
|
+
# find and classify all the arguments the operator can take
|
232
|
+
args = op.get_construct_args
|
233
|
+
required_input = []
|
234
|
+
optional_input = {}
|
235
|
+
required_output = []
|
236
|
+
optional_output = {}
|
237
|
+
args.each do |arg_name, flags|
|
238
|
+
next if (flags & ARGUMENT_DEPRECATED) != 0
|
239
|
+
|
240
|
+
if (flags & ARGUMENT_INPUT) != 0
|
241
|
+
if (flags & ARGUMENT_REQUIRED) != 0
|
242
|
+
required_input << [arg_name, flags]
|
243
|
+
else
|
244
|
+
optional_input[arg_name] = flags
|
245
|
+
end
|
120
246
|
end
|
121
247
|
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
else
|
132
|
-
# we have a 1D array ... use that as a pixel constant and
|
133
|
-
# expand to match match_image
|
134
|
-
return match_image.new_from_image value
|
135
|
-
end
|
248
|
+
# MODIFY INPUT args count as OUTPUT as well
|
249
|
+
if (flags & ARGUMENT_OUTPUT) != 0 ||
|
250
|
+
((flags & ARGUMENT_INPUT) != 0 &&
|
251
|
+
(flags & ARGUMENT_MODIFY) != 0)
|
252
|
+
if (flags & ARGUMENT_REQUIRED) != 0
|
253
|
+
required_output << [arg_name, flags]
|
254
|
+
else
|
255
|
+
optional_output[arg_name] = flags
|
256
|
+
end
|
136
257
|
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# so we should have been supplied with n_required_input values, or
|
261
|
+
# n_required_input + 1 if there's a hash of options at the end
|
262
|
+
unless supplied.is_a? Array
|
263
|
+
raise Vips::Error, "unable to call #{name}: " +
|
264
|
+
"argument array is not an array"
|
265
|
+
end
|
266
|
+
unless optional.is_a? Hash
|
267
|
+
raise Vips::Error, "unable to call #{name}: " +
|
268
|
+
"optional arguments are not a hash"
|
269
|
+
end
|
270
|
+
if supplied.length != required_input.length
|
271
|
+
raise Vips::Error, "unable to call #{name}: " +
|
272
|
+
"you supplied #{supplied.length} arguments, " +
|
273
|
+
"but operation needs #{required_input.length}."
|
274
|
+
end
|
275
|
+
|
276
|
+
# very that all supplied_optional keys are in optional_input or
|
277
|
+
# optional_output
|
278
|
+
optional.each do |key, _value|
|
279
|
+
arg_name = key.to_s
|
280
|
+
|
281
|
+
unless optional_input.has_key?(arg_name) ||
|
282
|
+
optional_output.has_key?(arg_name)
|
283
|
+
raise Vips::Error, "unable to call #{name}: " +
|
284
|
+
"unknown option #{arg_name}"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# the first image arg is the thing we expand constants to match ...
|
289
|
+
# we need to find it
|
290
|
+
#
|
291
|
+
# look inside array and hash arguments, since we may be passing an
|
292
|
+
# array of images
|
293
|
+
match_image = find_inside(supplied) do |value|
|
294
|
+
value.is_a? Image
|
295
|
+
end
|
296
|
+
|
297
|
+
# set any string args first so they can't be overridden
|
298
|
+
if option_string != nil
|
299
|
+
if Vips::vips_object_set_from_string(op, option_string) != 0
|
300
|
+
raise Vips::Error
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# set all required inputs
|
305
|
+
required_input.each_index do |i|
|
306
|
+
arg_name = required_input[i][0]
|
307
|
+
flags = required_input[i][1]
|
308
|
+
value = supplied[i]
|
309
|
+
|
310
|
+
op.set arg_name, value, match_image, flags
|
311
|
+
end
|
137
312
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
gtype = get_typeof name
|
313
|
+
# set all optional inputs
|
314
|
+
optional.each do |key, value|
|
315
|
+
next if value.nil?
|
142
316
|
|
143
|
-
|
144
|
-
value = Operation::imageize match_image, value
|
317
|
+
arg_name = key.to_s
|
145
318
|
|
146
|
-
|
147
|
-
|
148
|
-
value = value.copy.copy_memory
|
149
|
-
end
|
150
|
-
elsif gtype == ARRAY_IMAGE_TYPE
|
151
|
-
value = value.map {|x| Operation::imageize match_image, x}
|
152
|
-
end
|
319
|
+
if optional_input.has_key? arg_name
|
320
|
+
flags = optional_input[arg_name]
|
153
321
|
|
154
|
-
|
322
|
+
op.set arg_name, value, match_image, flags
|
155
323
|
end
|
324
|
+
end
|
156
325
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
# There are {Image#method_missing} hooks which will run {call} for you
|
173
|
-
# on {Image} for undefined instance or class methods. So you can also
|
174
|
-
# write:
|
175
|
-
#
|
176
|
-
# ```ruby
|
177
|
-
# out = Vips::Image.black 100, 100, bands: 12
|
178
|
-
# ```
|
179
|
-
#
|
180
|
-
# Or perhaps:
|
181
|
-
#
|
182
|
-
# ```ruby
|
183
|
-
# x = Vips::Image.black 100, 100
|
184
|
-
# y = x.invert
|
185
|
-
# ```
|
186
|
-
#
|
187
|
-
# to run the `vips_invert()` operator.
|
188
|
-
#
|
189
|
-
# There are also a set of operator overloads and some convenience
|
190
|
-
# functions, see {Image}.
|
191
|
-
#
|
192
|
-
# If the operator needs a vector constant, {call} will turn a scalar
|
193
|
-
# into a
|
194
|
-
# vector for you. So for `x.linear a, b`, which calculates
|
195
|
-
# `x * a + b` where `a` and `b` are vector constants, you can write:
|
196
|
-
#
|
197
|
-
# ```ruby
|
198
|
-
# x = Vips::Image.black 100, 100, bands: 3
|
199
|
-
# y = x.linear 1, 2
|
200
|
-
# y = x.linear [1], 4
|
201
|
-
# y = x.linear [1, 2, 3], 4
|
202
|
-
# ```
|
203
|
-
#
|
204
|
-
# or any other combination. The operator overloads use this facility to
|
205
|
-
# support all the variations on:
|
206
|
-
#
|
207
|
-
# ```ruby
|
208
|
-
# x = Vips::Image.black 100, 100, bands: 3
|
209
|
-
# y = x * 2
|
210
|
-
# y = x + [1,2,3]
|
211
|
-
# y = x % [1]
|
212
|
-
# ```
|
213
|
-
#
|
214
|
-
# Similarly, wherever an image is required, you can use a constant. The
|
215
|
-
# constant will be expanded to an image matching the first input image
|
216
|
-
# argument. For example, you can write:
|
217
|
-
#
|
218
|
-
# ```
|
219
|
-
# x = Vips::Image.black 100, 100, bands: 3
|
220
|
-
# y = x.bandjoin 255
|
221
|
-
# ```
|
222
|
-
#
|
223
|
-
# to add an extra band to the image where each pixel in the new band has
|
224
|
-
# the constant value 255.
|
225
|
-
|
226
|
-
def self.call name, supplied, optional = {}, option_string = ""
|
227
|
-
GLib::logger.debug("Vips::VipsOperation.call") {
|
228
|
-
"name = #{name}, supplied = #{supplied}, " +
|
229
|
-
"optional = #{optional}, option_string = #{option_string}"
|
230
|
-
}
|
231
|
-
|
232
|
-
op = Operation.new name
|
233
|
-
|
234
|
-
# find and classify all the arguments the operator can take
|
235
|
-
args = op.get_construct_args
|
236
|
-
required_input = []
|
237
|
-
optional_input = {}
|
238
|
-
required_output = []
|
239
|
-
optional_output = {}
|
240
|
-
args.each do |name, flags|
|
241
|
-
next if (flags & ARGUMENT_DEPRECATED) != 0
|
242
|
-
|
243
|
-
if (flags & ARGUMENT_INPUT) != 0
|
244
|
-
if (flags & ARGUMENT_REQUIRED) != 0
|
245
|
-
required_input << [name, flags]
|
246
|
-
else
|
247
|
-
optional_input[name] = flags
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
# MODIFY INPUT args count as OUTPUT as well
|
252
|
-
if (flags & ARGUMENT_OUTPUT) != 0 ||
|
253
|
-
((flags & ARGUMENT_INPUT) != 0 &&
|
254
|
-
(flags & ARGUMENT_MODIFY) != 0)
|
255
|
-
if (flags & ARGUMENT_REQUIRED) != 0
|
256
|
-
required_output << [name, flags]
|
257
|
-
else
|
258
|
-
optional_output[name] = flags
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
end
|
263
|
-
|
264
|
-
# so we should have been supplied with n_required_input values, or
|
265
|
-
# n_required_input + 1 if there's a hash of options at the end
|
266
|
-
unless supplied.is_a? Array
|
267
|
-
raise Vips::Error, "unable to call #{name}: " +
|
268
|
-
"argument array is not an array"
|
269
|
-
end
|
270
|
-
unless optional.is_a? Hash
|
271
|
-
raise Vips::Error, "unable to call #{name}: " +
|
272
|
-
"optional arguments are not a hash"
|
273
|
-
end
|
274
|
-
if supplied.length != required_input.length
|
275
|
-
raise Vips::Error, "unable to call #{name}: " +
|
276
|
-
"you supplied #{supplied.length} arguments, " +
|
277
|
-
"but operation needs #{required_input.length}."
|
278
|
-
end
|
279
|
-
|
280
|
-
# very that all supplied_optional keys are in optional_input or
|
281
|
-
# optional_output
|
282
|
-
optional.each do |key, value|
|
283
|
-
arg_name = key.to_s
|
284
|
-
|
285
|
-
unless optional_input.has_key?(arg_name) ||
|
286
|
-
optional_output.has_key?(arg_name)
|
287
|
-
raise Vips::Error, "unable to call #{name}: " +
|
288
|
-
"unknown option #{arg_name}"
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
# the first image arg is the thing we expand constants to match ...
|
293
|
-
# we need to find it
|
294
|
-
#
|
295
|
-
# look inside array and hash arguments, since we may be passing an
|
296
|
-
# array of images
|
297
|
-
match_image = find_inside(supplied) do |value|
|
298
|
-
value.is_a? Image
|
299
|
-
end
|
300
|
-
|
301
|
-
# set any string args first so they can't be overridden
|
302
|
-
if option_string != nil
|
303
|
-
if Vips::vips_object_set_from_string(op, option_string) != 0
|
304
|
-
raise Vips::Error
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
# set all required inputs
|
309
|
-
required_input.each_index do |i|
|
310
|
-
arg_name = required_input[i][0]
|
311
|
-
flags = required_input[i][1]
|
312
|
-
value = supplied[i]
|
313
|
-
|
314
|
-
op.set arg_name, value, match_image, flags
|
315
|
-
end
|
316
|
-
|
317
|
-
# set all optional inputs
|
318
|
-
optional.each do |key, value|
|
319
|
-
arg_name = key.to_s
|
320
|
-
|
321
|
-
if optional_input.has_key? arg_name
|
322
|
-
flags = optional_input[arg_name]
|
323
|
-
|
324
|
-
op.set arg_name, value, match_image, flags
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
op = op.build
|
329
|
-
|
330
|
-
# get all required results
|
331
|
-
result = []
|
332
|
-
required_output.each do |arg_name, flags|
|
333
|
-
result << op.get(arg_name)
|
334
|
-
end
|
335
|
-
|
336
|
-
# fetch all optional ones
|
337
|
-
optional_results = {}
|
338
|
-
optional.each do |key, value|
|
339
|
-
arg_name = key.to_s
|
340
|
-
|
341
|
-
if optional_output.has_key? arg_name
|
342
|
-
flags = optional_output[arg_name]
|
343
|
-
|
344
|
-
optional_results[arg_name] = op.get arg_name
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
result << optional_results if optional_results != {}
|
349
|
-
|
350
|
-
if result.length == 1
|
351
|
-
result = result.first
|
352
|
-
elsif result.length == 0
|
353
|
-
result = nil
|
354
|
-
end
|
355
|
-
|
356
|
-
GLib::logger.debug("Vips::Operation.call") {"result = #{result}"}
|
357
|
-
|
358
|
-
Vips::vips_object_unref_outputs op
|
359
|
-
|
360
|
-
return result
|
326
|
+
op = op.build
|
327
|
+
|
328
|
+
# get all required results
|
329
|
+
result = []
|
330
|
+
required_output.each do |arg_name, _flags|
|
331
|
+
result << op.get(arg_name)
|
332
|
+
end
|
333
|
+
|
334
|
+
# fetch all optional ones
|
335
|
+
optional_results = {}
|
336
|
+
optional.each do |key, _value|
|
337
|
+
arg_name = key.to_s
|
338
|
+
|
339
|
+
if optional_output.has_key? arg_name
|
340
|
+
optional_results[arg_name] = op.get arg_name
|
361
341
|
end
|
342
|
+
end
|
362
343
|
|
363
|
-
|
344
|
+
result << optional_results if optional_results != {}
|
364
345
|
|
346
|
+
if result.length == 1
|
347
|
+
result = result.first
|
348
|
+
elsif result.length == 0
|
349
|
+
result = nil
|
350
|
+
end
|
351
|
+
|
352
|
+
GLib::logger.debug("Vips::Operation.call") { "result = #{result}" }
|
353
|
+
|
354
|
+
Vips::vips_object_unref_outputs op
|
355
|
+
|
356
|
+
return result
|
357
|
+
end
|
358
|
+
end
|
365
359
|
end
|