cheers 0.0.1 → 0.0.3
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 +7 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.rvmrc +48 -0
- data/Gemfile +24 -2
- data/Guardfile +13 -0
- data/bin/cheers +14 -0
- data/cheers.gemspec +1 -1
- data/components/blank.png +0 -0
- data/lib/cheers.rb +18 -2
- data/lib/cheers/avatar.rb +25 -136
- data/lib/cheers/background.rb +19 -0
- data/lib/cheers/color.rb +12 -5
- data/lib/cheers/component.rb +50 -0
- data/lib/cheers/contrasting_color_picker.rb +25 -0
- data/lib/cheers/decoration.rb +25 -0
- data/lib/cheers/eyes.rb +20 -0
- data/lib/cheers/face.rb +14 -0
- data/lib/cheers/image_component.rb +13 -0
- data/lib/cheers/lower_glow.rb +34 -0
- data/lib/cheers/mouth.rb +18 -0
- data/lib/cheers/texture.rb +22 -0
- data/lib/cheers/upper_glow.rb +18 -0
- data/lib/cheers/version.rb +1 -1
- data/spec/cheers/color_spec.rb +96 -0
- data/spec/spec_helper.rb +15 -0
- metadata +40 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dc530a68f47497a4cb2a01b9cdcdd457c8a74c082363dc2c02c370659df6c54a
|
4
|
+
data.tar.gz: 1153a39c5a6caea0c03267623bdb0bafd48e7a404180dfd58ec994fd89feb003
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 21d50c1983d5e504f49ddee016740f82952ed10bdf74223f54c4eb6f6330e479548a3a14a51645b3d6bf9fb12a69a827466ce5dd38308bd6ee0d2c9ac6a9e3bf
|
7
|
+
data.tar.gz: 1cad389111a13dbcff6642d9f03176de7e23d300592efa1116e3fd0d382739c2340dae3deed37d0d12f7f06d2b875150ef3c5716486f9651b6b9024f7a9299ad
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.0
|
data/.rvmrc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
+
# Only full ruby name is supported here, for short names use:
|
8
|
+
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
+
environment_id="ruby-1.9.3-p125@cheers"
|
10
|
+
|
11
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
+
# rvmrc_rvm_version="1.10.3" # 1.10.1 seams as a safe start
|
13
|
+
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
+
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
+
# return 1
|
16
|
+
# }
|
17
|
+
|
18
|
+
# First we attempt to load the desired environment directly from the environment
|
19
|
+
# file. This is very fast and efficient compared to running through the entire
|
20
|
+
# CLI and selector. If you want feedback on which environment was used then
|
21
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
+
then
|
25
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
+
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
+
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
+
else
|
29
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
30
|
+
rvm --create "$environment_id" || {
|
31
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
32
|
+
return 1
|
33
|
+
}
|
34
|
+
fi
|
35
|
+
|
36
|
+
# If you use bundler, this might be useful to you:
|
37
|
+
if [[ -s Gemfile ]] && {
|
38
|
+
! builtin command -v bundle >/dev/null ||
|
39
|
+
builtin command -v bundle | grep $rvm_path/bin/bundle >/dev/null
|
40
|
+
}
|
41
|
+
then
|
42
|
+
printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
43
|
+
gem install bundler
|
44
|
+
fi
|
45
|
+
if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
|
46
|
+
then
|
47
|
+
bundle install | grep -vE '^Using|Your bundle is complete'
|
48
|
+
fi
|
data/Gemfile
CHANGED
@@ -1,4 +1,26 @@
|
|
1
|
-
source
|
1
|
+
source :rubygems
|
2
2
|
|
3
|
-
# Specify
|
3
|
+
# Specify the project's dependencies in the gemspec:
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
# Specifiy the development dependencies here:
|
7
|
+
group :development do
|
8
|
+
gem 'rake'
|
9
|
+
|
10
|
+
# Documentation:
|
11
|
+
gem 'yard'
|
12
|
+
|
13
|
+
# Testing libraries:
|
14
|
+
gem 'rspec'
|
15
|
+
|
16
|
+
# Colorful messages:
|
17
|
+
gem 'rainbow'
|
18
|
+
|
19
|
+
# Support for guard:
|
20
|
+
gem 'guard'
|
21
|
+
gem 'guard-bundler'
|
22
|
+
gem 'guard-rspec'
|
23
|
+
gem 'rb-fsevent'
|
24
|
+
gem 'rb-readline'
|
25
|
+
gem 'fuubar'
|
26
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rb-readline'
|
2
|
+
|
3
|
+
guard 'bundler' do
|
4
|
+
watch('Gemfile')
|
5
|
+
watch('cheers.gemspec')
|
6
|
+
end
|
7
|
+
|
8
|
+
guard 'rspec', version: 2, cli: '--format Fuubar --colour' do
|
9
|
+
watch(%r{^spec/.+_spec\.rb})
|
10
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{lib/.+\.rb}) { "spec" }
|
12
|
+
watch('spec/spec_helper.rb') { "spec" }
|
13
|
+
end
|
data/bin/cheers
ADDED
data/cheers.gemspec
CHANGED
Binary file
|
data/lib/cheers.rb
CHANGED
@@ -2,6 +2,22 @@ $LOAD_PATH << File.expand_path('../', __FILE__)
|
|
2
2
|
|
3
3
|
module Cheers
|
4
4
|
autoload :VERSION, 'cheers/version'
|
5
|
-
|
6
|
-
autoload :Avatar,
|
5
|
+
|
6
|
+
autoload :Avatar, 'cheers/avatar'
|
7
|
+
autoload :Background, 'cheers/background'
|
8
|
+
autoload :Color, 'cheers/color'
|
9
|
+
autoload :Component, 'cheers/component'
|
10
|
+
autoload :ContrastingColorPicker, 'cheers/contrasting_color_picker'
|
11
|
+
autoload :Decoration, 'cheers/decoration'
|
12
|
+
autoload :Eyes, 'cheers/eyes'
|
13
|
+
autoload :Face, 'cheers/face'
|
14
|
+
autoload :ImageComponent, 'cheers/image_component'
|
15
|
+
autoload :LowerGlow, 'cheers/lower_glow'
|
16
|
+
autoload :Mouth, 'cheers/mouth'
|
17
|
+
autoload :Texture, 'cheers/texture'
|
18
|
+
autoload :UpperGlow, 'cheers/upper_glow'
|
19
|
+
|
20
|
+
def self.root
|
21
|
+
File.expand_path('../../', __FILE__)
|
22
|
+
end
|
7
23
|
end
|
data/lib/cheers/avatar.rb
CHANGED
@@ -1,42 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'mini_magick'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'tempfile'
|
4
4
|
|
5
5
|
module Cheers
|
6
6
|
class Avatar
|
7
|
-
|
7
|
+
|
8
|
+
BACKGROUND_COLORS = %w(#cccccc #dddddd #bbbbbb #f1a800 #fef0cc
|
9
|
+
#fd4238 #fff0f0 #14899d #c3ecee #42991a
|
10
|
+
#f0fff0)
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
SMILE_COLORS = ['#333333', '#666666', '#9e005d', '#ef8200', '#db4640', '#0e788b', '#239340']
|
12
|
-
IMAGES = {
|
13
|
-
|
14
|
-
smiles: [
|
15
|
-
{ smile: 'components/mouths/1-smile.png',
|
16
|
-
smile_glow: 'components/mouths/1-smile-glow.png',
|
17
|
-
bg_mask: 'components/mouths/1-bgmask.png',
|
18
|
-
texture: 'components/texture.png' },
|
19
|
-
{ smile: 'components/mouths/2-smile.png',
|
20
|
-
smile_glow: 'components/mouths/2-smile-glow.png',
|
21
|
-
bg_mask: 'components/mouths/2-bgmask.png',
|
22
|
-
texture: 'components/texture.png' },
|
23
|
-
{ smile: 'components/mouths/3-smile.png',
|
24
|
-
smile_glow: 'components/mouths/3-smile-glow.png',
|
25
|
-
bg_mask: 'components/mouths/3-bgmask.png',
|
26
|
-
texture: 'components/texture.png' }
|
27
|
-
],
|
28
|
-
eyes: [
|
29
|
-
{ eyes: 'components/eyes/1.png' },
|
30
|
-
{ eyes: 'components/eyes/2.png' },
|
31
|
-
{ eyes: 'components/eyes/3.png' },
|
32
|
-
{ eyes: 'components/eyes/4.png' },
|
33
|
-
{ eyes: 'components/eyes/5.png' }
|
34
|
-
],
|
35
|
-
decorations: [
|
36
|
-
{ id: 1, decoration: 'components/decorations/1.png' },
|
37
|
-
{ id: 2, decoration: 'components/decorations/2.png' }
|
38
|
-
]
|
39
|
-
}
|
12
|
+
COMPONENT_COLORS = %w(#333333 #666666 #9e005d #ef8200 #db4640
|
13
|
+
#0e788b #239340)
|
40
14
|
|
41
15
|
# Creates a new avatar from the seed string
|
42
16
|
def initialize(seed)
|
@@ -45,117 +19,32 @@ module Cheers
|
|
45
19
|
|
46
20
|
# Writes avatar image at the provided file path
|
47
21
|
def avatar_file(file_path)
|
48
|
-
compose_avatar
|
49
|
-
|
50
|
-
@avatar.write(file_path)
|
22
|
+
avatar = compose_avatar
|
51
23
|
|
24
|
+
avatar.write(file_path)
|
25
|
+
|
52
26
|
file_path
|
53
27
|
end
|
54
28
|
|
29
|
+
# Returns a binary version of the image
|
30
|
+
def to_blob(format)
|
31
|
+
avatar = compose_avatar
|
32
|
+
|
33
|
+
avatar.format = format
|
34
|
+
avatar.to_blob
|
35
|
+
end
|
36
|
+
|
55
37
|
private
|
56
38
|
|
57
39
|
def compose_avatar #:nodoc:
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
smile_components = IMAGES[:smiles].sample(random: random_generator)
|
64
|
-
smile_bg_color = BACKGROUND_COLORS.sample(random: random_generator)
|
65
|
-
# smile_color = SMILE_COLORS.sample(random: random_generator)
|
66
|
-
# eyes_color = SMILE_COLORS.sample(random: random_generator)
|
67
|
-
eyes_components = IMAGES[:eyes].sample(random: random_generator)
|
68
|
-
smile_upper_glow_color = SMILE_COLORS.sample(random: random_generator)
|
69
|
-
smile_lower_glow_color = SMILE_COLORS.sample(random: random_generator)
|
70
|
-
has_decoration = [true, true, false].sample(random: random_generator)
|
71
|
-
decoration_component = IMAGES[:decorations].sample(random: random_generator)
|
72
|
-
decoration_color = BACKGROUND_COLORS.sample(random: random_generator)
|
73
|
-
|
74
|
-
# Lets test if the color behind eyes is very similar to the eye color.
|
75
|
-
# Generate a new eye color if that's the case.
|
76
|
-
eyes_contrasting_color = if has_decoration and decoration_component[:id] == 1
|
77
|
-
decoration_color
|
78
|
-
else
|
79
|
-
avatar_bg_color
|
80
|
-
end
|
81
|
-
|
82
|
-
# Lets not use the same random generator for generating unknown amount of new colors
|
83
|
-
rng = Random.new(random_generator.rand(10000))
|
84
|
-
begin
|
85
|
-
eyes_color = SMILE_COLORS.sample(random: rng)
|
86
|
-
end while Color.new(eyes_color).similar?(eyes_contrasting_color, 0.2)
|
87
|
-
|
88
|
-
# Lets test if the background colors are very similar to the smile color.
|
89
|
-
# Change the smile color if that's the case, right?
|
90
|
-
rng = Random.new(random_generator.rand(10000))
|
91
|
-
begin
|
92
|
-
smile_color = SMILE_COLORS.sample(random: rng)
|
93
|
-
the_smile_color = Color.new(smile_color)
|
94
|
-
end while the_smile_color.similar?(avatar_bg_color, 0.2) or the_smile_color.similar?(smile_bg_color, 0.2)
|
95
|
-
|
96
|
-
|
97
|
-
# 1. Lets create upper background
|
98
|
-
upper_background = Magick::Image.new(512, 512) { self.background_color = avatar_bg_color }
|
99
|
-
|
100
|
-
# This is smile glow mask
|
101
|
-
smile_glow_image = Magick::Image.read(component_path(smile_components[:smile_glow]))[0]
|
102
|
-
|
103
|
-
# Create smile glow layer and put it on upper background
|
104
|
-
smile_upper_glow = Magick::Image.new(512, 512) { self.background_color = smile_upper_glow_color }
|
105
|
-
upper_background.add_compose_mask(smile_glow_image)
|
106
|
-
upper_background.composite!(smile_upper_glow, 0, 0, Magick::OverCompositeOp)
|
107
|
-
upper_background.delete_compose_mask
|
108
|
-
|
109
|
-
|
110
|
-
# 2. Lets create lower background
|
111
|
-
lower_background = Magick::Image.new(512, 512) { self.background_color = smile_bg_color }
|
112
|
-
|
113
|
-
# Create another smile glow layer but put it on lower background
|
114
|
-
smile_lower_glow = Magick::Image.new(512, 512) { self.background_color = smile_lower_glow_color }
|
115
|
-
lower_background.add_compose_mask(smile_glow_image)
|
116
|
-
lower_background.composite!(smile_lower_glow, 0, 0, Magick::OverCompositeOp)
|
117
|
-
lower_background.delete_compose_mask
|
118
|
-
|
119
|
-
|
120
|
-
# 3. Lets compose both backgrounds together
|
121
|
-
|
122
|
-
# This will be the final avatar image.
|
123
|
-
# Because we will draw the lower background over the upper background,
|
124
|
-
# we can use the upper background as the starting image.
|
125
|
-
avatar = upper_background
|
126
|
-
|
127
|
-
# Lets mask and put the lower background on top of the image
|
128
|
-
avatar.add_compose_mask(Magick::Image.read(component_path(smile_components[:bg_mask]))[0])
|
129
|
-
avatar.composite!(lower_background, 0, 0, Magick::OverCompositeOp)
|
130
|
-
avatar.delete_compose_mask
|
131
|
-
|
132
|
-
# 4. Add decorations
|
133
|
-
if has_decoration
|
134
|
-
decoration = Magick::Image.new(512, 512) { self.background_color = decoration_color }
|
135
|
-
avatar.add_compose_mask(Magick::Image.read(component_path(decoration_component[:decoration]))[0])
|
136
|
-
avatar.composite!(decoration, 0, 0, Magick::OverCompositeOp)
|
137
|
-
avatar.delete_compose_mask
|
40
|
+
generator = Random.new(@seed)
|
41
|
+
|
42
|
+
result = nil
|
43
|
+
[Background, Face, Decoration, Eyes].each do |klass|
|
44
|
+
result = klass.new(result, generator).apply
|
138
45
|
end
|
139
|
-
|
140
|
-
|
141
|
-
texture = Magick::Image.read(component_path(smile_components[:texture]))[0]
|
142
|
-
avatar.composite!(texture, 0, 0, Magick::OverCompositeOp)
|
143
|
-
|
144
|
-
smile = Magick::Image.new(512, 512) { self.background_color = smile_color }
|
145
|
-
avatar.add_compose_mask(Magick::Image.read(component_path(smile_components[:smile]))[0])
|
146
|
-
avatar.composite!(smile, 0, 0, Magick::OverCompositeOp)
|
147
|
-
avatar.delete_compose_mask
|
148
|
-
|
149
|
-
eyes = Magick::Image.new(512, 512) { self.background_color = eyes_color }
|
150
|
-
avatar.add_compose_mask(Magick::Image.read(component_path(eyes_components[:eyes]))[0])
|
151
|
-
avatar.composite!(eyes, 0, 0, Magick::OverCompositeOp)
|
152
|
-
avatar.delete_compose_mask
|
153
|
-
|
154
|
-
@avatar = avatar
|
155
|
-
end
|
156
|
-
|
157
|
-
def component_path(asset) #:nodoc:
|
158
|
-
[GEM_ROOT, asset].join('/')
|
46
|
+
|
47
|
+
result
|
159
48
|
end
|
160
49
|
end
|
161
50
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Background < Component
|
3
|
+
|
4
|
+
attr_reader :color
|
5
|
+
|
6
|
+
def initialize(canvas, randomizer)
|
7
|
+
super
|
8
|
+
|
9
|
+
@color = Avatar::BACKGROUND_COLORS.sample(random: randomizer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def apply
|
13
|
+
# Work around instance_eval wonkiness by declaring local variables:
|
14
|
+
color = self.color
|
15
|
+
|
16
|
+
colored_image(color)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/cheers/color.rb
CHANGED
@@ -11,10 +11,12 @@ module Cheers
|
|
11
11
|
self.g = hex_string[2..3].to_i(16)
|
12
12
|
self.b = hex_string[4..5].to_i(16)
|
13
13
|
end
|
14
|
-
|
15
|
-
#
|
14
|
+
|
15
|
+
#
|
16
16
|
def to_s
|
17
|
-
return '#' + r.to_s(16)
|
17
|
+
return '#' + r.to_s(16).rjust(2, '0') +
|
18
|
+
g.to_s(16).rjust(2, '0') +
|
19
|
+
b.to_s(16).rjust(2, '0')
|
18
20
|
end
|
19
21
|
|
20
22
|
def to_hsv
|
@@ -36,7 +38,7 @@ module Cheers
|
|
36
38
|
[hue % 360, saturation, max]
|
37
39
|
end
|
38
40
|
|
39
|
-
def similar?(other_color, threshold)
|
41
|
+
def similar?(other_color, threshold = 0.1)
|
40
42
|
other_color = Color.new(other_color) unless other_color.is_a? Color
|
41
43
|
|
42
44
|
color_hsv = to_hsv
|
@@ -52,6 +54,11 @@ module Cheers
|
|
52
54
|
false
|
53
55
|
end
|
54
56
|
end
|
57
|
+
|
58
|
+
def self.rgb_to_hex(rgb)
|
59
|
+
hex = rgb.map {|c| c.to_s(16).rjust(2, '0')}.join
|
60
|
+
return "##{hex}"
|
61
|
+
end
|
55
62
|
end
|
56
63
|
|
57
|
-
end
|
64
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Component
|
3
|
+
|
4
|
+
attr_reader :canvas, :randomizer
|
5
|
+
|
6
|
+
def initialize(canvas, randomizer)
|
7
|
+
@canvas = canvas
|
8
|
+
@randomizer = randomizer
|
9
|
+
end
|
10
|
+
|
11
|
+
def image_path(component)
|
12
|
+
[Cheers.root, 'components', component].join '/'
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_image
|
16
|
+
MiniMagick::Image.open(image_path('blank.png'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def colored_image(color)
|
20
|
+
image = MiniMagick::Image.open(image_path('blank.png'))
|
21
|
+
|
22
|
+
image.combine_options do |c|
|
23
|
+
c.resize '512x512'
|
24
|
+
c.fuzz "100%"
|
25
|
+
c.fill color
|
26
|
+
c.floodfill "+0+0", 'white'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def composite_with_mask(base, second, mask_image)
|
31
|
+
mask = MiniMagick::Image.open(image_path(mask_image))
|
32
|
+
mask.combine_options do |m|
|
33
|
+
m.alpha 'copy'
|
34
|
+
end
|
35
|
+
|
36
|
+
base.composite(second, 'png', mask)
|
37
|
+
end
|
38
|
+
|
39
|
+
# assumes top left pixel is background since none of the parts overlap there
|
40
|
+
def extract_background_color(image)
|
41
|
+
rgb = image.get_pixels[0][0]
|
42
|
+
Color.rgb_to_hex(rgb)
|
43
|
+
end
|
44
|
+
|
45
|
+
def apply
|
46
|
+
color = self.color
|
47
|
+
composite_with_mask(canvas, colored_image(color), image)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cheers
|
2
|
+
class ContrastingColorPicker
|
3
|
+
|
4
|
+
MAX_RETRIES = 10
|
5
|
+
|
6
|
+
attr_reader :palette, :colors
|
7
|
+
|
8
|
+
def initialize(palette, *colors)
|
9
|
+
@palette = palette.map { |c| Color.new(c) }
|
10
|
+
@colors = colors.map { |c| Color.new(c) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def pick(randomizer = Random.new)
|
14
|
+
pick = palette.sample(random: randomizer)
|
15
|
+
|
16
|
+
try = 0
|
17
|
+
while colors.any? { |c| c.similar?(pick) } && try <= MAX_RETRIES
|
18
|
+
try += 1
|
19
|
+
pick = palette.sample(random: randomizer)
|
20
|
+
end
|
21
|
+
|
22
|
+
pick.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Decoration < ImageComponent
|
3
|
+
|
4
|
+
IMAGES = %w( decorations/1.png
|
5
|
+
decorations/2.png )
|
6
|
+
|
7
|
+
attr_reader :color, :image
|
8
|
+
|
9
|
+
def initialize(canvas, color_randomizer, image_randomizer = nil)
|
10
|
+
super
|
11
|
+
|
12
|
+
@color = ContrastingColorPicker.new(Avatar::BACKGROUND_COLORS, extract_background_color(canvas)).pick(color_randomizer)
|
13
|
+
@image = IMAGES.sample random: self.image_randomizer
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply?
|
17
|
+
[true, true, false].sample(random: image_randomizer)
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply
|
21
|
+
return canvas unless apply?
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/cheers/eyes.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Eyes < ImageComponent
|
3
|
+
|
4
|
+
IMAGES = %w( eyes/1.png
|
5
|
+
eyes/2.png
|
6
|
+
eyes/3.png
|
7
|
+
eyes/4.png
|
8
|
+
eyes/5.png )
|
9
|
+
|
10
|
+
attr_reader :color, :image
|
11
|
+
|
12
|
+
def initialize(canvas, color_randomizer, image_randomizer = nil)
|
13
|
+
super
|
14
|
+
|
15
|
+
@color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, extract_background_color(canvas)).pick(color_randomizer)
|
16
|
+
@image = IMAGES.sample random: self.image_randomizer
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/cheers/face.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Cheers
|
2
|
+
class ImageComponent < Component
|
3
|
+
|
4
|
+
attr_reader :canvas, :color_randomizer, :image_randomizer
|
5
|
+
|
6
|
+
def initialize(canvas, color_randomizer, image_randomizer = nil)
|
7
|
+
@canvas = canvas
|
8
|
+
@color_randomizer = color_randomizer
|
9
|
+
@image_randomizer = image_randomizer || color_randomizer
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Cheers
|
2
|
+
class LowerGlow < ImageComponent
|
3
|
+
|
4
|
+
GLOW_IMAGES = %w( mouths/1-smile-glow.png
|
5
|
+
mouths/2-smile-glow.png
|
6
|
+
mouths/3-smile-glow.png )
|
7
|
+
|
8
|
+
MASK_IMAGES = %w( mouths/1-bgmask.png
|
9
|
+
mouths/2-bgmask.png
|
10
|
+
mouths/3-bgmask.png )
|
11
|
+
|
12
|
+
attr_reader :background_color, :glow_color, :glow_image, :mask_image
|
13
|
+
|
14
|
+
def initialize(canvas, color_randomizer, element_randomizer = nil)
|
15
|
+
super
|
16
|
+
|
17
|
+
canvas_background = extract_background_color(canvas)
|
18
|
+
|
19
|
+
@background_color = ContrastingColorPicker.new(Avatar::BACKGROUND_COLORS, canvas_background).pick(color_randomizer)
|
20
|
+
@glow_color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, canvas_background, background_color).pick(color_randomizer)
|
21
|
+
@glow_image = GLOW_IMAGES.sample random: element_randomizer.dup
|
22
|
+
@mask_image = MASK_IMAGES.sample random: element_randomizer.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
def apply
|
26
|
+
glow_color = self.glow_color
|
27
|
+
background_color = self.background_color
|
28
|
+
|
29
|
+
background = composite_with_mask(colored_image(background_color), colored_image(glow_color), glow_image)
|
30
|
+
|
31
|
+
composite_with_mask(canvas, background, mask_image)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/cheers/mouth.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Mouth < ImageComponent
|
3
|
+
|
4
|
+
IMAGES = %w( mouths/1-smile.png
|
5
|
+
mouths/2-smile.png
|
6
|
+
mouths/3-smile.png )
|
7
|
+
|
8
|
+
attr_reader :color, :image
|
9
|
+
|
10
|
+
def initialize(canvas, color_randomizer, element_randomizer = nil)
|
11
|
+
super
|
12
|
+
|
13
|
+
@color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, extract_background_color(canvas)).pick(color_randomizer)
|
14
|
+
@image = IMAGES.sample random: element_randomizer
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Cheers
|
2
|
+
class Texture < ImageComponent
|
3
|
+
|
4
|
+
IMAGES = %w( texture.png )
|
5
|
+
|
6
|
+
attr_reader :color, :image
|
7
|
+
|
8
|
+
def initialize(canvas, color_randomizer, element_randomizer = nil)
|
9
|
+
super
|
10
|
+
|
11
|
+
@image = IMAGES.sample random: element_randomizer
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply
|
15
|
+
texture = MiniMagick::Image.open(image_path(image))
|
16
|
+
canvas.composite(texture) do |c|
|
17
|
+
c.compose "Over" # OverCompositeOp
|
18
|
+
c.geometry "+0+0"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Cheers
|
2
|
+
class UpperGlow < ImageComponent
|
3
|
+
|
4
|
+
IMAGES = %w( mouths/1-smile-glow.png
|
5
|
+
mouths/2-smile-glow.png
|
6
|
+
mouths/3-smile-glow.png )
|
7
|
+
|
8
|
+
attr_reader :color, :image
|
9
|
+
|
10
|
+
def initialize(canvas, color_randomizer, element_randomizer = nil)
|
11
|
+
super
|
12
|
+
|
13
|
+
@color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, extract_background_color(canvas)).pick(color_randomizer)
|
14
|
+
@image = IMAGES.sample random: element_randomizer
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/cheers/version.rb
CHANGED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cheers::Color do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'converts 32 bit hexadecimal color values to RGB' do
|
6
|
+
color = Cheers::Color.new('#7d7d7d')
|
7
|
+
[color.r, color.g, color.b].should == [125, 125, 125]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#r' do
|
12
|
+
it 'returns the intensity of the red component of the color' do
|
13
|
+
black = Cheers::Color.new '#000000'
|
14
|
+
black.r.should == 0
|
15
|
+
|
16
|
+
|
17
|
+
white = Cheers::Color.new '#ffffff'
|
18
|
+
white.r.should == 255
|
19
|
+
|
20
|
+
red = Cheers::Color.new '#7d0000'
|
21
|
+
red.r.should == 125
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#g' do
|
26
|
+
it 'returns the intensity of the green component of the color' do
|
27
|
+
black = Cheers::Color.new '#000000'
|
28
|
+
black.g.should == 0
|
29
|
+
|
30
|
+
|
31
|
+
white = Cheers::Color.new '#ffffff'
|
32
|
+
white.g.should == 255
|
33
|
+
|
34
|
+
green = Cheers::Color.new '#007d00'
|
35
|
+
green.g.should == 125
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#b' do
|
40
|
+
it 'returns the intensity of the blue component of the color' do
|
41
|
+
black = Cheers::Color.new '#000000'
|
42
|
+
black.b.should == 0
|
43
|
+
|
44
|
+
|
45
|
+
white = Cheers::Color.new '#ffffff'
|
46
|
+
white.b.should == 255
|
47
|
+
|
48
|
+
blue = Cheers::Color.new '#00007d'
|
49
|
+
blue.b.should == 125
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#to_hsv' do
|
54
|
+
it 'returns the HSV values for the color' do
|
55
|
+
orange = Cheers::Color.new '#d97621'
|
56
|
+
h, s, v = orange.to_hsv
|
57
|
+
|
58
|
+
h.should be_within(0.001).of 27.717
|
59
|
+
s.should be_within(0.001).of 0.848
|
60
|
+
v.should be_within(0.001).of 0.851
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#to_s' do
|
65
|
+
it 'returns a hexadecimal representation of the color' do
|
66
|
+
color = Cheers::Color.new('#00007d')
|
67
|
+
color.to_s.should == '#00007d'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#similar?' do
|
72
|
+
it 'returns true if the colors are similar' do
|
73
|
+
bright_white = Cheers::Color.new '#ffffff'
|
74
|
+
broken_white = Cheers::Color.new '#eeeeee'
|
75
|
+
|
76
|
+
bright_white.similar?(broken_white).should be_true
|
77
|
+
broken_white.similar?(bright_white).should be_true
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns false if the colors are not similar' do
|
81
|
+
white = Cheers::Color.new '#ffffff'
|
82
|
+
black = Cheers::Color.new '#000000'
|
83
|
+
|
84
|
+
white.similar?(black).should be_false
|
85
|
+
black.similar?(white).should be_false
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns true if the color is too similar for the given treshold' do
|
89
|
+
orange_1 = Cheers::Color.new '#f1a800'
|
90
|
+
orange_2 = Cheers::Color.new '#ef8200'
|
91
|
+
|
92
|
+
orange_1.similar?(orange_2, 0.02).should be_false
|
93
|
+
orange_1.similar?(orange_2, 0.03).should be_true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require File.expand_path('../../lib/cheers', __FILE__)
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
config.mock_with :rspec
|
15
|
+
end
|
metadata
CHANGED
@@ -1,41 +1,50 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cheers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mārtiņš Spilners
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2019-11-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
17
|
-
none: false
|
14
|
+
name: mini_magick
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
25
27
|
description: Cheers randomly generates user avatars from a set of colors and image
|
26
28
|
components.
|
27
29
|
email:
|
28
30
|
- martins@eet.nu
|
29
|
-
executables:
|
31
|
+
executables:
|
32
|
+
- cheers
|
30
33
|
extensions: []
|
31
34
|
extra_rdoc_files: []
|
32
35
|
files:
|
33
|
-
- .gitignore
|
36
|
+
- ".gitignore"
|
37
|
+
- ".rspec"
|
38
|
+
- ".ruby-version"
|
39
|
+
- ".rvmrc"
|
34
40
|
- Gemfile
|
41
|
+
- Guardfile
|
35
42
|
- LICENSE
|
36
43
|
- README.md
|
37
44
|
- Rakefile
|
45
|
+
- bin/cheers
|
38
46
|
- cheers.gemspec
|
47
|
+
- components/blank.png
|
39
48
|
- components/decorations/1.png
|
40
49
|
- components/decorations/2.png
|
41
50
|
- components/eyes/1.png
|
@@ -75,30 +84,43 @@ files:
|
|
75
84
|
- doc/example_9.png
|
76
85
|
- lib/cheers.rb
|
77
86
|
- lib/cheers/avatar.rb
|
87
|
+
- lib/cheers/background.rb
|
78
88
|
- lib/cheers/color.rb
|
89
|
+
- lib/cheers/component.rb
|
90
|
+
- lib/cheers/contrasting_color_picker.rb
|
91
|
+
- lib/cheers/decoration.rb
|
92
|
+
- lib/cheers/eyes.rb
|
93
|
+
- lib/cheers/face.rb
|
94
|
+
- lib/cheers/image_component.rb
|
95
|
+
- lib/cheers/lower_glow.rb
|
96
|
+
- lib/cheers/mouth.rb
|
97
|
+
- lib/cheers/texture.rb
|
98
|
+
- lib/cheers/upper_glow.rb
|
79
99
|
- lib/cheers/version.rb
|
100
|
+
- spec/cheers/color_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
80
102
|
homepage: http://github.com/eet-nu/cheers
|
81
103
|
licenses: []
|
104
|
+
metadata: {}
|
82
105
|
post_install_message:
|
83
106
|
rdoc_options: []
|
84
107
|
require_paths:
|
85
108
|
- lib
|
86
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
-
none: false
|
88
110
|
requirements:
|
89
|
-
- -
|
111
|
+
- - ">="
|
90
112
|
- !ruby/object:Gem::Version
|
91
113
|
version: '0'
|
92
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
-
none: false
|
94
115
|
requirements:
|
95
|
-
- -
|
116
|
+
- - ">="
|
96
117
|
- !ruby/object:Gem::Version
|
97
118
|
version: '0'
|
98
119
|
requirements: []
|
99
|
-
|
100
|
-
rubygems_version: 1.8.17
|
120
|
+
rubygems_version: 3.0.6
|
101
121
|
signing_key:
|
102
|
-
specification_version:
|
122
|
+
specification_version: 4
|
103
123
|
summary: Generate random user avatars.
|
104
|
-
test_files:
|
124
|
+
test_files:
|
125
|
+
- spec/cheers/color_spec.rb
|
126
|
+
- spec/spec_helper.rb
|