jr-paperclip 7.3.0 → 8.0.0.beta.1
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 +4 -4
- data/.github/workflows/{test.yml → tests.yml} +19 -9
- data/.rubocop.yml +2 -1
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -0
- data/NEWS +16 -1
- data/README.md +119 -8
- data/UPGRADING +5 -0
- data/VIPS_MIGRATION_GUIDE.md +131 -0
- data/features/basic_integration.feature +27 -0
- data/features/step_definitions/attachment_steps.rb +17 -0
- data/gemfiles/7.0.gemfile +1 -0
- data/gemfiles/7.1.gemfile +1 -0
- data/gemfiles/7.2.gemfile +1 -0
- data/gemfiles/8.0.gemfile +1 -0
- data/gemfiles/8.1.gemfile +1 -0
- data/lib/paperclip/attachment.rb +3 -2
- data/lib/paperclip/errors.rb +4 -5
- data/lib/paperclip/geometry.rb +3 -3
- data/lib/paperclip/geometry_detector_factory.rb +52 -12
- data/lib/paperclip/helpers.rb +18 -0
- data/lib/paperclip/processor.rb +36 -4
- data/lib/paperclip/thumbnail.rb +568 -62
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +26 -9
- data/paperclip.gemspec +3 -2
- data/spec/paperclip/attachment_definitions_spec.rb +300 -0
- data/spec/paperclip/attachment_spec.rb +1 -1
- data/spec/paperclip/geometry_detector_spec.rb +81 -32
- data/spec/paperclip/geometry_spec.rb +8 -5
- data/spec/paperclip/helpers_spec.rb +49 -0
- data/spec/paperclip/lazy_thumbnail_compatibility_spec.rb +266 -0
- data/spec/paperclip/processor_spec.rb +35 -1
- data/spec/paperclip/style_spec.rb +58 -0
- data/spec/paperclip/thumbnail_custom_options_spec.rb +173 -0
- data/spec/paperclip/thumbnail_loader_options_spec.rb +53 -0
- data/spec/paperclip/thumbnail_security_spec.rb +42 -0
- data/spec/paperclip/thumbnail_spec.rb +1127 -172
- metadata +36 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08e0a02cb6a9a3a1b126b744de6afe4654e9db7bf841bb710ac29b3cb702f5a2'
|
|
4
|
+
data.tar.gz: 5c3c603853869aa41d56026de0d71788f87f7b98ec4d8382adc811e23bc9eb42
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b71eb967b7cb2b0980e665c4886bbb5754bac409677b0af4e13578101dde22d710ab2bc11e31287dac3e99520f53f9e9b44fe79f5285f5fd5aa2cfe070edf43
|
|
7
|
+
data.tar.gz: ab955ec831d70c792bcaccbb41b5e2b6754fe0badddc1a52735d5a974f0982e3cdda316e5db9a274da73132482515ebf5b74775780d8e179e6d2493154370610
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Tests
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -13,13 +13,23 @@ jobs:
|
|
|
13
13
|
strategy:
|
|
14
14
|
fail-fast: false
|
|
15
15
|
matrix:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
16
|
+
include:
|
|
17
|
+
- ruby: '3.0'
|
|
18
|
+
gemfile: gemfiles/7.0.gemfile
|
|
19
|
+
- ruby: '3.1'
|
|
20
|
+
gemfile: gemfiles/7.1.gemfile
|
|
21
|
+
- ruby: '3.2'
|
|
22
|
+
gemfile: gemfiles/7.2.gemfile
|
|
23
|
+
- ruby: '3.3'
|
|
24
|
+
gemfile: gemfiles/8.0.gemfile
|
|
25
|
+
- ruby: '3.4'
|
|
26
|
+
gemfile: gemfiles/7.2.gemfile
|
|
27
|
+
- ruby: '3.4'
|
|
28
|
+
gemfile: gemfiles/8.0.gemfile
|
|
29
|
+
- ruby: '3.4'
|
|
30
|
+
gemfile: gemfiles/8.1.gemfile
|
|
31
|
+
- ruby: '4.0'
|
|
32
|
+
gemfile: gemfiles/8.1.gemfile
|
|
23
33
|
|
|
24
34
|
env:
|
|
25
35
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
@@ -36,7 +46,7 @@ jobs:
|
|
|
36
46
|
- name: Install dependencies
|
|
37
47
|
run: |
|
|
38
48
|
sudo apt-get update
|
|
39
|
-
sudo apt-get install -y ghostscript imagemagick
|
|
49
|
+
sudo apt-get install -y ghostscript imagemagick libvips
|
|
40
50
|
sudo rm -f /etc/ImageMagick-6/policy.xml
|
|
41
51
|
|
|
42
52
|
- name: Run tests
|
data/.rubocop.yml
CHANGED
|
@@ -3,7 +3,7 @@ plugins:
|
|
|
3
3
|
|
|
4
4
|
AllCops:
|
|
5
5
|
NewCops: disable
|
|
6
|
-
TargetRubyVersion: 3.
|
|
6
|
+
TargetRubyVersion: 3.0
|
|
7
7
|
Include:
|
|
8
8
|
- "**/*.gemspec"
|
|
9
9
|
- "**/*.podspec"
|
|
@@ -24,6 +24,7 @@ AllCops:
|
|
|
24
24
|
- "vendor/**/*"
|
|
25
25
|
- "db/schema.rb"
|
|
26
26
|
- 'gemfiles/vendor/**/*'
|
|
27
|
+
- 'tmp/**/*'
|
|
27
28
|
Naming/AccessorMethodName:
|
|
28
29
|
Description: Check the naming of accessor methods for get_/set_.
|
|
29
30
|
Enabled: false
|
data/CONTRIBUTING.md
CHANGED
|
@@ -13,7 +13,7 @@ Here's a quick guide for contributing:
|
|
|
13
13
|
1. Make sure you have ImageMagick and Ghostscript installed. See [this section](./README.md#image-processor) of the README.
|
|
14
14
|
|
|
15
15
|
1. Run the tests. We only take pull requests with passing tests, and it's great
|
|
16
|
-
to know that you have a clean slate: `bundle && bundle exec rake`
|
|
16
|
+
to know that you have a clean slate: `bundle && bundle exec appraisal rake`
|
|
17
17
|
|
|
18
18
|
1. Add a test for your change. Only refactoring and documentation changes
|
|
19
19
|
require no new tests. If you are adding functionality or fixing a bug, we need
|
data/Gemfile
CHANGED
data/NEWS
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
8.0.0.beta.1 (2026-01-09)
|
|
2
|
+
|
|
3
|
+
* Feature: Add libvips backend alongside ImageMagick via the image_processing gem
|
|
4
|
+
* Feature: Per-attachment and per-style backend selection (`:backend` option)
|
|
5
|
+
* Feature: ImageMagick 7 detection (uses `magick` command when available)
|
|
6
|
+
* Feature: Add `ALLOWED_IMAGEMAGICK_OPTIONS` security whitelist (GHSA-r4mg-4433-c7g3)
|
|
7
|
+
* Feature: Cross-platform convert_options support (-strip, -quality, -rotate, etc.)
|
|
8
|
+
* Documentation: Add VIPS_MIGRATION_GUIDE.md with step-by-step migration instructions
|
|
9
|
+
* Documentation: Expand README with backend configuration examples
|
|
10
|
+
* Chores: Add image_processing ~> 1.14 as runtime dependency
|
|
11
|
+
* Chores: CI now installs libvips for testing both backends
|
|
12
|
+
* Tests: Comprehensive test coverage for both backends, geometry modifiers, and convert options
|
|
13
|
+
|
|
14
|
+
7.3.1 (2025-12-17)
|
|
15
|
+
* Improvement: Relax Ruby requirement to 3.0 and optimize CI matrix
|
|
2
16
|
|
|
17
|
+
7.3.0 (2025-12-16)
|
|
3
18
|
* Breaking: Require Ruby >= 3.2.0 and Rails >= 7.0.0
|
|
4
19
|
* Feature: Add support for Rails 7.0, 7.1, 7.2, 8.0, and 8.1
|
|
5
20
|
* Improvement: Support aws-sdk-s3 >= 1.196.1 with TransferManager for multipart uploads/downloads
|
data/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Paperclip
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
[](https://rubygems.org/gems/jr-paperclip)
|
|
4
5
|
[](https://qlty.sh/gh/jukra/projects/jr-paperclip)
|
|
5
|
-
](https://github.com/jukra/jr-paperclip/actions/workflows/tests.yml)
|
|
7
|
+
[](https://github.com/jukra/jr-paperclip/actions/workflows/reviewdog.yml)
|
|
7
8
|
|
|
8
|
-
**Revived fork with active maintenance and support for Rails 7.0, 7.1, 8.0, and 8.1 on Ruby 3.
|
|
9
|
+
**Revived fork with active maintenance and support for Rails 7.0, 7.1, 8.0, and 8.1 on Ruby 3.0 and newer.**
|
|
9
10
|
|
|
10
11
|
If you are looking for older versions, please check the [original fork](https://github.com/kreeti/kt-paperclip).
|
|
11
12
|
|
|
@@ -57,6 +58,7 @@ Please feel free to contribute Issues and pull requests.
|
|
|
57
58
|
- [Understanding Storage](#understanding-storage)
|
|
58
59
|
- [IO Adapters](#io-adapters)
|
|
59
60
|
- [Post Processing](#post-processing)
|
|
61
|
+
- [Image Processing Backends](#image-processing-backends)
|
|
60
62
|
- [Custom Attachment Processors](#custom-attachment-processors)
|
|
61
63
|
- [Events](#events)
|
|
62
64
|
- [URI Obfuscation](#uri-obfuscation)
|
|
@@ -103,6 +105,10 @@ Paperclip now requires Ruby version **>= 2.3** and Rails version **>= 4.2**
|
|
|
103
105
|
|
|
104
106
|
### Image Processor
|
|
105
107
|
|
|
108
|
+
Paperclip supports two main image processing backends: **ImageMagick** (default) and **libvips** (recommended for performance).
|
|
109
|
+
|
|
110
|
+
#### ImageMagick
|
|
111
|
+
|
|
106
112
|
[ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it. To ensure
|
|
107
113
|
that it does, on your command line, run `which convert` (one of the ImageMagick
|
|
108
114
|
utilities). This will give you the path where that utility is installed. For
|
|
@@ -131,6 +137,32 @@ the following with apt-get:
|
|
|
131
137
|
|
|
132
138
|
sudo apt-get install imagemagick -y
|
|
133
139
|
|
|
140
|
+
#### libvips (Recommended for Performance)
|
|
141
|
+
|
|
142
|
+
[libvips](https://www.libvips.org/) is significantly faster and uses less memory than ImageMagick.
|
|
143
|
+
|
|
144
|
+
To use libvips, install the system library:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# macOS
|
|
148
|
+
brew install vips
|
|
149
|
+
|
|
150
|
+
# Ubuntu/Debian
|
|
151
|
+
sudo apt install libvips
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Then configure Paperclip to use it as the default backend in `config/initializers/paperclip.rb` (or in your environment configuration):
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
config.paperclip_defaults = {
|
|
158
|
+
backend: :vips
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
You can also specify the backend per-attachment (see [Image Processing Backends](#image-processing-backends)).
|
|
163
|
+
|
|
164
|
+
**Note on Geometry Detection:** When `vips` is the active backend, Paperclip uses the ruby-vips gem to determine image dimensions instead of ImageMagick's `identify` command.
|
|
165
|
+
|
|
134
166
|
### `file`
|
|
135
167
|
|
|
136
168
|
The Unix [`file` command](https://en.wikipedia.org/wiki/File_(command)) is required for content-type checking.
|
|
@@ -690,11 +722,11 @@ has_attached_file :avatar, styles: { thumb: ["32x32#", :png] }
|
|
|
690
722
|
|
|
691
723
|
This will convert the "thumb" style to a 32x32 square in PNG format, regardless
|
|
692
724
|
of what was uploaded. If the format is not specified, it is kept the same (e.g.
|
|
693
|
-
JPGs will remain JPGs). `Paperclip::Thumbnail` uses
|
|
694
|
-
|
|
695
|
-
has more information on the accepted style formats.
|
|
725
|
+
JPGs will remain JPGs). `Paperclip::Thumbnail` uses the [image_processing](https://github.com/janko/image_processing) gem to process images. This allows support for both ImageMagick (via MiniMagick) and libvips backends.
|
|
726
|
+
[ImageMagick's geometry documentation](http://www.imagemagick.org/script/command-line-processing.php#geometry)
|
|
727
|
+
has more information on the accepted style formats, which are generally supported by both backends in Paperclip.
|
|
696
728
|
|
|
697
|
-
For more fine-grained control of the conversion process, `source_file_options` and `convert_options` can be used
|
|
729
|
+
For more fine-grained control of the conversion process, `source_file_options` and `convert_options` can be used. These options are parsed and applied to the `image_processing` pipeline.
|
|
698
730
|
|
|
699
731
|
```ruby
|
|
700
732
|
has_attached_file :image, styles: { regular: ['800x800>', :png]},
|
|
@@ -702,6 +734,42 @@ has_attached_file :image, styles: { regular: ['800x800>', :png]},
|
|
|
702
734
|
convert_options: { regular: "-posterize 3"}
|
|
703
735
|
```
|
|
704
736
|
|
|
737
|
+
Since Paperclip now delegates to the `image_processing` gem, you should refer to its documentation for available methods/operations for your chosen backend:
|
|
738
|
+
|
|
739
|
+
* **ImageMagick:** [ImageProcessing::MiniMagick documentation](https://github.com/janko/image_processing/blob/master/doc/minimagick.md)
|
|
740
|
+
* **libvips:** [ImageProcessing::Vips documentation](https://github.com/janko/image_processing/blob/master/doc/vips.md)
|
|
741
|
+
|
|
742
|
+
Common options like `-strip`, `-quality`, `-rotate`, `-blur` are supported on both backends, but backend-specific options (like `-density` for ImageMagick) might not be available or behave differently on libvips.
|
|
743
|
+
|
|
744
|
+
### Cross-Platform Convert Options
|
|
745
|
+
|
|
746
|
+
Many common `convert_options` now work with **both** ImageMagick and libvips backends:
|
|
747
|
+
|
|
748
|
+
| Option | Description | Example |
|
|
749
|
+
|--------|-------------|---------|
|
|
750
|
+
| `-strip` | Remove metadata/EXIF | `convert_options: "-strip"` |
|
|
751
|
+
| `-quality N` | Output quality (1-100) | `convert_options: "-quality 80"` |
|
|
752
|
+
| `-rotate N` | Rotate by degrees | `convert_options: "-rotate 90"` |
|
|
753
|
+
| `-flip` | Vertical flip | `convert_options: "-flip"` |
|
|
754
|
+
| `-flop` | Horizontal flip | `convert_options: "-flop"` |
|
|
755
|
+
| `-blur 0xN` | Gaussian blur | `convert_options: "-blur 0x2"` |
|
|
756
|
+
| `-sharpen 0xN` | Sharpen image | `convert_options: "-sharpen 0x1"` |
|
|
757
|
+
| `-colorspace X` | Color space (Gray, sRGB, CMYK) | `convert_options: "-colorspace Gray"` |
|
|
758
|
+
| `-negate` | Invert colors | `convert_options: "-negate"` |
|
|
759
|
+
| `-flatten` | Flatten transparency | `convert_options: "-flatten"` |
|
|
760
|
+
| `-auto-orient` | Auto-rotate via EXIF | `convert_options: "-auto-orient"` |
|
|
761
|
+
| `-interlace X` | Progressive output | `convert_options: "-interlace Plane"` |
|
|
762
|
+
|
|
763
|
+
Example:
|
|
764
|
+
|
|
765
|
+
```ruby
|
|
766
|
+
has_attached_file :avatar,
|
|
767
|
+
styles: { thumb: "100x100#" },
|
|
768
|
+
convert_options: { all: "-strip -quality 80" }
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
**Note:** Some options only work with ImageMagick (e.g., `-density`, `-depth`, `-gravity`, `-crop`, `-trim`). When using the vips backend, these will be skipped with a warning logged.
|
|
772
|
+
|
|
705
773
|
ImageMagick supports a number of environment variables for controlling its resource limits. For example, you can enforce memory or execution time limits by setting the following variables in your application's process environment:
|
|
706
774
|
|
|
707
775
|
* `MAGICK_MEMORY_LIMIT=128MiB`
|
|
@@ -712,6 +780,48 @@ For a full list of variables and description, see [ImageMagick's resources docum
|
|
|
712
780
|
|
|
713
781
|
---
|
|
714
782
|
|
|
783
|
+
Image Processing Backends
|
|
784
|
+
-------------------------
|
|
785
|
+
|
|
786
|
+
jr-paperclip supports two image processing backends:
|
|
787
|
+
|
|
788
|
+
### ImageMagick (Default)
|
|
789
|
+
|
|
790
|
+
The traditional backend, using ImageMagick via shell commands.
|
|
791
|
+
|
|
792
|
+
```ruby
|
|
793
|
+
has_attached_file :avatar,
|
|
794
|
+
styles: { thumb: "100x100#" }
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### libvips (Recommended for Performance)
|
|
798
|
+
|
|
799
|
+
libvips is significantly faster and uses less memory than ImageMagick.
|
|
800
|
+
|
|
801
|
+
**Usage:**
|
|
802
|
+
|
|
803
|
+
```ruby
|
|
804
|
+
# Global default (in config/initializers/paperclip.rb or environment config)
|
|
805
|
+
config.paperclip_defaults = {
|
|
806
|
+
backend: :vips
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
# Or per-attachment
|
|
810
|
+
has_attached_file :avatar,
|
|
811
|
+
styles: { thumb: "100x100#" },
|
|
812
|
+
backend: :vips,
|
|
813
|
+
convert_options: { all: "-strip -quality 75" }
|
|
814
|
+
|
|
815
|
+
# Per-style backend selection (mix backends in one attachment)
|
|
816
|
+
has_attached_file :document,
|
|
817
|
+
styles: {
|
|
818
|
+
preview: { geometry: "800x800>", backend: :vips },
|
|
819
|
+
thumb: { geometry: "100x100#", backend: :image_magick }
|
|
820
|
+
}
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
715
825
|
Custom Attachment Processors
|
|
716
826
|
-------
|
|
717
827
|
|
|
@@ -1078,6 +1188,7 @@ Thank you to all [the contributors](https://github.com/jukra/jr-paperclip/graphs
|
|
|
1078
1188
|
License
|
|
1079
1189
|
-------
|
|
1080
1190
|
|
|
1081
|
-
Copyright
|
|
1191
|
+
Copyright (c) 2025- Jukka Rautanen
|
|
1192
|
+
Copyright © 2020-2025 Kreeti Technologies Pvt. Ltd.
|
|
1082
1193
|
Copyright © 2008-2017 thoughtbot, inc.
|
|
1083
1194
|
It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/UPGRADING
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
jr-paperclip – HEADS UP (major changes)
|
|
2
|
+
|
|
3
|
+
This version adds libvips support as a high-performance alternative to ImageMagick.
|
|
4
|
+
It also introduces ImageMagick 7 compatibility and updates geometry detection behavior.
|
|
5
|
+
For migration instructions and details, see README.md and VIPS_MIGRATION_GUIDE.md.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Migrating to the libvips Backend
|
|
2
|
+
|
|
3
|
+
Paperclip now supports [libvips](https://www.libvips.org/) via the `image_processing` gem. libvips is significantly faster and uses much less memory than ImageMagick, making it highly recommended for production environments.
|
|
4
|
+
|
|
5
|
+
This guide explains how to migrate your application to use libvips, either globally or gradually.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
You must install the libvips system library on your server or development machine:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# macOS
|
|
13
|
+
brew install vips
|
|
14
|
+
|
|
15
|
+
# Ubuntu/Debian
|
|
16
|
+
sudo apt install libvips
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Step 1: Update your Gemfile
|
|
20
|
+
|
|
21
|
+
`jr-paperclip` already includes the `image_processing` gem, which automatically provides the `ruby-vips` and `mini_magick` bindings. You do **not** need to add these gems explicitly to your `Gemfile`.
|
|
22
|
+
|
|
23
|
+
Ensure you are using the latest version of the gem:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem "jr-paperclip", "~> 8.0.0.beta"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 2: Gradual Migration (Per-Attachment)
|
|
30
|
+
|
|
31
|
+
The safest way to migrate is one attachment at a time. This allows you to verify that the output remains consistent and doesn't interfere with existing custom processors.
|
|
32
|
+
|
|
33
|
+
Simply add the `backend: :vips` option to a specific attachment:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
class User < ActiveRecord::Base
|
|
37
|
+
has_attached_file :avatar,
|
|
38
|
+
styles: { medium: "300x300>", thumb: "100x100#" },
|
|
39
|
+
backend: :vips
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Other attachments in your application will continue to use ImageMagick by default.
|
|
44
|
+
|
|
45
|
+
## Step 3: Cross-Platform Convert Options
|
|
46
|
+
|
|
47
|
+
Good news! Many common `convert_options` now work with **both** ImageMagick and libvips backends. You can keep using them as-is:
|
|
48
|
+
|
|
49
|
+
### Options That Work on Both Backends
|
|
50
|
+
|
|
51
|
+
| Option | Description |
|
|
52
|
+
|--------|-------------|
|
|
53
|
+
| `-strip` | Remove metadata/EXIF data |
|
|
54
|
+
| `-quality N` | Output quality (1-100) |
|
|
55
|
+
| `-rotate N` | Rotate by degrees |
|
|
56
|
+
| `-flip` | Vertical flip |
|
|
57
|
+
| `-flop` | Horizontal flip |
|
|
58
|
+
| `-blur 0xN` | Gaussian blur |
|
|
59
|
+
| `-sharpen 0xN` | Sharpen image |
|
|
60
|
+
| `-colorspace X` | Color space (Gray, sRGB, CMYK) |
|
|
61
|
+
| `-negate` | Invert colors |
|
|
62
|
+
| `-flatten` | Flatten transparency |
|
|
63
|
+
| `-auto-orient` | Auto-rotate via EXIF |
|
|
64
|
+
| `-interlace X` | Progressive/interlaced output |
|
|
65
|
+
|
|
66
|
+
**Example:**
|
|
67
|
+
```ruby
|
|
68
|
+
has_attached_file :avatar,
|
|
69
|
+
styles: { thumb: "100x100#" },
|
|
70
|
+
backend: :vips,
|
|
71
|
+
convert_options: { all: "-strip -quality 80" }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### ImageMagick-Only Options
|
|
75
|
+
|
|
76
|
+
The following options only work with ImageMagick. When used with the vips backend, they will be skipped and a warning will be logged:
|
|
77
|
+
|
|
78
|
+
`-density`, `-depth`, `-gravity`, `-crop`, `-extent`, `-alpha`, `-background`, `-type`, `-posterize`, `-dither`, `-colors`, `-channel`, `-transpose`, `-transverse`, `-normalize`, `-equalize`, `-trim`, `-monochrome`
|
|
79
|
+
|
|
80
|
+
If you rely heavily on these options, consider keeping those specific attachments on the ImageMagick backend.
|
|
81
|
+
|
|
82
|
+
## Step 4: Handling Custom Processors
|
|
83
|
+
|
|
84
|
+
If you have custom processors defined in `lib/paperclip`, they will continue to work even if you switch the primary backend to `:vips`, as long as they are still calling the `convert` or `identify` helper methods.
|
|
85
|
+
|
|
86
|
+
However, if you want to migrate a custom processor to libvips, you can now use the `vips`, `vips_image` and `vipsheader` helpers:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
module Paperclip
|
|
90
|
+
class MyVipsProcessor < Processor
|
|
91
|
+
def make
|
|
92
|
+
# Use the new vips helper instead of convert
|
|
93
|
+
vips("thumbnail :src :dst 100",
|
|
94
|
+
src: File.expand_path(file.path),
|
|
95
|
+
dst: File.expand_path(dst.path)
|
|
96
|
+
)
|
|
97
|
+
dst
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Step 5: Global Migration
|
|
104
|
+
|
|
105
|
+
Once you have verified that your attachments and processors work correctly with libvips, you can switch the entire application over by updating your global configuration:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
# config/initializers/paperclip.rb or config/environments/production.rb
|
|
109
|
+
config.paperclip_defaults = {
|
|
110
|
+
backend: :vips,
|
|
111
|
+
convert_options: { all: "-strip -quality 85" }
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
You can also use per-style backend selection to mix backends within a single attachment:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
has_attached_file :document,
|
|
119
|
+
styles: {
|
|
120
|
+
# Use vips for large previews (faster)
|
|
121
|
+
preview: { geometry: "800x800>", backend: :vips },
|
|
122
|
+
# Use ImageMagick for thumbnails needing specific options
|
|
123
|
+
thumb: { geometry: "100x100#", backend: :image_magick }
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Important Considerations
|
|
128
|
+
|
|
129
|
+
1. **Output Parity**: While libvips aims for high quality, its resizing algorithms (Lanczos) may produce slightly different visual results than ImageMagick.
|
|
130
|
+
2. **PDF/SVG Support**: libvips requires additional libraries (like `poppler` or `librsvg`) to process these formats. If you process complex vector formats, ensure the appropriate libraries are installed on your system.
|
|
131
|
+
3. **Exotic Formats**: If you rely on very specific ImageMagick features (like specialized filters or complex layer manipulation), test those attachments thoroughly before switching.
|
|
@@ -83,3 +83,30 @@ Feature: Rails integration
|
|
|
83
83
|
Then I should see "Name: something"
|
|
84
84
|
And I should see an image with a path of "//s3.amazonaws.com/paperclip/attachments/original/5k.png"
|
|
85
85
|
And the file at "//s3.amazonaws.com/paperclip/attachments/original/5k.png" should be uploaded to S3
|
|
86
|
+
|
|
87
|
+
Scenario: libvips integration test
|
|
88
|
+
Given I add this snippet to config/application.rb:
|
|
89
|
+
"""
|
|
90
|
+
config.paperclip_defaults = {
|
|
91
|
+
:backend => :vips
|
|
92
|
+
}
|
|
93
|
+
"""
|
|
94
|
+
And I attach :attachment with:
|
|
95
|
+
"""
|
|
96
|
+
url: "/system/:attachment/:style/:filename",
|
|
97
|
+
styles: { thumb: "100x100#" }
|
|
98
|
+
"""
|
|
99
|
+
And I start the rails application
|
|
100
|
+
And I overwrite "app/views/users/show.html.erb" with:
|
|
101
|
+
"""
|
|
102
|
+
<p>Name: <%= @user.name %></p>
|
|
103
|
+
<p>Original: <%= image_tag @user.attachment.url(:original) %></p>
|
|
104
|
+
<p>Thumb: <%= image_tag @user.attachment.url(:thumb) %></p>
|
|
105
|
+
"""
|
|
106
|
+
When I go to the new user page
|
|
107
|
+
And I fill in "Name" with "vips user"
|
|
108
|
+
And I attach the file "spec/support/fixtures/5k.png" to "Attachment"
|
|
109
|
+
And I press "Submit"
|
|
110
|
+
Then I should see "Name: vips user"
|
|
111
|
+
And the file at "/system/attachments/original/5k.png" should have dimensions "434x66"
|
|
112
|
+
And the file at "/system/attachments/thumb/5k.png" should have dimensions "100x100"
|
|
@@ -86,6 +86,23 @@ Then /^the attachment file "([^"]*)" should (not )?exist$/ do |filename, not_exi
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
Then /^the file at "([^"]*)" should have dimensions "([^"]*)"$/ do |web_path, dimension|
|
|
90
|
+
cd(".") do
|
|
91
|
+
local_path = "public#{web_path}"
|
|
92
|
+
# Try identify first, then vipsheader
|
|
93
|
+
require "shellwords"
|
|
94
|
+
escaped_path = Shellwords.escape(local_path)
|
|
95
|
+
geometry = `identify -format "%wx%h" #{escaped_path} 2>/dev/null`.strip
|
|
96
|
+
if geometry.empty?
|
|
97
|
+
width = `vipsheader -f width #{escaped_path} 2>/dev/null`.strip
|
|
98
|
+
height = `vipsheader -f height #{escaped_path} 2>/dev/null`.strip
|
|
99
|
+
geometry = "#{width}x#{height}"
|
|
100
|
+
end
|
|
101
|
+
raise "Could not determine dimensions for #{local_path}" if geometry == "x" || geometry.empty?
|
|
102
|
+
expect(geometry).to eq(dimension)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
89
106
|
Then /^I should have attachment columns for "([^"]*)"$/ do |attachment_name|
|
|
90
107
|
cd(".") do
|
|
91
108
|
columns = eval(`bundle exec rails runner "puts User.columns.map{ |column| [column.name, column.sql_type] }.inspect"`.strip)
|
data/gemfiles/7.0.gemfile
CHANGED
data/gemfiles/7.1.gemfile
CHANGED
data/gemfiles/7.2.gemfile
CHANGED
data/gemfiles/8.0.gemfile
CHANGED
data/gemfiles/8.1.gemfile
CHANGED
data/lib/paperclip/attachment.rb
CHANGED
|
@@ -34,7 +34,8 @@ module Paperclip
|
|
|
34
34
|
validate_media_type: true,
|
|
35
35
|
adapter_options: { hash_digest: Digest::MD5 },
|
|
36
36
|
check_validity_before_processing: true,
|
|
37
|
-
return_file_attributes_on_destroy: false
|
|
37
|
+
return_file_attributes_on_destroy: false,
|
|
38
|
+
backend: Paperclip.options[:backend]
|
|
38
39
|
}
|
|
39
40
|
end
|
|
40
41
|
|
|
@@ -537,7 +538,7 @@ module Paperclip
|
|
|
537
538
|
for(@queued_for_write[name], @options[:adapter_options])
|
|
538
539
|
unadapted_file.close if unadapted_file.respond_to?(:close)
|
|
539
540
|
@queued_for_write[name]
|
|
540
|
-
rescue Paperclip::Errors::
|
|
541
|
+
rescue Paperclip::Errors::NotIdentifiedByBackendError => e
|
|
541
542
|
log("An error was received while processing: #{e.inspect}")
|
|
542
543
|
(@errors[:processing] ||= []) << e.message if @options[:whiny]
|
|
543
544
|
ensure
|
data/lib/paperclip/errors.rb
CHANGED
|
@@ -18,12 +18,11 @@ module Paperclip
|
|
|
18
18
|
class MissingRequiredValidatorError < Paperclip::Error
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Will be thrown when
|
|
22
|
-
# metadata, usually this would mean the file is not an image.
|
|
23
|
-
|
|
24
|
-
# installed Ghostscript.
|
|
25
|
-
class NotIdentifiedByImageMagickError < Paperclip::Error
|
|
21
|
+
# Will be thrown when the backend cannot determine the uploaded file's
|
|
22
|
+
# metadata, usually this would mean the file is not an image.
|
|
23
|
+
class NotIdentifiedByBackendError < Paperclip::Error
|
|
26
24
|
end
|
|
25
|
+
NotIdentifiedByImageMagickError = NotIdentifiedByBackendError
|
|
27
26
|
|
|
28
27
|
# Will be thrown if the interpolation is creating an infinite loop. If you
|
|
29
28
|
# are creating an interpolator which might cause an infinite loop, you
|
data/lib/paperclip/geometry.rb
CHANGED
|
@@ -21,8 +21,8 @@ module Paperclip
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Extracts the Geometry from a file (or path to a file)
|
|
24
|
-
def self.from_file(file)
|
|
25
|
-
GeometryDetector.new(file).make
|
|
24
|
+
def self.from_file(file, backend = nil)
|
|
25
|
+
GeometryDetector.new(file, backend: backend).make
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Extracts the Geometry from a "WxH,O" string
|
|
@@ -84,7 +84,7 @@ module Paperclip
|
|
|
84
84
|
to_s
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
# Returns the scaling and cropping geometries (in string
|
|
87
|
+
# Returns the scaling and cropping geometries (in string format)
|
|
88
88
|
# neccessary to transform this Geometry into the Geometry given. If crop is true,
|
|
89
89
|
# then it is assumed the destination Geometry will be the exact final resolution.
|
|
90
90
|
# In this case, the source Geometry is scaled so that an image containing the
|