dragonfly 1.1.4 → 1.4.0
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/.travis.yml +14 -6
- data/History.md +336 -309
- data/README.md +1 -1
- data/dev/rails_template.rb +35 -33
- data/dragonfly.gemspec +10 -16
- data/lib/dragonfly.rb +3 -1
- data/lib/dragonfly/content.rb +21 -22
- data/lib/dragonfly/image_magick/commands.rb +35 -0
- data/lib/dragonfly/image_magick/generators/plain.rb +13 -7
- data/lib/dragonfly/image_magick/generators/plasma.rb +10 -6
- data/lib/dragonfly/image_magick/generators/text.rb +67 -58
- data/lib/dragonfly/image_magick/plugin.rb +26 -25
- data/lib/dragonfly/image_magick/processors/encode.rb +16 -5
- data/lib/dragonfly/image_magick/processors/thumb.rb +37 -31
- data/lib/dragonfly/job/fetch_url.rb +1 -1
- data/lib/dragonfly/model/class_methods.rb +6 -1
- data/lib/dragonfly/param_validators.rb +37 -0
- data/lib/dragonfly/response.rb +2 -2
- data/lib/dragonfly/shell.rb +19 -13
- data/lib/dragonfly/utils.rb +1 -1
- data/lib/dragonfly/version.rb +1 -1
- data/samples/white pixel.png b/data/samples/mevs' white → pixel.png +0 -0
- data/spec/dragonfly/content_spec.rb +3 -3
- data/spec/dragonfly/cookie_monster_spec.rb +2 -2
- data/spec/dragonfly/image_magick/commands_spec.rb +98 -0
- data/spec/dragonfly/image_magick/generators/plain_spec.rb +39 -13
- data/spec/dragonfly/image_magick/generators/plasma_spec.rb +28 -9
- data/spec/dragonfly/image_magick/generators/text_spec.rb +51 -20
- data/spec/dragonfly/image_magick/plugin_spec.rb +45 -28
- data/spec/dragonfly/image_magick/processors/encode_spec.rb +30 -0
- data/spec/dragonfly/image_magick/processors/thumb_spec.rb +46 -45
- data/spec/dragonfly/model/active_record_spec.rb +62 -0
- data/spec/dragonfly/param_validators_spec.rb +89 -0
- data/spec/dragonfly/shell_spec.rb +12 -10
- data/spec/dragonfly_spec.rb +37 -13
- data/spec/functional/shell_commands_spec.rb +6 -9
- data/spec/spec_helper.rb +12 -14
- metadata +45 -14
- data/lib/dragonfly/image_magick/generators/convert.rb +0 -19
- data/lib/dragonfly/image_magick/processors/convert.rb +0 -33
- data/spec/dragonfly/image_magick/generators/convert_spec.rb +0 -19
- data/spec/dragonfly/image_magick/processors/convert_spec.rb +0 -88
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
1
|
+
require "dragonfly/image_magick/analysers/image_properties"
|
2
|
+
require "dragonfly/image_magick/generators/plain"
|
3
|
+
require "dragonfly/image_magick/generators/plasma"
|
4
|
+
require "dragonfly/image_magick/generators/text"
|
5
|
+
require "dragonfly/image_magick/processors/encode"
|
6
|
+
require "dragonfly/image_magick/processors/thumb"
|
7
|
+
require "dragonfly/image_magick/commands"
|
8
|
+
require "dragonfly/param_validators"
|
9
9
|
|
10
10
|
module Dragonfly
|
11
11
|
module ImageMagick
|
@@ -13,37 +13,36 @@ module Dragonfly
|
|
13
13
|
# The ImageMagick Plugin registers an app with generators, analysers and processors.
|
14
14
|
# Look at the source code for #call to see exactly how it configures the app.
|
15
15
|
class Plugin
|
16
|
-
|
17
|
-
def call(app, opts={})
|
16
|
+
def call(app, opts = {})
|
18
17
|
# ENV
|
19
|
-
app.env[:convert_command] = opts[:convert_command] ||
|
20
|
-
app.env[:identify_command] = opts[:identify_command] ||
|
18
|
+
app.env[:convert_command] = opts[:convert_command] || "convert"
|
19
|
+
app.env[:identify_command] = opts[:identify_command] || "identify"
|
21
20
|
|
22
21
|
# Analysers
|
23
22
|
app.add_analyser :image_properties, ImageMagick::Analysers::ImageProperties.new
|
24
23
|
app.add_analyser :width do |content|
|
25
|
-
content.analyse(:image_properties)[
|
24
|
+
content.analyse(:image_properties)["width"]
|
26
25
|
end
|
27
26
|
app.add_analyser :height do |content|
|
28
|
-
content.analyse(:image_properties)[
|
27
|
+
content.analyse(:image_properties)["height"]
|
29
28
|
end
|
30
29
|
app.add_analyser :format do |content|
|
31
|
-
content.analyse(:image_properties)[
|
30
|
+
content.analyse(:image_properties)["format"]
|
32
31
|
end
|
33
32
|
app.add_analyser :aspect_ratio do |content|
|
34
33
|
attrs = content.analyse(:image_properties)
|
35
|
-
attrs[
|
34
|
+
attrs["width"].to_f / attrs["height"]
|
36
35
|
end
|
37
36
|
app.add_analyser :portrait do |content|
|
38
37
|
attrs = content.analyse(:image_properties)
|
39
|
-
attrs[
|
38
|
+
attrs["width"] <= attrs["height"]
|
40
39
|
end
|
41
40
|
app.add_analyser :landscape do |content|
|
42
41
|
!content.analyse(:portrait)
|
43
42
|
end
|
44
43
|
app.add_analyser :image do |content|
|
45
44
|
begin
|
46
|
-
content.analyse(:image_properties)[
|
45
|
+
content.analyse(:image_properties)["format"] != "pdf"
|
47
46
|
rescue Shell::CommandFailed
|
48
47
|
false
|
49
48
|
end
|
@@ -55,29 +54,31 @@ module Dragonfly
|
|
55
54
|
app.define(:image?) { image }
|
56
55
|
|
57
56
|
# Generators
|
58
|
-
app.add_generator :convert, ImageMagick::Generators::Convert.new
|
59
57
|
app.add_generator :plain, ImageMagick::Generators::Plain.new
|
60
58
|
app.add_generator :plasma, ImageMagick::Generators::Plasma.new
|
61
59
|
app.add_generator :text, ImageMagick::Generators::Text.new
|
60
|
+
app.add_generator :convert do
|
61
|
+
raise "The convert generator is deprecated for better security - use Dragonfly::ImageMagick::Commands.generate(content, args, format) instead."
|
62
|
+
end
|
62
63
|
|
63
64
|
# Processors
|
64
|
-
app.add_processor :convert, Processors::Convert.new
|
65
65
|
app.add_processor :encode, Processors::Encode.new
|
66
66
|
app.add_processor :thumb, Processors::Thumb.new
|
67
67
|
app.add_processor :rotate do |content, amount|
|
68
|
-
|
68
|
+
ParamValidators.validate!(amount, &ParamValidators.is_number)
|
69
|
+
Commands.convert(content, "-rotate #{amount}")
|
70
|
+
end
|
71
|
+
app.add_processor :convert do
|
72
|
+
raise "The convert processor is deprecated for better security - use Dragonfly::ImageMagick::Commands.convert(content, args, opts) instead."
|
69
73
|
end
|
70
74
|
|
71
75
|
# Extra methods
|
72
|
-
app.define :identify do |cli_args=nil|
|
76
|
+
app.define :identify do |cli_args = nil|
|
73
77
|
shell_eval do |path|
|
74
78
|
"#{app.env[:identify_command]} #{cli_args} #{path}"
|
75
79
|
end
|
76
80
|
end
|
77
|
-
|
78
81
|
end
|
79
|
-
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
83
|
-
|
@@ -1,18 +1,29 @@
|
|
1
|
+
require "dragonfly/image_magick/commands"
|
2
|
+
|
1
3
|
module Dragonfly
|
2
4
|
module ImageMagick
|
3
5
|
module Processors
|
4
6
|
class Encode
|
7
|
+
include ParamValidators
|
8
|
+
|
9
|
+
WHITELISTED_ARGS = %w(quality)
|
10
|
+
|
11
|
+
IS_IN_WHITELISTED_ARGS = ->(args_string) {
|
12
|
+
args_string.scan(/-\w+/).all? { |arg|
|
13
|
+
WHITELISTED_ARGS.include?(arg.sub("-", ""))
|
14
|
+
}
|
15
|
+
}
|
5
16
|
|
6
|
-
def update_url(attrs, format, args="")
|
17
|
+
def update_url(attrs, format, args = "")
|
7
18
|
attrs.ext = format.to_s
|
8
19
|
end
|
9
20
|
|
10
|
-
def call(content, format, args="")
|
11
|
-
|
21
|
+
def call(content, format, args = "")
|
22
|
+
validate!(format, &is_word)
|
23
|
+
validate!(args, &IS_IN_WHITELISTED_ARGS)
|
24
|
+
Commands.convert(content, args, "format" => format)
|
12
25
|
end
|
13
|
-
|
14
26
|
end
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
18
|
-
|
@@ -1,32 +1,40 @@
|
|
1
|
+
require "dragonfly/image_magick/commands"
|
2
|
+
|
1
3
|
module Dragonfly
|
2
4
|
module ImageMagick
|
3
5
|
module Processors
|
4
6
|
class Thumb
|
7
|
+
include ParamValidators
|
5
8
|
|
6
9
|
GRAVITIES = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
"nw" => "NorthWest",
|
11
|
+
"n" => "North",
|
12
|
+
"ne" => "NorthEast",
|
13
|
+
"w" => "West",
|
14
|
+
"c" => "Center",
|
15
|
+
"e" => "East",
|
16
|
+
"sw" => "SouthWest",
|
17
|
+
"s" => "South",
|
18
|
+
"se" => "SouthEast",
|
16
19
|
}
|
17
20
|
|
18
21
|
# Geometry string patterns
|
19
|
-
RESIZE_GEOMETRY
|
22
|
+
RESIZE_GEOMETRY = /\A\d*x\d*[><%^!]?\z|\A\d+@\z/ # e.g. '300x200!'
|
20
23
|
CROPPED_RESIZE_GEOMETRY = /\A(\d+)x(\d+)#(\w{1,2})?\z/ # e.g. '20x50#ne'
|
21
|
-
CROP_GEOMETRY
|
24
|
+
CROP_GEOMETRY = /\A(\d+)x(\d+)([+-]\d+)?([+-]\d+)?(\w{1,2})?\z/ # e.g. '30x30+10+10'
|
22
25
|
|
23
|
-
def update_url(url_attributes, geometry, opts={})
|
24
|
-
format = opts[
|
26
|
+
def update_url(url_attributes, geometry, opts = {})
|
27
|
+
format = opts["format"]
|
25
28
|
url_attributes.ext = format if format
|
26
29
|
end
|
27
30
|
|
28
|
-
def call(content, geometry, opts={})
|
29
|
-
|
31
|
+
def call(content, geometry, opts = {})
|
32
|
+
validate!(opts["format"], &is_word)
|
33
|
+
validate!(opts["frame"], &is_number)
|
34
|
+
Commands.convert(content, args_for_geometry(geometry), {
|
35
|
+
"format" => opts["format"],
|
36
|
+
"frame" => opts["frame"],
|
37
|
+
})
|
30
38
|
end
|
31
39
|
|
32
40
|
def args_for_geometry(geometry)
|
@@ -37,11 +45,11 @@ module Dragonfly
|
|
37
45
|
resize_and_crop_args($1, $2, $3)
|
38
46
|
when CROP_GEOMETRY
|
39
47
|
crop_args(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
"width" => $1,
|
49
|
+
"height" => $2,
|
50
|
+
"x" => $3,
|
51
|
+
"y" => $4,
|
52
|
+
"gravity" => $5,
|
45
53
|
)
|
46
54
|
else raise ArgumentError, "Didn't recognise the geometry string #{geometry}"
|
47
55
|
end
|
@@ -54,26 +62,24 @@ module Dragonfly
|
|
54
62
|
end
|
55
63
|
|
56
64
|
def crop_args(opts)
|
57
|
-
raise ArgumentError, "you can't give a crop offset and gravity at the same time" if opts[
|
65
|
+
raise ArgumentError, "you can't give a crop offset and gravity at the same time" if opts["x"] && opts["gravity"]
|
58
66
|
|
59
|
-
width
|
60
|
-
height
|
61
|
-
gravity = GRAVITIES[opts[
|
62
|
-
x
|
63
|
-
x =
|
64
|
-
y
|
65
|
-
y =
|
67
|
+
width = opts["width"]
|
68
|
+
height = opts["height"]
|
69
|
+
gravity = GRAVITIES[opts["gravity"]]
|
70
|
+
x = "#{opts["x"] || 0}"
|
71
|
+
x = "+" + x unless x[/\A[+-]/]
|
72
|
+
y = "#{opts["y"] || 0}"
|
73
|
+
y = "+" + y unless y[/\A[+-]/]
|
66
74
|
|
67
75
|
"#{"-gravity #{gravity} " if gravity}-crop #{width}x#{height}#{x}#{y} +repage"
|
68
76
|
end
|
69
77
|
|
70
78
|
def resize_and_crop_args(width, height, gravity)
|
71
|
-
gravity = GRAVITIES[gravity ||
|
79
|
+
gravity = GRAVITIES[gravity || "c"]
|
72
80
|
"-resize #{width}x#{height}^^ -gravity #{gravity} -crop #{width}x#{height}+0+0 +repage"
|
73
81
|
end
|
74
|
-
|
75
82
|
end
|
76
83
|
end
|
77
84
|
end
|
78
85
|
end
|
79
|
-
|
@@ -30,7 +30,12 @@ module Dragonfly
|
|
30
30
|
|
31
31
|
# Add callbacks
|
32
32
|
before_save :save_dragonfly_attachments if respond_to?(:before_save)
|
33
|
-
|
33
|
+
case
|
34
|
+
when respond_to?(:after_commit)
|
35
|
+
after_commit :destroy_dragonfly_attachments, on: :destroy
|
36
|
+
when respond_to?(:after_destroy)
|
37
|
+
after_destroy :destroy_dragonfly_attachments
|
38
|
+
end
|
34
39
|
|
35
40
|
# Register the new attribute
|
36
41
|
dragonfly_attachment_classes << new_dragonfly_attachment_class(attribute, app, config_block)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
module ParamValidators
|
3
|
+
class InvalidParameter < RuntimeError; end
|
4
|
+
|
5
|
+
module_function
|
6
|
+
|
7
|
+
IS_NUMBER = ->(param) {
|
8
|
+
param.is_a?(Numeric) || /\A[\d\.]+\z/ === param
|
9
|
+
}
|
10
|
+
|
11
|
+
IS_WORD = ->(param) {
|
12
|
+
/\A\w+\z/ === param
|
13
|
+
}
|
14
|
+
|
15
|
+
IS_WORDS = ->(param) {
|
16
|
+
/\A[\w ]+\z/ === param
|
17
|
+
}
|
18
|
+
|
19
|
+
def is_number; IS_NUMBER; end
|
20
|
+
def is_word; IS_WORD; end
|
21
|
+
def is_words; IS_WORDS; end
|
22
|
+
|
23
|
+
def validate!(parameter, &validator)
|
24
|
+
return if parameter.nil?
|
25
|
+
raise InvalidParameter unless validator.(parameter)
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_all!(parameters, &validator)
|
29
|
+
parameters.each { |p| validate!(p, &validator) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_all_keys!(obj, keys, &validator)
|
33
|
+
parameters = keys.map { |key| obj[key] }
|
34
|
+
validate_all!(parameters, &validator)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/dragonfly/response.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'cgi'
|
2
2
|
require 'rack'
|
3
3
|
|
4
4
|
module Dragonfly
|
@@ -99,7 +99,7 @@ module Dragonfly
|
|
99
99
|
|
100
100
|
def filename_string
|
101
101
|
return unless job.name
|
102
|
-
filename = request_from_msie? ?
|
102
|
+
filename = request_from_msie? ? CGI.escape(job.name) : job.name
|
103
103
|
%(filename="#{filename}")
|
104
104
|
end
|
105
105
|
|
data/lib/dragonfly/shell.rb
CHANGED
@@ -15,14 +15,11 @@ module Dragonfly
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def escape_args(args)
|
18
|
-
args.shellsplit.map
|
19
|
-
quote arg.gsub(/\\?'/, %q('\\\\''))
|
20
|
-
end.join(' ')
|
18
|
+
args.shellsplit.map{|arg| escape(arg) }.join(' ')
|
21
19
|
end
|
22
20
|
|
23
|
-
def
|
24
|
-
|
25
|
-
q + string + q
|
21
|
+
def escape(string)
|
22
|
+
Shellwords.escape(string)
|
26
23
|
end
|
27
24
|
|
28
25
|
private
|
@@ -36,22 +33,31 @@ module Dragonfly
|
|
36
33
|
def run_command(command)
|
37
34
|
result = `#{command}`
|
38
35
|
status = $?
|
39
|
-
|
36
|
+
raise_command_failed!(command, status.exitstatus) unless status.success?
|
40
37
|
result
|
38
|
+
rescue Errno::ENOENT => e
|
39
|
+
raise_command_failed!(command, nil, e.message)
|
41
40
|
end
|
42
41
|
|
43
42
|
else
|
44
43
|
|
45
44
|
def run_command(command)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
45
|
+
stdout_str, stderr_str, status = Open3.capture3(command)
|
46
|
+
raise_command_failed!(command, status.exitstatus, stderr_str) unless status.success?
|
47
|
+
stdout_str
|
48
|
+
rescue Errno::ENOENT => e
|
49
|
+
raise_command_failed!(command, nil, e.message)
|
52
50
|
end
|
53
51
|
|
54
52
|
end
|
55
53
|
|
54
|
+
def raise_command_failed!(command, status=nil, error=nil)
|
55
|
+
raise CommandFailed, [
|
56
|
+
"Command failed: #{command}",
|
57
|
+
("exit status: #{status}" if status),
|
58
|
+
("error: #{error}" if error),
|
59
|
+
].join(', ')
|
60
|
+
end
|
61
|
+
|
56
62
|
end
|
57
63
|
end
|
data/lib/dragonfly/utils.rb
CHANGED
data/lib/dragonfly/version.rb
CHANGED
File without changes
|
@@ -232,7 +232,7 @@ describe Dragonfly::Content do
|
|
232
232
|
path = p
|
233
233
|
"cat #{path}"
|
234
234
|
end.should == "big\nstuff"
|
235
|
-
path.should == app.shell.
|
235
|
+
path.should == app.shell.escape(content.path)
|
236
236
|
end
|
237
237
|
|
238
238
|
it "allows evaluating without escaping" do
|
@@ -253,8 +253,8 @@ describe Dragonfly::Content do
|
|
253
253
|
new_path = n
|
254
254
|
"cp #{o} #{n}"
|
255
255
|
end.should == content
|
256
|
-
old_path.should == app.shell.
|
257
|
-
new_path.should == app.shell.
|
256
|
+
old_path.should == app.shell.escape(original_path)
|
257
|
+
new_path.should == app.shell.escape(content.path)
|
258
258
|
content.data.should == "big\nstuff"
|
259
259
|
end
|
260
260
|
|
@@ -7,7 +7,7 @@ describe Dragonfly::CookieMonster do
|
|
7
7
|
def app(extra_env={})
|
8
8
|
Rack::Builder.new do
|
9
9
|
use Dragonfly::CookieMonster
|
10
|
-
run proc{|env| env.merge!(extra_env); [200, {"Set-Cookie" => "blah", "Something" => "else"}, ["body here"]] }
|
10
|
+
run proc{|env| env.merge!(extra_env); [200, {"Set-Cookie" => "blah=thing", "Something" => "else"}, ["body here"]] }
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -15,7 +15,7 @@ describe Dragonfly::CookieMonster do
|
|
15
15
|
response = Rack::MockRequest.new(app).get('')
|
16
16
|
response.status.should == 200
|
17
17
|
response.body.should == "body here"
|
18
|
-
response.headers["Set-Cookie"].should == "blah"
|
18
|
+
response.headers["Set-Cookie"].should == "blah=thing"
|
19
19
|
response.headers["Something"].should == "else"
|
20
20
|
end
|
21
21
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "dragonfly/image_magick/commands"
|
3
|
+
|
4
|
+
describe Dragonfly::ImageMagick::Commands do
|
5
|
+
include Dragonfly::ImageMagick::Commands
|
6
|
+
|
7
|
+
let(:app) { test_app }
|
8
|
+
|
9
|
+
def sample_content(name)
|
10
|
+
Dragonfly::Content.new(app, SAMPLES_DIR.join(name))
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "convert" do
|
14
|
+
let(:image) { sample_content("beach.png") } # 280x355
|
15
|
+
|
16
|
+
it "should allow for general convert commands" do
|
17
|
+
convert(image, "-scale 56x71")
|
18
|
+
image.should have_width(56)
|
19
|
+
image.should have_height(71)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow for general convert commands with added format" do
|
23
|
+
convert(image, "-scale 56x71", "format" => "gif")
|
24
|
+
image.should have_width(56)
|
25
|
+
image.should have_height(71)
|
26
|
+
image.should have_format("gif")
|
27
|
+
image.meta["format"].should == "gif"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should work for commands with parenthesis" do
|
31
|
+
convert(image, "\\( +clone -sparse-color Barycentric '0,0 black 0,%[fx:h-1] white' -function polynomial 2,-2,0.5 \\) -compose Blur -set option:compose:args 15 -composite")
|
32
|
+
image.should have_width(280)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should work for files with spaces/apostrophes in the name" do
|
36
|
+
image = Dragonfly::Content.new(app, SAMPLES_DIR.join("mevs' white pixel.png"))
|
37
|
+
convert(image, "-resize 2x2!")
|
38
|
+
image.should have_width(2)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "allows converting specific frames" do
|
42
|
+
gif = sample_content("gif.gif")
|
43
|
+
convert(gif, "-resize 50x50")
|
44
|
+
all_frames_size = gif.size
|
45
|
+
|
46
|
+
gif = sample_content("gif.gif")
|
47
|
+
convert(gif, "-resize 50x50", "frame" => 0)
|
48
|
+
one_frame_size = gif.size
|
49
|
+
|
50
|
+
one_frame_size.should < all_frames_size
|
51
|
+
end
|
52
|
+
|
53
|
+
it "accepts input arguments for convert commands" do
|
54
|
+
image2 = image.clone
|
55
|
+
convert(image, "")
|
56
|
+
convert(image2, "", "input_args" => "-extract 50x50+10+10")
|
57
|
+
|
58
|
+
image.should_not equal_image(image2)
|
59
|
+
image2.should have_width(50)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "allows converting using specific delegates" do
|
63
|
+
expect {
|
64
|
+
convert(image, "", "format" => "jpg", "delegate" => "png")
|
65
|
+
}.to call_command(app.shell, %r{convert png:/[^']+?/beach\.png /[^']+?\.jpg})
|
66
|
+
end
|
67
|
+
|
68
|
+
it "maintains the mime_type meta if it exists already" do
|
69
|
+
convert(image, "-resize 10x")
|
70
|
+
image.meta["mime_type"].should be_nil
|
71
|
+
|
72
|
+
image.add_meta("mime_type" => "image/png")
|
73
|
+
convert(image, "-resize 5x")
|
74
|
+
image.meta["mime_type"].should == "image/png"
|
75
|
+
image.mime_type.should == "image/png" # sanity check
|
76
|
+
end
|
77
|
+
|
78
|
+
it "doesn't maintain the mime_type meta on format change" do
|
79
|
+
image.add_meta("mime_type" => "image/png")
|
80
|
+
convert(image, "", "format" => "gif")
|
81
|
+
image.meta["mime_type"].should be_nil
|
82
|
+
image.mime_type.should == "image/gif" # sanity check
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "generate" do
|
87
|
+
let (:image) { Dragonfly::Content.new(app) }
|
88
|
+
|
89
|
+
before(:each) do
|
90
|
+
generate(image, "-size 1x1 xc:white", "png")
|
91
|
+
end
|
92
|
+
|
93
|
+
it { image.should have_width(1) }
|
94
|
+
it { image.should have_height(1) }
|
95
|
+
it { image.should have_format("png") }
|
96
|
+
it { image.meta.should == { "format" => "png" } }
|
97
|
+
end
|
98
|
+
end
|