oahu-dragonfly 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/.rspec +1 -0
  2. data/.yardopts +24 -0
  3. data/Gemfile +30 -0
  4. data/History.md +323 -0
  5. data/LICENSE +20 -0
  6. data/README.md +88 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/config.ru +14 -0
  10. data/docs.watchr +1 -0
  11. data/dragonfly.gemspec +297 -0
  12. data/extra_docs/Analysers.md +66 -0
  13. data/extra_docs/Caching.md +23 -0
  14. data/extra_docs/Configuration.md +124 -0
  15. data/extra_docs/Couch.md +49 -0
  16. data/extra_docs/DataStorage.md +153 -0
  17. data/extra_docs/Encoding.md +67 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +60 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/ImageMagick.md +125 -0
  22. data/extra_docs/Index.md +33 -0
  23. data/extra_docs/MimeTypes.md +40 -0
  24. data/extra_docs/Models.md +272 -0
  25. data/extra_docs/Mongo.md +45 -0
  26. data/extra_docs/Processing.md +77 -0
  27. data/extra_docs/Rack.md +52 -0
  28. data/extra_docs/Rails2.md +57 -0
  29. data/extra_docs/Rails3.md +62 -0
  30. data/extra_docs/Sinatra.md +25 -0
  31. data/extra_docs/URLs.md +169 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_3.0.5.feature +8 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +28 -0
  38. data/features/support/env.rb +13 -0
  39. data/features/support/setup.rb +32 -0
  40. data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
  41. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  42. data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
  43. data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
  44. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  45. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  46. data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
  47. data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
  48. data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
  49. data/fixtures/rails_3.0.5/template.rb +20 -0
  50. data/irbrc.rb +18 -0
  51. data/lib/dragonfly.rb +55 -0
  52. data/lib/dragonfly/active_model_extensions.rb +13 -0
  53. data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
  54. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
  55. data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
  56. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  57. data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
  58. data/lib/dragonfly/analyser.rb +58 -0
  59. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  60. data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
  61. data/lib/dragonfly/app.rb +172 -0
  62. data/lib/dragonfly/config/heroku.rb +19 -0
  63. data/lib/dragonfly/config/image_magick.rb +6 -0
  64. data/lib/dragonfly/config/rails.rb +20 -0
  65. data/lib/dragonfly/configurable.rb +207 -0
  66. data/lib/dragonfly/core_ext/array.rb +7 -0
  67. data/lib/dragonfly/core_ext/hash.rb +7 -0
  68. data/lib/dragonfly/core_ext/object.rb +12 -0
  69. data/lib/dragonfly/core_ext/string.rb +9 -0
  70. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  71. data/lib/dragonfly/data_storage.rb +9 -0
  72. data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
  73. data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
  74. data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
  75. data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
  76. data/lib/dragonfly/encoder.rb +13 -0
  77. data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
  78. data/lib/dragonfly/function_manager.rb +71 -0
  79. data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  82. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  83. data/lib/dragonfly/image_magick/config.rb +41 -0
  84. data/lib/dragonfly/image_magick/encoder.rb +57 -0
  85. data/lib/dragonfly/image_magick/generator.rb +145 -0
  86. data/lib/dragonfly/image_magick/processor.rb +99 -0
  87. data/lib/dragonfly/image_magick/utils.rb +72 -0
  88. data/lib/dragonfly/image_magick_utils.rb +4 -0
  89. data/lib/dragonfly/job.rb +451 -0
  90. data/lib/dragonfly/job_builder.rb +39 -0
  91. data/lib/dragonfly/job_definitions.rb +26 -0
  92. data/lib/dragonfly/job_endpoint.rb +15 -0
  93. data/lib/dragonfly/loggable.rb +28 -0
  94. data/lib/dragonfly/middleware.rb +20 -0
  95. data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
  96. data/lib/dragonfly/processor.rb +9 -0
  97. data/lib/dragonfly/rails/images.rb +27 -0
  98. data/lib/dragonfly/response.rb +97 -0
  99. data/lib/dragonfly/routed_endpoint.rb +40 -0
  100. data/lib/dragonfly/serializer.rb +32 -0
  101. data/lib/dragonfly/server.rb +113 -0
  102. data/lib/dragonfly/simple_cache.rb +23 -0
  103. data/lib/dragonfly/temp_object.rb +175 -0
  104. data/lib/dragonfly/url_mapper.rb +78 -0
  105. data/samples/beach.png +0 -0
  106. data/samples/egg.png +0 -0
  107. data/samples/round.gif +0 -0
  108. data/samples/sample.docx +0 -0
  109. data/samples/taj.jpg +0 -0
  110. data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
  111. data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
  112. data/spec/dragonfly/analyser_spec.rb +123 -0
  113. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
  114. data/spec/dragonfly/app_spec.rb +135 -0
  115. data/spec/dragonfly/configurable_spec.rb +461 -0
  116. data/spec/dragonfly/core_ext/array_spec.rb +19 -0
  117. data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
  118. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  119. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  120. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
  121. data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
  122. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
  123. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
  124. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
  125. data/spec/dragonfly/function_manager_spec.rb +154 -0
  126. data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
  127. data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
  128. data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
  129. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  130. data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
  131. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +173 -0
  135. data/spec/dragonfly/job_spec.rb +1046 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +47 -0
  138. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  139. data/spec/dragonfly/serializer_spec.rb +61 -0
  140. data/spec/dragonfly/server_spec.rb +278 -0
  141. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  142. data/spec/dragonfly/temp_object_spec.rb +306 -0
  143. data/spec/dragonfly/url_mapper_spec.rb +126 -0
  144. data/spec/functional/deprecations_spec.rb +51 -0
  145. data/spec/functional/image_magick_app_spec.rb +27 -0
  146. data/spec/functional/model_urls_spec.rb +85 -0
  147. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  148. data/spec/functional/to_response_spec.rb +31 -0
  149. data/spec/spec_helper.rb +51 -0
  150. data/spec/support/argument_matchers.rb +19 -0
  151. data/spec/support/image_matchers.rb +47 -0
  152. data/spec/support/simple_matchers.rb +53 -0
  153. data/yard/handlers/configurable_attr_handler.rb +38 -0
  154. data/yard/setup.rb +15 -0
  155. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  156. data/yard/templates/default/layout/html/layout.erb +89 -0
  157. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  158. data/yard/templates/default/module/setup.rb +17 -0
  159. metadata +544 -0
@@ -0,0 +1,13 @@
1
+ module Dragonfly
2
+ class Encoder < FunctionManager
3
+
4
+ def add(name=:encode, callable_obj=nil, &block)
5
+ super(name, callable_obj, &block)
6
+ end
7
+
8
+ def encode(temp_object, *args)
9
+ call_last(:encode, temp_object, *args)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Dragonfly
2
+ module Encoding
3
+ puts "WARNING: Dragonfly::Encoding::ImageMagickEncoder is DEPRECATED and will soon be removed. Please use Dragonfly::ImageMagick::Encoder instead."
4
+ ImageMagickEncoder = ImageMagick::Encoder
5
+ end
6
+ end
@@ -0,0 +1,71 @@
1
+ module Dragonfly
2
+ class FunctionManager
3
+
4
+ # Exceptions
5
+ class NotDefined < NoMethodError; end
6
+ class UnableToHandle < NotImplementedError; end
7
+
8
+ include Loggable
9
+ include Configurable
10
+
11
+ def initialize
12
+ @functions = {}
13
+ @objects = []
14
+ end
15
+
16
+ def add(name, callable_obj=nil, &block)
17
+ functions[name] ||= []
18
+ functions[name] << (callable_obj || block)
19
+ end
20
+
21
+ attr_reader :functions, :objects
22
+
23
+ def register(klass, *args, &block)
24
+ obj = klass.new(*args)
25
+ obj.configure(&block) if block
26
+ obj.use_same_log_as(self) if obj.is_a?(Loggable)
27
+ obj.use_as_fallback_config(self) if obj.is_a?(Configurable)
28
+ methods_to_add(obj).each do |meth|
29
+ add meth.to_sym, obj.method(meth)
30
+ end
31
+ objects << obj
32
+ obj
33
+ end
34
+
35
+ def call_last(meth, *args)
36
+ if functions[meth.to_sym]
37
+ functions[meth.to_sym].reverse.each do |function|
38
+ catch :unable_to_handle do
39
+ return function.call(*args)
40
+ end
41
+ end
42
+ # If the code gets here, then none of the registered functions were able to handle the method call
43
+ raise UnableToHandle, "None of the functions registered with #{self} were able to deal with the method call " +
44
+ "#{meth}(#{args.map{|a| a.inspect[0..100]}.join(',')}). You may need to register one that can."
45
+ else
46
+ raise NotDefined, "function #{meth} not registered with #{self}"
47
+ end
48
+ end
49
+
50
+ def get_registered(klass)
51
+ objects.reverse.detect{|o| o.instance_of?(klass) }
52
+ end
53
+
54
+ def inspect
55
+ to_s.sub(/>$/, " with functions: #{functions.keys.map{|k| k.to_s }.sort.join(', ')} >")
56
+ end
57
+
58
+ private
59
+
60
+ def methods_to_add(obj)
61
+ if obj.is_a?(Configurable)
62
+ obj.public_methods(false) -
63
+ obj.config_methods.map{|meth| meth.to_method_name} -
64
+ [:configured_class.to_method_name] # Hacky - there must be a better way...
65
+ else
66
+ obj.public_methods(false)
67
+ end
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,6 @@
1
+ module Dragonfly
2
+ module Generation
3
+ puts "WARNING: Dragonfly::Generation::ImageMagickGenerator is DEPRECATED and will soon be removed. Please use Dragonfly::ImageMagick::Generator instead."
4
+ ImageMagickGenerator = ImageMagick::Generator
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Dragonfly
2
+ class Generator < FunctionManager
3
+
4
+ def generate(method, *args)
5
+ call_last(method, *args)
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Dragonfly
2
+
3
+ # HashWithCssStyleKeys is solely for being able to access a hash
4
+ # which has css-style keys (e.g. 'font-size') with the underscore
5
+ # symbol version
6
+ # @example
7
+ # opts = {'font-size' => '23px', :color => 'white'}
8
+ # opts = HashWithCssStyleKeys[opts]
9
+ # opts[:font_size] # ===> '23px'
10
+ # opts[:color] # ===> 'white'
11
+ class HashWithCssStyleKeys < Hash
12
+ def [](key)
13
+ super || (
14
+ str_key = key.to_s
15
+ css_key = str_key.gsub('_','-')
16
+ super(str_key) || super(css_key) || super(css_key.to_sym)
17
+ )
18
+ end
19
+ end
20
+
21
+ end
@@ -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,41 @@
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 :convert do |args, format|
33
+ process :convert, args, format
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ module Dragonfly
2
+ module ImageMagick
3
+ class Encoder
4
+
5
+ include Configurable
6
+ include Utils
7
+
8
+ configurable_attr :supported_formats, [
9
+ :ai,
10
+ :bmp,
11
+ :eps,
12
+ :gif,
13
+ :gif87,
14
+ :ico,
15
+ :j2c,
16
+ :jp2,
17
+ :jpeg,
18
+ :jpg,
19
+ :pbm,
20
+ :pcd,
21
+ :pct,
22
+ :pcx,
23
+ :pdf,
24
+ :pict,
25
+ :pjpeg,
26
+ :png,
27
+ :png24,
28
+ :png32,
29
+ :png8,
30
+ :pnm,
31
+ :ppm,
32
+ :ps,
33
+ :psd,
34
+ :ras,
35
+ :tga,
36
+ :tiff,
37
+ :wbmp,
38
+ :xbm,
39
+ :xpm,
40
+ :xwd
41
+ ]
42
+
43
+ def encode(temp_object, format, args='')
44
+ format = format.to_s.downcase
45
+ throw :unable_to_handle unless supported_formats.include?(format.to_sym)
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)
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -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,99 @@
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
+
38
+ convert(temp_object, "-crop #{width}x#{height}#{x}#{y}#{" -gravity #{gravity}" if gravity}")
39
+ end
40
+
41
+ def flip(temp_object)
42
+ convert(temp_object, "-flip")
43
+ end
44
+
45
+ def flop(temp_object)
46
+ convert(temp_object, "-flop")
47
+ end
48
+
49
+ def greyscale(temp_object)
50
+ convert(temp_object, "-colorspace Gray")
51
+ end
52
+ alias grayscale greyscale
53
+
54
+ def resize_and_crop(temp_object, opts={})
55
+ attrs = identify(temp_object)
56
+ current_width = attrs[:width].to_i
57
+ current_height = attrs[:height].to_i
58
+
59
+ width = opts[:width] ? opts[:width].to_i : current_width
60
+ height = opts[:height] ? opts[:height].to_i : current_height
61
+ gravity = opts[:gravity] || 'c'
62
+
63
+ if width != current_width || height != current_height
64
+ scale = [width.to_f / current_width, height.to_f / current_height].max
65
+ temp_object = TempObject.new(resize(temp_object, "#{(scale * current_width).ceil}x#{(scale * current_height).ceil}"))
66
+ end
67
+
68
+ crop(temp_object, :width => width, :height => height, :gravity => gravity)
69
+ end
70
+
71
+ def rotate(temp_object, amount, opts={})
72
+ convert(temp_object, "-rotate '#{amount}#{opts[:qualifier]}'")
73
+ end
74
+
75
+ def thumb(temp_object, geometry)
76
+ case geometry
77
+ when RESIZE_GEOMETRY
78
+ resize(temp_object, geometry)
79
+ when CROPPED_RESIZE_GEOMETRY
80
+ resize_and_crop(temp_object, :width => $1, :height => $2, :gravity => $3)
81
+ when CROP_GEOMETRY
82
+ crop(temp_object,
83
+ :width => $1,
84
+ :height => $2,
85
+ :x => $3,
86
+ :y => $4,
87
+ :gravity => $5
88
+ )
89
+ else raise ArgumentError, "Didn't recognise the geometry string #{geometry}"
90
+ end
91
+ end
92
+
93
+ def convert(temp_object, args='', format=nil)
94
+ format ? [super, {:format => format.to_sym}] : super
95
+ end
96
+
97
+ end
98
+ end
99
+ end