dragonfly 0.5.7 → 0.6.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.
- data/.gitignore +1 -0
- data/.yardopts +1 -0
- data/History.md +109 -0
- data/VERSION +1 -1
- data/config.rb +1 -1
- data/dragonfly.gemspec +19 -16
- data/extra_docs/ActiveRecord.md +8 -7
- data/extra_docs/Analysers.md +1 -1
- data/extra_docs/Encoding.md +1 -1
- data/extra_docs/ExampleUseCases.md +66 -73
- data/extra_docs/GettingStarted.md +1 -1
- data/extra_docs/Processing.md +1 -1
- data/extra_docs/Shortcuts.md +2 -2
- data/extra_docs/UsingWithRails.md +25 -37
- data/features/rails_2.3.5.feature +1 -8
- data/features/rails_3.0.0.beta3.feature +7 -0
- data/features/steps/rails_steps.rb +1 -11
- data/features/support/env.rb +1 -1
- data/fixtures/files/app/views/albums/show.html.erb +1 -0
- data/fixtures/files/config/initializers/{aaa_dragonfly_load_path.rb → dragonfly.rb} +1 -0
- data/fixtures/rails_2.3.5/template.rb +4 -6
- data/fixtures/rails_3.0.0.beta3/template.rb +16 -0
- data/lib/dragonfly.rb +23 -1
- data/lib/dragonfly/active_record_extensions/attachment.rb +1 -1
- data/lib/dragonfly/analyser_list.rb +4 -0
- data/lib/dragonfly/analysis/base.rb +1 -0
- data/lib/dragonfly/analysis/r_magick_analyser.rb +7 -0
- data/lib/dragonfly/app.rb +3 -11
- data/lib/dragonfly/belongs_to_app.rb +24 -0
- data/lib/dragonfly/config/heroku_rails_images.rb +23 -0
- data/lib/dragonfly/config/r_magick_images.rb +69 -0
- data/lib/dragonfly/config/r_magick_text.rb +25 -0
- data/lib/dragonfly/config/rails_defaults.rb +18 -0
- data/lib/dragonfly/config/rails_images.rb +13 -0
- data/lib/dragonfly/configurable.rb +4 -3
- data/lib/dragonfly/data_storage/base.rb +2 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +11 -4
- data/lib/dragonfly/delegator.rb +22 -10
- data/lib/dragonfly/encoder_list.rb +4 -0
- data/lib/dragonfly/encoding/base.rb +1 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +52 -8
- data/lib/dragonfly/extended_temp_object.rb +26 -27
- data/lib/dragonfly/processing/base.rb +1 -0
- data/lib/dragonfly/processing/r_magick_processor.rb +12 -127
- data/lib/dragonfly/processing/r_magick_text_processor.rb +155 -0
- data/lib/dragonfly/processor_list.rb +4 -0
- data/lib/dragonfly/rails/images.rb +2 -14
- data/lib/dragonfly/temp_object.rb +41 -34
- data/spec/dragonfly/active_record_extensions/migration.rb +7 -0
- data/spec/dragonfly/active_record_extensions/model_spec.rb +10 -11
- data/spec/dragonfly/active_record_extensions/spec_helper.rb +1 -1
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +14 -1
- data/spec/dragonfly/belongs_to_app_spec.rb +55 -0
- data/spec/dragonfly/configurable_spec.rb +21 -6
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +1 -0
- data/spec/dragonfly/delegator_spec.rb +23 -12
- data/spec/dragonfly/extended_temp_object_spec.rb +13 -29
- data/spec/dragonfly/processing/{rmagick_processor_spec.rb → r_magick_processor_spec.rb} +8 -75
- data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +84 -0
- data/spec/dragonfly/temp_object_spec.rb +126 -151
- data/spec/dragonfly_spec.rb +12 -0
- data/spec/ginger_scenarios.rb +2 -2
- data/spec/image_matchers.rb +2 -2
- data/yard/setup.rb +12 -2
- data/yard/templates/default/fulldoc/html/css/common.css +1 -2
- data/yard/templates/default/layout/html/layout.erb +3 -2
- metadata +21 -18
- data/History.txt +0 -75
- data/features/rails_3.0.0.beta.feature +0 -15
- data/fixtures/dragonfly_setup.rb +0 -1
- data/fixtures/rails +0 -22
- data/fixtures/rails_3.0.0.beta/template.rb +0 -13
- data/generators/dragonfly_app/USAGE +0 -16
- data/generators/dragonfly_app/dragonfly_app_generator.rb +0 -24
- data/generators/dragonfly_app/templates/initializer.erb +0 -35
- data/lib/dragonfly/r_magick_configuration.rb +0 -67
- data/spec/dragonfly/active_record_extensions/initializer.rb +0 -1
@@ -0,0 +1,25 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
module Config
|
3
|
+
|
4
|
+
module RMagickText
|
5
|
+
|
6
|
+
def self.apply_configuration(app)
|
7
|
+
app.configure do |c|
|
8
|
+
c.datastore = DataStorage::TransparentDataStore.new
|
9
|
+
c.register_analyser(Analysis::FileCommandAnalyser)
|
10
|
+
c.register_processor(Processing::RMagickTextProcessor)
|
11
|
+
c.register_encoder(Encoding::RMagickEncoder)
|
12
|
+
c.parameters.add_shortcut :text, Hash do |_, options|
|
13
|
+
{
|
14
|
+
:processing_method => :text,
|
15
|
+
:processing_options => options,
|
16
|
+
:format => :png
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
module Config
|
3
|
+
|
4
|
+
module RailsDefaults
|
5
|
+
|
6
|
+
def self.apply_configuration(app)
|
7
|
+
app.configure do |c|
|
8
|
+
c.log = ::Rails.logger
|
9
|
+
c.datastore.root_path = "#{::Rails.root}/public/system/dragonfly/#{::Rails.env}"
|
10
|
+
c.url_handler.configure do |u|
|
11
|
+
u.path_prefix = '/media'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -27,12 +27,13 @@ module Dragonfly
|
|
27
27
|
|
28
28
|
module InstanceMethods
|
29
29
|
|
30
|
-
def configure(&
|
30
|
+
def configure(&block)
|
31
31
|
yield ConfigurationProxy.new(self)
|
32
32
|
end
|
33
33
|
|
34
|
-
def configure_with(configurer)
|
35
|
-
configurer.apply_configuration(self)
|
34
|
+
def configure_with(configurer, *args, &block)
|
35
|
+
configurer.apply_configuration(self, *args)
|
36
|
+
configure(&block) if block
|
36
37
|
end
|
37
38
|
|
38
39
|
def configuration
|
@@ -6,10 +6,12 @@ module Dragonfly
|
|
6
6
|
class S3DataStore < Base
|
7
7
|
|
8
8
|
include Configurable
|
9
|
+
include AWS::S3
|
9
10
|
|
10
11
|
configurable_attr :bucket_name
|
11
12
|
configurable_attr :access_key_id
|
12
13
|
configurable_attr :secret_access_key
|
14
|
+
configurable_attr :use_filesystem, true
|
13
15
|
|
14
16
|
def connect!
|
15
17
|
AWS::S3::Base.establish_connection!(
|
@@ -19,32 +21,37 @@ module Dragonfly
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def create_bucket!
|
22
|
-
|
24
|
+
Bucket.create(bucket_name) unless bucket_names.include?(bucket_name)
|
23
25
|
end
|
24
26
|
|
25
27
|
def store(temp_object)
|
26
28
|
uid = generate_uid(temp_object.basename || 'file')
|
27
29
|
ensure_initialized
|
28
|
-
|
30
|
+
object = use_filesystem ? temp_object.file : temp_object.data
|
31
|
+
S3Object.store(uid, object, bucket_name)
|
29
32
|
uid
|
30
33
|
end
|
31
34
|
|
32
35
|
def retrieve(uid)
|
33
36
|
ensure_initialized
|
34
|
-
|
37
|
+
S3Object.value(uid, bucket_name)
|
35
38
|
rescue AWS::S3::NoSuchKey => e
|
36
39
|
raise DataNotFound, "#{e} - #{uid}"
|
37
40
|
end
|
38
41
|
|
39
42
|
def destroy(uid)
|
40
43
|
ensure_initialized
|
41
|
-
|
44
|
+
S3Object.delete(uid, bucket_name)
|
42
45
|
rescue AWS::S3::NoSuchKey => e
|
43
46
|
raise DataNotFound, "#{e} - #{uid}"
|
44
47
|
end
|
45
48
|
|
46
49
|
private
|
47
50
|
|
51
|
+
def bucket_names
|
52
|
+
Service.buckets.map{|bucket| bucket.name }
|
53
|
+
end
|
54
|
+
|
48
55
|
def ensure_initialized
|
49
56
|
unless @initialized
|
50
57
|
connect!
|
data/lib/dragonfly/delegator.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Dragonfly
|
2
2
|
module Delegator
|
3
3
|
|
4
|
+
include BelongsToApp
|
5
|
+
|
4
6
|
# This gets raised if no delegated objects are able to handle
|
5
7
|
# the method call, even though they respond to that method.
|
6
8
|
class UnableToHandle < StandardError; end
|
@@ -8,7 +10,9 @@ module Dragonfly
|
|
8
10
|
def register(klass, *args, &block)
|
9
11
|
object = klass.new(*args)
|
10
12
|
object.configure(&block) if block
|
13
|
+
object.app = self.app if app_set? && object.is_a?(BelongsToApp)
|
11
14
|
registered_objects << object
|
15
|
+
object
|
12
16
|
end
|
13
17
|
|
14
18
|
def unregister(klass)
|
@@ -23,12 +27,23 @@ module Dragonfly
|
|
23
27
|
@registered_objects ||= []
|
24
28
|
end
|
25
29
|
|
26
|
-
def
|
30
|
+
def delegate(meth, *args)
|
31
|
+
registered_objects.reverse.each do |object|
|
32
|
+
catch :unable_to_handle do
|
33
|
+
return object.send(meth, *args) if object.respond_to?(meth)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
# If the code gets here, then none of the registered objects were able to handle the method call
|
37
|
+
raise UnableToHandle, "None of the objects registered with #{self} were able to deal with the method call " +
|
38
|
+
"#{meth}(#{args.map{|a| a.inspect[0..100]}.join(',')}). You need to register one that can."
|
39
|
+
end
|
40
|
+
|
41
|
+
def delegatable_methods
|
27
42
|
registered_objects.map{|a| a.delegatable_methods }.flatten.uniq
|
28
43
|
end
|
29
44
|
|
30
|
-
def
|
31
|
-
|
45
|
+
def has_delegatable_method?(method)
|
46
|
+
delegatable_methods.include?(method.to_method_name)
|
32
47
|
end
|
33
48
|
|
34
49
|
private
|
@@ -36,14 +51,11 @@ module Dragonfly
|
|
36
51
|
attr_writer :registered_objects
|
37
52
|
|
38
53
|
def method_missing(meth, *args)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
54
|
+
if has_delegatable_method?(meth)
|
55
|
+
delegate(meth, *args)
|
56
|
+
else
|
57
|
+
super
|
43
58
|
end
|
44
|
-
raise UnableToHandle, "None of the registered objects for #{self} were able to deal with the method call " +
|
45
|
-
"#{meth}(#{args.map{|a| a.inspect[0..100]}.join(',')}), even though the method is implemented" if self.has_callable_method?(meth)
|
46
|
-
super
|
47
59
|
end
|
48
60
|
|
49
61
|
end
|
@@ -2,15 +2,50 @@ require 'RMagick'
|
|
2
2
|
|
3
3
|
module Dragonfly
|
4
4
|
module Encoding
|
5
|
-
|
5
|
+
|
6
6
|
class RMagickEncoder < Base
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
|
8
|
+
include Configurable
|
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
|
+
|
10
45
|
def encode(image, format, encoding={})
|
11
46
|
format = format.to_s.downcase
|
12
|
-
throw :unable_to_handle unless
|
13
|
-
encoded_image =
|
47
|
+
throw :unable_to_handle unless supported_formats.include?(format.to_sym)
|
48
|
+
encoded_image = rmagick_image(image)
|
14
49
|
if encoded_image.format.downcase == format
|
15
50
|
image # do nothing
|
16
51
|
else
|
@@ -18,8 +53,17 @@ module Dragonfly
|
|
18
53
|
encoded_image.to_blob
|
19
54
|
end
|
20
55
|
end
|
21
|
-
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def rmagick_image(temp_object)
|
60
|
+
Magick::Image.from_blob(temp_object.data).first
|
61
|
+
rescue Magick::ImageMagickError => e
|
62
|
+
log.warn("Unable to handle content in #{self.class} - got:\n#{e}")
|
63
|
+
throw :unable_to_handle
|
64
|
+
end
|
65
|
+
|
22
66
|
end
|
23
|
-
|
67
|
+
|
24
68
|
end
|
25
69
|
end
|
@@ -22,15 +22,16 @@ module Dragonfly
|
|
22
22
|
# temp_object.transform!('300x200', :gif) # ===> operate on self
|
23
23
|
class ExtendedTempObject < TempObject
|
24
24
|
|
25
|
-
|
26
|
-
class NotConfiguredError < RuntimeError; end
|
25
|
+
include BelongsToApp
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
def initialize(obj, app)
|
28
|
+
super(obj)
|
29
|
+
self.app = app
|
30
|
+
@cache = {}
|
30
31
|
end
|
31
32
|
|
32
33
|
def process(processing_method, *args)
|
33
|
-
self.class.new(processor.send(processing_method, self, *args))
|
34
|
+
self.class.new(processor.send(processing_method, self, *args), app)
|
34
35
|
end
|
35
36
|
|
36
37
|
def process!(processing_method, *args)
|
@@ -38,7 +39,7 @@ module Dragonfly
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def encode(*args)
|
41
|
-
self.class.new(encoder.encode(self, *args))
|
42
|
+
self.class.new(encoder.encode(self, *args), app)
|
42
43
|
end
|
43
44
|
|
44
45
|
def encode!(*args)
|
@@ -56,38 +57,40 @@ module Dragonfly
|
|
56
57
|
self
|
57
58
|
end
|
58
59
|
|
59
|
-
# As we create customly configured subclasses of this class, the console
|
60
|
-
# gives a confusing output when inspecting, so modify here
|
61
|
-
def inspect
|
62
|
-
super.sub('Class:','Custom Dragonfly::ExtendedTempObject:')
|
63
|
-
end
|
64
|
-
|
65
60
|
# Modify methods, public_methods and respond_to?, because method_missing
|
66
61
|
# allows methods from the analyser
|
67
62
|
|
68
63
|
def methods(*args)
|
69
|
-
(super + analyser.
|
64
|
+
(super + analyser.delegatable_methods).uniq
|
70
65
|
end
|
71
66
|
|
72
67
|
def public_methods(*args)
|
73
|
-
(super + analyser.
|
68
|
+
(super + analyser.delegatable_methods).uniq
|
74
69
|
end
|
75
70
|
|
76
71
|
def respond_to?(method)
|
77
|
-
super || analyser.
|
72
|
+
super || analyser.has_delegatable_method?(method)
|
78
73
|
end
|
79
74
|
|
80
75
|
private
|
76
|
+
|
77
|
+
attr_reader :cache
|
81
78
|
|
79
|
+
def flush_cache!
|
80
|
+
@cache = {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def reset!
|
84
|
+
super
|
85
|
+
flush_cache!
|
86
|
+
end
|
87
|
+
|
82
88
|
def method_missing(method, *args, &block)
|
83
|
-
if analyser.
|
84
|
-
# Define the method so we don't use method_missing next time
|
85
|
-
|
86
|
-
self.class.class_eval do
|
89
|
+
if analyser.has_delegatable_method?(method)
|
90
|
+
# Define the method on the instance so we don't use method_missing next time
|
91
|
+
class << self; self; end.class_eval do
|
87
92
|
define_method method do
|
88
|
-
|
89
|
-
# @width ||= analyser.width(self)
|
90
|
-
instance_variable_set(instance_var, instance_variable_get(instance_var) || analyser.send(method, self))
|
93
|
+
cache[method] ||= analyser.delegate(method, self)
|
91
94
|
end
|
92
95
|
end
|
93
96
|
# Now that it's defined (for next time)
|
@@ -97,10 +100,6 @@ module Dragonfly
|
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
100
|
-
def app
|
101
|
-
self.class.app ? self.class.app : raise(NotConfiguredError, "#{self.class} has no app set")
|
102
|
-
end
|
103
|
-
|
104
103
|
def analyser
|
105
104
|
app.analysers
|
106
105
|
end
|
@@ -116,6 +115,6 @@ module Dragonfly
|
|
116
115
|
def parameters_class
|
117
116
|
app.parameters_class
|
118
117
|
end
|
119
|
-
|
118
|
+
|
120
119
|
end
|
121
120
|
end
|
@@ -2,7 +2,6 @@ require 'RMagick'
|
|
2
2
|
|
3
3
|
module Dragonfly
|
4
4
|
module Processing
|
5
|
-
|
6
5
|
class RMagickProcessor < Base
|
7
6
|
|
8
7
|
GRAVITIES = {
|
@@ -16,60 +15,13 @@ module Dragonfly
|
|
16
15
|
's' => Magick::SouthGravity,
|
17
16
|
'se' => Magick::SouthEastGravity
|
18
17
|
}
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
25
|
-
|
26
|
-
FONT_STRETCHES = {
|
27
|
-
'normal' => Magick::NormalStretch,
|
28
|
-
'semi-condensed' => Magick::SemiCondensedStretch,
|
29
|
-
'condensed' => Magick::CondensedStretch,
|
30
|
-
'extra-condensed' => Magick::ExtraCondensedStretch,
|
31
|
-
'ultra-condensed' => Magick::UltraCondensedStretch,
|
32
|
-
'semi-expanded' => Magick::SemiExpandedStretch,
|
33
|
-
'expanded' => Magick::ExpandedStretch,
|
34
|
-
'extra-expanded' => Magick::ExtraExpandedStretch,
|
35
|
-
'ultra-expanded' => Magick::UltraExpandedStretch
|
36
|
-
}
|
37
|
-
|
38
|
-
FONT_WEIGHTS = {
|
39
|
-
'normal' => Magick::NormalWeight,
|
40
|
-
'bold' => Magick::BoldWeight,
|
41
|
-
'bolder' => Magick::BolderWeight,
|
42
|
-
'lighter' => Magick::LighterWeight,
|
43
|
-
'100' => 100,
|
44
|
-
'200' => 200,
|
45
|
-
'300' => 300,
|
46
|
-
'400' => 400,
|
47
|
-
'500' => 500,
|
48
|
-
'600' => 600,
|
49
|
-
'700' => 700,
|
50
|
-
'800' => 800,
|
51
|
-
'900' => 900
|
52
|
-
}
|
53
|
-
|
54
|
-
# HashWithCssStyleKeys is solely for being able to access a hash
|
55
|
-
# which has css-style keys (e.g. 'font-size') with the underscore
|
56
|
-
# symbol version
|
57
|
-
# @example
|
58
|
-
# opts = {'font-size' => '23px', :color => 'white'}
|
59
|
-
# opts = HashWithCssStyleKeys[opts]
|
60
|
-
# opts[:font_size] # ===> '23px'
|
61
|
-
# opts[:color] # ===> 'white'
|
62
|
-
class HashWithCssStyleKeys < Hash
|
63
|
-
def [](key)
|
64
|
-
super || (
|
65
|
-
str_key = key.to_s
|
66
|
-
css_key = str_key.gsub('_','-')
|
67
|
-
super(str_key) || super(css_key) || super(css_key.to_sym)
|
68
|
-
)
|
69
|
-
end
|
18
|
+
|
19
|
+
def generate(width, height, format='png')
|
20
|
+
image = Magick::Image.read("plasma:fractal"){self.size = "#{width}x#{height}"}.first
|
21
|
+
image.format = format.to_s
|
22
|
+
image.to_blob
|
70
23
|
end
|
71
24
|
|
72
|
-
|
73
25
|
# Processing methods
|
74
26
|
|
75
27
|
def crop(temp_object, opts={})
|
@@ -89,11 +41,11 @@ module Dragonfly
|
|
89
41
|
image.crop(gravity, x, y, width, height).to_blob
|
90
42
|
end
|
91
43
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
image.to_blob
|
44
|
+
def greyscale(temp_object, opts={})
|
45
|
+
depth = opts[:depth] || 256
|
46
|
+
rmagick_image(temp_object).quantize(depth, Magick::GRAYColorspace).to_blob
|
96
47
|
end
|
48
|
+
alias grayscale greyscale
|
97
49
|
|
98
50
|
def resize(temp_object, opts={})
|
99
51
|
rmagick_image(temp_object).change_geometry!(opts[:geometry]) do |cols, rows, img|
|
@@ -124,52 +76,6 @@ module Dragonfly
|
|
124
76
|
temp_object
|
125
77
|
end
|
126
78
|
end
|
127
|
-
|
128
|
-
def text(temp_object, opts={})
|
129
|
-
opts = HashWithCssStyleKeys[opts]
|
130
|
-
|
131
|
-
draw = Magick::Draw.new
|
132
|
-
draw.gravity = Magick::CenterGravity
|
133
|
-
draw.text_antialias = true
|
134
|
-
|
135
|
-
# Settings
|
136
|
-
draw.font = opts[:font] if opts[:font]
|
137
|
-
draw.font_family = opts[:font_family] if opts[:font_family]
|
138
|
-
draw.pointsize = opts[:font_size].to_f if opts[:font_size]
|
139
|
-
draw.fill = opts[:color] if opts[:color]
|
140
|
-
draw.stroke = opts[:stroke_color] if opts[:stroke_color]
|
141
|
-
draw.font_style = FONT_STYLES[opts[:font_style]] if opts[:font_style]
|
142
|
-
draw.font_stretch = FONT_STRETCHES[opts[:font_stretch]] if opts[:font_stretch]
|
143
|
-
draw.font_weight = FONT_WEIGHTS[opts[:font_weight]] if opts[:font_weight]
|
144
|
-
|
145
|
-
text = temp_object.data
|
146
|
-
|
147
|
-
# Calculate dimensions
|
148
|
-
metrics = draw.get_type_metrics(text)
|
149
|
-
width, height = metrics.width, metrics.height
|
150
|
-
|
151
|
-
pt, pr, pb, pl = parse_padding_string(opts[:padding]) if opts[:padding]
|
152
|
-
padding_top = opts[:padding_top] || pt || 0
|
153
|
-
padding_right = opts[:padding_right] || pr || 0
|
154
|
-
padding_bottom = opts[:padding_bottom] || pb || 0
|
155
|
-
padding_left = opts[:padding_left] || pl || 0
|
156
|
-
|
157
|
-
# Hack - for small font sizes, the width seems to be affected by rounding errors
|
158
|
-
padding_right += 2
|
159
|
-
|
160
|
-
total_width = padding_left + width + padding_right
|
161
|
-
total_height = padding_top + height + padding_bottom
|
162
|
-
|
163
|
-
# Draw the background
|
164
|
-
image = Magick::Image.new(total_width, total_height){
|
165
|
-
self.background_color = opts[:background_color] || 'transparent'
|
166
|
-
}
|
167
|
-
# Draw the text
|
168
|
-
draw.annotate(image, width, height, padding_left, padding_top, text)
|
169
|
-
# Output image as string
|
170
|
-
image.format = 'png'
|
171
|
-
image.to_blob
|
172
|
-
end
|
173
79
|
|
174
80
|
def vignette(temp_object, opts={})
|
175
81
|
x = opts[:x].to_f || temp_object.width * 0.1
|
@@ -184,32 +90,11 @@ module Dragonfly
|
|
184
90
|
|
185
91
|
def rmagick_image(temp_object)
|
186
92
|
Magick::Image.from_blob(temp_object.data).first
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
# 10 (all sides)
|
191
|
-
# 10 5 (top/bottom, left/right)
|
192
|
-
# 10 5 10 (top, left/right, bottom)
|
193
|
-
# 10 5 10 5 (top, right, bottom, left)
|
194
|
-
def parse_padding_string(str)
|
195
|
-
padding_parts = str.gsub('px','').split(/\s+/).map{|px| px.to_i}
|
196
|
-
case padding_parts.size
|
197
|
-
when 1
|
198
|
-
p = padding_parts.first
|
199
|
-
[p,p,p,p]
|
200
|
-
when 2
|
201
|
-
p,q = padding_parts
|
202
|
-
[p,q,p,q]
|
203
|
-
when 3
|
204
|
-
p,q,r = padding_parts
|
205
|
-
[p,q,r,q]
|
206
|
-
when 4
|
207
|
-
padding_parts
|
208
|
-
else raise ArgumentError, "Couldn't parse padding string '#{str}' - should be a css-style string"
|
209
|
-
end
|
93
|
+
rescue Magick::ImageMagickError => e
|
94
|
+
log.warn("Unable to handle content in #{self.class} - got:\n#{e}")
|
95
|
+
throw :unable_to_handle
|
210
96
|
end
|
211
97
|
|
212
98
|
end
|
213
|
-
|
214
99
|
end
|
215
100
|
end
|