fog-dragonfly 0.8.1

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

Potentially problematic release.


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

Files changed (155) hide show
  1. data/.specopts +2 -0
  2. data/.yardopts +23 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.rails.2.3.5 +14 -0
  5. data/History.md +266 -0
  6. data/LICENSE +20 -0
  7. data/README.md +88 -0
  8. data/Rakefile +92 -0
  9. data/VERSION +1 -0
  10. data/config.ru +13 -0
  11. data/docs.watchr +1 -0
  12. data/dragonfly.gemspec +293 -0
  13. data/extra_docs/Analysers.md +108 -0
  14. data/extra_docs/Caching.md +23 -0
  15. data/extra_docs/Configuration.md +138 -0
  16. data/extra_docs/DataStorage.md +136 -0
  17. data/extra_docs/Encoding.md +96 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +102 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/Index.md +36 -0
  22. data/extra_docs/MimeTypes.md +40 -0
  23. data/extra_docs/Models.md +266 -0
  24. data/extra_docs/Mongo.md +45 -0
  25. data/extra_docs/Processing.md +130 -0
  26. data/extra_docs/Rack.md +52 -0
  27. data/extra_docs/Rails2.md +55 -0
  28. data/extra_docs/Rails3.md +62 -0
  29. data/extra_docs/Sinatra.md +25 -0
  30. data/extra_docs/URLs.md +169 -0
  31. data/features/3.0.3.feature +8 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_2.3.5.feature +7 -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 +39 -0
  38. data/features/support/env.rb +40 -0
  39. data/fixtures/files/app/models/album.rb +3 -0
  40. data/fixtures/files/app/views/albums/new.html.erb +4 -0
  41. data/fixtures/files/app/views/albums/show.html.erb +4 -0
  42. data/fixtures/files/config/initializers/dragonfly.rb +4 -0
  43. data/fixtures/files/features/manage_album_images.feature +12 -0
  44. data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
  45. data/fixtures/files/features/support/paths.rb +15 -0
  46. data/fixtures/files/features/text_images.feature +7 -0
  47. data/fixtures/rails_2.3.5/template.rb +10 -0
  48. data/fixtures/rails_3.0.3/template.rb +20 -0
  49. data/irbrc.rb +17 -0
  50. data/lib/dragonfly.rb +45 -0
  51. data/lib/dragonfly/active_model_extensions.rb +13 -0
  52. data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
  53. data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
  54. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  55. data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
  56. data/lib/dragonfly/analyser.rb +59 -0
  57. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  58. data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
  59. data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
  60. data/lib/dragonfly/app.rb +182 -0
  61. data/lib/dragonfly/config/heroku.rb +19 -0
  62. data/lib/dragonfly/config/image_magick.rb +41 -0
  63. data/lib/dragonfly/config/r_magick.rb +46 -0
  64. data/lib/dragonfly/config/rails.rb +17 -0
  65. data/lib/dragonfly/configurable.rb +119 -0
  66. data/lib/dragonfly/core_ext/object.rb +8 -0
  67. data/lib/dragonfly/core_ext/string.rb +9 -0
  68. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  69. data/lib/dragonfly/data_storage.rb +9 -0
  70. data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
  71. data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
  72. data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
  73. data/lib/dragonfly/encoder.rb +13 -0
  74. data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
  75. data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
  76. data/lib/dragonfly/function_manager.rb +69 -0
  77. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
  78. data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
  79. data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/image_magick_utils.rb +81 -0
  82. data/lib/dragonfly/job.rb +371 -0
  83. data/lib/dragonfly/job_builder.rb +39 -0
  84. data/lib/dragonfly/job_definitions.rb +26 -0
  85. data/lib/dragonfly/job_endpoint.rb +15 -0
  86. data/lib/dragonfly/loggable.rb +28 -0
  87. data/lib/dragonfly/middleware.rb +34 -0
  88. data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
  89. data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
  90. data/lib/dragonfly/processor.rb +9 -0
  91. data/lib/dragonfly/r_magick_utils.rb +48 -0
  92. data/lib/dragonfly/rails/images.rb +22 -0
  93. data/lib/dragonfly/response.rb +82 -0
  94. data/lib/dragonfly/routed_endpoint.rb +40 -0
  95. data/lib/dragonfly/serializer.rb +32 -0
  96. data/lib/dragonfly/simple_cache.rb +23 -0
  97. data/lib/dragonfly/simple_endpoint.rb +63 -0
  98. data/lib/dragonfly/temp_object.rb +220 -0
  99. data/samples/beach.png +0 -0
  100. data/samples/egg.png +0 -0
  101. data/samples/round.gif +0 -0
  102. data/samples/sample.docx +0 -0
  103. data/samples/taj.jpg +0 -0
  104. data/spec/argument_matchers.rb +19 -0
  105. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  106. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  107. data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
  108. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  109. data/spec/dragonfly/analyser_spec.rb +123 -0
  110. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
  111. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
  112. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
  113. data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
  114. data/spec/dragonfly/app_spec.rb +280 -0
  115. data/spec/dragonfly/config/r_magick_spec.rb +25 -0
  116. data/spec/dragonfly/configurable_spec.rb +220 -0
  117. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  118. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  119. data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
  120. data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
  121. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
  122. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
  123. data/spec/dragonfly/deprecation_spec.rb +20 -0
  124. data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
  125. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
  126. data/spec/dragonfly/function_manager_spec.rb +154 -0
  127. data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
  128. data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
  129. data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
  130. data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
  131. data/spec/dragonfly/image_magick_utils_spec.rb +16 -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 +120 -0
  135. data/spec/dragonfly/job_spec.rb +773 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +68 -0
  138. data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
  139. data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
  140. data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
  141. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  142. data/spec/dragonfly/serializer_spec.rb +61 -0
  143. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  144. data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
  145. data/spec/dragonfly/temp_object_spec.rb +352 -0
  146. data/spec/image_matchers.rb +47 -0
  147. data/spec/simple_matchers.rb +44 -0
  148. data/spec/spec_helper.rb +58 -0
  149. data/yard/handlers/configurable_attr_handler.rb +38 -0
  150. data/yard/setup.rb +15 -0
  151. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  152. data/yard/templates/default/layout/html/layout.erb +87 -0
  153. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  154. data/yard/templates/default/module/setup.rb +17 -0
  155. metadata +550 -0
@@ -0,0 +1,115 @@
1
+ require 'fog'
2
+
3
+ module Dragonfly
4
+ module DataStorage
5
+
6
+ class S3DataStore
7
+
8
+ include Configurable
9
+ include Serializer
10
+
11
+ # Available options are defined in Fog Storage[http://github.com/geemus/fog/blob/master/lib/fog/aws/storage.rb]
12
+ #
13
+ # 'eu-west-1' => 's3-eu-west-1.amazonaws.com'
14
+ # 'us-east-1' => 's3.amazonaws.com'
15
+ # 'ap-southeast-1' => 's3-ap-southeast-1.amazonaws.com'
16
+ # 'us-west-1' => 's3-us-west-1.amazonaws.com'
17
+
18
+ configurable_attr :bucket_name
19
+ configurable_attr :access_key_id
20
+ configurable_attr :secret_access_key
21
+ configurable_attr :region
22
+ configurable_attr :specific_uid
23
+ configurable_attr :use_filesystem, true
24
+ configurable_attr :autocreate_bucket, false
25
+
26
+ def initialize(opts={})
27
+ self.bucket_name = opts[:bucket_name]
28
+ self.access_key_id = opts[:access_key_id]
29
+ self.secret_access_key = opts[:secret_access_key]
30
+ end
31
+
32
+ def connection
33
+ @connection ||= Fog::AWS::Storage.new(
34
+ :aws_access_key_id => access_key_id,
35
+ :aws_secret_access_key => secret_access_key,
36
+ :region => region
37
+ )
38
+ end
39
+
40
+ def create_bucket!
41
+ connection.put_bucket(bucket_name) unless bucket_names.include?(bucket_name)
42
+ end
43
+
44
+ def store(temp_object, opts={})
45
+ uid = opts[:path] || generate_uid(temp_object.name || 'file')
46
+ ensure_initialized
47
+ extra_data = temp_object.attributes
48
+ if use_filesystem
49
+ temp_object.file do |f|
50
+ connection.put_object(bucket_name,
51
+ uid,
52
+ f.read,
53
+ s3_metadata_for(extra_data))
54
+ end
55
+ else
56
+ connection.put_object(bucket_name,
57
+ uid,
58
+ temp_object.data,
59
+ s3_metadata_for(extra_data))
60
+ end
61
+ uid
62
+ end
63
+
64
+ def retrieve(uid)
65
+ ensure_initialized
66
+ s3_object = connection.get_object(bucket_name, uid)
67
+ [
68
+ s3_object.body,
69
+ parse_s3_metadata(s3_object.headers)
70
+ ]
71
+ rescue Excon::Errors::NotFound => e
72
+ raise DataNotFound, "#{e} - #{uid}"
73
+ end
74
+
75
+ def destroy(uid)
76
+ ensure_initialized
77
+ connection.delete_object(bucket_name, uid)
78
+ rescue Excon::Errors::NotFound => e
79
+ raise DataNotFound, "#{e} - #{uid}"
80
+ end
81
+
82
+ private
83
+
84
+ def bucket_names
85
+ connection.get_service.body['Buckets'].map{|bucket| bucket['Name'] }
86
+ end
87
+
88
+ def ensure_initialized
89
+ unless @initialized
90
+ create_bucket! if autocreate_bucket
91
+ @initialized = true
92
+ end
93
+ end
94
+
95
+ def generate_uid(name)
96
+ if self.specific_uid.is_a?(Proc)
97
+ self.specific_uid.call(name)
98
+ else
99
+ "#{Time.now.strftime '%Y/%m/%d/%H/%M/%S'}/#{rand(1000)}/#{name.gsub(/[^\w.]+/, '_')}"
100
+ end
101
+ end
102
+
103
+ def s3_metadata_for(extra_data)
104
+ {'x-amz-meta-extra' => marshal_encode(extra_data)}
105
+ end
106
+
107
+ def parse_s3_metadata(metadata)
108
+ extra_data = metadata['x-amz-meta-extra']
109
+ marshal_decode(extra_data) if extra_data
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+ end
@@ -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,57 @@
1
+ module Dragonfly
2
+ module Encoding
3
+ class ImageMagickEncoder
4
+
5
+ include Configurable
6
+ include ImageMagickUtils
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,61 @@
1
+ require 'RMagick'
2
+
3
+ module Dragonfly
4
+ module Encoding
5
+ class RMagickEncoder
6
+
7
+ include Configurable
8
+ include RMagickUtils
9
+
10
+ configurable_attr :supported_formats, [
11
+ :ai,
12
+ :bmp,
13
+ :eps,
14
+ :gif,
15
+ :gif87,
16
+ :ico,
17
+ :j2c,
18
+ :jp2,
19
+ :jpeg,
20
+ :jpg,
21
+ :pbm,
22
+ :pcd,
23
+ :pct,
24
+ :pcx,
25
+ :pdf,
26
+ :pict,
27
+ :pjpeg,
28
+ :png,
29
+ :png24,
30
+ :png32,
31
+ :png8,
32
+ :pnm,
33
+ :ppm,
34
+ :ps,
35
+ :psd,
36
+ :ras,
37
+ :tga,
38
+ :tiff,
39
+ :wbmp,
40
+ :xbm,
41
+ :xpm,
42
+ :xwd
43
+ ]
44
+ configurable_attr :use_filesystem, true
45
+
46
+ def encode(temp_object, format, encoding={})
47
+ format = format.to_s.downcase
48
+ 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
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,69 @@
1
+ module Dragonfly
2
+ class FunctionManager
3
+
4
+ # Exceptions
5
+ class NotDefined < NoMethodError; end
6
+ class UnableToHandle < NotImplementedError; end
7
+
8
+ include Loggable
9
+
10
+ def initialize
11
+ @functions = {}
12
+ @objects = []
13
+ end
14
+
15
+ def add(name, callable_obj=nil, &block)
16
+ functions[name] ||= []
17
+ functions[name] << (callable_obj || block)
18
+ end
19
+
20
+ attr_reader :functions, :objects
21
+
22
+ def register(klass, *args, &block)
23
+ obj = klass.new(*args)
24
+ obj.configure(&block) if block
25
+ obj.use_same_log_as(self) if obj.is_a?(Loggable)
26
+ methods_to_add(obj).each do |meth|
27
+ add meth.to_sym, obj.method(meth)
28
+ end
29
+ objects << obj
30
+ obj
31
+ end
32
+
33
+ def call_last(meth, *args)
34
+ if functions[meth.to_sym]
35
+ functions[meth.to_sym].reverse.each do |function|
36
+ catch :unable_to_handle do
37
+ return function.call(*args)
38
+ end
39
+ end
40
+ # If the code gets here, then none of the registered functions were able to handle the method call
41
+ raise UnableToHandle, "None of the functions registered with #{self} were able to deal with the method call " +
42
+ "#{meth}(#{args.map{|a| a.inspect[0..100]}.join(',')}). You may need to register one that can."
43
+ else
44
+ raise NotDefined, "function #{meth} not registered with #{self}"
45
+ end
46
+ end
47
+
48
+ def get_registered(klass)
49
+ objects.reverse.detect{|o| o.instance_of?(klass) }
50
+ end
51
+
52
+ def inspect
53
+ to_s.sub(/>$/, " with functions: #{functions.keys.map{|k| k.to_s }.sort.join(', ')} >")
54
+ end
55
+
56
+ private
57
+
58
+ def methods_to_add(obj)
59
+ if obj.is_a?(Configurable)
60
+ obj.public_methods(false) -
61
+ obj.configuration_methods.map{|meth| meth.to_method_name} -
62
+ [:configuration_methods.to_method_name]
63
+ else
64
+ obj.public_methods(false)
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,23 @@
1
+ module Dragonfly
2
+ module Generation
3
+
4
+ # HashWithCssStyleKeys is solely for being able to access a hash
5
+ # which has css-style keys (e.g. 'font-size') with the underscore
6
+ # symbol version
7
+ # @example
8
+ # opts = {'font-size' => '23px', :color => 'white'}
9
+ # opts = HashWithCssStyleKeys[opts]
10
+ # opts[:font_size] # ===> '23px'
11
+ # opts[:color] # ===> 'white'
12
+ class HashWithCssStyleKeys < Hash
13
+ def [](key)
14
+ super || (
15
+ str_key = key.to_s
16
+ css_key = str_key.gsub('_','-')
17
+ super(str_key) || super(css_key) || super(css_key.to_sym)
18
+ )
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,140 @@
1
+ module Dragonfly
2
+ module Generation
3
+ class ImageMagickGenerator
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 ImageMagickUtils
40
+ include Configurable
41
+
42
+ def plasma(width, height, format='png')
43
+ tempfile = new_tempfile(format)
44
+ run "#{convert_command} -size #{width}x#{height} plasma:fractal #{tempfile.path}"
45
+ [
46
+ tempfile,
47
+ {:format => format.to_sym, :name => "plasma.#{format}"}
48
+ ]
49
+ end
50
+
51
+ def text(string, opts={})
52
+ opts = HashWithCssStyleKeys[opts]
53
+ args = []
54
+ format = (opts[:format] || :png)
55
+ background = opts[:background_color] || 'none'
56
+ font_size = (opts[:font_size] || 12).to_i
57
+ escaped_string = "\"#{string.gsub(/"/, '\"')}\""
58
+
59
+ # Settings
60
+ args.push("-gravity NorthWest")
61
+ args.push("-antialias")
62
+ args.push("-pointsize #{font_size}")
63
+ args.push("-font '#{opts[:font]}'") if opts[:font]
64
+ args.push("-family '#{opts[:font_family]}'") if opts[:font_family]
65
+ args.push("-fill #{opts[:color]}") if opts[:color]
66
+ args.push("-stroke #{opts[:stroke_color]}") if opts[:stroke_color]
67
+ args.push("-style #{FONT_STYLES[opts[:font_style]]}") if opts[:font_style]
68
+ args.push("-stretch #{FONT_STRETCHES[opts[:font_stretch]]}") if opts[:font_stretch]
69
+ args.push("-weight #{FONT_WEIGHTS[opts[:font_weight]]}") if opts[:font_weight]
70
+ args.push("-background #{background}")
71
+ args.push("label:#{escaped_string}")
72
+
73
+ # Padding
74
+ pt, pr, pb, pl = parse_padding_string(opts[:padding]) if opts[:padding]
75
+ padding_top = (opts[:padding_top] || pt || 0)
76
+ padding_right = (opts[:padding_right] || pr || 0)
77
+ padding_bottom = (opts[:padding_bottom] || pb || 0)
78
+ padding_left = (opts[:padding_left] || pl || 0)
79
+
80
+ tempfile = new_tempfile(format)
81
+ run "#{convert_command} #{args.join(' ')} #{tempfile.path}"
82
+
83
+ if (padding_top || padding_right || padding_bottom || padding_left)
84
+ attrs = identify(tempfile)
85
+ text_width = attrs[:width].to_i
86
+ text_height = attrs[:height].to_i
87
+ width = padding_left + text_width + padding_right
88
+ height = padding_top + text_height + padding_bottom
89
+
90
+ args = args.slice(0, args.length - 2)
91
+ args.push("-size #{width}x#{height}")
92
+ args.push("xc:#{background}")
93
+ args.push("-annotate 0x0+#{padding_left}+#{padding_top} #{escaped_string}")
94
+ run "#{convert_command} #{args.join(' ')} #{tempfile.path}"
95
+ end
96
+
97
+ [
98
+ tempfile,
99
+ {:format => format, :name => "text.#{format}"}
100
+ ]
101
+ end
102
+
103
+ private
104
+
105
+ # Use css-style padding declaration, i.e.
106
+ # 10 (all sides)
107
+ # 10 5 (top/bottom, left/right)
108
+ # 10 5 10 (top, left/right, bottom)
109
+ # 10 5 10 5 (top, right, bottom, left)
110
+ def parse_padding_string(str)
111
+ padding_parts = str.gsub('px','').split(/\s+/).map{|px| px.to_i}
112
+ case padding_parts.size
113
+ when 1
114
+ p = padding_parts.first
115
+ [p,p,p,p]
116
+ when 2
117
+ p,q = padding_parts
118
+ [p,q,p,q]
119
+ when 3
120
+ p,q,r = padding_parts
121
+ [p,q,r,q]
122
+ when 4
123
+ padding_parts
124
+ else raise ArgumentError, "Couldn't parse padding string '#{str}' - should be a css-style string"
125
+ end
126
+ end
127
+
128
+ def scale_factor_for(font_size)
129
+ # Scale approximately to 64 if below
130
+ min_size = 64
131
+ if font_size < min_size
132
+ (min_size.to_f / font_size).ceil
133
+ else
134
+ 1
135
+ end.to_f
136
+ end
137
+
138
+ end
139
+ end
140
+ end