Files

236 lines
6.1 KiB
Markdown
Raw Permalink Normal View History

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
In a Mac terminal:
2023-09-24 15:53:48 +02:00
```sh
2018-04-04 21:30:13 +02:00
$ brew install imagemagick vips
```
2018-04-03 19:30:02 -07: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
## 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
require "image_processing/mini_magick"
2018-03-16 14:58:37 +01:00
processed = ImageProcessing::MiniMagick
.source(file)
2018-03-16 14:58:37 +01:00
.resize_to_limit(400, 400)
.convert("png")
.call
2018-03-16 14:58:37 +01: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:
```rb
require "image_processing/vips"
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
```
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
a `Vips::Image`/`MiniMagick::Tool` object. Note that the processed file is
always saved to a new location, in-place processing is not supported.
```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
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:
* **[`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.
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
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
```
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
```
$ 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
[libvips performance]: https://github.com/libvips/libvips/wiki/Speed-and-memory-use