image_resizer 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +22 -0
- data/README.md +56 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/image_resizer.gemspec +93 -0
- data/lib/image_resizer/analyzer.rb +51 -0
- data/lib/image_resizer/configurable.rb +206 -0
- data/lib/image_resizer/encoder.rb +55 -0
- data/lib/image_resizer/has_filename.rb +24 -0
- data/lib/image_resizer/loggable.rb +28 -0
- data/lib/image_resizer/processor.rb +220 -0
- data/lib/image_resizer/shell.rb +48 -0
- data/lib/image_resizer/temp_object.rb +216 -0
- data/lib/image_resizer/utils.rb +44 -0
- data/lib/image_resizer.rb +10 -0
- data/samples/DSC02119.JPG +0 -0
- data/samples/a.jp2 +0 -0
- data/samples/beach.jpg +0 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/landscape.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/samples/white pixel.png +0 -0
- data/spec/image_resizer/analyzer_spec.rb +78 -0
- data/spec/image_resizer/configurable_spec.rb +479 -0
- data/spec/image_resizer/encoder_spec.rb +41 -0
- data/spec/image_resizer/has_filename_spec.rb +88 -0
- data/spec/image_resizer/loggable_spec.rb +80 -0
- data/spec/image_resizer/processor_spec.rb +590 -0
- data/spec/image_resizer/shell_spec.rb +34 -0
- data/spec/image_resizer/temp_object_spec.rb +442 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/argument_matchers.rb +19 -0
- data/spec/support/image_matchers.rb +58 -0
- data/spec/support/simple_matchers.rb +53 -0
- data/tmp/test_file +1 -0
- 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
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
|