dynamic_image 1.0.4 → 2.0.0.beta1

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/{LICENSE → MIT-LICENSE} +1 -1
  3. data/README.md +57 -80
  4. data/Rakefile +7 -30
  5. data/lib/dynamic_image/belongs_to.rb +22 -0
  6. data/lib/dynamic_image/controller.rb +94 -0
  7. data/lib/dynamic_image/digest_verifier.rb +62 -0
  8. data/lib/dynamic_image/errors.rb +10 -0
  9. data/lib/dynamic_image/helper.rb +139 -85
  10. data/lib/dynamic_image/image_sizing.rb +156 -0
  11. data/lib/dynamic_image/metadata.rb +84 -0
  12. data/lib/dynamic_image/model/dimensions.rb +95 -0
  13. data/lib/dynamic_image/model/validations.rb +94 -0
  14. data/lib/dynamic_image/model.rb +130 -0
  15. data/lib/dynamic_image/processed_image.rb +119 -0
  16. data/lib/dynamic_image/railtie.rb +18 -0
  17. data/lib/dynamic_image/routing.rb +24 -0
  18. data/lib/dynamic_image/version.rb +5 -0
  19. data/lib/dynamic_image.rb +14 -71
  20. data/lib/rails/generators/dynamic_image/resource/resource_generator.rb +74 -0
  21. metadata +130 -97
  22. data/VERSION +0 -1
  23. data/app/controllers/images_controller.rb +0 -79
  24. data/app/models/image.rb +0 -188
  25. data/config/routes.rb +0 -16
  26. data/dynamic_image.gemspec +0 -62
  27. data/dynamic_image.sublime-project +0 -9
  28. data/dynamic_image.sublime-workspace +0 -1599
  29. data/init.rb +0 -1
  30. data/install.rb +0 -1
  31. data/lib/binary_storage/active_record_extensions.rb +0 -144
  32. data/lib/binary_storage/blob.rb +0 -104
  33. data/lib/binary_storage.rb +0 -28
  34. data/lib/dynamic_image/active_record_extensions.rb +0 -60
  35. data/lib/dynamic_image/engine.rb +0 -6
  36. data/lib/dynamic_image/filterset.rb +0 -79
  37. data/lib/generators/dynamic_image/USAGE +0 -5
  38. data/lib/generators/dynamic_image/dynamic_image_generator.rb +0 -38
  39. data/lib/generators/dynamic_image/templates/migrations/create_images.rb +0 -21
  40. data/uninstall.rb +0 -1
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fa4635730b705cb0d3d48024139359bc7bbbfef6
4
+ data.tar.gz: ededec9d42f262502983c22c8c753b8de8498a9b
5
+ SHA512:
6
+ metadata.gz: 3558ebbfb2e0f5e2744bbdc028da4e73515134fa88100749bf072af97f61707dfb56a969d31a482d409e24818548dab1cd09207b46a4925552b5d051ce714cb5
7
+ data.tar.gz: be91b398098093248afd99558fe3101eedd1917193efba2632d36e3617d5929f5c3d1709745e2ddd8427b612b4a7024ad4c148e1e4adcf95044c0feb19564995
@@ -1,4 +1,4 @@
1
- Copyright (c) 2006-2010 Inge Jørgensen
1
+ Copyright 2006-2014 Inge Jørgensen
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,109 +1,86 @@
1
- # DynamicImage
2
-
3
- DynamicImage is a Rails plugin that simplifies image uploading and processing.
4
- No configuration is necessary, as resizing and processing is done on demand and
5
- cached rather than on upload.
6
-
7
- Note: This version is currently Rails 3 specific, although the final 1.0
8
- version will also be compatible with 2.x.
1
+ # DynamicImage [![Build Status](https://travis-ci.org/elektronaut/dynamic_image.png)](https://travis-ci.org/elektronaut/dynamic_image) [![Code Climate](https://codeclimate.com/github/elektronaut/dynamic_image.png)](https://codeclimate.com/github/elektronaut/dynamic_image) [![Code Climate](https://codeclimate.com/github/elektronaut/dynamic_image/coverage.png)](https://codeclimate.com/github/elektronaut/dynamic_image)
9
2
 
3
+ Requires Rails 4.1+ and Ruby 1.9.3+.
10
4
 
11
5
  ## Installation
12
6
 
13
- Install the gem:
14
-
15
- gem install dynamic_image
16
-
17
- Add the gem to your Gemfile:
18
-
19
- gem 'dynamic_image'
20
-
21
- Do the migrations:
22
-
23
- rails generate dynamic_image migrations
24
- rake db:migrate
25
-
26
-
27
- ## Getting started
7
+ Add the gem to your Gemfile and run `bundle install`.
28
8
 
29
- Let's create a model with an image:
9
+ ```ruby
10
+ gem "dynamic_image"
11
+ ```
30
12
 
31
- class User
32
- belongs_to_image :mugshot
33
- end
13
+ Run the `dis:install` generator to set up your storage.
34
14
 
35
- Uploading files is pretty straightforward, just add a <tt>file_field</tt>
36
- to your form and update your record as usual:
15
+ ```sh
16
+ bin/rails generate dis:install
17
+ ```
37
18
 
38
- <%= form_for @user, :html => {:multipart => true} do |f| %>
39
- Name: <%= f.text_field :name %>
40
- Mugshot: <%= f.file_field :mugshot %>
41
- <%= submit_tag "Save" %>
42
- <% end %>
19
+ You can edit the generated initializer to configure your storage, by default it
20
+ will store files in `db/dis`. See the
21
+ [Dis](https://github.com/elektronaut/dis) documentation for more
22
+ information.
43
23
 
44
- You can now use the <tt>dynamic_image_tag</tt> helper to show off your
45
- new image:
24
+ ## Creating your resource
46
25
 
47
- <% if @user.mugshot? %>
48
- <%= dynamic_image_tag @user.profile_picture, :size => '64x64' %>
49
- <% end %>
26
+ Run the `dynamic_image:resource` generator to create your resource.
50
27
 
28
+ ```sh
29
+ bin/rails generate dynamic_image:resource image
30
+ ```
51
31
 
52
- ## Filters
32
+ This will create an `Image` model and a controller, along with a migration and
33
+ the necessary routes.
53
34
 
54
- I'm cleaning up the filters syntax, watch this space.
35
+ Note that in this case, the route with collide with any static images stored
36
+ in `public/images`. You can customize the path if you want in the route
37
+ declaration.
55
38
 
39
+ ```ruby
40
+ image_resources :images, path: "dynamic_images/:digest(/:size)"
41
+ ```
56
42
 
57
- ## Technical
43
+ ## Rendering images in your views
58
44
 
59
- The original master files are stored in the file system and identified a
60
- SHA-1 hash of the contents. If you're familiar with the internal workings
61
- of git, this should seem familiar.
45
+ You should use the provided helpers for displaying images, this will ensure
46
+ that the generated URLs are properly signed and timestamped.
62
47
 
63
- Processing images on the fly is expensive. Therefore, page caching is enabled
64
- by default, even in development mode. To disable page caching, add the following
65
- line in your initializers:
48
+ To display the image at it's original size, use `dynamic_image_tag` without
49
+ any options.
66
50
 
67
- DynamicImage.page_caching = false
51
+ ```html
52
+ <%= dynamic_image_tag image %>
53
+ ```
68
54
 
55
+ To resize it, specify a max size. This will scale the image down to fit, but
56
+ no cropping will occur.
69
57
 
70
- ## History
58
+ ```html
59
+ <%= dynamic_image_tag image, size: '400x400' %>
60
+ ```
71
61
 
72
- DynamicImage was originally created in early 2006 to handle images
73
- for the Pages CMS. It was later extracted as a Rails Engine for Rails
74
- 1.2 in 2007, which also marked the first public release as
75
- dynamic_image_engine.
62
+ Setting `crop: true` will crop the image to the exact size.
76
63
 
77
- The API has remained more or less unchanged, but the internal workings
78
- have been refactored a few times over the years, most notably dropping
79
- the Engines dependency and transitioning from database storage to file
80
- system.
64
+ ```html
65
+ <%= dynamic_image_tag image, size: '400x400', crop: true %>
66
+ ```
81
67
 
82
- The current version is based on an internal branch targeting Rails
83
- 2.3, and modified to work as a Rails 3 plugin. It's not directly
84
- compatible with earlier versions, but upgrading shouldn't be more
85
- trouble than migrating the files out of the database.
68
+ Omitting either dimension will render the image at an exact width or height.
86
69
 
70
+ ```html
71
+ <%= dynamic_image_tag image, size: '400x' %>
72
+ ```
87
73
 
88
- ## Copyright
74
+ `dynamic_image_path` and `dynamic_image_url` act pretty much like regular URL
75
+ helpers.
89
76
 
90
- Copyright © 2006 Inge Jørgensen.
77
+ ```html
78
+ <%= link_to "See image", dynamic_image_path(image) %>
79
+ ```
91
80
 
92
- Permission is hereby granted, free of charge, to any person obtaining
93
- a copy of this software and associated documentation files (the
94
- "Software"), to deal in the Software without restriction, including
95
- without limitation the rights to use, copy, modify, merge, publish,
96
- distribute, sublicense, and/or sell copies of the Software, and to
97
- permit persons to whom the Software is furnished to do so, subject to
98
- the following conditions:
81
+ ## License
99
82
 
100
- The above copyright notice and this permission notice shall be
101
- included in all copies or substantial portions of the Software.
83
+ Copyright 2006-2014 Inge Jørgensen
102
84
 
103
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
104
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
105
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
106
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
107
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
108
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
109
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85
+ DynamicImage is released under the
86
+ [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,33 +1,10 @@
1
- require 'rake'
2
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
3
 
4
- require "rake"
4
+ APP_RAKEFILE = "spec/internal/Rakefile"
5
+ load 'rails/tasks/engine.rake'
5
6
 
6
- begin
7
- require "jeweler"
8
- Jeweler::Tasks.new do |gem|
9
- gem.name = "dynamic_image"
10
- gem.summary = "DynamicImage is a rails plugin providing transparent uploading and processing of image files."
11
- gem.email = "inge@elektronaut.no"
12
- gem.homepage = "http://github.com/elektronaut/dynamic_image"
13
- gem.authors = ["Inge Jørgensen"]
14
- gem.files = Dir["*", "{lib}/**/*", "{app}/**/*", "{config}/**/*"]
15
- gem.add_dependency("rmagick", "~> 2.13.2")
16
- gem.add_dependency("vector2d", "~> 1.0.0")
17
- end
18
- Jeweler::GemcutterTasks.new
19
- rescue LoadError
20
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
- end
22
-
23
- desc 'Default: run unit tests.'
24
- task :default => :test
25
-
26
- desc 'Test the dynamic_image plugin.'
27
- Rake::TestTask.new(:test) do |t|
28
- t.libs << 'lib'
29
- t.libs << 'test'
30
- t.pattern = 'test/**/*_test.rb'
31
- t.verbose = true
32
- end
7
+ RSpec::Core::RakeTask.new
33
8
 
9
+ task :default => :spec
10
+ task :test => :spec
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module DynamicImage
4
+ # = DynamicImage Belongs To
5
+ #
6
+ module BelongsTo
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def belongs_to_image(name, scope=nil, options={})
11
+ belongs_to(name, scope, options)
12
+
13
+ define_method "#{name}=" do |new_image|
14
+ if new_image.present? && !new_image.kind_of?(DynamicImage::Model)
15
+ new_image = self.send("build_#{name}", file: new_image)
16
+ end
17
+ super(new_image)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+
3
+ module DynamicImage
4
+ # = DynamicImage Controller
5
+ #
6
+ # Generating images is rather expensive, so all requests must be
7
+ # signed with a HMAC digest in order to avoid denial of service attacks.
8
+ # The methods in +DynamicImage::Helper+ handles this transparently.
9
+ # As a bonus, this also prevents unauthorized URL enumeration.
10
+ module Controller
11
+ extend ActiveSupport::Concern
12
+
13
+ included do
14
+ before_action :verify_signed_params
15
+ before_action :find_record
16
+ after_action :cache_expiration_header
17
+ respond_to :gif, :jpeg, :png, :tiff
18
+ end
19
+
20
+ # Renders the image.
21
+ def show
22
+ render_image(format: requested_format)
23
+ end
24
+
25
+ # Same as +show+, but renders the image without any pre-cropping applied.
26
+ def uncropped
27
+ render_image(format: requested_format, uncropped: true)
28
+ end
29
+
30
+ # Renders the original image data, without any processing.
31
+ def original
32
+ if stale?(@record)
33
+ respond_with(@record) do |format|
34
+ format.any(:gif, :jpeg, :png, :tiff) do
35
+ send_data(
36
+ @record.data,
37
+ content_type: @record.content_type,
38
+ disposition: 'inline'
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def cache_expiration_header
48
+ expires_in 30.days, public: true
49
+ end
50
+
51
+ def find_record
52
+ @record = model.find(params[:id])
53
+ end
54
+
55
+ def render_image(options)
56
+ processed_image = DynamicImage::ProcessedImage.new(@record, options)
57
+ if stale?(@record)
58
+ respond_with(@record) do |format|
59
+ format.any(:gif, :jpeg, :png, :tiff) do
60
+ send_data(
61
+ processed_image.cropped_and_resized(requested_size),
62
+ content_type: processed_image.content_type,
63
+ disposition: 'inline'
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ def requested_format
71
+ params[:format]
72
+ end
73
+
74
+ def requested_size
75
+ Vector2d.parse(params[:size])
76
+ end
77
+
78
+ def signed_params
79
+ case request[:action]
80
+ when "show", "uncropped"
81
+ [:action, :id, :size]
82
+ else
83
+ [:action, :id]
84
+ end
85
+ end
86
+
87
+ def verify_signed_params
88
+ key = signed_params.map { |k|
89
+ k == :id ? params.require(k).to_i : params.require(k)
90
+ }.join('-')
91
+ DynamicImage.digest_verifier.verify(key, params[:digest])
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module DynamicImage
4
+ # = DynamicImage Digest Verifier
5
+ #
6
+ # ==== Usage
7
+ #
8
+ # verifier = DynamicImage::DigestVerifier.new("super secret!")
9
+ #
10
+ # digest = verifier.generate("foo")
11
+ #
12
+ # digest.verify("foo", digest)
13
+ # # => true
14
+ # digest.verify("bar", digest)
15
+ # # => raises DynamicImage::Errors::InvalidSignature
16
+ #
17
+ # Credit where credit is due: adapted and simplified from
18
+ # +ActiveSupport::MessageVerifier+, since we don't need to handle
19
+ # arbitrary data structures and ship the serialized data to the client.
20
+ class DigestVerifier
21
+ def initialize(secret, options = {})
22
+ @secret = secret
23
+ @digest = options[:digest] || 'SHA1'
24
+ end
25
+
26
+ # Generates a digest for a string.
27
+ def generate(data)
28
+ generate_digest(data)
29
+ end
30
+
31
+ # Verifies that <tt>digest</tt> is valid for <tt>data</tt>.
32
+ # Raises a +DynamicImage::Errors::InvalidSignature+ error if not.
33
+ def verify(data, digest)
34
+ if valid_digest?(data, digest)
35
+ true
36
+ else
37
+ raise DynamicImage::Errors::InvalidSignature
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def secure_compare(a, b)
44
+ return false unless a.bytesize == b.bytesize
45
+
46
+ l = a.unpack "C#{a.bytesize}"
47
+
48
+ res = 0
49
+ b.each_byte { |byte| res |= byte ^ l.shift }
50
+ res == 0
51
+ end
52
+
53
+ def generate_digest(data)
54
+ require 'openssl' unless defined?(OpenSSL)
55
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
56
+ end
57
+
58
+ def valid_digest?(data, digest)
59
+ data.present? && digest.present? && secure_compare(digest, generate_digest(data))
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ module DynamicImage
4
+ module Errors
5
+ class Error < StandardError; end
6
+ class InvalidImage < DynamicImage::Errors::Error; end
7
+ class InvalidSignature < DynamicImage::Errors::Error; end
8
+ class InvalidSizeOptions < DynamicImage::Errors::Error; end
9
+ end
10
+ end
@@ -1,107 +1,161 @@
1
- require 'dynamic_image'
1
+ # encoding: utf-8
2
2
 
3
3
  module DynamicImage
4
+ # = DynamicImage Helper
5
+ #
6
+ # Provides helper methods for rendering and linking to images.
4
7
  module Helper
8
+ # Returns the path for a DynamicImage::Model record.
9
+ # Takes the same options as +dynamic_image_url+
10
+ def dynamic_image_path(record_or_array, options={})
11
+ dynamic_image_url(record_or_array, { routing_type: :path }.merge(options))
12
+ end
5
13
 
6
- # Returns an hash consisting of the URL to the dynamic image and parsed options. This is mostly for internal use by
7
- # dynamic_image_tag and dynamic_image_url.
8
- def dynamic_image_options(image, options = {})
9
- options.symbolize_keys!
10
-
11
- options = {:crop => false}.merge(options)
12
- url_options = {:controller => "/images", :action => :render_dynamic_image, :id => image}
14
+ # Returns an HTML image tag for the record. If no size is given, it will
15
+ # render at the original size.
16
+ #
17
+ # ==== Options
18
+ # * <tt>:alt</tt>: If no alt text is given, it will default to the
19
+ # filename of the uploaded image.
20
+ #
21
+ # See +dynamic_image_url+ for info on how to size and cropping. Options
22
+ # supported by +polymorphic_url+ will be passed to the router. Any other
23
+ # options will be added as HTML attributes.
24
+ #
25
+ # ==== Examples
26
+ #
27
+ # image = Image.find(params[:id])
28
+ # dynamic_image_tag(image)
29
+ # # => <img alt="My file" height="200" src="..." width="320" />
30
+ # dynamic_image_tag(image, size: "100x100", alt="Avatar")
31
+ # # => <img alt="Avatar" height="62" src="..." width="100" />
32
+ def dynamic_image_tag(record_or_array, options={})
33
+ record = extract_record(record_or_array)
34
+ options = {
35
+ alt: image_alt(record.filename)
36
+ }.merge(options)
37
+
38
+ size = fit_size!(record_or_array, options)
39
+ url_options = options.extract!(*allowed_dynamic_image_url_options)
40
+ html_options = { size: size }.merge(options)
41
+
42
+ image_tag(
43
+ dynamic_image_path_with_size(
44
+ record_or_array,
45
+ size,
46
+ url_options
47
+ ),
48
+ html_options
49
+ )
50
+ end
13
51
 
14
- if options[:original]
15
- url_options[:original] = 'original'
16
- options.delete(:original)
17
- end
52
+ # Returns the URL for a DynamicImage::Model record.
53
+ #
54
+ # ==== Options
55
+ #
56
+ # * <tt>:size</tt> - Desired image size, supplied as "{width}x{height}".
57
+ # The image will be scaled to fit. A partial size like "100x" or "x100"
58
+ # can be given, if you want a fixed width or height.
59
+ # * <tt>:crop</tt> - If true, the image will be cropped to the given size.
60
+ # * <tt>:upscale</tt> - By default, DynamicImage only scale images down,
61
+ # never up. Pass <tt>upscale: true</tt> to force upscaling.
62
+ #
63
+ # Any options supported by +polymorphic_url+ are also accepted.
64
+ #
65
+ # ==== Examples
66
+ #
67
+ # image = Image.find(params[:id])
68
+ # dynamic_image_url(image)
69
+ # # => "http://example.com/images/96...d1/300x187/1-2014062020...00.jpg"
70
+ # dynamic_image_url(image, size: '100x100')
71
+ # # => "http://example.com/images/72...c2/100x62/1-2014062020...00.jpg"
72
+ # dynamic_image_url(image, size: '100x100', crop: true)
73
+ # # => "http://example.com/images/a4...6b/100x100/1-2014062020...00.jpg"
74
+ def dynamic_image_url(record_or_array, options={})
75
+ size = fit_size!(record_or_array, options)
76
+ dynamic_image_url_with_size(record_or_array, size, options)
77
+ end
18
78
 
19
- # Image sizing
20
- if options[:size]
21
- new_size = Vector2d.new(options[:size])
22
- image_size = Vector2d.new(image.size)
79
+ # Returns a path to the original uploaded file, without any processing
80
+ # applied. Sizing options are not supported.
81
+ def original_dynamic_image_path(record_or_array, options={})
82
+ dynamic_image_path(record_or_array, { action: :original }.merge(options))
83
+ end
23
84
 
24
- unless options[:upscale]
25
- new_size.x = image_size.x if new_size.x > 0 && new_size.x > image_size.x
26
- new_size.y = image_size.y if new_size.y > 0 && new_size.y > image_size.y
27
- end
85
+ # Returns a URL to the original uploaded file, without any processing
86
+ # applied. Sizing options are not supported.
87
+ def original_dynamic_image_url(record_or_array, options={})
88
+ dynamic_image_url(record_or_array, { action: :original }.merge(options))
89
+ end
28
90
 
29
- unless options[:crop]
30
- new_size = image_size.constrain_both(new_size)
31
- end
91
+ # Same as +dynamic_image_path+, but points to an image with any
92
+ # pre-cropping disabled.
93
+ def uncropped_dynamic_image_path(record_or_array, options={})
94
+ dynamic_image_path(record_or_array, { action: :uncropped }.merge(options))
95
+ end
32
96
 
33
- options[:size] = new_size.round.to_s
34
- url_options[:size] = options[:size]
35
- end
36
- options.delete :crop
97
+ # Same as +dynamic_image_tag+, but renders an image with any
98
+ # pre-cropping disabled.
99
+ def uncropped_dynamic_image_tag(record_or_array, options={})
100
+ dynamic_image_tag(record_or_array, { action: :uncropped }.merge(options))
101
+ end
37
102
 
38
- if options[:no_size_attr]
39
- options.delete :no_size_attr
40
- options.delete :size
41
- end
103
+ # Same as +dynamic_image_url+, but points to an image with any
104
+ # pre-cropping disabled.
105
+ def uncropped_dynamic_image_url(record_or_array, options={})
106
+ dynamic_image_url(record_or_array, { action: :uncropped }.merge(options))
107
+ end
42
108
 
43
- # Filterset
44
- if options[:filterset]
45
- url_options[:filterset] = options[:filterset]
46
- options.delete :filterset
47
- end
109
+ private
48
110
 
49
- # Filename
50
- if options[:filename]
51
- filename = options[:filename]
52
- unless filename =~ /\.[\w]{1,4}$/
53
- filename += "." + image.filename.split(".").last
54
- end
55
- url_options[:filename] = filename
56
- else
57
- url_options[:filename] = image.filename
58
- end
111
+ def allowed_dynamic_image_url_options
112
+ [
113
+ :format, :only_path, :protocol, :host, :subdomain, :domain,
114
+ :tld_length, :port, :anchor, :trailing_slash, :script_name,
115
+ :action, :routing_type
116
+ ]
117
+ end
59
118
 
60
- # Alt attribute
61
- options[:alt] ||= image.name if image.name?
62
- options[:alt] ||= image.filename.split('.').first.capitalize
119
+ def default_format_for_image(record)
120
+ Mime::Type.lookup(record.safe_content_type).to_sym
121
+ end
63
122
 
64
- if options.has_key?(:only_path)
65
- url_options[:only_path] = options[:only_path]
66
- options[:only_path] = nil
67
- end
68
- if options.has_key?(:host)
69
- url_options[:host] = options[:host]
70
- options[:host] = nil
71
- end
123
+ def dynamic_image_digest(record, action, size=nil)
124
+ key = [action || 'show', record.id, size].compact.join('-')
125
+ DynamicImage.digest_verifier.generate(key)
126
+ end
72
127
 
73
- {:url => url_for(url_options), :options => options}
128
+ def dynamic_image_path_with_size(record_or_array, size=nil, options={})
129
+ dynamic_image_url_with_size(record_or_array, size, { routing_type: :path }.merge(options))
74
130
  end
75
131
 
76
- # Returns an image tag for the provided image model, works similar to the rails <tt>image_tag</tt> helper.
77
- #
78
- # The following options are supported (the rest will be forwarded to <tt>image_tag</tt>):
79
- #
80
- # * :size - Resize the image to fit these proportions. Size is given as a string with the format
81
- # '100x100'. Either dimension can be omitted, for example: '100x'
82
- # * :crop - Crop the image to the size given. (Boolean, default: <tt>false</tt>)
83
- # * :no_size_attr - Do not include width and height attributes in the image tag. (Boolean, default: false)
84
- # * :filterset - Apply the given filterset to the image
85
- #
86
- # ==== Examples
87
- #
88
- # dynamic_image_tag(@image) # Original image
89
- # dynamic_image_tag(@image, :size => "100x") # Will be 100px wide
90
- # dynamic_image_tag(@image, :size => "100x100") # Will fit within 100x100
91
- # dynamic_image_tag(@image, :size => "100x100", :crop => true) # Will be cropped to 100x100
92
- #
93
- def dynamic_image_tag(image, options = {})
94
- parsed_options = dynamic_image_options(image, options)
95
- image_tag(parsed_options[:url], parsed_options[:options] ).gsub(/\?[\d]+/,'').html_safe
132
+ def dynamic_image_url_with_size(record_or_array, size=nil, options={})
133
+ record = extract_record(record_or_array)
134
+ options = {
135
+ routing_type: :url,
136
+ action: nil,
137
+ format: default_format_for_image(record),
138
+ size: size
139
+ }.merge(options)
140
+ options[:digest] = dynamic_image_digest(record, options[:action], options[:size])
141
+ polymorphic_url(record_or_array, options)
96
142
  end
97
143
 
98
- # Returns an url corresponding to the provided image model.
99
- # Special options are documented in ApplicationHelper.dynamic_image_tag, only <tt>:size</tt>, <tt>:filterset</tt> and <tt>:crop</tt> apply.
100
- def dynamic_image_url(image, options = {})
101
- parsed_options = dynamic_image_options(image, options)
102
- parsed_options[:url]
144
+ def fit_size!(record_or_array, options)
145
+ record = extract_record(record_or_array)
146
+ action = options[:action].try(:to_s)
147
+ size_opts = options.extract!(:size, :crop, :upscale)
148
+
149
+ if size_opts[:size]
150
+ DynamicImage::ImageSizing.new(
151
+ record,
152
+ uncropped: (action == "uncropped")
153
+ ).fit(size_opts[:size], size_opts).floor.to_s
154
+ elsif action != "original"
155
+ record.size.floor.to_s
156
+ else
157
+ nil
158
+ end
103
159
  end
104
160
  end
105
161
  end
106
-
107
- ActionView::Base.send(:include, DynamicImage::Helper)