fog-dragonfly 0.8.1

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

Potentially problematic release.


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

Files changed (155) hide show
  1. data/.specopts +2 -0
  2. data/.yardopts +23 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.rails.2.3.5 +14 -0
  5. data/History.md +266 -0
  6. data/LICENSE +20 -0
  7. data/README.md +88 -0
  8. data/Rakefile +92 -0
  9. data/VERSION +1 -0
  10. data/config.ru +13 -0
  11. data/docs.watchr +1 -0
  12. data/dragonfly.gemspec +293 -0
  13. data/extra_docs/Analysers.md +108 -0
  14. data/extra_docs/Caching.md +23 -0
  15. data/extra_docs/Configuration.md +138 -0
  16. data/extra_docs/DataStorage.md +136 -0
  17. data/extra_docs/Encoding.md +96 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +102 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/Index.md +36 -0
  22. data/extra_docs/MimeTypes.md +40 -0
  23. data/extra_docs/Models.md +266 -0
  24. data/extra_docs/Mongo.md +45 -0
  25. data/extra_docs/Processing.md +130 -0
  26. data/extra_docs/Rack.md +52 -0
  27. data/extra_docs/Rails2.md +55 -0
  28. data/extra_docs/Rails3.md +62 -0
  29. data/extra_docs/Sinatra.md +25 -0
  30. data/extra_docs/URLs.md +169 -0
  31. data/features/3.0.3.feature +8 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_2.3.5.feature +7 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +39 -0
  38. data/features/support/env.rb +40 -0
  39. data/fixtures/files/app/models/album.rb +3 -0
  40. data/fixtures/files/app/views/albums/new.html.erb +4 -0
  41. data/fixtures/files/app/views/albums/show.html.erb +4 -0
  42. data/fixtures/files/config/initializers/dragonfly.rb +4 -0
  43. data/fixtures/files/features/manage_album_images.feature +12 -0
  44. data/fixtures/files/features/step_definitions/image_steps.rb +15 -0
  45. data/fixtures/files/features/support/paths.rb +15 -0
  46. data/fixtures/files/features/text_images.feature +7 -0
  47. data/fixtures/rails_2.3.5/template.rb +10 -0
  48. data/fixtures/rails_3.0.3/template.rb +20 -0
  49. data/irbrc.rb +17 -0
  50. data/lib/dragonfly.rb +45 -0
  51. data/lib/dragonfly/active_model_extensions.rb +13 -0
  52. data/lib/dragonfly/active_model_extensions/attachment.rb +169 -0
  53. data/lib/dragonfly/active_model_extensions/class_methods.rb +45 -0
  54. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  55. data/lib/dragonfly/active_model_extensions/validations.rb +37 -0
  56. data/lib/dragonfly/analyser.rb +59 -0
  57. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  58. data/lib/dragonfly/analysis/image_magick_analyser.rb +47 -0
  59. data/lib/dragonfly/analysis/r_magick_analyser.rb +63 -0
  60. data/lib/dragonfly/app.rb +182 -0
  61. data/lib/dragonfly/config/heroku.rb +19 -0
  62. data/lib/dragonfly/config/image_magick.rb +41 -0
  63. data/lib/dragonfly/config/r_magick.rb +46 -0
  64. data/lib/dragonfly/config/rails.rb +17 -0
  65. data/lib/dragonfly/configurable.rb +119 -0
  66. data/lib/dragonfly/core_ext/object.rb +8 -0
  67. data/lib/dragonfly/core_ext/string.rb +9 -0
  68. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  69. data/lib/dragonfly/data_storage.rb +9 -0
  70. data/lib/dragonfly/data_storage/file_data_store.rb +114 -0
  71. data/lib/dragonfly/data_storage/mongo_data_store.rb +82 -0
  72. data/lib/dragonfly/data_storage/s3data_store.rb +115 -0
  73. data/lib/dragonfly/encoder.rb +13 -0
  74. data/lib/dragonfly/encoding/image_magick_encoder.rb +57 -0
  75. data/lib/dragonfly/encoding/r_magick_encoder.rb +61 -0
  76. data/lib/dragonfly/function_manager.rb +69 -0
  77. data/lib/dragonfly/generation/hash_with_css_style_keys.rb +23 -0
  78. data/lib/dragonfly/generation/image_magick_generator.rb +140 -0
  79. data/lib/dragonfly/generation/r_magick_generator.rb +155 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/image_magick_utils.rb +81 -0
  82. data/lib/dragonfly/job.rb +371 -0
  83. data/lib/dragonfly/job_builder.rb +39 -0
  84. data/lib/dragonfly/job_definitions.rb +26 -0
  85. data/lib/dragonfly/job_endpoint.rb +15 -0
  86. data/lib/dragonfly/loggable.rb +28 -0
  87. data/lib/dragonfly/middleware.rb +34 -0
  88. data/lib/dragonfly/processing/image_magick_processor.rb +99 -0
  89. data/lib/dragonfly/processing/r_magick_processor.rb +126 -0
  90. data/lib/dragonfly/processor.rb +9 -0
  91. data/lib/dragonfly/r_magick_utils.rb +48 -0
  92. data/lib/dragonfly/rails/images.rb +22 -0
  93. data/lib/dragonfly/response.rb +82 -0
  94. data/lib/dragonfly/routed_endpoint.rb +40 -0
  95. data/lib/dragonfly/serializer.rb +32 -0
  96. data/lib/dragonfly/simple_cache.rb +23 -0
  97. data/lib/dragonfly/simple_endpoint.rb +63 -0
  98. data/lib/dragonfly/temp_object.rb +220 -0
  99. data/samples/beach.png +0 -0
  100. data/samples/egg.png +0 -0
  101. data/samples/round.gif +0 -0
  102. data/samples/sample.docx +0 -0
  103. data/samples/taj.jpg +0 -0
  104. data/spec/argument_matchers.rb +19 -0
  105. data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
  106. data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
  107. data/spec/dragonfly/active_model_extensions/model_spec.rb +723 -0
  108. data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
  109. data/spec/dragonfly/analyser_spec.rb +123 -0
  110. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +57 -0
  111. data/spec/dragonfly/analysis/image_magick_analyser_spec.rb +15 -0
  112. data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +27 -0
  113. data/spec/dragonfly/analysis/shared_analyser_spec.rb +51 -0
  114. data/spec/dragonfly/app_spec.rb +280 -0
  115. data/spec/dragonfly/config/r_magick_spec.rb +25 -0
  116. data/spec/dragonfly/configurable_spec.rb +220 -0
  117. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  118. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  119. data/spec/dragonfly/data_storage/data_store_spec.rb +76 -0
  120. data/spec/dragonfly/data_storage/file_data_store_spec.rb +169 -0
  121. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +38 -0
  122. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +94 -0
  123. data/spec/dragonfly/deprecation_spec.rb +20 -0
  124. data/spec/dragonfly/encoding/image_magick_encoder_spec.rb +41 -0
  125. data/spec/dragonfly/encoding/r_magick_encoder_spec.rb +37 -0
  126. data/spec/dragonfly/function_manager_spec.rb +154 -0
  127. data/spec/dragonfly/generation/hash_with_css_style_keys_spec.rb +24 -0
  128. data/spec/dragonfly/generation/image_magick_generator_spec.rb +12 -0
  129. data/spec/dragonfly/generation/r_magick_generator_spec.rb +24 -0
  130. data/spec/dragonfly/generation/shared_generator_spec.rb +91 -0
  131. data/spec/dragonfly/image_magick_utils_spec.rb +16 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +120 -0
  135. data/spec/dragonfly/job_spec.rb +773 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +68 -0
  138. data/spec/dragonfly/processing/image_magick_processor_spec.rb +29 -0
  139. data/spec/dragonfly/processing/r_magick_processor_spec.rb +26 -0
  140. data/spec/dragonfly/processing/shared_processing_spec.rb +215 -0
  141. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  142. data/spec/dragonfly/serializer_spec.rb +61 -0
  143. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  144. data/spec/dragonfly/simple_endpoint_spec.rb +89 -0
  145. data/spec/dragonfly/temp_object_spec.rb +352 -0
  146. data/spec/image_matchers.rb +47 -0
  147. data/spec/simple_matchers.rb +44 -0
  148. data/spec/spec_helper.rb +58 -0
  149. data/yard/handlers/configurable_attr_handler.rb +38 -0
  150. data/yard/setup.rb +15 -0
  151. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  152. data/yard/templates/default/layout/html/layout.erb +87 -0
  153. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  154. data/yard/templates/default/module/setup.rb +17 -0
  155. metadata +550 -0
@@ -0,0 +1,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)