oahu-dragonfly 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.yardopts +24 -0
- data/Gemfile +30 -0
- data/History.md +323 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/config.ru +14 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +297 -0
- data/extra_docs/Analysers.md +66 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +124 -0
- data/extra_docs/Couch.md +49 -0
- data/extra_docs/DataStorage.md +153 -0
- data/extra_docs/Encoding.md +67 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +60 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/ImageMagick.md +125 -0
- data/extra_docs/Index.md +33 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +272 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +77 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +57 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_3.0.5.feature +8 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +28 -0
- data/features/support/env.rb +13 -0
- data/features/support/setup.rb +32 -0
- data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
- data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
- data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
- data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
- data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.5/template.rb +20 -0
- data/irbrc.rb +18 -0
- data/lib/dragonfly.rb +55 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
- data/lib/dragonfly/analyser.rb +58 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
- data/lib/dragonfly/app.rb +172 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +6 -0
- data/lib/dragonfly/config/rails.rb +20 -0
- data/lib/dragonfly/configurable.rb +207 -0
- data/lib/dragonfly/core_ext/array.rb +7 -0
- data/lib/dragonfly/core_ext/hash.rb +7 -0
- data/lib/dragonfly/core_ext/object.rb +12 -0
- data/lib/dragonfly/core_ext/string.rb +9 -0
- data/lib/dragonfly/core_ext/symbol.rb +9 -0
- data/lib/dragonfly/data_storage.rb +9 -0
- data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
- data/lib/dragonfly/function_manager.rb +71 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
- data/lib/dragonfly/image_magick/analyser.rb +51 -0
- data/lib/dragonfly/image_magick/config.rb +41 -0
- data/lib/dragonfly/image_magick/encoder.rb +57 -0
- data/lib/dragonfly/image_magick/generator.rb +145 -0
- data/lib/dragonfly/image_magick/processor.rb +99 -0
- data/lib/dragonfly/image_magick/utils.rb +72 -0
- data/lib/dragonfly/image_magick_utils.rb +4 -0
- data/lib/dragonfly/job.rb +451 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +15 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +20 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/rails/images.rb +27 -0
- data/lib/dragonfly/response.rb +97 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/server.rb +113 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/temp_object.rb +175 -0
- data/lib/dragonfly/url_mapper.rb +78 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
- data/spec/dragonfly/app_spec.rb +135 -0
- data/spec/dragonfly/configurable_spec.rb +461 -0
- data/spec/dragonfly/core_ext/array_spec.rb +19 -0
- data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
- data/spec/dragonfly/core_ext/string_spec.rb +17 -0
- data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
- data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
- data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
- data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
- data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +173 -0
- data/spec/dragonfly/job_spec.rb +1046 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +47 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/server_spec.rb +278 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/temp_object_spec.rb +306 -0
- data/spec/dragonfly/url_mapper_spec.rb +126 -0
- data/spec/functional/deprecations_spec.rb +51 -0
- data/spec/functional/image_magick_app_spec.rb +27 -0
- data/spec/functional/model_urls_spec.rb +85 -0
- data/spec/functional/remote_on_the_fly_spec.rb +51 -0
- data/spec/functional/to_response_spec.rb +31 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/argument_matchers.rb +19 -0
- data/spec/support/image_matchers.rb +47 -0
- data/spec/support/simple_matchers.rb +53 -0
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +15 -0
- data/yard/templates/default/fulldoc/html/css/common.css +107 -0
- data/yard/templates/default/layout/html/layout.erb +89 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +544 -0
@@ -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,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
|