fog-dragonfly 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.specopts +2 -0
- data/.yardopts +23 -0
- data/Gemfile +23 -0
- data/Gemfile.rails.2.3.5 +14 -0
- data/History.md +266 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +92 -0
- data/VERSION +1 -0
- data/config.ru +13 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +293 -0
- data/extra_docs/Analysers.md +108 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +138 -0
- data/extra_docs/DataStorage.md +136 -0
- data/extra_docs/Encoding.md +96 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +102 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/Index.md +36 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +266 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +130 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +55 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/3.0.3.feature +8 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_2.3.5.feature +7 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +39 -0
- data/features/support/env.rb +40 -0
- data/fixtures/files/app/models/album.rb +3 -0
- data/fixtures/files/app/views/albums/new.html.erb +4 -0
- data/fixtures/files/app/views/albums/show.html.erb +4 -0
- data/fixtures/files/config/initializers/dragonfly.rb +4 -0
- data/fixtures/files/features/manage_album_images.feature +12 -0
- data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
- data/fixtures/files/features/support/paths.rb +15 -0
- data/fixtures/files/features/text_images.feature +7 -0
- data/fixtures/rails_2.3.5/template.rb +10 -0
- data/fixtures/rails_3.0.3/template.rb +20 -0
- data/irbrc.rb +17 -0
- data/lib/dragonfly.rb +45 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
- data/lib/dragonfly/analyser.rb +59 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
- data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
- data/lib/dragonfly/app.rb +182 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +41 -0
- data/lib/dragonfly/config/r_magick.rb +46 -0
- data/lib/dragonfly/config/rails.rb +17 -0
- data/lib/dragonfly/configurable.rb +119 -0
- data/lib/dragonfly/core_ext/object.rb +8 -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/file_data_store.rb +114 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
- data/lib/dragonfly/function_manager.rb +69 -0
- data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
- data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/image_magick_utils.rb +81 -0
- data/lib/dragonfly/job.rb +371 -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 +34 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
- data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/r_magick_utils.rb +48 -0
- data/lib/dragonfly/rails/images.rb +22 -0
- data/lib/dragonfly/response.rb +82 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/simple_endpoint.rb +63 -0
- data/lib/dragonfly/temp_object.rb +220 -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/argument_matchers.rb +19 -0
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
- data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
- data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
- data/spec/dragonfly/app_spec.rb +280 -0
- data/spec/dragonfly/config/r_magick_spec.rb +25 -0
- data/spec/dragonfly/configurable_spec.rb +220 -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/data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
- data/spec/dragonfly/deprecation_spec.rb +20 -0
- data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
- data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
- data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
- data/spec/dragonfly/image_magick_utils_spec.rb +16 -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 +120 -0
- data/spec/dragonfly/job_spec.rb +773 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +68 -0
- data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
- data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
- data/spec/dragonfly/temp_object_spec.rb +352 -0
- data/spec/image_matchers.rb +47 -0
- data/spec/simple_matchers.rb +44 -0
- data/spec/spec_helper.rb +58 -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 +87 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +550 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Data Storage
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
Each dragonfly app has a key-value datastore to store the content (originals only).
|
|
5
|
+
|
|
6
|
+
Lets say we have an app
|
|
7
|
+
|
|
8
|
+
app = Dragonfly[:my_app_name]
|
|
9
|
+
|
|
10
|
+
Then we can store data like so:
|
|
11
|
+
|
|
12
|
+
uid = app.store('SOME CONTENT') # Can pass in a String, File or Tempfile
|
|
13
|
+
|
|
14
|
+
We can also save metadata at the same time, and give it a name and format (if you pass in a File object the filename is used by default)
|
|
15
|
+
|
|
16
|
+
uid = app.store('SOME CONTENT',
|
|
17
|
+
:meta => {:time => Time.now},
|
|
18
|
+
:name => 'great_content.txt',
|
|
19
|
+
:format => :txt
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
We can get content with
|
|
23
|
+
|
|
24
|
+
content = app.fetch(uid)
|
|
25
|
+
content.data # "SOME CONTENT"
|
|
26
|
+
|
|
27
|
+
We can also get the extra saved attributes
|
|
28
|
+
|
|
29
|
+
content.meta # {:time => Sat Aug 14 12:04:13 +0100 2010}
|
|
30
|
+
content.name # 'great_content.txt'
|
|
31
|
+
content.format # :txt
|
|
32
|
+
|
|
33
|
+
We can destroy it with
|
|
34
|
+
|
|
35
|
+
app.destroy(uid)
|
|
36
|
+
|
|
37
|
+
You can create your own datastore, or use one of the provided ones as outlined below.
|
|
38
|
+
|
|
39
|
+
File datastore
|
|
40
|
+
--------------
|
|
41
|
+
The {Dragonfly::DataStorage::FileDataStore FileDataStore} stores data on the local filesystem.
|
|
42
|
+
|
|
43
|
+
It is used by default.
|
|
44
|
+
|
|
45
|
+
If for whatever reason you need to configure it again:
|
|
46
|
+
|
|
47
|
+
# shouldn't need this - it is the default
|
|
48
|
+
app.datastore = Dragonfly::DataStorage::FileDataStore.new
|
|
49
|
+
|
|
50
|
+
app.datastore.configure do |d|
|
|
51
|
+
d.root_path = '/my/custom/path' # defaults to /var/tmp/dragonfly
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
S3 datastore
|
|
56
|
+
------------
|
|
57
|
+
To configure with the {Dragonfly::DataStorage::S3DataStore S3DataStore}:
|
|
58
|
+
|
|
59
|
+
app.datastore = Dragonfly::DataStorage::S3DataStore.new
|
|
60
|
+
|
|
61
|
+
app.datastore.configure do |d|
|
|
62
|
+
c.bucket_name = 'my_bucket'
|
|
63
|
+
c.access_key_id = 'salfjasd34u23'
|
|
64
|
+
c.secret_access_key = '8u2u3rhkhfo23...'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
You can also pass these options to `S3DataStore.new` as an options hash.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Mongo datastore
|
|
71
|
+
---------------
|
|
72
|
+
To configure with the {Dragonfly::DataStorage::MongoDataStore MongoDataStore}:
|
|
73
|
+
|
|
74
|
+
app.datastore = Dragonfly::DataStorage::MongoDataStore.new
|
|
75
|
+
|
|
76
|
+
It won't normally need configuring, but if you wish to:
|
|
77
|
+
|
|
78
|
+
app.datastore.configure do |d|
|
|
79
|
+
c.host = 'http://egg.heads:5000' # defaults to localhost
|
|
80
|
+
c.port = '27018' # defaults to mongo default (27017)
|
|
81
|
+
c.database = 'my_database' # defaults to 'dragonfly'
|
|
82
|
+
c.username = 'some_user' # only needed if mongo is running in auth mode
|
|
83
|
+
c.password = 'some_password' # only needed if mongo is running in auth mode
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
You can also pass these options to `MongoDataStore.new` as an options hash.
|
|
87
|
+
|
|
88
|
+
Custom datastore
|
|
89
|
+
----------------
|
|
90
|
+
Data stores are key-value in nature, and need to implement 3 methods: `store`, `retrieve` and `destroy`.
|
|
91
|
+
|
|
92
|
+
class MyDataStore
|
|
93
|
+
|
|
94
|
+
def store(temp_object, opts={})
|
|
95
|
+
# ... use temp_object.data, temp_object.file, temp_object.path, etc. ...
|
|
96
|
+
# ... can also make use of temp_object.name, temp_object.format, temp_object.meta
|
|
97
|
+
# store and return the uid
|
|
98
|
+
'return_some_unique_uid'
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def retrieve(uid)
|
|
102
|
+
# return an array containing
|
|
103
|
+
[
|
|
104
|
+
content, # either a File, String or Tempfile
|
|
105
|
+
extra_data # Hash with optional keys :meta, :name, :format
|
|
106
|
+
]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def destroy(uid)
|
|
110
|
+
# find the content and destroy
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
You can now configure the app to use your datastore:
|
|
116
|
+
|
|
117
|
+
Dragonfly[:my_app_name].datastore = MyDataStore.new
|
|
118
|
+
|
|
119
|
+
Notice that `store` takes a second `opts` argument.
|
|
120
|
+
Any options other than `meta`, `name` and `format` get passed through to here, so calling
|
|
121
|
+
|
|
122
|
+
uid = app.store('SOME CONTENT',
|
|
123
|
+
:name => 'great_content.txt',
|
|
124
|
+
:some_other => :option
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
will be split inside `store` like so:
|
|
128
|
+
|
|
129
|
+
def store(temp_object, opts={})
|
|
130
|
+
temp_object.data # "SOME CONTENT"
|
|
131
|
+
temp_object.name # 'great_content.txt'
|
|
132
|
+
opts # {:some_other => :option}
|
|
133
|
+
# ...
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# ...
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Encoding
|
|
2
|
+
========
|
|
3
|
+
|
|
4
|
+
Changing the format of data, but not changing the data itself,
|
|
5
|
+
e.g. converting to gif format, comes under the banner of Encoding.
|
|
6
|
+
|
|
7
|
+
You can register as many encoders as you like.
|
|
8
|
+
|
|
9
|
+
Let's say we have a Dragonfly app
|
|
10
|
+
|
|
11
|
+
app = Dragonfly[:images]
|
|
12
|
+
|
|
13
|
+
and an image object (actually a {Dragonfly::Job Job} object)...
|
|
14
|
+
|
|
15
|
+
image = app.fetch('some/uid')
|
|
16
|
+
|
|
17
|
+
...OR a Dragonfly model accessor...
|
|
18
|
+
|
|
19
|
+
image = @album.cover_image
|
|
20
|
+
|
|
21
|
+
We can encode it to any format registered with the encoder.
|
|
22
|
+
|
|
23
|
+
ImageMagickEncoder
|
|
24
|
+
------------------
|
|
25
|
+
The {Dragonfly::Encoding::ImageMagickEncoder ImageMagickEncoder} is registered by default by
|
|
26
|
+
the {Dragonfly::Config::ImageMagick ImageMagick configuration} used by 'dragonfly/rails/images'.
|
|
27
|
+
|
|
28
|
+
If not already registered:
|
|
29
|
+
|
|
30
|
+
app.encoder.register(Dragonfly::Encoding::ImageMagickEncoder)
|
|
31
|
+
|
|
32
|
+
gives us:
|
|
33
|
+
|
|
34
|
+
image.encode(:jpg)
|
|
35
|
+
image.encode(:gif)
|
|
36
|
+
image.encode(:png)
|
|
37
|
+
image.encode(:tiff)
|
|
38
|
+
|
|
39
|
+
and various other formats (see {Dragonfly::Encoding::ImageMagickEncoder ImageMagickEncoder}).
|
|
40
|
+
|
|
41
|
+
You can also pass additional options to the imagemagick command line:
|
|
42
|
+
|
|
43
|
+
image.encode(:jpg, '-quality 10')
|
|
44
|
+
|
|
45
|
+
RMagickEncoder
|
|
46
|
+
--------------
|
|
47
|
+
The {Dragonfly::Encoding::RMagickEncoder RMagickEncoder} uses the {http://rmagick.rubyforge.org RMagick} library to do similar things to the
|
|
48
|
+
ImageMagickEncoder above.
|
|
49
|
+
|
|
50
|
+
You can tell it not to use the file system when registering it using
|
|
51
|
+
|
|
52
|
+
app.encoder.register(Dragonfly::Encoding::RMagickEncoder){|e| e.use_filesystem = false }
|
|
53
|
+
|
|
54
|
+
Lazy evaluation
|
|
55
|
+
---------------
|
|
56
|
+
|
|
57
|
+
gif_image = image.encode(:gif)
|
|
58
|
+
|
|
59
|
+
doesn't actually do anything until you call something on the returned {Dragonfly::Job Job} object, like `url`, `data`, etc.
|
|
60
|
+
|
|
61
|
+
Bang method
|
|
62
|
+
-----------
|
|
63
|
+
|
|
64
|
+
image.encode!(:gif)
|
|
65
|
+
|
|
66
|
+
modifies the image object itself, rather than returning a new object.
|
|
67
|
+
|
|
68
|
+
Custom Encoders
|
|
69
|
+
---------------
|
|
70
|
+
|
|
71
|
+
To register a custom encoder, for e.g. pdf format:
|
|
72
|
+
|
|
73
|
+
app.encoder.add do |temp_object, format|
|
|
74
|
+
throw :unable_to_handle unless format == :pdf
|
|
75
|
+
# use temp_object.data, temp_object.path, temp_object.file, etc.
|
|
76
|
+
SomeLibrary.convert_to_pdf(temp_object.data)
|
|
77
|
+
# return a String, File or Tempfile
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
pdf_image = image.encode(:pdf)
|
|
81
|
+
|
|
82
|
+
If `:unable_to_handle` is thrown, the next most recently registered encoder is used, and so on.
|
|
83
|
+
|
|
84
|
+
Alternatively you can create a class like the ImageMagick one above, which implements the method `encode`, and register this.
|
|
85
|
+
|
|
86
|
+
class MyEncoder
|
|
87
|
+
|
|
88
|
+
def encode(temp_object, format, *args)
|
|
89
|
+
SomeLib.encode(temp_object.data, format, *args)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
app.encoder.register(MyEncoder)
|
|
95
|
+
|
|
96
|
+
pdf_image = image.encode(:pdf, :some => :args)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
General Usage
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
You can have multiple dragonfly apps, each with their own configuration.
|
|
5
|
+
Each app has a name, and is referred to by that name.
|
|
6
|
+
|
|
7
|
+
Dragonfly[:images] # ===> Creates an app called 'images'
|
|
8
|
+
Dragonfly[:images] # ===> Refers to the already created app 'images'
|
|
9
|
+
|
|
10
|
+
app = Dragonfly[:images]
|
|
11
|
+
|
|
12
|
+
Getting/generating content
|
|
13
|
+
--------------------------
|
|
14
|
+
Three methods can be used to get content:
|
|
15
|
+
|
|
16
|
+
app.fetch('some_uid') # Fetch from datastore (default filesystem)
|
|
17
|
+
|
|
18
|
+
app.fetch_file('~/path/to/file.png') # Fetch from a local file
|
|
19
|
+
|
|
20
|
+
app.generate(:plasma, 400, 300) # Generates using a method from the configured
|
|
21
|
+
# generator (in this case a plasma image)
|
|
22
|
+
|
|
23
|
+
These all return {Dragonfly::Job Job} objects. These objects are lazy - they don't do any fetching/generating until
|
|
24
|
+
some other method is called on them.
|
|
25
|
+
|
|
26
|
+
Using the content
|
|
27
|
+
-----------------
|
|
28
|
+
Once we have a {Dragonfly::Job Job} object:
|
|
29
|
+
|
|
30
|
+
image = app.fetch('some_uid')
|
|
31
|
+
|
|
32
|
+
We can get the data a number of ways...
|
|
33
|
+
|
|
34
|
+
image.data # => "\377???JFIF\000\..."
|
|
35
|
+
image.to_file('out.png') # writes to file 'out.png' and returns a readable file object
|
|
36
|
+
image.tempfile # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a closed Tempfile object
|
|
37
|
+
image.file # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a readable (open) File object
|
|
38
|
+
image.file do |f| # Yields an open file object, returns the return value of
|
|
39
|
+
data = f.read(256) # the block, and closes the file object
|
|
40
|
+
end
|
|
41
|
+
image.path # => '/var/folders/st/strHv74sH044JPabSiODz...' i.e. the path of the tempfile
|
|
42
|
+
image.size # => 134507 (size in bytes)
|
|
43
|
+
|
|
44
|
+
We can get its url...
|
|
45
|
+
|
|
46
|
+
image.url # => "/media/BAhbBlsHOgZmIg9hc..."
|
|
47
|
+
|
|
48
|
+
We can analyse it (see {file:Analysers} for more info) ...
|
|
49
|
+
|
|
50
|
+
image.width # => 280
|
|
51
|
+
|
|
52
|
+
We can process it (see {file:Processing} for more info) ...
|
|
53
|
+
|
|
54
|
+
new_image = image.process(:thumb, '40x30') # returns another 'Job' object
|
|
55
|
+
|
|
56
|
+
We can encode it (see {file:Encoding} for more info) ...
|
|
57
|
+
|
|
58
|
+
new_image = image.encode(:gif) # returns another 'Job' object
|
|
59
|
+
|
|
60
|
+
Chaining
|
|
61
|
+
--------
|
|
62
|
+
Because the methods
|
|
63
|
+
|
|
64
|
+
- `fetch`
|
|
65
|
+
|
|
66
|
+
- `fetch_file`
|
|
67
|
+
|
|
68
|
+
- `generate`
|
|
69
|
+
|
|
70
|
+
- `process`
|
|
71
|
+
|
|
72
|
+
- `encode`
|
|
73
|
+
|
|
74
|
+
all return {Dragonfly::Job Job} objects, we can chain them as much as we want...
|
|
75
|
+
|
|
76
|
+
image = app.fetch('some_uid').process(:greyscale).process(:thumb, '40x20#').encode(:gif)
|
|
77
|
+
|
|
78
|
+
... and because they're lazy, we don't actually do any processing/encoding until either `apply` is called
|
|
79
|
+
|
|
80
|
+
image.apply # actually 'does' the processing and returns self
|
|
81
|
+
|
|
82
|
+
... or a method is called like `data`, `to_file`, etc.
|
|
83
|
+
|
|
84
|
+
This means we can cheaply generate urls for processed data without doing any fetching or processing:
|
|
85
|
+
|
|
86
|
+
url = app.fetch('some_uid').process(:thumb, '40x20#').encode(:gif).url
|
|
87
|
+
|
|
88
|
+
and then visit that url in a browser to get the actual processed image.
|
|
89
|
+
|
|
90
|
+
Shortcuts
|
|
91
|
+
---------
|
|
92
|
+
Commonly used processing/encoding steps can be shortened, so instead of
|
|
93
|
+
|
|
94
|
+
app.fetch('some_uid').process(:greyscale).process(:thumb, '40x20#').encode(:jpg)
|
|
95
|
+
|
|
96
|
+
we could use something like
|
|
97
|
+
|
|
98
|
+
app.fetch('some_uid').grey('40x20#')
|
|
99
|
+
|
|
100
|
+
This does exactly the same, returning a {Dragonfly::Job Job} object.
|
|
101
|
+
|
|
102
|
+
To define this shortcut:
|
|
103
|
+
|
|
104
|
+
app.configure do |c|
|
|
105
|
+
c.job :grey do |size|
|
|
106
|
+
process :greyscale
|
|
107
|
+
process :thumb, size
|
|
108
|
+
encode :jpg
|
|
109
|
+
end
|
|
110
|
+
# ...
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
The {Dragonfly::Config::ImageMagick ImageMagick} configuration comes with the pre-defined shortcuts:
|
|
114
|
+
|
|
115
|
+
image.thumb('40x30') # same as image.process(:thumb, '40x30')
|
|
116
|
+
image.jpg # same as image.encode(:jpg)
|
|
117
|
+
image.png # same as image.encode(:png)
|
|
118
|
+
image.gif # same as image.encode(:gif)
|
|
119
|
+
image.convert('-scale 30x30') # same as image.process(:convert, '-scale 30x30')
|
|
120
|
+
|
|
121
|
+
`thumb` and `convert` can optionally take a format (e.g. :gif) as the second argument.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Generators
|
|
2
|
+
==========
|
|
3
|
+
|
|
4
|
+
Unlike processors and encoders, generators create content out of nothing, rather than modifying already existing content, for example text image generation.
|
|
5
|
+
|
|
6
|
+
You can register as many generators as you like.
|
|
7
|
+
|
|
8
|
+
Given a Dragonfly app
|
|
9
|
+
|
|
10
|
+
app = Dragonfly[:images]
|
|
11
|
+
|
|
12
|
+
we can get generated content using
|
|
13
|
+
|
|
14
|
+
image = app.generate(:some_method, :some => :args)
|
|
15
|
+
|
|
16
|
+
where `:some_method` is added by the configured generators.
|
|
17
|
+
|
|
18
|
+
ImageMagickGenerator
|
|
19
|
+
--------------------
|
|
20
|
+
The {Dragonfly::Generation::ImageMagickGenerator ImageMagickGenerator} is registered by default by the
|
|
21
|
+
{Dragonfly::Config::ImageMagick ImageMagick configuration} used by 'dragonfly/rails/images'.
|
|
22
|
+
|
|
23
|
+
If not already registered:
|
|
24
|
+
|
|
25
|
+
app.generator.register(Dragonfly::Generation::ImageMagickGenerator)
|
|
26
|
+
|
|
27
|
+
gives us these methods:
|
|
28
|
+
|
|
29
|
+
image = app.generate(:plasma, 600, 400, :gif) # generate a 600x400 plasma image
|
|
30
|
+
# last arg defaults to :png
|
|
31
|
+
|
|
32
|
+
image = app.generate(:text, "Hello there") # an image of the text "Hello there"
|
|
33
|
+
|
|
34
|
+
image = app.generate(:text, "Hello there",
|
|
35
|
+
:font_size => 30, # defaults to 12
|
|
36
|
+
:font_family => 'Monaco',
|
|
37
|
+
:stroke_color => '#ddd',
|
|
38
|
+
:color => 'red',
|
|
39
|
+
:font_style => 'italic',
|
|
40
|
+
:font_stretch => 'expanded',
|
|
41
|
+
:font_weight => 'bold',
|
|
42
|
+
:padding => '30 20 10',
|
|
43
|
+
:background_color => '#efefef', # defaults to transparent
|
|
44
|
+
:format => :gif # defaults to png
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
Note that the options are meant to resemble css as much as possible. You can also use, for example, `'font-family'` instead of `:font_family`.
|
|
48
|
+
|
|
49
|
+
You can use `padding-top`, `padding-left`, etc., as well as the standard css shortcuts for `padding` (it assumes unit is px).
|
|
50
|
+
|
|
51
|
+
An alternative for `:font_family` is `:font` (see {http://www.imagemagick.org/script/command-line-options.php#font}), which could be a complete filename.
|
|
52
|
+
Available fonts are those available on your system.
|
|
53
|
+
|
|
54
|
+
RMagickGenerator
|
|
55
|
+
----------------
|
|
56
|
+
The {Dragonfly::Generation::RMagickGenerator RMagickGenerator} gives you `plasma` and `text` like the imagemagick generator above, using the
|
|
57
|
+
{http://rmagick.rubyforge.org RMagick} library.
|
|
58
|
+
|
|
59
|
+
You can tell it not to use the file system when registering it
|
|
60
|
+
|
|
61
|
+
app.generator.register(Dragonfly::Generation::RMagickGenerator){|g| g.use_filesystem = false }
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
Custom Generators
|
|
65
|
+
-----------------
|
|
66
|
+
To register a single custom generator:
|
|
67
|
+
|
|
68
|
+
app.generator.add :blank_image do |colour|
|
|
69
|
+
SomeLibrary.create_blank_image(colour) # return a String, File or Tempfile
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
app.generate(:blank_image, 'red') # => 'Job' object which we can get data, etc.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
Or create a class like the ImageMagick one above, in which case all public methods will be counted as generator methods.
|
|
76
|
+
|
|
77
|
+
class RoundedCornerGenerator
|
|
78
|
+
|
|
79
|
+
def top_left_corner(opts={})
|
|
80
|
+
SomeLib.tlc(opts)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def bottom_right_corner(opts={})
|
|
84
|
+
tempfile = Tempfile.new('brc')
|
|
85
|
+
`some_command -c #{opts[:colour]} -o #{tempfile.path}`
|
|
86
|
+
tempfile
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# ...
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def my_helper_method
|
|
94
|
+
# do stuff
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
app.generator.register(RoundedCornerGenerator)
|
|
100
|
+
|
|
101
|
+
app.generate(:top_left_corner, :colour => 'green')
|
|
102
|
+
app.generate(:bottom_right_corner, :colour => 'mauve')
|