image_resizer 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.rspec +1 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +45 -0
  5. data/LICENSE +22 -0
  6. data/README.md +56 -0
  7. data/Rakefile +53 -0
  8. data/VERSION +1 -0
  9. data/image_resizer.gemspec +93 -0
  10. data/lib/image_resizer/analyzer.rb +51 -0
  11. data/lib/image_resizer/configurable.rb +206 -0
  12. data/lib/image_resizer/encoder.rb +55 -0
  13. data/lib/image_resizer/has_filename.rb +24 -0
  14. data/lib/image_resizer/loggable.rb +28 -0
  15. data/lib/image_resizer/processor.rb +220 -0
  16. data/lib/image_resizer/shell.rb +48 -0
  17. data/lib/image_resizer/temp_object.rb +216 -0
  18. data/lib/image_resizer/utils.rb +44 -0
  19. data/lib/image_resizer.rb +10 -0
  20. data/samples/DSC02119.JPG +0 -0
  21. data/samples/a.jp2 +0 -0
  22. data/samples/beach.jpg +0 -0
  23. data/samples/beach.png +0 -0
  24. data/samples/egg.png +0 -0
  25. data/samples/landscape.png +0 -0
  26. data/samples/round.gif +0 -0
  27. data/samples/sample.docx +0 -0
  28. data/samples/taj.jpg +0 -0
  29. data/samples/white pixel.png +0 -0
  30. data/spec/image_resizer/analyzer_spec.rb +78 -0
  31. data/spec/image_resizer/configurable_spec.rb +479 -0
  32. data/spec/image_resizer/encoder_spec.rb +41 -0
  33. data/spec/image_resizer/has_filename_spec.rb +88 -0
  34. data/spec/image_resizer/loggable_spec.rb +80 -0
  35. data/spec/image_resizer/processor_spec.rb +590 -0
  36. data/spec/image_resizer/shell_spec.rb +34 -0
  37. data/spec/image_resizer/temp_object_spec.rb +442 -0
  38. data/spec/spec_helper.rb +61 -0
  39. data/spec/support/argument_matchers.rb +19 -0
  40. data/spec/support/image_matchers.rb +58 -0
  41. data/spec/support/simple_matchers.rb +53 -0
  42. data/tmp/test_file +1 -0
  43. metadata +147 -0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@image_resizer
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ group :development, :test do
4
+ gem 'rspec'
5
+ gem 'jeweler'
6
+ gem 'pry'
7
+ gem 'pry-nav'
8
+ gem 'pry-stack_explorer'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ binding_of_caller (0.6.7)
5
+ coderay (1.0.6)
6
+ diff-lcs (1.1.3)
7
+ git (1.2.5)
8
+ jeweler (1.8.3)
9
+ bundler (~> 1.0)
10
+ git (>= 1.2.5)
11
+ rake
12
+ rdoc
13
+ json (1.6.6)
14
+ method_source (0.7.1)
15
+ pry (0.9.8.4)
16
+ coderay (~> 1.0.5)
17
+ method_source (~> 0.7.1)
18
+ slop (>= 2.4.4, < 3)
19
+ pry-nav (0.2.0)
20
+ pry (~> 0.9.8.1)
21
+ pry-stack_explorer (0.4.1)
22
+ binding_of_caller (~> 0.6.2)
23
+ pry (~> 0.9.8.2)
24
+ rake (0.9.2.2)
25
+ rdoc (3.12)
26
+ json (~> 1.4)
27
+ rspec (2.9.0)
28
+ rspec-core (~> 2.9.0)
29
+ rspec-expectations (~> 2.9.0)
30
+ rspec-mocks (~> 2.9.0)
31
+ rspec-core (2.9.0)
32
+ rspec-expectations (2.9.1)
33
+ diff-lcs (~> 1.1.3)
34
+ rspec-mocks (2.9.0)
35
+ slop (2.4.4)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ jeweler
42
+ pry
43
+ pry-nav
44
+ pry-stack_explorer
45
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2012 Daniel W. Nelson
3
+ Development sponsored by Centresource, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ ImageResizer
2
+ ============
3
+
4
+ Provides an interface to ImageMagick for extracting image information and resizing / cropping.
5
+
6
+
7
+ Usage
8
+ =====
9
+
10
+ In your Gemfile:
11
+
12
+ gem 'image_resizer'
13
+
14
+ Example:
15
+
16
+ image = ImageResizer::TempObject.new(File.new(path_to_image_file))
17
+ processor = ImageResizer::Processor.new
18
+
19
+ # resize to fit the specified width, maintaining the original ratio
20
+ resized_file = processor.resize(temp_object, :width => 320)
21
+
22
+ # resize to fit the specified height, maintaining the original ratio
23
+ resized_file = processor.resize(temp_object, :height => 240)
24
+
25
+ # resize to the specified dimensions, cropping around the center to avoid stretching
26
+ resized_file = processor.resize(temp_object, :width => 320, :height => 240)
27
+
28
+ # crop the original image to a frame and resize the result
29
+ upper_left = [0.25, 0.15] # 25% from the left, 15% from the top
30
+ lower_right = [0.75, 0.95] # 75% from the left, 95% from the top
31
+ width = 320
32
+ resized_file = processor.crop_to_frame_and_resize(temp_object,
33
+ :upper_left => upper_left,
34
+ :lower_right => lower_right,
35
+ :width => width
36
+ )
37
+
38
+ # crop the original image around a point and resize the result
39
+ point = [0.8, 0.3] # 80% from the left, 30% from the top
40
+ width = 320
41
+ height = 400
42
+ resized_file = processor.resize_and_crop_around_point(temp_object,
43
+ :point => point,
44
+ :width => width,
45
+ :height => height
46
+ )
47
+ File.open(output_file, 'wb') { |f| f.write(File.read(processed)) }
48
+
49
+
50
+ Credits
51
+ =======
52
+
53
+ This project is heavily indebted to [Dragonfly](https://github.com/markevans/dragonfly). We needed the ability to crop and resize images, but there didn't appear to be any gems devoted to just that. Paperclip and Dragonfly both perform scaling and cropping using ImageMagick, but both do so as part of a larger project. So we pulled the ImageMagick specific parts out of Dragonfly, added new specs and cropping options, and are releasing the result as a dedicated image resizing gem.
54
+
55
+
56
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "image_resizer"
18
+ gem.homepage = "http://github.com/populr/image_resizer"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Image resizing gem (requires ImageMagick)}
21
+ gem.description = %Q{Image resizing gem (requires ImageMagick)}
22
+ gem.email = "daniel@populr.me"
23
+ gem.authors = ["Daniel Nelson"]
24
+ # dependencies defined in Gemfile
25
+ gem.files.exclude 'spec'
26
+ gem.files.exclude 'samples'
27
+ gem.files.exclude 'tmp'
28
+ gem.files.exclude 'demo.rb'
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+ require 'rspec/core'
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |spec|
35
+ spec.pattern = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
39
+ spec.pattern = 'spec/**/*_spec.rb'
40
+ spec.rcov = true
41
+ end
42
+
43
+ task :default => :spec
44
+
45
+ require 'rdoc/task'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "image_resizer #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.4
@@ -0,0 +1,93 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "image_resizer"
8
+ s.version = "0.1.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Daniel Nelson"]
12
+ s.date = "2012-04-24"
13
+ s.description = "Image resizing gem (requires ImageMagick)"
14
+ s.email = "daniel@populr.me"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".rspec",
21
+ ".rvmrc",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "image_resizer.gemspec",
29
+ "lib/image_resizer.rb",
30
+ "lib/image_resizer/analyzer.rb",
31
+ "lib/image_resizer/configurable.rb",
32
+ "lib/image_resizer/encoder.rb",
33
+ "lib/image_resizer/has_filename.rb",
34
+ "lib/image_resizer/loggable.rb",
35
+ "lib/image_resizer/processor.rb",
36
+ "lib/image_resizer/shell.rb",
37
+ "lib/image_resizer/temp_object.rb",
38
+ "lib/image_resizer/utils.rb",
39
+ "samples/DSC02119.JPG",
40
+ "samples/a.jp2",
41
+ "samples/beach.jpg",
42
+ "samples/beach.png",
43
+ "samples/egg.png",
44
+ "samples/landscape.png",
45
+ "samples/round.gif",
46
+ "samples/sample.docx",
47
+ "samples/taj.jpg",
48
+ "samples/white pixel.png",
49
+ "spec/image_resizer/analyzer_spec.rb",
50
+ "spec/image_resizer/configurable_spec.rb",
51
+ "spec/image_resizer/encoder_spec.rb",
52
+ "spec/image_resizer/has_filename_spec.rb",
53
+ "spec/image_resizer/loggable_spec.rb",
54
+ "spec/image_resizer/processor_spec.rb",
55
+ "spec/image_resizer/shell_spec.rb",
56
+ "spec/image_resizer/temp_object_spec.rb",
57
+ "spec/spec_helper.rb",
58
+ "spec/support/argument_matchers.rb",
59
+ "spec/support/image_matchers.rb",
60
+ "spec/support/simple_matchers.rb",
61
+ "tmp/test_file"
62
+ ]
63
+ s.homepage = "http://github.com/populr/image_resizer"
64
+ s.licenses = ["MIT"]
65
+ s.require_paths = ["lib"]
66
+ s.rubygems_version = "1.8.10"
67
+ s.summary = "Image resizing gem (requires ImageMagick)"
68
+
69
+ if s.respond_to? :specification_version then
70
+ s.specification_version = 3
71
+
72
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
+ s.add_development_dependency(%q<rspec>, [">= 0"])
74
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
75
+ s.add_development_dependency(%q<pry>, [">= 0"])
76
+ s.add_development_dependency(%q<pry-nav>, [">= 0"])
77
+ s.add_development_dependency(%q<pry-stack_explorer>, [">= 0"])
78
+ else
79
+ s.add_dependency(%q<rspec>, [">= 0"])
80
+ s.add_dependency(%q<jeweler>, [">= 0"])
81
+ s.add_dependency(%q<pry>, [">= 0"])
82
+ s.add_dependency(%q<pry-nav>, [">= 0"])
83
+ s.add_dependency(%q<pry-stack_explorer>, [">= 0"])
84
+ end
85
+ else
86
+ s.add_dependency(%q<rspec>, [">= 0"])
87
+ s.add_dependency(%q<jeweler>, [">= 0"])
88
+ s.add_dependency(%q<pry>, [">= 0"])
89
+ s.add_dependency(%q<pry-nav>, [">= 0"])
90
+ s.add_dependency(%q<pry-stack_explorer>, [">= 0"])
91
+ end
92
+ end
93
+
@@ -0,0 +1,51 @@
1
+ module ImageResizer
2
+ class Analyzer
3
+
4
+ include Configurable
5
+ include Utils
6
+
7
+ def width(temp_object)
8
+ identify(temp_object)[:width]
9
+ end
10
+
11
+ def height(temp_object)
12
+ identify(temp_object)[:height]
13
+ end
14
+
15
+ def aspect_ratio(temp_object)
16
+ attrs = identify(temp_object)
17
+ attrs[:width].to_f / attrs[:height]
18
+ end
19
+
20
+ def portrait?(temp_object)
21
+ attrs = identify(temp_object)
22
+ attrs[:width] <= attrs[:height]
23
+ end
24
+ alias portrait portrait?
25
+
26
+ def landscape?(temp_object)
27
+ attrs = identify(temp_object)
28
+ attrs[:width] >= attrs[:height]
29
+ end
30
+ alias landscape landscape?
31
+
32
+ def depth(temp_object)
33
+ identify(temp_object)[:depth]
34
+ end
35
+
36
+ def number_of_colours(temp_object)
37
+ details = raw_identify(temp_object, '-verbose -unique')
38
+ details[/Colors: (\d+)/, 1].to_i
39
+ end
40
+ alias number_of_colors number_of_colours
41
+
42
+ def format(temp_object)
43
+ identify(temp_object)[:format]
44
+ end
45
+
46
+ def image?(temp_object)
47
+ !!catch(:unable_to_handle){ identify(temp_object) }
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,206 @@
1
+ module ImageResizer
2
+ module Configurable
3
+
4
+ # Exceptions
5
+ class NotConfigured < RuntimeError; end
6
+ class BadConfigAttribute < RuntimeError; end
7
+
8
+ def self.included(klass)
9
+ klass.class_eval do
10
+ include Configurable::InstanceMethods
11
+ extend Configurable::ClassMethods
12
+ end
13
+ end
14
+
15
+ class DeferredBlock # Inheriting from Proc causes errors in some versions of Ruby
16
+ def initialize(blk)
17
+ @blk = blk
18
+ end
19
+
20
+ def call
21
+ @blk.call
22
+ end
23
+ end
24
+
25
+ module InstanceMethods
26
+
27
+ def configure(&block)
28
+ yield ConfigurationProxy.new(self)
29
+ self
30
+ end
31
+
32
+ def configure_with(config, *args, &block)
33
+ config = saved_config_for(config) if config.is_a?(Symbol)
34
+ config.apply_configuration(self, *args)
35
+ configure(&block) if block
36
+ self
37
+ end
38
+
39
+ def has_config_method?(method_name)
40
+ config_methods.include?(method_name.to_sym)
41
+ end
42
+
43
+ def configuration
44
+ @configuration ||= {}
45
+ end
46
+
47
+ def config_methods
48
+ @config_methods ||= self.class.config_methods.dup
49
+ end
50
+
51
+ def default_configuration
52
+ @default_configuration ||= self.class.default_configuration.dup
53
+ end
54
+
55
+ def set_config_value(key, value)
56
+ configuration[key] = value
57
+ child_configurables.each{|c| c.set_if_unset(key, value) }
58
+ value
59
+ end
60
+
61
+ def use_as_fallback_config(other_configurable)
62
+ other_configurable.add_child_configurable(self)
63
+ self.fallback_configurable = other_configurable
64
+ end
65
+
66
+ protected
67
+
68
+ def add_child_configurable(obj)
69
+ child_configurables << obj
70
+ config_methods.push(*obj.config_methods)
71
+ fallback_configurable.config_methods.push(*obj.config_methods) if fallback_configurable
72
+ end
73
+
74
+ def set_if_unset(key, value)
75
+ set_config_value(key, value) unless set_locally?(key)
76
+ end
77
+
78
+ private
79
+
80
+ attr_accessor :fallback_configurable
81
+
82
+ def child_configurables
83
+ @child_configurables ||= []
84
+ end
85
+
86
+ def set_locally?(key)
87
+ instance_variable_defined?("@#{key}")
88
+ end
89
+
90
+ def default_value(key)
91
+ if default_configuration[key].is_a?(DeferredBlock)
92
+ default_configuration[key] = default_configuration[key].call
93
+ end
94
+ default_configuration[key]
95
+ end
96
+
97
+ def saved_configs
98
+ self.class.saved_configs
99
+ end
100
+
101
+ def saved_config_for(symbol)
102
+ config = saved_configs[symbol]
103
+ if config.nil?
104
+ raise ArgumentError, "#{symbol.inspect} is not a known configuration - try one of #{saved_configs.keys.join(', ')}"
105
+ end
106
+ config = config.call if config.respond_to?(:call)
107
+ config
108
+ end
109
+
110
+ end
111
+
112
+ module ClassMethods
113
+
114
+ def default_configuration
115
+ @default_configuration ||= configurable_ancestors.reverse.inject({}) do |default_config, klass|
116
+ default_config.merge!(klass.default_configuration)
117
+ default_config
118
+ end
119
+ end
120
+
121
+ def config_methods
122
+ @config_methods ||= configurable_ancestors.inject([]) do |conf_methods, klass|
123
+ conf_methods |= klass.config_methods
124
+ conf_methods
125
+ end
126
+ end
127
+
128
+ def nested_configurables
129
+ @nested_configurables ||= []
130
+ end
131
+
132
+ def register_configuration(name, config=nil, &config_in_block)
133
+ saved_configs[name] = config_in_block || config
134
+ end
135
+
136
+ def saved_configs
137
+ @saved_configs ||= {}
138
+ end
139
+
140
+ def configurable_ancestors
141
+ @configurable_ancestors ||= ancestors.select{|a| a.included_modules.include?(Configurable) } - [self]
142
+ end
143
+
144
+ private
145
+
146
+ def configurable_attr attribute, default=nil, &blk
147
+ default_configuration[attribute] = blk ? DeferredBlock.new(blk) : default
148
+
149
+ # Define the reader
150
+ define_method(attribute) do
151
+ configuration.has_key?(attribute) ? configuration[attribute] : default_value(attribute)
152
+ end
153
+
154
+ # Define the writer
155
+ define_method("#{attribute}=") do |value|
156
+ instance_variable_set("@#{attribute}", value)
157
+ set_config_value(attribute, value)
158
+ end
159
+
160
+ configuration_method attribute
161
+ configuration_method "#{attribute}="
162
+ end
163
+
164
+ def configuration_method(*method_names)
165
+ config_methods.push(*method_names.map{|n| n.to_sym }).uniq!
166
+ end
167
+
168
+ def nested_configurable(*method_names)
169
+ nested_configurables.push(*method_names)
170
+ end
171
+
172
+ end
173
+
174
+ class ConfigurationProxy
175
+
176
+ def initialize(owner)
177
+ @owner = owner
178
+ end
179
+
180
+ def method_missing(method_name, *args, &block)
181
+ if owner.has_config_method?(method_name)
182
+ attribute = method_name.to_s.tr('=','').to_sym
183
+ if method_name.to_s =~ /=$/ && owner.has_config_method?(attribute) # a bit hacky - if it has both getter and setter, assume it's a configurable_attr
184
+ owner.set_config_value(attribute, args.first)
185
+ else
186
+ owner.send(method_name, *args, &block)
187
+ end
188
+ elsif nested_configurable?(method_name)
189
+ owner.send(method_name)
190
+ else
191
+ raise BadConfigAttribute, "You tried to configure using '#{method_name.inspect}', but the valid config attributes are #{owner.config_methods.map{|a| %('#{a.inspect}') }.sort.join(', ')}"
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ attr_reader :owner
198
+
199
+ def nested_configurable?(method)
200
+ owner.class.nested_configurables.include?(method.to_sym)
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+ end
@@ -0,0 +1,55 @@
1
+ module ImageResizer
2
+ class Encoder
3
+
4
+ include Configurable
5
+ include Utils
6
+
7
+ configurable_attr :supported_formats, [
8
+ :ai,
9
+ :bmp,
10
+ :eps,
11
+ :gif,
12
+ :gif87,
13
+ :ico,
14
+ :j2c,
15
+ :jp2,
16
+ :jpeg,
17
+ :jpg,
18
+ :pbm,
19
+ :pcd,
20
+ :pct,
21
+ :pcx,
22
+ :pdf,
23
+ :pict,
24
+ :pjpeg,
25
+ :png,
26
+ :png24,
27
+ :png32,
28
+ :png8,
29
+ :pnm,
30
+ :ppm,
31
+ :ps,
32
+ :psd,
33
+ :ras,
34
+ :tga,
35
+ :tiff,
36
+ :wbmp,
37
+ :xbm,
38
+ :xpm,
39
+ :xwd
40
+ ]
41
+
42
+ def encode(temp_object, format, args='')
43
+ format = format.to_s.downcase
44
+ throw :unable_to_handle unless supported_formats.include?(format.to_sym)
45
+ details = identify(temp_object)
46
+
47
+ if details[:format] == format.to_sym && args.empty?
48
+ temp_object
49
+ else
50
+ convert(temp_object, args, format)
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ module ImageResizer
2
+ # Convenience methods for setting basename and extension
3
+ # Including class needs to define a 'name' accessor
4
+ # which is assumed to hold a filename-style string
5
+ module HasFilename
6
+
7
+ def basename
8
+ File.basename(name, '.*') if name
9
+ end
10
+
11
+ def basename=(basename)
12
+ self.name = [basename, ext].compact.join('.')
13
+ end
14
+
15
+ def ext
16
+ File.extname(name)[/\.(.*)/, 1] if name
17
+ end
18
+
19
+ def ext=(ext)
20
+ self.name = [(basename || 'file'), ext].join('.')
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require 'logger'
2
+
3
+ module ImageResizer
4
+ module Loggable
5
+
6
+ def log
7
+ case @log_object
8
+ when nil
9
+ @log_object = Logger.new($stdout)
10
+ when Proc
11
+ @log_object[]
12
+ when Logger
13
+ @log_object
14
+ end
15
+ end
16
+
17
+ def log=(object)
18
+ @log_object = object
19
+ end
20
+
21
+ attr_reader :log_object
22
+
23
+ def use_same_log_as(object)
24
+ self.log = proc{ object.log }
25
+ end
26
+
27
+ end
28
+ end