miro 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8da79a7879154e553ec78af76e25f2a9d8a6b232
4
- data.tar.gz: d180f86a6a43976d2d0ef84455aca46b109e36af
3
+ metadata.gz: 269d3bca169bf72e9496cf0b019b2f39d844f05b
4
+ data.tar.gz: 7ca804e24f8f4433fb01064c98477b3c56ac8804
5
5
  SHA512:
6
- metadata.gz: 85e2a88179149a9afd9e4f62ad5a997115d705c72dd8d649a98b1cf157ee1e12fc756cf006a9f688f6e3a39c3aab8a6c4c03b8679fa2ba5765bb43c4330f0ee5
7
- data.tar.gz: b870d98b936ebc868b49d5771ae7e6a402c640becc21bbd5c84c3abc81e5da488dc37298277c900fe2de9bef94b1c1fd52badf2fa0cfbfd8d8b81fa6000fffd6
6
+ metadata.gz: c2391941d1a5fe148ca76c0807fa78db23ac7b86ff00df2a95b5d420217c06aecc354242dc8b1ae49162cb9cdf3f185b5b50a84d3c46ee44d8c8ee976b077801
7
+ data.tar.gz: 4f9ac4fb9fccf3ad157411175860a62c1dc935ea5b6b8df1e754204d6b58fa730802d4500c4a7c90733b4dce90935eaa91fea27d74fead5817ac0b7d5a5a3c84
@@ -0,0 +1,9 @@
1
+ # Miro Changelog
2
+
3
+ ## 0.3.0
4
+
5
+ * Enhancements
6
+ * new `:histogram` option for improved performance [#19][]
7
+ * Updated README
8
+
9
+ [#19]: https://github.com/jonbuda/miro/pull/19
data/README.md CHANGED
@@ -34,7 +34,9 @@ Miro.options # => {:image_magick_path => "/usr/bin/convert", :resolution => "15
34
34
  Miro.options[:image_magick_path] = '/usr/local/bin/convert'
35
35
  Miro.options[:resolution] = '100x100'
36
36
  Miro.options[:color_count] = 4
37
+ Miro.options[:method] = 'histogram'
37
38
  ```
39
+ By default the method option is configured with 'pixel_group' to improve performance change to 'histogram', this will fetch directly from imagemagick the image histogram without any disk operation(read/write) but read the original file.
38
40
 
39
41
  Initializing an image
40
42
 
@@ -58,8 +60,18 @@ colors.to_rgb # => [[81, 51, 42], [44, 29, 24], [108, 73, 55], [101, 81, 74], [1
58
60
  # RGB with Alpha channels
59
61
  colors.to_rgba # => [[82, 37, 40, 255], [48, 17, 19, 255], [109, 70, 71, 255], [221, 158, 48, 255], [168, 103, 48, 255], [226, 178, 79, 255], [191, 146, 65, 255], [199, 165, 150, 255]]
60
62
  ```
63
+ **Aditional methods only aviable when histogram method is enabled**
61
64
 
62
- Retrieving percentages of colors
65
+ ```ruby
66
+ # HSL
67
+ colors.to_hsl # => [[0.03846153846153848, 0.3170731707317073, 0.24117647058823527], [0.041666666666666664, 0.29411764705882354, 0.13333333333333333], [0.056603773584905634, 0.32515337423312884, 0.3196078431372549], [0.043209876543209826, 0.15428571428571422, 0.3431372549019608], [0.04999999999999999, 0.30701754385964913, 0.4470588235294118], [0.2727272727272729, 0.18644067796610145, 0.884313725490196], [0.030158730158730152, 0.47511312217194573, 0.4333333333333333], [0.17283950617283947, 0.22314049586776857, 0.5254901960784314]]
68
+ # CMYL
69
+ colors.to_cmyk # => [[0.15772788927335635, 0.2753749480968858, 0.3106690657439446, 0.5246250519031143], [0.10680607458669744, 0.16562960399846216, 0.1852374471357171, 0.7206449058054594], [0.18404784313725486, 0.32130274509803924, 0.39189098039215686, 0.3924227450980392], [0.20410654363706265, 0.2825379161860822, 0.30998889657823897, 0.3998150249903884], [0.18299487889273353, 0.37515174163783166, 0.4575046828143022, 0.23269139561707036], [0.11147515570934258, 0.0840241753171857, 0.12716143021914644, 0.010093471741637827], [0.14225937716262976, 0.479514279123414, 0.5540240830449827, 0.21852493656286048], [0.23082082276047672, 0.22297768550557479, 0.43474239138792764, 0.1456497654748174]]
70
+ # YIQ
71
+ colors.to_yiq # => => [[0.23115294117647056, 0.08144705882352937, 0.013964705882352914], [0.129078431372549, 0.04135294117647058, 0.006372549019607841], [0.31926666666666664, 0.10446274509803921, 0.007145098039215689], [0.33796862745098033, 0.05555686274509804, 0.008090196078431366], [0.4402235294117646, 0.14096078431372547, 0.015125490196078437], [0.892756862745098, 0.0, 0.0], [0.3943058823529411, 0.2249215686274509, 0.0483254901960784], [0.6048862745098039, 0.06330196078431369, 0.0]]
72
+ ```
73
+
74
+ Retrieving percentages of colors *disabled on histogram method*
63
75
 
64
76
  ```ruby
65
77
  # percentage of each color in an image. matches sorting from to_hex,
@@ -1,6 +1,7 @@
1
1
  require "miro/version"
2
2
  require "oily_png"
3
3
  require "cocaine"
4
+ require "color"
4
5
  require "tempfile"
5
6
  require "open-uri"
6
7
 
@@ -14,8 +15,16 @@ module Miro
14
15
  :image_magick_path => convert.length > 0 ? convert : '/usr/bin/convert',
15
16
  :resolution => "150x150",
16
17
  :color_count => 8,
17
- :quantize => 'RGB'
18
+ :quantize => 'RGB',
19
+ :method => 'pixel_group'
18
20
  }
19
21
  end
22
+ def pixel_group?
23
+ options[:method] == 'pixel_group'
24
+ end
25
+
26
+ def histogram?
27
+ options[:method] == 'histogram'
28
+ end
20
29
  end
21
30
  end
@@ -8,18 +8,34 @@ module Miro
8
8
  end
9
9
 
10
10
  def to_hex
11
- sorted_pixels.collect {|c| ChunkyPNG::Color.to_hex c, false }
11
+ return histogram.map{ |item| item[1].html } if Miro.histogram?
12
+ sorted_pixels.collect { |pixel| ChunkyPNG::Color.to_hex(pixel, false) }
12
13
  end
13
14
 
14
15
  def to_rgb
15
- sorted_pixels.collect {|c| ChunkyPNG::Color.to_truecolor_bytes c }
16
+ return histogram.map { |item| item[1].to_rgb.to_a } if Miro.histogram?
17
+ sorted_pixels.collect { |pixel| ChunkyPNG::Color.to_truecolor_bytes(pixel) }
16
18
  end
17
19
 
18
20
  def to_rgba
19
- sorted_pixels.collect {|c| ChunkyPNG::Color.to_truecolor_alpha_bytes c }
21
+ return histogram.map { |item| item[1].css_rgba } if Miro.histogram?
22
+ sorted_pixels.collect { |pixel| ChunkyPNG::Color.to_truecolor_alpha_bytes(pixel) }
23
+ end
24
+
25
+ def to_hsl
26
+ histogram.map { |item| item[1].to_hsl.to_a } if Miro.histogram?
27
+ end
28
+
29
+ def to_cmyk
30
+ histogram.map { |item| item[1].to_cmyk.to_a } if Miro.histogram?
31
+ end
32
+
33
+ def to_yiq
34
+ histogram.map { |item| item[1].to_yiq.to_a } if Miro.histogram?
20
35
  end
21
36
 
22
37
  def by_percentage
38
+ return nil if Miro.histogram?
23
39
  sorted_pixels
24
40
  pixel_count = @pixels.size
25
41
  sorted_pixels.collect { |pixel| @grouped_pixels[pixel].size / pixel_count.to_f }
@@ -29,23 +45,40 @@ module Miro
29
45
  @sorted_pixels ||= extract_colors_from_image
30
46
  end
31
47
 
48
+ def histogram
49
+ @histogram || downsample_and_histogram.sort_by { |item| item[0] }.reverse
50
+ end
32
51
  private
52
+
53
+ def downsample_and_histogram
54
+ @source_image = open_source_image
55
+ hstring = Cocaine::CommandLine.new(Miro.options[:image_magick_path], image_magick_params).
56
+ run(:in => File.expand_path(@source_image.path),
57
+ :resolution => Miro.options[:resolution],
58
+ :colors => Miro.options[:color_count].to_s,
59
+ :quantize => Miro.options[:quantize])
60
+ cleanup_temporary_files!
61
+ parse_result(hstring)
62
+ end
63
+
64
+ def parse_result(hstring)
65
+ hstring.scan(/(\d*):.*(#[0-9A-Fa-f]*)/).collect do |match|
66
+ [match[0].to_i, Object.const_get("Color::#{Miro.options[:quantize].upcase}").from_html(match[1])]
67
+ end
68
+ end
69
+
33
70
  def extract_colors_from_image
34
71
  downsample_colors_and_convert_to_png!
35
72
  colors = sort_by_dominant_color
36
73
  cleanup_temporary_files!
37
- return colors
38
- end
39
-
40
- def remote_source_image?
41
- @src_image_path =~ /^https?:\/\//
74
+ colors
42
75
  end
43
76
 
44
77
  def downsample_colors_and_convert_to_png!
45
78
  @source_image = open_source_image
46
79
  @downsampled_image = open_downsampled_image
47
80
 
48
- Cocaine::CommandLine.new(Miro.options[:image_magick_path], "':in[0]' -resize :resolution -colors :colors -colorspace :quantize -quantize :quantize :out").
81
+ Cocaine::CommandLine.new(Miro.options[:image_magick_path], image_magick_params).
49
82
  run(:in => File.expand_path(@source_image.path),
50
83
  :resolution => Miro.options[:resolution],
51
84
  :colors => Miro.options[:color_count].to_s,
@@ -54,22 +87,20 @@ module Miro
54
87
  end
55
88
 
56
89
  def open_source_image
57
- if remote_source_image?
58
- original_extension = @image_type || URI.parse(@src_image_path).path.split('.').last
90
+ return File.open(@src_image_path) unless remote_source_image?
59
91
 
60
- tempfile = Tempfile.open(["source", ".#{original_extension}"])
61
- remote_file_data = open(@src_image_path).read
92
+ original_extension = @image_type || URI.parse(@src_image_path).path.split('.').last
62
93
 
63
- tempfile.write(should_force_encoding? ? remote_file_data.force_encoding("UTF-8") : remote_file_data)
64
- tempfile.close
65
- return tempfile
66
- else
67
- return File.open(@src_image_path)
68
- end
94
+ tempfile = Tempfile.open(["source", ".#{original_extension}"])
95
+ remote_file_data = open(@src_image_path).read
96
+
97
+ tempfile.write(should_force_encoding? ? remote_file_data.force_encoding("UTF-8") : remote_file_data)
98
+ tempfile.close
99
+ tempfile
69
100
  end
70
101
 
71
102
  def should_force_encoding?
72
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9')
103
+ Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('1.9')
73
104
  end
74
105
 
75
106
  def open_downsampled_image
@@ -78,6 +109,14 @@ module Miro
78
109
  tempfile
79
110
  end
80
111
 
112
+ def image_magick_params
113
+ if Miro.histogram?
114
+ "':in[0]' -resize :resolution -colors :colors -colorspace :quantize -quantize :quantize -alpha remove -format %c histogram:info:"
115
+ else
116
+ "':in[0]' -resize :resolution -colors :colors -colorspace :quantize -quantize :quantize :out"
117
+ end
118
+ end
119
+
81
120
  def group_pixels_by_color
82
121
  @pixels ||= ChunkyPNG::Image.from_file(File.expand_path(@downsampled_image.path)).pixels
83
122
  @grouped_pixels ||= @pixels.group_by { |pixel| pixel }
@@ -88,8 +127,12 @@ module Miro
88
127
  end
89
128
 
90
129
  def cleanup_temporary_files!
91
- @source_image.close(true) if remote_source_image?
92
- @downsampled_image.close(true)
130
+ @source_image.close! if remote_source_image?
131
+ @downsampled_image.close! if @downsampled_image
132
+ end
133
+
134
+ def remote_source_image?
135
+ @src_image_path =~ /^https?:\/\//
93
136
  end
94
137
  end
95
138
  end
@@ -1,3 +1,3 @@
1
1
  module Miro
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -12,6 +12,7 @@ Gem::Specification.new do |gem|
12
12
 
13
13
  gem.add_dependency "cocaine"
14
14
  gem.add_dependency "oily_png"
15
+ gem.add_dependency "color"
15
16
 
16
17
  gem.add_development_dependency "rspec"
17
18
  gem.add_development_dependency "fakeweb"
@@ -22,4 +23,5 @@ Gem::Specification.new do |gem|
22
23
  gem.name = "miro"
23
24
  gem.require_paths = ["lib"]
24
25
  gem.version = Miro::VERSION
26
+ gem.license = "MIT"
25
27
  end
Binary file
@@ -1,10 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Miro::DominantColors do
4
+ context "colors_group method" do
4
5
  let(:subject) { Miro::DominantColors.new('/path/to/file') }
5
6
  let(:mock_source_image) { double('file', :path => '/path/to/source_image').as_null_object }
6
7
  let(:mock_downsampled_image) { double('file', :path => '/path/to/downsampled_image').as_null_object }
7
- let(:pixel_data) {
8
+ let(:pixel_data) {
8
9
  [ 2678156287,
9
10
  1362307839, 1362307839, 1362307839, 1362307839, 1362307839, 1362307839, 1362307839, 1362307839,
10
11
  2506379263, 2506379263, 2506379263, 2506379263,
@@ -20,6 +21,7 @@ describe Miro::DominantColors do
20
21
  let(:expected_rgb_values) { [[81, 51, 42], [44, 29, 24], [108, 73, 55], [101, 81, 74], [149, 100, 79], [224, 231, 220], [163, 77, 58], [159, 161, 107]] }
21
22
 
22
23
  before do
24
+ Miro.stub(:histogram?).and_return(false)
23
25
  Cocaine::CommandLine.stub(:new).and_return(double('command', :run => true))
24
26
  ChunkyPNG::Image.stub(:from_file).and_return(chunky_png_results)
25
27
  end
@@ -88,8 +90,8 @@ describe Miro::DominantColors do
88
90
  end
89
91
 
90
92
  it "deletes only temporary downsampled file when finished" do
91
- mock_downsampled_image.should_receive(:close).with(true)
92
- mock_source_image.should_not_receive(:close)
93
+ mock_downsampled_image.should_receive(:close!)
94
+ mock_source_image.should_not_receive(:close!)
93
95
  subject.sorted_pixels
94
96
  end
95
97
  end
@@ -108,7 +110,7 @@ describe Miro::DominantColors do
108
110
  end
109
111
 
110
112
  it "deletes the temporary source file when finished" do
111
- mock_source_image.should_receive(:close).with(true)
113
+ mock_source_image.should_receive(:close!)
112
114
  subject.sorted_pixels
113
115
  end
114
116
  end
@@ -155,5 +157,88 @@ describe Miro::DominantColors do
155
157
  end
156
158
  end
157
159
  end
158
-
160
+ end
161
+
162
+ context "histogram method" do
163
+ let(:subject) { Miro::DominantColors.new(File.expand_path('spec/data/test.png')) }
164
+ let(:hex_colors){["#00ff02","#0000ff","#ff009a","#fa0000","#878787","#585858","#001a6b","#8f0074"]}
165
+ let(:object_colors){ hex_colors.map{|c| Color::RGB.from_html(c) } }
166
+
167
+ before do
168
+ Miro.stub(:histogram?).and_return(true)
169
+ end
170
+
171
+ describe "#downsample_and_histogram" do
172
+ it "should return an array" do
173
+ subject.send(:downsample_and_histogram).should be_an_instance_of(Array)
174
+ end
175
+
176
+ it "should contain colors" do
177
+ subject.send(:downsample_and_histogram).each do |item|
178
+ item[1].should be_an_instance_of(Color::RGB)
179
+ end
180
+ end
181
+
182
+ it "should have the max length of the color config" do
183
+ subject.send(:downsample_and_histogram).count.should <= Miro.options[:color_count]
184
+ end
185
+ end
186
+
187
+ describe "#histogram" do
188
+ it "should return a hash" do
189
+ subject.histogram.should be_an_instance_of(Array)
190
+ end
191
+
192
+ it "should start with the most used color" do
193
+ subject.histogram.first[1].should == Color::RGB.from_html('#00FF02')
194
+ end
195
+
196
+ it "should end with the less used color" do
197
+ subject.histogram.last[1].should == Color::RGB.from_html('#8F0074')
198
+ end
199
+ end
200
+
201
+ describe "#to_hex" do
202
+ it "should be #00FF02 at the first element" do
203
+ subject.to_hex.first.should == hex_colors.first
204
+ end
205
+ it "should be #8F0074 at the first element" do
206
+ subject.to_hex.last.should == hex_colors.last
207
+ end
208
+ it "should have the right values" do
209
+ subject.to_hex.should == hex_colors
210
+ end
211
+ end
212
+
213
+ describe "#to_rgb" do
214
+ it "should have the right values" do
215
+ subject.to_rgb.should == object_colors.map(&:to_rgb).map(&:to_a)
216
+ end
217
+ end
218
+
219
+ describe "#to_rgba" do
220
+ it "should have the right values" do
221
+ subject.to_rgba.should == object_colors.map(&:css_rgba)
222
+ end
223
+ end
224
+
225
+ describe "#to_hsl" do
226
+ it "should have the right values" do
227
+ subject.to_hsl.should == object_colors.map(&:to_hsl).map(&:to_a)
228
+ end
229
+ end
230
+
231
+ describe "#to_cmyk" do
232
+ it "should have the right values" do
233
+ subject.to_cmyk.should == object_colors.map(&:to_cmyk).map(&:to_a)
234
+ end
235
+ end
236
+
237
+ describe "#to_yiq" do
238
+ it "should have the right values" do
239
+ subject.to_yiq.should == object_colors.map(&:to_yiq).map(&:to_a)
240
+ end
241
+ end
242
+
243
+ end
159
244
  end
metadata CHANGED
@@ -1,69 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Buda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-18 00:00:00.000000000 Z
11
+ date: 2014-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocaine
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: oily_png
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: color
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - '>='
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - '>='
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: fakeweb
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - '>='
73
+ - - ">="
60
74
  - !ruby/object:Gem::Version
61
75
  version: '0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - '>='
80
+ - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  description: Extract the dominant colors from an image.
@@ -73,8 +87,9 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
- - .gitignore
77
- - .rspec
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - CHANGELOG.md
78
93
  - Gemfile
79
94
  - LICENSE
80
95
  - README.md
@@ -83,11 +98,13 @@ files:
83
98
  - lib/miro/dominant_colors.rb
84
99
  - lib/miro/version.rb
85
100
  - miro.gemspec
101
+ - spec/data/test.png
86
102
  - spec/miro/dominant_colors_spec.rb
87
103
  - spec/miro_spec.rb
88
104
  - spec/spec_helper.rb
89
105
  homepage: https://github.com/jonbuda/miro
90
- licenses: []
106
+ licenses:
107
+ - MIT
91
108
  metadata: {}
92
109
  post_install_message:
93
110
  rdoc_options: []
@@ -95,22 +112,23 @@ require_paths:
95
112
  - lib
96
113
  required_ruby_version: !ruby/object:Gem::Requirement
97
114
  requirements:
98
- - - '>='
115
+ - - ">="
99
116
  - !ruby/object:Gem::Version
100
117
  version: '0'
101
118
  required_rubygems_version: !ruby/object:Gem::Requirement
102
119
  requirements:
103
- - - '>='
120
+ - - ">="
104
121
  - !ruby/object:Gem::Version
105
122
  version: '0'
106
123
  requirements:
107
124
  - ImageMagick
108
125
  rubyforge_project:
109
- rubygems_version: 2.0.3
126
+ rubygems_version: 2.2.2
110
127
  signing_key:
111
128
  specification_version: 4
112
129
  summary: Extract the dominant colors from an image.
113
130
  test_files:
131
+ - spec/data/test.png
114
132
  - spec/miro/dominant_colors_spec.rb
115
133
  - spec/miro_spec.rb
116
134
  - spec/spec_helper.rb