jnicklas-carrierwave 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Generators +4 -0
- data/LICENSE +20 -0
- data/README.md +211 -0
- data/Rakefile +96 -0
- data/TODO +0 -0
- data/lib/carrierwave/mount.rb +93 -0
- data/lib/carrierwave/orm/activerecord.rb +20 -0
- data/lib/carrierwave/orm/datamapper.rb +20 -0
- data/lib/carrierwave/processing/image_science.rb +70 -0
- data/lib/carrierwave/processing/rmagick.rb +161 -0
- data/lib/carrierwave/sanitized_file.rb +231 -0
- data/lib/carrierwave/storage/abstract.rb +80 -0
- data/lib/carrierwave/storage/file.rb +40 -0
- data/lib/carrierwave/storage/s3.rb +83 -0
- data/lib/carrierwave/uploader.rb +420 -0
- data/lib/carrierwave.rb +63 -0
- data/lib/generators/templates/uploader.rbt +32 -0
- data/lib/generators/uploader_generator.rb +20 -0
- data/spec/fixtures/bork.txt +1 -0
- data/spec/fixtures/test.jpeg +1 -0
- data/spec/fixtures/test.jpg +1 -0
- data/spec/mount_spec.rb +180 -0
- data/spec/orm/activerecord_spec.rb +168 -0
- data/spec/orm/datamapper_spec.rb +133 -0
- data/spec/sanitized_file_spec.rb +618 -0
- data/spec/spec_helper.rb +122 -0
- data/spec/uploader_spec.rb +709 -0
- metadata +89 -0
data/Generators
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 YOUR NAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
# CarrierWave
|
2
|
+
|
3
|
+
This plugin for Merb and Rails provides a simple and extremely flexible way to upload files.
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
At the moment you are going to have to grab it here from github and install it yourself.
|
8
|
+
|
9
|
+
In Merb, add it as a dependency to your config/dependencies.rb:
|
10
|
+
|
11
|
+
dependency 'carrierwave'
|
12
|
+
|
13
|
+
In Rails, add it to your environment.rb:
|
14
|
+
|
15
|
+
config.gem "carrierwave"
|
16
|
+
|
17
|
+
## Quick Start
|
18
|
+
|
19
|
+
Start off by generating an uploader:
|
20
|
+
|
21
|
+
merb-gen uploader Avatar
|
22
|
+
|
23
|
+
this should give you a file in:
|
24
|
+
|
25
|
+
app/uploaders/avatar_uploader.rb
|
26
|
+
|
27
|
+
Check out this file for some hints on how you can customize your uploader. It should look something like this:
|
28
|
+
|
29
|
+
class AvatarUploader < CarrierWave::Uploader
|
30
|
+
storage :file
|
31
|
+
end
|
32
|
+
|
33
|
+
You can use your uploader class to store and retrieve files like this:
|
34
|
+
|
35
|
+
uploader = AvatarUploader.new
|
36
|
+
|
37
|
+
uploader.store!(my_file)
|
38
|
+
|
39
|
+
uploader.retrieve_from_store!('my_file.png')
|
40
|
+
|
41
|
+
CarrierWave gives you a `store` for permanent storage, and a `cache` for temporary storage. You can use different stores, at the moment a filesystem store and an Amazon S3 store are bundled.
|
42
|
+
|
43
|
+
Most of the time you are going to want to use CarrierWave together with an ORM. It is quite simple to mount uploaders on columns in your model, so you can simply assign files and get going:
|
44
|
+
|
45
|
+
### ActiveRecord
|
46
|
+
|
47
|
+
First require the activerecord extension:
|
48
|
+
|
49
|
+
require 'carrierwave/orm/activerecord
|
50
|
+
|
51
|
+
You don't need to do this if you are using Merb or Rails.
|
52
|
+
|
53
|
+
Open your model file, and do something like:
|
54
|
+
|
55
|
+
class User < ActiveRecord::Base
|
56
|
+
mount_uploader :avatar, AvatarUploader
|
57
|
+
end
|
58
|
+
|
59
|
+
Now you can upload files!
|
60
|
+
|
61
|
+
u = User.new
|
62
|
+
u.avatar = params[:file]
|
63
|
+
u.avatar = File.open('somewhere')
|
64
|
+
u.save!
|
65
|
+
u.avatar.url # => '/url/to/file.png'
|
66
|
+
u.avatar.current_path # => 'path/to/file.png'
|
67
|
+
|
68
|
+
### DataMapper
|
69
|
+
|
70
|
+
First require the activerecord extension:
|
71
|
+
|
72
|
+
require 'carrierwave/orm/datamapper
|
73
|
+
|
74
|
+
You don't need to do this if you are using Merb or Rails.
|
75
|
+
|
76
|
+
Open your model file, and do something like:
|
77
|
+
|
78
|
+
class User
|
79
|
+
include DataMapper::Resource
|
80
|
+
|
81
|
+
mount_uploader :avatar, AvatarUploader
|
82
|
+
end
|
83
|
+
|
84
|
+
Now you can upload files!
|
85
|
+
|
86
|
+
u = User.new
|
87
|
+
u.avatar = params[:file]
|
88
|
+
u.avatar = File.open('somewhere')
|
89
|
+
u.save!
|
90
|
+
u.avatar.url # => '/url/to/file.png'
|
91
|
+
u.avatar.current_path # => 'path/to/file.png'
|
92
|
+
|
93
|
+
## Changing the storage directory
|
94
|
+
|
95
|
+
In order to change where uploaded files are put, just override the `store_dir` method:
|
96
|
+
|
97
|
+
class MyUploader < CarrierWave::Uploader
|
98
|
+
def store_dir
|
99
|
+
'public/my/upload/directory'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
This works for the file storage as well as Amazon S3.
|
104
|
+
|
105
|
+
## Adding versions
|
106
|
+
|
107
|
+
Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this:
|
108
|
+
|
109
|
+
class MyUploader < CarrierWave::Uploader
|
110
|
+
include CarrierWave::RMagick
|
111
|
+
|
112
|
+
process :resize => [800, 800]
|
113
|
+
|
114
|
+
version :thumb do
|
115
|
+
process :crop_resized => [200,200]
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
When this uploader is used, an uploaded image would be scaled to be no larger than 800 by 800 pixels. A version called thumb is then created, which is scaled and cropped to exactly 200 by 200 pixels. The uploader could be used like this:
|
121
|
+
|
122
|
+
uploader = AvatarUploader.new
|
123
|
+
uploader.store!(my_file) # size: 1024x768
|
124
|
+
|
125
|
+
uploader.url # => '/url/to/my_file.png' # size: 800x600
|
126
|
+
uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
|
127
|
+
|
128
|
+
One important thing to remember is that process is called *before* versions are created. This can cut down on processing cost.
|
129
|
+
|
130
|
+
## What's in that uploader file?
|
131
|
+
|
132
|
+
The fact that uploaders are separate classes in CarrierWave is a big advantage. What this means for you is:
|
133
|
+
|
134
|
+
#### Less magic
|
135
|
+
|
136
|
+
In order to customize your uploader, all you need to do is override methods and use normal, clear and simple Ruby code. That means no `alias_method_chain`'ing to hook into the upload process, no messing around with weird extensions. The code in CarrierWave is very simple and easy because of this.
|
137
|
+
|
138
|
+
#### Easier to test
|
139
|
+
|
140
|
+
How do you test file uploads? I always found this ridiculously hard. A separate class means you can test is separately, which is nicer, easier and more maintainable.
|
141
|
+
|
142
|
+
#### More Flexible
|
143
|
+
|
144
|
+
Many of the things you can do in CarrierWave are hard, or impossible to do in other file upload plugins, and have previously required you to roll your own. Now you can get all the flexibility without having to write low level stuff.
|
145
|
+
|
146
|
+
#### Easy to extend
|
147
|
+
|
148
|
+
CarrierWave has support for a few different image manipulation libraries. These need *no* code to hook into CarrierWave, because they are simple modules. If you want to write your own manipulation library (doesn't need to be for images), you can do the same.
|
149
|
+
|
150
|
+
## Using Amazon S3
|
151
|
+
|
152
|
+
You'll need to configure a bucket, access id and secret key like this:
|
153
|
+
|
154
|
+
CarrierWave.config[:s3][:access_key_id] = 'xxxxxx'
|
155
|
+
CarrierWave.config[:s3][:secret_access_key] = 'xxxxxx'
|
156
|
+
CarrierWave.config[:s3][:bucket] = 'name_of_bucket'
|
157
|
+
|
158
|
+
Do this in an initializer in Rails, and in a `before_app_loads` block in Merb.
|
159
|
+
|
160
|
+
And then in your uploader, set the storage to :s3
|
161
|
+
|
162
|
+
class AvatarUploader < CarrierWave::Uploader
|
163
|
+
storage :s3
|
164
|
+
end
|
165
|
+
|
166
|
+
That's it! You can still use the `CarrierWave::Uploader#url` method to return the url to the file on Amazon S3
|
167
|
+
|
168
|
+
## Using RMagick
|
169
|
+
|
170
|
+
If you're uploading images, you'll probably want to manipulate them in some way, you might want to create thumbnail images for example. CarrierWave comes with a small library to make manipulating images with RMagick easier. It's not loaded by default so you'll need to require it:
|
171
|
+
|
172
|
+
require 'carrierwave/processing/rmagick'
|
173
|
+
|
174
|
+
You'll also need to include it in your Uploader:
|
175
|
+
|
176
|
+
class AvatarUploader < CarrierWave::Uploader
|
177
|
+
include CarrierWave::RMagick
|
178
|
+
end
|
179
|
+
|
180
|
+
The RMagick module gives you a few methods, like `CarrierWave::RMagick#crop_resized` which manipulate the image file in some way. You can set a `process` callback, which will call that method any time a file is uploaded.
|
181
|
+
|
182
|
+
class AvatarUploader < CarrierWave::Uploader
|
183
|
+
include CarrierWave::RMagick
|
184
|
+
|
185
|
+
process :crop_resized => [200, 200]
|
186
|
+
process :convert => 'png'
|
187
|
+
|
188
|
+
def filename
|
189
|
+
super + '.png'
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
Check out the manipulate! method, which makes it easy for you to write your own manipulation methods.
|
194
|
+
|
195
|
+
## Using ImageScience
|
196
|
+
|
197
|
+
ImageScience works the same way as RMagick. As with RMagick you'll need to require it:
|
198
|
+
|
199
|
+
require 'carrierwave/processing/image_science'
|
200
|
+
|
201
|
+
And then include it in your model:
|
202
|
+
|
203
|
+
class AvatarUploader < CarrierWave::Uploader
|
204
|
+
include CarrierWave::ImageScience
|
205
|
+
|
206
|
+
process :crop_resized => [200, 200]
|
207
|
+
end
|
208
|
+
|
209
|
+
## Read the source
|
210
|
+
|
211
|
+
CarrierWave is still young, but most of it is pretty well documented. Just dig in and look at the source for more in-depth explanation of what things are doing.
|
data/Rakefile
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
require 'yard'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'cucumber/rake/task'
|
7
|
+
|
8
|
+
NAME = "carrierwave"
|
9
|
+
GEM_VERSION = "0.1"
|
10
|
+
AUTHOR = "Jonas Nicklas"
|
11
|
+
EMAIL = "jonas.nicklas@gmail.com"
|
12
|
+
HOMEPAGE = "http://www.example.com"
|
13
|
+
SUMMARY = "Simple and powerful uploads for Merb and Rails"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.rubyforge_project = 'carrierwave'
|
17
|
+
s.name = NAME
|
18
|
+
s.version = GEM_VERSION
|
19
|
+
s.platform = Gem::Platform::RUBY
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.extra_rdoc_files = ["README.md", "LICENSE", 'TODO']
|
22
|
+
s.summary = SUMMARY
|
23
|
+
s.description = s.summary
|
24
|
+
s.author = AUTHOR
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
s.require_path = 'lib'
|
28
|
+
s.files = %w(LICENSE Generators README.md Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# Try these:
|
33
|
+
#
|
34
|
+
# rake features
|
35
|
+
# rake features PROFILE=html
|
36
|
+
Cucumber::Rake::Task.new do |t|
|
37
|
+
profile = ENV['PROFILE'] || 'default'
|
38
|
+
t.cucumber_opts = "--profile #{profile}"
|
39
|
+
end
|
40
|
+
|
41
|
+
YARD::Rake::YardocTask.new do |t|
|
42
|
+
t.files = ["README.md", "LICENSE", "TODO", 'lib/carrierwave/**/*.rb']
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
46
|
+
pkg.gem_spec = spec
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "install the plugin locally"
|
50
|
+
task :install => [:package] do
|
51
|
+
sh %{#{sudo} gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "create a gemspec file"
|
55
|
+
task :make_spec do
|
56
|
+
File.open("#{NAME}.gemspec", "w") do |file|
|
57
|
+
file.puts spec.to_ruby
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
namespace :jruby do
|
62
|
+
|
63
|
+
desc "Run :package and install the resulting .gem with jruby"
|
64
|
+
task :install => :package do
|
65
|
+
sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION}.gem --no-rdoc --no-ri}
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
file_list = FileList['spec/**/*_spec.rb']
|
71
|
+
|
72
|
+
desc "Run all examples"
|
73
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
74
|
+
t.spec_files = file_list
|
75
|
+
end
|
76
|
+
|
77
|
+
namespace :spec do
|
78
|
+
desc "Run all examples with RCov"
|
79
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
80
|
+
t.spec_files = file_list
|
81
|
+
t.rcov = true
|
82
|
+
t.rcov_dir = "doc/coverage"
|
83
|
+
t.rcov_opts = ['--exclude', 'spec']
|
84
|
+
end
|
85
|
+
|
86
|
+
desc "Generate an html report"
|
87
|
+
Spec::Rake::SpecTask.new('report') do |t|
|
88
|
+
t.spec_files = file_list
|
89
|
+
t.spec_opts = ["--format", "html:doc/reports/specs.html"]
|
90
|
+
t.fail_on_error = false
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
desc 'Default: run unit tests.'
|
96
|
+
task :default => 'spec'
|
data/TODO
ADDED
File without changes
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
|
3
|
+
module Mount
|
4
|
+
module Extension
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def uploaders
|
9
|
+
@uploaders ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def store_uploader!(column)
|
13
|
+
if uploaders[column]
|
14
|
+
uploaders[column].store!
|
15
|
+
write_uploader(column, uploaders[column].identifier)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_uploader(column)
|
20
|
+
return uploaders[column] if uploaders[column]
|
21
|
+
|
22
|
+
identifier = read_uploader(column)
|
23
|
+
|
24
|
+
unless identifier.blank?
|
25
|
+
uploaders[column] ||= self.class.uploaders[column].new(self, column)
|
26
|
+
uploaders[column].retrieve_from_store!(identifier)
|
27
|
+
uploaders[column]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_uploader(column, new_file)
|
32
|
+
new_file = CarrierWave::SanitizedFile.new(new_file)
|
33
|
+
|
34
|
+
unless new_file.empty?
|
35
|
+
uploaders[column] ||= self.class.uploaders[column].new(self, column)
|
36
|
+
uploaders[column].cache!(new_file)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_uploader_cache(column)
|
41
|
+
uploaders[column].cache_name if uploaders[column]
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_uploader_cache(column, cache_name)
|
45
|
+
unless cache_name.blank?
|
46
|
+
uploaders[column] ||= self.class.uploaders[column].new(self, column)
|
47
|
+
uploaders[column].retrieve_from_cache(cache_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end # Extension
|
52
|
+
|
53
|
+
def uploaders
|
54
|
+
@uploaders ||= {}
|
55
|
+
end
|
56
|
+
|
57
|
+
def mount_uploader(column, uploader=nil, &block)
|
58
|
+
unless uploader
|
59
|
+
uploader = Class.new(CarrierWave::Uploader)
|
60
|
+
uploader.class_eval(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
uploaders[column.to_sym] = uploader
|
64
|
+
|
65
|
+
include CarrierWave::Mount::Extension
|
66
|
+
|
67
|
+
class_eval <<-EOF, __FILE__, __LINE__+1
|
68
|
+
def #{column} # def image
|
69
|
+
get_uploader(:#{column}) # get_uploader(:image)
|
70
|
+
end # end
|
71
|
+
#
|
72
|
+
def #{column}=(new_file) # def image=(new_file)
|
73
|
+
set_uploader(:#{column}, new_file) # set_uploader(:image, new_file)
|
74
|
+
end # end
|
75
|
+
#
|
76
|
+
def #{column}_cache # def image_cache
|
77
|
+
get_uploader_cache(:#{column}) # get_uploader_cache(:image)
|
78
|
+
end # end
|
79
|
+
#
|
80
|
+
def #{column}_cache=(cache_name) # def image_cache=(cache_name)
|
81
|
+
set_uploader_cache(:#{column}, cache_name) # set_uploader_cache(:image, cache_name)
|
82
|
+
end # end
|
83
|
+
#
|
84
|
+
def store_#{column}! # def store_image!
|
85
|
+
store_uploader!(:#{column}) # store_uploader!(:image)
|
86
|
+
end # end
|
87
|
+
EOF
|
88
|
+
|
89
|
+
after_mount(column, uploader) if respond_to?(:after_mount)
|
90
|
+
end
|
91
|
+
|
92
|
+
end # Mount
|
93
|
+
end # CarrierWave
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'activerecord'
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
module ActiveRecord
|
5
|
+
|
6
|
+
include CarrierWave::Mount
|
7
|
+
|
8
|
+
def after_mount(column, uploader)
|
9
|
+
alias_method :read_uploader, :read_attribute
|
10
|
+
alias_method :write_uploader, :write_attribute
|
11
|
+
|
12
|
+
before_save do |record|
|
13
|
+
record.send("store_#{column}!")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end # ActiveRecord
|
18
|
+
end # CarrierWave
|
19
|
+
|
20
|
+
ActiveRecord::Base.send(:extend, CarrierWave::ActiveRecord)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
module DataMapper
|
5
|
+
|
6
|
+
include CarrierWave::Mount
|
7
|
+
|
8
|
+
def after_mount(column, uploader)
|
9
|
+
alias_method :read_uploader, :attribute_get
|
10
|
+
alias_method :write_uploader, :attribute_set
|
11
|
+
|
12
|
+
before :save do
|
13
|
+
send("store_#{column}!")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end # DataMapper
|
18
|
+
end # CarrierWave
|
19
|
+
|
20
|
+
DataMapper::Model.send(:include, CarrierWave::DataMapper)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "image_science"
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
module ImageScience
|
5
|
+
|
6
|
+
# Resize the image so that it will not exceed the dimensions passed
|
7
|
+
# via geometry, geometry should be a string, formatted like '200x100' where
|
8
|
+
# the first number is the height and the second is the width
|
9
|
+
def resize!( geometry )
|
10
|
+
::ImageScience.with_image(self.current_path) do |img|
|
11
|
+
width, height = extract_dimensions(img.width, img.height, geometry)
|
12
|
+
img.resize( width, height ) do |file|
|
13
|
+
file.save( self.current_path )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Resize and crop the image so that it will have the exact dimensions passed
|
19
|
+
# via geometry, geometry should be a string, formatted like '200x100' where
|
20
|
+
# the first number is the height and the second is the width
|
21
|
+
def crop_resized!( geometry )
|
22
|
+
::ImageScience.with_image(self.current_path) do |img|
|
23
|
+
new_width, new_height = geometry.split('x').map{|i| i.to_i }
|
24
|
+
|
25
|
+
width, height = extract_dimensions_for_crop(img.width, img.height, geometry)
|
26
|
+
x_offset, y_offset = extract_placement_for_crop(width, height, geometry)
|
27
|
+
|
28
|
+
img.resize( width, height ) do |i2|
|
29
|
+
|
30
|
+
i2.with_crop( x_offset, y_offset, new_width + x_offset, new_height + y_offset) do |file|
|
31
|
+
file.save( self.current_path )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def extract_dimensions(width, height, new_geometry, type = :resize)
|
40
|
+
new_width, new_height = convert_geometry(new_geometry)
|
41
|
+
|
42
|
+
aspect_ratio = width.to_f / height.to_f
|
43
|
+
new_aspect_ratio = new_width / new_height
|
44
|
+
|
45
|
+
if (new_aspect_ratio > aspect_ratio) ^ ( type == :crop ) # Image is too wide, the caret is the XOR operator
|
46
|
+
new_width, new_height = [ (new_height * aspect_ratio), new_height]
|
47
|
+
else #Image is too narrow
|
48
|
+
new_width, new_height = [ new_width, (new_width / aspect_ratio)]
|
49
|
+
end
|
50
|
+
|
51
|
+
[new_width, new_height].collect! { |v| v.round }
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_dimensions_for_crop(width, height, new_geometry)
|
55
|
+
extract_dimensions(width, height, new_geometry, :crop)
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_placement_for_crop(width, height, new_geometry)
|
59
|
+
new_width, new_height = convert_geometry(new_geometry)
|
60
|
+
x_offset = (width / 2.0) - (new_width / 2.0)
|
61
|
+
y_offset = (height / 2.0) - (new_height / 2.0)
|
62
|
+
[x_offset, y_offset].collect! { |v| v.round }
|
63
|
+
end
|
64
|
+
|
65
|
+
def convert_geometry(geometry)
|
66
|
+
geometry.split('x').map{|i| i.to_f }
|
67
|
+
end
|
68
|
+
|
69
|
+
end # ImageScience
|
70
|
+
end # CarrierWave
|