dragonfly-minimagick 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dragonfly-minimagick.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec', ">= 2.0"
data/README.markdown ADDED
@@ -0,0 +1,17 @@
1
+ Dragonfly-Minimagick
2
+ =================
3
+
4
+ Dragonfly-Minimagick was extracted from the original dragonfly code and provides an analyser, processor, encoder and generator for Dragonfly using the MiniMagick image library.
5
+
6
+ It shouldn't be necessary and is provided here in case it's needed for some reason!
7
+
8
+ Usage
9
+ -----
10
+
11
+ require 'dragonfly-minimagick'
12
+ Dragonfly[:images].configure_with(:minimagick)
13
+
14
+ In Rails, the above would be done in an initializer.
15
+
16
+ See the [dragonfly documentation](http://markevans.github.com/dragonfly) for more info, as the equivalent ImageMagick methods have the same API.
17
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec) do |spec|
9
+ spec.pattern = FileList['spec/**/*_spec.rb']
10
+ end
11
+
12
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dragonfly-minimagick/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "dragonfly-minimagick"
7
+ s.version = Dragonfly::Minimagick::VERSION
8
+ s.authors = ["Paul Spieker"]
9
+ s.email = ["p.spieker@duenos.de"]
10
+ s.homepage = "https://github.com/spieker/dragonfly-minimagick"
11
+ s.summary = %q{Use MiniMagick for image processing within Dragonfly}
12
+ s.description = %q{Not yet completely implemented}
13
+
14
+ s.rubyforge_project = "dragonfly-minimagick"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency("dragonfly", [">= 0.9"])
22
+ s.add_dependency("mini_magick", ["~> 3.3"])
23
+ s.add_development_dependency("rspec", [">= 2.0"])
24
+ end
@@ -0,0 +1,16 @@
1
+ require "dragonfly-minimagick/version"
2
+
3
+ module Dragonfly
4
+ module Minimagick
5
+ # Your code goes here...
6
+ end
7
+ end
8
+
9
+ require 'dragonfly-minimagick/analyser'
10
+ require 'dragonfly-minimagick/processor'
11
+ require 'dragonfly-minimagick/encoder'
12
+ require 'dragonfly-minimagick/generator'
13
+ require 'dragonfly-minimagick/config'
14
+
15
+ Dragonfly::App.register_configuration(:minimagick){ Dragonfly::Minimagick::Config }
16
+ Dragonfly::App.register_configuration(:mini_magick){ Dragonfly::Minimagick::Config }
@@ -0,0 +1,67 @@
1
+ require 'mini_magick'
2
+ require 'dragonfly'
3
+ require 'dragonfly-minimagick/utils'
4
+
5
+ module Dragonfly
6
+ module Minimagick
7
+ class Analyser
8
+
9
+ include Utils
10
+ include Dragonfly::Configurable
11
+
12
+ def width(temp_object)
13
+ ping_minimagick_image(temp_object) do |image|
14
+ image[:width]
15
+ end
16
+ end
17
+
18
+ def height(temp_object)
19
+ ping_minimagick_image(temp_object) do |image|
20
+ image[:height]
21
+ end
22
+ end
23
+
24
+ def aspect_ratio(temp_object)
25
+ ping_minimagick_image(temp_object) do |image|
26
+ image[:width].to_f / image[:height].to_f
27
+ end
28
+ end
29
+
30
+ def portrait?(temp_object)
31
+ ping_minimagick_image(temp_object) do |image|
32
+ image[:width] <= image[:height]
33
+ end
34
+ end
35
+
36
+ def landscape?(temp_object)
37
+ ping_minimagick_image(temp_object) do |image|
38
+ image[:width] >= image[:height]
39
+ end
40
+ end
41
+
42
+ def depth(temp_object)
43
+ minimagick_image(temp_object) do |image|
44
+ image.verbose.match(/(\d{1,2})-bit/)[1].to_i
45
+ end
46
+ end
47
+
48
+ def number_of_colours(temp_object)
49
+ minimagick_image(temp_object) do |image|
50
+ # image.colors
51
+ 0
52
+ end
53
+ end
54
+ alias number_of_colors number_of_colours
55
+
56
+ def format(temp_object)
57
+ ping_minimagick_image(temp_object) do |image|
58
+ image[:format].downcase.to_sym
59
+ end
60
+ end
61
+
62
+ def image?(temp_object)
63
+ !!catch(:unable_to_handle){ format(temp_object) }
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ module Dragonfly
2
+ module Minimagick
3
+
4
+ # Minimagick is a saved configuration for Dragonfly apps, which does the following:
5
+ # - registers an minimagick analyser
6
+ # - registers an minimagick processor
7
+ # - registers an minimagick encoder
8
+ # - registers an minimagick generator
9
+ # - adds thumb shortcuts like '280x140!', etc.
10
+ # Look at the source code for apply_configuration to see exactly how it configures the app.
11
+ module Config
12
+ def self.apply_configuration(app, opts={})
13
+ app.configure do |c|
14
+ c.analyser.register(Analyser) do |a|
15
+ end
16
+ c.processor.register(Processor) do |p|
17
+ end
18
+ c.encoder.register(Encoder) do |e|
19
+ end
20
+ c.generator.register(Generator) do |g|
21
+ end
22
+ c.job :thumb do |geometry, format|
23
+ process :thumb, geometry
24
+ encode format if format
25
+ end
26
+ c.job :gif do
27
+ encode :gif
28
+ end
29
+ c.job :jpg do
30
+ encode :jpg
31
+ end
32
+ c.job :png do
33
+ encode :png
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+ require 'mini_magick'
2
+ require 'dragonfly'
3
+ require 'dragonfly-minimagick/utils'
4
+
5
+ module Dragonfly
6
+ module Minimagick
7
+ class Encoder
8
+
9
+ include Utils
10
+ include Dragonfly::Configurable
11
+
12
+ configurable_attr :supported_formats, [
13
+ :ai,
14
+ :bmp,
15
+ :eps,
16
+ :gif,
17
+ :gif87,
18
+ :ico,
19
+ :j2c,
20
+ :jp2,
21
+ :jpeg,
22
+ :jpg,
23
+ :pbm,
24
+ :pcd,
25
+ :pct,
26
+ :pcx,
27
+ :pdf,
28
+ :pict,
29
+ :pjpeg,
30
+ :png,
31
+ :png24,
32
+ :png32,
33
+ :png8,
34
+ :pnm,
35
+ :ppm,
36
+ :ps,
37
+ :psd,
38
+ :ras,
39
+ :tga,
40
+ :tiff,
41
+ :wbmp,
42
+ :xbm,
43
+ :xpm,
44
+ :xwd
45
+ ]
46
+
47
+ def encode(temp_object, format, encoding={})
48
+ format = format.to_s.downcase
49
+ throw :unable_to_handle unless supported_formats.include?(format.to_sym)
50
+ minimagick_image(temp_object) do |image|
51
+ if image[:format].downcase == format
52
+ temp_object # do nothing
53
+ else
54
+ image.format(format)
55
+ image
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,156 @@
1
+ require 'mini_magick'
2
+ require 'dragonfly'
3
+ require 'dragonfly-minimagick/utils'
4
+
5
+ module Dragonfly
6
+ module Minimagick
7
+ class Generator
8
+
9
+ FONT_STYLES = {
10
+ 'normal' => 'normal', #Magick::NormalStyle,
11
+ 'italic' => 'italic', #Magick::ItalicStyle,
12
+ 'oblique' => 'oblique' #Magick::ObliqueStyle
13
+ }
14
+
15
+ FONT_STRETCHES = {
16
+ 'normal' => 'normal', #Magick::NormalStretch,
17
+ 'semi-condensed' => 'semi-condensed', #Magick::SemiCondensedStretch,
18
+ 'condensed' => 'condensed', #Magick::CondensedStretch,
19
+ 'extra-condensed' => 'extra-condensed', #Magick::ExtraCondensedStretch,
20
+ 'ultra-condensed' => 'ultra-condensed', #Magick::UltraCondensedStretch,
21
+ 'semi-expanded' => 'semi-expanded', #Magick::SemiExpandedStretch,
22
+ 'expanded' => 'expanded', #Magick::ExpandedStretch,
23
+ 'extra-expanded' => 'extra-expanded', #Magick::ExtraExpandedStretch,
24
+ 'ultra-expanded' => 'ultra-expanded' #Magick::UltraExpandedStretch
25
+ }
26
+
27
+ FONT_WEIGHTS = {
28
+ 'normal' => 'normal', #Magick::NormalWeight,
29
+ 'bold' => 'bold', #Magick::BoldWeight,
30
+ 'bolder' => 'bolder', #Magick::BolderWeight,
31
+ 'lighter' => 'lighter', #Magick::LighterWeight,
32
+ '100' => 100,
33
+ '200' => 200,
34
+ '300' => 300,
35
+ '400' => 400,
36
+ '500' => 500,
37
+ '600' => 600,
38
+ '700' => 700,
39
+ '800' => 800,
40
+ '900' => 900
41
+ }
42
+
43
+ include Utils
44
+ include Dragonfly::Configurable
45
+
46
+ def plasma(width, height, format='png')
47
+ image = MiniMagick::Image.read("plasma:fractal"){self.size = "#{width}x#{height}"}.first
48
+ image.format = format.to_s
49
+ content = write_to_tempfile(image)
50
+ image.destroy!
51
+ [
52
+ content,
53
+ {:format => format.to_sym, :name => "plasma.#{format}"}
54
+ ]
55
+ end
56
+
57
+ def text(text_string, opts={})
58
+ opts = Dragonfly::HashWithCssStyleKeys[opts]
59
+
60
+ draw = MiniMagick::Draw.new
61
+ draw.gravity = 'center'
62
+ draw.text_antialias = true
63
+
64
+ # Font size
65
+ font_size = (opts[:font_size] || 12).to_i
66
+
67
+ # Scale up the text for better quality -
68
+ # it will be reshrunk at the end
69
+ s = scale_factor_for(font_size)
70
+
71
+ # Settings
72
+ draw.pointsize = font_size * s
73
+ draw.font = opts[:font] if opts[:font]
74
+ draw.font_family = opts[:font_family] if opts[:font_family]
75
+ draw.fill = opts[:color] if opts[:color]
76
+ draw.stroke = opts[:stroke_color] if opts[:stroke_color]
77
+ draw.font_style = FONT_STYLES[opts[:font_style]] if opts[:font_style]
78
+ draw.font_stretch = FONT_STRETCHES[opts[:font_stretch]] if opts[:font_stretch]
79
+ draw.font_weight = FONT_WEIGHTS[opts[:font_weight]] if opts[:font_weight]
80
+
81
+ # Padding
82
+ # NB the values are scaled up by the scale factor
83
+ pt, pr, pb, pl = parse_padding_string(opts[:padding]) if opts[:padding]
84
+ padding_top = (opts[:padding_top] || pt || 0) * s
85
+ padding_right = (opts[:padding_right] || pr || 0) * s
86
+ padding_bottom = (opts[:padding_bottom] || pb || 0) * s
87
+ padding_left = (opts[:padding_left] || pl || 0) * s
88
+
89
+ # Calculate (scaled up) dimensions
90
+ metrics = draw.get_type_metrics(text_string)
91
+ width, height = metrics.width, metrics.height
92
+
93
+ scaled_up_width = padding_left + width + padding_right
94
+ scaled_up_height = padding_top + height + padding_bottom
95
+
96
+ # Draw the background
97
+ image = MiniMagick::Image.new(scaled_up_width, scaled_up_height){
98
+ self.background_color = opts[:background_color] || 'transparent'
99
+ }
100
+ # Draw the text
101
+ draw.annotate(image, width, height, padding_left, padding_top, text_string)
102
+
103
+ # Scale back down again
104
+ image.scale!(1/s)
105
+
106
+ format = opts[:format] || :png
107
+ image.format = format.to_s
108
+
109
+ # Output image either as a string or a tempfile
110
+ content = write_to_tempfile(image)
111
+ image.destroy!
112
+ [
113
+ content,
114
+ {:format => format, :name => "text.#{format}"}
115
+ ]
116
+ end
117
+
118
+ private
119
+
120
+ # Use css-style padding declaration, i.e.
121
+ # 10 (all sides)
122
+ # 10 5 (top/bottom, left/right)
123
+ # 10 5 10 (top, left/right, bottom)
124
+ # 10 5 10 5 (top, right, bottom, left)
125
+ def parse_padding_string(str)
126
+ padding_parts = str.gsub('px','').split(/\s+/).map{|px| px.to_i}
127
+ case padding_parts.size
128
+ when 1
129
+ p = padding_parts.first
130
+ [p,p,p,p]
131
+ when 2
132
+ p,q = padding_parts
133
+ [p,q,p,q]
134
+ when 3
135
+ p,q,r = padding_parts
136
+ [p,q,r,q]
137
+ when 4
138
+ padding_parts
139
+ else raise ArgumentError, "Couldn't parse padding string '#{str}' - should be a css-style string"
140
+ end
141
+ end
142
+
143
+ def scale_factor_for(font_size)
144
+ # Scale approximately to 64 if below
145
+ min_size = 64
146
+ if font_size < min_size
147
+ (min_size.to_f / font_size).ceil
148
+ else
149
+ 1
150
+ end.to_f
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+ end
@@ -0,0 +1,155 @@
1
+ require 'mini_magick'
2
+ require 'dragonfly'
3
+ require 'dragonfly-minimagick/utils'
4
+
5
+ module Dragonfly
6
+ module Minimagick
7
+ class Processor
8
+
9
+ GRAVITIES = {
10
+ 'nw' => 'NorthWest',
11
+ 'n' => 'North',
12
+ 'ne' => 'NorthEast',
13
+ 'w' => 'West',
14
+ 'c' => 'Center',
15
+ 'e' => 'East',
16
+ 'sw' => 'SouthWest',
17
+ 's' => 'South',
18
+ 'se' => 'SouthEast'
19
+ }
20
+
21
+ # Geometry string patterns
22
+ RESIZE_GEOMETRY = /^\d*x\d*[><%^!]?$|^\d+@$/ # e.g. '300x200!'
23
+ CROPPED_RESIZE_GEOMETRY = /^(\d+)x(\d+)#(\w{1,2})?$/ # e.g. '20x50#ne'
24
+ CROP_GEOMETRY = /^(\d+)x(\d+)([+-]\d+)?([+-]\d+)?(\w{1,2})?$/ # e.g. '30x30+10+10'
25
+ THUMB_GEOMETRY = Regexp.union RESIZE_GEOMETRY, CROPPED_RESIZE_GEOMETRY, CROP_GEOMETRY
26
+
27
+ include Utils
28
+ include Dragonfly::Configurable
29
+
30
+ def crop(temp_object, opts={})
31
+ x = opts[:x].to_i
32
+ y = opts[:y].to_i
33
+ gravity = GRAVITIES[opts[:gravity]] || nil #Magick::ForgetGravity
34
+ width = opts[:width].to_i
35
+ height = opts[:height].to_i
36
+
37
+ unless opts.has_key?(:width) and opts.has_key?(:height) or opts.has_key?(:x) and opts.has_key?(:y)
38
+ return minimagick_image(temp_object) do |image|
39
+ image
40
+ end
41
+ end
42
+ minimagick_image(temp_object) do |image|
43
+ unless opts.has_key?(:width) and opts.has_key?(:height)
44
+ width = image[:width] - x
45
+ height = image[:height] - y
46
+ end
47
+ # Minimagick throws an error if the cropping area is bigger than the image,
48
+ # when the gravity is something other than nw
49
+ width = image[:width] - x if x + width > image[:width]
50
+ height = image[:height] - y if y + height > image[:height]
51
+ # p "\n\n#{opts[:width]}x#{opts[:height]}+#{opts[:x]}+#{opts[:y]} \n#{width}x#{height}+#{x}+#{y}"
52
+ image.gravity gravity unless gravity.nil? or gravity.empty?
53
+ image.crop "#{width}x#{height}+#{x}+#{y}" #(gravity, x, y, width, height)
54
+ image
55
+ end
56
+ end
57
+
58
+ def flip(temp_object)
59
+ minimagick_image(temp_object) do |image|
60
+ image.flip
61
+ image
62
+ end
63
+ end
64
+
65
+ def flop(temp_object)
66
+ minimagick_image(temp_object) do |image|
67
+ image.flop
68
+ image
69
+ end
70
+ end
71
+
72
+ def greyscale(temp_object, opts={})
73
+ depth = opts[:depth] || 256
74
+ minimagick_image(temp_object) do |image|
75
+ image.quantize(depth, nil) #Magick::GRAYColorspace)
76
+ image
77
+ end
78
+ end
79
+ alias grayscale greyscale
80
+
81
+ def resize(temp_object, geometry)
82
+ minimagick_image(temp_object) do |image|
83
+ # image.change_geometry!(geometry) do |cols, rows, img|
84
+ # img.resize!(cols, rows)
85
+ # end
86
+ image.resize geometry
87
+ image
88
+ end
89
+ end
90
+
91
+ def resize_and_crop(temp_object, opts={})
92
+ unless opts.has_key?(:width) or opts.has_key?(:height)
93
+ return minimagick_image(temp_object) do |image|
94
+ image
95
+ end
96
+ end
97
+
98
+ minimagick_image(temp_object) do |image|
99
+ width = opts[:width] ? opts[:width].to_i : image[:width]
100
+ height = opts[:height] ? opts[:height].to_i : image[:height]
101
+ gravity = GRAVITIES[opts[:gravity]] || 'center'
102
+ image.combine_options do |i|
103
+ i.resize "#{width}x#{height}^"
104
+ i.gravity gravity
105
+ i.extent "#{width}x#{height}"
106
+ end
107
+ # image.crop_resized(width, height, gravity)
108
+ image
109
+ end
110
+ end
111
+
112
+ def rotate(temp_object, amount, opts={})
113
+ args = [amount.to_f]
114
+ args << opts[:qualifier] if opts[:qualifier]
115
+ minimagick_image(temp_object) do |image|
116
+ image.background_color = opts[:background_colour] if opts[:background_colour]
117
+ image.background_color = opts[:background_color] if opts[:background_color]
118
+ image.rotate(args.join(''))
119
+ image
120
+ end
121
+ end
122
+
123
+ def thumb(temp_object, geometry)
124
+ case geometry
125
+ when RESIZE_GEOMETRY
126
+ resize(temp_object, geometry)
127
+ when CROPPED_RESIZE_GEOMETRY
128
+ resize_and_crop(temp_object, :width => $1, :height => $2, :gravity => $3)
129
+ when CROP_GEOMETRY
130
+ crop(temp_object,
131
+ :width => $1,
132
+ :height => $2,
133
+ :x => $3,
134
+ :y => $4,
135
+ :gravity => $5
136
+ )
137
+ else raise ArgumentError, "Didn't recognise the geometry string #{geometry}"
138
+ end
139
+ end
140
+
141
+ def vignette(temp_object, opts={})
142
+ x = opts[:x].to_f || temp_object.width * 0.1
143
+ y = opts[:y].to_f || temp_object.height * 0.1
144
+ radius = opts[:radius].to_f || 0.0
145
+ sigma = opts[:sigma].to_f || 10.0
146
+
147
+ minimagick_image(temp_object) do |image|
148
+ image.vignette(x, y, radius, sigma)
149
+ image
150
+ end
151
+ end
152
+
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,49 @@
1
+ require 'tempfile'
2
+ require 'mini_magick'
3
+ require 'dragonfly'
4
+
5
+ module Dragonfly
6
+ module Minimagick
7
+ module Utils
8
+
9
+ include Dragonfly::Loggable
10
+
11
+ private
12
+
13
+ def minimagick_image(temp_object, &block)
14
+ image = MiniMagick::Image.open(temp_object.path)
15
+ result = block.call(image)
16
+ case result
17
+ when MiniMagick::Image
18
+ content = write_to_tempfile(result)
19
+ result.destroy!
20
+ else
21
+ content = result
22
+ end
23
+ image.destroy!
24
+ content
25
+ rescue Exception => e
26
+ log.warn("Unable to handle content in #{self.class} - got:\n#{e}")
27
+ throw :unable_to_handle
28
+ end
29
+
30
+ def ping_minimagick_image(temp_object, &block)
31
+ image = MiniMagick::Image.open(temp_object.path)
32
+ result = block.call(image)
33
+ image.destroy!
34
+ result
35
+ rescue Exception => e
36
+ log.warn("Unable to handle content in #{self.class} - got:\n#{e}")
37
+ throw :unable_to_handle
38
+ end
39
+
40
+ def write_to_tempfile(minimagick_image)
41
+ tempfile = Tempfile.new('dragonfly')
42
+ tempfile.close
43
+ minimagick_image.write(tempfile.path)
44
+ tempfile
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ module Dragonfly
2
+ module Minimagick
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
data/samples/beach.png ADDED
Binary file
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "image analyser methods" do
4
+
5
+ # NEEDS:
6
+ # @image
7
+ # @processor
8
+
9
+ it "should return the width" do
10
+ @analyser.width(@image).should == 280
11
+ end
12
+
13
+ it "should return the height" do
14
+ @analyser.height(@image).should == 355
15
+ end
16
+
17
+ it "should return the aspect ratio" do
18
+ @analyser.aspect_ratio(@image).should == (280.0/355.0)
19
+ end
20
+
21
+ it "should say if it's portrait" do
22
+ @analyser.portrait?(@image).should be_true
23
+ end
24
+
25
+ it "should say if it's landscape" do
26
+ @analyser.landscape?(@image).should be_false
27
+ end
28
+
29
+ it "should return the number of colours" do
30
+ # @analyser.number_of_colours(@image).should == 34703
31
+ end
32
+
33
+ it "should return the depth" do
34
+ @analyser.depth(@image).should == 8
35
+ end
36
+
37
+ it "should return the format" do
38
+ @analyser.format(@image).should == :png
39
+ end
40
+
41
+ # %w(width height aspect_ratio number_of_colours depth format portrait? landscape?).each do |meth|
42
+ # it "should throw unable_to_handle in #{meth.inspect} if it's not an image file" do
43
+ # temp_object = Dragonfly::TempObject.new('blah')
44
+ # lambda{
45
+ # @analyser.send(meth, temp_object)
46
+ # }.should throw_symbol(:unable_to_handle)
47
+ # end
48
+ # end
49
+
50
+ end
51
+
52
+ describe Dragonfly::Minimagick::Analyser do
53
+
54
+ before(:each) do
55
+ image_path = SAMPLES_DIR + '/beach.png'
56
+ @image = Dragonfly::TempObject.new(File.new(image_path))
57
+ @analyser = Dragonfly::Minimagick::Analyser.new
58
+ @analyser.log = Logger.new(LOG_FILE)
59
+ end
60
+
61
+ describe "when using the filesystem" do
62
+ before(:each) do
63
+ end
64
+ it_should_behave_like "image analyser methods"
65
+ end
66
+
67
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::Minimagick::Config do
4
+
5
+ before(:each) do
6
+ @app = test_app
7
+ end
8
+
9
+ it "should configure all to use the filesystem by default" do
10
+ @app.configure_with(Dragonfly::Minimagick::Config)
11
+ end
12
+
13
+ it "should allow configuring with :minimagick" do
14
+ @app.configure_with(:minimagick)
15
+ @app.analyser.objects.first.should be_a(Dragonfly::Minimagick::Analyser)
16
+ end
17
+
18
+ it "should allow configuring with :mini_magick" do
19
+ @app.configure_with(:mini_magick)
20
+ @app.analyser.objects.first.should be_a(Dragonfly::Minimagick::Analyser)
21
+ end
22
+
23
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dragonfly::Minimagick::Encoder do
4
+
5
+ before(:all) do
6
+ sample_file = SAMPLES_DIR + '/beach.png' # 280x355
7
+ @image = Dragonfly::TempObject.new(File.new(sample_file))
8
+ @encoder = Dragonfly::Minimagick::Encoder.new
9
+ end
10
+
11
+ describe "#encode" do
12
+
13
+ it "should encode the image to the correct format" do
14
+ image = @encoder.encode(@image, :gif)
15
+ image.should have_format('gif')
16
+ end
17
+
18
+ it "should throw :unable_to_handle if the format is not handleable" do
19
+ lambda{
20
+ @encoder.encode(@image, :goofy)
21
+ }.should throw_symbol(:unable_to_handle)
22
+ end
23
+
24
+ it "should do nothing if the image is already in the correct format" do
25
+ image = @encoder.encode(@image, :png)
26
+ image.should == @image
27
+ end
28
+
29
+ it "should work when not using the filesystem" do
30
+ image = @encoder.encode(@image, :gif)
31
+ image.should have_format('gif')
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ # Needs: @generator
4
+ shared_examples_for "image generator" do
5
+
6
+ describe "generating an image with the given dimensions" do
7
+ before(:each) do
8
+ @image, @extra = @generator.plasma(23,12)
9
+ end
10
+ it {@image.should have_width(23)}
11
+ it {@image.should have_height(12)}
12
+ it {@image.should have_format('png')}
13
+ it {@extra.should == {:format => :png, :name => 'plasma.png'}}
14
+ end
15
+
16
+ describe "specifying the format" do
17
+ before(:each) do
18
+ @image, @extra = @generator.plasma(23, 12, :gif)
19
+ end
20
+ it {@image.should have_format('gif')}
21
+ it {@extra.should == {:format => :gif, :name => 'plasma.gif'}}
22
+ end
23
+
24
+ describe "text" do
25
+ before(:each) do
26
+ @text = "mmm"
27
+ end
28
+
29
+ describe "creating a text image" do
30
+ before(:each) do
31
+ @image, @extra = @generator.text(@text, :font_size => 12)
32
+ end
33
+ it {@image.should have_width(20..40)} # approximate
34
+ it {@image.should have_height(10..20)}
35
+ it {@image.should have_format('png')}
36
+ it {@extra.should == {:format => :png, :name => 'text.png'}}
37
+ end
38
+
39
+ describe "specifying the format" do
40
+ before(:each) do
41
+ @image, @extra = @generator.text(@text, :format => :gif)
42
+ end
43
+ it {@image.should have_format('gif')}
44
+ it {@extra.should == {:format => :gif, :name => 'text.gif'}}
45
+ end
46
+
47
+ describe "padding" do
48
+ before(:each) do
49
+ no_padding_text, extra = @generator.text(@text, :font_size => 12)
50
+ @width = image_properties(no_padding_text)[:width].to_i
51
+ @height = image_properties(no_padding_text)[:height].to_i
52
+ end
53
+ it "1 number shortcut" do
54
+ image, extra = @generator.text(@text, :padding => '10')
55
+ image.should have_width(@width + 20)
56
+ image.should have_height(@height + 20)
57
+ end
58
+ it "2 numbers shortcut" do
59
+ image, extra = @generator.text(@text, :padding => '10 5')
60
+ image.should have_width(@width + 10)
61
+ image.should have_height(@height + 20)
62
+ end
63
+ it "3 numbers shortcut" do
64
+ image, extra = @generator.text(@text, :padding => '10 5 8')
65
+ image.should have_width(@width + 10)
66
+ image.should have_height(@height + 18)
67
+ end
68
+ it "4 numbers shortcut" do
69
+ image, extra = @generator.text(@text, :padding => '1 2 3 4')
70
+ image.should have_width(@width + 6)
71
+ image.should have_height(@height + 4)
72
+ end
73
+ it "should override the general padding declaration with the specific one (e.g. 'padding-left')" do
74
+ image, extra = @generator.text(@text, :padding => '10', 'padding-left' => 9)
75
+ image.should have_width(@width + 19)
76
+ image.should have_height(@height + 20)
77
+ end
78
+ it "should ignore 'px' suffixes" do
79
+ image, extra = @generator.text(@text, :padding => '1px 2px 3px 4px')
80
+ image.should have_width(@width + 6)
81
+ image.should have_height(@height + 4)
82
+ end
83
+ it "bad padding string" do
84
+ lambda{
85
+ @generator.text(@text, :padding => '1 2 3 4 5')
86
+ }.should raise_error(ArgumentError)
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+
94
+ describe Dragonfly::Minimagick::Generator do
95
+
96
+ before(:each) do
97
+ @generator = Dragonfly::Minimagick::Generator.new
98
+ end
99
+
100
+ describe "when using the filesystem" do
101
+ before(:each) do
102
+ end
103
+ it_should_behave_like 'image generator'
104
+ end
105
+
106
+ end
@@ -0,0 +1,234 @@
1
+ require 'spec_helper'
2
+
3
+ # NEEDS:
4
+ #
5
+ # @image
6
+ # @processor
7
+ #
8
+ shared_examples_for "processing methods" do
9
+
10
+ describe "resize" do
11
+
12
+ it "should work correctly with xNN" do
13
+ image = @processor.resize(@image, 'x30')
14
+ image.should have_width(24)
15
+ image.should have_height(30)
16
+ end
17
+
18
+ it "should work correctly with NNx" do
19
+ image = @processor.resize(@image, '30x')
20
+ image.should have_width(30)
21
+ image.should have_height(38)
22
+ end
23
+
24
+ it "should work correctly with NNxNN" do
25
+ image = @processor.resize(@image, '30x30')
26
+ image.should have_width(24)
27
+ image.should have_height(30)
28
+ end
29
+
30
+ it "should work correctly with NNxNN!" do
31
+ image = @processor.resize(@image, '30x30!')
32
+ image.should have_width(30)
33
+ image.should have_height(30)
34
+ end
35
+
36
+ it "should work correctly with NNxNN%" do
37
+ image = @processor.resize(@image, '25x50%')
38
+ image.should have_width(70)
39
+ image.should have_height(178)
40
+ end
41
+
42
+ describe "NNxNN>" do
43
+
44
+ it "should not resize if the image is smaller than specified" do
45
+ image = @processor.resize(@image, '1000x1000>')
46
+ image.should have_width(280)
47
+ image.should have_height(355)
48
+ end
49
+
50
+ it "should resize if the image is larger than specified" do
51
+ image = @processor.resize(@image, '30x30>')
52
+ image.should have_width(24)
53
+ image.should have_height(30)
54
+ end
55
+
56
+ end
57
+
58
+ describe "NNxNN<" do
59
+
60
+ it "should not resize if the image is larger than specified" do
61
+ image = @processor.resize(@image, '10x10<')
62
+ image.should have_width(280)
63
+ image.should have_height(355)
64
+ end
65
+
66
+ it "should resize if the image is smaller than specified" do
67
+ image = @processor.resize(@image, '400x400<')
68
+ image.should have_width(315)
69
+ image.should have_height(400)
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+
76
+ describe "crop" do # Difficult to test here other than dimensions
77
+
78
+ it "should not crop if no args given" do
79
+ image = @processor.crop(@image)
80
+ image.should have_width(280)
81
+ image.should have_height(355)
82
+ end
83
+
84
+ it "should crop using the offset given" do
85
+ image = @processor.crop(@image, :x => '7', :y => '12')
86
+ image.should have_width(273)
87
+ image.should have_height(343)
88
+ end
89
+
90
+ it "should crop using the dimensions given" do
91
+ image = @processor.crop(@image, :width => '10', :height => '20')
92
+ image.should have_width(10)
93
+ image.should have_height(20)
94
+ end
95
+
96
+ it "should crop in one dimension if given" do
97
+ image = @processor.crop(@image, :width => '10')
98
+ image.should have_width(10)
99
+ image.should have_height(355)
100
+ end
101
+
102
+ it "should take into account the gravity given" do
103
+ image1 = @processor.crop(@image, :width => '10', :height => '10', :gravity => 'nw')
104
+ image2 = @processor.crop(@image, :width => '10', :height => '10', :gravity => 'se')
105
+ image1.should_not == image2
106
+ end
107
+
108
+ it "should clip bits of the image outside of the requested crop area when not nw gravity" do
109
+ # Minimagick was previously throwing an error when the cropping area was outside the image size, when
110
+ # using a gravity other than nw
111
+ image = @processor.crop(@image, :width => '500', :height => '1000', :x => '100', :y => '200', :gravity => 'se')
112
+ image.should have_width(180)
113
+ image.should have_height(155)
114
+ end
115
+
116
+ end
117
+
118
+ describe "greyscale" do
119
+ it "should not raise an error" do
120
+ # Bit tricky to test
121
+ @processor.greyscale(@image)
122
+ end
123
+ end
124
+
125
+ describe "resize_and_crop" do
126
+
127
+ it "should do nothing if no args given" do
128
+ image = @processor.resize_and_crop(@image)
129
+ image.should have_width(280)
130
+ image.should have_height(355)
131
+ end
132
+
133
+ it "should crop to the correct dimensions" do
134
+ image = @processor.resize_and_crop(@image, :width => '100', :height => '100')
135
+ image.should have_width(100)
136
+ image.should have_height(100)
137
+ end
138
+
139
+ it "should allow cropping in one dimension" do
140
+ image = @processor.resize_and_crop(@image, :width => '100')
141
+ image.should have_width(100)
142
+ image.should have_height(355)
143
+ end
144
+
145
+ it "should take into account the gravity given" do
146
+ image1 = @processor.resize_and_crop(@image, :width => '10', :height => '10', :gravity => 'nw')
147
+ image2 = @processor.resize_and_crop(@image, :width => '10', :height => '10', :gravity => 'se')
148
+ image1.should_not == image2
149
+ end
150
+
151
+ end
152
+
153
+ describe "rotate" do
154
+
155
+ it "should rotate by 90 degrees" do
156
+ image = @processor.rotate(@image, 90)
157
+ image.should have_width(355)
158
+ image.should have_height(280)
159
+ end
160
+
161
+ it "should not rotate given a larger height and the '>' qualifier" do
162
+ image = @processor.rotate(@image, 90, :qualifier => '>')
163
+ image.should have_width(280)
164
+ image.should have_height(355)
165
+ end
166
+
167
+ it "should rotate given a larger height and the '<' qualifier" do
168
+ image = @processor.rotate(@image, 90, :qualifier => '<')
169
+ image.should have_width(355)
170
+ image.should have_height(280)
171
+ end
172
+
173
+ end
174
+
175
+ describe "thumb" do
176
+ it "should call resize if the correct string given" do
177
+ @processor.should_receive(:resize).with(@image, '30x40').and_return(image = mock)
178
+ @processor.thumb(@image, '30x40').should == image
179
+ end
180
+ it "should call resize_and_crop if the correct string given" do
181
+ @processor.should_receive(:resize_and_crop).with(@image, :width => '30', :height => '40', :gravity => 'se').and_return(image = mock)
182
+ @processor.thumb(@image, '30x40#se').should == image
183
+ end
184
+ it "should call crop if x and y given" do
185
+ @processor.should_receive(:crop).with(@image, :width => '30', :height => '40', :x => '+10', :y => '+20', :gravity => nil).and_return(image = mock)
186
+ @processor.thumb(@image, '30x40+10+20').should == image
187
+ end
188
+ it "should call crop if just gravity given" do
189
+ @processor.should_receive(:crop).with(@image, :width => '30', :height => '40', :x => nil, :y => nil, :gravity => 'sw').and_return(image = mock)
190
+ @processor.thumb(@image, '30x40sw').should == image
191
+ end
192
+ it "should call crop if x, y and gravity given" do
193
+ @processor.should_receive(:crop).with(@image, :width => '30', :height => '40', :x => '-10', :y => '-20', :gravity => 'se').and_return(image = mock)
194
+ @processor.thumb(@image, '30x40-10-20se').should == image
195
+ end
196
+ it "should raise an argument error if an unrecognized string is given" do
197
+ lambda{ @processor.thumb(@image, '30x40#ne!') }.should raise_error(ArgumentError)
198
+ end
199
+ end
200
+
201
+ describe "flip" do
202
+ it "should flip the image, leaving the same dimensions" do
203
+ image = @processor.flip(@image)
204
+ image.should have_width(280)
205
+ image.should have_height(355)
206
+ end
207
+ end
208
+
209
+ describe "flop" do
210
+ it "should flop the image, leaving the same dimensions" do
211
+ image = @processor.flop(@image)
212
+ image.should have_width(280)
213
+ image.should have_height(355)
214
+ end
215
+ end
216
+
217
+ end
218
+
219
+
220
+ describe Dragonfly::Minimagick::Processor do
221
+
222
+ before(:each) do
223
+ sample_file = SAMPLES_DIR + '/beach.png' # 280x355
224
+ @image = Dragonfly::TempObject.new(File.new(sample_file))
225
+ @processor = Dragonfly::Minimagick::Processor.new
226
+ end
227
+
228
+ describe "when using the filesystem" do
229
+ before(:each) do
230
+ end
231
+ it_should_behave_like "processing methods"
232
+ end
233
+
234
+ end
data/spec/spec.log ADDED
@@ -0,0 +1 @@
1
+ # Logfile created on 2011-10-28 23:20:02 +0200 by logger.rb/25413
@@ -0,0 +1,25 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup(:default, :test)
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'rspec'
8
+ require 'dragonfly-minimagick'
9
+ require 'support/image_matchers'
10
+ require 'dragonfly-minimagick/analyser'
11
+ require 'dragonfly-minimagick/config'
12
+ require 'dragonfly-minimagick/encoder'
13
+ require 'dragonfly-minimagick/generator'
14
+ require 'dragonfly-minimagick/processor'
15
+ require 'dragonfly-minimagick/utils'
16
+
17
+ SAMPLES_DIR = File.expand_path(File.dirname(__FILE__) + '/../samples') unless defined?(SAMPLES_DIR)
18
+
19
+ require 'logger'
20
+ LOG_FILE = File.dirname(__FILE__) + '/spec.log' unless defined?(LOG_FILE)
21
+ FileUtils.rm_rf(LOG_FILE)
22
+
23
+ def test_app
24
+ Dragonfly::App.send(:new)
25
+ end
@@ -0,0 +1,47 @@
1
+ def image_properties(image)
2
+ if image.is_a?(Tempfile)
3
+ tempfile = image
4
+ else
5
+ tempfile = Tempfile.new('image')
6
+ tempfile.write(image.is_a?(Dragonfly::TempObject) ? image.data : image)
7
+ tempfile.close
8
+ end
9
+ details = `identify #{tempfile.path}`
10
+ # example of details string:
11
+ # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
12
+ filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
13
+ width, height = geometry.split('x')
14
+ {
15
+ :filename => filename,
16
+ :format => format.downcase,
17
+ :width => width,
18
+ :height => height,
19
+ :depth => depth,
20
+ :image_class => image_class,
21
+ :size => size
22
+ }
23
+ end
24
+
25
+ RSpec::Matchers.define :have_width do |width|
26
+ match do |given|
27
+ width.should === image_properties(given)[:width].to_i
28
+ end
29
+ end
30
+
31
+ RSpec::Matchers.define :have_height do |height|
32
+ match do |given|
33
+ height.should === image_properties(given)[:height].to_i
34
+ end
35
+ end
36
+
37
+ RSpec::Matchers.define :have_format do |format|
38
+ match do |given|
39
+ image_properties(given)[:format].should == format
40
+ end
41
+ end
42
+
43
+ RSpec::Matchers.define :have_size do |size|
44
+ match do |given|
45
+ image_properties(given)[:size].should == size
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dragonfly-minimagick
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Paul Spieker
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-01-02 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dragonfly
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0.9"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: mini_magick
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: "3.3"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "2.0"
46
+ type: :development
47
+ version_requirements: *id003
48
+ description: Not yet completely implemented
49
+ email:
50
+ - p.spieker@duenos.de
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - README.markdown
61
+ - Rakefile
62
+ - dragonfly-minimagick.gemspec
63
+ - lib/dragonfly-minimagick.rb
64
+ - lib/dragonfly-minimagick/analyser.rb
65
+ - lib/dragonfly-minimagick/config.rb
66
+ - lib/dragonfly-minimagick/encoder.rb
67
+ - lib/dragonfly-minimagick/generator.rb
68
+ - lib/dragonfly-minimagick/processor.rb
69
+ - lib/dragonfly-minimagick/utils.rb
70
+ - lib/dragonfly-minimagick/version.rb
71
+ - samples/beach.png
72
+ - spec/dragonfly-minimagick/analyser_spec.rb
73
+ - spec/dragonfly-minimagick/config_spec.rb
74
+ - spec/dragonfly-minimagick/encoder_spec.rb
75
+ - spec/dragonfly-minimagick/generator_spectmp.rb
76
+ - spec/dragonfly-minimagick/processor_spec.rb
77
+ - spec/spec.log
78
+ - spec/spec_helper.rb
79
+ - spec/support/image_matchers.rb
80
+ homepage: https://github.com/spieker/dragonfly-minimagick
81
+ licenses: []
82
+
83
+ post_install_message:
84
+ rdoc_options: []
85
+
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project: dragonfly-minimagick
103
+ rubygems_version: 1.8.8
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Use MiniMagick for image processing within Dragonfly
107
+ test_files:
108
+ - spec/dragonfly-minimagick/analyser_spec.rb
109
+ - spec/dragonfly-minimagick/config_spec.rb
110
+ - spec/dragonfly-minimagick/encoder_spec.rb
111
+ - spec/dragonfly-minimagick/generator_spectmp.rb
112
+ - spec/dragonfly-minimagick/processor_spec.rb
113
+ - spec/spec.log
114
+ - spec/spec_helper.rb
115
+ - spec/support/image_matchers.rb