ruby-vips 2.0.17 → 2.1.3

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 +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"