image_processing 1.2.0 → 1.12.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39c52030a178edeef33439eb70807d86935b1e05bbf250d0f30aa9a4947f6dea
4
- data.tar.gz: 60c936577febb87380de300024a8f4517ae9dafed394d74fe7b0f78ab04efd7f
3
+ metadata.gz: 31d06cb35ac94ec0787b21dd2118626f3a3a96685efab0d7eb58d9079b1fbf2c
4
+ data.tar.gz: 8f840074b8fe9511e59f4f005d144e39c9aba4d0699a48c29ffc6cb2513ec645
5
5
  SHA512:
6
- metadata.gz: 9bc68c91084d44b3052a47ac332d21840965537163b541ef09cd662d729c26e152b3e588f97fd954a13aaae0a5a645be86389a79308de4eee154feb7fed95baa
7
- data.tar.gz: 4c026c8eb9cc4dfa537ef3f0f86b460a8dc0a13134fe441604483b6a4b1afd1048911b499673807fac82f7a15c37773e27fad1dd2d049f8e8adedd5204166923
6
+ metadata.gz: 1d0fb1d9363b9b85e1895d05849a5c29b2c50b8213bf9e9d6ff8c2e1391a9bf6448a4e319a4cfd747183ec741ac42d6b1b1b9629ee91d97cc4a287ec6615042c
7
+ data.tar.gz: dd31dd0ca012ceb35aa276c5e00efd3e9bd2c40246f9b063ea39280ea13c546373fa641518fb55ebcf0e9d00ad6020be995b8d8636c8a3939bda31c643485cef
data/CHANGELOG.md CHANGED
@@ -1,112 +1,208 @@
1
+ ## 1.12.2 (2022-03-01)
2
+
3
+ * Prevent remote shell execution when using `#apply` with operations coming from user input (@janko)
4
+
5
+ ## 1.12.1 (2020-11-06)
6
+
7
+ * Fix format fallback for files ending with a dot on Ruby 2.7+ (@coding-chimp)
8
+
9
+ ## 1.12.0 (2020-09-20)
10
+
11
+ * Add instrumentation support via `#instrumenter` (@janko)
12
+
13
+ ## 1.11.0 (2020-05-17)
14
+
15
+ * [minimagick] Handle destination format having no file extension (@janko)
16
+
17
+ * [minimagick] Disable sharpening on `#resize_*` operators by default (@flori)
18
+
19
+ * [minimagick] Add `#crop` which accepts `left, top, width, height` arguments (@janko)
20
+
21
+ ## 1.10.3 (2020-01-12)
22
+
23
+ * [vips] Fix auto-rotation not working in certain cases on libvips 8.9.0 (@janko)
24
+
25
+ ## 1.10.2 (2020-01-11)
26
+
27
+ * Fix Ruby 2.7 warnings for separation of positional and keyword arguments (@kamipo, @janko)
28
+
29
+ ## 1.10.1 (2020-01-07)
30
+
31
+ * [vips] Fix compatibility with ruby-vips 2.0.17+ (@janko)
32
+
33
+ ## 1.10.0 (2019-12-18)
34
+
35
+ * [minimagick] Add `:loader` option for explicitly setting input file type (@janko)
36
+
37
+ ## 1.9.3 (2019-08-11)
38
+
39
+ * [vips] Use integer precision when sharpening for better quality (@metaskills)
40
+
41
+ ## 1.9.2 (2019-07-22)
42
+
43
+ * Bump `mini_magick` dependency to `>= 4.9.5` (@chioreandan)
44
+
45
+ ## 1.9.1 (2019-07-20)
46
+
47
+ * Bring back support for MRI 2.3 (@janko)
48
+
49
+ ## 1.9.0 (2019-04-09)
50
+
51
+ * Drop support for MRI 2.2 and 2.3 (@janko)
52
+
53
+ * [vips] Allow forcing a specific loader or saver (@janko)
54
+
55
+ ## 1.8.0 (2019-02-25)
56
+
57
+ * [vips] Perform resize-on-load when possible, significantly improving resizing speed (@janko)
58
+
59
+ ## 1.7.1 (2018-09-27)
60
+
61
+ * [vips] Make `#remove` that's used for removing image metadata chainable (@janko)
62
+
63
+ ## 1.7.0 (2018-09-20)
64
+
65
+ * [vips] `#rotate` now always calls `vips_similarity()` and forwards all options to it (@janko)
66
+
67
+ ## 1.6.0 (2018-07-13)
68
+
69
+ * [vips] In `#composite` accept `:offset` option for the position of the overlay image (@janko)
70
+
71
+ * [vips] In `#composite` accept `:gravity` option for the direction of the overlay image (@janko)
72
+
73
+ * [vips] In `#composite` accept blend mode as an optional `:mode` parameter which defaults to `:over` (@janko)
74
+
75
+ * [minimagick] In `#composite` rename `:compose` option to `:mode` (@janko)
76
+
77
+ * [minimagick] In `#composite` replace `:geometry` option with `:offset` which accepts an array (@janko)
78
+
79
+ ## 1.5.0 (2018-07-10)
80
+
81
+ * [minimagick, vips] Add `#composite` method (@janko)
82
+
83
+ * [core] Allow operations to accept blocks (janko-m)
84
+
85
+ ## 1.4.0 (2018-06-14)
86
+
87
+ * [minimagick] Accept RGB(A) arrays for color names for `:background` (@janko)
88
+
89
+ * [minimagick] Don't add empty `-background` option in `#rotate` when `:background` is not given (@janko)
90
+
91
+ * [vips] Modify `#rotate` to accept only `:background` and not other `vips_similarity()` options (@janko)
92
+
93
+ ## 1.3.0 (2018-06-13)
94
+
95
+ * [minimagick, vips] Add `#rotate` method (@janko)
96
+
97
+ * [vips] Use native `vips_image_hasalpha()` and `vips_addalpha()` functions in `#resize_and_pad` (@janko)
98
+
1
99
  ## 1.2.0 (2018-04-18)
2
100
 
3
- * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko-m)
101
+ * [minimagick] Allow appending "+" operators in `#loader` and `#saver` using the value `false` (@janko)
4
102
 
5
- * [core] Fix `#apply` not accepting a Hash as an argument (@janko-m)
103
+ * [core] Fix `#apply` not accepting a Hash as an argument (@janko)
6
104
 
7
- * [core] Allow sending any builder commands via `#apply`, not just operations (@janko-m)
105
+ * [core] Allow sending any builder commands via `#apply`, not just operations (@janko)
8
106
 
9
- * [minimagick] Add `#define` as a wrapper around `-define` (@janko-m)
107
+ * [minimagick] Add `#define` as a wrapper around `-define` (@janko)
10
108
 
11
109
  ## 1.1.0 (2018-04-05)
12
110
 
13
111
  * [minimagick] Disallow splitting multi-layer images into multiple single-layer
14
112
  images by default to avoid unexpected behaviour, but can be re-enabled with
15
- the `:allow_splitting` saver option (@janko-m)
113
+ the `:allow_splitting` saver option (@janko)
16
114
 
17
- * [core] Add `#apply` for applying a list of operations (@janko-m)
115
+ * [core] Add `#apply` for applying a list of operations (@janko)
18
116
 
19
117
  ## 1.0.0 (2018-04-04)
20
118
 
21
- * Depend on `mini_magick` and `ruby-vips` gems (@janko-m, @mokolabs)
119
+ * Depend on `mini_magick` and `ruby-vips` gems (@janko, @mokolabs)
22
120
 
23
- * [minimagick] Remove deprecated API in favor of the chainable API (@janko-m)
121
+ * [minimagick] Remove deprecated API in favor of the chainable API (@janko)
24
122
 
25
- * [core] Rename `Builder#default_options` to `Builder#options` (@janko-m)
123
+ * [core] Rename `Builder#default_options` to `Builder#options` (@janko)
26
124
 
27
- * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko-m)
125
+ * [minimagick] Remove `:fail` loader option in favor of the existing `:regard_warnings` (@janko)
28
126
 
29
- * [vips, minimagick] Don't fail on warnings when loading the image (@janko-m)
127
+ * [vips, minimagick] Don't fail on warnings when loading the image (@janko)
30
128
 
31
- * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko-m)
129
+ * [vips] Don't apply `Vips::Image#autorot` if `:autorotate` loader option was passed in (@janko)
32
130
 
33
- * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko-m)
131
+ * [minimagick] Allow using value `nil` to add ImageMagick options that don't have a value (@janko)
34
132
 
35
- * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko-m)
133
+ * [vips] Accept `:quality` saver option as an alias to `:Q` (@janko)
36
134
 
37
- * [minimagick] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
135
+ * [minimagick] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
38
136
 
39
- * [vips] Automatically sharpen thumbnails after resizing (@janko-m, @mokolabs)
137
+ * [vips] Automatically sharpen thumbnails after resizing (@janko, @mokolabs)
40
138
 
41
139
  ## 0.11.2 (2018-03-31)
42
140
 
43
- * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko-m)
44
-
45
- * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko-m)
141
+ * [minimagick] Avoid `#resize_*` operations stripping data by switching back to `-resize` (@janko)
46
142
 
47
- * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko-m)
143
+ * [core] Make sure an empty destination file doesn't remain on processing errors when `:destination` is used (@janko)
48
144
 
49
- * [minimagick] Drop official support for GraphicsMagick (@janko-m)
145
+ * [vips] Fix `:alpha` not correctly adding alpha for certain types of images (@janko)
50
146
 
51
147
  ## 0.11.1 (2018-03-27)
52
148
 
53
- * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko-m)
149
+ * [minimagick] Rename `#limit` to `#limits` to still allow adding `-limit` arguments directly (@janko)
54
150
 
55
151
  ## 0.11.0 (2018-03-27)
56
152
 
57
- * [minimagick] Fix broken deprecated `#convert` (@janko-m)
153
+ * [minimagick] Fix broken deprecated `#convert` (@janko)
58
154
 
59
- * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko-m)
155
+ * [minimagick] Add `#limit` for specifying resource limits using `-limit` (@janko)
60
156
 
61
- * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko-m)
157
+ * [minimagick] Use `-thumbnail` instead of `-resize` in `#resize_*` methods (@janko)
62
158
 
63
- * [minimagick] Add loader and saver options (@janko-m)
159
+ * [minimagick] Add loader and saver options (@janko)
64
160
 
65
161
  ## 0.10.3 (2018-03-24)
66
162
 
67
- * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko-m)
163
+ * [minimagick] Fix bang methods in deprecated API calling nondestructive versions (@janko)
68
164
 
69
165
  ## 0.10.2 (2018-03-22)
70
166
 
71
- * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko-m)
167
+ * [minimagick] Add back default offset arguments to deprecated `#crop` (@janko)
72
168
 
73
169
  ## 0.10.1 (2018-03-22)
74
170
 
75
- * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko-m)
171
+ * [minimagick] Don't print deprecation warning for old API twice when IO objects are used (@janko)
76
172
 
77
173
  ## 0.10.0 (2018-03-21)
78
174
 
79
- * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko-m)
175
+ * [minimagick] Rewrite MiniMagick module to use the chainable API (@janko)
80
176
 
81
- * [minimagick] Deprecate the old API (@janko-m)
177
+ * [minimagick] Deprecate the old API (@janko)
82
178
 
83
- * [minimagick] Raise an exception on processing warnings (@janko-m)
179
+ * [minimagick] Raise an exception on processing warnings (@janko)
84
180
 
85
- * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko-m)
181
+ * [minimagick] Speed up `.valid_image?` by an order of magnitude (@janko)
86
182
 
87
- * [minimagick] Don't accept arbitrary IO object anymore (@janko-m)
183
+ * [minimagick] Don't accept arbitrary IO object anymore (@janko)
88
184
 
89
- * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko-m)
185
+ * [minimagick] Removed unnecessary `#crop` and `#resample` macros (@janko)
90
186
 
91
- * [vips] Ignore undefined loader/saver options (@janko-m)
187
+ * [vips] Ignore undefined loader/saver options (@janko)
92
188
 
93
- * [vips] Preserve transparent background in `#resize_to_pad` (@janko-m)
189
+ * [vips] Preserve transparent background in `#resize_to_pad` (@janko)
94
190
 
95
- * [vips] Remove the ability to specify colors using names (@janko-m)
191
+ * [vips] Remove the ability to specify colors using names (@janko)
96
192
 
97
- * [minimagick, vips] Autorotate images after loading them (@janko-m)
193
+ * [minimagick, vips] Autorotate images after loading them (@janko)
98
194
 
99
- * [core] Delete result `Tempfile` object in case of processing errors (@janko-m)
195
+ * [core] Delete result `Tempfile` object in case of processing errors (@janko)
100
196
 
101
- * [core] Allow returning `nil` in the `#custom` block (@janko-m)
197
+ * [core] Allow returning `nil` in the `#custom` block (@janko)
102
198
 
103
- * [core] Allow specifying a path string as source file (@janko-m)
199
+ * [core] Allow specifying a path string as source file (@janko)
104
200
 
105
- * [core] Allow saving to a specific location with the `:destination` call option (@janko-m)
201
+ * [core] Allow saving to a specific location with the `:destination` call option (@janko)
106
202
 
107
203
  ## 0.9.0 (2018-03-16)
108
204
 
109
- * Added libvips module (@GustavoCaso, @janko-m)
205
+ * Added libvips module (@GustavoCaso, @janko)
110
206
 
111
207
  * Drop official support for MRI 2.0 and 2.1
112
208
 
@@ -116,15 +212,15 @@
116
212
 
117
213
  ## 0.4.4 (2017-06-16)
118
214
 
119
- * Fix last changes being incompatible with older Ruby versions, again (@janko-m)
215
+ * Fix last changes being incompatible with older Ruby versions, again (@janko)
120
216
 
121
217
  ## 0.4.3 (2017-06-16)
122
218
 
123
- * Fix last changes being incompatible with older Ruby versions (@janko-m)
219
+ * Fix last changes being incompatible with older Ruby versions (@janko)
124
220
 
125
221
  ## 0.4.2 (2017-06-16)
126
222
 
127
- * Don't use path of input file as basename for output file (@janko-m)
223
+ * Don't use path of input file as basename for output file (@janko)
128
224
 
129
225
  ## 0.4.1 (2016-09-08)
130
226
 
data/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  Provides higher-level image processing helpers that are commonly needed
4
4
  when handling image uploads.
5
5
 
6
- This gem can process images with either [ImageMagick] or [libvips] libraries.
7
- ImageMagick is a good default choice, especially if you are migrating from
8
- another gem or library that uses ImageMagick. Libvips is a newer library that
9
- can process images [very rapidly][libvips performance] (up to 10x faster than
10
- ImageMagick).
6
+ This gem can process images with either [ImageMagick]/[GraphicsMagick] or
7
+ [libvips] libraries. ImageMagick is a good default choice, especially if you
8
+ are migrating from another gem or library that uses ImageMagick. Libvips is a
9
+ newer library that can process images [very rapidly][libvips performance]
10
+ (often multiple times faster than ImageMagick).
11
11
 
12
12
 
13
13
  ## Goal
@@ -29,10 +29,18 @@ how to resize and process images.
29
29
 
30
30
  1. Install ImageMagick and/or libvips:
31
31
 
32
- ```sh
32
+ In a Mac terminal:
33
+
34
+ ```sh
33
35
  $ brew install imagemagick vips
34
36
  ```
35
37
 
38
+ In a debian/ubuntu terminal:
39
+
40
+ ```sh
41
+ $ sudo apt install imagemagick libvips
42
+ ```
43
+
36
44
  2. Add the gem to your Gemfile:
37
45
 
38
46
  ```rb
@@ -42,9 +50,9 @@ how to resize and process images.
42
50
 
43
51
  ## Usage
44
52
 
45
- Processing is performed through [`ImageProcessing::Vips`] or
46
- [`ImageProcessing::MiniMagick`] modules. Both modules share the same chainable
47
- API for defining the processing pipeline:
53
+ Processing is performed through **[`ImageProcessing::Vips`]** or
54
+ **[`ImageProcessing::MiniMagick`]** modules. Both modules share the same
55
+ chainable API for defining the processing pipeline:
48
56
 
49
57
  ```rb
50
58
  require "image_processing/mini_magick"
@@ -117,7 +125,8 @@ pipeline.options
117
125
  ```
118
126
 
119
127
  The source object needs to responds to `#path`, or be a String, a Pathname, or
120
- a `Vips::Image`/`MiniMagick::Tool` object.
128
+ a `Vips::Image`/`MiniMagick::Tool` object. Note that the processed file is
129
+ always saved to a new location, in-place processing is not supported.
121
130
 
122
131
  ```rb
123
132
  ImageProcessing::Vips.source(File.open("source.jpg"))
@@ -144,17 +153,53 @@ You can continue reading the API documentation for specific modules:
144
153
  * **[`ImageProcessing::Vips`]**
145
154
  * **[`ImageProcessing::MiniMagick`]**
146
155
 
147
- See the **[wiki]** for additional "How To" guides for common scenarios.
156
+ See the **[wiki]** for additional "How To" guides for common scenarios. The wiki
157
+ is publicly editable, so you're encouraged to add your own guides.
148
158
 
159
+ ## Instrumentation
160
+
161
+ You can register an `#instrumenter` block for a given pipeline, which will wrap
162
+ the pipeline execution, allowing you to record performance metrics.
163
+
164
+ ```rb
165
+ pipeline = ImageProcessing::Vips.instrumenter do |**options, &processing|
166
+ options[:source] #=> #<File:...>
167
+ options[:loader] #=> { fail: true }
168
+ options[:saver] #=> { quality: 85 }
169
+ options[:format] #=> "png"
170
+ options[:operations] #=> [[:resize_to_limit, 500, 500], [:flip, [:horizontal]]]
171
+ options[:processor] #=> ImageProcessing::Vips::Processor
172
+
173
+ ActiveSupport::Notifications.instrument("process.image_processing", **options) do
174
+ processing.call # calls the pipeline
175
+ end
176
+ end
177
+
178
+ pipeline
179
+ .source(image)
180
+ .loader(fail: true)
181
+ .saver(quality: 85)
182
+ .convert("png")
183
+ .resize_to_limit(500, 500)
184
+ .flip(:horizontal)
185
+ .call # calls instrumenter
186
+ ```
149
187
 
150
188
  ## Contributing
151
189
 
152
190
  Our test suite requires both `imagemagick` and `libvips` libraries to be installed.
153
191
 
192
+ In a Mac terminal:
193
+
154
194
  ```
155
195
  $ brew install imagemagick vips
156
196
  ```
157
197
 
198
+ In a debian/ubuntu terminal:
199
+ ```shell
200
+ sudo apt install imagemagick libvips
201
+ ```
202
+
158
203
  Afterwards you can run tests with
159
204
 
160
205
  ```
@@ -179,11 +224,12 @@ The `ImageProcessing::MiniMagick` functionality was extracted from
179
224
 
180
225
  [MIT](LICENSE.txt)
181
226
 
182
- [libvips]: http://jcupitt.github.io/libvips/
227
+ [libvips]: http://libvips.github.io/libvips/
183
228
  [ImageMagick]: https://www.imagemagick.org
184
- [`ImageProcessing::Vips`]: /doc/vips.md#imageprocessingvips
185
- [`ImageProcessing::MiniMagick`]: /doc/minimagick.md#imageprocessingminimagick
229
+ [GraphicsMagick]: http://www.graphicsmagick.org
230
+ [`ImageProcessing::Vips`]: doc/vips.md#readme
231
+ [`ImageProcessing::MiniMagick`]: doc/minimagick.md#readme
186
232
  [refile-mini_magick]: https://github.com/refile/refile-mini_magick
187
- [wiki]: https://github.com/janko-m/image_processing/wiki
233
+ [wiki]: https://github.com/janko/image_processing/wiki
188
234
  [HTTP.rb]: https://github.com/httprb/http
189
- [libvips performance]: https://github.com/jcupitt/libvips/wiki/Speed-and-memory-use
235
+ [libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use
@@ -1,14 +1,14 @@
1
- require File.expand_path('../lib/image_processing/version', __FILE__)
1
+ require File.expand_path("../lib/image_processing/version", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "image_processing"
5
5
  spec.version = ImageProcessing::VERSION
6
6
 
7
- spec.required_ruby_version = ">= 2.0"
7
+ spec.required_ruby_version = ">= 2.3"
8
8
 
9
- spec.summary = "Set of higher-level helper methods for image processing."
10
- spec.description = "Set of higher-level helper methods for image processing."
11
- spec.homepage = "https://github.com/janko-m/image_processing"
9
+ spec.summary = "High-level wrapper for processing images for the web with ImageMagick or libvips."
10
+ spec.description = "High-level wrapper for processing images for the web with ImageMagick or libvips."
11
+ spec.homepage = "https://github.com/janko/image_processing"
12
12
  spec.authors = ["Janko Marohnić"]
13
13
  spec.email = ["janko.marohnic@gmail.com"]
14
14
  spec.license = "MIT"
@@ -16,12 +16,12 @@ Gem::Specification.new do |spec|
16
16
  spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*.rb", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "mini_magick", "~> 4.0"
20
- spec.add_dependency "ruby-vips", ">= 2.0.10", "< 3"
19
+ spec.add_dependency "mini_magick", ">= 4.9.5", "< 5"
20
+ spec.add_dependency "ruby-vips", ">= 2.0.17", "< 3"
21
21
 
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "minitest", "~> 5.8"
24
24
  spec.add_development_dependency "minitest-hooks", ">= 1.4.2"
25
25
  spec.add_development_dependency "minispec-metadata"
26
- spec.add_development_dependency "phashion" unless RUBY_ENGINE == "jruby"
26
+ spec.add_development_dependency "dhash-vips"
27
27
  end
@@ -8,8 +8,25 @@ module ImageProcessing
8
8
  @options = options
9
9
  end
10
10
 
11
- def call!(**options)
12
- Pipeline.new(self.options).call(**options)
11
+ # Calls the pipeline to perform the processing from built options.
12
+ def call!(**call_options)
13
+ instrument do
14
+ Pipeline.new(pipeline_options).call(**call_options)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def instrument
21
+ return yield unless options[:instrumenter]
22
+
23
+ result = nil
24
+ options[:instrumenter].call(**pipeline_options) { result = yield }
25
+ result
26
+ end
27
+
28
+ def pipeline_options
29
+ options.reject { |key, _| key == :instrumenter }
13
30
  end
14
31
  end
15
32
  end
@@ -1,77 +1,104 @@
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
 
19
- def custom(&block)
20
- operation :custom, block
24
+ # Register instrumentation block that will be called around the pipeline.
25
+ def instrumenter(&block)
26
+ branch instrumenter: block
21
27
  end
22
28
 
29
+ # Add multiple operations as a hash or an array.
30
+ #
31
+ # .apply(resize_to_limit: [400, 400], strip: true)
32
+ # # or
33
+ # .apply([[:resize_to_limit, [400, 400]], [:strip, true])
23
34
  def apply(operations)
24
35
  operations.inject(self) do |builder, (name, argument)|
25
36
  if argument == true || argument == nil
26
- builder.send(name)
37
+ builder.public_send(name)
27
38
  elsif argument.is_a?(Array)
28
- builder.send(name, *argument)
39
+ builder.public_send(name, *argument)
40
+ elsif argument.is_a?(Hash)
41
+ builder.public_send(name, **argument)
29
42
  else
30
- builder.send(name, argument)
43
+ builder.public_send(name, argument)
31
44
  end
32
45
  end
33
46
  end
34
47
 
35
- def method_missing(name, *args)
36
- return super if name.to_s.end_with?("?")
37
- return send(name.to_s.chomp("!"), *args).call if name.to_s.end_with?("!")
38
-
39
- operation name, *args
40
- end
41
-
42
- def operation(name, *args)
43
- branch operations: [[name, args]]
48
+ # Add an operation defined by the processor.
49
+ def operation(name, *args, &block)
50
+ branch operations: [[name, args, *block]]
44
51
  end
45
52
 
53
+ # Call the defined processing and get the result. Allows specifying
54
+ # the source file and destination.
46
55
  def call(file = nil, destination: nil, **call_options)
47
56
  options = {}
48
- options = options.merge(source: file) if file
49
- options = options.merge(destination: destination) if destination
57
+ options[:source] = file if file
58
+ options[:destination] = destination if destination
50
59
 
51
- branch(options).call!(**call_options)
60
+ branch(**options).call!(**call_options)
52
61
  end
53
62
 
54
- def branch(loader: nil, saver: nil, operations: nil, **other_options)
55
- options = respond_to?(:options) ? self.options : DEFAULT_OPTIONS
63
+ # Creates a new builder object, merging current options with new options.
64
+ def branch(**new_options)
65
+ if self.is_a?(Builder)
66
+ options = self.options
67
+ else
68
+ options = DEFAULT_OPTIONS.merge(processor: self::Processor)
69
+ end
56
70
 
57
- options = options.merge(loader: options[:loader].merge(loader)) if loader
58
- options = options.merge(saver: options[:saver].merge(saver)) if saver
59
- options = options.merge(operations: options[:operations] + operations) if operations
60
- options = options.merge(processor_class: self::Processor) unless self.is_a?(Builder)
61
- options = options.merge(other_options)
71
+ options = options.merge(new_options) do |key, old_value, new_value|
72
+ case key
73
+ when :loader, :saver then old_value.merge(new_value)
74
+ when :operations then old_value + new_value
75
+ else new_value
76
+ end
77
+ end
78
+
79
+ Builder.new(options.freeze)
80
+ end
62
81
 
63
- options.freeze
82
+ private
83
+
84
+ # Assume that any unknown method names an operation supported by the
85
+ # processor. Add a bang ("!") if you want processing to be performed.
86
+ def method_missing(name, *args, &block)
87
+ return super if name.to_s.end_with?("?")
88
+ return send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
64
89
 
65
- Builder.new(options)
90
+ operation(name, *args, &block)
66
91
  end
92
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
67
93
 
94
+ # Empty options which the builder starts with.
68
95
  DEFAULT_OPTIONS = {
69
- source: nil,
70
- loader: {},
71
- saver: {},
72
- format: nil,
73
- operations: [],
74
- processor_class: nil,
96
+ source: nil,
97
+ loader: {},
98
+ saver: {},
99
+ format: nil,
100
+ operations: [],
101
+ processor: nil,
75
102
  }.freeze
76
103
  end
77
104
  end