ruby-vips 2.0.15 → 2.1.2

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