ruby-vips 2.0.17 → 2.1.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 (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 +26 -0
  7. data/Gemfile +3 -1
  8. data/README.md +12 -11
  9. data/Rakefile +13 -21
  10. data/TODO +4 -8
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +6 -6
  13. data/example/connection.rb +18 -9
  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 +46 -39
  22. data/example/progress.rb +3 -3
  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 +127 -76
  29. data/lib/vips/blend_mode.rb +29 -25
  30. data/lib/vips/connection.rb +4 -4
  31. data/lib/vips/gobject.rb +18 -11
  32. data/lib/vips/gvalue.rb +54 -54
  33. data/lib/vips/image.rb +289 -165
  34. data/lib/vips/interpolate.rb +3 -2
  35. data/lib/vips/methods.rb +484 -107
  36. data/lib/vips/mutableimage.rb +173 -0
  37. data/lib/vips/object.rb +86 -93
  38. data/lib/vips/operation.rb +161 -82
  39. data/lib/vips/region.rb +6 -6
  40. data/lib/vips/source.rb +11 -12
  41. data/lib/vips/sourcecustom.rb +7 -8
  42. data/lib/vips/target.rb +12 -13
  43. data/lib/vips/targetcustom.rb +9 -10
  44. data/lib/vips/version.rb +1 -1
  45. data/ruby-vips.gemspec +26 -22
  46. metadata +29 -49
  47. data/.rubocop.yml +0 -22
  48. data/.rubocop_todo.yml +0 -473
  49. data/.travis.yml +0 -57
  50. data/install-vips.sh +0 -26
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require "vips"
4
+
5
+ # load and stream into memory
6
+ image = Vips::Image.new_from_file(ARGV[0], access: :sequential).copy_memory
7
+
8
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
9
+
10
+ lines = image
11
+ (0..1).step 0.01 do |i|
12
+ lines = lines.draw_line 255, lines.width * i, 0, 0, lines.height * (1 - i)
13
+ end
14
+
15
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
16
+ puts "non-destructive took #{ending - starting}s"
17
+
18
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+
20
+ lines = image
21
+ lines = lines.mutate do |x|
22
+ (0..1).step 0.01 do |i|
23
+ x.draw_line! 255, x.width * i, 0, 0, x.height * (1 - i)
24
+ end
25
+ end
26
+
27
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
28
+ puts "mutate took #{ending - starting}s"
29
+
30
+ lines.write_to_file ARGV[1]
data/example/example1.rb CHANGED
@@ -1,9 +1,9 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/ruby
2
2
 
3
- require 'logger'
4
- require 'vips'
3
+ require "logger"
4
+ require "vips"
5
5
 
6
- GLib::logger.level = Logger::DEBUG
6
+ GLib.logger.level = Logger::DEBUG
7
7
 
8
8
  Vips::Operation.new "black"
9
9
 
data/example/example2.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'logger'
4
- require 'vips'
3
+ require "logger"
4
+ require "vips"
5
5
 
6
6
  puts ""
7
7
  puts "starting up:"
8
8
 
9
9
  # this makes vips keep a list of all active objects which we can print out
10
- Vips::leak_set true
10
+ Vips.leak_set true
11
11
 
12
12
  # disable the operation cache
13
- Vips::cache_set_max 0
13
+ Vips.cache_set_max 0
14
14
 
15
15
  # GLib::logger.level = Logger::DEBUG
16
16
 
@@ -20,7 +20,7 @@ n.times do |i|
20
20
  puts ""
21
21
  puts "call #{i} ..."
22
22
  out = Vips::Operation.call "black", [200, 300]
23
- if out.width != 200 or out.height != 300
23
+ if out.width != 200 || out.height != 300
24
24
  puts "bad image result from black"
25
25
  end
26
26
  end
@@ -28,7 +28,7 @@ end
28
28
  puts ""
29
29
  puts "after #{n} calls:"
30
30
  GC.start
31
- Vips::Object::print_all
31
+ Vips::Object.print_all
32
32
 
33
33
  puts ""
34
34
  puts "shutting down:"
data/example/example3.rb CHANGED
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  # this makes vips keep a list of all active objects
6
- Vips::leak_set true
6
+ Vips.leak_set true
7
7
 
8
8
  # disable the operation cache
9
9
  # Vips::cache_set_max 0
10
10
 
11
11
  # turn on debug logging
12
- GLib::logger.level = Logger::DEBUG
12
+ GLib.logger.level = Logger::DEBUG
13
13
 
14
- 1.times do |i|
14
+ 10.times do |i|
15
15
  puts "loop #{i} ..."
16
16
  im = Vips::Image.new_from_file ARGV[0]
17
- im = im.embed 100, 100, 3000, 3000, :extend => :mirror
17
+ im = im.embed 100, 100, 3000, 3000, extend: :mirror
18
18
  im.write_to_file "x.v"
19
19
  end
data/example/example4.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  # this makes vips keep a list of all active objects
6
- Vips::leak_set true
6
+ Vips.leak_set true
7
7
 
8
8
  # disable the operation cache
9
9
  # Vips::cache_set_max 0
data/example/example5.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  # this makes vips keep a list of all active objects
6
6
  # Vips::leak_set true
@@ -15,7 +15,7 @@ if ARGV.length < 2
15
15
  raise "usage: #{$PROGRAM_NAME}: input-file output-file"
16
16
  end
17
17
 
18
- im = Vips::Image.new_from_file ARGV[0], :access => :sequential
18
+ im = Vips::Image.new_from_file ARGV[0], access: :sequential
19
19
 
20
20
  im *= [1, 2, 1]
21
21
 
@@ -23,8 +23,8 @@ im *= [1, 2, 1]
23
23
  # make it ourselves
24
24
  # if you are OK with scale=1, you can just pass the array directly to .conv()
25
25
  mask = Vips::Image.new_from_array [[-1, -1, -1],
26
- [-1, 16, -1],
27
- [-1, -1, -1]], 8
26
+ [-1, 16, -1],
27
+ [-1, -1, -1]], 8
28
28
  im = im.conv mask
29
29
 
30
30
  im.write_to_file ARGV[1]
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'ffi'
4
- require 'forwardable'
3
+ require "ffi"
4
+ require "forwardable"
5
5
 
6
6
  # this is really very crude logging
7
7
 
@@ -29,7 +29,7 @@ end
29
29
 
30
30
  module GLib
31
31
  extend FFI::Library
32
- ffi_lib 'gobject-2.0'
32
+ ffi_lib "gobject-2.0"
33
33
 
34
34
  def self.set_log_domain(_domain)
35
35
  # FIXME: this needs hooking up
@@ -68,8 +68,8 @@ module GLib
68
68
  def self.included(base)
69
69
  base.class_eval do
70
70
  layout :g_type_instance, :pointer,
71
- :ref_count, :uint,
72
- :qdata, :pointer
71
+ :ref_count, :uint,
72
+ :qdata, :pointer
73
73
  end
74
74
  end
75
75
  end
@@ -85,7 +85,7 @@ module GLib
85
85
 
86
86
  def self.release(ptr)
87
87
  log "GLib::GObject::ManagedStruct.release: unreffing #{ptr}"
88
- GLib::g_object_unref(ptr) unless ptr.null?
88
+ GLib.g_object_unref(ptr) unless ptr.null?
89
89
  end
90
90
  end
91
91
 
@@ -116,7 +116,7 @@ module GLib
116
116
 
117
117
  class << self
118
118
  def ffi_struct
119
- self.const_get(:Struct)
119
+ const_get(:Struct)
120
120
  end
121
121
  end
122
122
 
@@ -127,24 +127,32 @@ module GLib
127
127
 
128
128
  class << self
129
129
  def ffi_managed_struct
130
- self.const_get(:ManagedStruct)
130
+ const_get(:ManagedStruct)
131
131
  end
132
132
  end
133
133
  end
134
134
 
135
- # :gtype will usually be 64-bit, but will be 32-bit on 32-bit Windows
136
- typedef :ulong, :GType
135
+ # we can't just use ulong, windows has different int sizing rules
136
+ if FFI::Platform::ADDRESS_SIZE == 64
137
+ typedef :uint64, :GType
138
+ else
139
+ typedef :uint32, :GType
140
+ end
137
141
  end
138
142
 
139
143
  module Vips
140
144
  extend FFI::Library
141
- ffi_lib 'vips'
145
+ ffi_lib "vips"
142
146
 
143
147
  LOG_DOMAIN = "VIPS"
144
- GLib::set_log_domain(LOG_DOMAIN)
148
+ GLib.set_log_domain(LOG_DOMAIN)
145
149
 
146
150
  # need to repeat this
147
- typedef :ulong, :GType
151
+ if FFI::Platform::ADDRESS_SIZE == 64
152
+ typedef :uint64, :GType
153
+ else
154
+ typedef :uint32, :GType
155
+ end
148
156
 
149
157
  attach_function :vips_init, [:string], :int
150
158
  attach_function :vips_shutdown, [], :void
@@ -153,19 +161,19 @@ module Vips
153
161
  attach_function :vips_error_clear, [], :void
154
162
 
155
163
  def self.get_error
156
- errstr = Vips::vips_error_buffer
157
- Vips::vips_error_clear
164
+ errstr = Vips.vips_error_buffer
165
+ Vips.vips_error_clear
158
166
  errstr
159
167
  end
160
168
 
161
- if Vips::vips_init($0) != 0
162
- puts Vips::get_error
169
+ if Vips.vips_init($0) != 0
170
+ puts Vips.get_error
163
171
  exit 1
164
172
  end
165
173
 
166
- at_exit {
167
- Vips::vips_shutdown
168
- }
174
+ at_exit do
175
+ Vips.vips_shutdown
176
+ end
169
177
 
170
178
  attach_function :vips_object_print_all, [], :void
171
179
  attach_function :vips_leak_set, [:int], :void
@@ -188,15 +196,15 @@ module Vips
188
196
  base.class_eval do
189
197
  # don't actually need most of these, remove them later
190
198
  layout :parent, GLib::GObject::Struct,
191
- :constructed, :int,
192
- :static_object, :int,
193
- :argument_table, :pointer,
194
- :nickname, :string,
195
- :description, :string,
196
- :preclose, :int,
197
- :close, :int,
198
- :postclose, :int,
199
- :local_memory, :size_t
199
+ :constructed, :int,
200
+ :static_object, :int,
201
+ :argument_table, :pointer,
202
+ :nickname, :string,
203
+ :description, :string,
204
+ :preclose, :int,
205
+ :close, :int,
206
+ :postclose, :int,
207
+ :local_memory, :size_t
200
208
  end
201
209
  end
202
210
  end
@@ -250,7 +258,7 @@ module Vips
250
258
  end
251
259
 
252
260
  def self.new_partial
253
- VipsImage.new(Vips::vips_image_new)
261
+ VipsImage.new(Vips.vips_image_new)
254
262
  end
255
263
  end
256
264
 
@@ -258,12 +266,11 @@ module Vips
258
266
  end
259
267
 
260
268
  puts "creating image"
261
- begin
262
- x = Vips::VipsImage.new_partial
263
- puts "x = #{x}"
264
- puts ""
265
- puts "x[:parent] = #{x[:parent]}"
266
- puts ""
267
- puts "x[:parent][:description] = #{x[:parent][:description]}"
268
- puts ""
269
- end
269
+
270
+ x = Vips::VipsImage.new_partial
271
+ puts "x = #{x}"
272
+ puts ""
273
+ puts "x[:parent] = #{x[:parent]}"
274
+ puts ""
275
+ puts "x[:parent][:description] = #{x[:parent][:description]}"
276
+ puts ""
data/example/progress.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  image = Vips::Image.black 1, 100000
6
6
  image.set_progress true
@@ -12,11 +12,11 @@ def progress_to_s(name, progress)
12
12
  puts " progress.tpels = #{progress[:tpels]}"
13
13
  puts " progress.npels = #{progress[:npels]}"
14
14
  puts " progress.percent = #{progress[:percent]}"
15
- end
15
+ end
16
16
 
17
17
  image.signal_connect :preeval do |progress|
18
18
  progress_to_s("preeval", progress)
19
- end
19
+ end
20
20
 
21
21
  image.signal_connect :eval do |progress|
22
22
  progress_to_s("eval", progress)
data/example/thumb.rb CHANGED
@@ -1,25 +1,25 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/ruby
2
2
 
3
3
  # batch-process a lot of files
4
4
  #
5
5
  # this should run in constant memory -- if it doesn't, something has broken
6
6
 
7
- require 'vips'
7
+ require "vips"
8
8
 
9
9
  # benchmark thumbnail via a memory buffer
10
10
  def via_memory(filename, thumbnail_width)
11
11
  data = IO.binread(filename)
12
12
 
13
- thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
13
+ thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: "centre"
14
14
 
15
- thumb.write_to_buffer '.jpg'
15
+ thumb.write_to_buffer ".jpg"
16
16
  end
17
17
 
18
18
  # benchmark thumbnail via files
19
19
  def via_files(filename, thumbnail_width)
20
- thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
20
+ thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: "centre"
21
21
 
22
- thumb.write_to_buffer '.jpg'
22
+ thumb.write_to_buffer ".jpg"
23
23
  end
24
24
 
25
25
  ARGV.each do |filename|
data/example/trim8.rb CHANGED
@@ -7,7 +7,7 @@
7
7
  # non-zero row or column is the object edge. We make the mask image with an
8
8
  # amount-different-from-background image plus a threshold.
9
9
 
10
- require 'vips'
10
+ require "vips"
11
11
 
12
12
  im = Vips::Image.new_from_file ARGV[0]
13
13
 
data/example/watermark.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  im = Vips::Image.new_from_file ARGV[0], access: :sequential
6
6
 
7
7
  # make the text mask
8
- text = Vips::Image.text ARGV[2], width: 200, dpi: 200, font: 'sans bold'
8
+ text = Vips::Image.text ARGV[2], width: 200, dpi: 200, font: "sans bold"
9
9
  text = text.rotate(-45)
10
10
  # make the text transparent
11
11
  text = (text * 0.3).cast(:uchar)
data/example/wobble.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
5
5
  image = Vips::Image.new_from_file ARGV[0]
6
6
 
data/lib/ruby-vips.rb CHANGED
@@ -1 +1 @@
1
- require 'vips'
1
+ require "vips"
data/lib/vips.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 'logger'
7
+ require "ffi"
8
+ require "logger"
9
9
 
10
10
  # This module uses FFI to make a simple layer over the glib and gobject
11
11
  # libraries.
@@ -37,12 +37,12 @@ module GLib
37
37
  class << self
38
38
  attr_accessor :logger
39
39
  end
40
- @logger = Logger.new(STDOUT)
40
+ @logger = Logger.new($stdout)
41
41
  @logger.level = Logger::WARN
42
42
 
43
43
  extend FFI::Library
44
44
 
45
- ffi_lib library_name('glib-2.0', 0)
45
+ ffi_lib library_name("glib-2.0", 0)
46
46
 
47
47
  attach_function :g_malloc, [:size_t], :pointer
48
48
 
@@ -52,20 +52,20 @@ module GLib
52
52
 
53
53
  callback :g_log_func, [:string, :int, :string, :pointer], :void
54
54
  attach_function :g_log_set_handler,
55
- [:string, :int, :g_log_func, :pointer], :int
55
+ [:string, :int, :g_log_func, :pointer], :int
56
56
  attach_function :g_log_remove_handler, [:string, :int], :void
57
57
 
58
58
  # log flags
59
- LOG_FLAG_RECURSION = 1 << 0
60
- LOG_FLAG_FATAL = 1 << 1
59
+ LOG_FLAG_RECURSION = 1 << 0
60
+ LOG_FLAG_FATAL = 1 << 1
61
61
 
62
62
  # GLib log levels
63
- LOG_LEVEL_ERROR = 1 << 2 # always fatal
64
- LOG_LEVEL_CRITICAL = 1 << 3
65
- LOG_LEVEL_WARNING = 1 << 4
66
- LOG_LEVEL_MESSAGE = 1 << 5
67
- LOG_LEVEL_INFO = 1 << 6
68
- LOG_LEVEL_DEBUG = 1 << 7
63
+ LOG_LEVEL_ERROR = 1 << 2 # always fatal
64
+ LOG_LEVEL_CRITICAL = 1 << 3
65
+ LOG_LEVEL_WARNING = 1 << 4
66
+ LOG_LEVEL_MESSAGE = 1 << 5
67
+ LOG_LEVEL_INFO = 1 << 6
68
+ LOG_LEVEL_DEBUG = 1 << 7
69
69
 
70
70
  # map glib levels to Logger::Severity
71
71
  GLIB_TO_SEVERITY = {
@@ -83,9 +83,9 @@ module GLib
83
83
  @glib_log_handler_id = 0
84
84
 
85
85
  # module-level, so it's not GCd away
86
- LOG_HANDLER = Proc.new do |domain, level, message, _user_data|
86
+ LOG_HANDLER = proc { |domain, level, message, _user_data|
87
87
  @logger.log(GLIB_TO_SEVERITY[level], message, domain)
88
- end
88
+ }
89
89
 
90
90
  def self.remove_log_handler
91
91
  if @glib_log_handler_id != 0 && @glib_log_domain
@@ -95,7 +95,7 @@ module GLib
95
95
  end
96
96
 
97
97
  def self.set_log_domain domain
98
- GLib::remove_log_handler
98
+ GLib.remove_log_handler
99
99
 
100
100
  @glib_log_domain = domain
101
101
 
@@ -125,7 +125,7 @@ module GLib
125
125
  # on shutdown and we don't want LOG_HANDLER to be invoked
126
126
  # after Ruby has gone
127
127
  at_exit {
128
- GLib::remove_log_handler
128
+ GLib.remove_log_handler
129
129
  }
130
130
  end
131
131
  end
@@ -134,7 +134,7 @@ end
134
134
  module GObject
135
135
  extend FFI::Library
136
136
 
137
- ffi_lib library_name('gobject-2.0', 0)
137
+ ffi_lib library_name("gobject-2.0", 0)
138
138
 
139
139
  # we can't just use ulong, windows has different int sizing rules
140
140
  if FFI::Platform::ADDRESS_SIZE == 64
@@ -162,8 +162,8 @@ module GObject
162
162
  GOBJECT_TYPE = g_type_from_name "GObject"
163
163
  end
164
164
 
165
- require 'vips/gobject'
166
- require 'vips/gvalue'
165
+ require "vips/gobject"
166
+ require "vips/gvalue"
167
167
 
168
168
  # This module provides a binding for the [libvips image processing
169
169
  # library](https://libvips.github.io/libvips/).
@@ -208,12 +208,10 @@ require 'vips/gvalue'
208
208
  # for full details
209
209
  # on the various modes available.
210
210
  #
211
- # You can also load formatted images from
212
- # memory buffers, create images that wrap C-style memory arrays, or make images
213
- # from constants.
214
- #
215
- # Use {Source} and {Image.new_from_source} to load images from any data
216
- # source, for example URIs.
211
+ # You can also load formatted images from memory buffers, create images that
212
+ # wrap C-style memory arrays, or make images from constants. Use {Source}
213
+ # and {Image.new_from_source} to load images from any data source, for
214
+ # example URIs.
217
215
  #
218
216
  # The next line:
219
217
  #
@@ -256,7 +254,7 @@ require 'vips/gvalue'
256
254
  # suffix. You can also write formatted images to memory buffers, or dump
257
255
  # image data to a raw memory array.
258
256
  #
259
- # Use {Target} and {Image#write_to_target} to write formatted images to
257
+ # Use {Target} and {Image#write_to_target} to write formatted images to
260
258
  # any data sink, for example URIs.
261
259
  #
262
260
  # # How it works
@@ -409,36 +407,83 @@ require 'vips/gvalue'
409
407
  #
410
408
  # # Automatic YARD documentation
411
409
  #
412
- # The bulk of these API docs are generated automatically by
413
- # {Vips::Yard::generate}. It examines
414
- # libvips and writes a summary of each operation and the arguments and options
415
- # that that operation expects.
410
+ # The bulk of these API docs are generated automatically by {Yard#generate}.
411
+ # It examines libvips and writes a summary of each operation and the arguments
412
+ # and options that that operation expects.
416
413
  #
417
- # Use the [C API
418
- # docs](https://libvips.github.io/libvips/API/current)
414
+ # Use the [C API # docs](https://libvips.github.io/libvips/API/current)
419
415
  # for more detail.
420
416
  #
421
417
  # # Enums
422
418
  #
423
419
  # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
424
420
  # like `:uchar`. They are documented as a set of classes for convenience, see
425
- # the class list.
421
+ # {Vips::BandFormat}, for example.
426
422
  #
427
423
  # # Draw operations
428
424
  #
429
- # Paint operations like {Image#draw_circle} and {Image#draw_line}
430
- # modify their input image. This
431
- # makes them hard to use with the rest of libvips: you need to be very careful
432
- # about the order in which operations execute or you can get nasty crashes.
425
+ # There are two ways of calling the libvips draw operations, like
426
+ # {Image#draw_circle} and {Image#draw_line}.
427
+ #
428
+ # First, you can use them like functions. For example:
429
+ #
430
+ # ```ruby
431
+ # y = x.draw_line 255, 0, 0, x.width, x.height
432
+ # ```
433
+ #
434
+ # This will make a new image, `y`, which is a copy of `x` but with a line
435
+ # drawn across it. `x` is unchanged.
436
+ #
437
+ # This is simple, but will be slow if you want to draw many lines, since
438
+ # ruby-vips will make a copy of the whole image each time.
439
+ #
440
+ # You can use {Image#mutate} to make a {MutableImage}. This is an image which
441
+ # is unshared and is only available inside the {Image#mutate} block. Within
442
+ # this block, you can use `!` versions of the draw operations to modify images
443
+ # and avoid the copy. For example:
444
+ #
445
+ # ```ruby
446
+ # image = image.mutate do |mutable|
447
+ # (0 ... 1).step(0.01) do |i|
448
+ # mutable.draw_line! 255, mutable.width * i, 0, 0, mutable.height * (1 - i)
449
+ # end
450
+ # end
451
+ # ```
452
+ #
453
+ # Now each {Image#draw_line} will directly modify the mutable image, saving
454
+ # the copy. This is much faster and needs much less memory.
455
+ #
456
+ # # Metadata read
457
+ #
458
+ # Use {Image#get_fields} to get a list of the metadata fields that an image
459
+ # supports. ICC profiles, for example, are in a field called
460
+ # `icc-profile-data`. Use `vipsheader -a something.jpg` at the command-line
461
+ # to see all the fields on an image.
462
+ #
463
+ # Use {Image#get_typeof} to get the type of a field. Types are integers, with
464
+ # 0 meaning "no such field". Constants like {GObject::GINT_TYPE} are useful for
465
+ # testing field types.
466
+ #
467
+ # You can read image metadata using {Image#get}. The field value is converted
468
+ # to a Ruby value in the obvious way.
433
469
  #
434
- # The wrapper spots operations of this type and makes a private copy of the
435
- # image in memory before calling the operation. This stops crashes, but it does
436
- # make it inefficient. If you draw 100 lines on an image, for example, you'll
437
- # copy the image 100 times. The wrapper does make sure that memory is recycled
438
- # where possible, so you won't have 100 copies in memory.
470
+ # # Metadata write
439
471
  #
440
- # If you want to avoid the copies, you'll need to call drawing operations
441
- # yourself.
472
+ # You can also set and remove image metadata fields. Images are immutable, so
473
+ # you must make any changes inside a {Image#mutate} block. For example:
474
+ #
475
+ # ```ruby
476
+ # image = image.mutate do |mutable|
477
+ # image.get_fields.each do |field|
478
+ # mutable.remove! field unless field == "icc-profile-data"
479
+ # end
480
+ # end
481
+ # ```
482
+ #
483
+ # To remove all metadata except the icc profile.
484
+ #
485
+ # You can use {MutableImage#set!} to change the value of an existing field,
486
+ # and {MutableImage#set_type!} to create a new field with a specified type.
442
487
  #
443
488
  # # Progress
444
489
  #
@@ -448,7 +493,7 @@ require 'vips/gvalue'
448
493
  # ```ruby
449
494
  # image = Vips::Image.black 1, 100000
450
495
  # image.set_progress true
451
- #
496
+ #
452
497
  # def progress_to_s(name, progress)
453
498
  # puts "#{name}:"
454
499
  # puts " run = #{progress[:run]}"
@@ -457,23 +502,23 @@ require 'vips/gvalue'
457
502
  # puts " npels = #{progress[:npels]}"
458
503
  # puts " percent = #{progress[:percent]}"
459
504
  # end
460
- #
505
+ #
461
506
  # image.signal_connect :preeval do |progress|
462
507
  # progress_to_s("preeval", progress)
463
508
  # end
464
- #
509
+ #
465
510
  # image.signal_connect :eval do |progress|
466
511
  # progress_to_s("eval", progress)
467
512
  # image.set_kill(true) if progress[:percent] > 50
468
513
  # end
469
- #
514
+ #
470
515
  # image.signal_connect :posteval do |progress|
471
516
  # progress_to_s("posteval", progress)
472
517
  # end
473
- #
518
+ #
474
519
  # image.avg
475
520
  # ```
476
- #
521
+ #
477
522
  # The `:eval` signal will fire for every tile that is processed. You can stop
478
523
  # progress with {Image#set_kill} and processing will end with an exception.
479
524
  #
@@ -525,12 +570,17 @@ require 'vips/gvalue'
525
570
  module Vips
526
571
  extend FFI::Library
527
572
 
528
- ffi_lib library_name('vips', 42)
573
+ ffi_lib library_name("vips", 42)
529
574
 
530
575
  LOG_DOMAIN = "VIPS"
531
- GLib::set_log_domain LOG_DOMAIN
576
+ GLib.set_log_domain LOG_DOMAIN
532
577
 
533
- typedef :ulong, :GType
578
+ # we can't just use ulong, windows has different int sizing rules
579
+ if FFI::Platform::ADDRESS_SIZE == 64
580
+ typedef :uint64, :GType
581
+ else
582
+ typedef :uint32, :GType
583
+ end
534
584
 
535
585
  attach_function :vips_error_buffer, [], :string
536
586
  attach_function :vips_error_clear, [], :void
@@ -542,9 +592,9 @@ module Vips
542
592
  def initialize msg = nil
543
593
  if msg
544
594
  @details = msg
545
- elsif Vips::vips_error_buffer != ""
546
- @details = Vips::vips_error_buffer
547
- Vips::vips_error_clear
595
+ elsif Vips.vips_error_buffer != ""
596
+ @details = Vips.vips_error_buffer
597
+ Vips.vips_error_clear
548
598
  else
549
599
  @details = nil
550
600
  end
@@ -554,7 +604,7 @@ module Vips
554
604
  #
555
605
  # @return [String] The error message
556
606
  def to_s
557
- if @details != nil
607
+ if !@details.nil?
558
608
  @details
559
609
  else
560
610
  super.to_s
@@ -564,8 +614,8 @@ module Vips
564
614
 
565
615
  attach_function :vips_init, [:string], :int
566
616
 
567
- if Vips::vips_init($0) != 0
568
- throw Vips::get_error
617
+ if Vips.vips_init($0) != 0
618
+ throw Vips.get_error
569
619
  end
570
620
 
571
621
  # don't use at_exit to call vips_shutdown, it causes problems with fork, and
@@ -629,7 +679,7 @@ module Vips
629
679
  # Don't use this, instead change GLib::logger.level.
630
680
  def self.set_debug debug
631
681
  if debug
632
- GLib::logger.level = Logger::DEBUG
682
+ GLib.logger.level = Logger::DEBUG
633
683
  end
634
684
  end
635
685
 
@@ -651,36 +701,37 @@ module Vips
651
701
  # vips_foreign_get_suffixes() was added in libvips 8.8
652
702
  return [] unless Vips.respond_to? :vips_foreign_get_suffixes
653
703
 
654
- array = Vips::vips_foreign_get_suffixes
704
+ array = Vips.vips_foreign_get_suffixes
655
705
 
656
706
  names = []
657
707
  p = array
658
708
  until (q = p.read_pointer).null?
659
709
  suff = q.read_string
660
- GLib::g_free q
710
+ GLib.g_free q
661
711
  names << suff unless names.include? suff
662
712
  p += FFI::Type::POINTER.size
663
713
  end
664
- GLib::g_free array
714
+ GLib.g_free array
665
715
 
666
716
  names
667
717
  end
668
718
 
669
- LIBRARY_VERSION = Vips::version_string
719
+ LIBRARY_VERSION = Vips.version_string
670
720
 
671
721
  # libvips has this arbitrary number as a sanity-check upper bound on image
672
722
  # size. It's sometimes useful to know when calculating scale factors.
673
723
  MAX_COORD = 10000000
674
724
  end
675
725
 
676
- require 'vips/object'
677
- require 'vips/operation'
678
- require 'vips/image'
679
- require 'vips/interpolate'
680
- require 'vips/region'
681
- require 'vips/version'
682
- require 'vips/connection'
683
- require 'vips/source'
684
- require 'vips/sourcecustom'
685
- require 'vips/target'
686
- require 'vips/targetcustom'
726
+ require "vips/object"
727
+ require "vips/operation"
728
+ require "vips/image"
729
+ require "vips/mutableimage"
730
+ require "vips/interpolate"
731
+ require "vips/region"
732
+ require "vips/version"
733
+ require "vips/connection"
734
+ require "vips/source"
735
+ require "vips/sourcecustom"
736
+ require "vips/target"
737
+ require "vips/targetcustom"