carrierwave 0.11.2 → 3.0.7
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 +5 -5
- data/README.md +452 -178
- data/lib/carrierwave/compatibility/paperclip.rb +4 -4
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +11 -5
- data/lib/carrierwave/mount.rb +217 -182
- data/lib/carrierwave/mounter.rb +255 -0
- data/lib/carrierwave/orm/activerecord.rb +29 -35
- data/lib/carrierwave/processing/mini_magick.rb +140 -84
- data/lib/carrierwave/processing/rmagick.rb +72 -21
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -1
- data/lib/carrierwave/sanitized_file.rb +83 -84
- data/lib/carrierwave/storage/abstract.rb +16 -3
- data/lib/carrierwave/storage/file.rb +71 -3
- data/lib/carrierwave/storage/fog.rb +215 -57
- data/lib/carrierwave/storage.rb +1 -9
- data/lib/carrierwave/test/matchers.rb +88 -19
- data/lib/carrierwave/uploader/cache.rb +75 -45
- data/lib/carrierwave/uploader/callbacks.rb +1 -3
- data/lib/carrierwave/uploader/configuration.rb +80 -16
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +4 -74
- data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
- data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
- data/lib/carrierwave/uploader/file_size.rb +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +48 -13
- data/lib/carrierwave/uploader/proxy.rb +20 -9
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +2 -4
- data/lib/carrierwave/uploader/store.rb +59 -28
- data/lib/carrierwave/uploader/url.rb +8 -7
- data/lib/carrierwave/uploader/versions.rb +171 -123
- data/lib/carrierwave/uploader.rb +12 -10
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -12
- data/lib/carrierwave/utilities.rb +1 -3
- data/lib/carrierwave/validations/active_model.rb +7 -11
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +39 -21
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +6 -10
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +135 -83
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/el.yml +0 -11
- data/lib/carrierwave/locale/es.yml +0 -11
- data/lib/carrierwave/locale/fr.yml +0 -11
- data/lib/carrierwave/locale/ja.yml +0 -11
- data/lib/carrierwave/locale/nb.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/pl.yml +0 -11
- data/lib/carrierwave/locale/pt-BR.yml +0 -11
- data/lib/carrierwave/locale/pt-PT.yml +0 -11
- data/lib/carrierwave/locale/ru.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/locale/tr.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -74
- data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
- data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
- data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
- data/lib/carrierwave/utilities/deprecation.rb +0 -18
| @@ -0,0 +1,255 @@ | |
| 1 | 
            +
            module CarrierWave
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              # this is an internal class, used by CarrierWave::Mount so that
         | 
| 4 | 
            +
              # we don't pollute the model with a lot of methods.
         | 
| 5 | 
            +
              class Mounter # :nodoc:
         | 
| 6 | 
            +
                class Single < Mounter # :nodoc
         | 
| 7 | 
            +
                  def identifier
         | 
| 8 | 
            +
                    uploaders.first&.identifier
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def temporary_identifier
         | 
| 12 | 
            +
                    temporary_identifiers.first
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                class Multiple < Mounter # :nodoc
         | 
| 17 | 
            +
                  def identifier
         | 
| 18 | 
            +
                    uploaders.map(&:identifier).presence
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def temporary_identifier
         | 
| 22 | 
            +
                    temporary_identifiers.presence
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def self.build(record, column)
         | 
| 27 | 
            +
                  if record.class.uploader_options[column][:multiple]
         | 
| 28 | 
            +
                    Multiple.new(record, column)
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    Single.new(record, column)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                attr_reader :column, :record, :remote_urls, :remove,
         | 
| 35 | 
            +
                            :integrity_errors, :processing_errors, :download_errors
         | 
| 36 | 
            +
                attr_accessor :remote_request_headers, :uploader_options
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def initialize(record, column)
         | 
| 39 | 
            +
                  @record = record
         | 
| 40 | 
            +
                  @column = column
         | 
| 41 | 
            +
                  @options = record.class.uploader_options[column]
         | 
| 42 | 
            +
                  @download_errors = []
         | 
| 43 | 
            +
                  @processing_errors = []
         | 
| 44 | 
            +
                  @integrity_errors = []
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  @removed_uploaders = []
         | 
| 47 | 
            +
                  @added_uploaders = []
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def uploader_class
         | 
| 51 | 
            +
                  record.class.uploaders[column]
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def blank_uploader
         | 
| 55 | 
            +
                  uploader_class.new(record, column)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def identifiers
         | 
| 59 | 
            +
                  uploaders.map(&:identifier)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def read_identifiers
         | 
| 63 | 
            +
                  [record.read_uploader(serialization_column)].flatten.reject(&:blank?)
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def uploaders
         | 
| 67 | 
            +
                  @uploaders ||= read_identifiers.map do |identifier|
         | 
| 68 | 
            +
                    uploader = blank_uploader
         | 
| 69 | 
            +
                    uploader.retrieve_from_store!(identifier)
         | 
| 70 | 
            +
                    uploader
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def cache(new_files)
         | 
| 75 | 
            +
                  return if !new_files.is_a?(Array) && new_files.blank?
         | 
| 76 | 
            +
                  old_uploaders = uploaders
         | 
| 77 | 
            +
                  @uploaders = new_files.map do |new_file|
         | 
| 78 | 
            +
                    handle_error do
         | 
| 79 | 
            +
                      if new_file.is_a?(String)
         | 
| 80 | 
            +
                        if (uploader = old_uploaders.detect { |old_uploader| old_uploader.identifier == new_file })
         | 
| 81 | 
            +
                          uploader.staged = true
         | 
| 82 | 
            +
                          uploader
         | 
| 83 | 
            +
                        else
         | 
| 84 | 
            +
                          begin
         | 
| 85 | 
            +
                            uploader = blank_uploader
         | 
| 86 | 
            +
                            uploader.retrieve_from_cache!(new_file)
         | 
| 87 | 
            +
                            uploader
         | 
| 88 | 
            +
                          rescue CarrierWave::InvalidParameter
         | 
| 89 | 
            +
                            nil
         | 
| 90 | 
            +
                          end
         | 
| 91 | 
            +
                        end
         | 
| 92 | 
            +
                      else
         | 
| 93 | 
            +
                        uploader = blank_uploader
         | 
| 94 | 
            +
                        uploader.cache!(new_file)
         | 
| 95 | 
            +
                        uploader
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
                  end.reject(&:blank?)
         | 
| 99 | 
            +
                  @removed_uploaders += (old_uploaders - @uploaders)
         | 
| 100 | 
            +
                  write_temporary_identifier
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def cache_names
         | 
| 104 | 
            +
                  uploaders.map(&:cache_name).compact
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def cache_names=(cache_names)
         | 
| 108 | 
            +
                  cache_names = cache_names.reject(&:blank?)
         | 
| 109 | 
            +
                  return if cache_names.blank?
         | 
| 110 | 
            +
                  clear_unstaged
         | 
| 111 | 
            +
                  cache_names.each do |cache_name|
         | 
| 112 | 
            +
                    uploader = blank_uploader
         | 
| 113 | 
            +
                    uploader.retrieve_from_cache!(cache_name)
         | 
| 114 | 
            +
                    @uploaders << uploader
         | 
| 115 | 
            +
                  rescue CarrierWave::InvalidParameter
         | 
| 116 | 
            +
                    # ignore
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                  write_temporary_identifier
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                def remote_urls=(urls)
         | 
| 122 | 
            +
                  if urls.nil?
         | 
| 123 | 
            +
                    urls = []
         | 
| 124 | 
            +
                  else
         | 
| 125 | 
            +
                    urls = Array.wrap(urls).reject(&:blank?)
         | 
| 126 | 
            +
                    return if urls.blank?
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                  @remote_urls = urls
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                  clear_unstaged
         | 
| 131 | 
            +
                  @remote_urls.zip(remote_request_headers || []) do |url, header|
         | 
| 132 | 
            +
                    handle_error do
         | 
| 133 | 
            +
                      uploader = blank_uploader
         | 
| 134 | 
            +
                      uploader.download!(url, header || {})
         | 
| 135 | 
            +
                      @uploaders << uploader
         | 
| 136 | 
            +
                    end
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
                  write_temporary_identifier
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                def store!
         | 
| 142 | 
            +
                  uploaders.each(&:store!)
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                def write_identifier
         | 
| 146 | 
            +
                  return if record.frozen?
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  clear! if remove?
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  additions, remains = uploaders.partition(&:cached?)
         | 
| 151 | 
            +
                  existing_identifiers = (@removed_uploaders + remains).map(&:identifier)
         | 
| 152 | 
            +
                  additions.each do |uploader|
         | 
| 153 | 
            +
                    uploader.deduplicate(existing_identifiers)
         | 
| 154 | 
            +
                    existing_identifiers << uploader.identifier
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                  @added_uploaders += additions
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  record.write_uploader(serialization_column, identifier)
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                def urls(*args)
         | 
| 162 | 
            +
                  uploaders.map { |u| u.url(*args) }
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                def blank?
         | 
| 166 | 
            +
                  uploaders.none?(&:present?)
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                def remove=(value)
         | 
| 170 | 
            +
                  @remove = value
         | 
| 171 | 
            +
                  write_temporary_identifier
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                def remove?
         | 
| 175 | 
            +
                  remove.present? && (remove.to_s !~ /\A0|false$\z/)
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                def remove!
         | 
| 179 | 
            +
                  uploaders.each(&:remove!)
         | 
| 180 | 
            +
                  clear!
         | 
| 181 | 
            +
                end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                def clear!
         | 
| 184 | 
            +
                  @removed_uploaders += uploaders
         | 
| 185 | 
            +
                  @remove = nil
         | 
| 186 | 
            +
                  @uploaders = []
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                def reset_changes!
         | 
| 190 | 
            +
                  @removed_uploaders = []
         | 
| 191 | 
            +
                  @added_uploaders = []
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def serialization_column
         | 
| 195 | 
            +
                  option(:mount_on) || column
         | 
| 196 | 
            +
                end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                def remove_previous
         | 
| 199 | 
            +
                  current_paths = uploaders.map(&:path)
         | 
| 200 | 
            +
                  @removed_uploaders
         | 
| 201 | 
            +
                    .reject {|uploader| current_paths.include?(uploader.path) }
         | 
| 202 | 
            +
                    .each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
         | 
| 203 | 
            +
                  reset_changes!
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                def remove_added
         | 
| 207 | 
            +
                  current_paths = (@removed_uploaders + uploaders.select(&:staged)).map(&:path)
         | 
| 208 | 
            +
                  @added_uploaders
         | 
| 209 | 
            +
                    .reject {|uploader| current_paths.include?(uploader.path) }
         | 
| 210 | 
            +
                    .each { |uploader| uploader.remove! }
         | 
| 211 | 
            +
                  reset_changes!
         | 
| 212 | 
            +
                end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
              private
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                def option(name)
         | 
| 217 | 
            +
                  self.uploader_options ||= {}
         | 
| 218 | 
            +
                  self.uploader_options[name] ||= record.class.uploader_option(column, name)
         | 
| 219 | 
            +
                end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                def clear_unstaged
         | 
| 222 | 
            +
                  @uploaders ||= []
         | 
| 223 | 
            +
                  staged, unstaged = @uploaders.partition(&:staged)
         | 
| 224 | 
            +
                  @uploaders = staged
         | 
| 225 | 
            +
                  @removed_uploaders += unstaged
         | 
| 226 | 
            +
                end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                def handle_error
         | 
| 229 | 
            +
                  yield
         | 
| 230 | 
            +
                rescue CarrierWave::DownloadError => e
         | 
| 231 | 
            +
                  @download_errors << e
         | 
| 232 | 
            +
                  raise e unless option(:ignore_download_errors)
         | 
| 233 | 
            +
                rescue CarrierWave::ProcessingError => e
         | 
| 234 | 
            +
                  @processing_errors << e
         | 
| 235 | 
            +
                  raise e unless option(:ignore_processing_errors)
         | 
| 236 | 
            +
                rescue CarrierWave::IntegrityError => e
         | 
| 237 | 
            +
                  @integrity_errors << e
         | 
| 238 | 
            +
                  raise e unless option(:ignore_integrity_errors)
         | 
| 239 | 
            +
                end
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                def write_temporary_identifier
         | 
| 242 | 
            +
                  return if record.frozen?
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                  record.write_uploader(serialization_column, temporary_identifier)
         | 
| 245 | 
            +
                end
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                def temporary_identifiers
         | 
| 248 | 
            +
                  if remove?
         | 
| 249 | 
            +
                    []
         | 
| 250 | 
            +
                  else
         | 
| 251 | 
            +
                    uploaders.map { |uploader| uploader.temporary_identifier }
         | 
| 252 | 
            +
                  end
         | 
| 253 | 
            +
                end
         | 
| 254 | 
            +
              end # Mounter
         | 
| 255 | 
            +
            end # CarrierWave
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            # encoding: utf-8
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            require 'active_record'
         | 
| 4 2 | 
             
            require 'carrierwave/validations/active_model'
         | 
| 5 3 |  | 
| @@ -8,10 +6,9 @@ module CarrierWave | |
| 8 6 |  | 
| 9 7 | 
             
                include CarrierWave::Mount
         | 
| 10 8 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
                 | 
| 14 | 
            -
                def mount_uploader(column, uploader=nil, options={}, &block)
         | 
| 9 | 
            +
              private
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def mount_base(column, uploader=nil, options={}, &block)
         | 
| 15 12 | 
             
                  super
         | 
| 16 13 |  | 
| 17 14 | 
             
                  alias_method :read_uploader, :read_attribute
         | 
| @@ -27,45 +24,42 @@ module CarrierWave | |
| 27 24 |  | 
| 28 25 | 
             
                  after_save :"store_#{column}!"
         | 
| 29 26 | 
             
                  before_save :"write_#{column}_identifier"
         | 
| 27 | 
            +
                  if ::ActiveRecord.try(:run_after_transaction_callbacks_in_order_defined)
         | 
| 28 | 
            +
                    after_commit :"remove_previously_stored_#{column}", :on => :update
         | 
| 29 | 
            +
                    after_commit :"reset_previous_changes_for_#{column}"
         | 
| 30 | 
            +
                    after_commit :"mark_remove_#{column}_false", :on => :update
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    after_commit :"mark_remove_#{column}_false", :on => :update
         | 
| 33 | 
            +
                    after_commit :"reset_previous_changes_for_#{column}"
         | 
| 34 | 
            +
                    after_commit :"remove_previously_stored_#{column}", :on => :update
         | 
| 35 | 
            +
                  end
         | 
| 30 36 | 
             
                  after_commit :"remove_#{column}!", :on => :destroy
         | 
| 31 | 
            -
                   | 
| 32 | 
            -
             | 
| 33 | 
            -
                   | 
| 34 | 
            -
             | 
| 35 | 
            -
                  class_eval <<-RUBY, __FILE__, __LINE__+1
         | 
| 36 | 
            -
                     | 
| 37 | 
            -
             | 
| 38 | 
            -
                       | 
| 37 | 
            +
                  after_rollback :"remove_rolled_back_#{column}"
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  mod = Module.new
         | 
| 40 | 
            +
                  prepend mod
         | 
| 41 | 
            +
                  mod.class_eval <<-RUBY, __FILE__, __LINE__+1
         | 
| 42 | 
            +
                    # Reset cached mounter on record reload
         | 
| 43 | 
            +
                    def reload(*)
         | 
| 44 | 
            +
                      @_mounters = nil
         | 
| 39 45 | 
             
                      super
         | 
| 40 46 | 
             
                    end
         | 
| 41 47 |  | 
| 42 | 
            -
                     | 
| 43 | 
            -
             | 
| 44 | 
            -
                       | 
| 48 | 
            +
                    # Reset cached mounter on record dup
         | 
| 49 | 
            +
                    def initialize_dup(other)
         | 
| 50 | 
            +
                      old_uploaders = _mounter(:"#{column}").uploaders
         | 
| 45 51 | 
             
                      super
         | 
| 52 | 
            +
                      @_mounters[:"#{column}"] = nil
         | 
| 53 | 
            +
                      # The attribute needs to be cleared to prevent it from picked up as identifier
         | 
| 54 | 
            +
                      write_attribute(_mounter(:#{column}).serialization_column, nil)
         | 
| 55 | 
            +
                      _mounter(:"#{column}").cache(old_uploaders)
         | 
| 46 56 | 
             
                    end
         | 
| 47 57 |  | 
| 48 | 
            -
                    def  | 
| 58 | 
            +
                    def write_#{column}_identifier
         | 
| 59 | 
            +
                      return unless has_attribute?(_mounter(:#{column}).serialization_column)
         | 
| 49 60 | 
             
                      super
         | 
| 50 | 
            -
                      _mounter(:#{column}).remove = true
         | 
| 51 | 
            -
                      _mounter(:#{column}).write_identifier
         | 
| 52 | 
            -
                    end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                    def serializable_hash(options=nil)
         | 
| 55 | 
            -
                      hash = {}
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                      except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
         | 
| 58 | 
            -
                      only   = options && options[:only]   && Array.wrap(options[:only]).map(&:to_s)
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                      self.class.uploaders.each do |column, uploader|
         | 
| 61 | 
            -
                        if (!only && !except) || (only && only.include?(column.to_s)) || (!only && except && !except.include?(column.to_s))
         | 
| 62 | 
            -
                          hash[column.to_s] = _mounter(column).uploader.serializable_hash
         | 
| 63 | 
            -
                        end
         | 
| 64 | 
            -
                      end
         | 
| 65 | 
            -
                      super(options).merge(hash)
         | 
| 66 61 | 
             
                    end
         | 
| 67 62 | 
             
                  RUBY
         | 
| 68 | 
            -
             | 
| 69 63 | 
             
                end
         | 
| 70 64 |  | 
| 71 65 | 
             
              end # ActiveRecord
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            # encoding: utf-8
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module CarrierWave
         | 
| 4 2 |  | 
| 5 3 | 
             
              ##
         | 
| @@ -23,9 +21,11 @@ module CarrierWave | |
| 23 21 | 
             
              #       process :resize_to_fit => [200, 200]
         | 
| 24 22 | 
             
              #     end
         | 
| 25 23 | 
             
              #
         | 
| 26 | 
            -
              # Or create your own helpers with the powerful  | 
| 27 | 
            -
              #  | 
| 28 | 
            -
              #  | 
| 24 | 
            +
              # Or create your own helpers with the powerful minimagick! method, which
         | 
| 25 | 
            +
              # yields an ImageProcessing::Builder object. Check out the ImageProcessing
         | 
| 26 | 
            +
              # docs at http://github.com/janko-m/image_processing and the list of all
         | 
| 27 | 
            +
              # available ImageMagick options at
         | 
| 28 | 
            +
              # http://www.imagemagick.org/script/command-line-options.php for more info.
         | 
| 29 29 | 
             
              #
         | 
| 30 30 | 
             
              #     class MyUploader < CarrierWave::Uploader::Base
         | 
| 31 31 | 
             
              #       include CarrierWave::MiniMagick
         | 
| @@ -33,35 +33,30 @@ module CarrierWave | |
| 33 33 | 
             
              #       process :radial_blur => 10
         | 
| 34 34 | 
             
              #
         | 
| 35 35 | 
             
              #       def radial_blur(amount)
         | 
| 36 | 
            -
              #          | 
| 37 | 
            -
              #            | 
| 38 | 
            -
              #            | 
| 39 | 
            -
              #            | 
| 36 | 
            +
              #         minimagick! do |builder|
         | 
| 37 | 
            +
              #           builder.radial_blur(amount)
         | 
| 38 | 
            +
              #           builder = yield(builder) if block_given?
         | 
| 39 | 
            +
              #           builder
         | 
| 40 40 | 
             
              #         end
         | 
| 41 41 | 
             
              #       end
         | 
| 42 | 
            +
              #     end
         | 
| 42 43 | 
             
              #
         | 
| 43 44 | 
             
              # === Note
         | 
| 44 45 | 
             
              #
         | 
| 45 | 
            -
              # MiniMagick  | 
| 46 | 
            -
              #  | 
| 46 | 
            +
              # The ImageProcessing gem uses MiniMagick, a mini replacement for RMagick
         | 
| 47 | 
            +
              # that uses ImageMagick command-line tools, to build a "convert" command that
         | 
| 48 | 
            +
              # performs the processing.
         | 
| 47 49 | 
             
              #
         | 
| 48 50 | 
             
              # You can find more information here:
         | 
| 49 51 | 
             
              #
         | 
| 50 | 
            -
              #  | 
| 51 | 
            -
              # and
         | 
| 52 | 
            -
              # https://github.com/minimagic/minimagick/
         | 
| 52 | 
            +
              # https://github.com/minimagick/minimagick/
         | 
| 53 53 | 
             
              #
         | 
| 54 54 | 
             
              #
         | 
| 55 55 | 
             
              module MiniMagick
         | 
| 56 56 | 
             
                extend ActiveSupport::Concern
         | 
| 57 57 |  | 
| 58 58 | 
             
                included do
         | 
| 59 | 
            -
                   | 
| 60 | 
            -
                    require "mini_magick"
         | 
| 61 | 
            -
                  rescue LoadError => e
         | 
| 62 | 
            -
                    e.message << " (You may need to install the mini_magick gem)"
         | 
| 63 | 
            -
                    raise e
         | 
| 64 | 
            -
                  end
         | 
| 59 | 
            +
                  require "image_processing/mini_magick"
         | 
| 65 60 | 
             
                end
         | 
| 66 61 |  | 
| 67 62 | 
             
                module ClassMethods
         | 
| @@ -81,7 +76,7 @@ module CarrierWave | |
| 81 76 | 
             
                    process :resize_to_fill => [width, height, gravity]
         | 
| 82 77 | 
             
                  end
         | 
| 83 78 |  | 
| 84 | 
            -
                  def resize_and_pad(width, height, background=:transparent, gravity | 
| 79 | 
            +
                  def resize_and_pad(width, height, background=:transparent, gravity='Center')
         | 
| 85 80 | 
             
                    process :resize_and_pad => [width, height, background, gravity]
         | 
| 86 81 | 
             
                  end
         | 
| 87 82 | 
             
                end
         | 
| @@ -93,7 +88,7 @@ module CarrierWave | |
| 93 88 | 
             
                #
         | 
| 94 89 | 
             
                # === Parameters
         | 
| 95 90 | 
             
                #
         | 
| 96 | 
            -
                # [format (#to_s)] an  | 
| 91 | 
            +
                # [format (#to_s)] an abbreviation of the format
         | 
| 97 92 | 
             
                #
         | 
| 98 93 | 
             
                # === Yields
         | 
| 99 94 | 
             
                #
         | 
| @@ -103,12 +98,11 @@ module CarrierWave | |
| 103 98 | 
             
                #
         | 
| 104 99 | 
             
                #     image.convert(:png)
         | 
| 105 100 | 
             
                #
         | 
| 106 | 
            -
                def convert(format)
         | 
| 107 | 
            -
                   | 
| 108 | 
            -
             | 
| 109 | 
            -
                     | 
| 110 | 
            -
                     | 
| 111 | 
            -
                    img
         | 
| 101 | 
            +
                def convert(format, page=nil, &block)
         | 
| 102 | 
            +
                  minimagick!(block) do |builder|
         | 
| 103 | 
            +
                    builder = builder.convert(format)
         | 
| 104 | 
            +
                    builder = builder.loader(page: page) if page
         | 
| 105 | 
            +
                    builder
         | 
| 112 106 | 
             
                  end
         | 
| 113 107 | 
             
                end
         | 
| 114 108 |  | 
| @@ -122,16 +116,18 @@ module CarrierWave | |
| 122 116 | 
             
                #
         | 
| 123 117 | 
             
                # [width (Integer)] the width to scale the image to
         | 
| 124 118 | 
             
                # [height (Integer)] the height to scale the image to
         | 
| 119 | 
            +
                # [combine_options (Hash)] additional ImageMagick options to apply before resizing
         | 
| 125 120 | 
             
                #
         | 
| 126 121 | 
             
                # === Yields
         | 
| 127 122 | 
             
                #
         | 
| 128 123 | 
             
                # [MiniMagick::Image] additional manipulations to perform
         | 
| 129 124 | 
             
                #
         | 
| 130 | 
            -
                def resize_to_limit(width, height)
         | 
| 131 | 
            -
                   | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
                     | 
| 125 | 
            +
                def resize_to_limit(width, height, combine_options: {}, &block)
         | 
| 126 | 
            +
                  width, height = resolve_dimensions(width, height)
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  minimagick!(block) do |builder|
         | 
| 129 | 
            +
                    builder.resize_to_limit(width, height)
         | 
| 130 | 
            +
                      .apply(combine_options)
         | 
| 135 131 | 
             
                  end
         | 
| 136 132 | 
             
                end
         | 
| 137 133 |  | 
| @@ -144,16 +140,18 @@ module CarrierWave | |
| 144 140 | 
             
                #
         | 
| 145 141 | 
             
                # [width (Integer)] the width to scale the image to
         | 
| 146 142 | 
             
                # [height (Integer)] the height to scale the image to
         | 
| 143 | 
            +
                # [combine_options (Hash)] additional ImageMagick options to apply before resizing
         | 
| 147 144 | 
             
                #
         | 
| 148 145 | 
             
                # === Yields
         | 
| 149 146 | 
             
                #
         | 
| 150 147 | 
             
                # [MiniMagick::Image] additional manipulations to perform
         | 
| 151 148 | 
             
                #
         | 
| 152 | 
            -
                def resize_to_fit(width, height)
         | 
| 153 | 
            -
                   | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
                     | 
| 149 | 
            +
                def resize_to_fit(width, height, combine_options: {}, &block)
         | 
| 150 | 
            +
                  width, height = resolve_dimensions(width, height)
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  minimagick!(block) do |builder|
         | 
| 153 | 
            +
                    builder.resize_to_fit(width, height)
         | 
| 154 | 
            +
                      .apply(combine_options)
         | 
| 157 155 | 
             
                  end
         | 
| 158 156 | 
             
                end
         | 
| 159 157 |  | 
| @@ -167,34 +165,18 @@ module CarrierWave | |
| 167 165 | 
             
                # [width (Integer)] the width to scale the image to
         | 
| 168 166 | 
             
                # [height (Integer)] the height to scale the image to
         | 
| 169 167 | 
             
                # [gravity (String)] the current gravity suggestion (default: 'Center'; options: 'NorthWest', 'North', 'NorthEast', 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast')
         | 
| 168 | 
            +
                # [combine_options (Hash)] additional ImageMagick options to apply before resizing
         | 
| 170 169 | 
             
                #
         | 
| 171 170 | 
             
                # === Yields
         | 
| 172 171 | 
             
                #
         | 
| 173 172 | 
             
                # [MiniMagick::Image] additional manipulations to perform
         | 
| 174 173 | 
             
                #
         | 
| 175 | 
            -
                def resize_to_fill(width, height, gravity = 'Center')
         | 
| 176 | 
            -
                   | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
                        scale_y = height/rows.to_f
         | 
| 182 | 
            -
                        if scale_x >= scale_y
         | 
| 183 | 
            -
                          cols = (scale_x * (cols + 0.5)).round
         | 
| 184 | 
            -
                          rows = (scale_x * (rows + 0.5)).round
         | 
| 185 | 
            -
                          cmd.resize "#{cols}"
         | 
| 186 | 
            -
                        else
         | 
| 187 | 
            -
                          cols = (scale_y * (cols + 0.5)).round
         | 
| 188 | 
            -
                          rows = (scale_y * (rows + 0.5)).round
         | 
| 189 | 
            -
                          cmd.resize "x#{rows}"
         | 
| 190 | 
            -
                        end
         | 
| 191 | 
            -
                      end
         | 
| 192 | 
            -
                      cmd.gravity gravity
         | 
| 193 | 
            -
                      cmd.background "rgba(255,255,255,0.0)"
         | 
| 194 | 
            -
                      cmd.extent "#{width}x#{height}" if cols != width || rows != height
         | 
| 195 | 
            -
                    end
         | 
| 196 | 
            -
                    img = yield(img) if block_given?
         | 
| 197 | 
            -
                    img
         | 
| 174 | 
            +
                def resize_to_fill(width, height, gravity = 'Center', combine_options: {}, &block)
         | 
| 175 | 
            +
                  width, height = resolve_dimensions(width, height)
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  minimagick!(block) do |builder|
         | 
| 178 | 
            +
                    builder.resize_to_fill(width, height, gravity: gravity)
         | 
| 179 | 
            +
                      .apply(combine_options)
         | 
| 198 180 | 
             
                  end
         | 
| 199 181 | 
             
                end
         | 
| 200 182 |  | 
| @@ -213,33 +195,51 @@ module CarrierWave | |
| 213 195 | 
             
                # [height (Integer)] the height to scale the image to
         | 
| 214 196 | 
             
                # [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
         | 
| 215 197 | 
             
                # [gravity (String)] how to position the image
         | 
| 198 | 
            +
                # [combine_options (Hash)] additional ImageMagick options to apply before resizing
         | 
| 216 199 | 
             
                #
         | 
| 217 200 | 
             
                # === Yields
         | 
| 218 201 | 
             
                #
         | 
| 219 202 | 
             
                # [MiniMagick::Image] additional manipulations to perform
         | 
| 220 203 | 
             
                #
         | 
| 221 | 
            -
                def resize_and_pad(width, height, background=:transparent, gravity='Center')
         | 
| 222 | 
            -
                   | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
                      else
         | 
| 228 | 
            -
                        cmd.background background
         | 
| 229 | 
            -
                      end
         | 
| 230 | 
            -
                      cmd.gravity gravity
         | 
| 231 | 
            -
                      cmd.extent "#{width}x#{height}"
         | 
| 232 | 
            -
                    end
         | 
| 233 | 
            -
                    img = yield(img) if block_given?
         | 
| 234 | 
            -
                    img
         | 
| 204 | 
            +
                def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {}, &block)
         | 
| 205 | 
            +
                  width, height = resolve_dimensions(width, height)
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  minimagick!(block) do |builder|
         | 
| 208 | 
            +
                    builder.resize_and_pad(width, height, background: background, gravity: gravity)
         | 
| 209 | 
            +
                      .apply(combine_options)
         | 
| 235 210 | 
             
                  end
         | 
| 236 211 | 
             
                end
         | 
| 237 212 |  | 
| 213 | 
            +
                ##
         | 
| 214 | 
            +
                # Returns the width of the image in pixels.
         | 
| 215 | 
            +
                #
         | 
| 216 | 
            +
                # === Returns
         | 
| 217 | 
            +
                #
         | 
| 218 | 
            +
                # [Integer] the image's width in pixels
         | 
| 219 | 
            +
                #
         | 
| 220 | 
            +
                def width
         | 
| 221 | 
            +
                  mini_magick_image[:width]
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                ##
         | 
| 225 | 
            +
                # Returns the height of the image in pixels.
         | 
| 226 | 
            +
                #
         | 
| 227 | 
            +
                # === Returns
         | 
| 228 | 
            +
                #
         | 
| 229 | 
            +
                # [Integer] the image's height in pixels
         | 
| 230 | 
            +
                #
         | 
| 231 | 
            +
                def height
         | 
| 232 | 
            +
                  mini_magick_image[:height]
         | 
| 233 | 
            +
                end
         | 
| 234 | 
            +
             | 
| 238 235 | 
             
                ##
         | 
| 239 236 | 
             
                # Manipulate the image with MiniMagick. This method will load up an image
         | 
| 240 237 | 
             
                # and then pass each of its frames to the supplied block. It will then
         | 
| 241 238 | 
             
                # save the image to disk.
         | 
| 242 239 | 
             
                #
         | 
| 240 | 
            +
                # NOTE: This method exists mostly for backwards compatibility, you should
         | 
| 241 | 
            +
                # probably use #minimagick!.
         | 
| 242 | 
            +
                #
         | 
| 243 243 | 
             
                # === Gotcha
         | 
| 244 244 | 
             
                #
         | 
| 245 245 | 
             
                # This method assumes that the object responds to +current_path+.
         | 
| @@ -259,19 +259,75 @@ module CarrierWave | |
| 259 259 | 
             
                  cache_stored_file! if !cached?
         | 
| 260 260 | 
             
                  image = ::MiniMagick::Image.open(current_path)
         | 
| 261 261 |  | 
| 262 | 
            -
                   | 
| 263 | 
            -
             | 
| 264 | 
            -
             | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 267 | 
            -
                   | 
| 268 | 
            -
             | 
| 262 | 
            +
                  image = yield(image)
         | 
| 263 | 
            +
                  FileUtils.mv image.path, current_path
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                  image.run_command("identify", current_path)
         | 
| 266 | 
            +
                rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
         | 
| 267 | 
            +
                  raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
         | 
| 268 | 
            +
                  message = I18n.translate(:"errors.messages.processing_error")
         | 
| 269 | 
            +
                  raise CarrierWave::ProcessingError, message
         | 
| 270 | 
            +
                ensure
         | 
| 271 | 
            +
                  image.destroy! if image
         | 
| 272 | 
            +
                end
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                # Process the image with MiniMagick, using the ImageProcessing gem. This
         | 
| 275 | 
            +
                # method will build a "convert" ImageMagick command and execute it on the
         | 
| 276 | 
            +
                # current image.
         | 
| 277 | 
            +
                #
         | 
| 278 | 
            +
                # === Gotcha
         | 
| 279 | 
            +
                #
         | 
| 280 | 
            +
                # This method assumes that the object responds to +current_path+.
         | 
| 281 | 
            +
                # Any class that this module is mixed into must have a +current_path+ method.
         | 
| 282 | 
            +
                # CarrierWave::Uploader does, so you won't need to worry about this in
         | 
| 283 | 
            +
                # most cases.
         | 
| 284 | 
            +
                #
         | 
| 285 | 
            +
                # === Yields
         | 
| 286 | 
            +
                #
         | 
| 287 | 
            +
                # [ImageProcessing::Builder] use it to define processing to be performed
         | 
| 288 | 
            +
                #
         | 
| 289 | 
            +
                # === Raises
         | 
| 290 | 
            +
                #
         | 
| 291 | 
            +
                # [CarrierWave::ProcessingError] if processing failed.
         | 
| 292 | 
            +
                def minimagick!(block = nil)
         | 
| 293 | 
            +
                  builder = ImageProcessing::MiniMagick.source(current_path)
         | 
| 294 | 
            +
                  builder = yield(builder)
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                  result = builder.call
         | 
| 297 | 
            +
                  result.close
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                  # backwards compatibility (we want to eventually move away from MiniMagick::Image)
         | 
| 300 | 
            +
                  if block
         | 
| 301 | 
            +
                    image  = ::MiniMagick::Image.new(result.path, result)
         | 
| 302 | 
            +
                    image  = block.call(image)
         | 
| 303 | 
            +
                    result = image.instance_variable_get(:@tempfile)
         | 
| 304 | 
            +
                  end
         | 
| 305 | 
            +
             | 
| 306 | 
            +
                  FileUtils.mv result.path, current_path
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                  if File.extname(result.path) != File.extname(current_path)
         | 
| 309 | 
            +
                    move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
         | 
| 310 | 
            +
                    file.content_type = Marcel::Magic.by_path(move_to).try(:type)
         | 
| 311 | 
            +
                    file.move_to(move_to, permissions, directory_permissions)
         | 
| 269 312 | 
             
                  end
         | 
| 270 313 | 
             
                rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
         | 
| 271 | 
            -
                   | 
| 272 | 
            -
                  message = I18n.translate(:"errors.messages. | 
| 314 | 
            +
                  raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
         | 
| 315 | 
            +
                  message = I18n.translate(:"errors.messages.processing_error")
         | 
| 273 316 | 
             
                  raise CarrierWave::ProcessingError, message
         | 
| 274 317 | 
             
                end
         | 
| 275 318 |  | 
| 319 | 
            +
              private
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                def resolve_dimensions(*dimensions)
         | 
| 322 | 
            +
                  dimensions.map do |value|
         | 
| 323 | 
            +
                    next value unless value.instance_of?(Proc)
         | 
| 324 | 
            +
                    value.arity >= 1 ? value.call(self) : value.call
         | 
| 325 | 
            +
                  end
         | 
| 326 | 
            +
                end
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                def mini_magick_image
         | 
| 329 | 
            +
                  ::MiniMagick::Image.read(read)
         | 
| 330 | 
            +
                end
         | 
| 331 | 
            +
             | 
| 276 332 | 
             
              end # MiniMagick
         | 
| 277 333 | 
             
            end # CarrierWave
         |