vips 8.8.4 → 8.9.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +3 -1
- data/example/connection.rb +17 -0
- data/example/progress.rb +30 -0
- data/lib/vips.rb +91 -19
- data/lib/vips/connection.rb +46 -0
- data/lib/vips/gobject.rb +9 -1
- data/lib/vips/gvalue.rb +13 -1
- data/lib/vips/image.rb +226 -158
- data/lib/vips/object.rb +117 -5
- data/lib/vips/operation.rb +156 -80
- data/lib/vips/region.rb +73 -0
- data/lib/vips/source.rb +89 -0
- data/lib/vips/sourcecustom.rb +90 -0
- data/lib/vips/target.rb +87 -0
- data/lib/vips/targetcustom.rb +78 -0
- data/lib/vips/version.rb +1 -1
- metadata +11 -4
- data/CHANGELOG.md +0 -273
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5603f19612f6051e2ec146f82ef9ac652b0790a1f00499fcea3d27eb4141c144
|
4
|
+
data.tar.gz: 3ad98dc9631a08e364181f4edc10716059e997cb8a86c507e61d1d46a1cfe907
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccef89e9e98babf11c0b07073700c0406cc296c6b2a6f3f92ee87b1fbb89ac17edf32fc48f4366b3f776e1ca239174c1147fa457c1362eb2ca3883fb3b0acf2d
|
7
|
+
data.tar.gz: 9970c5801392bf405dc75f2b8e3edc174b597d90d3e1e184b08c7a9362ba0feea0c9d68bad012a924f390a776ef36a78160d7364da637e001f1660742052543f
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# Vips
|
2
2
|
|
3
|
+
Programs that use `vips` don't manipulate images directly, instead they create pipelines of image processing operations building on a source image. When the end of the pipe is connected to a destination, the whole pipeline executes at once, streaming the image in parallel from source to destination a section at a time. Because `ruby-vips` is parallel, it's quick, and because it doesn't need to keep entire images in memory, it's light.
|
4
|
+
|
3
5
|
This gem is a backwards compatible fork of `ruby-vips` but also includes (and compiles) the [libvips] source code.
|
4
6
|
|
5
7
|
[](http://travis-ci.org/ioquatix/vips)
|
6
8
|
|
7
|
-
[libvips]: https://
|
9
|
+
[libvips]: https://libvips.github.io/libvips
|
8
10
|
|
9
11
|
## Installation
|
10
12
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
|
5
|
+
file = File.open ARGV[0], "rb"
|
6
|
+
source = Vips::SourceCustom.new
|
7
|
+
source.on_read { |length| file.read length }
|
8
|
+
# this method is optional
|
9
|
+
# source.on_seek { |offset, whence| file.seek(offset, whence) }
|
10
|
+
|
11
|
+
dest = File.open ARGV[1], "wb"
|
12
|
+
target = Vips::TargetCustom.new
|
13
|
+
target.on_write { |chunk| dest.write(chunk) }
|
14
|
+
target.on_finish { dest.close }
|
15
|
+
|
16
|
+
image = Vips::Image.new_from_source source, "", access: :sequential
|
17
|
+
image.write_to_target target, ".png"
|
data/example/progress.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
|
5
|
+
image = Vips::Image.black 1, 100000
|
6
|
+
image.set_progress true
|
7
|
+
|
8
|
+
def progress_to_s(name, progress)
|
9
|
+
puts "#{name}:"
|
10
|
+
puts " progress.run = #{progress[:run]}"
|
11
|
+
puts " progress.eta = #{progress[:eta]}"
|
12
|
+
puts " progress.tpels = #{progress[:tpels]}"
|
13
|
+
puts " progress.npels = #{progress[:npels]}"
|
14
|
+
puts " progress.percent = #{progress[:percent]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
image.signal_connect :preeval do |progress|
|
18
|
+
progress_to_s("preeval", progress)
|
19
|
+
end
|
20
|
+
|
21
|
+
image.signal_connect :eval do |progress|
|
22
|
+
progress_to_s("eval", progress)
|
23
|
+
image.set_kill(true) if progress[:percent] > 50
|
24
|
+
end
|
25
|
+
|
26
|
+
image.signal_connect :posteval do |progress|
|
27
|
+
progress_to_s("posteval", progress)
|
28
|
+
end
|
29
|
+
|
30
|
+
image.avg
|
data/lib/vips.rb
CHANGED
@@ -10,6 +10,29 @@ require 'logger'
|
|
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
|
@@ -19,13 +42,7 @@ module GLib
|
|
19
42
|
|
20
43
|
extend FFI::Library
|
21
44
|
|
22
|
-
|
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
|
|
@@ -117,13 +134,7 @@ end
|
|
117
134
|
module GObject
|
118
135
|
extend FFI::Library
|
119
136
|
|
120
|
-
|
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
|
@@ -155,7 +166,7 @@ require 'vips/gobject'
|
|
155
166
|
require 'vips/gvalue'
|
156
167
|
|
157
168
|
# This module provides a binding for the [libvips image processing
|
158
|
-
# library](https://
|
169
|
+
# library](https://libvips.github.io/libvips/).
|
159
170
|
#
|
160
171
|
# # Example
|
161
172
|
#
|
@@ -201,6 +212,9 @@ require 'vips/gvalue'
|
|
201
212
|
# memory buffers, create images that wrap C-style memory arrays, or make images
|
202
213
|
# from constants.
|
203
214
|
#
|
215
|
+
# Use {Source} and {Image.new_from_source} to load images from any data
|
216
|
+
# source, for example URIs.
|
217
|
+
#
|
204
218
|
# The next line:
|
205
219
|
#
|
206
220
|
# ```ruby
|
@@ -242,6 +256,9 @@ require 'vips/gvalue'
|
|
242
256
|
# suffix. You can also write formatted images to memory buffers, or dump
|
243
257
|
# image data to a raw memory array.
|
244
258
|
#
|
259
|
+
# Use {Target} and {Image#write_to_target} to write formatted images to
|
260
|
+
# any data sink, for example URIs.
|
261
|
+
#
|
245
262
|
# # How it works
|
246
263
|
#
|
247
264
|
# The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips
|
@@ -393,12 +410,12 @@ require 'vips/gvalue'
|
|
393
410
|
# # Automatic YARD documentation
|
394
411
|
#
|
395
412
|
# The bulk of these API docs are generated automatically by
|
396
|
-
# {Vips::
|
413
|
+
# {Vips::Yard::generate}. It examines
|
397
414
|
# libvips and writes a summary of each operation and the arguments and options
|
398
415
|
# that that operation expects.
|
399
416
|
#
|
400
417
|
# Use the [C API
|
401
|
-
# docs](https://
|
418
|
+
# docs](https://libvips.github.io/libvips/API/current)
|
402
419
|
# for more detail.
|
403
420
|
#
|
404
421
|
# # Enums
|
@@ -423,6 +440,55 @@ require 'vips/gvalue'
|
|
423
440
|
# If you want to avoid the copies, you'll need to call drawing operations
|
424
441
|
# yourself.
|
425
442
|
#
|
443
|
+
# # Progress
|
444
|
+
#
|
445
|
+
# You can attach signal handlers to images to watch computation progress. For
|
446
|
+
# example:
|
447
|
+
#
|
448
|
+
# ```ruby
|
449
|
+
# image = Vips::Image.black 1, 100000
|
450
|
+
# image.set_progress true
|
451
|
+
#
|
452
|
+
# def progress_to_s(name, progress)
|
453
|
+
# puts "#{name}:"
|
454
|
+
# puts " run = #{progress[:run]}"
|
455
|
+
# puts " eta = #{progress[:eta]}"
|
456
|
+
# puts " tpels = #{progress[:tpels]}"
|
457
|
+
# puts " npels = #{progress[:npels]}"
|
458
|
+
# puts " percent = #{progress[:percent]}"
|
459
|
+
# end
|
460
|
+
#
|
461
|
+
# image.signal_connect :preeval do |progress|
|
462
|
+
# progress_to_s("preeval", progress)
|
463
|
+
# end
|
464
|
+
#
|
465
|
+
# image.signal_connect :eval do |progress|
|
466
|
+
# progress_to_s("eval", progress)
|
467
|
+
# image.set_kill(true) if progress[:percent] > 50
|
468
|
+
# end
|
469
|
+
#
|
470
|
+
# image.signal_connect :posteval do |progress|
|
471
|
+
# progress_to_s("posteval", progress)
|
472
|
+
# end
|
473
|
+
#
|
474
|
+
# image.avg
|
475
|
+
# ```
|
476
|
+
#
|
477
|
+
# The `:eval` signal will fire for every tile that is processed. You can stop
|
478
|
+
# progress with {Image#set_kill} and processing will end with an exception.
|
479
|
+
#
|
480
|
+
# User streams
|
481
|
+
#
|
482
|
+
# You can make your own input and output stream objects with {SourceCustom} and
|
483
|
+
# {TargetCustom}. For example:
|
484
|
+
#
|
485
|
+
# ```ruby
|
486
|
+
# file = File.open "some/file", "rb"
|
487
|
+
# source = Vips::SourceCustom.new
|
488
|
+
# source.on_read { |length| file.read length }
|
489
|
+
# image = Vips::Image.new_from_source source, "", access: "sequential"
|
490
|
+
# ```
|
491
|
+
#
|
426
492
|
# # Overloads
|
427
493
|
#
|
428
494
|
# The wrapper defines the usual set of arithmetic, boolean and relational
|
@@ -462,7 +528,7 @@ module Vips
|
|
462
528
|
if FFI::Platform.windows?
|
463
529
|
vips_libname = 'libvips-42.dll'
|
464
530
|
else
|
465
|
-
vips_libname = File.expand_path(FFI
|
531
|
+
vips_libname = File.expand_path(FFI.map_library_name('vips'), __dir__)
|
466
532
|
end
|
467
533
|
|
468
534
|
ffi_lib vips_libname
|
@@ -609,7 +675,7 @@ module Vips
|
|
609
675
|
LIBRARY_VERSION = Vips::version_string
|
610
676
|
|
611
677
|
# libvips has this arbitrary number as a sanity-check upper bound on image
|
612
|
-
# size. It's sometimes useful
|
678
|
+
# size. It's sometimes useful to know when calculating scale factors.
|
613
679
|
MAX_COORD = 10000000
|
614
680
|
end
|
615
681
|
|
@@ -617,4 +683,10 @@ require 'vips/object'
|
|
617
683
|
require 'vips/operation'
|
618
684
|
require 'vips/image'
|
619
685
|
require 'vips/interpolate'
|
686
|
+
require 'vips/region'
|
620
687
|
require 'vips/version'
|
688
|
+
require 'vips/connection'
|
689
|
+
require 'vips/source'
|
690
|
+
require 'vips/sourcecustom'
|
691
|
+
require 'vips/target'
|
692
|
+
require 'vips/targetcustom'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# This module provides an interface to the top level bits of libvips
|
2
|
+
# via ruby-ffi.
|
3
|
+
#
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
module Vips
|
10
|
+
if Vips::at_least_libvips?(8, 9)
|
11
|
+
attach_function :vips_connection_filename, [:pointer], :string
|
12
|
+
attach_function :vips_connection_nick, [:pointer], :string
|
13
|
+
end
|
14
|
+
|
15
|
+
# Abstract base class for connections.
|
16
|
+
class Connection < Vips::Object
|
17
|
+
# The layout of the VipsRegion struct.
|
18
|
+
module ConnectionLayout
|
19
|
+
def self.included(base)
|
20
|
+
base.class_eval do
|
21
|
+
layout :parent, Vips::Object::Struct
|
22
|
+
# rest opaque
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Struct < Vips::Object::Struct
|
28
|
+
include ConnectionLayout
|
29
|
+
end
|
30
|
+
|
31
|
+
class ManagedStruct < Vips::Object::ManagedStruct
|
32
|
+
include ConnectionLayout
|
33
|
+
end
|
34
|
+
|
35
|
+
# Get any filename associated with a connection, or nil.
|
36
|
+
def filename
|
37
|
+
Vips::vips_connection_filename self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get a nickname (short description) of a connection that could be shown to
|
41
|
+
# the user.
|
42
|
+
def nick
|
43
|
+
Vips::vips_connection_nick self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/vips/gobject.rb
CHANGED
@@ -73,6 +73,9 @@ module GObject
|
|
73
73
|
def initialize ptr
|
74
74
|
# GLib::logger.debug("GObject::GObject.initialize") {"ptr = #{ptr}"}
|
75
75
|
@struct = ffi_managed_struct.new ptr
|
76
|
+
|
77
|
+
# sometimes we need to keep refs across C calls ... hide them here
|
78
|
+
@references = []
|
76
79
|
end
|
77
80
|
|
78
81
|
# access to the casting struct for this class
|
@@ -111,8 +114,13 @@ module GObject
|
|
111
114
|
layout :value, GParamSpec.ptr
|
112
115
|
end
|
113
116
|
|
114
|
-
attach_function :g_param_spec_get_blurb, [
|
117
|
+
attach_function :g_param_spec_get_blurb, [:pointer], :string
|
115
118
|
|
116
119
|
attach_function :g_object_ref, [:pointer], :void
|
117
120
|
attach_function :g_object_unref, [:pointer], :void
|
121
|
+
|
122
|
+
# we just use one gcallback type for every signal, hopefully this is OK
|
123
|
+
callback :gcallback, [:pointer], :void
|
124
|
+
attach_function :g_signal_connect_data,
|
125
|
+
[:pointer, :string, :gcallback, :pointer, :pointer, :int], :long
|
118
126
|
end
|
data/lib/vips/gvalue.rb
CHANGED
@@ -13,6 +13,8 @@ module GObject
|
|
13
13
|
# gvalue.init GObject::GDOUBLE_TYPE
|
14
14
|
# gvalue.set 3.1415
|
15
15
|
# value = gvalue.get
|
16
|
+
# # optional -- drop any ref the gvalue had
|
17
|
+
# gvalue.unset
|
16
18
|
# ```
|
17
19
|
#
|
18
20
|
# Lifetime is managed automatically. It doesn't know about all GType values,
|
@@ -27,7 +29,9 @@ module GObject
|
|
27
29
|
value = value.to_s if value.is_a? Symbol
|
28
30
|
|
29
31
|
if value.is_a? String
|
30
|
-
|
32
|
+
# libvips expects "-" as a separator in enum names, but "_" is more
|
33
|
+
# convenient for ruby, eg. :b_w
|
34
|
+
value = Vips::vips_enum_from_nick "ruby-vips", gtype, value.tr("_", "-")
|
31
35
|
if value == -1
|
32
36
|
raise Vips::Error
|
33
37
|
end
|
@@ -241,6 +245,14 @@ module GObject
|
|
241
245
|
|
242
246
|
return result
|
243
247
|
end
|
248
|
+
|
249
|
+
# Clear the thing held by a GValue.
|
250
|
+
#
|
251
|
+
# This happens automatically when a GValue is GCed, but this method can be
|
252
|
+
# handy if you need to drop a reference explicitly for some reason.
|
253
|
+
def unset
|
254
|
+
::GObject::g_value_unset self
|
255
|
+
end
|
244
256
|
end
|
245
257
|
|
246
258
|
attach_function :g_value_init, [GValue.ptr, :GType], :void
|
data/lib/vips/image.rb
CHANGED
@@ -14,6 +14,9 @@ module Vips
|
|
14
14
|
|
15
15
|
attach_function :vips_image_copy_memory, [:pointer], :pointer
|
16
16
|
|
17
|
+
attach_function :vips_image_set_progress, [:pointer, :bool], :void
|
18
|
+
attach_function :vips_image_set_kill, [:pointer, :bool], :void
|
19
|
+
|
17
20
|
attach_function :vips_filename_get_filename, [:string], :pointer
|
18
21
|
attach_function :vips_filename_get_options, [:string], :pointer
|
19
22
|
|
@@ -22,6 +25,11 @@ module Vips
|
|
22
25
|
attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
|
23
26
|
attach_function :vips_foreign_find_save_buffer, [:string], :string
|
24
27
|
|
28
|
+
if Vips::at_least_libvips?(8, 9)
|
29
|
+
attach_function :vips_foreign_find_load_source, [:pointer], :string
|
30
|
+
attach_function :vips_foreign_find_save_target, [:string], :string
|
31
|
+
end
|
32
|
+
|
25
33
|
attach_function :vips_image_write_to_memory,
|
26
34
|
[:pointer, SizeStruct.ptr], :pointer
|
27
35
|
|
@@ -29,20 +37,14 @@ module Vips
|
|
29
37
|
attach_function :vips_image_get,
|
30
38
|
[:pointer, :string, GObject::GValue.ptr], :int
|
31
39
|
|
32
|
-
|
33
|
-
begin
|
40
|
+
if Vips::at_least_libvips?(8, 5)
|
34
41
|
attach_function :vips_image_get_fields, [:pointer], :pointer
|
35
|
-
|
36
|
-
nil
|
42
|
+
attach_function :vips_image_hasalpha, [:pointer], :int
|
37
43
|
end
|
38
44
|
|
39
|
-
# vips_addalpha was added in libvips 8.6
|
40
45
|
if Vips::at_least_libvips?(8, 6)
|
41
46
|
attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
|
42
47
|
end
|
43
|
-
if Vips::at_least_libvips?(8, 5)
|
44
|
-
attach_function :vips_image_hasalpha, [:pointer], :int
|
45
|
-
end
|
46
48
|
|
47
49
|
attach_function :vips_image_set,
|
48
50
|
[:pointer, :string, GObject::GValue.ptr], :void
|
@@ -53,6 +55,8 @@ module Vips
|
|
53
55
|
|
54
56
|
attach_function :nickname_find, :vips_nickname_find, [:GType], :string
|
55
57
|
|
58
|
+
attach_function :vips_image_invalidate_all, [:pointer], :void
|
59
|
+
|
56
60
|
# turn a raw pointer that must be freed into a self-freeing Ruby string
|
57
61
|
def self.p2str(pointer)
|
58
62
|
pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
|
@@ -67,6 +71,10 @@ module Vips
|
|
67
71
|
class Image < Vips::Object
|
68
72
|
alias_method :parent_get_typeof, :get_typeof
|
69
73
|
|
74
|
+
def close
|
75
|
+
Vips.vips_image_invalidate_all(self)
|
76
|
+
end
|
77
|
+
|
70
78
|
private
|
71
79
|
|
72
80
|
# the layout of the VipsImage struct
|
@@ -115,7 +123,7 @@ module Vips
|
|
115
123
|
|
116
124
|
unless Image::complex? image.format
|
117
125
|
if image.bands % 2 != 0
|
118
|
-
raise Error, "not an even number of bands"
|
126
|
+
raise Vips::Error, "not an even number of bands"
|
119
127
|
end
|
120
128
|
|
121
129
|
unless Image::float? image.format
|
@@ -145,34 +153,6 @@ module Vips
|
|
145
153
|
end
|
146
154
|
end
|
147
155
|
|
148
|
-
# Write can fail due to no file descriptors and memory can fill if
|
149
|
-
# large objects are not collected fairly soon. We can't try a
|
150
|
-
# write and GC and retry on fail, since the write may take a
|
151
|
-
# long time and may not be repeatable.
|
152
|
-
#
|
153
|
-
# GCing before every write would have a horrible effect on
|
154
|
-
# performance, so as a compromise we GC every @@gc_interval writes.
|
155
|
-
#
|
156
|
-
# ruby2.1 introduced a generational GC which is fast enough to be
|
157
|
-
# able to GC on every write.
|
158
|
-
|
159
|
-
@@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
|
160
|
-
|
161
|
-
@@gc_interval = 100
|
162
|
-
@@gc_countdown = @@gc_interval
|
163
|
-
|
164
|
-
def write_gc
|
165
|
-
if @@generational_gc
|
166
|
-
GC.start full_mark: false
|
167
|
-
else
|
168
|
-
@@gc_countdown -= 1
|
169
|
-
if @@gc_countdown < 0
|
170
|
-
@@gc_countdown = @@gc_interval
|
171
|
-
GC.start
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
156
|
public
|
177
157
|
|
178
158
|
def inspect
|
@@ -219,13 +199,13 @@ module Vips
|
|
219
199
|
# load options, for example:
|
220
200
|
#
|
221
201
|
# ```
|
222
|
-
# image = Vips::new_from_file "fred.jpg[shrink=2]"
|
202
|
+
# image = Vips::Image.new_from_file "fred.jpg[shrink=2]"
|
223
203
|
# ```
|
224
204
|
#
|
225
205
|
# You can also supply options as a hash, for example:
|
226
206
|
#
|
227
207
|
# ```
|
228
|
-
# image = Vips::new_from_file "fred.jpg", shrink: 2
|
208
|
+
# image = Vips::Image.new_from_file "fred.jpg", shrink: 2
|
229
209
|
# ```
|
230
210
|
#
|
231
211
|
# The full set of options available depend upon the load operation that
|
@@ -296,11 +276,50 @@ module Vips
|
|
296
276
|
# @return [Image] the loaded image
|
297
277
|
def self.new_from_buffer data, option_string, **opts
|
298
278
|
loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
|
299
|
-
raise Vips::Error if loader
|
279
|
+
raise Vips::Error if loader.nil?
|
300
280
|
|
301
281
|
Vips::Operation.call loader, [data], opts, option_string
|
302
282
|
end
|
303
283
|
|
284
|
+
# Create a new {Image} from a source. Load options may be passed as
|
285
|
+
# strings or appended as a hash. For example:
|
286
|
+
#
|
287
|
+
# ```
|
288
|
+
# source = Vips::Source.new_from_file("k2.jpg")
|
289
|
+
# image = Vips::Image.new_from_source source, "shrink=2"
|
290
|
+
# ```
|
291
|
+
#
|
292
|
+
# or alternatively:
|
293
|
+
#
|
294
|
+
# ```
|
295
|
+
# image = Vips::Image.new_from_source source, "", shrink: 2
|
296
|
+
# ```
|
297
|
+
#
|
298
|
+
# The options available depend on the file format. Try something like:
|
299
|
+
#
|
300
|
+
# ```
|
301
|
+
# $ vips jpegload_source
|
302
|
+
# ```
|
303
|
+
#
|
304
|
+
# at the command-line to see the available options. Not all loaders
|
305
|
+
# support load from source, but at least JPEG, PNG and
|
306
|
+
# TIFF images will work.
|
307
|
+
#
|
308
|
+
# Loading is fast: only enough data is read to be able to fill
|
309
|
+
# out the header. Pixels will only be read and decompressed when they are
|
310
|
+
# needed.
|
311
|
+
#
|
312
|
+
# @param source [Vips::Source] the source to load from
|
313
|
+
# @param option_string [String] load options as a string
|
314
|
+
# @macro vips.loadopts
|
315
|
+
# @return [Image] the loaded image
|
316
|
+
def self.new_from_source source, option_string, **opts
|
317
|
+
loader = Vips::vips_foreign_find_load_source source
|
318
|
+
raise Vips::Error if loader.nil?
|
319
|
+
|
320
|
+
Vips::Operation.call loader, [source], opts, option_string
|
321
|
+
end
|
322
|
+
|
304
323
|
def self.matrix_from_array width, height, array
|
305
324
|
ptr = FFI::MemoryPointer.new :double, array.length
|
306
325
|
ptr.write_array_of_double array
|
@@ -317,13 +336,13 @@ module Vips
|
|
317
336
|
# For example:
|
318
337
|
#
|
319
338
|
# ```
|
320
|
-
# image = Vips::new_from_array [1, 2, 3]
|
339
|
+
# image = Vips::Image.new_from_array [1, 2, 3]
|
321
340
|
# ```
|
322
341
|
#
|
323
342
|
# or
|
324
343
|
#
|
325
344
|
# ```
|
326
|
-
# image = Vips::new_from_array [
|
345
|
+
# image = Vips::Image.new_from_array [
|
327
346
|
# [-1, -1, -1],
|
328
347
|
# [-1, 16, -1],
|
329
348
|
# [-1, -1, -1]], 8
|
@@ -426,8 +445,6 @@ module Vips
|
|
426
445
|
end
|
427
446
|
|
428
447
|
Vips::Operation.call saver, [self, filename], opts, option_string
|
429
|
-
|
430
|
-
write_gc
|
431
448
|
end
|
432
449
|
|
433
450
|
# Write this image to a memory buffer. Save options may be encoded in
|
@@ -460,17 +477,52 @@ module Vips
|
|
460
477
|
option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
|
461
478
|
saver = Vips::vips_foreign_find_save_buffer filename
|
462
479
|
if saver == nil
|
463
|
-
raise Vips::Error, "No known saver for '#{filename}'."
|
480
|
+
raise Vips::Error, "No known buffer saver for '#{filename}'."
|
464
481
|
end
|
465
482
|
|
466
483
|
buffer = Vips::Operation.call saver, [self], opts, option_string
|
467
484
|
raise Vips::Error if buffer == nil
|
468
485
|
|
469
|
-
write_gc
|
470
|
-
|
471
486
|
return buffer
|
472
487
|
end
|
473
488
|
|
489
|
+
# Write this image to a target. Save options may be encoded in
|
490
|
+
# the format_string or given as a hash. For example:
|
491
|
+
#
|
492
|
+
# ```ruby
|
493
|
+
# target = Vips::Target.new_to_file "k2.jpg"
|
494
|
+
# image.write_to_target target, ".jpg[Q=90]"
|
495
|
+
# ```
|
496
|
+
#
|
497
|
+
# or equivalently:
|
498
|
+
#
|
499
|
+
# ```ruby
|
500
|
+
# image.write_to_target target, ".jpg", Q: 90
|
501
|
+
# ```
|
502
|
+
#
|
503
|
+
# The full set of save options depend on the selected saver. Try
|
504
|
+
# something like:
|
505
|
+
#
|
506
|
+
# ```
|
507
|
+
# $ vips jpegsave_target
|
508
|
+
# ```
|
509
|
+
#
|
510
|
+
# to see all the available options for JPEG save.
|
511
|
+
#
|
512
|
+
# @param target [Vips::Target] the target to write to
|
513
|
+
# @param format_string [String] save format plus string options
|
514
|
+
# @macro vips.saveopts
|
515
|
+
def write_to_target target, format_string, **opts
|
516
|
+
filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
|
517
|
+
option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
|
518
|
+
saver = Vips::vips_foreign_find_save_target filename
|
519
|
+
if saver == nil
|
520
|
+
raise Vips::Error, "No known target saver for '#{filename}'."
|
521
|
+
end
|
522
|
+
|
523
|
+
Vips::Operation.call saver, [self, target], opts, option_string
|
524
|
+
end
|
525
|
+
|
474
526
|
# Write this image to a large memory buffer.
|
475
527
|
#
|
476
528
|
# @return [String] the pixels as a huge binary string
|
@@ -485,6 +537,28 @@ module Vips
|
|
485
537
|
ptr.get_bytes 0, len[:value]
|
486
538
|
end
|
487
539
|
|
540
|
+
# Turn progress signalling on and off.
|
541
|
+
#
|
542
|
+
# If this is on, the most-downstream image from this image will issue
|
543
|
+
# progress signals.
|
544
|
+
#
|
545
|
+
# @see Object#signal_connect
|
546
|
+
# @param state [Boolean] progress signalling state
|
547
|
+
def set_progress state
|
548
|
+
Vips::vips_image_set_progress self, state
|
549
|
+
end
|
550
|
+
|
551
|
+
# Kill computation of this time.
|
552
|
+
#
|
553
|
+
# Set true to stop computation of this image. You can call this from a
|
554
|
+
# progress handler, for example.
|
555
|
+
#
|
556
|
+
# @see Object#signal_connect
|
557
|
+
# @param kill [Boolean] stop computation
|
558
|
+
def set_kill kill
|
559
|
+
Vips::vips_image_set_kill self, kill
|
560
|
+
end
|
561
|
+
|
488
562
|
# Get the `GType` of a metadata field. The result is 0 if no such field
|
489
563
|
# exists.
|
490
564
|
#
|
@@ -523,10 +597,11 @@ module Vips
|
|
523
597
|
end
|
524
598
|
|
525
599
|
gvalue = GObject::GValue.alloc
|
526
|
-
|
527
|
-
|
600
|
+
raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
|
601
|
+
result = gvalue.get
|
602
|
+
gvalue.unset
|
528
603
|
|
529
|
-
|
604
|
+
result
|
530
605
|
end
|
531
606
|
|
532
607
|
# Get the names of all fields on an image. Use this to loop over all
|
@@ -571,6 +646,7 @@ module Vips
|
|
571
646
|
gvalue.init gtype
|
572
647
|
gvalue.set value
|
573
648
|
Vips::vips_image_set self, name, gvalue
|
649
|
+
gvalue.unset
|
574
650
|
end
|
575
651
|
|
576
652
|
# Set the value of a metadata item on an image. The metadata item must
|
@@ -1059,7 +1135,7 @@ module Vips
|
|
1059
1135
|
# @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
|
1060
1136
|
# @option opts [Boolean] :premultiplied Images have premultiplied alpha
|
1061
1137
|
# @return [Image] blended image
|
1062
|
-
def composite overlay, mode, **
|
1138
|
+
def composite overlay, mode, **options
|
1063
1139
|
unless overlay.is_a? Array
|
1064
1140
|
overlay = [overlay]
|
1065
1141
|
end
|
@@ -1071,7 +1147,7 @@ module Vips
|
|
1071
1147
|
GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
|
1072
1148
|
end
|
1073
1149
|
|
1074
|
-
Vips::Image.composite([self] + overlay, mode,
|
1150
|
+
Vips::Image.composite([self] + overlay, mode, **options)
|
1075
1151
|
end
|
1076
1152
|
|
1077
1153
|
# Return the coordinates of the image maximum.
|
@@ -1320,30 +1396,27 @@ module Vips
|
|
1320
1396
|
#
|
1321
1397
|
# @param opts [Hash] Set of options
|
1322
1398
|
# @return [Vips::Image] Output image
|
1323
|
-
def scaleimage **
|
1324
|
-
Vips::Image.scale self,
|
1399
|
+
def scaleimage **options
|
1400
|
+
Vips::Image.scale self, **options
|
1325
1401
|
end
|
1326
1402
|
end
|
1327
1403
|
end
|
1328
1404
|
|
1329
1405
|
module Vips
|
1330
|
-
# This
|
1406
|
+
# This module generates yard comments for all the dynamically bound
|
1331
1407
|
# vips operations.
|
1332
1408
|
#
|
1333
1409
|
# Regenerate with something like:
|
1334
1410
|
#
|
1335
1411
|
# ```
|
1336
1412
|
# $ ruby > methods.rb
|
1337
|
-
# require 'vips'; Vips::
|
1413
|
+
# require 'vips'; Vips::Yard.generate
|
1338
1414
|
# ^D
|
1339
1415
|
# ```
|
1340
1416
|
|
1341
|
-
|
1342
|
-
# these have hand-written methods, see above
|
1343
|
-
no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
|
1344
|
-
|
1417
|
+
module Yard
|
1345
1418
|
# map gobject's type names to Ruby
|
1346
|
-
|
1419
|
+
MAP_GO_TO_RUBY = {
|
1347
1420
|
"gboolean" => "Boolean",
|
1348
1421
|
"gint" => "Integer",
|
1349
1422
|
"gdouble" => "Float",
|
@@ -1351,116 +1424,99 @@ module Vips
|
|
1351
1424
|
"gchararray" => "String",
|
1352
1425
|
"VipsImage" => "Vips::Image",
|
1353
1426
|
"VipsInterpolate" => "Vips::Interpolate",
|
1427
|
+
"VipsConnection" => "Vips::Connection",
|
1428
|
+
"VipsSource" => "Vips::Source",
|
1429
|
+
"VipsTarget" => "Vips::Target",
|
1430
|
+
"VipsSourceCustom" => "Vips::SourceCustom",
|
1431
|
+
"VipsTargetCustom" => "Vips::TargetCustom",
|
1354
1432
|
"VipsArrayDouble" => "Array<Double>",
|
1355
1433
|
"VipsArrayInt" => "Array<Integer>",
|
1356
1434
|
"VipsArrayImage" => "Array<Image>",
|
1357
1435
|
"VipsArrayString" => "Array<String>",
|
1358
1436
|
}
|
1359
1437
|
|
1360
|
-
|
1361
|
-
|
1362
|
-
return if (op_flags & OPERATION_DEPRECATED) != 0
|
1363
|
-
return if no_generate.include? nickname
|
1364
|
-
|
1365
|
-
description = Vips::vips_object_get_description op
|
1366
|
-
|
1367
|
-
# find and classify all the arguments the operator can take
|
1368
|
-
required_input = []
|
1369
|
-
optional_input = []
|
1370
|
-
required_output = []
|
1371
|
-
optional_output = []
|
1372
|
-
member_x = nil
|
1373
|
-
op.argument_map do |pspec, argument_class, _argument_instance|
|
1374
|
-
arg_flags = argument_class[:flags]
|
1375
|
-
next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
|
1376
|
-
next if (arg_flags & ARGUMENT_DEPRECATED) != 0
|
1377
|
-
|
1378
|
-
name = pspec[:name].tr("-", "_")
|
1379
|
-
# 'in' as a param name confuses yard
|
1380
|
-
name = "im" if name == "in"
|
1381
|
-
gtype = pspec[:value_type]
|
1382
|
-
fundamental = GObject::g_type_fundamental gtype
|
1383
|
-
type_name = GObject::g_type_name gtype
|
1384
|
-
if map_go_to_ruby.include? type_name
|
1385
|
-
type_name = map_go_to_ruby[type_name]
|
1386
|
-
end
|
1387
|
-
if fundamental == GObject::GFLAGS_TYPE ||
|
1388
|
-
fundamental == GObject::GENUM_TYPE
|
1389
|
-
type_name = "Vips::" + type_name[/Vips(.*)/, 1]
|
1390
|
-
end
|
1391
|
-
blurb = GObject::g_param_spec_get_blurb pspec
|
1392
|
-
value = {
|
1393
|
-
name: name,
|
1394
|
-
flags: arg_flags,
|
1395
|
-
gtype: gtype,
|
1396
|
-
type_name: type_name,
|
1397
|
-
blurb: blurb
|
1398
|
-
}
|
1399
|
-
|
1400
|
-
if (arg_flags & ARGUMENT_INPUT) != 0
|
1401
|
-
if (arg_flags & ARGUMENT_REQUIRED) != 0
|
1402
|
-
# note the first required input image, if any ... we
|
1403
|
-
# will be a method of this instance
|
1404
|
-
if !member_x && gtype == Vips::IMAGE_TYPE
|
1405
|
-
member_x = value
|
1406
|
-
else
|
1407
|
-
required_input << value
|
1408
|
-
end
|
1409
|
-
else
|
1410
|
-
optional_input << value
|
1411
|
-
end
|
1412
|
-
end
|
1438
|
+
# these have hand-written methods, see above
|
1439
|
+
NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
|
1413
1440
|
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1441
|
+
# these are aliased (appear under several names)
|
1442
|
+
ALIAS = ["crop"]
|
1443
|
+
|
1444
|
+
# turn a gtype into a ruby type name
|
1445
|
+
def self.gtype_to_ruby gtype
|
1446
|
+
fundamental = GObject::g_type_fundamental gtype
|
1447
|
+
type_name = GObject::g_type_name gtype
|
1448
|
+
|
1449
|
+
if MAP_GO_TO_RUBY.include? type_name
|
1450
|
+
type_name = MAP_GO_TO_RUBY[type_name]
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
if fundamental == GObject::GFLAGS_TYPE ||
|
1454
|
+
fundamental == GObject::GENUM_TYPE
|
1455
|
+
type_name = "Vips::" + type_name[/Vips(.*)/, 1]
|
1424
1456
|
end
|
1425
1457
|
|
1458
|
+
type_name
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
def self.generate_operation introspect
|
1462
|
+
return if (introspect.flags & OPERATION_DEPRECATED) != 0
|
1463
|
+
return if NO_GENERATE.include? introspect.name
|
1464
|
+
|
1465
|
+
method_args = introspect.method_args
|
1466
|
+
required_output = introspect.required_output
|
1467
|
+
optional_input = introspect.optional_input
|
1468
|
+
optional_output = introspect.optional_output
|
1469
|
+
|
1426
1470
|
print "# @!method "
|
1427
|
-
print "self." unless member_x
|
1428
|
-
print "#{
|
1429
|
-
print
|
1430
|
-
print ", " if
|
1471
|
+
print "self." unless introspect.member_x
|
1472
|
+
print "#{introspect.name}("
|
1473
|
+
print method_args.map{ |x| x[:yard_name] }.join(", ")
|
1474
|
+
print ", " if method_args.length > 0
|
1431
1475
|
puts "**opts)"
|
1432
1476
|
|
1433
|
-
puts "# #{description.capitalize}."
|
1477
|
+
puts "# #{introspect.description.capitalize}."
|
1478
|
+
|
1479
|
+
method_args.each do |details|
|
1480
|
+
yard_name = details[:yard_name]
|
1481
|
+
gtype = details[:gtype]
|
1482
|
+
blurb = details[:blurb]
|
1434
1483
|
|
1435
|
-
|
1436
|
-
puts "# @param #{arg[:name]} [#{arg[:type_name]}] #{arg[:blurb]}"
|
1484
|
+
puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
|
1437
1485
|
end
|
1438
1486
|
|
1439
1487
|
puts "# @param opts [Hash] Set of options"
|
1440
|
-
optional_input.each do |
|
1441
|
-
|
1442
|
-
|
1488
|
+
optional_input.each do |arg_name, details|
|
1489
|
+
yard_name = details[:yard_name]
|
1490
|
+
gtype = details[:gtype]
|
1491
|
+
blurb = details[:blurb]
|
1492
|
+
|
1493
|
+
puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
|
1494
|
+
"#{blurb}"
|
1443
1495
|
end
|
1444
|
-
optional_output.each do |
|
1445
|
-
|
1446
|
-
|
1496
|
+
optional_output.each do |arg_name, details|
|
1497
|
+
yard_name = details[:yard_name]
|
1498
|
+
gtype = details[:gtype]
|
1499
|
+
blurb = details[:blurb]
|
1500
|
+
|
1501
|
+
print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
|
1502
|
+
puts " Output #{blurb}"
|
1447
1503
|
end
|
1448
1504
|
|
1449
1505
|
print "# @return ["
|
1450
1506
|
if required_output.length == 0
|
1451
1507
|
print "nil"
|
1452
1508
|
elsif required_output.length == 1
|
1453
|
-
print required_output.first[:
|
1509
|
+
print gtype_to_ruby(required_output.first[:gtype])
|
1454
1510
|
else
|
1455
1511
|
print "Array<"
|
1456
|
-
print required_output.map
|
1512
|
+
print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
|
1457
1513
|
print ">"
|
1458
1514
|
end
|
1459
1515
|
if optional_output.length > 0
|
1460
1516
|
print ", Hash<Symbol => Object>"
|
1461
1517
|
end
|
1462
1518
|
print "] "
|
1463
|
-
print required_output.map
|
1519
|
+
print required_output.map{ |x| x[:blurb] }.join(", ")
|
1464
1520
|
if optional_output.length > 0
|
1465
1521
|
print ", " if required_output.length > 0
|
1466
1522
|
print "Hash of optional output items"
|
@@ -1470,30 +1526,42 @@ module Vips
|
|
1470
1526
|
puts ""
|
1471
1527
|
end
|
1472
1528
|
|
1473
|
-
|
1474
|
-
|
1529
|
+
def self.generate
|
1530
|
+
alias_gtypes = {}
|
1531
|
+
ALIAS.each do |name|
|
1532
|
+
gtype = Vips::type_find "VipsOperation", name
|
1533
|
+
alias_gtypes[gtype] = name
|
1534
|
+
end
|
1475
1535
|
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
nil
|
1536
|
+
generate_class = lambda do |gtype, _|
|
1537
|
+
if alias_gtypes.key? gtype
|
1538
|
+
name = alias_gtypes[gtype]
|
1539
|
+
else
|
1540
|
+
name = Vips::nickname_find gtype
|
1482
1541
|
end
|
1483
1542
|
|
1484
|
-
|
1485
|
-
|
1543
|
+
if name
|
1544
|
+
begin
|
1545
|
+
# can fail for abstract types
|
1546
|
+
introspect = Vips::Introspect.get_yard name
|
1547
|
+
rescue Vips::Error
|
1548
|
+
nil
|
1549
|
+
end
|
1486
1550
|
|
1487
|
-
|
1488
|
-
|
1551
|
+
generate_operation(introspect) if introspect
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
Vips::vips_type_map gtype, generate_class, nil
|
1555
|
+
end
|
1489
1556
|
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1557
|
+
puts "module Vips"
|
1558
|
+
puts " class Image"
|
1559
|
+
puts ""
|
1493
1560
|
|
1494
|
-
|
1561
|
+
generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
|
1495
1562
|
|
1496
|
-
|
1497
|
-
|
1563
|
+
puts " end"
|
1564
|
+
puts "end"
|
1565
|
+
end
|
1498
1566
|
end
|
1499
1567
|
end
|