image_processing 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of image_processing might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/image_processing.gemspec +1 -1
- data/lib/image_processing/builder.rb +1 -0
- data/lib/image_processing/chainable.rb +17 -0
- data/lib/image_processing/mini_magick.rb +36 -2
- data/lib/image_processing/pipeline.rb +10 -0
- data/lib/image_processing/processor.rb +9 -0
- data/lib/image_processing/version.rb +1 -1
- data/lib/image_processing/vips.rb +41 -16
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ebf3b3c8fc4a4729473e346f5caddb1cc56fd971436ead2842185aa900c33b5
|
4
|
+
data.tar.gz: 9aaa8ae0ffbecbb0d3badd05835ca1d04c800bd0da4dfdec0beb11ea895fe003
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e223f370b545ff3181877d416565e3e5e67ce9bc4478b0b94a26434a2086cb76f1f07f9099e27b01d7b4c46a90c457e39409b146b5839fd953b1d08f694acae6
|
7
|
+
data.tar.gz: a0e9c3db88a40607128d90a4f37e8c5b5ba5e56064a7cc8c38f6ee13bb585f6de0d13b40177f5af20434e6b1ab37b5dbe22ca96d22cb4b98266878673d3c9e4b
|
data/CHANGELOG.md
CHANGED
data/image_processing.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
19
|
spec.add_dependency "mini_magick", "~> 4.0"
|
20
|
-
spec.add_dependency "ruby-vips", ">= 2.0.
|
20
|
+
spec.add_dependency "ruby-vips", ">= 2.0.13", "< 3"
|
21
21
|
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "minitest", "~> 5.8"
|
@@ -1,21 +1,31 @@
|
|
1
1
|
module ImageProcessing
|
2
|
+
# Implements a chainable interface for building processing options.
|
2
3
|
module Chainable
|
4
|
+
# Specify the source image file.
|
3
5
|
def source(file)
|
4
6
|
branch source: file
|
5
7
|
end
|
6
8
|
|
9
|
+
# Specify the output format.
|
7
10
|
def convert(format)
|
8
11
|
branch format: format
|
9
12
|
end
|
10
13
|
|
14
|
+
# Specify processor options applied when loading the image.
|
11
15
|
def loader(**options)
|
12
16
|
branch loader: options
|
13
17
|
end
|
14
18
|
|
19
|
+
# Specify processor options applied when saving the image.
|
15
20
|
def saver(**options)
|
16
21
|
branch saver: options
|
17
22
|
end
|
18
23
|
|
24
|
+
# Add multiple operations as a hash or an array.
|
25
|
+
#
|
26
|
+
# .apply(resize_to_limit: [400, 400], strip: true)
|
27
|
+
# # or
|
28
|
+
# .apply([[:resize_to_limit, [400, 400]], [:strip, true])
|
19
29
|
def apply(operations)
|
20
30
|
operations.inject(self) do |builder, (name, argument)|
|
21
31
|
if argument == true || argument == nil
|
@@ -28,6 +38,8 @@ module ImageProcessing
|
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
41
|
+
# Assume that any unknown method names an operation supported by the
|
42
|
+
# processor. Add a bang ("!") if you want processing to be performed.
|
31
43
|
def method_missing(name, *args, &block)
|
32
44
|
return super if name.to_s.end_with?("?")
|
33
45
|
return send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
|
@@ -35,10 +47,13 @@ module ImageProcessing
|
|
35
47
|
operation(name, *args, &block)
|
36
48
|
end
|
37
49
|
|
50
|
+
# Add an operation defined by the processor.
|
38
51
|
def operation(name, *args, &block)
|
39
52
|
branch operations: [[name, args, *block]]
|
40
53
|
end
|
41
54
|
|
55
|
+
# Call the defined processing and get the result. Allows specifying
|
56
|
+
# the source file and destination.
|
42
57
|
def call(file = nil, destination: nil, **call_options)
|
43
58
|
options = {}
|
44
59
|
options = options.merge(source: file) if file
|
@@ -47,6 +62,7 @@ module ImageProcessing
|
|
47
62
|
branch(options).call!(**call_options)
|
48
63
|
end
|
49
64
|
|
65
|
+
# Creates a new builder object, merging current options with new options.
|
50
66
|
def branch(loader: nil, saver: nil, operations: nil, **other_options)
|
51
67
|
options = respond_to?(:options) ? self.options : DEFAULT_OPTIONS
|
52
68
|
|
@@ -61,6 +77,7 @@ module ImageProcessing
|
|
61
77
|
Builder.new(options)
|
62
78
|
end
|
63
79
|
|
80
|
+
# Empty options which the builder starts with.
|
64
81
|
DEFAULT_OPTIONS = {
|
65
82
|
source: nil,
|
66
83
|
loader: {},
|
@@ -5,6 +5,7 @@ module ImageProcessing
|
|
5
5
|
module MiniMagick
|
6
6
|
extend Chainable
|
7
7
|
|
8
|
+
# Returns whether the given image file is processable.
|
8
9
|
def self.valid_image?(file)
|
9
10
|
::MiniMagick::Tool::Convert.new do |convert|
|
10
11
|
convert << file.path
|
@@ -18,8 +19,12 @@ module ImageProcessing
|
|
18
19
|
class Processor < ImageProcessing::Processor
|
19
20
|
accumulator :magick, ::MiniMagick::Tool
|
20
21
|
|
22
|
+
# Default sharpening parameters used on generated thumbnails.
|
21
23
|
SHARPEN_PARAMETERS = { radius: 0, sigma: 1 }
|
22
24
|
|
25
|
+
# Initializes the image on disk into a MiniMagick::Tool object. Accepts
|
26
|
+
# additional options related to loading the image (e.g. geometry).
|
27
|
+
# Additionally auto-orients the image to be upright.
|
23
28
|
def self.load_image(path_or_magick, page: nil, geometry: nil, auto_orient: true, **options)
|
24
29
|
if path_or_magick.is_a?(::MiniMagick::Tool)
|
25
30
|
magick = path_or_magick
|
@@ -40,6 +45,9 @@ module ImageProcessing
|
|
40
45
|
magick
|
41
46
|
end
|
42
47
|
|
48
|
+
# Calls the built ImageMagick command to perform processing and save
|
49
|
+
# the result to disk. Accepts additional options related to saving the
|
50
|
+
# image (e.g. quality).
|
43
51
|
def self.save_image(magick, destination_path, allow_splitting: false, **options)
|
44
52
|
Utils.apply_options(magick, options)
|
45
53
|
|
@@ -49,14 +57,18 @@ module ImageProcessing
|
|
49
57
|
Utils.disallow_split_layers!(destination_path) unless allow_splitting
|
50
58
|
end
|
51
59
|
|
60
|
+
# Resizes the image to not be larger than the specified dimensions.
|
52
61
|
def resize_to_limit(width, height, **options)
|
53
62
|
thumbnail("#{width}x#{height}>", **options)
|
54
63
|
end
|
55
64
|
|
65
|
+
# Resizes the image to fit within the specified dimensions.
|
56
66
|
def resize_to_fit(width, height, **options)
|
57
67
|
thumbnail("#{width}x#{height}", **options)
|
58
68
|
end
|
59
69
|
|
70
|
+
# Resizes the image to fill the specified dimensions, applying any
|
71
|
+
# necessary cropping.
|
60
72
|
def resize_to_fill(width, height, gravity: "Center", **options)
|
61
73
|
thumbnail("#{width}x#{height}^", **options)
|
62
74
|
magick.gravity gravity
|
@@ -64,6 +76,8 @@ module ImageProcessing
|
|
64
76
|
magick.extent "#{width}x#{height}"
|
65
77
|
end
|
66
78
|
|
79
|
+
# Resizes the image to fit within the specified dimensions and fills
|
80
|
+
# the remaining area with the specified background color.
|
67
81
|
def resize_and_pad(width, height, background: :transparent, gravity: "Center", **options)
|
68
82
|
thumbnail("#{width}x#{height}", **options)
|
69
83
|
magick.background color(background)
|
@@ -71,11 +85,17 @@ module ImageProcessing
|
|
71
85
|
magick.extent "#{width}x#{height}"
|
72
86
|
end
|
73
87
|
|
88
|
+
# Rotates the image by an arbitrary angle. For angles that are not
|
89
|
+
# multiple of 90 degrees an optional background color can be specified to
|
90
|
+
# fill in the gaps.
|
74
91
|
def rotate(degrees, background: nil)
|
75
92
|
magick.background color(background) if background
|
76
93
|
magick.rotate(degrees)
|
77
94
|
end
|
78
95
|
|
96
|
+
# Overlays the specified image over the current one. Supports specifying
|
97
|
+
# an additional mask, composite mode, direction or offset of the overlay
|
98
|
+
# image.
|
79
99
|
def composite(overlay = :none, mask: nil, mode: nil, gravity: nil, offset: nil, args: nil, **options, &block)
|
80
100
|
return magick.composite if overlay == :none
|
81
101
|
|
@@ -107,22 +127,28 @@ module ImageProcessing
|
|
107
127
|
magick.composite
|
108
128
|
end
|
109
129
|
|
130
|
+
# Defines settings from the provided hash.
|
110
131
|
def define(options)
|
111
132
|
return magick.define(options) if options.is_a?(String)
|
112
133
|
Utils.apply_define(magick, options)
|
113
134
|
end
|
114
135
|
|
136
|
+
# Specifies resource limits from the provided hash.
|
115
137
|
def limits(options)
|
116
138
|
options.each { |type, value| magick.args.unshift("-limit", type.to_s, value.to_s) }
|
117
139
|
magick
|
118
140
|
end
|
119
141
|
|
142
|
+
# Appends a raw ImageMagick command-line argument to the command.
|
120
143
|
def append(*args)
|
121
144
|
magick.merge! args
|
122
145
|
end
|
123
146
|
|
124
147
|
private
|
125
148
|
|
149
|
+
# Converts the given color value into an identifier ImageMagick understands.
|
150
|
+
# This supports specifying RGB(A) values with arrays, which mainly exists
|
151
|
+
# for compatibility with the libvips implementation.
|
126
152
|
def color(value)
|
127
153
|
return "rgba(255,255,255,0.0)" if value.to_s == "transparent"
|
128
154
|
return "rgb(#{value.join(",")})" if value.is_a?(Array) && value.count == 3
|
@@ -132,6 +158,8 @@ module ImageProcessing
|
|
132
158
|
raise ArgumentError, "unrecognized color format: #{value.inspect} (must be one of: string, 3-element RGB array, 4-element RGBA array)"
|
133
159
|
end
|
134
160
|
|
161
|
+
# Resizes the image using the specified geometry, and sharpens the
|
162
|
+
# resulting thumbnail.
|
135
163
|
def thumbnail(geometry, sharpen: {})
|
136
164
|
magick.resize(geometry)
|
137
165
|
|
@@ -143,6 +171,7 @@ module ImageProcessing
|
|
143
171
|
magick
|
144
172
|
end
|
145
173
|
|
174
|
+
# Converts the image on disk in various forms into a path.
|
146
175
|
def convert_to_path(file, name)
|
147
176
|
if file.is_a?(String)
|
148
177
|
file
|
@@ -158,6 +187,9 @@ module ImageProcessing
|
|
158
187
|
module Utils
|
159
188
|
module_function
|
160
189
|
|
190
|
+
# When a multi-layer format is being converted into a single-layer
|
191
|
+
# format, ImageMagick will create multiple images, one for each layer.
|
192
|
+
# We want to warn the user that this is probably not what they wanted.
|
161
193
|
def disallow_split_layers!(destination_path)
|
162
194
|
layers = Dir[destination_path.sub(/\.\w+$/, '-*\0')]
|
163
195
|
|
@@ -167,6 +199,7 @@ module ImageProcessing
|
|
167
199
|
end
|
168
200
|
end
|
169
201
|
|
202
|
+
# Applies options from the provided hash.
|
170
203
|
def apply_options(magick, define: {}, **options)
|
171
204
|
options.each do |option, value|
|
172
205
|
case value
|
@@ -179,12 +212,13 @@ module ImageProcessing
|
|
179
212
|
apply_define(magick, define)
|
180
213
|
end
|
181
214
|
|
215
|
+
# Applies settings from the provided (nested) hash.
|
182
216
|
def apply_define(magick, options)
|
183
217
|
options.each do |namespace, settings|
|
184
|
-
namespace = namespace.to_s.
|
218
|
+
namespace = namespace.to_s.tr("_", "-")
|
185
219
|
|
186
220
|
settings.each do |key, value|
|
187
|
-
key = key.to_s.
|
221
|
+
key = key.to_s.tr("_", "-")
|
188
222
|
|
189
223
|
magick.define "#{namespace}:#{key}=#{value}"
|
190
224
|
end
|
@@ -6,6 +6,7 @@ module ImageProcessing
|
|
6
6
|
|
7
7
|
attr_reader :source, :loader, :saver, :format, :operations, :processor, :destination
|
8
8
|
|
9
|
+
# Initializes the pipeline with all the processing options.
|
9
10
|
def initialize(options)
|
10
11
|
options.each do |name, value|
|
11
12
|
value = normalize_source(value, options) if name == :source
|
@@ -13,6 +14,10 @@ module ImageProcessing
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
17
|
+
# Performs the defined series of operations, and saves the result in a new
|
18
|
+
# tempfile or a specified path on disk, or if `save: false` was passed in
|
19
|
+
# returns the unsaved accumulator object that can be used for further
|
20
|
+
# processing.
|
16
21
|
def call(save: true)
|
17
22
|
accumulator = processor.load_image(source, **loader)
|
18
23
|
|
@@ -33,10 +38,12 @@ module ImageProcessing
|
|
33
38
|
end
|
34
39
|
end
|
35
40
|
|
41
|
+
# Retrieves the source path on disk.
|
36
42
|
def source_path
|
37
43
|
source if source.is_a?(String)
|
38
44
|
end
|
39
45
|
|
46
|
+
# Determines the appropriate destination image format.
|
40
47
|
def destination_format
|
41
48
|
format = File.extname(destination)[1..-1] if destination
|
42
49
|
format ||= self.format
|
@@ -47,6 +54,8 @@ module ImageProcessing
|
|
47
54
|
|
48
55
|
private
|
49
56
|
|
57
|
+
# Creates a new tempfile for the destination file, yields it, and refreshes
|
58
|
+
# the file descriptor to get the updated file.
|
50
59
|
def create_tempfile
|
51
60
|
tempfile = Tempfile.new(["image_processing", ".#{destination_format}"], binmode: true)
|
52
61
|
|
@@ -70,6 +79,7 @@ module ImageProcessing
|
|
70
79
|
raise
|
71
80
|
end
|
72
81
|
|
82
|
+
# Converts the source image object into a path or the accumulator object.
|
73
83
|
def normalize_source(source, options)
|
74
84
|
fail Error, "source file is not provided" unless source
|
75
85
|
|
@@ -1,11 +1,18 @@
|
|
1
1
|
module ImageProcessing
|
2
|
+
# Abstract class inherited by individual processors.
|
2
3
|
class Processor
|
4
|
+
# Use for processor subclasses to specify the name and the class of their
|
5
|
+
# accumulator object (e.g. MiniMagic::Tool or Vips::Image).
|
3
6
|
def self.accumulator(name, klass)
|
4
7
|
define_method(name) { @accumulator }
|
5
8
|
protected(name)
|
6
9
|
const_set(:ACCUMULATOR_CLASS, klass)
|
7
10
|
end
|
8
11
|
|
12
|
+
# Calls the operation to perform the processing. If the operation is
|
13
|
+
# defined on the processor (macro), calls it. Otherwise calls the
|
14
|
+
# operation directly on the accumulator object. This provides a common
|
15
|
+
# umbrella above defined macros and direct operations.
|
9
16
|
def self.apply_operation(accumulator, name, *args, &block)
|
10
17
|
if (instance_methods - Object.instance_methods).include?(name)
|
11
18
|
instance = new(accumulator)
|
@@ -19,6 +26,8 @@ module ImageProcessing
|
|
19
26
|
@accumulator = accumulator
|
20
27
|
end
|
21
28
|
|
29
|
+
# Calls the given block with the accumulator object. Useful for when you
|
30
|
+
# want to access the accumulator object directly.
|
22
31
|
def custom(&block)
|
23
32
|
(block && block.call(@accumulator)) || @accumulator
|
24
33
|
end
|
@@ -7,6 +7,7 @@ module ImageProcessing
|
|
7
7
|
module Vips
|
8
8
|
extend Chainable
|
9
9
|
|
10
|
+
# Returns whether the given image file is processable.
|
10
11
|
def self.valid_image?(file)
|
11
12
|
::Vips::Image.new_from_file(file.path, access: :sequential).avg
|
12
13
|
true
|
@@ -17,12 +18,15 @@ module ImageProcessing
|
|
17
18
|
class Processor < ImageProcessing::Processor
|
18
19
|
accumulator :image, ::Vips::Image
|
19
20
|
|
20
|
-
#
|
21
|
+
# Default sharpening mask that provides a fast and mild sharpen.
|
21
22
|
SHARPEN_MASK = ::Vips::Image.new_from_array [[-1, -1, -1],
|
22
23
|
[-1, 32, -1],
|
23
24
|
[-1, -1, -1]], 24
|
24
25
|
|
25
26
|
|
27
|
+
# Loads the image on disk into a Vips::Image object. Accepts additional
|
28
|
+
# loader-specific options (e.g. interlacing). Afterwards auto-rotates the
|
29
|
+
# image to be upright.
|
26
30
|
def self.load_image(path_or_image, autorot: true, **options)
|
27
31
|
if path_or_image.is_a?(::Vips::Image)
|
28
32
|
image = path_or_image
|
@@ -37,6 +41,9 @@ module ImageProcessing
|
|
37
41
|
image
|
38
42
|
end
|
39
43
|
|
44
|
+
# Writes the Vips::Image object to disk. This starts the processing
|
45
|
+
# pipeline defined in the Vips::Image object. Accepts additional
|
46
|
+
# saver-specific options (e.g. quality).
|
40
47
|
def self.save_image(image, destination_path, quality: nil, **options)
|
41
48
|
options = options.merge(Q: quality) if quality
|
42
49
|
options = Utils.select_valid_saver_options(destination_path, options)
|
@@ -44,41 +51,43 @@ module ImageProcessing
|
|
44
51
|
image.write_to_file(destination_path, **options)
|
45
52
|
end
|
46
53
|
|
54
|
+
# Resizes the image to not be larger than the specified dimensions.
|
47
55
|
def resize_to_limit(width, height, **options)
|
48
56
|
width, height = default_dimensions(width, height)
|
49
57
|
thumbnail(width, height, size: :down, **options)
|
50
58
|
end
|
51
59
|
|
60
|
+
# Resizes the image to fit within the specified dimensions.
|
52
61
|
def resize_to_fit(width, height, **options)
|
53
62
|
width, height = default_dimensions(width, height)
|
54
63
|
thumbnail(width, height, **options)
|
55
64
|
end
|
56
65
|
|
66
|
+
# Resizes the image to fill the specified dimensions, applying any
|
67
|
+
# necessary cropping.
|
57
68
|
def resize_to_fill(width, height, **options)
|
58
69
|
thumbnail(width, height, crop: :centre, **options)
|
59
70
|
end
|
60
71
|
|
72
|
+
# Resizes the image to fit within the specified dimensions and fills
|
73
|
+
# the remaining area with the specified background color.
|
61
74
|
def resize_and_pad(width, height, gravity: "centre", extend: nil, background: nil, alpha: nil, **options)
|
62
|
-
embed_options = { extend: extend, background: background }
|
63
|
-
embed_options.reject! { |name, value| value.nil? }
|
64
|
-
|
65
75
|
image = thumbnail(width, height, **options)
|
66
76
|
image = image.add_alpha if alpha && !image.has_alpha?
|
67
|
-
image.gravity(gravity, width, height,
|
77
|
+
image.gravity(gravity, width, height, extend: extend, background: background)
|
68
78
|
end
|
69
79
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
options[:background] = background if background
|
76
|
-
|
77
|
-
image.similarity(**options)
|
78
|
-
end
|
80
|
+
# Rotates the image by an arbitrary angle. Additional options can be
|
81
|
+
# specified, such as background colors to fill in the gaps when rotating
|
82
|
+
# with an angle which is not a multiple of 90 degrees.
|
83
|
+
def rotate(degrees, **options)
|
84
|
+
image.similarity(angle: degrees, **options)
|
79
85
|
end
|
80
86
|
|
81
|
-
|
87
|
+
# Overlays the specified image over the current one. Supports specifying
|
88
|
+
# composite mode, direction or offset of the overlay image.
|
89
|
+
def composite(overlay, _mode = nil, mode: "over", gravity: "north-west", offset: nil, **options)
|
90
|
+
# if the mode argument is given, call the original Vips::Image#composite
|
82
91
|
if _mode
|
83
92
|
overlay = [overlay] unless overlay.is_a?(Array)
|
84
93
|
overlay = overlay.map { |object| convert_to_image(object, "overlay") }
|
@@ -87,15 +96,19 @@ module ImageProcessing
|
|
87
96
|
end
|
88
97
|
|
89
98
|
overlay = convert_to_image(overlay, "overlay")
|
90
|
-
|
99
|
+
# add alpha channel so that #gravity can use a transparent background
|
100
|
+
overlay = overlay.add_alpha unless overlay.has_alpha?
|
91
101
|
|
102
|
+
# apply offset with correct gravity and make remainder transparent
|
92
103
|
if offset
|
93
104
|
opposite_gravity = gravity.to_s.gsub(/\w+/, "north"=>"south", "south"=>"north", "east"=>"west", "west"=>"east")
|
94
105
|
overlay = overlay.gravity(opposite_gravity, overlay.width + offset.first, overlay.height + offset.last)
|
95
106
|
end
|
96
107
|
|
108
|
+
# create image-sized transparent background and apply specified gravity
|
97
109
|
overlay = overlay.gravity(gravity, image.width, image.height)
|
98
110
|
|
111
|
+
# apply the composition
|
99
112
|
image.composite(overlay, mode, **options)
|
100
113
|
end
|
101
114
|
|
@@ -106,6 +119,8 @@ module ImageProcessing
|
|
106
119
|
|
107
120
|
private
|
108
121
|
|
122
|
+
# Resizes the image according to the specified parameters, and sharpens
|
123
|
+
# the resulting thumbnail.
|
109
124
|
def thumbnail(width, height, sharpen: SHARPEN_MASK, **options)
|
110
125
|
image = self.image
|
111
126
|
image = image.thumbnail_image(width, height: height, **options)
|
@@ -113,12 +128,14 @@ module ImageProcessing
|
|
113
128
|
image
|
114
129
|
end
|
115
130
|
|
131
|
+
# Hack to allow omitting one dimension.
|
116
132
|
def default_dimensions(width, height)
|
117
133
|
raise Error, "either width or height must be specified" unless width || height
|
118
134
|
|
119
135
|
[width || ::Vips::MAX_COORD, height || ::Vips::MAX_COORD]
|
120
136
|
end
|
121
137
|
|
138
|
+
# Converts the image on disk in various forms into a Vips::Image object.
|
122
139
|
def convert_to_image(object, name)
|
123
140
|
return object if object.is_a?(::Vips::Image)
|
124
141
|
|
@@ -138,16 +155,24 @@ module ImageProcessing
|
|
138
155
|
module Utils
|
139
156
|
module_function
|
140
157
|
|
158
|
+
# libvips uses various loaders depending on the input format.
|
141
159
|
def select_valid_loader_options(source_path, options)
|
142
160
|
loader = ::Vips.vips_foreign_find_load(source_path)
|
143
161
|
loader ? select_valid_options(loader, options) : options
|
144
162
|
end
|
145
163
|
|
164
|
+
# Filters out unknown options for saving images.
|
146
165
|
def select_valid_saver_options(destination_path, options)
|
147
166
|
saver = ::Vips.vips_foreign_find_save(destination_path)
|
148
167
|
saver ? select_valid_options(saver, options) : options
|
149
168
|
end
|
150
169
|
|
170
|
+
# libvips uses various loaders and savers depending on the input and
|
171
|
+
# output image format. Each of these loaders and savers accept slightly
|
172
|
+
# different options, so to allow the user to be able to specify options
|
173
|
+
# for a specific loader/saver and have it ignored for other
|
174
|
+
# loaders/savers, we do a little bit of introspection and filter out
|
175
|
+
# options that don't exist for a particular loader or saver.
|
151
176
|
def select_valid_options(operation_name, options)
|
152
177
|
operation = ::Vips::Operation.new(operation_name)
|
153
178
|
|
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.7.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-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.0.
|
33
|
+
version: 2.0.13
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '3'
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 2.0.
|
43
|
+
version: 2.0.13
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '3'
|