dougmcbride-fleximage 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. data/.gitignore +27 -0
  2. data/CHANGELOG.rdoc +14 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +257 -0
  5. data/Rakefile +49 -0
  6. data/VERSION +1 -0
  7. data/autotest.rb +5 -0
  8. data/fleximage.gemspec +236 -0
  9. data/init.rb +1 -0
  10. data/lib/dsl_accessor.rb +52 -0
  11. data/lib/fleximage.rb +59 -0
  12. data/lib/fleximage/aviary_controller.rb +75 -0
  13. data/lib/fleximage/blank.rb +70 -0
  14. data/lib/fleximage/helper.rb +41 -0
  15. data/lib/fleximage/image_proxy.rb +69 -0
  16. data/lib/fleximage/legacy_view.rb +63 -0
  17. data/lib/fleximage/model.rb +726 -0
  18. data/lib/fleximage/operator/background.rb +62 -0
  19. data/lib/fleximage/operator/base.rb +189 -0
  20. data/lib/fleximage/operator/border.rb +50 -0
  21. data/lib/fleximage/operator/crop.rb +58 -0
  22. data/lib/fleximage/operator/image_overlay.rb +85 -0
  23. data/lib/fleximage/operator/resize.rb +92 -0
  24. data/lib/fleximage/operator/shadow.rb +87 -0
  25. data/lib/fleximage/operator/text.rb +104 -0
  26. data/lib/fleximage/operator/trim.rb +14 -0
  27. data/lib/fleximage/operator/unsharp_mask.rb +36 -0
  28. data/lib/fleximage/rmagick_image_patch.rb +5 -0
  29. data/lib/fleximage/string_patch.rb +5 -0
  30. data/lib/fleximage/view.rb +58 -0
  31. data/tasks/fleximage_tasks.rake +154 -0
  32. data/test/fixtures/100x1.jpg +0 -0
  33. data/test/fixtures/100x100.jpg +0 -0
  34. data/test/fixtures/1x1.jpg +0 -0
  35. data/test/fixtures/1x100.jpg +0 -0
  36. data/test/fixtures/cmyk.jpg +0 -0
  37. data/test/fixtures/not_a_photo.xml +1 -0
  38. data/test/fixtures/photo.jpg +0 -0
  39. data/test/mock_file.rb +21 -0
  40. data/test/rails_root/app/controllers/application.rb +10 -0
  41. data/test/rails_root/app/controllers/avatars_controller.rb +85 -0
  42. data/test/rails_root/app/controllers/photo_bares_controller.rb +85 -0
  43. data/test/rails_root/app/controllers/photo_dbs_controller.rb +85 -0
  44. data/test/rails_root/app/controllers/photo_files_controller.rb +85 -0
  45. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  46. data/test/rails_root/app/helpers/avatars_helper.rb +2 -0
  47. data/test/rails_root/app/helpers/photo_bares_helper.rb +2 -0
  48. data/test/rails_root/app/helpers/photo_dbs_helper.rb +2 -0
  49. data/test/rails_root/app/helpers/photo_files_helper.rb +2 -0
  50. data/test/rails_root/app/locales/de.yml +7 -0
  51. data/test/rails_root/app/locales/en.yml +8 -0
  52. data/test/rails_root/app/models/abstract.rb +8 -0
  53. data/test/rails_root/app/models/avatar.rb +4 -0
  54. data/test/rails_root/app/models/photo_bare.rb +7 -0
  55. data/test/rails_root/app/models/photo_custom_error.rb +10 -0
  56. data/test/rails_root/app/models/photo_db.rb +3 -0
  57. data/test/rails_root/app/models/photo_file.rb +3 -0
  58. data/test/rails_root/app/views/avatars/edit.html.erb +17 -0
  59. data/test/rails_root/app/views/avatars/index.html.erb +20 -0
  60. data/test/rails_root/app/views/avatars/new.html.erb +16 -0
  61. data/test/rails_root/app/views/avatars/show.html.erb +8 -0
  62. data/test/rails_root/app/views/layouts/avatars.html.erb +17 -0
  63. data/test/rails_root/app/views/layouts/photo_bares.html.erb +17 -0
  64. data/test/rails_root/app/views/layouts/photo_dbs.html.erb +17 -0
  65. data/test/rails_root/app/views/layouts/photo_files.html.erb +17 -0
  66. data/test/rails_root/app/views/photo_bares/edit.html.erb +12 -0
  67. data/test/rails_root/app/views/photo_bares/index.html.erb +18 -0
  68. data/test/rails_root/app/views/photo_bares/new.html.erb +11 -0
  69. data/test/rails_root/app/views/photo_bares/show.html.erb +3 -0
  70. data/test/rails_root/app/views/photo_dbs/edit.html.erb +32 -0
  71. data/test/rails_root/app/views/photo_dbs/index.html.erb +26 -0
  72. data/test/rails_root/app/views/photo_dbs/new.html.erb +31 -0
  73. data/test/rails_root/app/views/photo_dbs/show.html.erb +23 -0
  74. data/test/rails_root/app/views/photo_files/edit.html.erb +27 -0
  75. data/test/rails_root/app/views/photo_files/index.html.erb +24 -0
  76. data/test/rails_root/app/views/photo_files/new.html.erb +26 -0
  77. data/test/rails_root/app/views/photo_files/show.html.erb +18 -0
  78. data/test/rails_root/config/boot.rb +109 -0
  79. data/test/rails_root/config/database.yml +7 -0
  80. data/test/rails_root/config/environment.rb +66 -0
  81. data/test/rails_root/config/environments/development.rb +18 -0
  82. data/test/rails_root/config/environments/production.rb +19 -0
  83. data/test/rails_root/config/environments/sqlite3.rb +0 -0
  84. data/test/rails_root/config/environments/test.rb +22 -0
  85. data/test/rails_root/config/initializers/inflections.rb +10 -0
  86. data/test/rails_root/config/initializers/load_translations.rb +4 -0
  87. data/test/rails_root/config/initializers/mime_types.rb +5 -0
  88. data/test/rails_root/config/routes.rb +43 -0
  89. data/test/rails_root/db/migrate/001_create_photo_files.rb +16 -0
  90. data/test/rails_root/db/migrate/002_create_photo_dbs.rb +16 -0
  91. data/test/rails_root/db/migrate/003_create_photo_bares.rb +12 -0
  92. data/test/rails_root/db/migrate/004_create_avatars.rb +13 -0
  93. data/test/rails_root/public/.htaccess +40 -0
  94. data/test/rails_root/public/404.html +30 -0
  95. data/test/rails_root/public/422.html +30 -0
  96. data/test/rails_root/public/500.html +30 -0
  97. data/test/rails_root/public/dispatch.cgi +10 -0
  98. data/test/rails_root/public/dispatch.fcgi +24 -0
  99. data/test/rails_root/public/dispatch.rb +10 -0
  100. data/test/rails_root/public/favicon.ico +0 -0
  101. data/test/rails_root/public/images/rails.png +0 -0
  102. data/test/rails_root/public/index.html +277 -0
  103. data/test/rails_root/public/javascripts/application.js +2 -0
  104. data/test/rails_root/public/javascripts/controls.js +963 -0
  105. data/test/rails_root/public/javascripts/dragdrop.js +972 -0
  106. data/test/rails_root/public/javascripts/effects.js +1120 -0
  107. data/test/rails_root/public/javascripts/prototype.js +4225 -0
  108. data/test/rails_root/public/robots.txt +5 -0
  109. data/test/rails_root/public/stylesheets/scaffold.css +74 -0
  110. data/test/rails_root/vendor/plugins/fleximage/init.rb +2 -0
  111. data/test/test_helper.rb +81 -0
  112. data/test/unit/abstract_test.rb +20 -0
  113. data/test/unit/basic_model_test.rb +36 -0
  114. data/test/unit/blank_test.rb +23 -0
  115. data/test/unit/default_image_path_option_test.rb +16 -0
  116. data/test/unit/dsl_accessor_test.rb +120 -0
  117. data/test/unit/file_upload_from_local_test.rb +31 -0
  118. data/test/unit/file_upload_from_strings_test.rb +23 -0
  119. data/test/unit/file_upload_from_url_test.rb +35 -0
  120. data/test/unit/file_upload_to_db_test.rb +41 -0
  121. data/test/unit/i18n_messages_test.rb +49 -0
  122. data/test/unit/image_directory_option_test.rb +20 -0
  123. data/test/unit/image_proxy_test.rb +17 -0
  124. data/test/unit/image_storage_format_option_test.rb +31 -0
  125. data/test/unit/magic_columns_test.rb +34 -0
  126. data/test/unit/minimum_image_size_test.rb +56 -0
  127. data/test/unit/operator_base_test.rb +124 -0
  128. data/test/unit/operator_resize_test.rb +18 -0
  129. data/test/unit/preprocess_image_option_test.rb +21 -0
  130. data/test/unit/require_image_option_test.rb +30 -0
  131. data/test/unit/temp_image_test.rb +23 -0
  132. data/test/unit/use_creation_date_based_directories_option_test.rb +16 -0
  133. metadata +284 -0
@@ -0,0 +1,87 @@
1
+ module Fleximage
2
+ module Operator
3
+
4
+ # Add a drop shadow to the image.
5
+ #
6
+ # image.shadow(options = {})
7
+ #
8
+ # Use the following keys in the +options+ hash:
9
+ #
10
+ # * +offset+: distance of the dropsahdow form the image, in FlexImage *size* format. Positive
11
+ # number move it down and right, negative numbers move it up and left.
12
+ #
13
+ # * +blur+: how blurry the shadow is. Roughly corresponds to distance in pixels of the blur.
14
+ #
15
+ # * +background+: a color for the background of the image. What the shadow fades into.
16
+ # Use an RMagick named color or use the +color+ method in FlexImage::Controller, or a
17
+ # Magick::Pixel object.
18
+ #
19
+ # * +color+: color of the shadow itself.
20
+ # Use an RMagick named color or use the +color+ method in FlexImage::Controller, or a
21
+ # Magick::Pixel object.
22
+ #
23
+ # * +opacity+: opacity of the shadow. A value between 0.0 and 1.0, where 1 is opaque and 0 is
24
+ # transparent.
25
+ #
26
+ # Example:
27
+ #
28
+ # @photo.operate do |image|
29
+ # # Default settings
30
+ # image.shadow(
31
+ # :color => 'black', # or color(0, 0, 0)
32
+ # :background => 'white', # or color(255, 255, 255)
33
+ # :blur => 8,
34
+ # :offset => '2x2',
35
+ # :opacity => 0.75
36
+ # )
37
+ #
38
+ # # Huge, red shadow
39
+ # image.shadow(
40
+ # :color => color(255, 0, 0),
41
+ # :background => 'black', # or color(255, 255, 255)
42
+ # :blur => 30,
43
+ # :offset => '20x10',
44
+ # :opacity => 1
45
+ # )
46
+ # end
47
+ class Shadow < Operator::Base
48
+ def operate(options = {})
49
+ options = options.symbolize_keys if options.respond_to?(:symbolize_keys)
50
+ defaults = {
51
+ :offset => 2,
52
+ :blur => 8,
53
+ :background => 'white',
54
+ :color => 'black',
55
+ :opacity => 0.75
56
+ }
57
+ options = options.is_a?(Hash) ? defaults.update(options) : defaults
58
+
59
+ # verify options
60
+ options[:offset] = size_to_xy(options[:offset])
61
+ options[:blur] = options[:blur].to_i
62
+
63
+ options[:background] = Magick::Pixel.from_color(options[:background]) unless options[:background].is_a?(Magick::Pixel)
64
+ options[:color] = Magick::Pixel.from_color(options[:color]) unless options[:color].is_a?(Magick::Pixel)
65
+ options[:color].opacity = (1 - options[:opacity]) * 255
66
+
67
+ # generate shadow image
68
+ shadow = @image.dup
69
+ shadow.background_color = options[:color]
70
+ shadow.erase!
71
+ shadow.border!(options[:offset].max + options[:blur] * 3, options[:offset].max + options[:blur] * 3, options[:background])
72
+ shadow = shadow.blur_image(0, options[:blur] / 2)
73
+
74
+ # apply shadow
75
+ @image = shadow.composite(
76
+ @image,
77
+ symbol_to_gravity(:top_left),
78
+ (shadow.columns - @image.columns) / 2 - options[:offset][0],
79
+ (shadow.rows - @image.rows) / 2 - options[:offset][1],
80
+ symbol_to_blending_mode(:over)
81
+ )
82
+ @image.trim!
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,104 @@
1
+ module Fleximage
2
+ module Operator
3
+
4
+ # Draw text on the image. Customize size, position, color, dropshadow, and font.
5
+ #
6
+ # image.text(string_to_write, options = {})
7
+ #
8
+ # Use the following keys in the +options+ hash:
9
+ #
10
+ # * alignment: symbol like in <tt>ImageOverlay</tt>
11
+ # * offset: size string
12
+ # * antialias: true or false
13
+ # * color: string or <tt>color(r, g, b)</tt>
14
+ # * font_size: integer
15
+ # * font: path to a font file relative to +RAILS_ROOT+
16
+ # * rotate: degrees as an integer
17
+ # * shadow: <tt>{:blur => 1, :opacity => 1.0}</tt>
18
+ # * font_weight: RMagick font weight constant or value. See: http://www.imagemagick.org/RMagick/doc/draw.html#font_weight
19
+ # * stroke: hash that, if present, will stroke the text. The hash should have both <tt>:width</tt> (integer) and <tt>:color</tt> (string or color object).
20
+ #
21
+ # Example:
22
+ #
23
+ # @photo.operate do |image|
24
+ # image.text('I like Cheese',
25
+ # :alignment => :top_left,
26
+ # :offset => '300x150',
27
+ # :antialias => true,
28
+ # :color => 'pink',
29
+ # :font_size => 24,
30
+ # :font => 'path/to/myfont.ttf',
31
+ # :rotate => -15,
32
+ # :shadow => {
33
+ # :blur => 1,
34
+ # :opacity => 0.5,
35
+ # },
36
+ # :stroke => {
37
+ # :width => 3,
38
+ # :color => color(0, 0, 0),
39
+ # }
40
+ # )
41
+ # end
42
+ class Text < Operator::Base
43
+ def operate(string_to_write, options = {})
44
+ options = {
45
+ :alignment => :top_left,
46
+ :offset => '0x0',
47
+ :antialias => true,
48
+ :color => 'black',
49
+ :font_size => '12',
50
+ :font => nil,
51
+ :text_align => :left,
52
+ :rotate => 0,
53
+ :shadow => nil,
54
+ :stroke => {
55
+ :width => 0,
56
+ :color => 'white',
57
+ }
58
+ }.merge(options)
59
+ options[:offset] = size_to_xy(options[:offset])
60
+
61
+ # prepare drawing surface
62
+ text = Magick::Draw.new
63
+ text.gravity = symbol_to_gravity(options[:alignment])
64
+ text.fill = options[:color]
65
+ text.text_antialias = options[:antialias]
66
+ text.pointsize = options[:font_size].to_i
67
+ text.rotation = options[:rotate]
68
+ text.font_weight = options[:font_weight] if options[:font_weight]
69
+
70
+ if options[:stroke][:width] > 0
71
+ text.stroke_width = options[:stroke][:width]
72
+ text.stroke = options[:stroke][:color]
73
+ end
74
+
75
+ # assign font path with to rails root unless the path is absolute
76
+ if options[:font]
77
+ font = options[:font]
78
+ font = "#{RAILS_ROOT}/#{font}" unless font =~ %r{^(~?|[A-Za-z]:)/}
79
+ text.font = font
80
+ end
81
+
82
+ # draw text on transparent image
83
+ temp_image = Magick::Image.new(@image.columns, @image.rows) { self.background_color = 'none' }
84
+ temp_image = temp_image.annotate(text, 0, 0, options[:offset][0], options[:offset][1], string_to_write)
85
+
86
+ # add drop shadow to text image
87
+ if options[:shadow]
88
+ shadow_args = [2, 2, 1, 1]
89
+ if options[:shadow].is_a?(Hash)
90
+ #shadow_args[0], shadow_args[1] = size_to_xy(options[:shadow][:offset]) if options[:shadow][:offset]
91
+ shadow_args[2] = options[:shadow][:blur] if options[:shadow][:blur]
92
+ shadow_args[3] = options[:shadow][:opacity] if options[:shadow][:opacity]
93
+ end
94
+ shadow = temp_image.shadow(*shadow_args)
95
+ temp_image = shadow.composite(temp_image, 0, 0, symbol_to_blending_mode(:over))
96
+ end
97
+
98
+ # composite text on original image
99
+ @image.composite!(temp_image, 0, 0, symbol_to_blending_mode(:over))
100
+ end
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,14 @@
1
+ module Fleximage
2
+ module Operator
3
+
4
+ # Trim off all the pixels around the image border that have the same color.
5
+ #
6
+ # image.trim
7
+ class Trim < Operator::Base
8
+ def operate()
9
+ @image.trim!(true)
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ module Fleximage
2
+ module Operator
3
+
4
+ # Sharpen an image using an unsharp mask filter.
5
+ #
6
+ # image.unsharp_mask(options = {})
7
+ #
8
+ # Use the following keys in the +options+ hash:
9
+ #
10
+ # * +radius+: The radius of the Gaussian operator. The default is 0.0.
11
+ # * +sigma+: The standard deviation of the Gaussian operator. A good starting value is 1.0, which is the default.
12
+ # * +amount+: The percentage of the blurred image to be added to the receiver, specified as a fraction between 0 and 1.0. A good starting value is 1.0, which is the default.
13
+ # * +threshold+: The threshold needed to apply the amount, specified as a fraction between 0 and 1.0. A good starting value is 0.05, which is the default.
14
+ #
15
+ # Example:
16
+ #
17
+ # @photo.operate do |image|
18
+ # image.unsharp_mask
19
+ # end
20
+ class UnsharpMask < Operator::Base
21
+ def operate(options = {})
22
+ options = options.symbolize_keys if options.respond_to?(:symbolize_keys)
23
+ options = {
24
+ :radius => 0.0,
25
+ :sigma => 1.0,
26
+ :amount => 1.0,
27
+ :threshold => 0.05
28
+ }.merge(options)
29
+
30
+ # sharpen image
31
+ @image = @image.unsharp_mask(options[:radius], options[:sigma], options[:amount], options[:threshold])
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ class Magick::Image
2
+ def dispose!
3
+ destroy! if respond_to?(:destroy!)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ unless "string".respond_to?(:present?)
2
+ class String
3
+ alias_method :present?, :present?
4
+ end
5
+ end
@@ -0,0 +1,58 @@
1
+ module Fleximage
2
+
3
+ # Renders a .flexi template
4
+ class View < ActionView::TemplateHandler #:nodoc:
5
+ class TemplateDidNotReturnImage < RuntimeError #:nodoc:
6
+ end
7
+
8
+ def self.call(template)
9
+ "Fleximage::View.new(self).render(template)"
10
+ end
11
+
12
+ def initialize(action_view)
13
+ @view = action_view
14
+ end
15
+
16
+ def render(template)
17
+ # process the view
18
+ result = @view.instance_eval do
19
+
20
+ # Shorthand color creation
21
+ def color(*args)
22
+ Fleximage::Operator::Base.color(*args)
23
+ end
24
+
25
+ #execute the template
26
+ eval(template.source)
27
+ end
28
+
29
+ # Raise an error if object returned from template is not an image record
30
+ unless result.class.include?(Fleximage::Model::InstanceMethods)
31
+ raise TemplateDidNotReturnImage,
32
+ ".flexi template was expected to return a model instance that acts_as_fleximage, but got an instance of <#{result.class}> instead."
33
+ end
34
+
35
+ # Figure out the proper format
36
+ requested_format = (@view.params[:format] || :jpg).to_sym
37
+ requested_format = :jpg if requested_format == :jpeg
38
+ unless [:jpg, :gif, :png].include?(requested_format)
39
+ raise 'Image must be requested with an image type format. jpg, gif and png only are supported.'
40
+ end
41
+
42
+ # Set proper content type
43
+ @view.controller.response.content_type = Mime::Type.lookup_by_extension(requested_format.to_s).to_s
44
+
45
+ # Set proper caching headers
46
+ if defined?(Rails) && Rails.env == 'production'
47
+ @view.controller.response.headers['Cache-Control'] = 'public, max-age=86400'
48
+ end
49
+
50
+ # return rendered result
51
+ return result.output_image(:format => requested_format)
52
+ ensure
53
+
54
+ # ensure garbage collection happens after every flex image render
55
+ GC.start
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,154 @@
1
+ namespace :fleximage do
2
+
3
+ # Find the model class
4
+ def model_class
5
+ raise 'You must specify a FLEXIMAGE_CLASS=MyClass' unless ENV['FLEXIMAGE_CLASS']
6
+ @model_class ||= ENV['FLEXIMAGE_CLASS'].camelcase.constantize
7
+ end
8
+
9
+ desc "Populate width and height magic columns from the current image store. Useful when migrating from on old installation."
10
+ task :dimensions => :environment do
11
+ model_class.find(:all).each do |obj|
12
+ if obj.has_image?
13
+ img = obj.load_image
14
+ obj.update_attribute :image_width, img.columns if obj.respond_to?(:image_width=)
15
+ obj.update_attribute :image_height, img.rows if obj.respond_to?(:image_height=)
16
+ end
17
+ end
18
+ end
19
+
20
+ namespace :convert do
21
+
22
+ def convert_directory_format(to_format)
23
+ model_class.find(:all).each do |obj|
24
+
25
+ # Get the creation date
26
+ creation = obj[:created_at] || obj[:created_on]
27
+
28
+ # Generate both types of file paths
29
+ flat_path = "#{RAILS_ROOT}/#{model_class.image_directory}/#{obj.id}.#{model_class.image_storage_format}"
30
+ nested_path = "#{RAILS_ROOT}/#{model_class.image_directory}/#{creation.year}/#{creation.month}/#{creation.day}/#{obj.id}.#{model_class.image_storage_format}"
31
+
32
+ # Assign old path and new path based on desired directory format
33
+ if to_format == :nested
34
+ old_path = flat_path
35
+ new_path = nested_path
36
+ else
37
+ old_path = nested_path
38
+ new_path = flat_path
39
+ end
40
+
41
+ # Move the files
42
+ if old_path != new_path && File.exists?(old_path)
43
+ FileUtils.mkdir_p(File.dirname(new_path))
44
+ FileUtils.move old_path, new_path
45
+ puts "#{old_path} -> #{new_path}"
46
+ end
47
+ end
48
+ end
49
+
50
+ def convert_image_format(to_format)
51
+ model_class.find(:all).each do |obj|
52
+
53
+ # convert DB stored images
54
+ if model_class.db_store?
55
+ if obj.image_file_data && obj.image_file_data.any?
56
+ begin
57
+ image = Magick::Image.from_blob(obj.image_file_data).first
58
+ image.format = to_format.to_s.upcase
59
+ obj.image_file_data = image.to_blob
60
+ obj.save
61
+ rescue Exception => e
62
+ puts "Could not convert image for #{model_class} with id #{obj.id}\n #{e.class} #{e}\n"
63
+ end
64
+ end
65
+
66
+ # Convert file system stored images
67
+ else
68
+ # Generate both types of file paths
69
+ png_path = obj.file_path.gsub(/\.jpg$/, '.png')
70
+ jpg_path = obj.file_path.gsub(/\.png$/, '.jpg')
71
+
72
+ # Output stub
73
+ output = (to_format == :jpg) ? 'PNG -> JPG' : 'JPG -> PNG'
74
+
75
+ # Assign old path and new path based on desired image format
76
+ if to_format == :jpg
77
+ old_path = png_path
78
+ new_path = jpg_path
79
+ else
80
+ old_path = jpg_path
81
+ new_path = png_path
82
+ end
83
+
84
+ # Perform conversion
85
+ if File.exists?(old_path)
86
+ image = Magick::Image.read(old_path).first
87
+ image.format = to_format.to_s.upcase
88
+ image.write(new_path)
89
+ File.delete(old_path)
90
+
91
+ puts "#{output} : Image #{obj.id}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def ensure_db_store
98
+ col = model_class.columns.find {|c| c.name == 'image_file_data'}
99
+ unless col && col.type == :binary
100
+ raise "No image_file_data field of type :binary for this model!"
101
+ end
102
+ end
103
+
104
+ desc "Convert a flat images/123.png style image store to a images/2007/11/12/123.png style. Requires FLEXIMAGE_CLASS=ModelName"
105
+ task :to_nested => :environment do
106
+ convert_directory_format :nested
107
+ end
108
+
109
+ desc "Convert a nested images/2007/11/12/123.png style image store to a images/123.png style. Requires FLEXIMAGE_CLASS=ModelName"
110
+ task :to_flat => :environment do
111
+ convert_directory_format :flat
112
+ end
113
+
114
+ desc "Convert master images stored as JPGs to PNGs"
115
+ task :to_png => :environment do
116
+ convert_image_format :png
117
+ end
118
+
119
+ desc "Convert master images stored as PNGs to JPGs"
120
+ task :to_jpg => :environment do
121
+ convert_image_format :jpg
122
+ end
123
+
124
+ desc "Convert master image storage to use the database. Loads all file-stored images into the database."
125
+ task :to_db => :environment do
126
+ ensure_db_store
127
+ model_class.find(:all).each do |obj|
128
+ if File.exists?(obj.file_path)
129
+ File.open(obj.file_path, 'rb') do |f|
130
+ obj.image_file_data = f.read
131
+ obj.save
132
+ end
133
+ end
134
+ end
135
+
136
+ puts "--- All images successfully moved to the database. Check to make sure the transfer worked cleanly before deleting your file system image store."
137
+ end
138
+
139
+ desc "Convert master image storage to use the file system. Loads all database images into files."
140
+ task :to_filestore => :environment do
141
+ ensure_db_store
142
+ model_class.find(:all).each do |obj|
143
+ if obj.image_file_data && obj.image_file_data.any?
144
+ File.open(obj.file_path, 'wb+') do |f|
145
+ f.write obj.image_file_data
146
+ end
147
+ end
148
+ end
149
+
150
+ puts "--- All images successfully moved to the file system. Remember to remove your image_file_data field from your models database table."
151
+ end
152
+
153
+ end
154
+ end