image_processing 1.4.0 → 1.5.0
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.
Potentially problematic release.
This version of image_processing might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/lib/image_processing/chainable.rb +12 -16
- data/lib/image_processing/mini_magick.rb +107 -74
- data/lib/image_processing/pipeline.rb +10 -11
- data/lib/image_processing/processor.rb +14 -11
- data/lib/image_processing/version.rb +1 -1
- data/lib/image_processing/vips.rb +70 -45
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b28b25634ec49e61835850b56f7c1c46b4d0e10ea99fbb6ef05c238e307d348
|
4
|
+
data.tar.gz: 348ff75f2a0779c085341248ac9cf4e9a931e984a3ba2e2e016c77dd63cc04e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85f39d0e536bddda22b5a79d5a0cc95496cf8eccccb536549ac209dbad3850b83add4797420a165582c666230015a1a4f969c0846e026f950a0d4dee1c5d00a8
|
7
|
+
data.tar.gz: e9b452b98df5b6f96cccf89b51a17b6ea3d06197adce46549d441fbd6822bcecac58cb9bf8e8ddc8ad14c3b144f8a8d703cb4d183d615ad349337430f6da9b7c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 1.5.0 (2018-07-10)
|
2
|
+
|
3
|
+
* [minimagick, vips] Add `#composite` method (@janko-m)
|
4
|
+
|
5
|
+
* [core] Allow operations to accept blocks (janko-m)
|
6
|
+
|
1
7
|
## 1.4.0 (2018-06-14)
|
2
8
|
|
3
9
|
* [minimagick] Accept RGB(A) arrays for color names for `:background` (@janko-m)
|
@@ -8,7 +14,7 @@
|
|
8
14
|
|
9
15
|
## 1.3.0 (2018-06-13)
|
10
16
|
|
11
|
-
* [minimagick, vips] Add `#rotate`
|
17
|
+
* [minimagick, vips] Add `#rotate` method (@janko-m)
|
12
18
|
|
13
19
|
* [vips] Use native `vips_image_hasalpha()` and `vips_addalpha()` functions in `#resize_and_pad` (@janko-m)
|
14
20
|
|
@@ -16,10 +16,6 @@ module ImageProcessing
|
|
16
16
|
branch saver: options
|
17
17
|
end
|
18
18
|
|
19
|
-
def custom(&block)
|
20
|
-
operation :custom, block
|
21
|
-
end
|
22
|
-
|
23
19
|
def apply(operations)
|
24
20
|
operations.inject(self) do |builder, (name, argument)|
|
25
21
|
if argument == true || argument == nil
|
@@ -32,15 +28,15 @@ module ImageProcessing
|
|
32
28
|
end
|
33
29
|
end
|
34
30
|
|
35
|
-
def method_missing(name, *args)
|
31
|
+
def method_missing(name, *args, &block)
|
36
32
|
return super if name.to_s.end_with?("?")
|
37
|
-
return send(name.to_s.chomp("!"), *args).call if name.to_s.end_with?("!")
|
33
|
+
return send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
|
38
34
|
|
39
|
-
operation
|
35
|
+
operation(name, *args, &block)
|
40
36
|
end
|
41
37
|
|
42
|
-
def operation(name, *args)
|
43
|
-
branch operations: [[name, args]]
|
38
|
+
def operation(name, *args, &block)
|
39
|
+
branch operations: [[name, args, *block]]
|
44
40
|
end
|
45
41
|
|
46
42
|
def call(file = nil, destination: nil, **call_options)
|
@@ -57,7 +53,7 @@ module ImageProcessing
|
|
57
53
|
options = options.merge(loader: options[:loader].merge(loader)) if loader
|
58
54
|
options = options.merge(saver: options[:saver].merge(saver)) if saver
|
59
55
|
options = options.merge(operations: options[:operations] + operations) if operations
|
60
|
-
options = options.merge(
|
56
|
+
options = options.merge(processor: self::Processor) unless self.is_a?(Builder)
|
61
57
|
options = options.merge(other_options)
|
62
58
|
|
63
59
|
options.freeze
|
@@ -66,12 +62,12 @@ module ImageProcessing
|
|
66
62
|
end
|
67
63
|
|
68
64
|
DEFAULT_OPTIONS = {
|
69
|
-
source:
|
70
|
-
loader:
|
71
|
-
saver:
|
72
|
-
format:
|
73
|
-
operations:
|
74
|
-
|
65
|
+
source: nil,
|
66
|
+
loader: {},
|
67
|
+
saver: {},
|
68
|
+
format: nil,
|
69
|
+
operations: [],
|
70
|
+
processor: nil,
|
75
71
|
}.freeze
|
76
72
|
end
|
77
73
|
end
|
@@ -16,88 +16,98 @@ module ImageProcessing
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class Processor < ImageProcessing::Processor
|
19
|
-
|
19
|
+
accumulator :magick, ::MiniMagick::Tool
|
20
|
+
|
20
21
|
SHARPEN_PARAMETERS = { radius: 0, sigma: 1 }
|
21
22
|
|
22
|
-
def
|
23
|
-
|
23
|
+
def self.load_image(path_or_magick, page: nil, geometry: nil, auto_orient: true, **options)
|
24
|
+
if path_or_magick.is_a?(::MiniMagick::Tool)
|
25
|
+
magick = path_or_magick
|
26
|
+
else
|
27
|
+
source_path = path_or_magick
|
28
|
+
magick = ::MiniMagick::Tool::Convert.new
|
29
|
+
|
30
|
+
Utils.apply_options(magick, options)
|
31
|
+
|
32
|
+
input_path = source_path
|
33
|
+
input_path += "[#{page}]" if page
|
34
|
+
input_path += "[#{geometry}]" if geometry
|
35
|
+
|
36
|
+
magick << input_path
|
37
|
+
end
|
38
|
+
|
39
|
+
magick.auto_orient if auto_orient
|
40
|
+
magick
|
24
41
|
end
|
25
42
|
|
26
|
-
def
|
27
|
-
|
43
|
+
def self.save_image(magick, destination_path, allow_splitting: false, **options)
|
44
|
+
Utils.apply_options(magick, options)
|
45
|
+
|
46
|
+
magick << destination_path
|
47
|
+
magick.call
|
48
|
+
|
49
|
+
Utils.disallow_split_layers!(destination_path) unless allow_splitting
|
50
|
+
end
|
51
|
+
|
52
|
+
def resize_to_limit(width, height, **options)
|
53
|
+
thumbnail("#{width}x#{height}>", **options)
|
28
54
|
end
|
29
55
|
|
30
|
-
def
|
31
|
-
thumbnail(
|
56
|
+
def resize_to_fit(width, height, **options)
|
57
|
+
thumbnail("#{width}x#{height}", **options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def resize_to_fill(width, height, gravity: "Center", **options)
|
61
|
+
thumbnail("#{width}x#{height}^", **options)
|
32
62
|
magick.gravity gravity
|
33
63
|
magick.background color(:transparent)
|
34
64
|
magick.extent "#{width}x#{height}"
|
35
65
|
end
|
36
66
|
|
37
|
-
def resize_and_pad(
|
38
|
-
thumbnail(
|
67
|
+
def resize_and_pad(width, height, background: :transparent, gravity: "Center", **options)
|
68
|
+
thumbnail("#{width}x#{height}", **options)
|
39
69
|
magick.background color(background)
|
40
70
|
magick.gravity gravity
|
41
71
|
magick.extent "#{width}x#{height}"
|
42
72
|
end
|
43
73
|
|
44
|
-
def rotate(
|
74
|
+
def rotate(degrees, background: nil)
|
45
75
|
magick.background color(background) if background
|
46
76
|
magick.rotate(degrees)
|
47
77
|
end
|
48
78
|
|
49
|
-
def
|
50
|
-
return magick.
|
79
|
+
def composite(overlay = :none, mask: nil, compose: nil, gravity: nil, geometry: nil, args: nil, &block)
|
80
|
+
return magick.composite if overlay == :none
|
51
81
|
|
52
|
-
|
53
|
-
|
82
|
+
overlay_path = convert_to_path(overlay, "overlay")
|
83
|
+
mask_path = convert_to_path(mask, "mask") if mask
|
54
84
|
|
55
|
-
|
56
|
-
|
85
|
+
magick << overlay_path
|
86
|
+
magick << mask_path if mask_path
|
57
87
|
|
58
|
-
|
59
|
-
|
60
|
-
end
|
88
|
+
magick.compose(compose) if compose
|
89
|
+
define(compose: { args: args }) if args
|
61
90
|
|
62
|
-
magick
|
63
|
-
|
91
|
+
magick.gravity(gravity) if gravity
|
92
|
+
magick.geometry(geometry) if geometry
|
64
93
|
|
65
|
-
|
66
|
-
limit_args = options.flat_map { |type, value| %W[-limit #{type} #{value}] }
|
67
|
-
prepend_args(magick, limit_args)
|
68
|
-
end
|
94
|
+
yield magick if block_given?
|
69
95
|
|
70
|
-
|
71
|
-
magick.merge! args
|
96
|
+
magick.composite
|
72
97
|
end
|
73
98
|
|
74
|
-
def
|
75
|
-
if
|
76
|
-
|
77
|
-
|
78
|
-
source_path = path_or_magick
|
79
|
-
magick = ::MiniMagick::Tool::Convert.new
|
80
|
-
|
81
|
-
apply_options(magick, options)
|
82
|
-
|
83
|
-
input_path = source_path
|
84
|
-
input_path += "[#{page}]" if page
|
85
|
-
input_path += "[#{geometry}]" if geometry
|
86
|
-
|
87
|
-
magick << input_path
|
88
|
-
end
|
99
|
+
def define(options)
|
100
|
+
return magick.define(options) if options.is_a?(String)
|
101
|
+
Utils.apply_define(magick, options)
|
102
|
+
end
|
89
103
|
|
90
|
-
|
104
|
+
def limits(options)
|
105
|
+
options.each { |type, value| magick.args.unshift("-limit", type.to_s, value.to_s) }
|
91
106
|
magick
|
92
107
|
end
|
93
108
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
magick << destination_path
|
98
|
-
magick.call
|
99
|
-
|
100
|
-
disallow_split_layers!(destination_path) unless allow_splitting
|
109
|
+
def append(*args)
|
110
|
+
magick.merge! args
|
101
111
|
end
|
102
112
|
|
103
113
|
private
|
@@ -111,42 +121,65 @@ module ImageProcessing
|
|
111
121
|
raise ArgumentError, "unrecognized color format: #{value.inspect} (must be one of: string, 3-element RGB array, 4-element RGBA array)"
|
112
122
|
end
|
113
123
|
|
114
|
-
def thumbnail(
|
124
|
+
def thumbnail(geometry, sharpen: {})
|
115
125
|
magick.resize(geometry)
|
116
|
-
|
126
|
+
|
127
|
+
if sharpen
|
128
|
+
sharpen = SHARPEN_PARAMETERS.merge(sharpen)
|
129
|
+
magick.sharpen("#{sharpen[:radius]}x#{sharpen[:sigma]}")
|
130
|
+
end
|
131
|
+
|
117
132
|
magick
|
118
133
|
end
|
119
134
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
135
|
+
def convert_to_path(file, name)
|
136
|
+
if file.is_a?(String)
|
137
|
+
file
|
138
|
+
elsif file.respond_to?(:to_path)
|
139
|
+
file.to_path
|
140
|
+
elsif file.respond_to?(:path)
|
141
|
+
file.path
|
142
|
+
else
|
143
|
+
raise ArgumentError, "#{name} must be a String, Pathname, or respond to #path"
|
144
|
+
end
|
125
145
|
end
|
126
146
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
147
|
+
module Utils
|
148
|
+
module_function
|
149
|
+
|
150
|
+
def disallow_split_layers!(destination_path)
|
151
|
+
layers = Dir[destination_path.sub(/\.\w+$/, '-*\0')]
|
152
|
+
|
153
|
+
if layers.any?
|
154
|
+
layers.each { |path| File.delete(path) }
|
155
|
+
raise Error, "Multi-layer image is being converted into a single-layer format. You should either process individual layers or set :allow_splitting to true. See https://github.com/janko-m/image_processing/wiki/Splitting-a-PDF-into-multiple-images for how to process each layer individually."
|
133
156
|
end
|
134
157
|
end
|
135
158
|
|
136
|
-
|
137
|
-
|
159
|
+
def apply_options(magick, define: {}, **options)
|
160
|
+
options.each do |option, value|
|
161
|
+
case value
|
162
|
+
when true, nil then magick.send(option)
|
163
|
+
when false then magick.send(option).+
|
164
|
+
else magick.send(option, *value)
|
165
|
+
end
|
166
|
+
end
|
138
167
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
168
|
+
apply_define(magick, define)
|
169
|
+
end
|
170
|
+
|
171
|
+
def apply_define(magick, options)
|
172
|
+
options.each do |namespace, settings|
|
173
|
+
namespace = namespace.to_s.gsub("_", "-")
|
143
174
|
|
144
|
-
|
145
|
-
|
175
|
+
settings.each do |key, value|
|
176
|
+
key = key.to_s.gsub("_", "-")
|
177
|
+
|
178
|
+
magick.define "#{namespace}:#{key}=#{value}"
|
179
|
+
end
|
180
|
+
end
|
146
181
|
|
147
|
-
|
148
|
-
layers.each { |path| File.delete(path) }
|
149
|
-
raise Error, "Multi-layer image is being converted into a single-layer format. You should either process individual layers or set :allow_splitting to true. See https://github.com/janko-m/image_processing/wiki/Splitting-a-PDF-into-multiple-images for how to process each layer individually."
|
182
|
+
magick
|
150
183
|
end
|
151
184
|
end
|
152
185
|
end
|
@@ -4,7 +4,7 @@ module ImageProcessing
|
|
4
4
|
class Pipeline
|
5
5
|
DEFAULT_FORMAT = "jpg"
|
6
6
|
|
7
|
-
attr_reader :source, :loader, :saver, :format, :operations, :
|
7
|
+
attr_reader :source, :loader, :saver, :format, :operations, :processor, :destination
|
8
8
|
|
9
9
|
def initialize(options)
|
10
10
|
options.each do |name, value|
|
@@ -14,22 +14,21 @@ module ImageProcessing
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def call(save: true)
|
17
|
-
|
18
|
-
image = processor.load_image(source, **loader)
|
17
|
+
accumulator = processor.load_image(source, **loader)
|
19
18
|
|
20
|
-
operations.each do |name, args|
|
21
|
-
|
19
|
+
operations.each do |name, args, block|
|
20
|
+
accumulator = processor.apply_operation(accumulator, name, *args, &block)
|
22
21
|
end
|
23
22
|
|
24
23
|
if save == false
|
25
|
-
|
24
|
+
accumulator
|
26
25
|
elsif destination
|
27
26
|
handle_destination do
|
28
|
-
processor.save_image(
|
27
|
+
processor.save_image(accumulator, destination, **saver)
|
29
28
|
end
|
30
29
|
else
|
31
30
|
create_tempfile do |tempfile|
|
32
|
-
processor.save_image(
|
31
|
+
processor.save_image(accumulator, tempfile.path, **saver)
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -74,9 +73,9 @@ module ImageProcessing
|
|
74
73
|
def normalize_source(source, options)
|
75
74
|
fail Error, "source file is not provided" unless source
|
76
75
|
|
77
|
-
|
76
|
+
accumulator_class = options[:processor]::ACCUMULATOR_CLASS
|
78
77
|
|
79
|
-
if source.is_a?(
|
78
|
+
if source.is_a?(accumulator_class)
|
80
79
|
source
|
81
80
|
elsif source.is_a?(String)
|
82
81
|
source
|
@@ -85,7 +84,7 @@ module ImageProcessing
|
|
85
84
|
elsif source.respond_to?(:to_path)
|
86
85
|
source.to_path
|
87
86
|
else
|
88
|
-
fail Error, "source file needs to respond to #path, or be a String, a Pathname, or a #{
|
87
|
+
fail Error, "source file needs to respond to #path, or be a String, a Pathname, or a #{accumulator_class} object"
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -1,23 +1,26 @@
|
|
1
1
|
module ImageProcessing
|
2
2
|
class Processor
|
3
|
-
def
|
4
|
-
@
|
3
|
+
def self.accumulator(name, klass)
|
4
|
+
define_method(name) { @accumulator }
|
5
|
+
protected(name)
|
6
|
+
const_set(:ACCUMULATOR_CLASS, klass)
|
5
7
|
end
|
6
8
|
|
7
|
-
def apply_operation(
|
8
|
-
if
|
9
|
-
|
9
|
+
def self.apply_operation(accumulator, name, *args, &block)
|
10
|
+
if (instance_methods - Object.instance_methods).include?(name)
|
11
|
+
instance = new(accumulator)
|
12
|
+
instance.public_send(name, *args, &block)
|
10
13
|
else
|
11
|
-
|
14
|
+
accumulator.send(name, *args, &block)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
def
|
16
|
-
|
18
|
+
def initialize(accumulator = nil)
|
19
|
+
@accumulator = accumulator
|
17
20
|
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
def custom(&block)
|
23
|
+
(block && block.call(@accumulator)) || @accumulator
|
24
|
+
end
|
22
25
|
end
|
23
26
|
end
|
@@ -15,41 +15,59 @@ module ImageProcessing
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class Processor < ImageProcessing::Processor
|
18
|
-
|
18
|
+
accumulator :image, ::Vips::Image
|
19
|
+
|
19
20
|
# default sharpening mask that provides a fast and mild sharpen
|
20
21
|
SHARPEN_MASK = ::Vips::Image.new_from_array [[-1, -1, -1],
|
21
22
|
[-1, 32, -1],
|
22
23
|
[-1, -1, -1]], 24
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
def self.load_image(path_or_image, autorot: true, **options)
|
27
|
+
if path_or_image.is_a?(::Vips::Image)
|
28
|
+
image = path_or_image
|
29
|
+
else
|
30
|
+
source_path = path_or_image
|
31
|
+
options = Utils.select_valid_loader_options(source_path, options)
|
32
|
+
|
33
|
+
image = ::Vips::Image.new_from_file(source_path, **options)
|
34
|
+
end
|
35
|
+
|
36
|
+
image = image.autorot if autorot && !options.key?(:autorotate)
|
37
|
+
image
|
27
38
|
end
|
28
39
|
|
29
|
-
def
|
40
|
+
def self.save_image(image, destination_path, quality: nil, **options)
|
41
|
+
options = options.merge(Q: quality) if quality
|
42
|
+
options = Utils.select_valid_saver_options(destination_path, options)
|
43
|
+
|
44
|
+
image.write_to_file(destination_path, **options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def resize_to_limit(width, height, **options)
|
30
48
|
width, height = default_dimensions(width, height)
|
31
|
-
thumbnail(
|
49
|
+
thumbnail(width, height, size: :down, **options)
|
32
50
|
end
|
33
51
|
|
34
|
-
def resize_to_fit(
|
52
|
+
def resize_to_fit(width, height, **options)
|
35
53
|
width, height = default_dimensions(width, height)
|
36
|
-
thumbnail(
|
54
|
+
thumbnail(width, height, **options)
|
37
55
|
end
|
38
56
|
|
39
|
-
def resize_to_fill(
|
40
|
-
thumbnail(
|
57
|
+
def resize_to_fill(width, height, **options)
|
58
|
+
thumbnail(width, height, crop: :centre, **options)
|
41
59
|
end
|
42
60
|
|
43
|
-
def resize_and_pad(
|
61
|
+
def resize_and_pad(width, height, gravity: "centre", extend: nil, background: nil, alpha: nil, **options)
|
44
62
|
embed_options = { extend: extend, background: background }
|
45
63
|
embed_options.reject! { |name, value| value.nil? }
|
46
64
|
|
47
|
-
image = thumbnail(
|
65
|
+
image = thumbnail(width, height, **options)
|
48
66
|
image = image.add_alpha if alpha && !image.has_alpha?
|
49
67
|
image.gravity(gravity, width, height, **embed_options)
|
50
68
|
end
|
51
69
|
|
52
|
-
def rotate(
|
70
|
+
def rotate(degrees, background: nil)
|
53
71
|
if degrees % 90 == 0
|
54
72
|
image.rot(:"d#{degrees % 360}")
|
55
73
|
else
|
@@ -60,30 +78,33 @@ module ImageProcessing
|
|
60
78
|
end
|
61
79
|
end
|
62
80
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
81
|
+
def composite(other, mode, **options)
|
82
|
+
other = [other] unless other.is_a?(Array)
|
83
|
+
|
84
|
+
other = other.map do |object|
|
85
|
+
if object.is_a?(String)
|
86
|
+
::Vips::Image.new_from_file(object)
|
87
|
+
elsif object.respond_to?(:to_path)
|
88
|
+
::Vips::Image.new_from_file(object.to_path)
|
89
|
+
elsif object.respond_to?(:path)
|
90
|
+
::Vips::Image.new_from_file(object.path)
|
91
|
+
else
|
92
|
+
object
|
93
|
+
end
|
71
94
|
end
|
72
95
|
|
73
|
-
image
|
74
|
-
image
|
96
|
+
image.composite(other, mode, **options)
|
75
97
|
end
|
76
98
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
image.write_to_file(destination_path, **options)
|
82
|
-
end
|
99
|
+
# make Vips::Image#set, #set_type, and #set_value chainable
|
100
|
+
def set(*args) image.tap { |img| img.set(*args) } end
|
101
|
+
def set_type(*args) image.tap { |img| img.set_type(*args) } end
|
102
|
+
def set_value(*args) image.tap { |img| img.set_value(*args) } end
|
83
103
|
|
84
104
|
private
|
85
105
|
|
86
|
-
def thumbnail(
|
106
|
+
def thumbnail(width, height, sharpen: SHARPEN_MASK, **options)
|
107
|
+
image = self.image
|
87
108
|
image = image.thumbnail_image(width, height: height, **options)
|
88
109
|
image = image.conv(sharpen) if sharpen
|
89
110
|
image
|
@@ -95,25 +116,29 @@ module ImageProcessing
|
|
95
116
|
[width || ::Vips::MAX_COORD, height || ::Vips::MAX_COORD]
|
96
117
|
end
|
97
118
|
|
98
|
-
|
99
|
-
|
100
|
-
loader ? select_valid_options(loader, options) : options
|
101
|
-
end
|
119
|
+
module Utils
|
120
|
+
module_function
|
102
121
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
122
|
+
def select_valid_loader_options(source_path, options)
|
123
|
+
loader = ::Vips.vips_foreign_find_load(source_path)
|
124
|
+
loader ? select_valid_options(loader, options) : options
|
125
|
+
end
|
126
|
+
|
127
|
+
def select_valid_saver_options(destination_path, options)
|
128
|
+
saver = ::Vips.vips_foreign_find_save(destination_path)
|
129
|
+
saver ? select_valid_options(saver, options) : options
|
130
|
+
end
|
107
131
|
|
108
|
-
|
109
|
-
|
132
|
+
def select_valid_options(operation_name, options)
|
133
|
+
operation = ::Vips::Operation.new(operation_name)
|
110
134
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
135
|
+
operation_options = operation.get_construct_args
|
136
|
+
.select { |name, flags| (flags & ::Vips::ARGUMENT_INPUT) != 0 }
|
137
|
+
.select { |name, flags| (flags & ::Vips::ARGUMENT_REQUIRED) == 0 }
|
138
|
+
.map(&:first).map(&:to_sym)
|
115
139
|
|
116
|
-
|
140
|
+
options.select { |name, value| operation_options.include?(name) }
|
141
|
+
end
|
117
142
|
end
|
118
143
|
end
|
119
144
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: image_processing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|