camalian 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/.tool-versions +1 -1
- data/Gemfile +2 -0
- data/README.md +16 -13
- data/Rakefile +1 -0
- data/lib/camalian.rb +2 -0
- data/lib/camalian/palette.rb +4 -0
- data/lib/camalian/quantization/median_cut.rb +74 -0
- data/lib/camalian/version.rb +1 -1
- data/test/{test_color.rb → color_test.rb} +0 -0
- data/test/palette_test.rb +64 -0
- data/test/quantization/histogram_test.rb +61 -0
- data/test/quantization/k_means_test.rb +61 -0
- data/test/quantization/median_cut_test.rb +63 -0
- data/test/test_helper.rb +3 -0
- metadata +14 -9
- data/test/test_palette.rb +0 -30
- data/test/test_quantization.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6d9583383ecf60a0cd259bcce471abe319f2b4390b52c53d63a2504f3dd020f
|
4
|
+
data.tar.gz: 6e5cb3a2c174539b91bae01fafad0e9ef658756bebc7809837cc0edb019cfacd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c79fb3ea3e499fee16fa36f8e10c640a54a1ddc3d0121a99d5053b7c28a60cfbe903f2600c59ec61997a42942f40b16298714904dfbbdb170dbbfa0adf23540b
|
7
|
+
data.tar.gz: 4d7a82621d0429c005f4d3743724bc2de51c7f57110416d50a1397de8d6a473e73ec25416f53533b12c500670709412cee6fd73b529fc68dfc044e5112f54578
|
data/.rubocop.yml
CHANGED
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 2.7.
|
1
|
+
ruby 2.7.3
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ Ruby gem to extract color palettes from images and play with their saturation
|
|
10
10
|
|
11
11
|
Add this line to your application's Gemfile:
|
12
12
|
|
13
|
-
gem 'camalian', '~> 0.
|
13
|
+
gem 'camalian', '~> 0.2.0'
|
14
14
|
|
15
15
|
And then execute:
|
16
16
|
|
@@ -28,18 +28,26 @@ colors = image.prominent_colors(15)
|
|
28
28
|
colors = colors.sort_similar_colors
|
29
29
|
colors.light_colors(0, 40)
|
30
30
|
```
|
31
|
-
|
32
|
-
### Quantization Algorithms
|
33
|
-
Currently following algorithms are implemented.
|
34
31
|
|
35
|
-
|
32
|
+
You can find a working example with detail explanation and reference code here on [this link](https://basicdrift.com/color-extraction-library-build-color-search-engine-fdf369678d5a). Here we will build a functional color based image search engine in Ruby on Rails.
|
33
|
+
|
34
|
+
NOTE: Since its a compute intensive operation so for production use its suggested to use under a background job and not within a request/response cycle.
|
35
|
+
|
36
|
+
## Quantization Algorithms
|
37
|
+
|
38
|
+
Currently following algorithms are implemented.
|
39
|
+
|
40
|
+
### Histogram
|
36
41
|
|
37
|
-
Its a most common algorithm for color quantization and used different bucket technique to group the colors together. You can read more about this technique here
|
42
|
+
Its a most common algorithm for color quantization and used different bucket technique to group the colors together. You can read more about this [technique here](https://en.wikipedia.org/wiki/Color_histogram). It can be accessed by `Camalian::QUANTIZATION_HISTOGRAM` constant. This is used as default method as well.
|
38
43
|
|
44
|
+
### K Means
|
39
45
|
|
40
|
-
|
46
|
+
This algorithm uses color distancing in RGB space to group the similar colors. You can learn more about this [technique here](https://en.wikipedia.org/wiki/K-means_clustering). It can be accessed by `Camalian::QUANTIZATION_K_MEANS` constant.
|
41
47
|
|
42
|
-
|
48
|
+
### Median Cut
|
49
|
+
|
50
|
+
This algorithm uses color highest color range to determine the median and split colors to groups. The output consists of average color of such color groups. Since these algorithm don't use actual colors and instead average, so you will may not exact matching pixel in the image. This algorithm is nice to be used with image compression, where similarity and compression is important than having same pixel colors. You can learn more about this [technique here](https://tpgit.github.io/UnOfficialLeptDocs/leptonica/color-quantization.html) . It can be accessed by `Camalian::QUANTIZATION_MEDIAN_CUT` constant.
|
43
51
|
|
44
52
|
|
45
53
|
You can set default quantization method globally as:
|
@@ -55,11 +63,6 @@ image = Camalian::load('file_path')
|
|
55
63
|
colors = image.prominent_colors(15, quantization: Camalian::QUANTIZATION_K_MEANS)
|
56
64
|
```
|
57
65
|
|
58
|
-
## Usage
|
59
|
-
You can find a working example with detail explanation and reference code here on [this link](https://basicdrift.com/color-extraction-library-build-color-search-engine-fdf369678d5a). Here we will build a functional color based image search engine in Ruby on Rails.
|
60
|
-
|
61
|
-
NOTE: Since its a compute intensive operation so for production use its suggested to use under a background job and not within a request/response cycle.
|
62
|
-
|
63
66
|
## Contributing
|
64
67
|
|
65
68
|
1. Fork it
|
data/Rakefile
CHANGED
data/lib/camalian.rb
CHANGED
@@ -10,10 +10,12 @@ require 'camalian/palette'
|
|
10
10
|
require 'camalian/image'
|
11
11
|
require 'camalian/quantization/histogram'
|
12
12
|
require 'camalian/quantization/k_means'
|
13
|
+
require 'camalian/quantization/median_cut'
|
13
14
|
|
14
15
|
module Camalian # :nodoc:
|
15
16
|
QUANTIZATION_HISTOGRAM = Camalian::Quantization::Histogram
|
16
17
|
QUANTIZATION_K_MEANS = Camalian::Quantization::KMeans
|
18
|
+
QUANTIZATION_MEDIAN_CUT = Camalian::Quantization::MedianCut
|
17
19
|
|
18
20
|
class << self
|
19
21
|
def options
|
data/lib/camalian/palette.rb
CHANGED
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Camalian
|
4
|
+
module Quantization
|
5
|
+
class MedianCut # :nodoc:
|
6
|
+
SplitInfo = Struct.new(:range, :group_index, :color, keyword_init: true)
|
7
|
+
def process(colors, count)
|
8
|
+
# Its faster to extract unique colors once
|
9
|
+
colors = colors.uniq
|
10
|
+
groups = [colors]
|
11
|
+
limit = [count, colors.size].min
|
12
|
+
|
13
|
+
loop do
|
14
|
+
split_info = determine_group_split(groups)
|
15
|
+
group1, group2 = split_group(groups[split_info.group_index], split_info)
|
16
|
+
groups.reject!.each_with_index { |_g, index| index == split_info.group_index }
|
17
|
+
groups << group1 unless group1.empty?
|
18
|
+
groups << group2 unless group2.empty?
|
19
|
+
|
20
|
+
break if groups.size >= limit
|
21
|
+
end
|
22
|
+
|
23
|
+
palletes = groups.map { |g| Palette.new(g.uniq) }
|
24
|
+
average_colors = palletes.map(&:average_color)
|
25
|
+
|
26
|
+
Palette.new(average_colors[0...count])
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def determine_group_split(groups)
|
32
|
+
stats = []
|
33
|
+
|
34
|
+
groups.each_with_index do |group, index|
|
35
|
+
reds = group.map(&:r)
|
36
|
+
greens = group.map(&:g)
|
37
|
+
blues = group.map(&:b)
|
38
|
+
|
39
|
+
ranges = []
|
40
|
+
ranges << SplitInfo.new(group_index: index, range: reds.max - reds.min, color: :r) unless reds.empty?
|
41
|
+
ranges << SplitInfo.new(group_index: index, range: greens.max - greens.min, color: :g) unless greens.empty?
|
42
|
+
ranges << SplitInfo.new(group_index: index, range: blues.max - blues.min, color: :b) unless blues.empty?
|
43
|
+
|
44
|
+
stats << ranges.max_by(&:range)
|
45
|
+
end
|
46
|
+
|
47
|
+
stats.max_by(&:range)
|
48
|
+
end
|
49
|
+
|
50
|
+
def split_group(group, split_info)
|
51
|
+
split_color = split_info.color
|
52
|
+
colors = group.sort_by { |pixel| pixel.send split_color }
|
53
|
+
|
54
|
+
return [[colors[0]], [colors[1]]] if colors.size == 2
|
55
|
+
|
56
|
+
median_index = colors.size / 2
|
57
|
+
median_value = colors[median_index].send split_color
|
58
|
+
|
59
|
+
group1 = []
|
60
|
+
group2 = []
|
61
|
+
|
62
|
+
colors.each do |color|
|
63
|
+
if color.send(split_color) <= median_value
|
64
|
+
group1 << color
|
65
|
+
else
|
66
|
+
group2 << color
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
[group1, group2]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/camalian/version.rb
CHANGED
File without changes
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/spec'
|
6
|
+
require 'camalian'
|
7
|
+
|
8
|
+
describe Camalian::Palette do
|
9
|
+
before do
|
10
|
+
mixed_colors = %w[#2560a2 #4dd915 #1530db #49cc23 #45c031 #3da84d #1d48be #399c5b #359069 #318478 #2d7886 #296c94
|
11
|
+
#2154b0 #193ccc #41b43f].freeze
|
12
|
+
|
13
|
+
@palette = Camalian::Palette.from_hex(mixed_colors)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'initialize palette with correct size' do
|
17
|
+
_(@palette.size).must_equal 15
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#sort_by_lightness' do
|
21
|
+
it 'sort colors by lightness ' do
|
22
|
+
_(@palette.sort_by_lightness.to_hex).must_equal ['#41b43f', '#45c031', '#1530db', '#49cc23', '#4dd915',
|
23
|
+
'#193ccc', '#3da84d', '#1d48be', '#399c5b', '#2154b0',
|
24
|
+
'#2560a2', '#359069', '#296c94', '#318478', '#2d7886']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#sort_by_hue' do
|
29
|
+
it 'sort colors by hue' do
|
30
|
+
_(@palette.sort_by_hue.to_hex).must_equal ['#1530db', '#193ccc', '#1d48be', '#2154b0', '#2560a2', '#296c94',
|
31
|
+
'#2d7886', '#318478', '#359069', '#399c5b', '#3da84d', '#41b43f',
|
32
|
+
'#45c031', '#49cc23', '#4dd915']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#sort_by_saturation' do
|
37
|
+
it 'sort colors by saturation' do
|
38
|
+
_(@palette.sort_by_saturation.to_hex).must_equal ['#1530db', '#4dd915', '#193ccc', '#1d48be', '#49cc23',
|
39
|
+
'#2154b0', '#2560a2', '#45c031', '#296c94', '#2d7886',
|
40
|
+
'#41b43f', '#3da84d', '#399c5b', '#359069', '#318478']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#sort_similar_colors' do
|
45
|
+
it 'sort colors by hsv' do
|
46
|
+
_(@palette.sort_similar_colors.to_hex).must_equal ['#4dd915', '#49cc23', '#45c031', '#41b43f', '#3da84d',
|
47
|
+
'#399c5b', '#359069', '#318478', '#2d7886', '#296c94',
|
48
|
+
'#2560a2', '#2154b0', '#1d48be', '#193ccc', '#1530db']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#average_color' do
|
53
|
+
it 'return one average color' do
|
54
|
+
_(@palette.average_color.to_hex).must_equal '#318477'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#light_colors' do
|
59
|
+
it 'extract light colors in provided limit' do
|
60
|
+
_(@palette.light_colors(40, 90).to_hex).must_equal ['#4dd915', '#1530db', '#49cc23', '#45c031', '#3da84d',
|
61
|
+
'#1d48be', '#399c5b', '#2154b0', '#193ccc', '#41b43f']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/spec'
|
6
|
+
require 'camalian'
|
7
|
+
|
8
|
+
describe Camalian::Quantization::Histogram do
|
9
|
+
describe 'palette with 15 colors extracted' do
|
10
|
+
before do
|
11
|
+
@image = Camalian.load(File.join(File.dirname(__FILE__), '../assets/palette.png'))
|
12
|
+
@palette = @image.prominent_colors(15, optimal: false, quantization: Camalian::QUANTIZATION_HISTOGRAM)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must have 15 colors' do
|
16
|
+
_(@palette.size).must_equal 15
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sort similar colors in order' do
|
20
|
+
_(@palette.sort_similar_colors.map(&:to_hex)).must_equal PALLET_IMAGE_COLORS
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should extract distinct colors' do
|
25
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
26
|
+
result = Camalian::Quantization::Histogram.new.process(colors, 3)
|
27
|
+
|
28
|
+
_(result.size).must_equal 3
|
29
|
+
_(result).must_equal colors
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should extract distinct colors lesser than pixels' do
|
33
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
34
|
+
result = Camalian::Quantization::Histogram.new.process(colors, 2)
|
35
|
+
|
36
|
+
_(result.size).must_equal 2
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should extract distinct colors not more than pixels' do
|
40
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
41
|
+
result = Camalian::Quantization::Histogram.new.process(colors, 4)
|
42
|
+
|
43
|
+
_(result.size).must_equal 3
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should extract same color' do
|
47
|
+
colors = %w[#FF0000 #FF0000 #FF0000].map { |c| Camalian::Color.from_hex(c) }
|
48
|
+
result = Camalian::Quantization::Histogram.new.process(colors, 3)
|
49
|
+
|
50
|
+
_(result.size).must_equal 1
|
51
|
+
_(result.to_hex).must_equal ['#ff0000']
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should extract multiple colors' do
|
55
|
+
colors = %w[#FF0000 #FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
56
|
+
result = Camalian::Quantization::Histogram.new.process(colors, 3)
|
57
|
+
|
58
|
+
_(result.size).must_equal 3
|
59
|
+
_(result.to_hex).must_equal %w[#ff0000 #00ff00 #0000ff]
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/spec'
|
6
|
+
require 'camalian'
|
7
|
+
|
8
|
+
describe Camalian::Quantization::KMeans do
|
9
|
+
describe 'palette with 15 colors extracted' do
|
10
|
+
before do
|
11
|
+
@image = Camalian.load(File.join(File.dirname(__FILE__), '../assets/palette.png'))
|
12
|
+
@palette = @image.prominent_colors(15, optimal: false, quantization: Camalian::QUANTIZATION_K_MEANS)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must have 15 colors' do
|
16
|
+
_(@palette.size).must_equal 15
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sort similar colors in order' do
|
20
|
+
_(@palette.sort_similar_colors.map(&:to_hex)).must_equal PALLET_IMAGE_COLORS
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should extract distinct colors' do
|
25
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
26
|
+
result = Camalian::Quantization::KMeans.new.process(colors, 3)
|
27
|
+
|
28
|
+
_(result.size).must_equal 3
|
29
|
+
_(result).must_equal colors
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should extract distinct colors lesser than pixels' do
|
33
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
34
|
+
result = Camalian::Quantization::KMeans.new.process(colors, 2)
|
35
|
+
|
36
|
+
_(result.size).must_equal 2
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should extract distinct colors not more than pixels' do
|
40
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
41
|
+
result = Camalian::Quantization::KMeans.new.process(colors, 4)
|
42
|
+
|
43
|
+
_(result.size).must_equal 3
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should extract same color' do
|
47
|
+
colors = %w[#FF0000 #FF0000 #FF0000].map { |c| Camalian::Color.from_hex(c) }
|
48
|
+
result = Camalian::Quantization::KMeans.new.process(colors, 3)
|
49
|
+
|
50
|
+
_(result.size).must_equal 1
|
51
|
+
_(result.to_hex).must_equal ['#ff0000']
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should extract multiple colors' do
|
55
|
+
colors = %w[#FF0000 #FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
56
|
+
result = Camalian::Quantization::KMeans.new.process(colors, 3)
|
57
|
+
|
58
|
+
_(result.size).must_equal 3
|
59
|
+
_(result.to_hex).must_equal %w[#ff0000 #00ff00 #0000ff]
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/spec'
|
6
|
+
require 'camalian'
|
7
|
+
|
8
|
+
describe Camalian::Quantization::MedianCut do
|
9
|
+
describe 'palette with 15 colors extracted' do
|
10
|
+
before do
|
11
|
+
@image = Camalian.load(File.join(File.dirname(__FILE__), '../assets/palette.png'))
|
12
|
+
@palette = @image.prominent_colors(15, optimal: false, quantization: Camalian::QUANTIZATION_MEDIAN_CUT)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must have 15 colors' do
|
16
|
+
_(@palette.size).must_equal 15
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sort similar colors in order' do
|
20
|
+
_(@palette.sort_similar_colors.map(&:to_hex)).must_equal ['#4dd915', '#49cc23', '#45c031', '#41b43f', '#3da84d',
|
21
|
+
'#399c5b', '#359069', '#318478', '#2d7886', '#296c94',
|
22
|
+
'#2560a2', '#2154b0', '#1d48be', '#193ccc', '#1530db']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should extract distinct colors' do
|
27
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
28
|
+
result = Camalian::Quantization::MedianCut.new.process(colors, 3)
|
29
|
+
|
30
|
+
_(result.size).must_equal 3
|
31
|
+
_(result.to_hex.sort).must_equal colors.map(&:to_hex).sort
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should extract distinct colors lesser than pixels' do
|
35
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
36
|
+
result = Camalian::Quantization::MedianCut.new.process(colors, 2)
|
37
|
+
|
38
|
+
_(result.size).must_equal 2
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should extract distinct colors not more than pixels' do
|
42
|
+
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
43
|
+
result = Camalian::Quantization::MedianCut.new.process(colors, 4)
|
44
|
+
|
45
|
+
_(result.size).must_equal 3
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should extract same color' do
|
49
|
+
colors = %w[#FF0000 #FF0000 #FF0000].map { |c| Camalian::Color.from_hex(c) }
|
50
|
+
result = Camalian::Quantization::MedianCut.new.process(colors, 3)
|
51
|
+
|
52
|
+
_(result.size).must_equal 1
|
53
|
+
_(result.to_hex).must_equal ['#ff0000']
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'only: should extract multiple colors' do
|
57
|
+
colors = %w[#FF0000 #FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
58
|
+
result = Camalian::Quantization::MedianCut.new.process(colors, 3)
|
59
|
+
|
60
|
+
_(result.size).must_equal 3
|
61
|
+
_(result.to_hex).must_equal ['#ff0000', '#0000ff', '#00ff00']
|
62
|
+
end
|
63
|
+
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: camalian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nazar Hussain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chunky_png
|
@@ -96,12 +96,15 @@ files:
|
|
96
96
|
- lib/camalian/palette.rb
|
97
97
|
- lib/camalian/quantization/histogram.rb
|
98
98
|
- lib/camalian/quantization/k_means.rb
|
99
|
+
- lib/camalian/quantization/median_cut.rb
|
99
100
|
- lib/camalian/version.rb
|
100
101
|
- test/assets/palette.png
|
101
|
-
- test/
|
102
|
+
- test/color_test.rb
|
103
|
+
- test/palette_test.rb
|
104
|
+
- test/quantization/histogram_test.rb
|
105
|
+
- test/quantization/k_means_test.rb
|
106
|
+
- test/quantization/median_cut_test.rb
|
102
107
|
- test/test_helper.rb
|
103
|
-
- test/test_palette.rb
|
104
|
-
- test/test_quantization.rb
|
105
108
|
homepage: https://github.com/nazarhussain/camalian
|
106
109
|
licenses:
|
107
110
|
- MIT
|
@@ -121,14 +124,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
124
|
- !ruby/object:Gem::Version
|
122
125
|
version: '0'
|
123
126
|
requirements: []
|
124
|
-
rubygems_version: 3.0.3
|
127
|
+
rubygems_version: 3.0.3.1
|
125
128
|
signing_key:
|
126
129
|
specification_version: 4
|
127
130
|
summary: Library used to deal with colors and images. You can extract colors from
|
128
131
|
images.
|
129
132
|
test_files:
|
130
133
|
- test/assets/palette.png
|
131
|
-
- test/
|
134
|
+
- test/color_test.rb
|
135
|
+
- test/palette_test.rb
|
136
|
+
- test/quantization/histogram_test.rb
|
137
|
+
- test/quantization/k_means_test.rb
|
138
|
+
- test/quantization/median_cut_test.rb
|
132
139
|
- test/test_helper.rb
|
133
|
-
- test/test_palette.rb
|
134
|
-
- test/test_quantization.rb
|
data/test/test_palette.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
require 'minitest/autorun'
|
5
|
-
require 'minitest/spec'
|
6
|
-
require 'camalian'
|
7
|
-
|
8
|
-
PALLET_IMAGE_COLORS = %w[#4dd915 #49cc23 #45c031 #41b43f #3da84d #399c5b #359069 #318478 #2d7886 #296c94 #2560a2
|
9
|
-
#2154b0 #1d48be #193ccc #1530db].freeze
|
10
|
-
|
11
|
-
describe Camalian::Palette do
|
12
|
-
before do
|
13
|
-
@image = Camalian.load(File.join(File.dirname(__FILE__), 'assets/palette.png'))
|
14
|
-
@palette = @image.prominent_colors(15, optimal: false)
|
15
|
-
end
|
16
|
-
|
17
|
-
describe 'palette with 15 colors extracted' do
|
18
|
-
it 'must have 15 colors' do
|
19
|
-
_(@palette.size).must_equal 15
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'sort similar colors in order' do
|
23
|
-
_(@palette.sort_similar_colors.map(&:to_hex)).must_equal PALLET_IMAGE_COLORS
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'color with intensity 0-40 works well' do
|
27
|
-
_(@palette.light_colors(0, 40).map(&:to_hex)).must_equal %w[#2560a2 #296c94 #2d7886 #318478 #359069]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/test/test_quantization.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
describe Camalian::Quantization do
|
6
|
-
[Camalian::Quantization::KMeans, Camalian::Quantization::Histogram].each do |klass|
|
7
|
-
describe klass.name.to_s do
|
8
|
-
it 'should extract distinct colors' do
|
9
|
-
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
10
|
-
result = klass.new.process(colors, 3)
|
11
|
-
|
12
|
-
_(result.size).must_equal 3
|
13
|
-
_(result).must_equal colors
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should extract distinct colors lesser than pixels' do
|
17
|
-
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
18
|
-
result = klass.new.process(colors, 2)
|
19
|
-
|
20
|
-
_(result.size).must_equal 2
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should extract distinct colors not more than pixels' do
|
24
|
-
colors = %w[#FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
25
|
-
result = klass.new.process(colors, 4)
|
26
|
-
|
27
|
-
_(result.size).must_equal 3
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should extract same color' do
|
31
|
-
colors = %w[#FF0000 #FF0000 #FF0000].map { |c| Camalian::Color.from_hex(c) }
|
32
|
-
result = klass.new.process(colors, 3)
|
33
|
-
|
34
|
-
_(result.size).must_equal 1
|
35
|
-
_(result.to_hex).must_equal ['#ff0000']
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'should extract multiple colors' do
|
39
|
-
colors = %w[#FF0000 #FF0000 #00FF00 #0000FF].map { |c| Camalian::Color.from_hex(c) }
|
40
|
-
result = klass.new.process(colors, 3)
|
41
|
-
|
42
|
-
_(result.size).must_equal 3
|
43
|
-
_(result.to_hex).must_equal %w[#ff0000 #00ff00 #0000ff]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|