vips 8.6.3

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +47 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +4 -0
  6. data/README.md +64 -0
  7. data/Rakefile +28 -0
  8. data/example/annotate.rb +17 -0
  9. data/example/daltonize8.rb +75 -0
  10. data/example/example1.rb +12 -0
  11. data/example/example2.rb +34 -0
  12. data/example/example3.rb +19 -0
  13. data/example/example4.rb +18 -0
  14. data/example/example5.rb +31 -0
  15. data/example/inheritance_with_refcount.rb +286 -0
  16. data/example/thumb.rb +31 -0
  17. data/example/trim8.rb +41 -0
  18. data/example/watermark.rb +44 -0
  19. data/example/wobble.rb +36 -0
  20. data/ext/Rakefile +35 -0
  21. data/lib/vips.rb +597 -0
  22. data/lib/vips/access.rb +11 -0
  23. data/lib/vips/align.rb +11 -0
  24. data/lib/vips/angle.rb +12 -0
  25. data/lib/vips/angle45.rb +16 -0
  26. data/lib/vips/bandformat.rb +20 -0
  27. data/lib/vips/coding.rb +14 -0
  28. data/lib/vips/compass_direction.rb +17 -0
  29. data/lib/vips/direction.rb +11 -0
  30. data/lib/vips/extend.rb +17 -0
  31. data/lib/vips/gobject.rb +122 -0
  32. data/lib/vips/gvalue.rb +281 -0
  33. data/lib/vips/image.rb +1500 -0
  34. data/lib/vips/interesting.rb +14 -0
  35. data/lib/vips/interpolate.rb +62 -0
  36. data/lib/vips/interpretation.rb +28 -0
  37. data/lib/vips/kernel.rb +22 -0
  38. data/lib/vips/methods.rb +2145 -0
  39. data/lib/vips/object.rb +244 -0
  40. data/lib/vips/operation.rb +365 -0
  41. data/lib/vips/operationboolean.rb +14 -0
  42. data/lib/vips/operationcomplex.rb +12 -0
  43. data/lib/vips/operationcomplex2.rb +10 -0
  44. data/lib/vips/operationcomplexget.rb +11 -0
  45. data/lib/vips/operationmath.rb +18 -0
  46. data/lib/vips/operationmath2.rb +10 -0
  47. data/lib/vips/operationrelational.rb +15 -0
  48. data/lib/vips/operationround.rb +11 -0
  49. data/lib/vips/size.rb +13 -0
  50. data/lib/vips/version.rb +4 -0
  51. data/vips.gemspec +36 -0
  52. metadata +209 -0
@@ -0,0 +1,244 @@
1
+ # This module provides an interface to the top level bits of libvips
2
+ # via ruby-ffi.
3
+ #
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require 'ffi'
8
+
9
+ module Vips
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
+
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
+
173
+ end
174
+
175
+ class ObjectClass < FFI::Struct
176
+ # opaque
177
+ end
178
+
179
+ class Argument < FFI::Struct
180
+ layout :pspec, GObject::GParamSpec.ptr
181
+ end
182
+
183
+ class ArgumentInstance < Argument
184
+ layout :parent, Argument
185
+ # rest opaque
186
+ end
187
+
188
+ # enum VipsArgumentFlags
189
+ ARGUMENT_REQUIRED = 1
190
+ ARGUMENT_CONSTRUCT = 2
191
+ ARGUMENT_SET_ONCE = 4
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
216
+
217
+ class ArgumentClassPtr < FFI::Struct
218
+ layout :value, ArgumentClass.ptr
219
+ end
220
+
221
+ class ArgumentInstancePtr < FFI::Struct
222
+ layout :value, ArgumentInstance.ptr
223
+ end
224
+
225
+ # just use :pointer, not VipsObject.ptr, to avoid casting gobject
226
+ # subclasses
227
+ attach_function :vips_object_get_argument,
228
+ [:pointer, :string,
229
+ GObject::GParamSpecPtr.ptr,
230
+ ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
231
+ :int
232
+
233
+ attach_function :vips_object_print_all, [], :void
234
+
235
+ attach_function :vips_object_set_from_string, [:pointer, :string], :int
236
+
237
+ callback :type_map_fn, [:GType, :pointer], :pointer
238
+ attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
239
+
240
+ attach_function :vips_object_get_description, [:pointer], :string
241
+
242
+ end
243
+
244
+
@@ -0,0 +1,365 @@
1
+ # This module provides an interface to the top level bits of libvips
2
+ # via ruby-ffi.
3
+ #
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require 'ffi'
8
+
9
+ module Vips
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
+
40
+ # the layout of the VipsOperation struct
41
+ module OperationLayout
42
+ def self.included base
43
+ base.class_eval do
44
+ layout :parent, Object::Struct
45
+ # rest opaque
46
+ end
47
+ end
48
+ end
49
+
50
+ class Struct < Object::Struct
51
+ include OperationLayout
52
+
53
+ end
54
+
55
+ class ManagedStruct < Object::ManagedStruct
56
+ include OperationLayout
57
+
58
+ end
59
+
60
+ def initialize value
61
+ # allow init with a pointer so we can wrap the return values from
62
+ # things like _build
63
+ if value.is_a? String
64
+ value = Vips::vips_operation_new value
65
+ raise Vips::Error if value == nil
66
+ end
67
+
68
+ super value
69
+ end
70
+
71
+ def build
72
+ op = Vips::vips_cache_operation_build self
73
+ if op == nil
74
+ raise Vips::Error
75
+ end
76
+
77
+ return Operation.new op
78
+ end
79
+
80
+ def argument_map &block
81
+ fn = Proc.new do |op, pspec, argument_class, argument_instance, a, b|
82
+ block.call pspec, argument_class, argument_instance
83
+ end
84
+
85
+ Vips::vips_argument_map self, fn, nil, nil
86
+ end
87
+
88
+ def get_flags
89
+ Vips::vips_operation_get_flags self
90
+ end
91
+
92
+ # not quick! try to call this infrequently
93
+ def get_construct_args
94
+ args = []
95
+
96
+ argument_map do |pspec, argument_class, argument_instance|
97
+ flags = argument_class[:flags]
98
+ if (flags & ARGUMENT_CONSTRUCT) != 0
99
+ # names can include - as punctuation, but we always use _ in
100
+ # Ruby
101
+ name = pspec[:name].tr("-", "_")
102
+
103
+ args << [name, flags]
104
+ end
105
+ end
106
+
107
+ return args
108
+ end
109
+
110
+ # search array for the first element to match a predicate ...
111
+ # search inside subarrays and sub-hashes
112
+ def self.find_inside object, &block
113
+ return object if block.call object
114
+
115
+ if object.is_a? Enumerable
116
+ object.find {|value| block.call value, block}
117
+ end
118
+
119
+ return nil
120
+ end
121
+
122
+ # expand a constant into an image
123
+ def self.imageize match_image, value
124
+ return value if value.is_a? Image
125
+
126
+ # 2D array values become tiny 2D images
127
+ # if there's nothing to match to, we also make a 2D image
128
+ if (value.is_a?(Array) && value[0].is_a?(Array)) ||
129
+ match_image == nil
130
+ return Image.new_from_array value
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
136
+ end
137
+
138
+ # set an operation argument, expanding constants and copying images as
139
+ # required
140
+ def set name, value, match_image = nil, flags = 0
141
+ gtype = get_typeof name
142
+
143
+ if gtype == IMAGE_TYPE
144
+ value = Operation::imageize match_image, value
145
+
146
+ if (flags & ARGUMENT_MODIFY) != 0
147
+ # make sure we have a unique copy
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
153
+
154
+ super name, value
155
+ end
156
+
157
+ public
158
+
159
+ # This is the public entry point for the vips binding. {call} will run
160
+ # any vips operation, for example:
161
+ #
162
+ # ```ruby
163
+ # out = Vips::Operation.call "black", [100, 100], {:bands => 12}
164
+ # ```
165
+ #
166
+ # will call the C function
167
+ #
168
+ # ```C
169
+ # vips_black( &out, 100, 100, "bands", 12, NULL );
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
361
+ end
362
+
363
+ end
364
+
365
+ end