ruby-vips 2.0.17 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +13 -0
- data/Gemfile +3 -1
- data/README.md +4 -4
- data/Rakefile +13 -21
- data/TODO +3 -6
- data/VERSION +1 -1
- data/example/annotate.rb +6 -6
- data/example/connection.rb +18 -9
- 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 +3 -3
- 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 +121 -75
- data/lib/vips/blend_mode.rb +29 -25
- data/lib/vips/connection.rb +4 -4
- data/lib/vips/gobject.rb +18 -11
- data/lib/vips/gvalue.rb +54 -54
- data/lib/vips/image.rb +232 -155
- data/lib/vips/interpolate.rb +3 -2
- data/lib/vips/methods.rb +165 -15
- data/lib/vips/mutableimage.rb +154 -0
- data/lib/vips/object.rb +84 -85
- data/lib/vips/operation.rb +161 -82
- data/lib/vips/region.rb +6 -6
- data/lib/vips/source.rb +11 -12
- data/lib/vips/sourcecustom.rb +7 -8
- data/lib/vips/target.rb +12 -13
- data/lib/vips/targetcustom.rb +9 -10
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +26 -22
- metadata +28 -48
- data/.rubocop.yml +0 -22
- data/.rubocop_todo.yml +0 -473
- data/.travis.yml +0 -57
- data/install-vips.sh +0 -26
@@ -0,0 +1,154 @@
|
|
1
|
+
# This module provides an interface to the vips image processing library
|
2
|
+
# via ruby-ffi.
|
3
|
+
#
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require "ffi"
|
8
|
+
require "forwardable"
|
9
|
+
|
10
|
+
module Vips
|
11
|
+
# This class represents a libvips image which can be modified. See
|
12
|
+
# {Vips::Image#mutate}.
|
13
|
+
class MutableImage < Vips::Object
|
14
|
+
extend Forwardable
|
15
|
+
alias_method :parent_get_typeof, :get_typeof
|
16
|
+
def_instance_delegators :@image, :width, :height, :bands, :format,
|
17
|
+
:interpretation, :filename, :xoffset, :yoffset, :xres, :yres, :size,
|
18
|
+
:get, :get_typeof, :get_fields
|
19
|
+
|
20
|
+
# layout is exactly as {Image} (since we are also wrapping a VipsImage
|
21
|
+
# object)
|
22
|
+
module MutableImageLayout
|
23
|
+
def self.included base
|
24
|
+
base.class_eval do
|
25
|
+
layout :parent, Vips::Object::Struct
|
26
|
+
# rest opaque
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Struct < Vips::Object::Struct
|
32
|
+
include MutableImageLayout
|
33
|
+
end
|
34
|
+
|
35
|
+
class ManagedStruct < Vips::Object::ManagedStruct
|
36
|
+
include MutableImageLayout
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get the {Image} this {MutableImage} is modifying. Only use this once you
|
40
|
+
# have finished all modifications.
|
41
|
+
#
|
42
|
+
# This is for internal use only. See {Vips::Image#mutate} for the
|
43
|
+
# user-facing interface.
|
44
|
+
attr_reader :image
|
45
|
+
|
46
|
+
# Make a {MutableImage} from a regular {Image}.
|
47
|
+
#
|
48
|
+
# This is for internal use only. See {Vips::Image#mutate} for the
|
49
|
+
# user-facing interface.
|
50
|
+
def initialize(image)
|
51
|
+
# We take a copy of the regular Image to ensure we have an unshared
|
52
|
+
# (unique) object. We forward things like #width and #height to this, and
|
53
|
+
# it's the thing we return at the end of the mutate block.
|
54
|
+
copy_image = image.copy
|
55
|
+
|
56
|
+
# use ptr since we need the raw unwrapped pointer inside the image ...
|
57
|
+
# and make the ref that gobject will unref when it finishes
|
58
|
+
pointer = copy_image.ptr
|
59
|
+
::GObject.g_object_ref pointer
|
60
|
+
super pointer
|
61
|
+
|
62
|
+
# and save the copy ready for when we finish mutating
|
63
|
+
@image = copy_image
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect
|
67
|
+
"#<MutableImage #{width}x#{height} #{format}, #{bands} bands, #{interpretation}>"
|
68
|
+
end
|
69
|
+
|
70
|
+
def respond_to? name, include_all = false
|
71
|
+
# To support keyword args, we need to tell Ruby that final image
|
72
|
+
# arguments cannot be hashes of keywords.
|
73
|
+
#
|
74
|
+
# https://makandracards.com/makandra/
|
75
|
+
# 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
|
76
|
+
return false if name == :to_hash
|
77
|
+
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def respond_to_missing? name, include_all = false
|
82
|
+
# respond to all vips operations by nickname
|
83
|
+
return true if Vips.type_find("VipsOperation", name.to_s) != 0
|
84
|
+
|
85
|
+
super
|
86
|
+
end
|
87
|
+
|
88
|
+
# Invoke a vips operation with {Vips::Operation#call}, using self as
|
89
|
+
# the first input argument. {Vips::Operation#call} will only allow
|
90
|
+
# operations that modify self when passed a {MutableImage}.
|
91
|
+
#
|
92
|
+
# @param name [String] vips operation to call
|
93
|
+
# @return result of vips operation
|
94
|
+
def method_missing name, *args, **options
|
95
|
+
Vips::Operation.call name.to_s, [self, *args], options
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create a metadata item on an image of the specifed type. Ruby types
|
99
|
+
# are automatically transformed into the matching glib type (eg.
|
100
|
+
# {GObject::GINT_TYPE}), if possible.
|
101
|
+
#
|
102
|
+
# For example, you can use this to set an image's ICC profile:
|
103
|
+
#
|
104
|
+
# ```ruby
|
105
|
+
# x.set_type! Vips::BLOB_TYPE, "icc-profile-data", profile
|
106
|
+
# ```
|
107
|
+
#
|
108
|
+
# where `profile` is an ICC profile held as a binary string object.
|
109
|
+
#
|
110
|
+
# @see set!
|
111
|
+
# @param gtype [Integer] GType of item
|
112
|
+
# @param name [String] Metadata field to set
|
113
|
+
# @param value [Object] Value to set
|
114
|
+
def set_type! gtype, name, value
|
115
|
+
gvalue = GObject::GValue.alloc
|
116
|
+
gvalue.init gtype
|
117
|
+
gvalue.set value
|
118
|
+
Vips.vips_image_set self, name, gvalue
|
119
|
+
gvalue.unset
|
120
|
+
end
|
121
|
+
|
122
|
+
# Set the value of a metadata item on an image. The metadata item must
|
123
|
+
# already exist. Ruby types are automatically transformed into the
|
124
|
+
# matching {GObject::GValue}, if possible.
|
125
|
+
#
|
126
|
+
# For example, you can use this to set an image's ICC profile:
|
127
|
+
#
|
128
|
+
# ```
|
129
|
+
# x.set! "icc-profile-data", profile
|
130
|
+
# ```
|
131
|
+
#
|
132
|
+
# where `profile` is an ICC profile held as a binary string object.
|
133
|
+
#
|
134
|
+
# @see set_type!
|
135
|
+
# @param name [String] Metadata field to set
|
136
|
+
# @param value [Object] Value to set
|
137
|
+
def set! name, value
|
138
|
+
set_type! get_typeof(name), name, value
|
139
|
+
end
|
140
|
+
|
141
|
+
# Remove a metadata item from an image.
|
142
|
+
#
|
143
|
+
# For example:
|
144
|
+
#
|
145
|
+
# ```
|
146
|
+
# x.remove! "icc-profile-data"
|
147
|
+
# ```
|
148
|
+
#
|
149
|
+
# @param name [String] Metadata field to remove
|
150
|
+
def remove! name
|
151
|
+
Vips.vips_image_remove self, name
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/lib/vips/object.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
5
|
# License:: MIT
|
6
6
|
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
8
|
|
9
9
|
module Vips
|
10
10
|
private
|
@@ -21,20 +21,20 @@ module Vips
|
|
21
21
|
public
|
22
22
|
|
23
23
|
# some handy gtypes
|
24
|
-
IMAGE_TYPE = GObject
|
25
|
-
ARRAY_INT_TYPE = GObject
|
26
|
-
ARRAY_DOUBLE_TYPE = GObject
|
27
|
-
ARRAY_IMAGE_TYPE = GObject
|
28
|
-
REFSTR_TYPE = GObject
|
29
|
-
BLOB_TYPE = GObject
|
30
|
-
|
31
|
-
BAND_FORMAT_TYPE = Vips
|
32
|
-
INTERPRETATION_TYPE = Vips
|
33
|
-
CODING_TYPE = Vips
|
34
|
-
|
35
|
-
if Vips
|
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
36
|
attach_function :vips_blend_mode_get_type, [], :GType
|
37
|
-
BLEND_MODE_TYPE = Vips
|
37
|
+
BLEND_MODE_TYPE = Vips.vips_blend_mode_get_type
|
38
38
|
else
|
39
39
|
BLEND_MODE_TYPE = nil
|
40
40
|
end
|
@@ -45,37 +45,37 @@ module Vips
|
|
45
45
|
layout :im, :pointer,
|
46
46
|
:run, :int,
|
47
47
|
:eta, :int,
|
48
|
-
:tpels, :int64_t,
|
49
|
-
:npels, :int64_t,
|
50
|
-
:percent, :int,
|
51
|
-
:start, :pointer
|
48
|
+
:tpels, :int64_t,
|
49
|
+
:npels, :int64_t,
|
50
|
+
:percent, :int,
|
51
|
+
:start, :pointer
|
52
52
|
end
|
53
53
|
|
54
|
-
# Our signal marshalers.
|
54
|
+
# Our signal marshalers.
|
55
55
|
#
|
56
|
-
# These are functions which take the handler as a param and return a
|
56
|
+
# These are functions which take the handler as a param and return a
|
57
57
|
# closure with the right FFI signature for g_signal_connect for this
|
58
|
-
# specific signal.
|
58
|
+
# specific signal.
|
59
59
|
#
|
60
|
-
# ruby-ffi makes it hard to use the g_signal_connect user data param
|
60
|
+
# ruby-ffi makes it hard to use the g_signal_connect user data param
|
61
61
|
# to pass the function pointer through, unfortunately.
|
62
62
|
#
|
63
63
|
# We can't throw exceptions across C, so we must catch everything.
|
64
64
|
|
65
|
-
MARSHAL_PROGRESS =
|
65
|
+
MARSHAL_PROGRESS = proc do |handler|
|
66
66
|
FFI::Function.new(:void, [:pointer, :pointer, :pointer]) do |vi, prog, cb|
|
67
67
|
begin
|
68
|
-
handler.(Progress.new(prog))
|
68
|
+
handler.call(Progress.new(prog))
|
69
69
|
rescue Exception => e
|
70
70
|
puts "progress: #{e}"
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
MARSHAL_READ =
|
75
|
+
MARSHAL_READ = proc do |handler|
|
76
76
|
FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
|
77
77
|
begin
|
78
|
-
result = handler.(p, len)
|
78
|
+
result = handler.call(p, len)
|
79
79
|
rescue Exception => e
|
80
80
|
puts "read: #{e}"
|
81
81
|
result = 0
|
@@ -85,10 +85,10 @@ module Vips
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
MARSHAL_SEEK =
|
88
|
+
MARSHAL_SEEK = proc do |handler|
|
89
89
|
FFI::Function.new(:int64_t, [:pointer, :int64_t, :int]) do |i, off, whence|
|
90
90
|
begin
|
91
|
-
result = handler.(off, whence)
|
91
|
+
result = handler.call(off, whence)
|
92
92
|
rescue Exception => e
|
93
93
|
puts "seek: #{e}"
|
94
94
|
result = -1
|
@@ -98,10 +98,10 @@ module Vips
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
MARSHAL_WRITE =
|
101
|
+
MARSHAL_WRITE = proc do |handler|
|
102
102
|
FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
|
103
103
|
begin
|
104
|
-
result = handler.(p, len)
|
104
|
+
result = handler.call(p, len)
|
105
105
|
rescue Exception => e
|
106
106
|
puts "write: #{e}"
|
107
107
|
result = 0
|
@@ -111,10 +111,10 @@ module Vips
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
MARSHAL_FINISH =
|
114
|
+
MARSHAL_FINISH = proc do |handler|
|
115
115
|
FFI::Function.new(:void, [:pointer, :pointer]) do |i, cb|
|
116
116
|
begin
|
117
|
-
handler.
|
117
|
+
handler.call
|
118
118
|
rescue Exception => e
|
119
119
|
puts "finish: #{e}"
|
120
120
|
end
|
@@ -123,29 +123,29 @@ module Vips
|
|
123
123
|
|
124
124
|
# map signal name to marshal proc
|
125
125
|
MARSHAL_ALL = {
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
132
|
-
:
|
126
|
+
preeval: MARSHAL_PROGRESS,
|
127
|
+
eval: MARSHAL_PROGRESS,
|
128
|
+
posteval: MARSHAL_PROGRESS,
|
129
|
+
read: MARSHAL_READ,
|
130
|
+
seek: MARSHAL_SEEK,
|
131
|
+
write: MARSHAL_WRITE,
|
132
|
+
finish: MARSHAL_FINISH
|
133
133
|
}
|
134
134
|
|
135
135
|
attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
|
136
136
|
attach_function :vips_enum_nick, [:GType, :int], :string
|
137
137
|
|
138
138
|
attach_function :vips_value_set_ref_string,
|
139
|
-
|
139
|
+
[GObject::GValue.ptr, :string], :void
|
140
140
|
attach_function :vips_value_set_array_double,
|
141
|
-
|
141
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
142
142
|
attach_function :vips_value_set_array_int,
|
143
|
-
|
143
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
144
144
|
attach_function :vips_value_set_array_image,
|
145
|
-
|
145
|
+
[GObject::GValue.ptr, :int], :void
|
146
146
|
callback :free_fn, [:pointer], :void
|
147
147
|
attach_function :vips_value_set_blob,
|
148
|
-
|
148
|
+
[GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void
|
149
149
|
|
150
150
|
class SizeStruct < FFI::Struct
|
151
151
|
layout :value, :size_t
|
@@ -156,15 +156,15 @@ module Vips
|
|
156
156
|
end
|
157
157
|
|
158
158
|
attach_function :vips_value_get_ref_string,
|
159
|
-
|
159
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :string
|
160
160
|
attach_function :vips_value_get_array_double,
|
161
|
-
|
161
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
162
162
|
attach_function :vips_value_get_array_int,
|
163
|
-
|
163
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
164
164
|
attach_function :vips_value_get_array_image,
|
165
|
-
|
165
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
166
166
|
attach_function :vips_value_get_blob,
|
167
|
-
|
167
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :pointer
|
168
168
|
|
169
169
|
attach_function :type_find, :vips_type_find, [:string, :string], :GType
|
170
170
|
|
@@ -173,7 +173,7 @@ module Vips
|
|
173
173
|
# debugging ruby-vips.
|
174
174
|
def self.print_all
|
175
175
|
GC.start
|
176
|
-
Vips
|
176
|
+
Vips.vips_object_print_all
|
177
177
|
end
|
178
178
|
|
179
179
|
# the layout of the VipsObject struct
|
@@ -182,15 +182,15 @@ module Vips
|
|
182
182
|
base.class_eval do
|
183
183
|
# don't actually need most of these
|
184
184
|
layout :parent, GObject::GObject::Struct,
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
185
|
+
:constructed, :int,
|
186
|
+
:static_object, :int,
|
187
|
+
:argument_table, :pointer,
|
188
|
+
:nickname, :string,
|
189
|
+
:description, :string,
|
190
|
+
:preclose, :int,
|
191
|
+
:close, :int,
|
192
|
+
:postclose, :int,
|
193
|
+
:local_memory, :size_t
|
194
194
|
end
|
195
195
|
end
|
196
196
|
end
|
@@ -210,8 +210,8 @@ module Vips
|
|
210
210
|
argument_class = Vips::ArgumentClassPtr.new
|
211
211
|
argument_instance = Vips::ArgumentInstancePtr.new
|
212
212
|
|
213
|
-
result = Vips
|
214
|
-
|
213
|
+
result = Vips.vips_object_get_argument self, name,
|
214
|
+
ppspec, argument_class, argument_instance
|
215
215
|
return nil if result != 0
|
216
216
|
|
217
217
|
ppspec[:value]
|
@@ -229,7 +229,7 @@ module Vips
|
|
229
229
|
def get_typeof name
|
230
230
|
pspec = get_pspec name
|
231
231
|
unless pspec
|
232
|
-
Vips
|
232
|
+
Vips.vips_error_clear
|
233
233
|
return 0
|
234
234
|
end
|
235
235
|
|
@@ -240,50 +240,49 @@ module Vips
|
|
240
240
|
gtype = get_typeof_error name
|
241
241
|
gvalue = GObject::GValue.alloc
|
242
242
|
gvalue.init gtype
|
243
|
-
GObject
|
243
|
+
GObject.g_object_get_property self, name, gvalue
|
244
244
|
result = gvalue.get
|
245
245
|
gvalue.unset
|
246
246
|
|
247
|
-
GLib
|
247
|
+
GLib.logger.debug("Vips::Object.get") { "#{name} == #{result}" }
|
248
248
|
|
249
|
-
|
249
|
+
result
|
250
250
|
end
|
251
251
|
|
252
252
|
def set name, value
|
253
|
-
GLib
|
253
|
+
GLib.logger.debug("Vips::Object.set") { "#{name} = #{value}" }
|
254
254
|
|
255
255
|
gtype = get_typeof_error name
|
256
256
|
gvalue = GObject::GValue.alloc
|
257
257
|
gvalue.init gtype
|
258
258
|
gvalue.set value
|
259
|
-
GObject
|
259
|
+
GObject.g_object_set_property self, name, gvalue
|
260
260
|
gvalue.unset
|
261
261
|
end
|
262
262
|
|
263
|
-
def signal_connect name, handler=nil
|
263
|
+
def signal_connect name, handler = nil, &block
|
264
264
|
marshal = MARSHAL_ALL[name.to_sym]
|
265
|
-
raise Vips::Error, "unsupported signal #{name}" if marshal
|
265
|
+
raise Vips::Error, "unsupported signal #{name}" if marshal.nil?
|
266
266
|
|
267
|
-
if
|
268
|
-
#
|
269
|
-
prc =
|
267
|
+
if block
|
268
|
+
# our block as a Proc
|
269
|
+
prc = block
|
270
270
|
elsif handler
|
271
|
-
# We assume the hander is a
|
271
|
+
# We assume the hander is a Proc (perhaps we should test)
|
272
272
|
prc = handler
|
273
273
|
else
|
274
274
|
raise Vips::Error, "must supply either block or handler"
|
275
275
|
end
|
276
276
|
|
277
|
-
# The marshal function will make a closure with the right type signature
|
277
|
+
# The marshal function will make a closure with the right type signature
|
278
278
|
# for the selected signal
|
279
|
-
callback = marshal.(prc)
|
279
|
+
callback = marshal.call(prc)
|
280
280
|
|
281
281
|
# we need to make sure this is not GCd while self is alive
|
282
282
|
@references << callback
|
283
283
|
|
284
|
-
GObject
|
284
|
+
GObject.g_signal_connect_data(self, name.to_s, callback, nil, nil, 0)
|
285
285
|
end
|
286
|
-
|
287
286
|
end
|
288
287
|
|
289
288
|
class ObjectClass < FFI::Struct
|
@@ -322,10 +321,10 @@ module Vips
|
|
322
321
|
|
323
322
|
class ArgumentClass < Argument
|
324
323
|
layout :parent, Argument,
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
324
|
+
:object_class, ObjectClass.ptr,
|
325
|
+
:flags, :uint,
|
326
|
+
:priority, :int,
|
327
|
+
:offset, :ulong_long
|
329
328
|
end
|
330
329
|
|
331
330
|
class ArgumentClassPtr < FFI::Struct
|
@@ -339,10 +338,10 @@ module Vips
|
|
339
338
|
# just use :pointer, not VipsObject.ptr, to avoid casting gobject
|
340
339
|
# subclasses
|
341
340
|
attach_function :vips_object_get_argument,
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
341
|
+
[:pointer, :string,
|
342
|
+
GObject::GParamSpecPtr.ptr,
|
343
|
+
ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
|
344
|
+
:int
|
346
345
|
|
347
346
|
attach_function :vips_object_print_all, [], :void
|
348
347
|
|