camalian 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/gpr-push.yml +30 -0
- data/.github/workflows/ruby.yml +32 -0
- data/.github/workflows/rubygems-push.yml +29 -0
- data/.gitignore +2 -1
- data/.overcommit.yml +33 -0
- data/.rubocop.yml +33 -0
- data/.tool-versions +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +5 -0
- data/README.md +5 -1
- data/Rakefile +5 -3
- data/camalian.gemspec +16 -15
- data/lib/camalian.rb +16 -14
- data/lib/camalian/color.rb +28 -26
- data/lib/camalian/image.rb +24 -22
- data/lib/camalian/palette.rb +17 -6
- data/lib/camalian/quantization/histogram.rb +26 -0
- data/lib/camalian/version.rb +3 -1
- data/test/assets/palette.png +0 -0
- data/test/test_color.rb +14 -11
- data/test/test_helper.rb +4 -0
- data/test/test_palette.rb +14 -12
- metadata +44 -19
- data/lib/chunky_png_patch/color.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bdc6f4d61421eac9f0017baf9e6f290c37e47b633ee4533e18d00883fd162b54
|
4
|
+
data.tar.gz: 5cb477be826b4c0706a9385ce31699a34aab8b27c66c5c57140d1818650ca60e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 912bcad8d3db3362d2997877fe42b9d2df01c806b9bbfe965463d5df8e530dab55f716820f414e44910e5818ff86ac1ac256f8c9d1a2d760ca75d38c69492dcc
|
7
|
+
data.tar.gz: fe6989ee96c21f12482857c26aed89f7db69e6d1a41616c9aaed3a11732ccf76c8376c6711b49dc375cbb8d29adfef1ff09ba3ea3c5780c4f70cdce0431041eb
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: Github Packages Push
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
push:
|
6
|
+
tags:
|
7
|
+
- '*'
|
8
|
+
jobs:
|
9
|
+
build:
|
10
|
+
name: Build + Publish
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- name: Set up Ruby 2.6
|
16
|
+
uses: actions/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: 2.6.x
|
19
|
+
|
20
|
+
- name: Publish to GPR
|
21
|
+
run: |
|
22
|
+
mkdir -p $HOME/.gem
|
23
|
+
touch $HOME/.gem/credentials
|
24
|
+
chmod 0600 $HOME/.gem/credentials
|
25
|
+
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
26
|
+
gem build *.gemspec
|
27
|
+
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
28
|
+
env:
|
29
|
+
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
30
|
+
OWNER: ${{ github.repository_owner }}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: build
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
runs-on: ubuntu-16.04
|
19
|
+
strategy:
|
20
|
+
matrix:
|
21
|
+
ruby: [ '2.4', '2.5', '2.6', '2.7' ]
|
22
|
+
name: Ruby ${{ matrix.ruby }}
|
23
|
+
steps:
|
24
|
+
- uses: actions/checkout@v2
|
25
|
+
- uses: actions/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: ${{ matrix.ruby }}
|
28
|
+
- name: Install dependencies
|
29
|
+
run: bundle install
|
30
|
+
- name: Run tests
|
31
|
+
run: bundle exec rake
|
32
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
name: Ruby Gems Push
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
push:
|
6
|
+
tags:
|
7
|
+
- '*'
|
8
|
+
jobs:
|
9
|
+
build:
|
10
|
+
name: Build + Publish
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- name: Set up Ruby 2.6
|
16
|
+
uses: actions/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: 2.6.x
|
19
|
+
|
20
|
+
- name: Publish to RubyGems
|
21
|
+
run: |
|
22
|
+
mkdir -p $HOME/.gem
|
23
|
+
touch $HOME/.gem/credentials
|
24
|
+
chmod 0600 $HOME/.gem/credentials
|
25
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
26
|
+
gem build *.gemspec
|
27
|
+
gem push *.gem
|
28
|
+
env:
|
29
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
data/.gitignore
CHANGED
data/.overcommit.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Use this file to configure the Overcommit hooks you wish to use. This will
|
2
|
+
# extend the default configuration defined in:
|
3
|
+
# https://github.com/sds/overcommit/blob/master/config/default.yml
|
4
|
+
#
|
5
|
+
# At the topmost level of this YAML file is a key representing type of hook
|
6
|
+
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
|
7
|
+
# customize each hook, such as whether to only run it on certain files (via
|
8
|
+
# `include`), whether to only display output if it fails (via `quiet`), etc.
|
9
|
+
#
|
10
|
+
# For a complete list of hooks, see:
|
11
|
+
# https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
|
12
|
+
#
|
13
|
+
# For a complete list of options that you can use to customize hooks, see:
|
14
|
+
# https://github.com/sds/overcommit#configuration
|
15
|
+
#
|
16
|
+
# Uncomment the following lines to make the configuration take effect.
|
17
|
+
|
18
|
+
PreCommit:
|
19
|
+
RuboCop:
|
20
|
+
enabled: true
|
21
|
+
on_warn: fail # Treat all warnings as failures
|
22
|
+
|
23
|
+
# TrailingWhitespace:
|
24
|
+
# enabled: true
|
25
|
+
# exclude:
|
26
|
+
# - '**/db/structure.sql' # Ignore trailing whitespace in generated files
|
27
|
+
#
|
28
|
+
#PostCheckout:
|
29
|
+
# ALL: # Special hook name that customizes all hooks of this type
|
30
|
+
# quiet: true # Change all post-checkout hooks to only display output on failure
|
31
|
+
#
|
32
|
+
# IndexTags:
|
33
|
+
# enabled: true # Generate a tags file with `ctags` each time HEAD changes
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# The behavior of RuboCop can be controlled via the .rubocop.yml
|
2
|
+
# configuration file. It makes it possible to enable/disable
|
3
|
+
# certain cops (checks) and to alter their behavior if they accept
|
4
|
+
# any parameters. The file can be placed either in your home
|
5
|
+
# directory or in some project directory.
|
6
|
+
#
|
7
|
+
# RuboCop will start looking for the configuration file in the directory
|
8
|
+
# where the inspected file is and continue its way up to the root directory.
|
9
|
+
#
|
10
|
+
# See https://docs.rubocop.org/rubocop/configuration
|
11
|
+
|
12
|
+
AllCops:
|
13
|
+
NewCops: enable
|
14
|
+
|
15
|
+
Naming/MethodParameterName:
|
16
|
+
AllowedNames:
|
17
|
+
- r
|
18
|
+
- g
|
19
|
+
- b
|
20
|
+
|
21
|
+
Metrics/MethodLength:
|
22
|
+
Max: 50
|
23
|
+
|
24
|
+
Metrics/PerceivedComplexity:
|
25
|
+
Max: 25
|
26
|
+
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Max: 15
|
29
|
+
|
30
|
+
Metrics/AbcSize:
|
31
|
+
Max: 20
|
32
|
+
IgnoredMethods:
|
33
|
+
- build_components
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.7.1
|
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.7
|
4
|
+
- 2.6
|
5
|
+
- 2.5
|
6
|
+
- 2.4
|
7
|
+
|
8
|
+
before_script:
|
9
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
10
|
+
- chmod +x ./cc-test-reporter
|
11
|
+
- ./cc-test-reporter before-build
|
12
|
+
|
13
|
+
script:
|
14
|
+
- bundle exec rake test
|
15
|
+
|
16
|
+
after_script:
|
17
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# Camalian
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/camalian)
|
4
|
+

|
5
|
+
[](https://codeclimate.com/github/nazarhussain/camalian/maintainability)
|
6
|
+
|
3
7
|
Ruby gem to extract color palettes from images and play with their saturation
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
7
11
|
Add this line to your application's Gemfile:
|
8
12
|
|
9
|
-
gem 'camalian', '~> 0.0
|
13
|
+
gem 'camalian', '~> 0.1.0'
|
10
14
|
|
11
15
|
And then execute:
|
12
16
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
2
4
|
|
3
5
|
require 'rake/testtask'
|
4
6
|
|
@@ -6,5 +8,5 @@ Rake::TestTask.new do |t|
|
|
6
8
|
t.libs << 'test'
|
7
9
|
end
|
8
10
|
|
9
|
-
desc
|
10
|
-
task :
|
11
|
+
desc 'Run tests'
|
12
|
+
task default: :test
|
data/camalian.gemspec
CHANGED
@@ -1,27 +1,28 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'camalian/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'camalian'
|
8
9
|
spec.version = Camalian::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Nazar Hussain']
|
11
|
+
spec.email = ['nazarhussain@gmail.com']
|
12
|
+
spec.description = 'Library used to deal with colors and images'
|
13
|
+
spec.summary = 'Library used to deal with colors and images. You can extract colors from images.'
|
14
|
+
spec.homepage = 'https://github.com/nazarhussain/camalian'
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
20
21
|
|
21
|
-
spec.
|
22
|
+
spec.add_dependency 'chunky_png', '~> 1.3', '>= 1.3.14'
|
22
23
|
|
23
|
-
spec.
|
24
|
-
spec.
|
25
|
-
spec.add_dependency "oily_png", "~> 1.2.0"
|
24
|
+
spec.add_development_dependency 'minitest', '~> 5.14', '>= 5.14.2'
|
25
|
+
spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1'
|
26
26
|
|
27
|
+
spec.required_ruby_version = '>= 2.4'
|
27
28
|
end
|
data/lib/camalian.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
|
2
|
-
require "tempfile"
|
3
|
-
require "open-uri"
|
4
|
-
require "cocaine"
|
5
|
-
require "chunky_png_patch/color"
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
3
|
+
require 'chunky_png'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
require 'camalian/version'
|
8
|
+
require 'camalian/color'
|
9
|
+
require 'camalian/palette'
|
10
|
+
require 'camalian/image'
|
11
|
+
require 'camalian/quantization/histogram'
|
12
|
+
|
13
|
+
module Camalian # :nodoc:
|
14
|
+
QUANTIZATION_HISTOGRAM = 'histogram'
|
11
15
|
|
12
|
-
module Camalian
|
13
16
|
class << self
|
14
17
|
def options
|
15
|
-
convert = `which convert`.strip
|
16
18
|
@options ||= {
|
17
|
-
|
18
|
-
|
19
|
+
color_count: 8,
|
20
|
+
quantization: Camalian::QUANTIZATION_HISTOGRAM
|
19
21
|
}
|
20
22
|
end
|
21
23
|
|
22
|
-
def load(image_path)
|
24
|
+
def load(image_path)
|
23
25
|
Image.new(image_path)
|
24
26
|
end
|
25
27
|
end
|
data/lib/camalian/color.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Camalian
|
4
|
+
# Camalian color object
|
2
5
|
class Color
|
3
|
-
|
4
6
|
attr_reader :r, :g, :b, :h, :s, :l, :hsv
|
5
7
|
|
6
|
-
def initialize(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def initialize(r, g, b)
|
9
|
+
build_components(r, g, b)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_hex(hex_value)
|
13
|
+
r, g, b = extract_rgb(hex_value)
|
14
|
+
Color.new(r, g, b)
|
13
15
|
end
|
14
16
|
|
15
17
|
def to_s
|
@@ -21,7 +23,7 @@ module Camalian
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def distance(color)
|
24
|
-
[(
|
26
|
+
[(h - color.h) % 360, (color.h - h) % 360].min
|
25
27
|
end
|
26
28
|
|
27
29
|
def extract_rgb(color_hash)
|
@@ -35,7 +37,7 @@ module Camalian
|
|
35
37
|
|
36
38
|
private
|
37
39
|
|
38
|
-
def build_components(r,g,b)
|
40
|
+
def build_components(r, g, b)
|
39
41
|
@r = r
|
40
42
|
@g = g
|
41
43
|
@b = b
|
@@ -50,21 +52,21 @@ module Camalian
|
|
50
52
|
|
51
53
|
@l = (cmax + cmin) / 2.0
|
52
54
|
|
53
|
-
if delta
|
55
|
+
if delta.zero?
|
54
56
|
@h = 0
|
55
57
|
elsif cmax == ri
|
56
58
|
@h = 60 * (((gi - bi) / delta) % 6)
|
57
59
|
elsif cmax == gi
|
58
|
-
@h = 60 * (((bi - ri)/ delta) + 2)
|
60
|
+
@h = 60 * (((bi - ri) / delta) + 2)
|
59
61
|
elsif cmax == bi
|
60
|
-
@h = 60 * (((ri - gi)/ delta) + 4)
|
62
|
+
@h = 60 * (((ri - gi) / delta) + 4)
|
61
63
|
end
|
62
64
|
|
63
|
-
if
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
@s = if delta.zero?
|
66
|
+
0
|
67
|
+
else
|
68
|
+
delta / (1 - (2 * @l - 1).abs)
|
69
|
+
end
|
68
70
|
|
69
71
|
@h = @h.round(2)
|
70
72
|
@s = (@s * 100).round(2)
|
@@ -72,22 +74,22 @@ module Camalian
|
|
72
74
|
|
73
75
|
# HSV Calculation
|
74
76
|
# Hue calculation
|
75
|
-
if delta
|
77
|
+
if delta.zero?
|
76
78
|
@hsv = [0]
|
77
79
|
elsif cmax == ri
|
78
80
|
@hsv = [60 * (((gi - bi) / delta) % 6)]
|
79
81
|
elsif cmax == gi
|
80
|
-
@hsv = [60 * (((bi - ri)/ delta) + 2)]
|
82
|
+
@hsv = [60 * (((bi - ri) / delta) + 2)]
|
81
83
|
elsif cmax == bi
|
82
|
-
@hsv = [60 * (((ri - gi)/ delta) + 4)]
|
84
|
+
@hsv = [60 * (((ri - gi) / delta) + 4)]
|
83
85
|
end
|
84
86
|
|
85
87
|
# Saturation calculation
|
86
|
-
if
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
@hsv << if cmax.zero?
|
89
|
+
0
|
90
|
+
else
|
91
|
+
delta / cmax
|
92
|
+
end
|
91
93
|
|
92
94
|
# Value calculation
|
93
95
|
@hsv << cmax
|
data/lib/camalian/image.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Camalian
|
4
|
+
# Load image into Camalian
|
4
5
|
class Image
|
5
6
|
attr_accessor :src_file_path
|
6
7
|
|
@@ -8,29 +9,30 @@ module Camalian
|
|
8
9
|
@src_file_path = file_path
|
9
10
|
end
|
10
11
|
|
11
|
-
def prominent_colors(count=Camalian.options[:color_count]
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
def prominent_colors(count = Camalian.options[:color_count],
|
13
|
+
quantization: Camalian.options[:quantization],
|
14
|
+
optimal: true)
|
15
|
+
image = ::ChunkyPNG::Image.from_file(@src_file_path)
|
16
|
+
|
17
|
+
colors = image.pixels.map do |val|
|
18
|
+
Color.new(
|
19
|
+
ChunkyPNG::Color.r(val),
|
20
|
+
ChunkyPNG::Color.g(val),
|
21
|
+
ChunkyPNG::Color.b(val)
|
22
|
+
)
|
21
23
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
colors << Color.new(c[0],c[1],c[2])
|
24
|
+
|
25
|
+
quantize = Object.const_get("Camalian::Quantization::#{quantization.capitalize}").new
|
26
|
+
|
27
|
+
palette = quantize.process(colors, count)
|
28
|
+
|
29
|
+
retry_count = 1
|
30
|
+
while !optimal && palette.size < count
|
31
|
+
palette = quantize.process(colors, count + retry_count)
|
32
|
+
retry_count += 1
|
32
33
|
end
|
33
|
-
|
34
|
+
|
35
|
+
palette
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
data/lib/camalian/palette.rb
CHANGED
@@ -1,26 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Camalian
|
4
|
+
# Collection of colors with some useful features
|
2
5
|
class Palette < Array
|
3
|
-
|
4
6
|
def sort_by_lightness
|
5
|
-
Palette.new(
|
7
|
+
Palette.new(sort_by(&:l).reverse)
|
6
8
|
end
|
7
9
|
|
8
10
|
def sort_by_hue
|
9
|
-
Palette.new(
|
11
|
+
Palette.new(sort_by(&:h).reverse)
|
10
12
|
end
|
11
13
|
|
12
14
|
def sort_similar_colors
|
13
|
-
Palette.new(
|
15
|
+
Palette.new(sort_by(&:hsv))
|
14
16
|
end
|
15
17
|
|
16
18
|
def sort_by_saturation
|
17
|
-
Palette.new(
|
19
|
+
Palette.new(sort_by(&:s).reverse)
|
20
|
+
end
|
21
|
+
|
22
|
+
def average_color
|
23
|
+
r = map(&:r).inject(&:+)
|
24
|
+
g = map(&:g).inject(&:+)
|
25
|
+
b = map(&:b).inject(&:+)
|
26
|
+
size = self.size
|
27
|
+
|
28
|
+
Color.new(r / size, g / size, b / size)
|
18
29
|
end
|
19
30
|
|
20
31
|
def light_colors(limit1, limit2)
|
21
32
|
min = [limit1, limit2].min
|
22
33
|
max = [limit1, limit2].max
|
23
|
-
table =
|
34
|
+
table = dup
|
24
35
|
Palette.new(table.delete_if { |color| color.l > max or color.l < min })
|
25
36
|
end
|
26
37
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Camalian
|
4
|
+
module Quantization
|
5
|
+
class Histogram # :nodoc:
|
6
|
+
def process(colors, count)
|
7
|
+
bucket_size = (255.0 / count).ceil
|
8
|
+
buckets = {}
|
9
|
+
|
10
|
+
colors.each do |color|
|
11
|
+
key = bucket_key(color, bucket_size)
|
12
|
+
buckets[key] ||= Palette.new
|
13
|
+
buckets[key].push(color)
|
14
|
+
end
|
15
|
+
|
16
|
+
Palette.new(buckets.map { |_, value| value.average_color })
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def bucket_key(color, bucket_size)
|
22
|
+
"#{color.r / bucket_size}:#{color.g / bucket_size}:#{color.b / bucket_size}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/camalian/version.rb
CHANGED
data/test/assets/palette.png
CHANGED
Binary file
|
data/test/test_color.rb
CHANGED
@@ -1,29 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
1
4
|
require 'minitest/autorun'
|
2
5
|
require 'minitest/spec'
|
3
6
|
require 'camalian'
|
4
7
|
|
5
8
|
describe Camalian::Color do
|
6
9
|
before do
|
7
|
-
@color = Camalian::Color.new(120,255,30)
|
10
|
+
@color = Camalian::Color.new(120, 255, 30)
|
8
11
|
end
|
9
12
|
|
10
|
-
describe
|
11
|
-
it
|
12
|
-
@color.to_hex.must_equal
|
13
|
+
describe 'Color initialized with 120, 255, 30 rgb values' do
|
14
|
+
it 'hex value must be #78ff1e' do
|
15
|
+
_(@color.to_hex).must_equal '#78ff1e'
|
13
16
|
end
|
14
17
|
|
15
|
-
it
|
16
|
-
[@color.h.to_i, @color.s.to_i, @color.l.to_i].must_equal [96, 100, 55]
|
18
|
+
it 'hsl color components must ' do
|
19
|
+
_([@color.h.to_i, @color.s.to_i, @color.l.to_i]).must_equal [96, 100, 55]
|
17
20
|
end
|
18
21
|
|
19
|
-
it
|
20
|
-
@color.hsv.map(&:to_i).must_equal [96, 88, 100]
|
22
|
+
it 'hsv color components must ' do
|
23
|
+
_(@color.hsv.map(&:to_i)).must_equal [96, 88, 100]
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
describe
|
25
|
-
it
|
26
|
-
Camalian::Color.new(7, 7, 7).to_hex.must_equal
|
27
|
+
describe 'initialized with 1 integer rgb value' do
|
28
|
+
it 'must have leading zero' do
|
29
|
+
_(Camalian::Color.new(7, 7, 7).to_hex).must_equal '#070707'
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
data/test/test_helper.rb
ADDED
data/test/test_palette.rb
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
1
4
|
require 'minitest/autorun'
|
2
5
|
require 'minitest/spec'
|
3
6
|
require 'camalian'
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
+
PALLET_IMAGE_COLORS = %w[#4dd915 #49cc23 #45c031 #41b43f #3da84d #399c5b #359069 #318478 #2d7886 #296c94 #2560a2
|
9
|
+
#2154b0 #1d48be #193ccc #1530db].freeze
|
8
10
|
|
9
11
|
describe Camalian::Palette do
|
10
12
|
before do
|
11
|
-
@image = Camalian
|
12
|
-
@palette = @image.prominent_colors(15)
|
13
|
+
@image = Camalian.load(File.join(File.dirname(__FILE__), 'assets/palette.png'))
|
14
|
+
@palette = @image.prominent_colors(15, optimal: false)
|
13
15
|
end
|
14
16
|
|
15
|
-
describe
|
16
|
-
it
|
17
|
-
@palette.size.must_equal 15
|
17
|
+
describe 'palette with 15 colors extracted' do
|
18
|
+
it 'must have 15 colors' do
|
19
|
+
_(@palette.size).must_equal 15
|
18
20
|
end
|
19
21
|
|
20
|
-
it
|
21
|
-
@palette.sort_similar_colors.map(&:to_hex).must_equal
|
22
|
+
it 'sort similar colors in order' do
|
23
|
+
_(@palette.sort_similar_colors.map(&:to_hex)).must_equal PALLET_IMAGE_COLORS
|
22
24
|
end
|
23
25
|
|
24
|
-
it
|
25
|
-
@palette.light_colors(0, 40).map(&:to_hex).must_equal %
|
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]
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
metadata
CHANGED
@@ -1,57 +1,75 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: camalian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.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: 2020-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: chunky_png
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
17
20
|
- - ">="
|
18
21
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
22
|
+
version: 1.3.14
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
24
30
|
- - ">="
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
32
|
+
version: 1.3.14
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
34
|
+
name: minitest
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - "~>"
|
32
38
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
|
39
|
+
version: '5.14'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 5.14.2
|
43
|
+
type: :development
|
35
44
|
prerelease: false
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
37
46
|
requirements:
|
38
47
|
- - "~>"
|
39
48
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
49
|
+
version: '5.14'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 5.14.2
|
41
53
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
54
|
+
name: rake
|
43
55
|
requirement: !ruby/object:Gem::Requirement
|
44
56
|
requirements:
|
45
57
|
- - "~>"
|
46
58
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
|
59
|
+
version: '13.0'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 13.0.1
|
63
|
+
type: :development
|
49
64
|
prerelease: false
|
50
65
|
version_requirements: !ruby/object:Gem::Requirement
|
51
66
|
requirements:
|
52
67
|
- - "~>"
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
69
|
+
version: '13.0'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 13.0.1
|
55
73
|
description: Library used to deal with colors and images
|
56
74
|
email:
|
57
75
|
- nazarhussain@gmail.com
|
@@ -59,7 +77,14 @@ executables: []
|
|
59
77
|
extensions: []
|
60
78
|
extra_rdoc_files: []
|
61
79
|
files:
|
80
|
+
- ".github/workflows/gpr-push.yml"
|
81
|
+
- ".github/workflows/ruby.yml"
|
82
|
+
- ".github/workflows/rubygems-push.yml"
|
62
83
|
- ".gitignore"
|
84
|
+
- ".overcommit.yml"
|
85
|
+
- ".rubocop.yml"
|
86
|
+
- ".tool-versions"
|
87
|
+
- ".travis.yml"
|
63
88
|
- Gemfile
|
64
89
|
- LICENSE.txt
|
65
90
|
- README.md
|
@@ -69,10 +94,11 @@ files:
|
|
69
94
|
- lib/camalian/color.rb
|
70
95
|
- lib/camalian/image.rb
|
71
96
|
- lib/camalian/palette.rb
|
97
|
+
- lib/camalian/quantization/histogram.rb
|
72
98
|
- lib/camalian/version.rb
|
73
|
-
- lib/chunky_png_patch/color.rb
|
74
99
|
- test/assets/palette.png
|
75
100
|
- test/test_color.rb
|
101
|
+
- test/test_helper.rb
|
76
102
|
- test/test_palette.rb
|
77
103
|
homepage: https://github.com/nazarhussain/camalian
|
78
104
|
licenses:
|
@@ -86,16 +112,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
112
|
requirements:
|
87
113
|
- - ">="
|
88
114
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
115
|
+
version: '2.4'
|
90
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
117
|
requirements:
|
92
118
|
- - ">="
|
93
119
|
- !ruby/object:Gem::Version
|
94
120
|
version: '0'
|
95
|
-
requirements:
|
96
|
-
|
97
|
-
rubyforge_project:
|
98
|
-
rubygems_version: 2.4.5
|
121
|
+
requirements: []
|
122
|
+
rubygems_version: 3.0.3
|
99
123
|
signing_key:
|
100
124
|
specification_version: 4
|
101
125
|
summary: Library used to deal with colors and images. You can extract colors from
|
@@ -103,4 +127,5 @@ summary: Library used to deal with colors and images. You can extract colors fro
|
|
103
127
|
test_files:
|
104
128
|
- test/assets/palette.png
|
105
129
|
- test/test_color.rb
|
130
|
+
- test/test_helper.rb
|
106
131
|
- test/test_palette.rb
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module ChunkyPNG::Color
|
2
|
-
# See http://en.wikipedia.org/wiki/Hue#Computing_hue_from_RGB
|
3
|
-
def self.hue(pixel)
|
4
|
-
r, g, b = r(pixel), g(pixel), b(pixel)
|
5
|
-
return 0 if r == b and b == g
|
6
|
-
((180 / Math::PI * Math.atan2((2 * r) - g - b, Math.sqrt(3) * (g - b))) - 90) % 360
|
7
|
-
end
|
8
|
-
|
9
|
-
# The modular distance, as the hue is circular
|
10
|
-
def self.distance(pixel, poxel)
|
11
|
-
hue_pixel, hue_poxel = hue(pixel), hue(poxel)
|
12
|
-
[(hue_pixel - hue_poxel) % 360, (hue_poxel - hue_pixel) % 360].min
|
13
|
-
end
|
14
|
-
end
|