dragonfly 0.8.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dragonfly might be problematic. Click here for more details.

Files changed (155) hide show
  1. data/{.specopts → .rspec} +0 -1
  2. data/.yardopts +6 -2
  3. data/Gemfile +14 -13
  4. data/History.md +47 -9
  5. data/README.md +25 -5
  6. data/Rakefile +37 -79
  7. data/VERSION +1 -1
  8. data/dragonfly.gemspec +140 -89
  9. data/extra_docs/Analysers.md +8 -48
  10. data/extra_docs/Configuration.md +40 -25
  11. data/extra_docs/Couch.md +49 -0
  12. data/extra_docs/DataStorage.md +94 -24
  13. data/extra_docs/Encoding.md +6 -35
  14. data/extra_docs/ExampleUseCases.md +113 -0
  15. data/extra_docs/GeneralUsage.md +7 -23
  16. data/extra_docs/Generators.md +15 -49
  17. data/extra_docs/Heroku.md +7 -8
  18. data/extra_docs/ImageMagick.md +126 -0
  19. data/extra_docs/MimeTypes.md +3 -3
  20. data/extra_docs/Models.md +163 -0
  21. data/extra_docs/Mongo.md +1 -4
  22. data/extra_docs/Processing.md +7 -60
  23. data/extra_docs/Rails2.md +3 -1
  24. data/extra_docs/Rails3.md +2 -10
  25. data/extra_docs/ServingRemotely.md +83 -0
  26. data/extra_docs/Sinatra.md +3 -3
  27. data/extra_docs/URLs.md +60 -33
  28. data/features/rails_3.0.5.feature +8 -0
  29. data/features/steps/rails_steps.rb +7 -18
  30. data/features/support/env.rb +10 -37
  31. data/features/support/setup.rb +32 -0
  32. data/fixtures/rails_3.0.5/files/app/models/album.rb +5 -0
  33. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  34. data/fixtures/{files → rails_3.0.5/files}/app/views/albums/show.html.erb +2 -0
  35. data/fixtures/{files → rails_3.0.5/files}/config/initializers/dragonfly.rb +0 -0
  36. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  37. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  38. data/fixtures/{files → rails_3.0.5/files}/features/step_definitions/image_steps.rb +11 -1
  39. data/fixtures/{files → rails_3.0.5/files}/features/support/paths.rb +2 -0
  40. data/fixtures/{files → rails_3.0.5/files}/features/text_images.feature +0 -0
  41. data/fixtures/{rails_3.0.3 → rails_3.0.5}/template.rb +2 -2
  42. data/irbrc.rb +2 -1
  43. data/lib/dragonfly.rb +7 -0
  44. data/lib/dragonfly/active_model_extensions/attachment.rb +134 -46
  45. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +144 -0
  46. data/lib/dragonfly/active_model_extensions/class_methods.rb +62 -9
  47. data/lib/dragonfly/active_model_extensions/instance_methods.rb +2 -2
  48. data/lib/dragonfly/active_model_extensions/validations.rb +10 -6
  49. data/lib/dragonfly/analyser.rb +0 -1
  50. data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
  51. data/lib/dragonfly/analysis/image_magick_analyser.rb +2 -43
  52. data/lib/dragonfly/app.rb +64 -55
  53. data/lib/dragonfly/config/heroku.rb +1 -1
  54. data/lib/dragonfly/config/image_magick.rb +2 -37
  55. data/lib/dragonfly/config/rails.rb +5 -2
  56. data/lib/dragonfly/configurable.rb +115 -35
  57. data/lib/dragonfly/core_ext/object.rb +1 -1
  58. data/lib/dragonfly/core_ext/string.rb +1 -1
  59. data/lib/dragonfly/data_storage/couch_data_store.rb +84 -0
  60. data/lib/dragonfly/data_storage/file_data_store.rb +43 -18
  61. data/lib/dragonfly/data_storage/mongo_data_store.rb +8 -4
  62. data/lib/dragonfly/data_storage/s3data_store.rb +82 -38
  63. data/lib/dragonfly/encoding/image_magick_encoder.rb +2 -53
  64. data/lib/dragonfly/function_manager.rb +4 -2
  65. data/lib/dragonfly/generation/image_magick_generator.rb +2 -136
  66. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  67. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  68. data/lib/dragonfly/image_magick/config.rb +44 -0
  69. data/lib/dragonfly/{encoding/r_magick_encoder.rb → image_magick/encoder.rb} +10 -14
  70. data/lib/dragonfly/image_magick/generator.rb +145 -0
  71. data/lib/dragonfly/image_magick/processor.rb +104 -0
  72. data/lib/dragonfly/image_magick/utils.rb +72 -0
  73. data/lib/dragonfly/image_magick_utils.rb +2 -79
  74. data/lib/dragonfly/job.rb +152 -90
  75. data/lib/dragonfly/middleware.rb +5 -19
  76. data/lib/dragonfly/processing/image_magick_processor.rb +2 -95
  77. data/lib/dragonfly/rails/images.rb +15 -10
  78. data/lib/dragonfly/response.rb +26 -12
  79. data/lib/dragonfly/serializer.rb +1 -4
  80. data/lib/dragonfly/server.rb +103 -0
  81. data/lib/dragonfly/temp_object.rb +56 -101
  82. data/lib/dragonfly/url_mapper.rb +78 -0
  83. data/spec/dragonfly/active_model_extensions/model_spec.rb +772 -65
  84. data/spec/dragonfly/active_model_extensions/spec_helper.rb +90 -10
  85. data/spec/dragonfly/analyser_spec.rb +1 -1
  86. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +5 -14
  87. data/spec/dragonfly/app_spec.rb +35 -180
  88. data/spec/dragonfly/configurable_spec.rb +259 -18
  89. data/spec/dragonfly/core_ext/string_spec.rb +2 -2
  90. data/spec/dragonfly/core_ext/symbol_spec.rb +1 -1
  91. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +84 -0
  92. data/spec/dragonfly/data_storage/file_data_store_spec.rb +149 -22
  93. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +21 -2
  94. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +207 -43
  95. data/spec/dragonfly/data_storage/{data_store_spec.rb → shared_data_store_examples.rb} +16 -15
  96. data/spec/dragonfly/function_manager_spec.rb +2 -2
  97. data/spec/dragonfly/{generation/hash_with_css_style_keys_spec.rb → hash_with_css_style_keys_spec.rb} +2 -2
  98. data/spec/dragonfly/{analysis/shared_analyser_spec.rb → image_magick/analyser_spec.rb} +19 -6
  99. data/spec/dragonfly/{encoding/image_magick_encoder_spec.rb → image_magick/encoder_spec.rb} +2 -2
  100. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  101. data/spec/dragonfly/{processing/shared_processing_spec.rb → image_magick/processor_spec.rb} +55 -6
  102. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  103. data/spec/dragonfly/job_builder_spec.rb +1 -1
  104. data/spec/dragonfly/job_definitions_spec.rb +1 -1
  105. data/spec/dragonfly/job_endpoint_spec.rb +26 -3
  106. data/spec/dragonfly/job_spec.rb +426 -208
  107. data/spec/dragonfly/loggable_spec.rb +2 -2
  108. data/spec/dragonfly/middleware_spec.rb +5 -26
  109. data/spec/dragonfly/routed_endpoint_spec.rb +1 -1
  110. data/spec/dragonfly/serializer_spec.rb +1 -14
  111. data/spec/dragonfly/server_spec.rb +261 -0
  112. data/spec/dragonfly/simple_cache_spec.rb +1 -1
  113. data/spec/dragonfly/temp_object_spec.rb +84 -130
  114. data/spec/dragonfly/url_mapper_spec.rb +130 -0
  115. data/spec/functional/deprecations_spec.rb +51 -0
  116. data/spec/functional/image_magick_app_spec.rb +27 -0
  117. data/spec/functional/model_urls_spec.rb +85 -0
  118. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  119. data/spec/functional/to_response_spec.rb +31 -0
  120. data/spec/spec_helper.rb +12 -22
  121. data/spec/{argument_matchers.rb → support/argument_matchers.rb} +0 -0
  122. data/spec/{image_matchers.rb → support/image_matchers.rb} +4 -4
  123. data/spec/support/simple_matchers.rb +53 -0
  124. data/yard/handlers/configurable_attr_handler.rb +2 -2
  125. data/yard/templates/default/fulldoc/html/css/common.css +12 -10
  126. data/yard/templates/default/layout/html/layout.erb +6 -0
  127. metadata +267 -308
  128. data/Gemfile.rails.2.3.5 +0 -20
  129. data/features/3.0.3.feature +0 -8
  130. data/features/rails_2.3.5.feature +0 -7
  131. data/fixtures/files/app/models/album.rb +0 -3
  132. data/fixtures/files/app/views/albums/new.html.erb +0 -4
  133. data/fixtures/files/features/manage_album_images.feature +0 -12
  134. data/fixtures/rails_2.3.5/template.rb +0 -10
  135. data/lib/dragonfly/analysis/r_magick_analyser.rb +0 -63
  136. data/lib/dragonfly/config/r_magick.rb +0 -46
  137. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +0 -23
  138. data/lib/dragonfly/generation/r_magick_generator.rb +0 -155
  139. data/lib/dragonfly/processing/r_magick_processor.rb +0 -126
  140. data/lib/dragonfly/r_magick_utils.rb +0 -48
  141. data/lib/dragonfly/simple_endpoint.rb +0 -76
  142. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +0 -97
  143. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +0 -85
  144. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +0 -15
  145. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +0 -31
  146. data/spec/dragonfly/config/r_magick_spec.rb +0 -29
  147. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +0 -41
  148. data/spec/dragonfly/generation/image_magick_generator_spec.rb +0 -12
  149. data/spec/dragonfly/generation/r_magick_generator_spec.rb +0 -28
  150. data/spec/dragonfly/generation/shared_generator_spec.rb +0 -91
  151. data/spec/dragonfly/image_magick_utils_spec.rb +0 -16
  152. data/spec/dragonfly/processing/image_magick_processor_spec.rb +0 -29
  153. data/spec/dragonfly/processing/r_magick_processor_spec.rb +0 -30
  154. data/spec/dragonfly/simple_endpoint_spec.rb +0 -97
  155. data/spec/simple_matchers.rb +0 -44
@@ -0,0 +1,51 @@
1
+ module Dragonfly
2
+ module ImageMagick
3
+ class Analyser
4
+
5
+ include Utils
6
+ include Configurable
7
+
8
+ def width(temp_object)
9
+ identify(temp_object)[:width]
10
+ end
11
+
12
+ def height(temp_object)
13
+ identify(temp_object)[:height]
14
+ end
15
+
16
+ def aspect_ratio(temp_object)
17
+ attrs = identify(temp_object)
18
+ attrs[:width].to_f / attrs[:height]
19
+ end
20
+
21
+ def portrait?(temp_object)
22
+ attrs = identify(temp_object)
23
+ attrs[:width] <= attrs[:height]
24
+ end
25
+
26
+ def landscape?(temp_object)
27
+ attrs = identify(temp_object)
28
+ attrs[:width] >= attrs[:height]
29
+ end
30
+
31
+ def depth(temp_object)
32
+ identify(temp_object)[:depth]
33
+ end
34
+
35
+ def number_of_colours(temp_object)
36
+ details = raw_identify(temp_object, '-verbose -unique')
37
+ details[/Colors: (\d+)/, 1].to_i
38
+ end
39
+ alias number_of_colors number_of_colours
40
+
41
+ def format(temp_object)
42
+ identify(temp_object)[:format]
43
+ end
44
+
45
+ def image?(temp_object)
46
+ !!catch(:unable_to_handle){ identify(temp_object) }
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ module Dragonfly
2
+ module ImageMagick
3
+
4
+ # ImageMagick Config is a saved configuration for Dragonfly apps, which does the following:
5
+ # - registers an imagemagick analyser
6
+ # - registers an imagemagick processor
7
+ # - registers an imagemagick encoder
8
+ # - adds thumb shortcuts like '280x140!', etc.
9
+ # Look at the source code for apply_configuration to see exactly how it configures the app.
10
+ module Config
11
+
12
+ def self.apply_configuration(app, opts={})
13
+ app.configure do |c|
14
+ c.analyser.register(ImageMagick::Analyser)
15
+ c.processor.register(ImageMagick::Processor)
16
+ c.encoder.register(ImageMagick::Encoder)
17
+ c.generator.register(ImageMagick::Generator)
18
+
19
+ c.job :thumb do |geometry, format|
20
+ process :thumb, geometry
21
+ encode format if format
22
+ end
23
+ c.job :gif do
24
+ encode :gif
25
+ end
26
+ c.job :jpg do
27
+ encode :jpg
28
+ end
29
+ c.job :png do
30
+ encode :png
31
+ end
32
+ c.job :strip do
33
+ process :strip
34
+ end
35
+ c.job :convert do |args, format|
36
+ process :convert, args, format
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -1,11 +1,9 @@
1
- require 'RMagick'
2
-
3
1
  module Dragonfly
4
- module Encoding
5
- class RMagickEncoder
2
+ module ImageMagick
3
+ class Encoder
6
4
 
7
5
  include Configurable
8
- include RMagickUtils
6
+ include Utils
9
7
 
10
8
  configurable_attr :supported_formats, [
11
9
  :ai,
@@ -41,18 +39,16 @@ module Dragonfly
41
39
  :xpm,
42
40
  :xwd
43
41
  ]
44
- configurable_attr :use_filesystem, true
45
42
 
46
- def encode(temp_object, format, encoding={})
43
+ def encode(temp_object, format, args='')
47
44
  format = format.to_s.downcase
48
45
  throw :unable_to_handle unless supported_formats.include?(format.to_sym)
49
- rmagick_image(temp_object) do |image|
50
- if image.format.downcase == format
51
- temp_object # do nothing
52
- else
53
- image.format = format
54
- image
55
- end
46
+ details = identify(temp_object)
47
+
48
+ if details[:format] == format.to_sym && args.empty?
49
+ temp_object
50
+ else
51
+ convert(temp_object, args, format)
56
52
  end
57
53
  end
58
54
 
@@ -0,0 +1,145 @@
1
+ module Dragonfly
2
+ module ImageMagick
3
+ class Generator
4
+
5
+ FONT_STYLES = {
6
+ 'normal' => 'normal',
7
+ 'italic' => 'italic',
8
+ 'oblique' => 'oblique'
9
+ }
10
+
11
+ FONT_STRETCHES = {
12
+ 'normal' => 'normal',
13
+ 'semi-condensed' => 'semi-condensed',
14
+ 'condensed' => 'condensed',
15
+ 'extra-condensed' => 'extra-condensed',
16
+ 'ultra-condensed' => 'ultra-condensed',
17
+ 'semi-expanded' => 'semi-expanded',
18
+ 'expanded' => 'expanded',
19
+ 'extra-expanded' => 'extra-expanded',
20
+ 'ultra-expanded' => 'ultra-expanded'
21
+ }
22
+
23
+ FONT_WEIGHTS = {
24
+ 'normal' => 'normal',
25
+ 'bold' => 'bold',
26
+ 'bolder' => 'bolder',
27
+ 'lighter' => 'lighter',
28
+ '100' => 100,
29
+ '200' => 200,
30
+ '300' => 300,
31
+ '400' => 400,
32
+ '500' => 500,
33
+ '600' => 600,
34
+ '700' => 700,
35
+ '800' => 800,
36
+ '900' => 900
37
+ }
38
+
39
+ include Utils
40
+ include Configurable
41
+
42
+ def plain(width, height, colour, opts={})
43
+ format = opts[:format] || 'png'
44
+ [
45
+ convert(nil, "-size #{width}x#{height} \"xc:#{colour}\"", format),
46
+ {:format => format.to_sym, :name => "plain.#{format}"}
47
+ ]
48
+ end
49
+
50
+ def plasma(width, height, format='png')
51
+ [
52
+ convert(nil, "-size #{width}x#{height} plasma:fractal", format),
53
+ {:format => format.to_sym, :name => "plasma.#{format}"}
54
+ ]
55
+ end
56
+
57
+ def text(string, opts={})
58
+ opts = HashWithCssStyleKeys[opts]
59
+ args = []
60
+ format = (opts[:format] || :png)
61
+ background = opts[:background_color] || 'none'
62
+ font_size = (opts[:font_size] || 12).to_i
63
+ escaped_string = "\"#{string.gsub(/"/, '\"')}\""
64
+
65
+ # Settings
66
+ args.push("-gravity NorthWest")
67
+ args.push("-antialias")
68
+ args.push("-pointsize #{font_size}")
69
+ args.push("-font \"#{opts[:font]}\"") if opts[:font]
70
+ args.push("-family '#{opts[:font_family]}'") if opts[:font_family]
71
+ args.push("-fill #{opts[:color]}") if opts[:color]
72
+ args.push("-stroke #{opts[:stroke_color]}") if opts[:stroke_color]
73
+ args.push("-style #{FONT_STYLES[opts[:font_style]]}") if opts[:font_style]
74
+ args.push("-stretch #{FONT_STRETCHES[opts[:font_stretch]]}") if opts[:font_stretch]
75
+ args.push("-weight #{FONT_WEIGHTS[opts[:font_weight]]}") if opts[:font_weight]
76
+ args.push("-background #{background}")
77
+ args.push("label:#{escaped_string}")
78
+
79
+ # Padding
80
+ pt, pr, pb, pl = parse_padding_string(opts[:padding]) if opts[:padding]
81
+ padding_top = (opts[:padding_top] || pt || 0)
82
+ padding_right = (opts[:padding_right] || pr || 0)
83
+ padding_bottom = (opts[:padding_bottom] || pb || 0)
84
+ padding_left = (opts[:padding_left] || pl || 0)
85
+
86
+ tempfile = convert(nil, args.join(' '), format)
87
+
88
+ if (padding_top || padding_right || padding_bottom || padding_left)
89
+ attrs = identify(tempfile)
90
+ text_width = attrs[:width].to_i
91
+ text_height = attrs[:height].to_i
92
+ width = padding_left + text_width + padding_right
93
+ height = padding_top + text_height + padding_bottom
94
+
95
+ args = args.slice(0, args.length - 2)
96
+ args.push("-size #{width}x#{height}")
97
+ args.push("xc:#{background}")
98
+ args.push("-annotate 0x0+#{padding_left}+#{padding_top} #{escaped_string}")
99
+ run "#{convert_command} #{args.join(' ')} #{tempfile.path}"
100
+ end
101
+
102
+ [
103
+ tempfile,
104
+ {:format => format, :name => "text.#{format}"}
105
+ ]
106
+ end
107
+
108
+ private
109
+
110
+ # Use css-style padding declaration, i.e.
111
+ # 10 (all sides)
112
+ # 10 5 (top/bottom, left/right)
113
+ # 10 5 10 (top, left/right, bottom)
114
+ # 10 5 10 5 (top, right, bottom, left)
115
+ def parse_padding_string(str)
116
+ padding_parts = str.gsub('px','').split(/\s+/).map{|px| px.to_i}
117
+ case padding_parts.size
118
+ when 1
119
+ p = padding_parts.first
120
+ [p,p,p,p]
121
+ when 2
122
+ p,q = padding_parts
123
+ [p,q,p,q]
124
+ when 3
125
+ p,q,r = padding_parts
126
+ [p,q,r,q]
127
+ when 4
128
+ padding_parts
129
+ else raise ArgumentError, "Couldn't parse padding string '#{str}' - should be a css-style string"
130
+ end
131
+ end
132
+
133
+ def scale_factor_for(font_size)
134
+ # Scale approximately to 64 if below
135
+ min_size = 64
136
+ if font_size < min_size
137
+ (min_size.to_f / font_size).ceil
138
+ else
139
+ 1
140
+ end.to_f
141
+ end
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,104 @@
1
+ module Dragonfly
2
+ module ImageMagick
3
+ class Processor
4
+
5
+ GRAVITIES = {
6
+ 'nw' => 'NorthWest',
7
+ 'n' => 'North',
8
+ 'ne' => 'NorthEast',
9
+ 'w' => 'West',
10
+ 'c' => 'Center',
11
+ 'e' => 'East',
12
+ 'sw' => 'SouthWest',
13
+ 's' => 'South',
14
+ 'se' => 'SouthEast'
15
+ }
16
+
17
+ # Geometry string patterns
18
+ RESIZE_GEOMETRY = /^\d*x\d*[><%^!]?$|^\d+@$/ # e.g. '300x200!'
19
+ CROPPED_RESIZE_GEOMETRY = /^(\d+)x(\d+)#(\w{1,2})?$/ # e.g. '20x50#ne'
20
+ CROP_GEOMETRY = /^(\d+)x(\d+)([+-]\d+)?([+-]\d+)?(\w{1,2})?$/ # e.g. '30x30+10+10'
21
+ THUMB_GEOMETRY = Regexp.union RESIZE_GEOMETRY, CROPPED_RESIZE_GEOMETRY, CROP_GEOMETRY
22
+
23
+ include Utils
24
+
25
+ def resize(temp_object, geometry)
26
+ convert(temp_object, "-resize \"#{geometry}\"")
27
+ end
28
+
29
+ def crop(temp_object, opts={})
30
+ width = opts[:width]
31
+ height = opts[:height]
32
+ gravity = GRAVITIES[opts[:gravity]]
33
+ x = "#{opts[:x] || 0}"
34
+ x = '+' + x unless x[/^[+-]/]
35
+ y = "#{opts[:y] || 0}"
36
+ y = '+' + y unless y[/^[+-]/]
37
+ repage = opts[:repage] == false ? '' : '+repage'
38
+
39
+ convert(temp_object, "-crop #{width}x#{height}#{x}#{y}#{" -gravity #{gravity}" if gravity} #{repage}")
40
+ end
41
+
42
+ def flip(temp_object)
43
+ convert(temp_object, "-flip")
44
+ end
45
+
46
+ def flop(temp_object)
47
+ convert(temp_object, "-flop")
48
+ end
49
+
50
+ def greyscale(temp_object)
51
+ convert(temp_object, "-colorspace Gray")
52
+ end
53
+ alias grayscale greyscale
54
+
55
+ def resize_and_crop(temp_object, opts={})
56
+ attrs = identify(temp_object)
57
+ current_width = attrs[:width].to_i
58
+ current_height = attrs[:height].to_i
59
+
60
+ width = opts[:width] ? opts[:width].to_i : current_width
61
+ height = opts[:height] ? opts[:height].to_i : current_height
62
+ gravity = opts[:gravity] || 'c'
63
+
64
+ if width != current_width || height != current_height
65
+ scale = [width.to_f / current_width, height.to_f / current_height].max
66
+ temp_object = TempObject.new(resize(temp_object, "#{(scale * current_width).ceil}x#{(scale * current_height).ceil}"))
67
+ end
68
+
69
+ crop(temp_object, :width => width, :height => height, :gravity => gravity)
70
+ end
71
+
72
+ def rotate(temp_object, amount, opts={})
73
+ convert(temp_object, "-rotate \"#{amount}#{opts[:qualifier]}\"")
74
+ end
75
+
76
+ def strip(temp_object)
77
+ convert(temp_object, "-strip")
78
+ end
79
+
80
+ def thumb(temp_object, geometry)
81
+ case geometry
82
+ when RESIZE_GEOMETRY
83
+ resize(temp_object, geometry)
84
+ when CROPPED_RESIZE_GEOMETRY
85
+ resize_and_crop(temp_object, :width => $1, :height => $2, :gravity => $3)
86
+ when CROP_GEOMETRY
87
+ crop(temp_object,
88
+ :width => $1,
89
+ :height => $2,
90
+ :x => $3,
91
+ :y => $4,
92
+ :gravity => $5
93
+ )
94
+ else raise ArgumentError, "Didn't recognise the geometry string #{geometry}"
95
+ end
96
+ end
97
+
98
+ def convert(temp_object, args='', format=nil)
99
+ format ? [super, {:format => format.to_sym}] : super
100
+ end
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,72 @@
1
+ require 'tempfile'
2
+
3
+ module Dragonfly
4
+ module ImageMagick
5
+ module Utils
6
+
7
+ # Exceptions
8
+ class ShellCommandFailed < RuntimeError; end
9
+
10
+ include Loggable
11
+ include Configurable
12
+ configurable_attr :convert_command, "convert"
13
+ configurable_attr :identify_command, "identify"
14
+ configurable_attr :log_commands, false
15
+
16
+ private
17
+
18
+ def convert(temp_object=nil, args='', format=nil)
19
+ tempfile = new_tempfile(format)
20
+ run "#{convert_command} #{temp_object.path if temp_object} #{args} #{tempfile.path}"
21
+ tempfile
22
+ end
23
+
24
+ def identify(temp_object)
25
+ # example of details string:
26
+ # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
27
+ details = raw_identify(temp_object)
28
+ filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
29
+ width, height = geometry.split('x')
30
+ {
31
+ :filename => filename,
32
+ :format => format.downcase.to_sym,
33
+ :width => width.to_i,
34
+ :height => height.to_i,
35
+ :depth => depth.to_i,
36
+ :image_class => image_class
37
+ }
38
+ end
39
+
40
+ def raw_identify(temp_object, args='')
41
+ run "#{identify_command} #{args} #{temp_object.path}"
42
+ end
43
+
44
+ def new_tempfile(ext=nil)
45
+ tempfile = ext ? Tempfile.new(['dragonfly', ".#{ext}"]) : Tempfile.new('dragonfly')
46
+ tempfile.binmode
47
+ tempfile.close
48
+ tempfile
49
+ end
50
+
51
+ def run(command)
52
+ log.debug("Running command: #{command}") if log_commands
53
+ begin
54
+ result = `#{command}`
55
+ rescue Errno::ENOENT
56
+ raise_shell_command_failed(command)
57
+ end
58
+ if $?.exitstatus == 1
59
+ throw :unable_to_handle
60
+ elsif !$?.success?
61
+ raise_shell_command_failed(command)
62
+ end
63
+ result
64
+ end
65
+
66
+ def raise_shell_command_failed(command)
67
+ raise ShellCommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
68
+ end
69
+
70
+ end
71
+ end
72
+ end