lib/dynamic_image/helper.rb in dynamic_image-1.0.4 vs lib/dynamic_image/helper.rb in dynamic_image-2.0.0.beta1

- old
+ new

@@ -1,107 +1,161 @@ -require 'dynamic_image' +# encoding: utf-8 module DynamicImage + # = DynamicImage Helper + # + # Provides helper methods for rendering and linking to images. module Helper + # Returns the path for a DynamicImage::Model record. + # Takes the same options as +dynamic_image_url+ + def dynamic_image_path(record_or_array, options={}) + dynamic_image_url(record_or_array, { routing_type: :path }.merge(options)) + end - # Returns an hash consisting of the URL to the dynamic image and parsed options. This is mostly for internal use by - # dynamic_image_tag and dynamic_image_url. - def dynamic_image_options(image, options = {}) - options.symbolize_keys! + # Returns an HTML image tag for the record. If no size is given, it will + # render at the original size. + # + # ==== Options + # * <tt>:alt</tt>: If no alt text is given, it will default to the + # filename of the uploaded image. + # + # See +dynamic_image_url+ for info on how to size and cropping. Options + # supported by +polymorphic_url+ will be passed to the router. Any other + # options will be added as HTML attributes. + # + # ==== Examples + # + # image = Image.find(params[:id]) + # dynamic_image_tag(image) + # # => <img alt="My file" height="200" src="..." width="320" /> + # dynamic_image_tag(image, size: "100x100", alt="Avatar") + # # => <img alt="Avatar" height="62" src="..." width="100" /> + def dynamic_image_tag(record_or_array, options={}) + record = extract_record(record_or_array) + options = { + alt: image_alt(record.filename) + }.merge(options) - options = {:crop => false}.merge(options) - url_options = {:controller => "/images", :action => :render_dynamic_image, :id => image} + size = fit_size!(record_or_array, options) + url_options = options.extract!(*allowed_dynamic_image_url_options) + html_options = { size: size }.merge(options) - if options[:original] - url_options[:original] = 'original' - options.delete(:original) - end + image_tag( + dynamic_image_path_with_size( + record_or_array, + size, + url_options + ), + html_options + ) + end - # Image sizing - if options[:size] - new_size = Vector2d.new(options[:size]) - image_size = Vector2d.new(image.size) + # Returns the URL for a DynamicImage::Model record. + # + # ==== Options + # + # * <tt>:size</tt> - Desired image size, supplied as "{width}x{height}". + # The image will be scaled to fit. A partial size like "100x" or "x100" + # can be given, if you want a fixed width or height. + # * <tt>:crop</tt> - If true, the image will be cropped to the given size. + # * <tt>:upscale</tt> - By default, DynamicImage only scale images down, + # never up. Pass <tt>upscale: true</tt> to force upscaling. + # + # Any options supported by +polymorphic_url+ are also accepted. + # + # ==== Examples + # + # image = Image.find(params[:id]) + # dynamic_image_url(image) + # # => "http://example.com/images/96...d1/300x187/1-2014062020...00.jpg" + # dynamic_image_url(image, size: '100x100') + # # => "http://example.com/images/72...c2/100x62/1-2014062020...00.jpg" + # dynamic_image_url(image, size: '100x100', crop: true) + # # => "http://example.com/images/a4...6b/100x100/1-2014062020...00.jpg" + def dynamic_image_url(record_or_array, options={}) + size = fit_size!(record_or_array, options) + dynamic_image_url_with_size(record_or_array, size, options) + end - unless options[:upscale] - new_size.x = image_size.x if new_size.x > 0 && new_size.x > image_size.x - new_size.y = image_size.y if new_size.y > 0 && new_size.y > image_size.y - end + # Returns a path to the original uploaded file, without any processing + # applied. Sizing options are not supported. + def original_dynamic_image_path(record_or_array, options={}) + dynamic_image_path(record_or_array, { action: :original }.merge(options)) + end - unless options[:crop] - new_size = image_size.constrain_both(new_size) - end + # Returns a URL to the original uploaded file, without any processing + # applied. Sizing options are not supported. + def original_dynamic_image_url(record_or_array, options={}) + dynamic_image_url(record_or_array, { action: :original }.merge(options)) + end - options[:size] = new_size.round.to_s - url_options[:size] = options[:size] - end - options.delete :crop + # Same as +dynamic_image_path+, but points to an image with any + # pre-cropping disabled. + def uncropped_dynamic_image_path(record_or_array, options={}) + dynamic_image_path(record_or_array, { action: :uncropped }.merge(options)) + end - if options[:no_size_attr] - options.delete :no_size_attr - options.delete :size - end + # Same as +dynamic_image_tag+, but renders an image with any + # pre-cropping disabled. + def uncropped_dynamic_image_tag(record_or_array, options={}) + dynamic_image_tag(record_or_array, { action: :uncropped }.merge(options)) + end - # Filterset - if options[:filterset] - url_options[:filterset] = options[:filterset] - options.delete :filterset - end + # Same as +dynamic_image_url+, but points to an image with any + # pre-cropping disabled. + def uncropped_dynamic_image_url(record_or_array, options={}) + dynamic_image_url(record_or_array, { action: :uncropped }.merge(options)) + end - # Filename - if options[:filename] - filename = options[:filename] - unless filename =~ /\.[\w]{1,4}$/ - filename += "." + image.filename.split(".").last - end - url_options[:filename] = filename - else - url_options[:filename] = image.filename - end + private - # Alt attribute - options[:alt] ||= image.name if image.name? - options[:alt] ||= image.filename.split('.').first.capitalize + def allowed_dynamic_image_url_options + [ + :format, :only_path, :protocol, :host, :subdomain, :domain, + :tld_length, :port, :anchor, :trailing_slash, :script_name, + :action, :routing_type + ] + end - if options.has_key?(:only_path) - url_options[:only_path] = options[:only_path] - options[:only_path] = nil - end - if options.has_key?(:host) - url_options[:host] = options[:host] - options[:host] = nil - end + def default_format_for_image(record) + Mime::Type.lookup(record.safe_content_type).to_sym + end - {:url => url_for(url_options), :options => options} + def dynamic_image_digest(record, action, size=nil) + key = [action || 'show', record.id, size].compact.join('-') + DynamicImage.digest_verifier.generate(key) end - # Returns an image tag for the provided image model, works similar to the rails <tt>image_tag</tt> helper. - # - # The following options are supported (the rest will be forwarded to <tt>image_tag</tt>): - # - # * :size - Resize the image to fit these proportions. Size is given as a string with the format - # '100x100'. Either dimension can be omitted, for example: '100x' - # * :crop - Crop the image to the size given. (Boolean, default: <tt>false</tt>) - # * :no_size_attr - Do not include width and height attributes in the image tag. (Boolean, default: false) - # * :filterset - Apply the given filterset to the image - # - # ==== Examples - # - # dynamic_image_tag(@image) # Original image - # dynamic_image_tag(@image, :size => "100x") # Will be 100px wide - # dynamic_image_tag(@image, :size => "100x100") # Will fit within 100x100 - # dynamic_image_tag(@image, :size => "100x100", :crop => true) # Will be cropped to 100x100 - # - def dynamic_image_tag(image, options = {}) - parsed_options = dynamic_image_options(image, options) - image_tag(parsed_options[:url], parsed_options[:options] ).gsub(/\?[\d]+/,'').html_safe + def dynamic_image_path_with_size(record_or_array, size=nil, options={}) + dynamic_image_url_with_size(record_or_array, size, { routing_type: :path }.merge(options)) end - # Returns an url corresponding to the provided image model. - # Special options are documented in ApplicationHelper.dynamic_image_tag, only <tt>:size</tt>, <tt>:filterset</tt> and <tt>:crop</tt> apply. - def dynamic_image_url(image, options = {}) - parsed_options = dynamic_image_options(image, options) - parsed_options[:url] + def dynamic_image_url_with_size(record_or_array, size=nil, options={}) + record = extract_record(record_or_array) + options = { + routing_type: :url, + action: nil, + format: default_format_for_image(record), + size: size + }.merge(options) + options[:digest] = dynamic_image_digest(record, options[:action], options[:size]) + polymorphic_url(record_or_array, options) end + + def fit_size!(record_or_array, options) + record = extract_record(record_or_array) + action = options[:action].try(:to_s) + size_opts = options.extract!(:size, :crop, :upscale) + + if size_opts[:size] + DynamicImage::ImageSizing.new( + record, + uncropped: (action == "uncropped") + ).fit(size_opts[:size], size_opts).floor.to_s + elsif action != "original" + record.size.floor.to_s + else + nil + end + end end end - -ActionView::Base.send(:include, DynamicImage::Helper)