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.
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
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,28 +4,45 @@
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.
12
12
 
13
+ # Generate a library name for ffi.
14
+ #
15
+ # Platform notes:
16
+ # linux:
17
+ # Some distros allow "libvips.so", but only if the -dev headers have been
18
+ # installed. To work everywhere, you must include the ABI number.
19
+ # Confusingly, the file extension is not at the end. ffi adds the "lib"
20
+ # prefix.
21
+ # mac:
22
+ # As linux, but the extension is at the end and is added by ffi.
23
+ # windows:
24
+ # The ABI number must be included, but with a hyphen. ffi does not add a
25
+ # "lib" prefix or a ".dll" suffix.
26
+ def library_name(name, abi_number)
27
+ if FFI::Platform.windows?
28
+ "lib#{name}-#{abi_number}.dll"
29
+ elsif FFI::Platform.mac?
30
+ "#{name}.#{abi_number}"
31
+ else
32
+ "#{name}.so.#{abi_number}"
33
+ end
34
+ end
35
+
13
36
  module GLib
14
37
  class << self
15
38
  attr_accessor :logger
16
39
  end
17
- @logger = Logger.new(STDOUT)
40
+ @logger = Logger.new($stdout)
18
41
  @logger.level = Logger::WARN
19
42
 
20
43
  extend FFI::Library
21
44
 
22
- if FFI::Platform.windows?
23
- glib_libname = 'libglib-2.0-0.dll'
24
- else
25
- glib_libname = 'glib-2.0'
26
- end
27
-
28
- ffi_lib glib_libname
45
+ ffi_lib library_name("glib-2.0", 0)
29
46
 
30
47
  attach_function :g_malloc, [:size_t], :pointer
31
48
 
@@ -35,20 +52,20 @@ module GLib
35
52
 
36
53
  callback :g_log_func, [:string, :int, :string, :pointer], :void
37
54
  attach_function :g_log_set_handler,
38
- [:string, :int, :g_log_func, :pointer], :int
55
+ [:string, :int, :g_log_func, :pointer], :int
39
56
  attach_function :g_log_remove_handler, [:string, :int], :void
40
57
 
41
58
  # log flags
42
- LOG_FLAG_RECURSION = 1 << 0
43
- LOG_FLAG_FATAL = 1 << 1
59
+ LOG_FLAG_RECURSION = 1 << 0
60
+ LOG_FLAG_FATAL = 1 << 1
44
61
 
45
62
  # GLib log levels
46
- LOG_LEVEL_ERROR = 1 << 2 # always fatal
47
- LOG_LEVEL_CRITICAL = 1 << 3
48
- LOG_LEVEL_WARNING = 1 << 4
49
- LOG_LEVEL_MESSAGE = 1 << 5
50
- LOG_LEVEL_INFO = 1 << 6
51
- 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
52
69
 
53
70
  # map glib levels to Logger::Severity
54
71
  GLIB_TO_SEVERITY = {
@@ -66,9 +83,9 @@ module GLib
66
83
  @glib_log_handler_id = 0
67
84
 
68
85
  # module-level, so it's not GCd away
69
- LOG_HANDLER = Proc.new do |domain, level, message, _user_data|
86
+ LOG_HANDLER = proc { |domain, level, message, _user_data|
70
87
  @logger.log(GLIB_TO_SEVERITY[level], message, domain)
71
- end
88
+ }
72
89
 
73
90
  def self.remove_log_handler
74
91
  if @glib_log_handler_id != 0 && @glib_log_domain
@@ -78,7 +95,7 @@ module GLib
78
95
  end
79
96
 
80
97
  def self.set_log_domain domain
81
- GLib::remove_log_handler
98
+ GLib.remove_log_handler
82
99
 
83
100
  @glib_log_domain = domain
84
101
 
@@ -108,7 +125,7 @@ module GLib
108
125
  # on shutdown and we don't want LOG_HANDLER to be invoked
109
126
  # after Ruby has gone
110
127
  at_exit {
111
- GLib::remove_log_handler
128
+ GLib.remove_log_handler
112
129
  }
113
130
  end
114
131
  end
@@ -117,13 +134,7 @@ end
117
134
  module GObject
118
135
  extend FFI::Library
119
136
 
120
- if FFI::Platform.windows?
121
- gobject_libname = 'libgobject-2.0-0.dll'
122
- else
123
- gobject_libname = 'gobject-2.0'
124
- end
125
-
126
- ffi_lib gobject_libname
137
+ ffi_lib library_name("gobject-2.0", 0)
127
138
 
128
139
  # we can't just use ulong, windows has different int sizing rules
129
140
  if FFI::Platform::ADDRESS_SIZE == 64
@@ -151,11 +162,11 @@ module GObject
151
162
  GOBJECT_TYPE = g_type_from_name "GObject"
152
163
  end
153
164
 
154
- require 'vips/gobject'
155
- require 'vips/gvalue'
165
+ require "vips/gobject"
166
+ require "vips/gvalue"
156
167
 
157
168
  # This module provides a binding for the [libvips image processing
158
- # library](https://jcupitt.github.io/libvips/).
169
+ # library](https://libvips.github.io/libvips/).
159
170
  #
160
171
  # # Example
161
172
  #
@@ -197,9 +208,10 @@ require 'vips/gvalue'
197
208
  # for full details
198
209
  # on the various modes available.
199
210
  #
200
- # You can also load formatted images from
201
- # memory buffers, create images that wrap C-style memory arrays, or make images
202
- # from constants.
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.
203
215
  #
204
216
  # The next line:
205
217
  #
@@ -242,6 +254,9 @@ require 'vips/gvalue'
242
254
  # suffix. You can also write formatted images to memory buffers, or dump
243
255
  # image data to a raw memory array.
244
256
  #
257
+ # Use {Target} and {Image#write_to_target} to write formatted images to
258
+ # any data sink, for example URIs.
259
+ #
245
260
  # # How it works
246
261
  #
247
262
  # The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips
@@ -392,36 +407,132 @@ require 'vips/gvalue'
392
407
  #
393
408
  # # Automatic YARD documentation
394
409
  #
395
- # The bulk of these API docs are generated automatically by
396
- # {Vips::generate_yard}. It examines
397
- # libvips and writes a summary of each operation and the arguments and options
398
- # 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.
399
413
  #
400
- # Use the [C API
401
- # docs](https://jcupitt.github.io/libvips/API/current)
414
+ # Use the [C API # docs](https://libvips.github.io/libvips/API/current)
402
415
  # for more detail.
403
416
  #
404
417
  # # Enums
405
418
  #
406
419
  # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
407
420
  # like `:uchar`. They are documented as a set of classes for convenience, see
408
- # the class list.
421
+ # {Vips::BandFormat}, for example.
409
422
  #
410
423
  # # Draw operations
411
424
  #
412
- # Paint operations like {Image#draw_circle} and {Image#draw_line}
413
- # modify their input image. This
414
- # makes them hard to use with the rest of libvips: you need to be very careful
415
- # 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.
416
466
  #
417
- # The wrapper spots operations of this type and makes a private copy of the
418
- # image in memory before calling the operation. This stops crashes, but it does
419
- # make it inefficient. If you draw 100 lines on an image, for example, you'll
420
- # copy the image 100 times. The wrapper does make sure that memory is recycled
421
- # where possible, so you won't have 100 copies in memory.
467
+ # You can read image metadata using {Image#get}. The field value is converted
468
+ # to a Ruby value in the obvious way.
422
469
  #
423
- # If you want to avoid the copies, you'll need to call drawing operations
424
- # yourself.
470
+ # # Metadata write
471
+ #
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.
487
+ #
488
+ # # Progress
489
+ #
490
+ # You can attach signal handlers to images to watch computation progress. For
491
+ # example:
492
+ #
493
+ # ```ruby
494
+ # image = Vips::Image.black 1, 100000
495
+ # image.set_progress true
496
+ #
497
+ # def progress_to_s(name, progress)
498
+ # puts "#{name}:"
499
+ # puts " run = #{progress[:run]}"
500
+ # puts " eta = #{progress[:eta]}"
501
+ # puts " tpels = #{progress[:tpels]}"
502
+ # puts " npels = #{progress[:npels]}"
503
+ # puts " percent = #{progress[:percent]}"
504
+ # end
505
+ #
506
+ # image.signal_connect :preeval do |progress|
507
+ # progress_to_s("preeval", progress)
508
+ # end
509
+ #
510
+ # image.signal_connect :eval do |progress|
511
+ # progress_to_s("eval", progress)
512
+ # image.set_kill(true) if progress[:percent] > 50
513
+ # end
514
+ #
515
+ # image.signal_connect :posteval do |progress|
516
+ # progress_to_s("posteval", progress)
517
+ # end
518
+ #
519
+ # image.avg
520
+ # ```
521
+ #
522
+ # The `:eval` signal will fire for every tile that is processed. You can stop
523
+ # progress with {Image#set_kill} and processing will end with an exception.
524
+ #
525
+ # User streams
526
+ #
527
+ # You can make your own input and output stream objects with {SourceCustom} and
528
+ # {TargetCustom}. For example:
529
+ #
530
+ # ```ruby
531
+ # file = File.open "some/file", "rb"
532
+ # source = Vips::SourceCustom.new
533
+ # source.on_read { |length| file.read length }
534
+ # image = Vips::Image.new_from_source source, "", access: "sequential"
535
+ # ```
425
536
  #
426
537
  # # Overloads
427
538
  #
@@ -459,16 +570,10 @@ require 'vips/gvalue'
459
570
  module Vips
460
571
  extend FFI::Library
461
572
 
462
- if FFI::Platform.windows?
463
- vips_libname = 'libvips-42.dll'
464
- else
465
- vips_libname = 'vips'
466
- end
467
-
468
- ffi_lib vips_libname
573
+ ffi_lib library_name("vips", 42)
469
574
 
470
575
  LOG_DOMAIN = "VIPS"
471
- GLib::set_log_domain LOG_DOMAIN
576
+ GLib.set_log_domain LOG_DOMAIN
472
577
 
473
578
  typedef :ulong, :GType
474
579
 
@@ -482,9 +587,9 @@ module Vips
482
587
  def initialize msg = nil
483
588
  if msg
484
589
  @details = msg
485
- elsif Vips::vips_error_buffer != ""
486
- @details = Vips::vips_error_buffer
487
- Vips::vips_error_clear
590
+ elsif Vips.vips_error_buffer != ""
591
+ @details = Vips.vips_error_buffer
592
+ Vips.vips_error_clear
488
593
  else
489
594
  @details = nil
490
595
  end
@@ -494,7 +599,7 @@ module Vips
494
599
  #
495
600
  # @return [String] The error message
496
601
  def to_s
497
- if @details != nil
602
+ if !@details.nil?
498
603
  @details
499
604
  else
500
605
  super.to_s
@@ -504,8 +609,8 @@ module Vips
504
609
 
505
610
  attach_function :vips_init, [:string], :int
506
611
 
507
- if Vips::vips_init($0) != 0
508
- throw Vips::get_error
612
+ if Vips.vips_init($0) != 0
613
+ throw Vips.get_error
509
614
  end
510
615
 
511
616
  # don't use at_exit to call vips_shutdown, it causes problems with fork, and
@@ -569,7 +674,7 @@ module Vips
569
674
  # Don't use this, instead change GLib::logger.level.
570
675
  def self.set_debug debug
571
676
  if debug
572
- GLib::logger.level = Logger::DEBUG
677
+ GLib.logger.level = Logger::DEBUG
573
678
  end
574
679
  end
575
680
 
@@ -591,30 +696,37 @@ module Vips
591
696
  # vips_foreign_get_suffixes() was added in libvips 8.8
592
697
  return [] unless Vips.respond_to? :vips_foreign_get_suffixes
593
698
 
594
- array = Vips::vips_foreign_get_suffixes
699
+ array = Vips.vips_foreign_get_suffixes
595
700
 
596
701
  names = []
597
702
  p = array
598
703
  until (q = p.read_pointer).null?
599
704
  suff = q.read_string
600
- GLib::g_free q
705
+ GLib.g_free q
601
706
  names << suff unless names.include? suff
602
707
  p += FFI::Type::POINTER.size
603
708
  end
604
- GLib::g_free array
709
+ GLib.g_free array
605
710
 
606
711
  names
607
712
  end
608
713
 
609
- LIBRARY_VERSION = Vips::version_string
714
+ LIBRARY_VERSION = Vips.version_string
610
715
 
611
716
  # libvips has this arbitrary number as a sanity-check upper bound on image
612
- # size. It's sometimes useful for know whan calculating image ratios.
717
+ # size. It's sometimes useful to know when calculating scale factors.
613
718
  MAX_COORD = 10000000
614
719
  end
615
720
 
616
- require 'vips/object'
617
- require 'vips/operation'
618
- require 'vips/image'
619
- require 'vips/interpolate'
620
- require 'vips/version'
721
+ require "vips/object"
722
+ require "vips/operation"
723
+ require "vips/image"
724
+ require "vips/mutableimage"
725
+ require "vips/interpolate"
726
+ require "vips/region"
727
+ require "vips/version"
728
+ require "vips/connection"
729
+ require "vips/source"
730
+ require "vips/sourcecustom"
731
+ require "vips/target"
732
+ require "vips/targetcustom"