ruby-vips 2.0.15 → 2.1.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/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- data/.github/workflows/test.yml +80 -0
- data/.standard.yml +17 -0
- data/.yardopts +0 -1
- data/CHANGELOG.md +39 -0
- data/Gemfile +3 -1
- data/README.md +42 -41
- data/Rakefile +13 -21
- data/TODO +14 -14
- data/VERSION +1 -1
- data/example/annotate.rb +6 -6
- data/example/connection.rb +26 -0
- data/example/daltonize8.rb +6 -6
- data/example/draw_lines.rb +30 -0
- data/example/example1.rb +4 -4
- data/example/example2.rb +6 -6
- data/example/example3.rb +5 -5
- data/example/example4.rb +2 -2
- data/example/example5.rb +4 -4
- data/example/inheritance_with_refcount.rb +35 -36
- data/example/progress.rb +30 -0
- data/example/thumb.rb +6 -6
- data/example/trim8.rb +1 -1
- data/example/watermark.rb +2 -2
- data/example/wobble.rb +1 -1
- data/lib/ruby-vips.rb +1 -1
- data/lib/vips.rb +191 -79
- data/lib/vips/blend_mode.rb +29 -25
- data/lib/vips/connection.rb +46 -0
- data/lib/vips/gobject.rb +27 -12
- data/lib/vips/gvalue.rb +62 -50
- data/lib/vips/image.rb +475 -256
- data/lib/vips/interpolate.rb +3 -2
- data/lib/vips/methods.rb +788 -121
- data/lib/vips/mutableimage.rb +173 -0
- data/lib/vips/object.rb +171 -54
- data/lib/vips/operation.rb +272 -117
- data/lib/vips/region.rb +73 -0
- data/lib/vips/source.rb +88 -0
- data/lib/vips/sourcecustom.rb +89 -0
- data/lib/vips/target.rb +86 -0
- data/lib/vips/targetcustom.rb +77 -0
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +26 -20
- metadata +39 -50
- data/.rubocop.yml +0 -22
- data/.rubocop_todo.yml +0 -515
- data/.travis.yml +0 -62
- data/install-vips.sh +0 -26
data/lib/vips/blend_mode.rb
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
module Vips
|
2
2
|
# Blend mode to use when compositing images. See {Image#composite}.
|
3
3
|
#
|
4
|
-
# `:clear`
|
5
|
-
# `:source`
|
6
|
-
# `:over`
|
7
|
-
#
|
8
|
-
# `:
|
9
|
-
#
|
10
|
-
# `:
|
11
|
-
# `:
|
12
|
-
#
|
13
|
-
# `:
|
14
|
-
#
|
15
|
-
# `:
|
16
|
-
# `:
|
17
|
-
# `:
|
18
|
-
# `:
|
19
|
-
# `:
|
20
|
-
# `:
|
21
|
-
# `:
|
22
|
-
# `:
|
23
|
-
# `:
|
24
|
-
# `:
|
25
|
-
# `:
|
26
|
-
# `:
|
27
|
-
# `:
|
28
|
-
# `:
|
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
|
8
|
-
require
|
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
|
-
|
46
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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, [
|
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
|
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
|
-
|
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
|
-
|
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
|
42
|
-
if enum_name
|
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
|
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
|
-
|
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
|
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
|
93
|
+
fundamental = ::GObject.g_type_fundamental gtype
|
90
94
|
|
91
95
|
case gtype
|
92
96
|
when GBOOL_TYPE
|
93
|
-
::GObject
|
97
|
+
::GObject.g_value_set_boolean self, (value ? 1 : 0)
|
94
98
|
|
95
99
|
when GINT_TYPE
|
96
|
-
::GObject
|
100
|
+
::GObject.g_value_set_int self, value
|
97
101
|
|
98
102
|
when GUINT64_TYPE
|
99
|
-
::GObject
|
103
|
+
::GObject.g_value_set_uint64 self, value
|
100
104
|
|
101
105
|
when GDOUBLE_TYPE
|
102
|
-
::GObject
|
106
|
+
::GObject.g_value_set_double self, value
|
103
107
|
|
104
108
|
when GSTR_TYPE
|
105
|
-
::GObject
|
109
|
+
::GObject.g_value_set_string self, value
|
106
110
|
|
107
111
|
when Vips::REFSTR_TYPE
|
108
|
-
::Vips
|
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
|
114
|
-
ptr = Vips
|
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
|
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
|
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
|
132
|
-
ptr = Vips
|
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
|
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
|
141
|
-
Vips
|
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
|
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
|
155
|
+
::GObject.g_value_set_enum self, enum_value
|
152
156
|
|
153
157
|
when GOBJECT_TYPE
|
154
|
-
::GObject
|
158
|
+
::GObject.g_value_set_object self, value
|
155
159
|
|
156
160
|
else
|
157
|
-
raise Vips::Error, "unimplemented gtype for set: "
|
158
|
-
|
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
|
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
|
178
|
+
result = ::GObject.g_value_get_boolean(self) != 0
|
175
179
|
|
176
180
|
when GINT_TYPE
|
177
|
-
result = ::GObject
|
181
|
+
result = ::GObject.g_value_get_int self
|
178
182
|
|
179
183
|
when GUINT64_TYPE
|
180
|
-
result = ::GObject
|
184
|
+
result = ::GObject.g_value_get_uint64 self
|
181
185
|
|
182
186
|
when GDOUBLE_TYPE
|
183
|
-
result = ::GObject
|
187
|
+
result = ::GObject.g_value_get_double self
|
184
188
|
|
185
189
|
when GSTR_TYPE
|
186
|
-
result = ::GObject
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
223
|
+
result = ::GObject.g_value_get_flags self
|
220
224
|
|
221
225
|
when GENUM_TYPE
|
222
|
-
enum_value = ::GObject
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
284
|
+
[:pointer, :string, GValue.ptr], :void
|
273
285
|
attach_function :g_object_get_property,
|
274
|
-
|
286
|
+
[:pointer, :string, GValue.ptr], :void
|
275
287
|
end
|