image_processing 1.2.0 → 1.12.2

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 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