insano_image_resizer 0.3.0 → 0.3.1
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.
- data/README.md +1 -1
- data/VERSION +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +1 -10
- data/lib/image_resizer.rb +0 -5
- data/lib/image_resizer/configurable.rb +0 -206
- data/lib/image_resizer/loggable.rb +0 -28
- data/lib/image_resizer/processor.rb +0 -199
- data/lib/image_resizer/shell.rb +0 -48
- data/spec/image_resizer/configurable_spec.rb +0 -479
- data/spec/image_resizer/loggable_spec.rb +0 -80
- data/spec/image_resizer/processor_spec.rb +0 -144
- data/spec/image_resizer/shell_spec.rb +0 -34
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/spec/spec_helper.rb
CHANGED
@@ -5,7 +5,7 @@ Bundler.setup(:default, :test)
|
|
5
5
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
6
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
7
|
require 'rspec'
|
8
|
-
require '
|
8
|
+
require 'insano_image_resizer'
|
9
9
|
require 'fileutils'
|
10
10
|
require 'pry'
|
11
11
|
require 'pry-nav'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: insano_image_resizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -111,18 +111,9 @@ files:
|
|
111
111
|
- README.md
|
112
112
|
- Rakefile
|
113
113
|
- VERSION
|
114
|
-
- lib/image_resizer.rb
|
115
|
-
- lib/image_resizer/configurable.rb
|
116
|
-
- lib/image_resizer/loggable.rb
|
117
|
-
- lib/image_resizer/processor.rb
|
118
|
-
- lib/image_resizer/shell.rb
|
119
114
|
- samples/explanation.png
|
120
115
|
- samples/test.jpg
|
121
116
|
- samples/test.png
|
122
|
-
- spec/image_resizer/configurable_spec.rb
|
123
|
-
- spec/image_resizer/loggable_spec.rb
|
124
|
-
- spec/image_resizer/processor_spec.rb
|
125
|
-
- spec/image_resizer/shell_spec.rb
|
126
117
|
- spec/spec_helper.rb
|
127
118
|
homepage: http://github.com/populr/insano_image_resizer
|
128
119
|
licenses:
|
data/lib/image_resizer.rb
DELETED
@@ -1,206 +0,0 @@
|
|
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
|
@@ -1,28 +0,0 @@
|
|
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
|
@@ -1,199 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require 'shellwords'
|
3
|
-
|
4
|
-
module ImageResizer
|
5
|
-
class Processor
|
6
|
-
|
7
|
-
include Configurable
|
8
|
-
include Shell
|
9
|
-
include Loggable
|
10
|
-
|
11
|
-
def process(input_path, viewport_size = {}, interest_point = {})
|
12
|
-
input_properties = fetch_image_properties(input_path)
|
13
|
-
input_has_alpha = (input_properties["bands"] == 4)
|
14
|
-
|
15
|
-
output_tmp = Tempfile.new(["img", input_has_alpha ? ".png" : ".jpg"])
|
16
|
-
|
17
|
-
transform = calculate_transform(input_path, input_properties, viewport_size, interest_point)
|
18
|
-
run_transform(input_path, output_tmp.path, transform)
|
19
|
-
|
20
|
-
return output_tmp.path
|
21
|
-
end
|
22
|
-
|
23
|
-
def fetch_image_properties(input_path)
|
24
|
-
# read in the image headers to discover the width and height of the image.
|
25
|
-
# There's actually some extra metadata we ignore here, but this seems to be
|
26
|
-
# the only way to get width and height from VIPS.
|
27
|
-
result = run("vips im_printdesc '#{input_path}'")
|
28
|
-
|
29
|
-
# for some reason, the response isn't just YAML. It's one line of text in parenthesis
|
30
|
-
# followed by YAML. Let's chop off the first line to get to the good stuff.
|
31
|
-
result = result[(result.index(')') + 2)..-1]
|
32
|
-
return YAML::load(result)
|
33
|
-
end
|
34
|
-
|
35
|
-
def calculate_transform(input_path, input_properties, viewport_size, interest_point)
|
36
|
-
|
37
|
-
# Pull out the properties we're interested in
|
38
|
-
image_size = {w: input_properties["width"].to_f, h: input_properties["height"].to_f}
|
39
|
-
|
40
|
-
# By default, the interest size is 30% of the total image size.
|
41
|
-
# In the future, this could be a parameter, and you'd pass the # of pixels around
|
42
|
-
# the POI you are interested in.
|
43
|
-
if (interest_point[:xf])
|
44
|
-
interest_point[:x] = image_size[:w] * interest_point[:xf]
|
45
|
-
end
|
46
|
-
|
47
|
-
if (interest_point[:yf])
|
48
|
-
interest_point[:y] = image_size[:h] * interest_point[:yf]
|
49
|
-
end
|
50
|
-
|
51
|
-
if (interest_point[:region] == nil)
|
52
|
-
interest_point[:region] = 1
|
53
|
-
end
|
54
|
-
|
55
|
-
if (interest_point[:x] == nil)
|
56
|
-
interest_point[:x] = image_size[:w] * 0.5
|
57
|
-
interest_point[:region] = 1
|
58
|
-
end
|
59
|
-
if (interest_point[:y] == nil)
|
60
|
-
interest_point[:y] = image_size[:h] * 0.5
|
61
|
-
interest_point[:region] = 1
|
62
|
-
end
|
63
|
-
|
64
|
-
interest_size = {w: image_size[:w] * interest_point[:region], h: image_size[:h] * interest_point[:region]}
|
65
|
-
|
66
|
-
# Has the user specified both the width and the height of the viewport? If they haven't,
|
67
|
-
# let's go ahead and fill in the missing properties for them so that they get output at
|
68
|
-
# the original aspect ratio of the image.
|
69
|
-
if ((viewport_size[:w] == nil) && (viewport_size[:h] == nil))
|
70
|
-
viewport_size = {w: input_properties["width"], h: input_properties["height"]}
|
71
|
-
|
72
|
-
elsif (viewport_size[:w] == nil)
|
73
|
-
viewport_size[:w] = viewport_size[:h] * (input_properties["width"] / input_properties["height"])
|
74
|
-
|
75
|
-
elsif (viewport_size[:h] == nil)
|
76
|
-
viewport_size[:h] = viewport_size[:w] * (input_properties["height"] / input_properties["width"])
|
77
|
-
end
|
78
|
-
|
79
|
-
# how can we take our current image and fit it into the viewport? Time for
|
80
|
-
# some fun math! First, let's determine a scale such that the image fits
|
81
|
-
# within the viewport. There are a few rules we want to apply:
|
82
|
-
# 1) The image should _always_ fill the viewport.
|
83
|
-
# 2) The 1/3 of the image around the interest_point should always be visible.
|
84
|
-
# This means that if we try to cram a massive image into a tiny viewport,
|
85
|
-
# we won't get a simple scale-to-fill. We'll get a more zoomed-in version
|
86
|
-
# showing just the 1/3 around the interest_point.
|
87
|
-
|
88
|
-
scale_to_fill = [viewport_size[:w] / image_size[:w], viewport_size[:h] / image_size[:h]].max
|
89
|
-
|
90
|
-
scale_to_interest = [interest_size[:w] / image_size[:w], interest_size[:h] / image_size[:h]].max
|
91
|
-
|
92
|
-
log.debug("POI: ")
|
93
|
-
log.debug(interest_point)
|
94
|
-
log.debug("Image size: ")
|
95
|
-
log.debug(image_size)
|
96
|
-
log.debug("Requested viewport size: ")
|
97
|
-
log.debug(viewport_size)
|
98
|
-
log.debug("scale_to_fill: %f" % scale_to_fill)
|
99
|
-
log.debug("scale_to_interest: %f" % scale_to_interest)
|
100
|
-
|
101
|
-
|
102
|
-
scale_for_best_region = [scale_to_fill, scale_to_interest].max
|
103
|
-
|
104
|
-
# cool! Now, let's figure out what the content offset within the image should be.
|
105
|
-
# We want to keep the point of interest in view whenever possible. First, let's
|
106
|
-
# compute an optimal frame around the POI:
|
107
|
-
best_region = {x: interest_point[:x].to_f - (image_size[:w] * scale_for_best_region) / 2,
|
108
|
-
y: interest_point[:y].to_f - (image_size[:h] * scale_for_best_region) / 2,
|
109
|
-
w: image_size[:w] * scale_for_best_region,
|
110
|
-
h: image_size[:h] * scale_for_best_region}
|
111
|
-
|
112
|
-
# Up to this point, we've been using 'scale_for_best_region' to be the preferred scale of the image.
|
113
|
-
# So, scale could be 1/3 if we want to show the area around the POI, or 1 if we're fitting a whole image
|
114
|
-
# in a viewport that is exactly the same aspect ratio.
|
115
|
-
|
116
|
-
# The next step is to compute a scale that should be applied to the image to make this desired section of
|
117
|
-
# the image fit within the viewport. This is different from the previous scale—if we wanted to fit 1/3 of
|
118
|
-
# the image in a 100x100 pixel viewport, we computed best_region using that 1/3, and now we need to find
|
119
|
-
# the scale that will fit it into 100px.
|
120
|
-
scale = [scale_to_fill, viewport_size[:w] / best_region[:w], viewport_size[:h] / best_region[:h]].max
|
121
|
-
|
122
|
-
# Next, we scale the best_region so that it is in final coordinates. When we perform the affine transform,
|
123
|
-
# it will SCALE the entire image and then CROP it to a region, so our transform rect needs to be in the
|
124
|
-
# coordinate space of the SCALED image, not the initial image.
|
125
|
-
transform = {}
|
126
|
-
transform[:x] = best_region[:x] * scale
|
127
|
-
transform[:y] = best_region[:y] * scale
|
128
|
-
transform[:w] = best_region[:w] * scale
|
129
|
-
transform[:h] = best_region[:h] * scale
|
130
|
-
transform[:scale] = scale
|
131
|
-
|
132
|
-
# transform now represents the region we'd like to have in the final image. All of it, or part of it, may
|
133
|
-
# not actually be within the bounds of the image! We're about to apply some constraints, but first let's
|
134
|
-
# trim the best_region so that it's the SHAPE of the viewport, not just the SCALE of the viewport. Remember,
|
135
|
-
# since the region is still centered around the POI, we can just trim equally on either the W or H as necessary.
|
136
|
-
transform[:x] -= (viewport_size[:w] - transform[:w]) / 2
|
137
|
-
transform[:y] -= (viewport_size[:h] - transform[:h]) / 2
|
138
|
-
transform[:w] = viewport_size[:w]
|
139
|
-
transform[:h] = viewport_size[:h]
|
140
|
-
|
141
|
-
# alright—now our transform most likely extends beyond the bounds of the image
|
142
|
-
# data. Let's add some constraints that push it within the bounds of the image.
|
143
|
-
if (transform[:x] + transform[:w] > image_size[:w] * scale)
|
144
|
-
transform[:x] = image_size[:w] * scale - transform[:w]
|
145
|
-
end
|
146
|
-
|
147
|
-
if (transform[:y] + transform[:h] > image_size[:h] * scale)
|
148
|
-
transform[:y] = image_size[:h] * scale - transform[:h]
|
149
|
-
end
|
150
|
-
|
151
|
-
if (transform[:x] < 0)
|
152
|
-
transform[:x] = 0.0
|
153
|
-
end
|
154
|
-
|
155
|
-
if (transform[:y] < 0)
|
156
|
-
transform[:y] = 0.0
|
157
|
-
end
|
158
|
-
|
159
|
-
log.debug("The transform properties:")
|
160
|
-
log.debug(transform)
|
161
|
-
|
162
|
-
return transform
|
163
|
-
end
|
164
|
-
|
165
|
-
def run_transform(input_path, output_path, transform)
|
166
|
-
# Call through to VIPS:
|
167
|
-
# int im_affinei(in, out, interpolate, a, b, c, d, dx, dy, x, y, w, h)
|
168
|
-
# The first six params are a transformation matrix. A and D are used for X and Y
|
169
|
-
# scale, the other two are b = Y skew and c = X skew. TX and TY are translations
|
170
|
-
# but don't seem to be used.
|
171
|
-
# The last four params define a rect of the source image that is transformed.
|
172
|
-
log.debug(output_path[-3..-1])
|
173
|
-
|
174
|
-
if ((transform[:scale] < 0.5) && (output_path[-3..-1] == "jpg"))
|
175
|
-
scale = transform[:scale]
|
176
|
-
size = [transform[:w], transform[:h]].max
|
177
|
-
|
178
|
-
transform[:scale] = scale * 2
|
179
|
-
transform[:x] *= 2
|
180
|
-
transform[:y] *= 2
|
181
|
-
transform[:w] *= 2
|
182
|
-
transform[:h] *= 2
|
183
|
-
|
184
|
-
|
185
|
-
log.debug("Using two-pass transform")
|
186
|
-
run("vips im_affinei '#{input_path}' '#{output_path}' bilinear #{transform[:scale]} 0 0 #{transform[:scale]} 0 0 #{transform[:x]} #{transform[:y]} #{transform[:w]} #{transform[:h]}")
|
187
|
-
run("vipsthumbnail -s #{size} --nosharpen -o '%s_thumb.jpg:65' '#{output_path}'")
|
188
|
-
FileUtils.mv(output_path[0..-5]+"_thumb.jpg", output_path)
|
189
|
-
|
190
|
-
else
|
191
|
-
run("vips im_affinei '#{input_path}' '#{output_path}' bilinear #{transform[:scale]} 0 0 #{transform[:scale]} 0 0 #{transform[:x]} #{transform[:y]} #{transform[:w]} #{transform[:h]}")
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
return output_path
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
data/lib/image_resizer/shell.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'shellwords'
|
2
|
-
|
3
|
-
module ImageResizer
|
4
|
-
module Shell
|
5
|
-
|
6
|
-
include Configurable
|
7
|
-
configurable_attr :log_commands, true
|
8
|
-
|
9
|
-
# Exceptions
|
10
|
-
class CommandFailed < RuntimeError; end
|
11
|
-
|
12
|
-
def run(command, args="")
|
13
|
-
full_command = "#{command} #{escape_args(args)}"
|
14
|
-
log.debug("Running command: #{full_command}") if log_commands
|
15
|
-
begin
|
16
|
-
result = `#{full_command}`
|
17
|
-
rescue Errno::ENOENT
|
18
|
-
raise_shell_command_failed(full_command)
|
19
|
-
end
|
20
|
-
if $?.exitstatus == 1
|
21
|
-
throw :unable_to_handle
|
22
|
-
elsif !$?.success?
|
23
|
-
raise_shell_command_failed(full_command)
|
24
|
-
end
|
25
|
-
result
|
26
|
-
end
|
27
|
-
|
28
|
-
def raise_shell_command_failed(command)
|
29
|
-
raise CommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def escape_args(args)
|
33
|
-
args.shellsplit.map do |arg|
|
34
|
-
quote arg.gsub(/\\?'/, %q('\\\\''))
|
35
|
-
end.join(' ')
|
36
|
-
end
|
37
|
-
|
38
|
-
def quote(string)
|
39
|
-
q = running_on_windows? ? '"' : "'"
|
40
|
-
q + string + q
|
41
|
-
end
|
42
|
-
|
43
|
-
def running_on_windows?
|
44
|
-
ENV['OS'] && ENV['OS'].downcase == 'windows_nt'
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
@@ -1,479 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ImageResizer::Configurable do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
class Car
|
7
|
-
include ImageResizer::Configurable
|
8
|
-
configurable_attr :colour
|
9
|
-
configurable_attr :top_speed, 216
|
10
|
-
def self.other_thing=(thing); end
|
11
|
-
end
|
12
|
-
@car = Car.new
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "setup" do
|
16
|
-
it "should provide attr_readers for configurable attributes" do
|
17
|
-
@car.should respond_to(:colour)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should provide attr_writers for configurable attributes" do
|
21
|
-
@car.colour = 'verde'
|
22
|
-
@car.colour.should == 'verde'
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should set default values for configurable attributes" do
|
26
|
-
@car.top_speed.should == 216
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should set the default as nil if not specified" do
|
30
|
-
@car.colour.should be_nil
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should allow setting to nil" do
|
34
|
-
@car.top_speed = nil
|
35
|
-
@car.top_speed.should be_nil
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should allow specifying configurable attrs as strings" do
|
39
|
-
class Bike
|
40
|
-
include ImageResizer::Configurable
|
41
|
-
configurable_attr 'colour', 'rude'
|
42
|
-
end
|
43
|
-
Bike.new.colour.should == 'rude'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "configuring" do
|
48
|
-
it "should allow you to change values" do
|
49
|
-
@car.configure do |c|
|
50
|
-
c.colour = 'red'
|
51
|
-
end
|
52
|
-
@car.colour.should == 'red'
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should not allow you to call other methods on the object via the configuration" do
|
56
|
-
lambda{
|
57
|
-
@car.configure do |c|
|
58
|
-
c.other_thing = 5
|
59
|
-
end
|
60
|
-
}.should raise_error(ImageResizer::Configurable::BadConfigAttribute)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should return itself" do
|
64
|
-
@car.configure{|c|}.should == @car
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe "getting configuration" do
|
69
|
-
it "should return the configuration when nothing is set" do
|
70
|
-
@car.configuration.should == {}
|
71
|
-
end
|
72
|
-
it "should return the configuration when something is set" do
|
73
|
-
@car.top_speed = 10
|
74
|
-
@car.configuration.should == {:top_speed => 10}
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "multiple objects" do
|
79
|
-
it "should return the default configuration" do
|
80
|
-
Car.default_configuration.should == {:colour => nil, :top_speed => 216}
|
81
|
-
end
|
82
|
-
it "should allow instances to be configured differently" do
|
83
|
-
car1 = Car.new
|
84
|
-
car1.configure{|c| c.colour = 'green'}
|
85
|
-
car2 = Car.new
|
86
|
-
car2.configure{|c| c.colour = 'yellow'}
|
87
|
-
car1.configuration.should == {:colour => 'green'}
|
88
|
-
car2.configuration.should == {:colour => 'yellow'}
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "lazy attributes" do
|
93
|
-
before(:each) do
|
94
|
-
cow = @cow = mock('cow')
|
95
|
-
class Lazy; end
|
96
|
-
Lazy.class_eval do
|
97
|
-
include ImageResizer::Configurable
|
98
|
-
configurable_attr(:sound){ cow.moo }
|
99
|
-
end
|
100
|
-
@lazy = Lazy.new
|
101
|
-
end
|
102
|
-
it "should not call the block if the configurable attribute is set to something else" do
|
103
|
-
@cow.should_not_receive(:moo)
|
104
|
-
@lazy.configure{|c| c.sound = 'baa' }
|
105
|
-
@lazy.sound.should == 'baa'
|
106
|
-
end
|
107
|
-
it "should call the block if it's not been changed, once it's accessed" do
|
108
|
-
@cow.should_receive(:moo).and_return('mooo!')
|
109
|
-
@lazy.sound.should == 'mooo!'
|
110
|
-
end
|
111
|
-
it "should not call the block when accessed again" do
|
112
|
-
@cow.should_receive(:moo).exactly(:once).and_return('mooo!')
|
113
|
-
@lazy.sound.should == 'mooo!'
|
114
|
-
@lazy.sound.should == 'mooo!'
|
115
|
-
end
|
116
|
-
it "should not call an explicitly passed in proc" do
|
117
|
-
@lazy.configure{|c| c.sound = lambda{ @cow.fart }}
|
118
|
-
@lazy.sound.should be_a(Proc)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "configuration method" do
|
123
|
-
|
124
|
-
before(:each) do
|
125
|
-
class ClassWithMethod
|
126
|
-
include ImageResizer::Configurable
|
127
|
-
def add_thing(thing)
|
128
|
-
'poo'
|
129
|
-
end
|
130
|
-
def remove_thing(thing)
|
131
|
-
'bum'
|
132
|
-
end
|
133
|
-
configuration_method :add_thing, :remove_thing
|
134
|
-
end
|
135
|
-
@thing = ClassWithMethod.new
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should allow calling the method through 'configure'" do
|
139
|
-
@thing.configure do |c|
|
140
|
-
c.add_thing('duck')
|
141
|
-
c.remove_thing('dog')
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
describe "nested configurable objects" do
|
148
|
-
|
149
|
-
before(:each) do
|
150
|
-
class NestedThing
|
151
|
-
include ImageResizer::Configurable
|
152
|
-
configurable_attr :age, 29
|
153
|
-
def some_method(val)
|
154
|
-
@some_thing = val
|
155
|
-
end
|
156
|
-
configuration_method :some_method
|
157
|
-
attr_reader :some_thing
|
158
|
-
end
|
159
|
-
|
160
|
-
class Car
|
161
|
-
def nested_thing
|
162
|
-
@nested_thing ||= NestedThing.new
|
163
|
-
end
|
164
|
-
nested_configurable :nested_thing
|
165
|
-
end
|
166
|
-
|
167
|
-
@car.configure do |c|
|
168
|
-
c.nested_thing.configure do |nt|
|
169
|
-
nt.age = 50
|
170
|
-
nt.some_method('yo')
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
it "should allow configuring nested configurable accessors" do
|
176
|
-
@car.nested_thing.age.should == 50
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should allow configuring nested configurable normal methods" do
|
180
|
-
@car.nested_thing.some_thing.should == 'yo'
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should not allow configuring directly on the config object" do
|
184
|
-
expect{
|
185
|
-
@car.configure do |c|
|
186
|
-
c.some_method('other')
|
187
|
-
end
|
188
|
-
}.to raise_error(ImageResizer::Configurable::BadConfigAttribute)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
describe "configuring with a saved config" do
|
193
|
-
before(:each) do
|
194
|
-
@cool_configuration = Object.new
|
195
|
-
def @cool_configuration.apply_configuration(car, colour=nil)
|
196
|
-
car.configure do |c|
|
197
|
-
c.colour = (colour || 'vermelho')
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
it "should allow configuration by a saved config" do
|
203
|
-
@car.configure_with(@cool_configuration)
|
204
|
-
@car.colour.should == 'vermelho'
|
205
|
-
@car.top_speed.should == 216
|
206
|
-
end
|
207
|
-
|
208
|
-
it "should pass any args through to the saved config" do
|
209
|
-
@car.configure_with(@cool_configuration, 'preto')
|
210
|
-
@car.colour.should == 'preto'
|
211
|
-
end
|
212
|
-
|
213
|
-
it "should yield a block for any extra configuration" do
|
214
|
-
@car.configure_with(@cool_configuration) do |c|
|
215
|
-
c.colour = 'branco'
|
216
|
-
end
|
217
|
-
@car.colour.should == 'branco'
|
218
|
-
end
|
219
|
-
|
220
|
-
it "should return itself" do
|
221
|
-
@car.configure_with(@cool_configuration).should == @car
|
222
|
-
end
|
223
|
-
|
224
|
-
describe "using a symbol to specify the config" do
|
225
|
-
|
226
|
-
before(:all) do
|
227
|
-
@rally_config = Object.new
|
228
|
-
Car.register_configuration(:rally, @rally_config)
|
229
|
-
@long_journey_config = Object.new
|
230
|
-
Car.register_configuration(:long_journey){ @long_journey_config }
|
231
|
-
Car.register_configuration(:some_library){ SomeLibrary }
|
232
|
-
end
|
233
|
-
|
234
|
-
it "should map the symbol to the correct configuration" do
|
235
|
-
@rally_config.should_receive(:apply_configuration).with(@car)
|
236
|
-
@car.configure_with(:rally)
|
237
|
-
end
|
238
|
-
|
239
|
-
it "should map the symbol to the correct configuration lazily" do
|
240
|
-
@long_journey_config.should_receive(:apply_configuration).with(@car)
|
241
|
-
@car.configure_with(:long_journey)
|
242
|
-
end
|
243
|
-
|
244
|
-
it "should throw an error if an unknown symbol is passed in" do
|
245
|
-
lambda {
|
246
|
-
@car.configure_with(:eggs)
|
247
|
-
}.should raise_error(ArgumentError)
|
248
|
-
end
|
249
|
-
|
250
|
-
it "should only try to load the library when asked to" do
|
251
|
-
lambda{
|
252
|
-
@car.configure_with(:some_library)
|
253
|
-
}.should raise_error(NameError, /uninitialized constant.*SomeLibrary/)
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
end
|
258
|
-
|
259
|
-
describe "falling back to another config" do
|
260
|
-
before(:each) do
|
261
|
-
class Garage
|
262
|
-
include ImageResizer::Configurable
|
263
|
-
configurable_attr :top_speed, 100
|
264
|
-
end
|
265
|
-
@garage = Garage.new
|
266
|
-
@car.use_as_fallback_config(@garage)
|
267
|
-
end
|
268
|
-
|
269
|
-
describe "when nothing set" do
|
270
|
-
it "should use its default" do
|
271
|
-
@car.top_speed.should == 216
|
272
|
-
end
|
273
|
-
it "shouldn't affect the fallback config object" do
|
274
|
-
@garage.top_speed.should == 100
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
describe "if set" do
|
279
|
-
before(:each) do
|
280
|
-
@car.top_speed = 444
|
281
|
-
end
|
282
|
-
it "should work normally" do
|
283
|
-
@car.top_speed.should == 444
|
284
|
-
end
|
285
|
-
it "shouldn't affect the fallback config object" do
|
286
|
-
@garage.top_speed.should == 100
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
describe "both set" do
|
291
|
-
before(:each) do
|
292
|
-
@car.top_speed = 444
|
293
|
-
@garage.top_speed = 3000
|
294
|
-
end
|
295
|
-
it "should prefer its own setting" do
|
296
|
-
@car.top_speed.should == 444
|
297
|
-
end
|
298
|
-
it "shouldn't affect the fallback config object" do
|
299
|
-
@garage.top_speed.should == 3000
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
describe "the fallback config is set" do
|
304
|
-
before(:each) do
|
305
|
-
@garage.top_speed = 3000
|
306
|
-
end
|
307
|
-
it "should use the fallback config" do
|
308
|
-
@car.top_speed.should == 3000
|
309
|
-
end
|
310
|
-
it "shouldn't affect the fallback config object" do
|
311
|
-
@garage.top_speed.should == 3000
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
describe "falling back multiple levels" do
|
316
|
-
before(:each) do
|
317
|
-
@klass = Class.new
|
318
|
-
@klass.class_eval do
|
319
|
-
include ImageResizer::Configurable
|
320
|
-
configurable_attr :veg, 'carrot'
|
321
|
-
end
|
322
|
-
@a = @klass.new
|
323
|
-
@b = @klass.new
|
324
|
-
@b.use_as_fallback_config(@a)
|
325
|
-
@c = @klass.new
|
326
|
-
@c.use_as_fallback_config(@b)
|
327
|
-
end
|
328
|
-
|
329
|
-
it "should be the default if nothing set" do
|
330
|
-
@c.veg.should == 'carrot'
|
331
|
-
end
|
332
|
-
|
333
|
-
it "should fall all the way back to the top one if necessary" do
|
334
|
-
@a.veg = 'turnip'
|
335
|
-
@c.veg.should == 'turnip'
|
336
|
-
end
|
337
|
-
|
338
|
-
it "should prefer the closer one over the further away one" do
|
339
|
-
@b.veg = 'tatty'
|
340
|
-
@a.veg = 'turnip'
|
341
|
-
@c.veg.should == 'tatty'
|
342
|
-
end
|
343
|
-
|
344
|
-
it "should work properly with nils" do
|
345
|
-
@a.veg = nil
|
346
|
-
@c.veg = 'broc'
|
347
|
-
@a.veg.should be_nil
|
348
|
-
@b.veg.should be_nil
|
349
|
-
@c.veg.should == 'broc'
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
describe "objects with different methods" do
|
354
|
-
before(:each) do
|
355
|
-
class Dad
|
356
|
-
include ImageResizer::Configurable
|
357
|
-
end
|
358
|
-
@dad = Dad.new
|
359
|
-
class Kid
|
360
|
-
include ImageResizer::Configurable
|
361
|
-
configurable_attr :lug, 'default-lug'
|
362
|
-
end
|
363
|
-
@kid = Kid.new
|
364
|
-
@kid.use_as_fallback_config(@dad)
|
365
|
-
end
|
366
|
-
|
367
|
-
it "should not allow setting on the fallback obj directly" do
|
368
|
-
lambda{
|
369
|
-
@dad.lug = 'leg'
|
370
|
-
}.should raise_error(NoMethodError)
|
371
|
-
end
|
372
|
-
|
373
|
-
it "should not have the fallback obj respond to the method" do
|
374
|
-
@dad.should_not respond_to(:lug=)
|
375
|
-
end
|
376
|
-
|
377
|
-
it "should allow configuring through the fallback object even if it doesn't have that method" do
|
378
|
-
@dad.configure do |c|
|
379
|
-
c.lug = 'leg'
|
380
|
-
end
|
381
|
-
@kid.lug.should == 'leg'
|
382
|
-
end
|
383
|
-
|
384
|
-
it "should work when a grandchild config is added later" do
|
385
|
-
class Grandkid
|
386
|
-
include ImageResizer::Configurable
|
387
|
-
configurable_attr :oogie, 'boogie'
|
388
|
-
end
|
389
|
-
grandkid = Grandkid.new
|
390
|
-
grandkid.use_as_fallback_config(@kid)
|
391
|
-
@dad.configure{|c| c.oogie = 'duggen' }
|
392
|
-
grandkid.oogie.should == 'duggen'
|
393
|
-
end
|
394
|
-
|
395
|
-
it "should allow configuring twice through the fallback object" do
|
396
|
-
@dad.configure{|c| c.lug = 'leg' }
|
397
|
-
@dad.configure{|c| c.lug = 'blug' }
|
398
|
-
@kid.lug.should == 'blug'
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
describe "clashing with configurable modules" do
|
403
|
-
before(:each) do
|
404
|
-
@mod = mod = Module.new
|
405
|
-
@mod.module_eval do
|
406
|
-
include ImageResizer::Configurable
|
407
|
-
configurable_attr :team, 'spurs'
|
408
|
-
end
|
409
|
-
@class = Class.new
|
410
|
-
@class.class_eval do
|
411
|
-
include mod
|
412
|
-
include ImageResizer::Configurable
|
413
|
-
configurable_attr :tree, 'elm'
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
it "should not override the defaults from the module" do
|
418
|
-
obj = @class.new
|
419
|
-
obj.team.should == 'spurs'
|
420
|
-
end
|
421
|
-
|
422
|
-
it "should still use its own defaults" do
|
423
|
-
obj = @class.new
|
424
|
-
obj.tree.should == 'elm'
|
425
|
-
end
|
426
|
-
|
427
|
-
describe "when the configurable_attr is specified in a subclass that doesn't include Configurable" do
|
428
|
-
before(:each) do
|
429
|
-
@subclass = Class.new(@class)
|
430
|
-
@subclass.class_eval do
|
431
|
-
configurable_attr :car, 'mazda'
|
432
|
-
configurable_attr :tree, 'oak'
|
433
|
-
end
|
434
|
-
@obj = @subclass.new
|
435
|
-
end
|
436
|
-
|
437
|
-
it "should still work with default values" do
|
438
|
-
@obj.car.should == 'mazda'
|
439
|
-
end
|
440
|
-
|
441
|
-
it "should override the default from the parent" do
|
442
|
-
@obj.tree.should == 'oak'
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
end
|
447
|
-
|
448
|
-
end
|
449
|
-
|
450
|
-
describe "inheriting configurable_attrs from multiple places" do
|
451
|
-
before(:each) do
|
452
|
-
module A
|
453
|
-
include ImageResizer::Configurable
|
454
|
-
configurable_attr :a
|
455
|
-
end
|
456
|
-
module B
|
457
|
-
include ImageResizer::Configurable
|
458
|
-
configurable_attr :b
|
459
|
-
end
|
460
|
-
class K
|
461
|
-
include ImageResizer::Configurable
|
462
|
-
include A
|
463
|
-
include B
|
464
|
-
configurable_attr :c
|
465
|
-
end
|
466
|
-
class L < K
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
it "should include configuration from all of its mixins" do
|
471
|
-
l = L.new
|
472
|
-
l.configure do |c|
|
473
|
-
c.a = 'something'
|
474
|
-
c.b = 'something'
|
475
|
-
c.c = 'something'
|
476
|
-
end
|
477
|
-
end
|
478
|
-
end
|
479
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class Testoast
|
4
|
-
include ImageResizer::Loggable
|
5
|
-
end
|
6
|
-
|
7
|
-
describe ImageResizer::Loggable do
|
8
|
-
|
9
|
-
before(:each) do
|
10
|
-
@object = Testoast.new
|
11
|
-
end
|
12
|
-
|
13
|
-
shared_examples_for "common" do
|
14
|
-
it "should return a log" do
|
15
|
-
@object.log.should be_a(Logger)
|
16
|
-
end
|
17
|
-
it "should cache the log" do
|
18
|
-
@object.log.should == @object.log
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe "without being set" do
|
23
|
-
it "should return the log object as nil" do
|
24
|
-
@object.log_object.should be_nil
|
25
|
-
end
|
26
|
-
it_should_behave_like 'common'
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "when set" do
|
30
|
-
before(:each) do
|
31
|
-
@log = Logger.new($stdout)
|
32
|
-
@object.log = @log
|
33
|
-
end
|
34
|
-
it "should return the new log" do
|
35
|
-
@object.log.should == @log
|
36
|
-
end
|
37
|
-
it "should return the log object" do
|
38
|
-
@object.log_object.should == @log
|
39
|
-
end
|
40
|
-
it_should_behave_like 'common'
|
41
|
-
end
|
42
|
-
|
43
|
-
describe "when set as a proc" do
|
44
|
-
before(:each) do
|
45
|
-
@log = Logger.new($stdout)
|
46
|
-
@object.log = proc{ @log }
|
47
|
-
end
|
48
|
-
it "should return the new log" do
|
49
|
-
@object.log.should == @log
|
50
|
-
end
|
51
|
-
it "should return the log object" do
|
52
|
-
@object.log_object.should be_a(Proc)
|
53
|
-
end
|
54
|
-
it "should allow for changing logs" do
|
55
|
-
logs = [@log]
|
56
|
-
@object.log = proc{ logs[0] }
|
57
|
-
@object.log.should == @log
|
58
|
-
|
59
|
-
new_log = Logger.new($stdout)
|
60
|
-
logs[0] = new_log
|
61
|
-
|
62
|
-
@object.log.should == new_log
|
63
|
-
end
|
64
|
-
it_should_behave_like 'common'
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "sharing logs" do
|
68
|
-
before(:each) do
|
69
|
-
@log = Logger.new($stdout)
|
70
|
-
@obj1 = Testoast.new
|
71
|
-
@obj2 = Testoast.new
|
72
|
-
end
|
73
|
-
it "should enable sharing logs" do
|
74
|
-
@obj1.log = proc{ @log }
|
75
|
-
@obj2.use_same_log_as(@obj1)
|
76
|
-
@obj2.log.should == @log
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ImageResizer::Processor do
|
4
|
-
|
5
|
-
# IMPORTANT: Enable the flag below to print out the transforms that are generated by calculate_transform
|
6
|
-
# as you run the tests. This is great for updating the expected_results array below if you change the
|
7
|
-
# function and desire different behavior for the inputs, or add other test viewports of POIs.
|
8
|
-
actual_printed = false
|
9
|
-
actual_results = []
|
10
|
-
|
11
|
-
interest_variants_fractional = [{xf: 0, yf: 0}, {xf: 0, yf: 1}, {xf: 1, yf: 1}, {xf: 1, yf: 0}, {xf: 0.5, yf: 0.5}]
|
12
|
-
interest_variants_absolute = [{x: 0, y: 0}, {x: 0, y: 2500}, {x: 3800, y: 2500}, {x: 3800, y: 0}, {x: 3800.0 * 0.5, y: 2500.0 * 0.5}]
|
13
|
-
viewport_variants = [{w: 3800, h: 3000},
|
14
|
-
{w: 5000, h: 5000},
|
15
|
-
{w: 100, h: 100},
|
16
|
-
{w: 100, h: 300},
|
17
|
-
{w: 300, h: 100},
|
18
|
-
{w: 100},
|
19
|
-
{h: 100},
|
20
|
-
{w: 3000},
|
21
|
-
{h: 3000},
|
22
|
-
{}]
|
23
|
-
|
24
|
-
expected_abs_index = 0
|
25
|
-
expected_fraction_index = 0
|
26
|
-
|
27
|
-
expected_results = [{:x=>0.0, :y=>0.0, :w=>3800, :h=>3000, :scale=>1.2},
|
28
|
-
{:x=>0.0, :y=>0.0, :w=>5000, :h=>5000, :scale=>2.0},
|
29
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
30
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>300, :scale=>0.12},
|
31
|
-
{:x=>0.0, :y=>0.0, :w=>300, :h=>100, :scale=>0.07894736842105263},
|
32
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>0, :scale=>0.02631578947368421},
|
33
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
34
|
-
{:x=>0.0, :y=>0.0, :w=>3000, :h=>0, :scale=>0.7894736842105263},
|
35
|
-
{:x=>0.0, :y=>0.0, :w=>3000, :h=>3000, :scale=>1.2},
|
36
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>2500, :scale=>1.0},
|
37
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>3000, :scale=>1.2},
|
38
|
-
{:x=>0.0, :y=>0.0, :w=>5000, :h=>5000, :scale=>2.0},
|
39
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
40
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>300, :scale=>0.12},
|
41
|
-
{:x=>0.0, :y=>97.36842105263156, :w=>300, :h=>100, :scale=>0.07894736842105263},
|
42
|
-
{:x=>0.0, :y=>65.78947368421052, :w=>100, :h=>0, :scale=>0.02631578947368421},
|
43
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
44
|
-
{:x=>0.0, :y=>1973.6842105263158, :w=>3000, :h=>0, :scale=>0.7894736842105263},
|
45
|
-
{:x=>0.0, :y=>0.0, :w=>3000, :h=>3000, :scale=>1.2},
|
46
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>2500, :scale=>1.0},
|
47
|
-
{:x=>760.0, :y=>0.0, :w=>3800, :h=>3000, :scale=>1.2},
|
48
|
-
{:x=>2600.0, :y=>0.0, :w=>5000, :h=>5000, :scale=>2.0},
|
49
|
-
{:x=>52.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
50
|
-
{:x=>356.0, :y=>0.0, :w=>100, :h=>300, :scale=>0.12},
|
51
|
-
{:x=>0.0, :y=>97.36842105263156, :w=>300, :h=>100, :scale=>0.07894736842105263},
|
52
|
-
{:x=>0.0, :y=>65.78947368421052, :w=>100, :h=>0, :scale=>0.02631578947368421},
|
53
|
-
{:x=>52.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
54
|
-
{:x=>0.0, :y=>1973.6842105263158, :w=>3000, :h=>0, :scale=>0.7894736842105263},
|
55
|
-
{:x=>1560.0, :y=>0.0, :w=>3000, :h=>3000, :scale=>1.2},
|
56
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>2500, :scale=>1.0},
|
57
|
-
{:x=>760.0, :y=>0.0, :w=>3800, :h=>3000, :scale=>1.2},
|
58
|
-
{:x=>2600.0, :y=>0.0, :w=>5000, :h=>5000, :scale=>2.0},
|
59
|
-
{:x=>52.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
60
|
-
{:x=>356.0, :y=>0.0, :w=>100, :h=>300, :scale=>0.12},
|
61
|
-
{:x=>0.0, :y=>0.0, :w=>300, :h=>100, :scale=>0.07894736842105263},
|
62
|
-
{:x=>0.0, :y=>0.0, :w=>100, :h=>0, :scale=>0.02631578947368421},
|
63
|
-
{:x=>52.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
64
|
-
{:x=>0.0, :y=>0.0, :w=>3000, :h=>0, :scale=>0.7894736842105263},
|
65
|
-
{:x=>1560.0, :y=>0.0, :w=>3000, :h=>3000, :scale=>1.2},
|
66
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>2500, :scale=>1.0},
|
67
|
-
{:x=>380.0, :y=>0.0, :w=>3800, :h=>3000, :scale=>1.2},
|
68
|
-
{:x=>1300.0, :y=>0.0, :w=>5000, :h=>5000, :scale=>2.0},
|
69
|
-
{:x=>26.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
70
|
-
{:x=>178.0, :y=>0.0, :w=>100, :h=>300, :scale=>0.12},
|
71
|
-
{:x=>0.0, :y=>48.68421052631578, :w=>300, :h=>100, :scale=>0.07894736842105263},
|
72
|
-
{:x=>0.0, :y=>32.89473684210526, :w=>100, :h=>0, :scale=>0.02631578947368421},
|
73
|
-
{:x=>26.0, :y=>0.0, :w=>100, :h=>100, :scale=>0.04},
|
74
|
-
{:x=>0.0, :y=>986.8421052631579, :w=>3000, :h=>0, :scale=>0.7894736842105263},
|
75
|
-
{:x=>780.0, :y=>0.0, :w=>3000, :h=>3000, :scale=>1.2},
|
76
|
-
{:x=>0.0, :y=>0.0, :w=>3800, :h=>2500, :scale=>1.0}]
|
77
|
-
|
78
|
-
before(:each) do
|
79
|
-
@source_jpg_path = SAMPLES_DIR.join('test.jpg') # 3872, 2592
|
80
|
-
@source_png_path = SAMPLES_DIR.join('test.png') # 177, 180
|
81
|
-
@source_jpg_props = {};
|
82
|
-
@source_jpg_props['width'] = 3800
|
83
|
-
@source_jpg_props['height'] = 2500
|
84
|
-
@source_jpg_props['bands'] = 3
|
85
|
-
|
86
|
-
|
87
|
-
@processor = ImageResizer::Processor.new
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "fetch_image_properties" do
|
91
|
-
|
92
|
-
it "should return a hash of properties containing width and height" do
|
93
|
-
properties = @processor.fetch_image_properties(@source_jpg_path)
|
94
|
-
properties['width'].should == @source_jpg_props['width']
|
95
|
-
properties['height'].should == @source_jpg_props['height']
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should return a hash of properties containing depth (JPG=3)" do
|
99
|
-
properties = @processor.fetch_image_properties(@source_jpg_path)
|
100
|
-
properties['bands'].should == 3
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should return a hash of properties containing depth (PNG=4)" do
|
104
|
-
properties = @processor.fetch_image_properties(@source_png_path)
|
105
|
-
properties['bands'].should == 4
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "calculate_transform" do
|
109
|
-
|
110
|
-
interest_variants_absolute.each do |ip|
|
111
|
-
viewport_variants.each do |viewport|
|
112
|
-
|
113
|
-
it "should produce the correct transform viewport: #{viewport}, point: #{ip}" do
|
114
|
-
transform = @processor.calculate_transform(@source_jpg_path, @source_jpg_props, viewport, ip)
|
115
|
-
transform.should == expected_results[expected_abs_index]
|
116
|
-
expected_abs_index += 1
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
interest_variants_fractional.each do |ip|
|
123
|
-
viewport_variants.each do |viewport|
|
124
|
-
|
125
|
-
it "should produce the correct transform viewport: #{viewport}, point: #{ip}" do
|
126
|
-
transform = @processor.calculate_transform(@source_jpg_path, @source_jpg_props, viewport, ip)
|
127
|
-
|
128
|
-
if (actual_printed == true)
|
129
|
-
actual_results.push(transform)
|
130
|
-
if (actual_results.size() == interest_variants_fractional.size() * viewport_variants.size() - 1)
|
131
|
-
print actual_results
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
transform.should == expected_results[expected_fraction_index]
|
136
|
-
expected_fraction_index += 1
|
137
|
-
end
|
138
|
-
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ImageResizer::Shell do
|
4
|
-
|
5
|
-
include ImageResizer::Shell
|
6
|
-
|
7
|
-
it "should raise an error if the identify command isn't found" do
|
8
|
-
suppressing_stderr do
|
9
|
-
lambda{
|
10
|
-
run "non-existent-command"
|
11
|
-
}.should raise_error(ImageResizer::Shell::CommandFailed)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "escaping args" do
|
16
|
-
{
|
17
|
-
%q(hello) => %q('hello'),
|
18
|
-
%q("hello") => %q('hello'),
|
19
|
-
%q('hello') => %q('hello'),
|
20
|
-
%q(he\'llo) => %q('he'\''llo'),
|
21
|
-
%q('he'\''llo') => %q('he'\''llo'),
|
22
|
-
%q("he'llo") => %q('he'\''llo'),
|
23
|
-
%q(hel$(lo)) => %q('hel$(lo)'),
|
24
|
-
%q(hel\$(lo)) => %q('hel$(lo)'),
|
25
|
-
%q('hel\$(lo)') => %q('hel\$(lo)')
|
26
|
-
}.each do |args, escaped_args|
|
27
|
-
it "should escape #{args.inspect} -> #{escaped_args.inspect}" do
|
28
|
-
pending "not applicable to windows" if running_on_windows?
|
29
|
-
escape_args(args).should == escaped_args
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|