ruby-vips 2.0.15 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/workflows/test.yml +80 -0
  4. data/.standard.yml +17 -0
  5. data/.yardopts +0 -1
  6. data/CHANGELOG.md +39 -0
  7. data/Gemfile +3 -1
  8. data/README.md +42 -41
  9. data/Rakefile +13 -21
  10. data/TODO +14 -14
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +6 -6
  13. data/example/connection.rb +26 -0
  14. data/example/daltonize8.rb +6 -6
  15. data/example/draw_lines.rb +30 -0
  16. data/example/example1.rb +4 -4
  17. data/example/example2.rb +6 -6
  18. data/example/example3.rb +5 -5
  19. data/example/example4.rb +2 -2
  20. data/example/example5.rb +4 -4
  21. data/example/inheritance_with_refcount.rb +35 -36
  22. data/example/progress.rb +30 -0
  23. data/example/thumb.rb +6 -6
  24. data/example/trim8.rb +1 -1
  25. data/example/watermark.rb +2 -2
  26. data/example/wobble.rb +1 -1
  27. data/lib/ruby-vips.rb +1 -1
  28. data/lib/vips.rb +191 -79
  29. data/lib/vips/blend_mode.rb +29 -25
  30. data/lib/vips/connection.rb +46 -0
  31. data/lib/vips/gobject.rb +27 -12
  32. data/lib/vips/gvalue.rb +62 -50
  33. data/lib/vips/image.rb +475 -256
  34. data/lib/vips/interpolate.rb +3 -2
  35. data/lib/vips/methods.rb +788 -121
  36. data/lib/vips/mutableimage.rb +173 -0
  37. data/lib/vips/object.rb +171 -54
  38. data/lib/vips/operation.rb +272 -117
  39. data/lib/vips/region.rb +73 -0
  40. data/lib/vips/source.rb +88 -0
  41. data/lib/vips/sourcecustom.rb +89 -0
  42. data/lib/vips/target.rb +86 -0
  43. data/lib/vips/targetcustom.rb +77 -0
  44. data/lib/vips/version.rb +1 -1
  45. data/ruby-vips.gemspec +26 -20
  46. metadata +39 -50
  47. data/.rubocop.yml +0 -22
  48. data/.rubocop_todo.yml +0 -515
  49. data/.travis.yml +0 -62
  50. data/install-vips.sh +0 -26
@@ -1,31 +1,35 @@
1
1
  module Vips
2
2
  # Blend mode to use when compositing images. See {Image#composite}.
3
3
  #
4
- # `:clear` - where the second object is drawn, the first is removed
5
- # `:source` - the second object is drawn as if nothing were below
6
- # `:over` - the image shows what you would expect if you held two semi-transparent slides on top of each other
7
- # `:in` - the first object is removed completely, the second is only drawn where the first was
8
- # `:out` - the second is drawn only where the first isn't
9
- # `:atop` - this leaves the first object mostly intact, but mixes both objects in the overlapping area
10
- # `:dest` - leaves the first object untouched, the second is discarded completely
11
- # `:dest_over` - like `:over`, but swaps the arguments
12
- # `:dest_in` - like `:in`, but swaps the arguments
13
- # `:dest_out` - like `:out`, but swaps the arguments
14
- # `:dest_atop` - like `:atop`, but swaps the arguments
15
- # `:xor` - something like a difference operator
16
- # `:add` - a bit like adding the two images
17
- # `:saturate` - a bit like the darker of the two
18
- # `:multiply` - at least as dark as the darker of the two inputs
19
- # `:screen` - at least as light as the lighter of the inputs
20
- # `:overlay` - multiplies or screens colors, depending on the lightness
21
- # `:darken` - the darker of each component
22
- # `:lighten` - the lighter of each component
23
- # `:colour_dodge` - brighten first by a factor second
24
- # `:colour_burn` - darken first by a factor of second
25
- # `:hard_light` - multiply or screen, depending on lightness
26
- # `:soft_light` - darken or lighten, depending on lightness
27
- # `:difference` - difference of the two
28
- # `:exclusion` - somewhat like `:difference`, but lower-contrast
4
+ # * `:clear` where the second object is drawn, the first is removed
5
+ # * `:source` the second object is drawn as if nothing were below
6
+ # * `:over` the image shows what you would expect if you held two
7
+ # semi-transparent slides on top of each other
8
+ # * `:in` the first object is removed completely, the second is only
9
+ # drawn where the first was
10
+ # * `:out` the second is drawn only where the first isn't
11
+ # * `:atop` this leaves the first object mostly intact, but mixes both
12
+ # objects in the overlapping area
13
+ # * `:dest` leaves the first object untouched, the second is discarded
14
+ # completely
15
+ # * `:dest_over` like `:over`, but swaps the arguments
16
+ # * `:dest_in` like `:in`, but swaps the arguments
17
+ # * `:dest_out` like `:out`, but swaps the arguments
18
+ # * `:dest_atop` like `:atop`, but swaps the arguments
19
+ # * `:xor` something like a difference operator
20
+ # * `:add` a bit like adding the two images
21
+ # * `:saturate` a bit like the darker of the two
22
+ # * `:multiply` at least as dark as the darker of the two inputs
23
+ # * `:screen` at least as light as the lighter of the inputs
24
+ # * `:overlay` multiplies or screens colors, depending on the lightness
25
+ # * `:darken` the darker of each component
26
+ # * `:lighten` the lighter of each component
27
+ # * `:colour_dodge` brighten first by a factor second
28
+ # * `:colour_burn` darken first by a factor of second
29
+ # * `:hard_light` multiply or screen, depending on lightness
30
+ # * `:soft_light` darken or lighten, depending on lightness
31
+ # * `:difference` difference of the two
32
+ # * `:exclusion` somewhat like `:difference`, but lower-contrast
29
33
 
30
34
  class BlendMode < Symbol
31
35
  end
@@ -0,0 +1,46 @@
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
+ if Vips.at_least_libvips?(8, 9)
11
+ attach_function :vips_connection_filename, [:pointer], :string
12
+ attach_function :vips_connection_nick, [:pointer], :string
13
+ end
14
+
15
+ # Abstract base class for connections.
16
+ class Connection < Vips::Object
17
+ # The layout of the VipsRegion struct.
18
+ module ConnectionLayout
19
+ def self.included(base)
20
+ base.class_eval do
21
+ layout :parent, Vips::Object::Struct
22
+ # rest opaque
23
+ end
24
+ end
25
+ end
26
+
27
+ class Struct < Vips::Object::Struct
28
+ include ConnectionLayout
29
+ end
30
+
31
+ class ManagedStruct < Vips::Object::ManagedStruct
32
+ include ConnectionLayout
33
+ end
34
+
35
+ # Get any filename associated with a connection, or nil.
36
+ def filename
37
+ Vips.vips_connection_filename self
38
+ end
39
+
40
+ # Get a nickname (short description) of a connection that could be shown to
41
+ # the user.
42
+ def nick
43
+ Vips.vips_connection_nick self
44
+ end
45
+ end
46
+ end
data/lib/vips/gobject.rb CHANGED
@@ -4,8 +4,8 @@
4
4
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
5
  # License:: MIT
6
6
 
7
- require 'ffi'
8
- require 'forwardable'
7
+ require "ffi"
8
+ require "forwardable"
9
9
 
10
10
  module GObject
11
11
  # we have a number of things we need to inherit in different ways:
@@ -37,13 +37,15 @@ module GObject
37
37
  def_instance_delegators :@struct, :[], :to_ptr
38
38
  def_single_delegators :ffi_struct, :ptr
39
39
 
40
+ attr_reader :references
41
+
40
42
  # the layout of the GObject struct
41
43
  module GObjectLayout
42
44
  def self.included base
43
45
  base.class_eval do
44
46
  layout :g_type_instance, :pointer,
45
- :ref_count, :uint,
46
- :qdata, :pointer
47
+ :ref_count, :uint,
48
+ :qdata, :pointer
47
49
  end
48
50
  end
49
51
  end
@@ -56,7 +58,7 @@ module GObject
56
58
  # GLib::logger.debug("GObject::GObject::ManagedStruct.release") {
57
59
  # "unreffing #{ptr}"
58
60
  # }
59
- ::GObject::g_object_unref ptr
61
+ ::GObject.g_object_unref ptr
60
62
  end
61
63
  end
62
64
 
@@ -72,7 +74,11 @@ module GObject
72
74
  # need the unref
73
75
  def initialize ptr
74
76
  # GLib::logger.debug("GObject::GObject.initialize") {"ptr = #{ptr}"}
77
+ @ptr = ptr
75
78
  @struct = ffi_managed_struct.new ptr
79
+
80
+ # sometimes we need to keep refs across C calls ... hide them here
81
+ @references = []
76
82
  end
77
83
 
78
84
  # access to the casting struct for this class
@@ -80,9 +86,13 @@ module GObject
80
86
  self.class.ffi_struct
81
87
  end
82
88
 
89
+ # get the pointer we were built from ... #to_ptr gets the pointer after we
90
+ # have wrapped it up with an auto unref
91
+ attr_reader :ptr
92
+
83
93
  class << self
84
94
  def ffi_struct
85
- self.const_get :Struct
95
+ const_get :Struct
86
96
  end
87
97
  end
88
98
 
@@ -93,7 +103,7 @@ module GObject
93
103
 
94
104
  class << self
95
105
  def ffi_managed_struct
96
- self.const_get :ManagedStruct
106
+ const_get :ManagedStruct
97
107
  end
98
108
  end
99
109
  end
@@ -101,18 +111,23 @@ module GObject
101
111
  class GParamSpec < FFI::Struct
102
112
  # the first few public fields
103
113
  layout :g_type_instance, :pointer,
104
- :name, :string,
105
- :flags, :uint,
106
- :value_type, :GType,
107
- :owner_type, :GType
114
+ :name, :string,
115
+ :flags, :uint,
116
+ :value_type, :GType,
117
+ :owner_type, :GType
108
118
  end
109
119
 
110
120
  class GParamSpecPtr < FFI::Struct
111
121
  layout :value, GParamSpec.ptr
112
122
  end
113
123
 
114
- attach_function :g_param_spec_get_blurb, [GParamSpec.ptr], :string
124
+ attach_function :g_param_spec_get_blurb, [:pointer], :string
115
125
 
116
126
  attach_function :g_object_ref, [:pointer], :void
117
127
  attach_function :g_object_unref, [:pointer], :void
128
+
129
+ # we just use one gcallback type for every signal, hopefully this is OK
130
+ callback :gcallback, [:pointer], :void
131
+ attach_function :g_signal_connect_data,
132
+ [:pointer, :string, :gcallback, :pointer, :pointer, :int], :long
118
133
  end
data/lib/vips/gvalue.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
4
4
  # License:: MIT
5
5
 
6
- require 'ffi'
6
+ require "ffi"
7
7
 
8
8
  module GObject
9
9
  # Represent a GValue. Example use:
@@ -13,6 +13,8 @@ module GObject
13
13
  # gvalue.init GObject::GDOUBLE_TYPE
14
14
  # gvalue.set 3.1415
15
15
  # value = gvalue.get
16
+ # # optional -- drop any ref the gvalue had
17
+ # gvalue.unset
16
18
  # ```
17
19
  #
18
20
  # Lifetime is managed automatically. It doesn't know about all GType values,
@@ -20,14 +22,16 @@ module GObject
20
22
 
21
23
  class GValue < FFI::ManagedStruct
22
24
  layout :gtype, :GType,
23
- :data, [:ulong_long, 2]
25
+ :data, [:ulong_long, 2]
24
26
 
25
27
  # convert an enum value (str/symb/int) into an int ready for libvips
26
28
  def self.from_nick(gtype, value)
27
29
  value = value.to_s if value.is_a? Symbol
28
30
 
29
31
  if value.is_a? String
30
- value = Vips::vips_enum_from_nick "ruby-vips", gtype, value
32
+ # libvips expects "-" as a separator in enum names, but "_" is more
33
+ # convenient for ruby, eg. :b_w
34
+ value = Vips.vips_enum_from_nick "ruby-vips", gtype, value.tr("_", "-")
31
35
  if value == -1
32
36
  raise Vips::Error
33
37
  end
@@ -38,8 +42,8 @@ module GObject
38
42
 
39
43
  # convert an int enum back into a symbol
40
44
  def self.to_nick(gtype, enum_value)
41
- enum_name = Vips::vips_enum_nick gtype, enum_value
42
- if enum_name == nil
45
+ enum_name = Vips.vips_enum_nick gtype, enum_value
46
+ if enum_name.nil?
43
47
  raise Vips::Error
44
48
  end
45
49
 
@@ -48,7 +52,7 @@ module GObject
48
52
 
49
53
  def self.release ptr
50
54
  # GLib::logger.debug("GObject::GValue::release") {"ptr = #{ptr}"}
51
- ::GObject::g_value_unset ptr
55
+ ::GObject.g_value_unset ptr
52
56
  end
53
57
 
54
58
  # Allocate memory for a GValue and return a class wrapper. Memory will
@@ -66,14 +70,14 @@ module GObject
66
70
  pointer = FFI::Pointer.new GValue, memory
67
71
 
68
72
  # ... and wrap in a GValue
69
- return GValue.new pointer
73
+ GValue.new pointer
70
74
  end
71
75
 
72
76
  # Set the type of thing a gvalue can hold.
73
77
  #
74
78
  # @param gtype [GType] the type of thing this GValue can hold.
75
79
  def init gtype
76
- ::GObject::g_value_init self, gtype
80
+ ::GObject.g_value_init self, gtype
77
81
  end
78
82
 
79
83
  # Set the value of a GValue. The value is converted to the type of the
@@ -86,76 +90,76 @@ module GObject
86
90
  # }
87
91
 
88
92
  gtype = self[:gtype]
89
- fundamental = ::GObject::g_type_fundamental gtype
93
+ fundamental = ::GObject.g_type_fundamental gtype
90
94
 
91
95
  case gtype
92
96
  when GBOOL_TYPE
93
- ::GObject::g_value_set_boolean self, (value ? 1 : 0)
97
+ ::GObject.g_value_set_boolean self, (value ? 1 : 0)
94
98
 
95
99
  when GINT_TYPE
96
- ::GObject::g_value_set_int self, value
100
+ ::GObject.g_value_set_int self, value
97
101
 
98
102
  when GUINT64_TYPE
99
- ::GObject::g_value_set_uint64 self, value
103
+ ::GObject.g_value_set_uint64 self, value
100
104
 
101
105
  when GDOUBLE_TYPE
102
- ::GObject::g_value_set_double self, value
106
+ ::GObject.g_value_set_double self, value
103
107
 
104
108
  when GSTR_TYPE
105
- ::GObject::g_value_set_string self, value
109
+ ::GObject.g_value_set_string self, value
106
110
 
107
111
  when Vips::REFSTR_TYPE
108
- ::Vips::vips_value_set_ref_string self, value
112
+ ::Vips.vips_value_set_ref_string self, value
109
113
 
110
114
  when Vips::ARRAY_INT_TYPE
111
115
  value = [value] unless value.is_a? Array
112
116
 
113
- Vips::vips_value_set_array_int self, nil, value.length
114
- ptr = Vips::vips_value_get_array_int self, nil
117
+ Vips.vips_value_set_array_int self, nil, value.length
118
+ ptr = Vips.vips_value_get_array_int self, nil
115
119
  ptr.write_array_of_int32 value
116
120
 
117
121
  when Vips::ARRAY_DOUBLE_TYPE
118
122
  value = [value] unless value.is_a? Array
119
123
 
120
124
  # this will allocate an array in the gvalue
121
- Vips::vips_value_set_array_double self, nil, value.length
125
+ Vips.vips_value_set_array_double self, nil, value.length
122
126
 
123
127
  # pull the array out and fill it
124
- ptr = Vips::vips_value_get_array_double self, nil
128
+ ptr = Vips.vips_value_get_array_double self, nil
125
129
 
126
130
  ptr.write_array_of_double value
127
131
 
128
132
  when Vips::ARRAY_IMAGE_TYPE
129
133
  value = [value] unless value.is_a? Array
130
134
 
131
- Vips::vips_value_set_array_image self, value.length
132
- ptr = Vips::vips_value_get_array_image self, nil
135
+ Vips.vips_value_set_array_image self, value.length
136
+ ptr = Vips.vips_value_get_array_image self, nil
133
137
  ptr.write_array_of_pointer value
134
138
 
135
139
  # the gvalue needs a ref on each of the images
136
- value.each { |image| ::GObject::g_object_ref image }
140
+ value.each { |image| ::GObject.g_object_ref image }
137
141
 
138
142
  when Vips::BLOB_TYPE
139
143
  len = value.bytesize
140
- ptr = GLib::g_malloc len
141
- Vips::vips_value_set_blob self, GLib::G_FREE, ptr, len
144
+ ptr = GLib.g_malloc len
145
+ Vips.vips_value_set_blob self, GLib::G_FREE, ptr, len
142
146
  ptr.write_bytes value
143
147
 
144
148
  else
145
149
  case fundamental
146
150
  when GFLAGS_TYPE
147
- ::GObject::g_value_set_flags self, value
151
+ ::GObject.g_value_set_flags self, value
148
152
 
149
153
  when GENUM_TYPE
150
154
  enum_value = GValue.from_nick(self[:gtype], value)
151
- ::GObject::g_value_set_enum self, enum_value
155
+ ::GObject.g_value_set_enum self, enum_value
152
156
 
153
157
  when GOBJECT_TYPE
154
- ::GObject::g_value_set_object self, value
158
+ ::GObject.g_value_set_object self, value
155
159
 
156
160
  else
157
- raise Vips::Error, "unimplemented gtype for set: " +
158
- "#{::GObject::g_type_name gtype} (#{gtype})"
161
+ raise Vips::Error, "unimplemented gtype for set: " \
162
+ "#{::GObject.g_type_name gtype} (#{gtype})"
159
163
  end
160
164
  end
161
165
  end
@@ -166,72 +170,72 @@ module GObject
166
170
  # @return [Any] the value held by the GValue
167
171
  def get
168
172
  gtype = self[:gtype]
169
- fundamental = ::GObject::g_type_fundamental gtype
173
+ fundamental = ::GObject.g_type_fundamental gtype
170
174
  result = nil
171
175
 
172
176
  case gtype
173
177
  when GBOOL_TYPE
174
- result = ::GObject::g_value_get_boolean(self) != 0 ? true : false
178
+ result = ::GObject.g_value_get_boolean(self) != 0
175
179
 
176
180
  when GINT_TYPE
177
- result = ::GObject::g_value_get_int self
181
+ result = ::GObject.g_value_get_int self
178
182
 
179
183
  when GUINT64_TYPE
180
- result = ::GObject::g_value_get_uint64 self
184
+ result = ::GObject.g_value_get_uint64 self
181
185
 
182
186
  when GDOUBLE_TYPE
183
- result = ::GObject::g_value_get_double self
187
+ result = ::GObject.g_value_get_double self
184
188
 
185
189
  when GSTR_TYPE
186
- result = ::GObject::g_value_get_string self
190
+ result = ::GObject.g_value_get_string self
187
191
 
188
192
  when Vips::REFSTR_TYPE
189
193
  len = Vips::SizeStruct.new
190
- result = ::Vips::vips_value_get_ref_string self, len
194
+ result = ::Vips.vips_value_get_ref_string self, len
191
195
 
192
196
  when Vips::ARRAY_INT_TYPE
193
197
  len = Vips::IntStruct.new
194
- array = Vips::vips_value_get_array_int self, len
198
+ array = Vips.vips_value_get_array_int self, len
195
199
  result = array.get_array_of_int32 0, len[:value]
196
200
 
197
201
  when Vips::ARRAY_DOUBLE_TYPE
198
202
  len = Vips::IntStruct.new
199
- array = Vips::vips_value_get_array_double self, len
203
+ array = Vips.vips_value_get_array_double self, len
200
204
  result = array.get_array_of_double 0, len[:value]
201
205
 
202
206
  when Vips::ARRAY_IMAGE_TYPE
203
207
  len = Vips::IntStruct.new
204
- array = Vips::vips_value_get_array_image self, len
208
+ array = Vips.vips_value_get_array_image self, len
205
209
  result = array.get_array_of_pointer 0, len[:value]
206
210
  result.map! do |pointer|
207
- ::GObject::g_object_ref pointer
211
+ ::GObject.g_object_ref pointer
208
212
  Vips::Image.new pointer
209
213
  end
210
214
 
211
215
  when Vips::BLOB_TYPE
212
216
  len = Vips::SizeStruct.new
213
- array = Vips::vips_value_get_blob self, len
217
+ array = Vips.vips_value_get_blob self, len
214
218
  result = array.get_bytes 0, len[:value]
215
219
 
216
220
  else
217
221
  case fundamental
218
222
  when GFLAGS_TYPE
219
- result = ::GObject::g_value_get_flags self
223
+ result = ::GObject.g_value_get_flags self
220
224
 
221
225
  when GENUM_TYPE
222
- enum_value = ::GObject::g_value_get_enum(self)
226
+ enum_value = ::GObject.g_value_get_enum(self)
223
227
  result = GValue.to_nick self[:gtype], enum_value
224
228
 
225
229
  when GOBJECT_TYPE
226
- obj = ::GObject::g_value_get_object self
230
+ obj = ::GObject.g_value_get_object self
227
231
  # g_value_get_object() does not add a ref ... we need to add
228
232
  # one to match the unref in gobject release
229
- ::GObject::g_object_ref obj
233
+ ::GObject.g_object_ref obj
230
234
  result = Vips::Image.new obj
231
235
 
232
236
  else
233
- raise Vips::Error, "unimplemented gtype for get: " +
234
- "#{::GObject::g_type_name gtype} (#{gtype})"
237
+ raise Vips::Error, "unimplemented gtype for get: " \
238
+ "#{::GObject.g_type_name gtype} (#{gtype})"
235
239
  end
236
240
  end
237
241
 
@@ -239,7 +243,15 @@ module GObject
239
243
  # "result = #{result.inspect[0..50]}"
240
244
  # }
241
245
 
242
- return result
246
+ result
247
+ end
248
+
249
+ # Clear the thing held by a GValue.
250
+ #
251
+ # This happens automatically when a GValue is GCed, but this method can be
252
+ # handy if you need to drop a reference explicitly for some reason.
253
+ def unset
254
+ ::GObject.g_value_unset self
243
255
  end
244
256
  end
245
257
 
@@ -269,7 +281,7 @@ module GObject
269
281
 
270
282
  # use :pointer rather than GObject.ptr to avoid casting later
271
283
  attach_function :g_object_set_property,
272
- [:pointer, :string, GValue.ptr], :void
284
+ [:pointer, :string, GValue.ptr], :void
273
285
  attach_function :g_object_get_property,
274
- [:pointer, :string, GValue.ptr], :void
286
+ [:pointer, :string, GValue.ptr], :void
275
287
  end