image_processing 1.6.0 → 1.7.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 +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'
|