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.
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,50 @@
1
+ Heroku
2
+ ======
3
+
4
+ The default configuration won't work out of the box for Heroku, because
5
+
6
+ - Heroku doesn't allow saving files to the filesystem (although it does use tempfiles)
7
+ - We won't need {http://tomayko.com/src/rack-cache/ Rack::Cache} on Heroku because it already uses the caching proxy {http://varnish.projects.linpro.no/ Varnish}, which we can make use of
8
+
9
+ Instead of the normal {Dragonfly::DataStorage::FileDataStore FileDataStore}, we can use the {Dragonfly::DataStorage::S3DataStore S3DataStore}.
10
+
11
+ Assuming you have an S3 account set up...
12
+
13
+ Gem dependencies:
14
+
15
+ - aws-s3 (require as aws/s3)
16
+ - dragonfly
17
+
18
+ Initializer (e.g. config/initializers/dragonfly.rb):
19
+
20
+ require 'dragonfly'
21
+ app = Dragonfly[:images]
22
+
23
+ app.configure_with(:imagemagick)
24
+ app.configure_with(:rails)
25
+ app.configure_with(:heroku, 'my_bucket_name') if Rails.env.production?
26
+
27
+ app.define_macro(ActiveRecord::Base, :image_accessor)
28
+
29
+ The datastore remains as the {Dragonfly::DataStorage::FileDataStore FileDataStore} for non-production environments.
30
+
31
+ environment.rb (application.rb in Rails 3):
32
+
33
+ # make sure the last arg is the same as the app's configured prefix
34
+ config.middleware.insert_before 'Rack::Lock', 'Dragonfly::Middleware', :images, '/media'
35
+
36
+ We don't store the S3 access key and secret in the repository, rather we use Heroku's
37
+ {http://docs.heroku.com/config-vars config variables} using the command line (we only have to do this once).
38
+
39
+ From your app's directory:
40
+
41
+ heroku config:add S3_KEY=XXXXXXXXX S3_SECRET=XXXXXXXXXX
42
+
43
+ Obviously replace 'XXXXXXXXX' with your access key and secret.
44
+
45
+ Now you can benefit from super-fast images served straight from Heroku's cache!
46
+
47
+ NOTE: HEROKU'S CACHE IS CLEARED EVERY TIME YOU DEPLOY!!!
48
+
49
+ If this is an issue, you may want to look into using something like a Memcached add-on, or maybe an after-deploy hook for hitting specific Dragonfly urls you want to cache, etc.
50
+ It won't be a problem for most sites though.
@@ -0,0 +1,36 @@
1
+ Dragonfly is a {http://rack.rubyforge.org Rack} framework for on-the-fly image handling in Ruby.
2
+
3
+ It is suitable for using with web frameworks such as Rails(2.3 and 3), Sinatra, etc.
4
+
5
+ I actually lied about image handling - it can be used for any type of content.
6
+
7
+ See the links on the right for more info.
8
+
9
+ **NOTE: the API has changed since v0.6.2!
10
+ [Docs for v0.6.2 are here](v0.6.2/index.html) for a very limited time.**
11
+
12
+ Installation
13
+ ------------
14
+
15
+ gem install dragonfly
16
+
17
+ Add-ons
18
+ -------
19
+ For third-party add-ons, see [the Add-ons wiki](http://github.com/markevans/dragonfly/wiki/Dragonfly-add-ons)
20
+
21
+ Issues
22
+ ------
23
+ Please use the <a href="http://github.com/markevans/dragonfly/issues">github issue tracker</a>.
24
+
25
+ Suggestions/Questions
26
+ ---------------------
27
+ {http://groups.google.com/group/dragonfly-users}
28
+
29
+ Credits
30
+ -------
31
+ - [Mark Evans](http://github.com/markevans) (author)
32
+ - Loads of helpful comments, issues, questions, suggestions and insults from others - you know who you are!
33
+
34
+ Copyright
35
+ ---------
36
+ Copyright (c) 2009-2010 Mark Evans. See LICENSE for details.
@@ -0,0 +1,40 @@
1
+ Mime Types
2
+ ==========
3
+
4
+ Responses from the Dragonfly app have the HTTP 'Content-Type' header set.
5
+
6
+ This is decided by the first found from:
7
+
8
+ 1. The requested format (e.g. when encode is specifically called)
9
+ 2. The original file extension (you can configure it to ignore this if you wish)
10
+ 3. Analyse the content using the analyser's 'mime_type' method (if exists)
11
+ 4. Analyse the content using the analyser's 'format' method (if exists)
12
+ 5. Use the fallback mime-type (default 'application/octet-stream')
13
+
14
+ Note that 'format' means 'jpg', 'png', etc. whereas mime-type would be 'image/jpeg', image/png', etc.
15
+ Formats are mapped to mime-types using the app's registered list of mime-types.
16
+
17
+ Registered mime-types
18
+ ---------------------
19
+ Registered mime-types default to the list given by Rack (see {http://rack.rubyforge.org/doc/Rack/Mime.html#MIME_TYPES Rack mime-types}).
20
+
21
+ To register a mime-type for the format 'egg':
22
+
23
+ Dragonfly[:my_app].register_mime_type(:egg, 'fried/egg')
24
+
25
+ You can also do this inside a configuration block.
26
+
27
+ Analysers
28
+ ---------
29
+ The {Dragonfly::Analysis::FileCommandAnalyser FileCommandAnalyser} has a `mime_type` method and the
30
+ {Dragonfly::Analysis::ImageMagickAnalyser ImageMagickAnalyser} has a `format` method.
31
+
32
+ These are both registered by default when you use the preconfigured 'dragonfly/rails/images' file.
33
+
34
+ Fallback mime-type
35
+ ------------------
36
+ By default this is 'application/octet-stream', but it can be changed using
37
+
38
+ Dragonfly[:my_app].fallback_mime_type = 'meaty/beef'
39
+
40
+ This can also be done inside a configuration block.
@@ -0,0 +1,266 @@
1
+ Using with Models
2
+ =================
3
+
4
+ You can extend ActiveModel-compatible models to make working with content such as images
5
+ as easy as working with strings or numbers!
6
+
7
+ The examples below assume an initialized Dragonfly app, e.g.
8
+
9
+ app = Dragonfly[:images]
10
+
11
+ ActiveRecord
12
+ ------------
13
+ If you've required 'dragonfly/rails/images', then the following step will be already done for you.
14
+ Otherwise:
15
+
16
+ app.define_macro(ActiveRecord::Base, :image_accessor)
17
+
18
+ defines the macro `image_accessor` on any ActiveRecord models.
19
+
20
+ Mongoid
21
+ -------
22
+
23
+ app.define_macro_on_include(Mongoid::Document, :image_accessor)
24
+
25
+ defines the macro `image_accessor` on any models that include `Mongoid::Document`
26
+
27
+ Adding accessors
28
+ ----------------
29
+ Now we have the method `image_accessor` available in our model classes, which we can use as many times as we like
30
+
31
+ class Album
32
+ image_accessor :cover_image
33
+ image_accessor :band_photo # Note: this is a different image altogether, not a thumbnail of cover_image
34
+ end
35
+
36
+ Each accessor (e.g. `cover_image`) depends on a string field to actually hold the datastore uid,
37
+ named by appending the suffix `_uid` (e.g. `cover_image_uid`).
38
+
39
+ For example, ActiveRecord models need a migration such as:
40
+
41
+ class MyMigration < ActiveRecord::Migration
42
+
43
+ def self.up
44
+ add_column :albums, :cover_image_uid, :string
45
+ add_column :albums, :band_photo_uid, :string
46
+ end
47
+
48
+ def self.down
49
+ remove_column :albums, :cover_image_uid
50
+ remove_column :albums, :band_photo_uid
51
+ end
52
+
53
+ end
54
+
55
+ Using the accessors
56
+ -------------------
57
+
58
+ We can use the attribute much like other other model attributes:
59
+
60
+ @album = Album.new
61
+
62
+ @album.cover_image = "\377???JFIF\000\..." # can assign as a string...
63
+ @album.cover_image = File.new('path/to/my_image.png') # ... or as a file...
64
+ @album.cover_image = some_tempfile # ... or as a tempfile...
65
+ @album.cover_image = @album.band_photo # ... or as another Dragonfly attachment
66
+
67
+ @album.cover_image # => #<Dragonfly::ActiveModelExtensions::Attachment:0x103ef6128...
68
+
69
+ @album.cover_image = nil
70
+ @album.cover_image # => nil
71
+
72
+ We can inspect properties of the attribute
73
+
74
+ @album.cover_image.width # => 280
75
+ @album.cover_image.height # => 140
76
+ @album.cover_image.number_of_colours # => 34703
77
+ @album.cover_image.mime_type # => 'image/png'
78
+
79
+ The properties available (i.e. 'width', etc.) come from the app's registered analysers - see {file:Analysers.md Analysers}.
80
+
81
+ We can play around with the data
82
+
83
+ @album.cover_image.data # => "\377???JFIF\000\..."
84
+ @album.cover_image.to_file('out.png') # writes to file 'out.png' and returns a readable file object
85
+ @album.cover_image.tempfile # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a closed Tempfile object
86
+ @album.cover_image.file # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a readable (open) File object
87
+ @album.cover_image.file do |f| # Yields an open file object, returns the return value of
88
+ data = f.read(256) # the block, and closes the file object
89
+ end
90
+ @album.cover_image.path # => '/var/folders/st/strHv74sH044JPabSiODz...' i.e. the path of the tempfile
91
+ @album.cover_image.size # => 134507 (size in bytes)
92
+
93
+ We can process the data
94
+
95
+ image = @album.cover_image.process(:thumb, '20x20') # returns a 'Job' object, with similar properties
96
+ image.width # => 20
97
+ @album.cover_image.width # => 280 (no change)
98
+
99
+ The available processing methods available (i.e. 'thumb', etc.) come from the {Dragonfly} app's registered processors - see {file:Processing.md Processing}
100
+
101
+ We can encode the data
102
+
103
+ image = @album.cover_image.encode(:gif) # returns a 'Job' object, with similar properties
104
+ image.format # => :gif
105
+ @album.cover_image.format # => :png (no change)
106
+
107
+ The encoding is implemented by the {Dragonfly} app's registered encoders (which will usually just be one) - see {file:Encoding.md Encoding}
108
+
109
+ We can use configured shortcuts for processing/encoding, and chain them:
110
+
111
+ @album.cover_image.thumb('300x200#ne') # => returns a 'Job' object, with similar properties
112
+
113
+ We can chain all these things much like ActiveRecord scopes:
114
+
115
+ @album.cover_image.png.thumb('300x200#ne').process(:greyscale).encode(:tiff)
116
+
117
+ Because the processing/encoding methods are lazy, no actual processing or encoding is done until a method like `data`, `file`, `to_file`, `width`, etc. is called.
118
+ You can force the processing to be done if you must by then calling `apply`.
119
+
120
+ @album.cover_image.process(:greyscale).apply
121
+
122
+ Persisting
123
+ ----------
124
+ When the model is saved, a before_save callback persists the data to the {Dragonfly::App App}'s configured datastore (see {file:DataStorage.md DataStorage})
125
+ The uid column is then filled in.
126
+
127
+ @album = Album.new
128
+
129
+ @album.cover_image_uid # => nil
130
+
131
+ @album.cover_image = File.new('path/to/my_image.png')
132
+ @album.cover_image_uid # => nil
133
+
134
+ @album.save
135
+ @album.cover_image_uid # => '2009/12/05/file.png' (some unique uid, used by the datastore)
136
+
137
+ URLs
138
+ ----
139
+ Once the model is saved, we can get a url for the image (which is served by the Dragonfly {Dragonfly::App App} itself), and for its processed/encoded versions:
140
+
141
+ @album.cover_image.url # => '/media/BAhbBlsHOgZmIhgy...'
142
+ @album.cover_image.thumb('300x200#nw').url # => '/media/BAhbB1sYusgZhgyM...'
143
+ @album.cover_image.process(:greyscale).jpg.url # => '/media/BnA6CnRodW1iIg8z...'
144
+
145
+ Because the processing/encoding methods (including shortcuts like `thumb` and `jpg`) are lazy, no processing or encoding is actually done.
146
+
147
+ Validations
148
+ -----------
149
+ `validates_presence_of` and `validates_size_of` work out of the box, and Dragonfly also provides `validates_property`.
150
+
151
+ class Album
152
+
153
+ validates_presence_of :cover_image
154
+ validates_size_of :cover_image, :maximum => 500.kilobytes
155
+
156
+ validates_property :format, :of => :cover_image, :in => [:jpeg, :png, :gif]
157
+ # ..or..
158
+ validates_property :mime_type, :of => :cover_image, :in => %w(image/jpeg image/png image/gif)
159
+
160
+ validates_property :width, :of => :cover_image, :in => (0..400), :message => "é demais cara!"
161
+
162
+ # ...
163
+ end
164
+
165
+ The property argument of `validates_property` will generally be one of the registered analyser properties as described in {file:Analysers.md Analysers}.
166
+ However it would actually work for arbitrary properties, including those of non-dragonfly model attributes.
167
+
168
+ Name and extension
169
+ ------------------
170
+ If the object assigned is a file, or responds to `original_filename` (as is the case with file uploads in Rails, etc.), then `name` will be set.
171
+
172
+ @album.cover_image = File.new('path/to/my_image.png')
173
+
174
+ @album.cover_image.name # => 'my_image.png'
175
+ @album.cover_image.ext # => 'png'
176
+
177
+ Meta data
178
+ ---------
179
+ You can store metadata along with the content data of your attachment:
180
+
181
+ @album.cover_image = File.new('path/to/my_image.png')
182
+ @album.cover_image.meta = {:taken => Date.yesterday}
183
+ @album.save!
184
+
185
+ @album.cover_image.meta # => {:model_class=>"Album",
186
+ # :model_attachment=>:cover_image,
187
+ # :taken=>Sat, 11 Sep 2010}
188
+
189
+ As you can see, a couple of things are added by the model. You can also access this directly on the {Dragonfly::Job Job} object.
190
+
191
+ app.fetch(@album.cover_image_uid).meta # => {:model_class=>"Album", ...}
192
+
193
+ "Magic" Attributes
194
+ ------------------
195
+ An accessor like `cover_image` only relies on the accessor `cover_image_uid` to work.
196
+ However, in some cases you may want to record some other properties, whether it be for using in queries, or
197
+ for caching an attribute for performance reasons, etc.
198
+
199
+ For the properties `name`, `ext`, `size` and any of the registered analysis methods (e.g. `width`, etc. in the examples above),
200
+ this is done automatically for you, if the corresponding accessor exists.
201
+
202
+ For example - with ActiveRecord, given the migration:
203
+
204
+ add_column :albums, :cover_image_width, :integer
205
+
206
+ This will automatically be set when assigned:
207
+
208
+ @album.cover_image = File.new('path/to/my_image.png')
209
+
210
+ @album.cover_image_width # => 280
211
+
212
+ They can be used to avoid retrieving data from the datastore for analysis
213
+
214
+ @album = Album.first
215
+
216
+ @album.cover_image.width # => 280 - no need to retrieve data - takes it from `cover_image_width`
217
+ @album.cover_image.size # => 134507 - but this needs to retrieve data from the data store, then analyse
218
+
219
+
220
+ Custom Model
221
+ ------------
222
+ The accessors only require that your model class implements `before_save`, `before_destroy` and `validates_each`
223
+ (if using validations), as well as of course the `..._uid` field for storing the datastore uid.
224
+
225
+ Here is an example of a minimal ActiveModel `Album` model:
226
+
227
+ class CustomModel::Base
228
+
229
+ extend ActiveModel::Callbacks
230
+ define_model_callbacks :save, :destroy
231
+
232
+ include ActiveModel::Validations # if needed
233
+
234
+ def save
235
+ _run_save_callbacks {
236
+ # do some saving!
237
+ }
238
+ end
239
+
240
+ def destroy
241
+ _run_destroy_callbacks {
242
+ # do some destroying!
243
+ }
244
+ end
245
+
246
+ end
247
+
248
+ Define our `image_accessor` macro...
249
+
250
+ app.define_macro(CustomModel::Base, :image_accessor)
251
+
252
+ ...which is used by `Album`:
253
+
254
+ class Album < CustomModel::Base
255
+
256
+ def cover_image_uid=
257
+ # ...
258
+ end
259
+
260
+ def cover_image_uid
261
+ # ...
262
+ end
263
+
264
+ image_accessor :cover_image
265
+
266
+ end
@@ -0,0 +1,45 @@
1
+ Mongo
2
+ =====
3
+ Dragonfly can be used with any ActiveModel-compatible model, therefore libraries like [Mongoid](http://mongoid.org) work out of the box.
4
+
5
+ Furthermore, Mongo DB has support for storing blob-like objects directly in the database (using MongoDB 'GridFS'),
6
+ so you can make use of this with the supplied {Dragonfly::DataStorage::MongoDataStore MongoDataStore}.
7
+
8
+ For more info about ActiveModel, see {file:Models}.
9
+
10
+ For more info about using the Mongo data store, see {file:DataStorage}.
11
+
12
+ Example setup in Rails, using Mongoid
13
+ -------------------------------------
14
+ In config/initializers/dragonfly.rb:
15
+
16
+ require 'dragonfly'
17
+
18
+ app = Dragonfly[:images]
19
+
20
+ # Get database name from config/mongoid.yml
21
+ db = YAML.load_file(Rails.root.join('config/mongoid.yml'))[Rails.env]['database']
22
+
23
+ # Configure to use ImageMagick, Rails defaults, and the Mongo data store
24
+ app.configure_with(:imagemagick)
25
+ app.configure_with(:rails) do |c|
26
+ c.datastore = Dragonfly::DataStorage::MongoDataStore.new :database => db
27
+ end
28
+
29
+ # Allow all mongoid models to use the macro 'image_accessor'
30
+ app.define_macro_on_include(Mongoid::Document, :image_accessor)
31
+
32
+ # ... any other setup, see Rails docs
33
+
34
+ Then in models:
35
+
36
+ class Album
37
+ include Mongoid::Document
38
+
39
+ field :cover_image_uid
40
+ image_accessor :cover_image
41
+
42
+ # ...
43
+ end
44
+
45
+ See {file:Models} for more info.
@@ -0,0 +1,130 @@
1
+ Processing
2
+ ==========
3
+
4
+ Changing data in some way, e.g. resizing an image, comes under the banner of Processing.
5
+
6
+ You can register as many processors as you like.
7
+
8
+ Let's say we have a Dragonfly app
9
+
10
+ app = Dragonfly[:images]
11
+
12
+ and an image object (actually a {Dragonfly::Job Job} object)...
13
+
14
+ image = app.fetch('some/uid')
15
+
16
+ ...OR a Dragonfly model accessor...
17
+
18
+ image = @album.cover_image
19
+
20
+ We can process it using any processing methods that have been registered with the processor.
21
+
22
+ ImageMagickProcessor
23
+ --------------------
24
+ The {Dragonfly::Processing::ImageMagickProcessor ImageMagickProcessor} is registered by default by
25
+ the {Dragonfly::Config::ImageMagick ImageMagick configuration} used by 'dragonfly/rails/images'.
26
+
27
+ If not already registered:
28
+
29
+ app.processor.register(Dragonfly::Processing::ImageMagickProcessor)
30
+
31
+ gives us these methods:
32
+
33
+ image.process(:thumb, '400x300#') # see below
34
+
35
+ image.process(:crop, :width => 40, :height => 50, :x => 20, :y => 30)
36
+ image.process(:crop, :width => 40, :height => 50, :gravity => 'ne')
37
+
38
+ image.process(:flip) # flips it vertically
39
+ image.process(:flop) # flips it horizontally
40
+
41
+ image.process(:greyscale, :depth => 128) # default depth 256
42
+
43
+ image.process(:resize, '40x40')
44
+ image.process(:resize_and_crop, :width => 40, :height=> 50, :gravity => 'ne')
45
+
46
+ image.process(:rotate, 45, :background_colour => 'transparent') # default bg black
47
+
48
+ The method `thumb` takes a geometry string and calls `resize`, `resize_and_crop` or `crop` accordingly.
49
+
50
+ image.process(:thumb, '400x300') # calls resize
51
+
52
+ Below are some examples of geometry strings:
53
+
54
+ '400x300' # resize, maintain aspect ratio
55
+ '400x300!' # force resize, don't maintain aspect ratio
56
+ '400x' # resize width, maintain aspect ratio
57
+ 'x300' # resize height, maintain aspect ratio
58
+ '400x300>' # resize only if the image is larger than this
59
+ '400x300<' # resize only if the image is smaller than this
60
+ '50x50%' # resize width and height to 50%
61
+ '400x300^' # resize width, height to minimum 400,300, maintain aspect ratio
62
+ '2000@' # resize so max area in pixels is 2000
63
+ '400x300#' # resize, crop if necessary to maintain aspect ratio (centre gravity)
64
+ '400x300#ne' # as above, north-east gravity
65
+ '400x300se' # crop, with south-east gravity
66
+ '400x300+50+100' # crop from the point 50,100 with width, height 400,300
67
+
68
+ RMagickProcessor
69
+ ----------------
70
+ The {Dragonfly::Processing::RMagickProcessor RMagickProcessor} uses the {http://rmagick.rubyforge.org RMagick} library and provides the methods
71
+ `thumb`, `crop`, `flip`, `flop`, `greyscale`, `resize`, `resize_and_crop` and `rotate` like the ImageMagickProcessor above.
72
+
73
+ You can tell it not to use the file system when registering it
74
+
75
+ app.processor.register(Dragonfly::Processing::RMagickProcessor){|p| p.use_filesystem = false }
76
+
77
+
78
+ Lazy evaluation
79
+ ---------------
80
+
81
+ new_image = image.process(:some_method)
82
+
83
+ doesn't actually do anything until you call something on the returned {Dragonfly::Job Job} object, like `url`, `data`, etc.
84
+
85
+ Bang method
86
+ -----------
87
+
88
+ image.process!(:some_method)
89
+
90
+ modifies the image object itself, rather than returning a new object.
91
+
92
+ Custom Processors
93
+ -----------------
94
+
95
+ To register a single custom processor:
96
+
97
+ app.processor.add :watermark do |temp_object, *args|
98
+ # use temp_object.data, temp_object.path, temp_object.file, etc.
99
+ SomeLibrary.add_watermark(temp_object.data, 'some/watermark/file.png')
100
+ # return a String, File or Tempfile
101
+ end
102
+
103
+ new_image = image.process(:watermark)
104
+
105
+ You can create a class like the RMagick one above, in which case all public methods will be counted as processing methods.
106
+ Each method takes the temp_object as its argument, plus any other args.
107
+
108
+ class MyProcessor
109
+
110
+ def coolify(temp_object, opts={})
111
+ SomeLib.coolify(temp_object.data, opts)
112
+ end
113
+
114
+ def uglify(temp_object, ugliness)
115
+ `uglify -i #{temp_object.path} -u #{ugliness}`
116
+ end
117
+
118
+ private
119
+
120
+ def my_helper_method
121
+ # do stuff
122
+ end
123
+
124
+ end
125
+
126
+ app.processor.register(MyProcessor)
127
+
128
+ new_image = image.coolify(:some => :args)
129
+
130
+ new_image = image.uglify(:loads)