2015-10-03 20:36:13 +02:00
|
|
|
# ImageProcessing
|
|
|
|
|
|
2018-04-03 19:30:02 -07:00
|
|
|
Provides higher-level image processing helpers that are commonly needed
|
|
|
|
|
when handling image uploads.
|
2015-10-03 22:15:45 +02:00
|
|
|
|
2018-04-19 13:45:31 +02:00
|
|
|
This gem can process images with either [ImageMagick]/[GraphicsMagick] or
|
|
|
|
|
[libvips] libraries. ImageMagick is a good default choice, especially if you
|
|
|
|
|
are migrating from another gem or library that uses ImageMagick. Libvips is a
|
2019-02-05 04:00:27 +01:00
|
|
|
newer library that can process images [very rapidly][libvips performance]
|
|
|
|
|
(often multiple times faster than ImageMagick).
|
2015-10-03 20:36:13 +02:00
|
|
|
|
2018-04-03 19:40:02 -07:00
|
|
|
|
|
|
|
|
## Goal
|
|
|
|
|
|
|
|
|
|
The goal of this project is to have a single gem that contains all the
|
2018-04-04 08:48:50 -07:00
|
|
|
helper methods needed to resize and process images.
|
|
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
Currently, existing attachment gems (like Paperclip, CarrierWave, Refile,
|
|
|
|
|
Dragonfly, ActiveStorage, and others) implement their own custom image
|
2018-04-04 08:48:50 -07:00
|
|
|
helper methods. But why? That's not very DRY, is it?
|
2018-04-03 19:40:02 -07:00
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
Let's be honest. Image processing is a dark, mysterious art. So we want to
|
|
|
|
|
combine every great idea from all of these separate gems into a single awesome
|
|
|
|
|
library that is constantly updated with best-practice thinking about
|
2018-04-03 19:43:15 -07:00
|
|
|
how to resize and process images.
|
2018-04-03 19:40:02 -07:00
|
|
|
|
|
|
|
|
|
2015-10-03 20:36:13 +02:00
|
|
|
## Installation
|
|
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
1. Install ImageMagick and/or libvips:
|
2018-04-03 19:30:02 -07:00
|
|
|
|
2022-01-13 13:55:34 +06:00
|
|
|
In a Mac terminal:
|
2023-09-24 15:53:48 +02:00
|
|
|
|
2022-01-13 13:55:34 +06:00
|
|
|
```sh
|
2018-04-04 21:30:13 +02:00
|
|
|
$ brew install imagemagick vips
|
|
|
|
|
```
|
2018-04-03 19:30:02 -07:00
|
|
|
|
2022-01-13 13:55:34 +06:00
|
|
|
In a debian/ubuntu terminal:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
$ sudo apt install imagemagick libvips
|
|
|
|
|
```
|
|
|
|
|
|
2018-04-03 19:30:02 -07:00
|
|
|
2. Add the gem to your Gemfile:
|
|
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
```rb
|
2018-04-04 22:01:31 +02:00
|
|
|
gem "image_processing", "~> 1.0"
|
2018-04-04 21:30:13 +02:00
|
|
|
```
|
2018-04-03 19:30:02 -07:00
|
|
|
|
2015-10-03 20:36:13 +02:00
|
|
|
|
2018-03-17 02:04:51 +01:00
|
|
|
## Usage
|
2018-03-16 14:58:37 +01:00
|
|
|
|
2020-01-07 16:27:29 +01:00
|
|
|
Processing is performed through **[`ImageProcessing::Vips`]** or
|
|
|
|
|
**[`ImageProcessing::MiniMagick`]** modules. Both modules share the same
|
|
|
|
|
chainable API for defining the processing pipeline:
|
2018-03-16 14:58:37 +01:00
|
|
|
|
|
|
|
|
```rb
|
2018-03-17 02:04:51 +01:00
|
|
|
require "image_processing/mini_magick"
|
2018-03-16 14:58:37 +01:00
|
|
|
|
2018-03-17 02:04:51 +01:00
|
|
|
processed = ImageProcessing::MiniMagick
|
2018-03-16 15:49:41 +01:00
|
|
|
.source(file)
|
2018-03-16 14:58:37 +01:00
|
|
|
.resize_to_limit(400, 400)
|
2018-03-16 15:49:41 +01:00
|
|
|
.convert("png")
|
|
|
|
|
.call
|
2018-03-16 14:58:37 +01:00
|
|
|
|
2018-04-04 21:50:27 +02:00
|
|
|
processed #=> #<Tempfile:/var/folders/.../image_processing20180316-18446-1j247h6.png>
|
2018-03-16 14:58:37 +01:00
|
|
|
```
|
|
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
This allows easy branching when generating multiple derivates:
|
2018-03-16 15:49:41 +01:00
|
|
|
|
|
|
|
|
```rb
|
2018-03-17 02:04:51 +01:00
|
|
|
require "image_processing/vips"
|
|
|
|
|
|
2018-03-16 15:49:41 +01:00
|
|
|
pipeline = ImageProcessing::Vips
|
|
|
|
|
.source(file)
|
|
|
|
|
.convert("png")
|
|
|
|
|
|
|
|
|
|
large = pipeline.resize_to_limit!(800, 800)
|
|
|
|
|
medium = pipeline.resize_to_limit!(500, 500)
|
|
|
|
|
small = pipeline.resize_to_limit!(300, 300)
|
|
|
|
|
```
|
|
|
|
|
|
2018-03-16 14:58:37 +01:00
|
|
|
The processing is executed on `#call` or when a processing method is called
|
|
|
|
|
with a bang (`!`).
|
|
|
|
|
|
|
|
|
|
```rb
|
2018-03-21 22:10:25 +01:00
|
|
|
processed = ImageProcessing::MiniMagick
|
2018-03-16 14:58:37 +01:00
|
|
|
.convert("png")
|
|
|
|
|
.resize_to_limit(400, 400)
|
|
|
|
|
.call(image)
|
|
|
|
|
|
|
|
|
|
# OR
|
|
|
|
|
|
2018-03-21 22:10:25 +01:00
|
|
|
processed = ImageProcessing::MiniMagick
|
2018-03-16 14:58:37 +01:00
|
|
|
.source(image) # declare source image
|
|
|
|
|
.convert("png")
|
|
|
|
|
.resize_to_limit(400, 400)
|
|
|
|
|
.call
|
|
|
|
|
|
|
|
|
|
# OR
|
|
|
|
|
|
2018-03-21 22:10:25 +01:00
|
|
|
processed = ImageProcessing::MiniMagick
|
2018-03-16 14:58:37 +01:00
|
|
|
.source(image)
|
|
|
|
|
.convert("png")
|
|
|
|
|
.resize_to_limit!(400, 400) # bang method
|
|
|
|
|
```
|
|
|
|
|
|
2018-04-03 13:03:40 +02:00
|
|
|
You can inspect the pipeline options at any point before executing it:
|
|
|
|
|
|
|
|
|
|
```rb
|
|
|
|
|
pipeline = ImageProcessing::MiniMagick
|
|
|
|
|
.source(image)
|
|
|
|
|
.loader(page: 1)
|
|
|
|
|
.convert("png")
|
|
|
|
|
.resize_to_limit(400, 400)
|
|
|
|
|
.strip
|
|
|
|
|
|
|
|
|
|
pipeline.options
|
|
|
|
|
# => {:source=>#<File:/path/to/source.jpg>,
|
|
|
|
|
# :loader=>{:page=>1},
|
|
|
|
|
# :saver=>{},
|
|
|
|
|
# :format=>"png",
|
|
|
|
|
# :operations=>[[:resize_to_limit, [400, 400]], [:strip, []]],
|
|
|
|
|
# :processor_class=>ImageProcessing::MiniMagick::Processor}
|
|
|
|
|
```
|
|
|
|
|
|
2018-03-21 22:10:25 +01:00
|
|
|
The source object needs to responds to `#path`, or be a String, a Pathname, or
|
2018-04-19 12:36:08 +02:00
|
|
|
a `Vips::Image`/`MiniMagick::Tool` object. Note that the processed file is
|
|
|
|
|
always saved to a new location, in-place processing is not supported.
|
2018-03-21 22:26:38 +01:00
|
|
|
|
|
|
|
|
```rb
|
|
|
|
|
ImageProcessing::Vips.source(File.open("source.jpg"))
|
|
|
|
|
ImageProcessing::Vips.source("source.jpg")
|
|
|
|
|
ImageProcessing::Vips.source(Pathname.new("source.jpg"))
|
|
|
|
|
ImageProcessing::Vips.source(Vips::Image.new_from_file("source.jpg"))
|
|
|
|
|
```
|
|
|
|
|
|
2018-04-04 21:30:13 +02:00
|
|
|
When `#call` is called without options, the result of processing is a
|
|
|
|
|
`Tempfile` object. You can save the processing result to a specific location by
|
|
|
|
|
passing `:destination` to `#call`, or pass `save: false` to retrieve the raw
|
|
|
|
|
`Vips::Image`/`MiniMagick::Tool` object.
|
2018-03-16 14:58:37 +01:00
|
|
|
|
|
|
|
|
```rb
|
|
|
|
|
pipeline = ImageProcessing::Vips.source(image)
|
2018-03-21 22:10:25 +01:00
|
|
|
|
2018-03-21 22:26:38 +01:00
|
|
|
pipeline.call #=> #<Tempfile ...>
|
|
|
|
|
pipeline.call(save: false) #=> #<Vips::Image ...>
|
|
|
|
|
pipeline.call(destination: "/path/to/destination")
|
2018-03-16 14:58:37 +01:00
|
|
|
```
|
|
|
|
|
|
2018-03-20 18:37:36 +01:00
|
|
|
You can continue reading the API documentation for specific modules:
|
2018-03-17 02:04:51 +01:00
|
|
|
|
2018-03-21 22:33:08 +01:00
|
|
|
* **[`ImageProcessing::Vips`]**
|
|
|
|
|
* **[`ImageProcessing::MiniMagick`]**
|
2015-10-04 02:42:36 +02:00
|
|
|
|
2018-04-19 12:35:47 +02:00
|
|
|
See the **[wiki]** for additional "How To" guides for common scenarios. The wiki
|
|
|
|
|
is publicly editable, so you're encouraged to add your own guides.
|
2018-03-21 22:44:13 +01:00
|
|
|
|
2020-09-20 21:19:50 +02:00
|
|
|
## Instrumentation
|
|
|
|
|
|
|
|
|
|
You can register an `#instrumenter` block for a given pipeline, which will wrap
|
|
|
|
|
the pipeline execution, allowing you to record performance metrics.
|
|
|
|
|
|
|
|
|
|
```rb
|
|
|
|
|
pipeline = ImageProcessing::Vips.instrumenter do |**options, &processing|
|
|
|
|
|
options[:source] #=> #<File:...>
|
|
|
|
|
options[:loader] #=> { fail: true }
|
|
|
|
|
options[:saver] #=> { quality: 85 }
|
|
|
|
|
options[:format] #=> "png"
|
|
|
|
|
options[:operations] #=> [[:resize_to_limit, 500, 500], [:flip, [:horizontal]]]
|
|
|
|
|
options[:processor] #=> ImageProcessing::Vips::Processor
|
|
|
|
|
|
|
|
|
|
ActiveSupport::Notifications.instrument("process.image_processing", **options) do
|
|
|
|
|
processing.call # calls the pipeline
|
|
|
|
|
end
|
|
|
|
|
end
|
2020-09-20 21:26:38 +02:00
|
|
|
|
|
|
|
|
pipeline
|
|
|
|
|
.source(image)
|
|
|
|
|
.loader(fail: true)
|
|
|
|
|
.saver(quality: 85)
|
|
|
|
|
.convert("png")
|
|
|
|
|
.resize_to_limit(500, 500)
|
|
|
|
|
.flip(:horizontal)
|
|
|
|
|
.call # calls instrumenter
|
2020-09-20 21:19:50 +02:00
|
|
|
```
|
2018-04-03 19:30:02 -07:00
|
|
|
|
2015-10-03 20:36:13 +02:00
|
|
|
## Contributing
|
|
|
|
|
|
2018-04-04 08:48:50 -07:00
|
|
|
Our test suite requires both `imagemagick` and `libvips` libraries to be installed.
|
2015-10-03 20:36:13 +02:00
|
|
|
|
2022-01-13 13:55:34 +06:00
|
|
|
In a Mac terminal:
|
|
|
|
|
|
2015-10-03 20:36:13 +02:00
|
|
|
```
|
2018-03-29 09:44:25 +02:00
|
|
|
$ brew install imagemagick vips
|
2015-10-03 20:36:13 +02:00
|
|
|
```
|
|
|
|
|
|
2022-01-13 13:55:34 +06:00
|
|
|
In a debian/ubuntu terminal:
|
|
|
|
|
```shell
|
|
|
|
|
sudo apt install imagemagick libvips
|
|
|
|
|
```
|
|
|
|
|
|
2018-03-16 14:58:37 +01:00
|
|
|
Afterwards you can run tests with
|
2015-10-03 20:36:13 +02:00
|
|
|
|
|
|
|
|
```
|
2018-03-30 00:31:46 +02:00
|
|
|
$ bundle exec rake test
|
2015-10-03 20:36:13 +02:00
|
|
|
```
|
|
|
|
|
|
2018-04-03 19:30:02 -07:00
|
|
|
|
|
|
|
|
## Feedback
|
|
|
|
|
|
|
|
|
|
We welcome your feedback! What would you like to see added to image_processing?
|
|
|
|
|
How can we improve this gem? Open an issue and let us know!
|
|
|
|
|
|
|
|
|
|
|
2018-03-16 14:58:37 +01:00
|
|
|
## Credits
|
|
|
|
|
|
|
|
|
|
The `ImageProcessing::MiniMagick` functionality was extracted from
|
2018-04-02 09:47:00 +02:00
|
|
|
[refile-mini_magick]. The chainable interface was heavily inspired by
|
|
|
|
|
[HTTP.rb].
|
2018-03-31 12:41:15 +02:00
|
|
|
|
2018-04-03 19:30:02 -07:00
|
|
|
|
2015-10-03 20:36:13 +02:00
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
[MIT](LICENSE.txt)
|
2016-05-03 19:50:53 +08:00
|
|
|
|
2018-09-27 01:11:17 +02:00
|
|
|
[libvips]: http://libvips.github.io/libvips/
|
2018-03-16 14:58:37 +01:00
|
|
|
[ImageMagick]: https://www.imagemagick.org
|
2018-04-19 13:45:31 +02:00
|
|
|
[GraphicsMagick]: http://www.graphicsmagick.org
|
2019-02-05 04:02:44 +01:00
|
|
|
[`ImageProcessing::Vips`]: doc/vips.md#readme
|
|
|
|
|
[`ImageProcessing::MiniMagick`]: doc/minimagick.md#readme
|
2016-05-03 19:50:53 +08:00
|
|
|
[refile-mini_magick]: https://github.com/refile/refile-mini_magick
|
2019-02-04 19:43:08 +01:00
|
|
|
[wiki]: https://github.com/janko/image_processing/wiki
|
2018-03-31 12:41:15 +02:00
|
|
|
[HTTP.rb]: https://github.com/httprb/http
|
2018-09-27 01:12:55 +02:00
|
|
|
[libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use
|