kt-paperclip 7.3.0 → 8.0.0
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/README.md +24 -56
- data/lib/generators/paperclip/paperclip_generator.rb +3 -1
- data/lib/kt-paperclip.rb +2 -0
- data/lib/paperclip/attachment.rb +2 -0
- data/lib/paperclip/attachment_registry.rb +2 -0
- data/lib/paperclip/callbacks.rb +7 -4
- data/lib/paperclip/commands/imagemagick/geometry_parser.rb +63 -0
- data/lib/paperclip/commands/imagemagick/version_detector.rb +41 -0
- data/lib/paperclip/commands/imagemagick.rb +44 -0
- data/lib/paperclip/commands/runner.rb +38 -0
- data/lib/paperclip/commands/unix_file.rb +28 -0
- data/lib/paperclip/content_type_detector.rb +31 -32
- data/lib/paperclip/errors.rb +2 -0
- data/lib/paperclip/file_command_content_type_detector.rb +11 -12
- data/lib/paperclip/filename_cleaner.rb +2 -0
- data/lib/paperclip/geometry.rb +22 -7
- data/lib/paperclip/geometry_detector_factory.rb +11 -31
- data/lib/paperclip/geometry_parser_factory.rb +13 -17
- data/lib/paperclip/glue.rb +2 -0
- data/lib/paperclip/has_attached_file.rb +2 -0
- data/lib/paperclip/helpers.rb +5 -25
- data/lib/paperclip/interpolations/plural_cache.rb +2 -0
- data/lib/paperclip/interpolations.rb +2 -0
- data/lib/paperclip/io_adapters/abstract_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/identity_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/nil_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/registry.rb +2 -0
- data/lib/paperclip/io_adapters/stringio_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +2 -0
- data/lib/paperclip/io_adapters/uri_adapter.rb +5 -13
- data/lib/paperclip/logger.rb +2 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +5 -3
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -0
- data/lib/paperclip/matchers.rb +2 -0
- data/lib/paperclip/media_type_spoof_detector.rb +3 -10
- data/lib/paperclip/missing_attachment_styles.rb +2 -0
- data/lib/paperclip/processor.rb +6 -19
- data/lib/paperclip/processor_helpers.rb +2 -0
- data/lib/paperclip/rails_environment.rb +2 -0
- data/lib/paperclip/railtie.rb +2 -0
- data/lib/paperclip/schema.rb +6 -4
- data/lib/paperclip/storage/filesystem.rb +2 -0
- data/lib/paperclip/storage/fog.rb +4 -3
- data/lib/paperclip/storage/s3.rb +3 -3
- data/lib/paperclip/storage.rb +2 -0
- data/lib/paperclip/style.rb +2 -0
- data/lib/paperclip/tempfile.rb +2 -0
- data/lib/paperclip/tempfile_factory.rb +2 -0
- data/lib/paperclip/thumbnail.rb +9 -10
- data/lib/paperclip/url_generator.rb +2 -0
- data/lib/paperclip/validators/attachment_content_type_validator.rb +2 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +2 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +2 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +2 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +2 -0
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +2 -0
- data/lib/paperclip/validators.rb +2 -0
- data/lib/paperclip/version.rb +3 -1
- data/lib/paperclip.rb +25 -4
- data/lib/tasks/paperclip.rake +9 -4
- data/shoulda_macros/paperclip.rb +2 -0
- metadata +18 -538
- data/.codeclimate.yml +0 -17
- data/.github/FUNDING.yml +0 -3
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- data/.github/ISSUE_TEMPLATE/custom.md +0 -10
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- data/.gitignore +0 -19
- data/.hound.yml +0 -3
- data/.rubocop.yml +0 -1061
- data/.travis.yml +0 -45
- data/Appraisals +0 -30
- data/CONTRIBUTING.md +0 -85
- data/Gemfile +0 -19
- data/OLD_NEWS +0 -556
- data/RELEASING.md +0 -17
- data/Rakefile +0 -52
- data/UPGRADING +0 -17
- data/features/basic_integration.feature +0 -85
- data/features/migration.feature +0 -29
- data/features/rake_tasks.feature +0 -62
- data/features/step_definitions/attachment_steps.rb +0 -120
- data/features/step_definitions/html_steps.rb +0 -15
- data/features/step_definitions/rails_steps.rb +0 -257
- data/features/step_definitions/s3_steps.rb +0 -14
- data/features/step_definitions/web_steps.rb +0 -106
- data/features/support/env.rb +0 -12
- data/features/support/fakeweb.rb +0 -11
- data/features/support/file_helpers.rb +0 -34
- data/features/support/fixtures/boot_config.txt +0 -15
- data/features/support/fixtures/gemfile.txt +0 -5
- data/features/support/fixtures/preinitializer.txt +0 -20
- data/features/support/paths.rb +0 -28
- data/features/support/rails.rb +0 -39
- data/features/support/selectors.rb +0 -19
- data/gemfiles/4.2.gemfile +0 -20
- data/gemfiles/5.0.gemfile +0 -20
- data/gemfiles/5.1.gemfile +0 -20
- data/gemfiles/5.2.gemfile +0 -20
- data/gemfiles/6.0.gemfile +0 -20
- data/gemfiles/6.1.gemfile +0 -21
- data/gemfiles/7.0.gemfile +0 -21
- data/paperclip.gemspec +0 -50
- data/spec/database.yml +0 -4
- data/spec/paperclip/attachment_definitions_spec.rb +0 -13
- data/spec/paperclip/attachment_processing_spec.rb +0 -79
- data/spec/paperclip/attachment_registry_spec.rb +0 -158
- data/spec/paperclip/attachment_spec.rb +0 -1616
- data/spec/paperclip/content_type_detector_spec.rb +0 -54
- data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -40
- data/spec/paperclip/filename_cleaner_spec.rb +0 -13
- data/spec/paperclip/geometry_detector_spec.rb +0 -47
- data/spec/paperclip/geometry_parser_spec.rb +0 -73
- data/spec/paperclip/geometry_spec.rb +0 -267
- data/spec/paperclip/glue_spec.rb +0 -63
- data/spec/paperclip/has_attached_file_spec.rb +0 -78
- data/spec/paperclip/integration_spec.rb +0 -702
- data/spec/paperclip/interpolations_spec.rb +0 -270
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +0 -160
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +0 -167
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +0 -88
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +0 -17
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +0 -131
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +0 -142
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +0 -8
- data/spec/paperclip/io_adapters/nil_adapter_spec.rb +0 -25
- data/spec/paperclip/io_adapters/registry_spec.rb +0 -35
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +0 -64
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +0 -146
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +0 -231
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +0 -19
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +0 -108
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +0 -69
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +0 -88
- data/spec/paperclip/media_type_spoof_detector_spec.rb +0 -126
- data/spec/paperclip/meta_class_spec.rb +0 -30
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +0 -88
- data/spec/paperclip/paperclip_spec.rb +0 -196
- data/spec/paperclip/plural_cache_spec.rb +0 -37
- data/spec/paperclip/processor_helpers_spec.rb +0 -57
- data/spec/paperclip/processor_spec.rb +0 -26
- data/spec/paperclip/rails_environment_spec.rb +0 -30
- data/spec/paperclip/rake_spec.rb +0 -103
- data/spec/paperclip/schema_spec.rb +0 -252
- data/spec/paperclip/storage/filesystem_spec.rb +0 -102
- data/spec/paperclip/storage/fog_spec.rb +0 -606
- data/spec/paperclip/storage/s3_live_spec.rb +0 -188
- data/spec/paperclip/storage/s3_spec.rb +0 -1961
- data/spec/paperclip/style_spec.rb +0 -251
- data/spec/paperclip/tempfile_factory_spec.rb +0 -33
- data/spec/paperclip/tempfile_spec.rb +0 -35
- data/spec/paperclip/thumbnail_spec.rb +0 -504
- data/spec/paperclip/url_generator_spec.rb +0 -231
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +0 -410
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +0 -249
- data/spec/paperclip/validators/attachment_presence_validator_spec.rb +0 -85
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +0 -325
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +0 -48
- data/spec/paperclip/validators_spec.rb +0 -179
- data/spec/spec_helper.rb +0 -46
- data/spec/support/assertions.rb +0 -84
- data/spec/support/fake_model.rb +0 -24
- data/spec/support/fake_rails.rb +0 -12
- data/spec/support/fixtures/12k.png +0 -0
- data/spec/support/fixtures/50x50.png +0 -0
- data/spec/support/fixtures/5k.png +0 -0
- data/spec/support/fixtures/animated +0 -0
- data/spec/support/fixtures/animated.gif +0 -0
- data/spec/support/fixtures/animated.unknown +0 -0
- data/spec/support/fixtures/aws_s3.yml +0 -13
- data/spec/support/fixtures/bad.png +0 -1
- data/spec/support/fixtures/empty.html +0 -1
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/fixtures/fog.yml +0 -8
- data/spec/support/fixtures/rotated.jpg +0 -0
- data/spec/support/fixtures/s3.yml +0 -8
- data/spec/support/fixtures/sample.xlsm +0 -0
- data/spec/support/fixtures/spaced file.jpg +0 -0
- data/spec/support/fixtures/spaced file.png +0 -0
- data/spec/support/fixtures/text.txt +0 -1
- data/spec/support/fixtures/twopage.pdf +0 -0
- data/spec/support/fixtures/uppercase.PNG +0 -0
- data/spec/support/matchers/accept.rb +0 -5
- data/spec/support/matchers/exist.rb +0 -5
- data/spec/support/matchers/have_column.rb +0 -23
- data/spec/support/mock_attachment.rb +0 -24
- data/spec/support/mock_interpolator.rb +0 -24
- data/spec/support/mock_url_generator_builder.rb +0 -26
- data/spec/support/model_reconstruction.rb +0 -72
- data/spec/support/reporting.rb +0 -11
- data/spec/support/test_data.rb +0 -13
- data/spec/support/version_helper.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 57acb40c010d089179840fb06116bb36527035ce5e6ddaa25531d2d24067456f
|
|
4
|
+
data.tar.gz: f49b37dbd63550be17c59b47ce930981dae6f7d88461cf90721925051e579efa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f92b7453a259e25763375ba727dc262910ec647e54017182befa98e0330e6ac5890cd76ab27476a3be6725de35aeb8b85f73db463ad75007370d0076ed3220bb
|
|
7
|
+
data.tar.gz: dae535db1d37087c4505aaa0db691c2e300377755c9345ef412a28dfde1bf55f64f169d6f438d0285672db9bc8681629708c1c366e719cfcb2773d89f6ad5906
|
data/README.md
CHANGED
|
@@ -93,73 +93,41 @@ Requirements
|
|
|
93
93
|
Paperclip now requires Ruby version **>= 2.3** and Rails version **>= 4.2**
|
|
94
94
|
(only if you're going to use Paperclip with Ruby on Rails).
|
|
95
95
|
|
|
96
|
-
### Image Processor
|
|
96
|
+
### ImageMagick Image Processor
|
|
97
97
|
|
|
98
|
-
[ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
[ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it.
|
|
99
|
+
Refer to ImageMagick's [installations instructions](https://imagemagick.org/download/).
|
|
100
|
+
ImageMagick 7 is the latest version. As of April 2026, some package managers such as `apt`
|
|
101
|
+
still install ImageMagick 6.
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
In development mode, you might add this line to `config/environments/development.rb)`:
|
|
103
|
+
Paperclip supports both ImageMagick versions 6 and 7, and will auto-detect your version.
|
|
104
|
+
You may enforce a specific version in an initializer such as `config/initializers/paperclip.rb`:
|
|
107
105
|
|
|
108
106
|
```ruby
|
|
109
|
-
Paperclip.options[:
|
|
107
|
+
Paperclip.options[:imagemagick_version] = "7"
|
|
110
108
|
```
|
|
111
109
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
brew install imagemagick
|
|
115
|
-
|
|
116
|
-
If you are dealing with pdf uploads or running the test suite, you'll also need
|
|
117
|
-
to install GhostScript. On Mac OS X, you can also install that using Homebrew:
|
|
118
|
-
|
|
119
|
-
brew install gs
|
|
120
|
-
|
|
121
|
-
If you are on Ubuntu (or any Debian base Linux distribution), you'll want to run
|
|
122
|
-
the following with apt-get:
|
|
123
|
-
|
|
124
|
-
sudo apt-get install imagemagick -y
|
|
125
|
-
|
|
126
|
-
### `file`
|
|
127
|
-
|
|
128
|
-
The Unix [`file` command](https://en.wikipedia.org/wiki/File_(command)) is required for content-type checking.
|
|
129
|
-
This utility isn't available in Windows, but comes bundled with Ruby [Devkit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit),
|
|
130
|
-
so Windows users must make sure that the devkit is installed and added to the system `PATH`.
|
|
131
|
-
|
|
132
|
-
**Manual Installation**
|
|
133
|
-
|
|
134
|
-
If you're using Windows 7+ as a development environment, you may need to install the `file.exe` application manually. The `file spoofing` system in Paperclip 4+ relies on this; if you don't have it working, you'll receive `Validation failed: Upload file has an extension that does not match its contents.` errors.
|
|
110
|
+
Please ensure ImageMagick is in your environment path, or alternatively set
|
|
111
|
+
the path manually in an initializer:
|
|
135
112
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
To test, you can use the image below:
|
|
141
|
-

|
|
142
|
-
|
|
143
|
-
Next, you need to integrate with your environment - preferably through the `PATH` variable, or by changing your `config/environments/development.rb` file
|
|
144
|
-
|
|
145
|
-
**PATH**
|
|
146
|
-
|
|
147
|
-
1. Click "Start"
|
|
148
|
-
2. On "Computer", right-click and select "Properties"
|
|
149
|
-
3. In Properties, select "Advanced System Settings"
|
|
150
|
-
4. Click the "Environment Variables" button
|
|
151
|
-
5. Locate the "PATH" var - at the end, add the path to your newly installed `file.exe` (typically `C:\Program Files (x86)\GnuWin32\bin`)
|
|
152
|
-
6. Restart any CMD shells you have open & see if it works
|
|
113
|
+
```ruby
|
|
114
|
+
Paperclip.options[:imagemagick_path] = "/usr/local/bin/"
|
|
115
|
+
```
|
|
153
116
|
|
|
154
|
-
|
|
117
|
+
### Optional: Unix `file` Command
|
|
155
118
|
|
|
156
|
-
|
|
119
|
+
Paperclip uses the [Marcel gem](https://github.com/rails/marcel) to detect file content types.
|
|
120
|
+
If Marcel cannot detect the type, the [Unix `file` command](https://en.wikipedia.org/wiki/File_(command))
|
|
121
|
+
is used as an optional fallback. To use it, ensure `file` is in your environment path,
|
|
122
|
+
or alternatively set its path manually in an initializer:
|
|
157
123
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
124
|
+
```ruby
|
|
125
|
+
Paperclip.options[:file_command_path] = "/usr/local/bin/"
|
|
126
|
+
```
|
|
161
127
|
|
|
162
|
-
|
|
128
|
+
Windows users should install the `file` utility via the Ruby Installer for Windows'
|
|
129
|
+
[DevKit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit), or alternatively,
|
|
130
|
+
by installing [MSYS2](https://www.msys2.org/) which provides Unix utilities for Windows.
|
|
163
131
|
|
|
164
132
|
---
|
|
165
133
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "rails/generators/active_record"
|
|
2
4
|
|
|
3
5
|
class PaperclipGenerator < ActiveRecord::Generators::Base
|
|
@@ -31,6 +33,6 @@ class PaperclipGenerator < ActiveRecord::Generators::Base
|
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def migration_version
|
|
34
|
-
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
36
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
35
37
|
end
|
|
36
38
|
end
|
data/lib/kt-paperclip.rb
CHANGED
data/lib/paperclip/attachment.rb
CHANGED
data/lib/paperclip/callbacks.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Paperclip
|
|
2
4
|
module Callbacks
|
|
3
5
|
def self.included(base)
|
|
@@ -9,14 +11,15 @@ module Paperclip
|
|
|
9
11
|
def define_paperclip_callbacks(*callbacks)
|
|
10
12
|
define_callbacks(*[callbacks, { terminator: hasta_la_vista_baby }].flatten)
|
|
11
13
|
callbacks.each do |callback|
|
|
12
|
-
|
|
13
|
-
def before_#{callback}(*args, &blk)
|
|
14
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
|
15
|
+
def self.before_#{callback}(*args, &blk)
|
|
14
16
|
set_callback(:#{callback}, :before, *args, &blk)
|
|
15
17
|
end
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
def self.after_#{callback}(*args, &blk)
|
|
17
20
|
set_callback(:#{callback}, :after, *args, &blk)
|
|
18
21
|
end
|
|
19
|
-
|
|
22
|
+
RUBY
|
|
20
23
|
end
|
|
21
24
|
end
|
|
22
25
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Paperclip
|
|
4
|
+
module Commands
|
|
5
|
+
module ImageMagick
|
|
6
|
+
module GeometryParser
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
FORMAT = /\b(\d*)x?(\d*)\b(?:,(\d?))?(@>|>@|[><#@%^!])?/i.freeze
|
|
10
|
+
|
|
11
|
+
# Runs `magick identify` and returns a Paperclip::Geometry
|
|
12
|
+
def detect(file)
|
|
13
|
+
parse(fetch(file))
|
|
14
|
+
end
|
|
15
|
+
alias_method :from_file, :detect
|
|
16
|
+
|
|
17
|
+
# Parses a "WxH,O" string into a Paperclip::Geometry
|
|
18
|
+
def parse(string)
|
|
19
|
+
return unless (match = string&.strip&.match(FORMAT))
|
|
20
|
+
|
|
21
|
+
Paperclip::Geometry.new(
|
|
22
|
+
width: match[1],
|
|
23
|
+
height: match[2],
|
|
24
|
+
orientation: match[3],
|
|
25
|
+
modifier: match[4]
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def fetch(file)
|
|
32
|
+
filepath = path(file)
|
|
33
|
+
raise_error("Cannot find the geometry of a file with a blank name") if filepath.blank?
|
|
34
|
+
|
|
35
|
+
str = Paperclip::Commands::ImageMagick.identify(
|
|
36
|
+
"-format '%wx%h,#{orientation}' :file",
|
|
37
|
+
{ file: "#{filepath}[0]" },
|
|
38
|
+
{ swallow_stderr: true }
|
|
39
|
+
).presence
|
|
40
|
+
|
|
41
|
+
raise_error unless str
|
|
42
|
+
|
|
43
|
+
str
|
|
44
|
+
rescue Terrapin::ExitStatusError
|
|
45
|
+
raise_error
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def path(file)
|
|
49
|
+
file.respond_to?(:path) ? file.path : file
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def orientation
|
|
53
|
+
Paperclip.options[:use_exif_orientation] ? "%[exif:orientation]" : "1"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def raise_error(message = nil)
|
|
57
|
+
message ||= "Could not identify image size"
|
|
58
|
+
raise Errors::NotIdentifiedByImageMagickError.new(message)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Paperclip
|
|
4
|
+
module Commands
|
|
5
|
+
module ImageMagick
|
|
6
|
+
module VersionDetector
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
# Returns 6, 7, or nil (not installed)
|
|
10
|
+
def detected_version
|
|
11
|
+
return @detected_version if defined?(@detected_version)
|
|
12
|
+
|
|
13
|
+
@detected_version = detect
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def detect
|
|
19
|
+
return 7 if valid?("magick")
|
|
20
|
+
return 6 if valid?("convert")
|
|
21
|
+
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def valid?(command)
|
|
26
|
+
run(command).to_s.include?("ImageMagick")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run(command)
|
|
30
|
+
Paperclip::Commands::Runner.run(command, path, "-version", {}, swallow_stderr: true)
|
|
31
|
+
rescue Terrapin::CommandLineError
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def path
|
|
36
|
+
Paperclip::Commands::ImageMagick.imagemagick_path
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Paperclip
|
|
4
|
+
module Commands
|
|
5
|
+
module ImageMagick
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def convert(arguments = nil, interpolation_values = {}, local_options = {})
|
|
9
|
+
run(convert_command, imagemagick_path, arguments, interpolation_values, local_options)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def identify(arguments = nil, interpolation_values = {}, local_options = {})
|
|
13
|
+
run(identify_command, imagemagick_path, arguments, interpolation_values, local_options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def imagemagick_path
|
|
17
|
+
Paperclip.options[:imagemagick_path]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def run(command, path = nil, arguments = nil, interpolation_values = {}, local_options = {})
|
|
23
|
+
Runner.run(command, path || imagemagick_path, arguments, interpolation_values, local_options)
|
|
24
|
+
rescue Terrapin::CommandNotFoundError
|
|
25
|
+
raise Errors::CommandNotFoundError.new("Could not run the `#{command}` command. Please install ImageMagick.")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns true if ImageMagick 7 is in use (either detected or forced via config)
|
|
29
|
+
def magick_command?
|
|
30
|
+
version = Paperclip.options[:imagemagick_version]&.to_i ||
|
|
31
|
+
VersionDetector.detected_version
|
|
32
|
+
!version.nil? && version >= 7
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def convert_command
|
|
36
|
+
magick_command? ? "magick" : "convert"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def identify_command
|
|
40
|
+
magick_command? ? "magick identify" : "identify"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Paperclip
|
|
4
|
+
module Commands
|
|
5
|
+
module Runner
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def run(command, path = nil, arguments = nil, interpolation_values = {}, local_options = {})
|
|
9
|
+
if Paperclip.logging? && (Paperclip.options[:log_command] || local_options[:log_command])
|
|
10
|
+
local_options = local_options.merge(logger: Paperclip.logger)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
binary = resolve_binary(command, path)
|
|
14
|
+
|
|
15
|
+
Terrapin::CommandLine.new(binary, arguments, local_options)
|
|
16
|
+
.run(interpolation_values)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def resolve_binary(command, path)
|
|
22
|
+
# @deprecated +Paperclip.options[:command_path]+ will be removed in Paperclip 8.0
|
|
23
|
+
path ||= Paperclip.options[:command_path]
|
|
24
|
+
return command unless path
|
|
25
|
+
|
|
26
|
+
# command may be multi-word (e.g. "magick identify")
|
|
27
|
+
words = command.split(" ", 2)
|
|
28
|
+
candidate = File.join(path, words[0])
|
|
29
|
+
if File.executable?(candidate)
|
|
30
|
+
words[0] = candidate
|
|
31
|
+
words.join(" ")
|
|
32
|
+
else
|
|
33
|
+
command
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Paperclip
|
|
4
|
+
module Commands
|
|
5
|
+
module UnixFile
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
# Returns a normalized content type value, otherwise nil.
|
|
9
|
+
def detect_content_type(file)
|
|
10
|
+
type = run_file_command(file)
|
|
11
|
+
return if type.blank? || type.match(/\(.*?\)/)
|
|
12
|
+
|
|
13
|
+
type.split(/[:;\s]+/)[0].strip
|
|
14
|
+
rescue Terrapin::CommandLineError => e
|
|
15
|
+
Paperclip.log("Error while determining content type: #{e}")
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def run_file_command(file)
|
|
22
|
+
Runner.run("file", Paperclip.options[:file_command_path], "-b --mime :file", { file: file })
|
|
23
|
+
rescue Terrapin::CommandLineError
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Paperclip
|
|
4
|
+
# The content-type detection strategy is as follows:
|
|
5
|
+
#
|
|
6
|
+
# 1. Blank/Empty files: If there's no filepath or the file is empty,
|
|
7
|
+
# provide a sensible default (application/octet-stream or inode/x-empty)
|
|
8
|
+
#
|
|
9
|
+
# 2. Calculated match: Return the first result that is found by both the
|
|
10
|
+
# Marcel gem (or `file` command) and MIME::Types.
|
|
11
|
+
#
|
|
12
|
+
# 3. Standard types: Return the first standard (without an x- prefix) entry
|
|
13
|
+
# in MIME::Types
|
|
14
|
+
#
|
|
15
|
+
# 4. Experimental types: If there were no standard types in MIME::Types
|
|
16
|
+
# list, try to return the first experimental one
|
|
17
|
+
#
|
|
18
|
+
# 5. Raw `file` command: Just use the output of Marcel (or `file` command),
|
|
19
|
+
# cached from step 2.
|
|
20
|
+
#
|
|
21
|
+
# 6. If nothing found, return a sensible default.
|
|
2
22
|
class ContentTypeDetector
|
|
3
|
-
# The content-type detection strategy is as follows:
|
|
4
|
-
#
|
|
5
|
-
# 1. Blank/Empty files: If there's no filepath or the file is empty,
|
|
6
|
-
# provide a sensible default (application/octet-stream or inode/x-empty)
|
|
7
|
-
#
|
|
8
|
-
# 2. Calculated match: Return the first result that is found by both the
|
|
9
|
-
# `file` command and MIME::Types.
|
|
10
|
-
#
|
|
11
|
-
# 3. Standard types: Return the first standard (without an x- prefix) entry
|
|
12
|
-
# in MIME::Types
|
|
13
|
-
#
|
|
14
|
-
# 4. Experimental types: If there were no standard types in MIME::Types
|
|
15
|
-
# list, try to return the first experimental one
|
|
16
|
-
#
|
|
17
|
-
# 5. Raw `file` command: Just use the output of the `file` command raw, or
|
|
18
|
-
# a sensible default. This is cached from Step 2.
|
|
19
|
-
|
|
20
23
|
EMPTY_TYPE = "inode/x-empty"
|
|
21
24
|
SENSIBLE_DEFAULT = "application/octet-stream"
|
|
22
25
|
|
|
@@ -25,15 +28,15 @@ module Paperclip
|
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
# Returns a String describing the file's content type
|
|
28
|
-
def detect
|
|
31
|
+
def detect(default = SENSIBLE_DEFAULT)
|
|
29
32
|
if blank_name?
|
|
30
|
-
|
|
33
|
+
default
|
|
31
34
|
elsif empty_file?
|
|
32
35
|
EMPTY_TYPE
|
|
33
36
|
elsif calculated_type_matches.any?
|
|
34
37
|
calculated_type_matches.first
|
|
35
38
|
else
|
|
36
|
-
type_from_file_contents ||
|
|
39
|
+
type_from_file_contents || default
|
|
37
40
|
end.to_s
|
|
38
41
|
end
|
|
39
42
|
|
|
@@ -60,26 +63,22 @@ module Paperclip
|
|
|
60
63
|
end
|
|
61
64
|
|
|
62
65
|
def type_from_file_contents
|
|
63
|
-
|
|
66
|
+
return @type_from_file_contents if defined?(@type_from_file_contents)
|
|
67
|
+
|
|
68
|
+
@type_from_file_contents = type_from_marcel || type_from_file_command
|
|
64
69
|
rescue Errno::ENOENT => e
|
|
65
70
|
Paperclip.log("Error while determining content type: #{e}")
|
|
66
|
-
|
|
71
|
+
@type_from_file_contents = nil
|
|
67
72
|
end
|
|
68
73
|
|
|
69
74
|
def type_from_marcel
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
name: @filepath
|
|
74
|
-
# Marcel::MineType returns 'application/octet-stream' if it can't find
|
|
75
|
-
# a valid type.
|
|
76
|
-
@type_from_marcel = nil if @type_from_marcel == SENSIBLE_DEFAULT
|
|
77
|
-
@type_from_marcel
|
|
75
|
+
type = Marcel::MimeType.for(Pathname.new(@filepath), name: @filepath)
|
|
76
|
+
# Marcel::MineType returns 'application/octet-stream' if it can't find a valid type.
|
|
77
|
+
type == SENSIBLE_DEFAULT ? nil : type
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def type_from_file_command
|
|
81
|
-
@
|
|
82
|
-
FileCommandContentTypeDetector.new(@filepath).detect
|
|
81
|
+
Commands::UnixFile.detect_content_type(@filepath)
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
end
|
data/lib/paperclip/errors.rb
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Paperclip
|
|
4
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
|
|
2
5
|
class FileCommandContentTypeDetector
|
|
6
|
+
# @deprecated Will be removed in Paperclip 8.0.
|
|
3
7
|
SENSIBLE_DEFAULT = "application/octet-stream"
|
|
4
8
|
|
|
9
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
|
|
5
10
|
def initialize(filename)
|
|
11
|
+
warn_deprecation
|
|
6
12
|
@filename = filename
|
|
7
13
|
end
|
|
8
14
|
|
|
15
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
|
|
9
16
|
def detect
|
|
10
|
-
|
|
17
|
+
warn_deprecation
|
|
18
|
+
Paperclip::Commands::UnixFile.detect_content_type(@filename) || SENSIBLE_DEFAULT
|
|
11
19
|
end
|
|
12
20
|
|
|
13
21
|
private
|
|
14
22
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
type = begin
|
|
18
|
-
Paperclip.run("file", "-b --mime :file", file: @filename)
|
|
19
|
-
rescue Terrapin::CommandLineError => e
|
|
20
|
-
Paperclip.log("Error while determining content type: #{e}")
|
|
21
|
-
SENSIBLE_DEFAULT
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
type = SENSIBLE_DEFAULT if type.nil? || type.match(/\(.*?\)/)
|
|
25
|
-
type.split(/[:;\s]+/)[0]
|
|
23
|
+
def warn_deprecation
|
|
24
|
+
Paperclip.deprecator.warn("Paperclip::FileCommandContentTypeDetector has been replaced by Paperclip::ContentTypeDetector.")
|
|
26
25
|
end
|
|
27
26
|
end
|
|
28
27
|
end
|
data/lib/paperclip/geometry.rb
CHANGED
|
@@ -1,35 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Paperclip
|
|
2
4
|
# Defines the geometry of an image.
|
|
3
5
|
class Geometry
|
|
4
|
-
attr_accessor :height, :width, :modifier
|
|
6
|
+
attr_accessor :height, :width, :modifier, :orientation
|
|
5
7
|
|
|
6
8
|
EXIF_ROTATED_ORIENTATION_VALUES = [5, 6, 7, 8].freeze
|
|
7
9
|
|
|
8
10
|
# Gives a Geometry representing the given height and width
|
|
9
|
-
def initialize(width = nil, height = nil, modifier = nil)
|
|
11
|
+
def initialize(width = nil, height = nil, modifier = nil, orientation = nil)
|
|
10
12
|
if width.is_a?(Hash)
|
|
11
13
|
options = width
|
|
12
14
|
@height = options[:height].to_f
|
|
13
15
|
@width = options[:width].to_f
|
|
14
|
-
@modifier = options[:modifier]
|
|
16
|
+
@modifier = options[:modifier].presence
|
|
15
17
|
@orientation = options[:orientation].to_i
|
|
16
18
|
else
|
|
17
19
|
@height = height.to_f
|
|
18
20
|
@width = width.to_f
|
|
19
|
-
@modifier = modifier
|
|
21
|
+
@modifier = modifier.presence
|
|
22
|
+
@orientation = orientation.to_i
|
|
20
23
|
end
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
# Extracts the Geometry from a file (or path to a file)
|
|
27
|
+
#
|
|
28
|
+
# @deprecated Will be removed in Paperclip 8.0.
|
|
24
29
|
def self.from_file(file)
|
|
25
|
-
|
|
30
|
+
Commands::ImageMagick::GeometryParser.from_file(file)
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
# Extracts the Geometry from a "WxH,O" string
|
|
29
34
|
# Where W is the width, H is the height,
|
|
30
35
|
# and O is the EXIF orientation
|
|
36
|
+
#
|
|
37
|
+
# @deprecated Will be removed in Paperclip 8.0.
|
|
31
38
|
def self.parse(string)
|
|
32
|
-
GeometryParser.
|
|
39
|
+
Commands::ImageMagick::GeometryParser.parse(string)
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
# Swaps the height and width if necessary
|
|
@@ -72,13 +79,21 @@ module Paperclip
|
|
|
72
79
|
|
|
73
80
|
# Returns the width and height in a format suitable to be passed to Geometry.parse
|
|
74
81
|
def to_s
|
|
75
|
-
s =
|
|
82
|
+
s = +""
|
|
76
83
|
s << width.to_i.to_s if width > 0
|
|
77
84
|
s << "x#{height.to_i}" if height > 0
|
|
78
85
|
s << modifier.to_s
|
|
79
86
|
s
|
|
80
87
|
end
|
|
81
88
|
|
|
89
|
+
def ==(other)
|
|
90
|
+
other.is_a?(Geometry) &&
|
|
91
|
+
width == other.width &&
|
|
92
|
+
height == other.height &&
|
|
93
|
+
modifier == other.modifier &&
|
|
94
|
+
orientation == other.orientation
|
|
95
|
+
end
|
|
96
|
+
|
|
82
97
|
# Same as to_s
|
|
83
98
|
def inspect
|
|
84
99
|
to_s
|
|
@@ -1,45 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Paperclip
|
|
4
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::Commands::ImageMagick::GeometryParser+ instead.
|
|
2
5
|
class GeometryDetector
|
|
6
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::Commands::ImageMagick::GeometryParser+ instead.
|
|
3
7
|
def initialize(file)
|
|
8
|
+
warn_deprecation
|
|
4
9
|
@file = file
|
|
5
|
-
|
|
10
|
+
raise Errors::NotIdentifiedByImageMagickError.new("Cannot find the geometry of a file with a blank name") if @file.blank?
|
|
6
11
|
end
|
|
7
12
|
|
|
13
|
+
# @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::Commands::ImageMagick::GeometryParser+ instead.
|
|
8
14
|
def make
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
warn_deprecation
|
|
16
|
+
Paperclip::Commands::ImageMagick::GeometryParser.from_file(@file)
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
private
|
|
14
20
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
"%[exif:orientation]" : "1"
|
|
18
|
-
Paperclip.run(
|
|
19
|
-
Paperclip.options[:is_windows] ? "magick identify" : "identify",
|
|
20
|
-
"-format '%wx%h,#{orientation}' :file", {
|
|
21
|
-
file: "#{path}[0]"
|
|
22
|
-
},
|
|
23
|
-
swallow_stderr: true
|
|
24
|
-
)
|
|
25
|
-
rescue Terrapin::ExitStatusError
|
|
26
|
-
""
|
|
27
|
-
rescue Terrapin::CommandNotFoundError => e
|
|
28
|
-
raise_because_imagemagick_missing
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def path
|
|
32
|
-
@file.respond_to?(:path) ? @file.path : @file
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def raise_if_blank_file
|
|
36
|
-
if path.blank?
|
|
37
|
-
raise Errors::NotIdentifiedByImageMagickError.new("Cannot find the geometry of a file with a blank name")
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def raise_because_imagemagick_missing
|
|
42
|
-
raise Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
|
|
21
|
+
def warn_deprecation
|
|
22
|
+
Paperclip.deprecator.warn("Paperclip::GeometryDetector has been replaced by Paperclip::Commands::ImageMagick::GeometryParser")
|
|
43
23
|
end
|
|
44
24
|
end
|
|
45
25
|
end
|