airbrush 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/bin/airbrush CHANGED
File without changes
@@ -51,10 +51,30 @@ raise "Source image does not exist: #{OPTIONS[:image]}" unless File.exists?(OPTI
51
51
  require 'airbrush'
52
52
 
53
53
  client = Airbrush::Client.new(OPTIONS[:memcache])
54
- puts "Sending #{OPTIONS[:image]} for preview processing"
54
+ puts "Sending #{OPTIONS[:image]} for processing"
55
+
56
+ # previews..
55
57
  results = client.process('generate-previews', :previews, :image => File.read(OPTIONS[:image]), :filename => OPTIONS[:image], :sizes => {:small => [300], :large => [600]})
58
+
56
59
  results.each do |k,v|
57
- next if k == :original
58
- File.open("#{OPTIONS[:output]}-#{k}.jpg", 'w') { |f| f << v[:image] }
59
- puts "Saved preview #{OPTIONS[:output]}-#{k}.jpg (#{v[:width]}x#{v[:height]})" if OPTIONS[:verbose]
60
- end
60
+ next if k == :original
61
+ puts v[:format].inspect
62
+ File.open("#{OPTIONS[:output]}-#{k}.jpg", 'w') { |f| f << v[:image] }
63
+ puts "Saved preview #{OPTIONS[:output]}-#{k}.jpg (#{v[:width]}x#{v[:height]})" if OPTIONS[:verbose]
64
+ end
65
+
66
+ # Exif data..
67
+ results = client.process('exif',:exif_data, :image => File.read(OPTIONS[:image]))
68
+ puts results.inspect
69
+
70
+ # resized_crop_mask..
71
+ results = client.process('crop-and-resize',
72
+ :resized_crop_mask,
73
+ :image => File.read(OPTIONS[:image]),
74
+ :filename => OPTIONS[:image],
75
+ :crop => {:x => 0, :y => 0, :width => 800, :height => 800 },
76
+ :size => { :width => 2890, :height => 1940 })
77
+
78
+ File.open("#{OPTIONS[:output]}.jpg", 'w'){|f| f << results[:image] }
79
+ puts "Saved resized image #{OPTIONS[:output]}.jpg" if OPTIONS[:verbose]
80
+
data/config/hoe.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'airbrush/version'
2
2
 
3
- AUTHOR = 'FIXME full name' # can also be an array of Authors
4
- EMAIL = "FIXME email"
5
- DESCRIPTION = "description of gem"
3
+ AUTHOR = ['Marcus Crafter', 'Nick Marfleet'] # can also be an array of Authors
4
+ EMAIL = "nick@whatevernext.org"
5
+ DESCRIPTION = "Distributed image processing server."
6
6
  GEM_NAME = 'airbrush' # what ppl will type to install your gem
7
7
  RUBYFORGE_PROJECT = 'airbrush' # The unix name for your project
8
8
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
@@ -10,7 +10,7 @@ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
10
 
11
11
  @config_file = "~/.rubyforge/user-config.yml"
12
12
  @config = nil
13
- RUBYFORGE_USERNAME = "unknown"
13
+ RUBYFORGE_USERNAME = "nickm"
14
14
  def rubyforge_username
15
15
  unless @config
16
16
  begin
@@ -59,7 +59,7 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
59
59
 
60
60
  # == Optional
61
61
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
62
- p.extra_deps = [ [ 'starling', '>= 0.9.3' ], [ 'activesupport', '>= 2.0.2' ], [ 'ruby2ruby', '>= 1.1.8' ], [ 'daemons', '>= 1.0.9' ] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
+ p.extra_deps = [ [ 'starling', '= 0.9.8' ], [ 'activesupport', '= 2.3.5' ], [ 'ruby2ruby', '= 1.2.1' ], [ 'daemons', '= 1.0.10' ] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
63
 
64
64
  #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
65
 
@@ -4,6 +4,9 @@ module Airbrush
4
4
  module Processors
5
5
  module Image
6
6
  class Rmagick < ImageProcessor
7
+
8
+ VALID_OUTPUT_FORMATS = ['JPEG', 'PNG', 'JPG', 'GIF']
9
+
7
10
  filter_params :image # ignore any argument called 'image' in any logging
8
11
 
9
12
  def resize(image, width, height = nil)
@@ -33,6 +36,18 @@ module Airbrush
33
36
  images[:original] = dimensions(image)
34
37
  images
35
38
  end
39
+
40
+ def exif_data(image)
41
+ data = Magick::Image.from_blob(image).first.get_exif_by_entry
42
+ data.inject({}) { |m, exif_entry| m[exif_entry[0]] = exif_entry[1]; m }
43
+ end
44
+
45
+ def resized_crop_mask(image, crop, size)
46
+ process image do
47
+ resize!(size[:width], size[:height])
48
+ crop!(crop[:x], crop[:y], crop[:width], crop[:height])
49
+ end
50
+ end
36
51
 
37
52
  protected
38
53
 
@@ -40,11 +55,16 @@ module Airbrush
40
55
  img = Magick::Image.from_blob(image).first
41
56
  img.instance_eval &block
42
57
  img.ensure_rgb!
43
- img.format = 'JPEG' # ensure that resized output is a JPEG
58
+ img.format = get_format(image) # ensure that resized output is a JPEG
44
59
  {
45
- :image => img.to_blob, :width => img.columns, :height => img.rows
60
+ :image => img.to_blob, :width => img.columns, :height => img.rows, :format => img.format
46
61
  }
47
62
  end
63
+
64
+ def get_format(image_data)
65
+ current_format = Magick::Image.from_blob(image_data).first.format
66
+ VALID_OUTPUT_FORMATS.include?(current_format) ? current_format : 'JPEG'
67
+ end
48
68
 
49
69
  def dimensions(image_data)
50
70
  image = Magick::Image.from_blob(image_data).first
@@ -53,32 +73,19 @@ module Airbrush
53
73
 
54
74
  def calculate_dimensions(image_data, size)
55
75
  image = Magick::Image.from_blob(image_data).first
56
- return image.columns, image.rows if clipping_required?(image, size)
76
+ return image.columns, image.rows unless clipping_required?(image, size)
57
77
 
58
78
  ratio = image.columns.to_f / image.rows.to_f
59
79
 
60
- portrait image do
61
- return [ size, size.to_f / ratio ]
62
- end
63
-
64
- landscape image do
65
- return [ ratio * size, size ]
66
- end
80
+ return [ size, size.to_f / ratio ] if ratio > 1 # landscape
81
+
82
+ return [ ratio * size, size ] if ratio < 1 # Portrait
67
83
 
68
- # Must be a square image.
69
- return [ size, size ]
84
+ return [ size, size ] # Square
70
85
  end
71
86
 
72
87
  def clipping_required?(image, size)
73
- size > image.columns or size > image.rows
74
- end
75
-
76
- def portrait(image, &block)
77
- block.call if image.columns > image.rows
78
- end
79
-
80
- def landscape(image, &block)
81
- block.call if image.columns < image.rows
88
+ (image.columns > size) || (image.rows > size)
82
89
  end
83
90
 
84
91
  end
@@ -2,7 +2,7 @@ module Airbrush #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -12,8 +12,10 @@ describe Airbrush::Processors::Image::Rmagick do
12
12
  @rm_image.stub!(:change_geometry).and_return
13
13
  @rm_image.stub!(:crop!).and_return
14
14
  @rm_image.stub!(:crop_resized!).and_return
15
+ @rm_image.stub!(:resize!).and_return
15
16
  @rm_image.stub!(:ensure_rgb!).and_return
16
17
  @rm_image.stub!(:to_blob).and_return(@blob)
18
+ @rm_image.stub!(:format).and_return('JPEG')
17
19
  @rm_image.stub!(:format=).and_return('JPEG')
18
20
  @rm_image.stub!(:columns).and_return(@columns)
19
21
  @rm_image.stub!(:rows).and_return(@rows)
@@ -47,7 +49,7 @@ describe Airbrush::Processors::Image::Rmagick do
47
49
 
48
50
  it 'should return the raw image data back to the caller' do
49
51
  @rm_image.should_receive(:to_blob).and_return('blob')
50
- @processor.resize(@image, 300, 200).should == { :image => "blob", :height => 1000, :width => 1500 }
52
+ @processor.resize(@image, 300, 200).should == { :format => "JPEG", :image => "blob", :height => 1000, :width => 1500 }
51
53
  end
52
54
 
53
55
  end
@@ -70,7 +72,7 @@ describe Airbrush::Processors::Image::Rmagick do
70
72
 
71
73
  it 'should return the raw image data back to the caller' do
72
74
  @rm_image.should_receive(:to_blob).and_return('blob')
73
- @processor.crop(@image, 10, 10, 100, 100).should == { :image => "blob", :height => 1000, :width => 1500 }
75
+ @processor.crop(@image, 10, 10, 100, 100).should == { :format => "JPEG", :image => "blob", :height => 1000, :width => 1500 }
74
76
  end
75
77
 
76
78
  end
@@ -93,7 +95,7 @@ describe Airbrush::Processors::Image::Rmagick do
93
95
 
94
96
  it 'should return the raw image data back to the caller' do
95
97
  @rm_image.should_receive(:to_blob).and_return('blob')
96
- @processor.crop_resize(@image, 75, 75).should == { :image => "blob", :height => 1000, :width => 1500 }
98
+ @processor.crop_resize(@image, 75, 75).should == { :format => "JPEG", :image => "blob", :height => 1000, :width => 1500 }
97
99
  end
98
100
 
99
101
  end
@@ -107,10 +109,56 @@ describe Airbrush::Processors::Image::Rmagick do
107
109
 
108
110
  it 'should return the raw image data back to the caller' do
109
111
  @rm_image.should_receive(:to_blob).twice.and_return('blob')
110
- @processor.previews(@image, { :small => [200,100], :large => [500,250] }).should == { :small=> { :image => "blob", :height => 1000, :width => 1500 }, :large=> { :image => "blob", :height => 1000, :width => 1500 }, :original => [1500, 1000] }
112
+ @processor.previews(@image, { :small => [200,100], :large => [500,250] }).should == { :small=> { :format => "JPEG", :image => "blob", :height => 1000, :width => 1500 }, :large=> { :format => "JPEG", :image => "blob", :height => 1000, :width => 1500 }, :original => [1500, 1000] }
111
113
  end
112
114
 
113
115
  end
116
+
117
+ describe 'crop_and_resize' do
118
+
119
+ it 'should return an image with the specified sizes' do
120
+ @processor.resized_crop_mask(@image, {:x => 0, :y => 0, :width => 800, :height => 800 }, { :width => 2890, :height => 1940 }).should == {
121
+ :format => "JPEG", :image => "blob", :width => 1500, :height => 1000}
122
+
123
+ end
124
+
125
+ it 'should return an image cropped to the crop marks' do
126
+ @rm_image.should_receive(:crop!).with(0,20,800,900).once
127
+ @processor.resized_crop_mask(@image, {:x => 0, :y => 20, :width => 800, :height => 900 }, { :width => 2890, :height => 1940 }).should == {
128
+ :format => "JPEG", :image => "blob", :width => 1500, :height => 1000}
129
+ end
130
+
131
+ it 'should return the raw image data back to the caller' do
132
+ @rm_image.should_receive(:resize!).with(2890,1940).once
133
+ @processor.resized_crop_mask(@image, {:x => 0, :y => 0, :width => 800, :height => 800 }, { :width => 2890, :height => 1940 }).should == {
134
+ :format => "JPEG", :image => "blob", :width => 1500, :height => 1000}
135
+ end
136
+ end
137
+
138
+ describe "exif_data" do
139
+ it "should return a hash of exif data for the image" do
140
+ @rm_image.should_receive(:get_exif_by_entry).once.and_return([["Make", "Canon"], ["ShutterSpeedValue", "189/32"]])
141
+ @processor.exif_data(@image).should == { "Make" => "Canon", "ShutterSpeedValue" => "189/32" }
142
+ end
143
+ end
144
+
145
+ describe "get_format" do
146
+
147
+ Airbrush::Processors::Image::Rmagick::VALID_OUTPUT_FORMATS.each do |valid_format|
148
+ it "should not change the image format if it is a #{valid_format}" do
149
+ @rm_image.should_receive(:format).and_return(valid_format)
150
+ @processor.send(:get_format, @rm_image).should == valid_format
151
+ end
152
+ end
153
+
154
+ it "should change the format to JPEG if a non valid return format is found" do
155
+ ['TIF', 'TIFF', 'PDF'].each do |bad_format|
156
+ @rm_image.should_receive(:format).and_return(bad_format)
157
+ @processor.send(:get_format, @rm_image).should == 'JPEG'
158
+ end
159
+ end
160
+ end
161
+
114
162
 
115
163
  describe 'dimension calculation' do
116
164
 
metadata CHANGED
@@ -1,69 +1,100 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrush
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 3
9
+ version: 0.0.3
5
10
  platform: ruby
6
11
  authors:
7
- - FIXME full name
12
+ - Marcus Crafter
13
+ - Nick Marfleet
8
14
  autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2008-10-29 00:00:00 +11:00
18
+ date: 2010-05-18 00:00:00 +10:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: starling
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
- - - ">="
27
+ - - "="
22
28
  - !ruby/object:Gem::Version
23
- version: 0.9.3
24
- version:
29
+ segments:
30
+ - 0
31
+ - 9
32
+ - 8
33
+ version: 0.9.8
34
+ type: :runtime
35
+ version_requirements: *id001
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: activesupport
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
30
41
  requirements:
31
- - - ">="
42
+ - - "="
32
43
  - !ruby/object:Gem::Version
33
- version: 2.0.2
34
- version:
44
+ segments:
45
+ - 2
46
+ - 3
47
+ - 5
48
+ version: 2.3.5
49
+ type: :runtime
50
+ version_requirements: *id002
35
51
  - !ruby/object:Gem::Dependency
36
52
  name: ruby2ruby
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
40
56
  requirements:
41
- - - ">="
57
+ - - "="
42
58
  - !ruby/object:Gem::Version
43
- version: 1.1.8
44
- version:
59
+ segments:
60
+ - 1
61
+ - 2
62
+ - 1
63
+ version: 1.2.1
64
+ type: :runtime
65
+ version_requirements: *id003
45
66
  - !ruby/object:Gem::Dependency
46
67
  name: daemons
47
- type: :runtime
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
50
71
  requirements:
51
- - - ">="
72
+ - - "="
52
73
  - !ruby/object:Gem::Version
53
- version: 1.0.9
54
- version:
74
+ segments:
75
+ - 1
76
+ - 0
77
+ - 10
78
+ version: 1.0.10
79
+ type: :runtime
80
+ version_requirements: *id004
55
81
  - !ruby/object:Gem::Dependency
56
82
  name: hoe
57
- type: :development
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Requirement
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
60
86
  requirements:
61
87
  - - ">="
62
88
  - !ruby/object:Gem::Version
63
- version: 1.8.2
64
- version:
65
- description: description of gem
66
- email: FIXME email
89
+ segments:
90
+ - 1
91
+ - 8
92
+ - 0
93
+ version: 1.8.0
94
+ type: :development
95
+ version_requirements: *id005
96
+ description: Distributed image processing server.
97
+ email: nick@whatevernext.org
67
98
  executables:
68
99
  - airbrush
69
100
  - airbrush-example-client
@@ -132,6 +163,8 @@ files:
132
163
  - website/template.rhtml
133
164
  has_rdoc: true
134
165
  homepage: http://airbrush.rubyforge.org
166
+ licenses: []
167
+
135
168
  post_install_message:
136
169
  rdoc_options:
137
170
  - --main
@@ -139,23 +172,27 @@ rdoc_options:
139
172
  require_paths:
140
173
  - lib
141
174
  required_ruby_version: !ruby/object:Gem::Requirement
175
+ none: false
142
176
  requirements:
143
177
  - - ">="
144
178
  - !ruby/object:Gem::Version
179
+ segments:
180
+ - 0
145
181
  version: "0"
146
- version:
147
182
  required_rubygems_version: !ruby/object:Gem::Requirement
183
+ none: false
148
184
  requirements:
149
185
  - - ">="
150
186
  - !ruby/object:Gem::Version
187
+ segments:
188
+ - 0
151
189
  version: "0"
152
- version:
153
190
  requirements: []
154
191
 
155
192
  rubyforge_project: airbrush
156
- rubygems_version: 1.2.0
193
+ rubygems_version: 1.3.7
157
194
  signing_key:
158
- specification_version: 2
159
- summary: description of gem
195
+ specification_version: 3
196
+ summary: Distributed image processing server.
160
197
  test_files: []
161
198