Skip to content
Browse files

Start with breaking up the avatar into multiple components

  • Loading branch information...
1 parent 9537854 commit 9d7ad5f51d587b29c7d5525e9ca001a589f7a952 @tomeric tomeric committed
View
20 lib/cheers.rb
@@ -2,6 +2,22 @@
module Cheers
autoload :VERSION, 'cheers/version'
- autoload :Color, 'cheers/color'
- autoload :Avatar, 'cheers/avatar'
+
+ autoload :Avatar, 'cheers/avatar'
+ autoload :Background, 'cheers/background'
+ autoload :Color, 'cheers/color'
+ autoload :Component, 'cheers/component'
+ autoload :ContrastingColorPicker, 'cheers/contrasting_color_picker'
+ autoload :Decoration, 'cheers/decoration'
+ autoload :Eyes, 'cheers/eyes'
+ autoload :Face, 'cheers/face'
+ autoload :ImageComponent, 'cheers/image_component'
+ autoload :LowerGlow, 'cheers/lower_glow'
+ autoload :Mouth, 'cheers/mouth'
+ autoload :Texture, 'cheers/texture'
+ autoload :UpperGlow, 'cheers/upper_glow'
+
+ def self.root
+ File.expand_path('../../', __FILE__)
+ end
end
View
140 lib/cheers/avatar.rb
@@ -4,39 +4,13 @@
module Cheers
class Avatar
- GEM_ROOT = File.expand_path('../../../', __FILE__)
- BACKGROUND_COLORS = ['#cccccc', '#dddddd', '#bbbbbb', '#F1A800', '#FEF0CC', '#fd4238', '#fff0f0', '#14899d', '#c3ecee', '#42991a', '#f0fff0']
- # SMILE_COLORS = ['#333', '#666', '#9e005d', '#ef8200', '#d8a129', '#db4640', '#0e788b', '#239340']
- SMILE_COLORS = ['#333333', '#666666', '#9e005d', '#ef8200', '#db4640', '#0e788b', '#239340']
- IMAGES = {
-
- smiles: [
- { smile: 'components/mouths/1-smile.png',
- smile_glow: 'components/mouths/1-smile-glow.png',
- bg_mask: 'components/mouths/1-bgmask.png',
- texture: 'components/texture.png' },
- { smile: 'components/mouths/2-smile.png',
- smile_glow: 'components/mouths/2-smile-glow.png',
- bg_mask: 'components/mouths/2-bgmask.png',
- texture: 'components/texture.png' },
- { smile: 'components/mouths/3-smile.png',
- smile_glow: 'components/mouths/3-smile-glow.png',
- bg_mask: 'components/mouths/3-bgmask.png',
- texture: 'components/texture.png' }
- ],
- eyes: [
- { eyes: 'components/eyes/1.png' },
- { eyes: 'components/eyes/2.png' },
- { eyes: 'components/eyes/3.png' },
- { eyes: 'components/eyes/4.png' },
- { eyes: 'components/eyes/5.png' }
- ],
- decorations: [
- { id: 1, decoration: 'components/decorations/1.png' },
- { id: 2, decoration: 'components/decorations/2.png' }
- ]
- }
+ BACKGROUND_COLORS = %w(#cccccc #dddddd #bbbbbb #f1a800 #fef0cc
+ #fd4238 #fff0f0 #14899d #c3ecee #42991a
+ #f0fff0)
+
+ COMPONENT_COLORS = %w(#333333 #666666 #9e005d #ef8200 #db4640
+ #0e788b #239340)
# Creates a new avatar from the seed string
def initialize(seed)
@@ -55,107 +29,15 @@ def avatar_file(file_path)
private
def compose_avatar #:nodoc:
- random_generator = Random.new(@seed)
-
- # 0. Let's get some random colors
- # We shoudn't change the order we call #rand to keep version changes minimal
- avatar_bg_color = BACKGROUND_COLORS.sample(random: random_generator)
- smile_components = IMAGES[:smiles].sample(random: random_generator)
- smile_bg_color = BACKGROUND_COLORS.sample(random: random_generator)
- # smile_color = SMILE_COLORS.sample(random: random_generator)
- # eyes_color = SMILE_COLORS.sample(random: random_generator)
- eyes_components = IMAGES[:eyes].sample(random: random_generator)
- smile_upper_glow_color = SMILE_COLORS.sample(random: random_generator)
- smile_lower_glow_color = SMILE_COLORS.sample(random: random_generator)
- has_decoration = [true, true, false].sample(random: random_generator)
- decoration_component = IMAGES[:decorations].sample(random: random_generator)
- decoration_color = BACKGROUND_COLORS.sample(random: random_generator)
-
- # Lets test if the color behind eyes is very similar to the eye color.
- # Generate a new eye color if that's the case.
- eyes_contrasting_color = if has_decoration and decoration_component[:id] == 1
- decoration_color
- else
- avatar_bg_color
- end
-
- # Lets not use the same random generator for generating unknown amount of new colors
- rng = Random.new(random_generator.rand(10000))
- begin
- eyes_color = SMILE_COLORS.sample(random: rng)
- end while Color.new(eyes_color).similar?(eyes_contrasting_color, 0.2)
-
- # Lets test if the background colors are very similar to the smile color.
- # Change the smile color if that's the case, right?
- rng = Random.new(random_generator.rand(10000))
- begin
- smile_color = SMILE_COLORS.sample(random: rng)
- the_smile_color = Color.new(smile_color)
- end while the_smile_color.similar?(avatar_bg_color, 0.2) or the_smile_color.similar?(smile_bg_color, 0.2)
-
-
- # 1. Lets create upper background
- upper_background = Magick::Image.new(512, 512) { self.background_color = avatar_bg_color }
-
- # This is smile glow mask
- smile_glow_image = Magick::Image.read(component_path(smile_components[:smile_glow]))[0]
-
- # Create smile glow layer and put it on upper background
- smile_upper_glow = Magick::Image.new(512, 512) { self.background_color = smile_upper_glow_color }
- upper_background.add_compose_mask(smile_glow_image)
- upper_background.composite!(smile_upper_glow, 0, 0, Magick::OverCompositeOp)
- upper_background.delete_compose_mask
+ generator = Random.new(@seed)
+ @avatar = Magick::Image.new(512, 512)
- # 2. Lets create lower background
- lower_background = Magick::Image.new(512, 512) { self.background_color = smile_bg_color }
-
- # Create another smile glow layer but put it on lower background
- smile_lower_glow = Magick::Image.new(512, 512) { self.background_color = smile_lower_glow_color }
- lower_background.add_compose_mask(smile_glow_image)
- lower_background.composite!(smile_lower_glow, 0, 0, Magick::OverCompositeOp)
- lower_background.delete_compose_mask
-
-
- # 3. Lets compose both backgrounds together
-
- # This will be the final avatar image.
- # Because we will draw the lower background over the upper background,
- # we can use the upper background as the starting image.
- avatar = upper_background
-
- # Lets mask and put the lower background on top of the image
- avatar.add_compose_mask(Magick::Image.read(component_path(smile_components[:bg_mask]))[0])
- avatar.composite!(lower_background, 0, 0, Magick::OverCompositeOp)
- avatar.delete_compose_mask
-
- # 4. Add decorations
- if has_decoration
- decoration = Magick::Image.new(512, 512) { self.background_color = decoration_color }
- avatar.add_compose_mask(Magick::Image.read(component_path(decoration_component[:decoration]))[0])
- avatar.composite!(decoration, 0, 0, Magick::OverCompositeOp)
- avatar.delete_compose_mask
+ [Background, Face, Decoration, Eyes].each do |klass|
+ klass.new(@avatar, generator).apply
end
- # 5. Add the texture
- texture = Magick::Image.read(component_path(smile_components[:texture]))[0]
- avatar.composite!(texture, 0, 0, Magick::OverCompositeOp)
-
- smile = Magick::Image.new(512, 512) { self.background_color = smile_color }
- avatar.add_compose_mask(Magick::Image.read(component_path(smile_components[:smile]))[0])
- avatar.composite!(smile, 0, 0, Magick::OverCompositeOp)
- avatar.delete_compose_mask
-
- eyes = Magick::Image.new(512, 512) { self.background_color = eyes_color }
- avatar.add_compose_mask(Magick::Image.read(component_path(eyes_components[:eyes]))[0])
- avatar.composite!(eyes, 0, 0, Magick::OverCompositeOp)
- avatar.delete_compose_mask
-
- @avatar = avatar
- end
-
- def component_path(asset) #:nodoc:
- [GEM_ROOT, asset].join('/')
+ @avatar
end
end
end
View
23 lib/cheers/background.rb
@@ -0,0 +1,23 @@
+module Cheers
+ class Background < Component
+
+ attr_reader :color
+
+ def initialize(canvas, randomizer)
+ super
+
+ @color = Avatar::BACKGROUND_COLORS.sample(random: randomizer)
+ end
+
+ def apply
+ # Work around instance_eval wonkiness by declaring local variables:
+ color = self.color
+
+ background = Magick::Image.new(512, 512) do
+ self.background_color = color
+ end
+
+ canvas.composite!(background, 0, 0, Magick::OverCompositeOp)
+ end
+ end
+end
View
12 lib/cheers/component.rb
@@ -0,0 +1,12 @@
+module Cheers
+ class Component
+
+ attr_reader :canvas, :randomizer
+
+ def initialize(canvas, randomizer)
+ @canvas = canvas
+ @randomizer = randomizer
+ end
+
+ end
+end
View
25 lib/cheers/contrasting_color_picker.rb
@@ -0,0 +1,25 @@
+module Cheers
+ class ContrastingColorPicker
+
+ MAX_RETRIES = 10
+
+ attr_reader :palette, :colors
+
+ def initialize(palette, *colors)
+ @palette = palette.map { |c| Color.new(c) }
+ @colors = colors.map { |c| Color.new(c) }
+ end
+
+ def pick(randomizer = Random.new)
+ pick = palette.sample(random: randomizer)
+
+ try = 0
+ while colors.any? { |c| c.similar?(pick) } && try <= MAX_RETRIES
+ try += 1
+ pick = palette.sample(random: randomizer)
+ end
+
+ pick.to_s
+ end
+ end
+end
View
35 lib/cheers/decoration.rb
@@ -0,0 +1,35 @@
+module Cheers
+ class Decoration < ImageComponent
+
+ IMAGES = %w( decorations/1.png
+ decorations/2.png )
+
+ attr_reader :color, :image
+
+ def initialize(canvas, color_randomizer, image_randomizer = nil)
+ super
+
+ @color = ContrastingColorPicker.new(Avatar::BACKGROUND_COLORS, canvas.background_color).pick
+ @image = IMAGES.sample random: self.image_randomizer
+ end
+
+ def apply?
+ [true, true, false].sample(random: image_randomizer)
+ end
+
+ def apply
+ return unless apply?
+
+ mask = Magick::Image.read(image_path(image))[0]
+ color = self.color
+
+ decoration = Magick::Image.new(512, 512) do
+ self.background_color = color
+ end
+
+ canvas.add_compose_mask(mask)
+ canvas.composite!(decoration, 0, 0, Magick::OverCompositeOp)
+ canvas.delete_compose_mask
+ end
+ end
+end
View
32 lib/cheers/eyes.rb
@@ -0,0 +1,32 @@
+module Cheers
+ class Eyes < ImageComponent
+
+ IMAGES = %w( eyes/1.png
+ eyes/2.png
+ eyes/3.png
+ eyes/4.png
+ eyes/5.png )
+
+ attr_reader :color, :image
+
+ def initialize(canvas, color_randomizer, image_randomizer = nil)
+ super
+
+ @color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, canvas.background_color).pick
+ @image = IMAGES.sample random: self.image_randomizer
+ end
+
+ def apply
+ mask = Magick::Image.read(image_path(image))[0]
+ color = self.color
+
+ eyes = Magick::Image.new(512, 512) do
+ self.background_color = color
+ end
+
+ canvas.add_compose_mask(mask)
+ canvas.composite!(eyes, 0, 0, Magick::OverCompositeOp)
+ canvas.delete_compose_mask
+ end
+ end
+end
View
11 lib/cheers/face.rb
@@ -0,0 +1,11 @@
+module Cheers
+ class Face < ImageComponent
+
+ def apply
+ [UpperGlow, LowerGlow, Texture, Mouth].each do |klass|
+ klass.new(canvas, color_randomizer, image_randomizer.dup).apply
+ end
+ end
+
+ end
+end
View
18 lib/cheers/image_component.rb
@@ -0,0 +1,18 @@
+module Cheers
+ class ImageComponent
+
+ attr_reader :canvas, :color_randomizer, :image_randomizer
+
+ def initialize(canvas, color_randomizer, image_randomizer = nil)
+ @canvas = canvas
+ @color_randomizer = color_randomizer
+ @image_randomizer = image_randomizer || color_randomizer
+ end
+
+ private
+
+ def image_path(component)
+ [Cheers.root, 'components', component].join '/'
+ end
+ end
+end
View
50 lib/cheers/lower_glow.rb
@@ -0,0 +1,50 @@
+module Cheers
+ class LowerGlow < ImageComponent
+
+ GLOW_IMAGES = %w( mouths/1-smile-glow.png
+ mouths/2-smile-glow.png
+ mouths/3-smile-glow.png )
+
+ MASK_IMAGES = %w( mouths/1-bgmask.png
+ mouths/2-bgmask.png
+ mouths/3-bgmask.png )
+
+ attr_reader :background_color, :glow_color, :glow_image, :mask_image
+
+ def initialize(canvas, color_randomizer, element_randomizer = nil)
+ super
+
+ @background_color = ContrastingColorPicker.new(Avatar::BACKGROUND_COLORS, canvas.background_color).pick
+ @glow_color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, canvas.background_color, background_color).pick
+ @glow_image = GLOW_IMAGES.sample random: element_randomizer.dup
+ @mask_image = MASK_IMAGES.sample random: element_randomizer.dup
+ end
+
+ def apply
+ glow = Magick::Image.read(image_path(glow_image))[0]
+ mask = Magick::Image.read(image_path(mask_image))[0]
+
+ # Work around instance_eval wonkiness by declaring local variables:
+ glow_color = self.glow_color
+ background_color = self.background_color
+
+ # 2. Lets create lower background
+ background = Magick::Image.new(512, 512) do
+ self.background_color = background_color
+ end
+
+ # Create another smile glow layer but put it on lower background
+ glow_background = Magick::Image.new(512, 512) do
+ self.background_color = glow_color
+ end
+
+ background.add_compose_mask(glow)
+ background.composite!(glow_background, 0, 0, Magick::OverCompositeOp)
+ background.delete_compose_mask
+
+ canvas.add_compose_mask(mask)
+ canvas.composite!(background, 0, 0, Magick::OverCompositeOp)
+ canvas.delete_compose_mask
+ end
+ end
+end
View
30 lib/cheers/mouth.rb
@@ -0,0 +1,30 @@
+module Cheers
+ class Mouth < ImageComponent
+
+ IMAGES = %w( mouths/1-smile.png
+ mouths/2-smile.png
+ mouths/3-smile.png )
+
+ attr_reader :color, :image
+
+ def initialize(canvas, color_randomizer, element_randomizer = nil)
+ super
+
+ @color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, canvas.background_color).pick
+ @image = IMAGES.sample random: element_randomizer
+ end
+
+ def apply
+ color = self.color
+ smile = Magick::Image.new(512, 512) do
+ self.background_color = color
+ end
+
+ mask = Magick::Image.read(image_path(image))[0]
+
+ canvas.add_compose_mask(mask)
+ canvas.composite!(smile, 0, 0, Magick::OverCompositeOp)
+ canvas.delete_compose_mask
+ end
+ end
+end
View
19 lib/cheers/texture.rb
@@ -0,0 +1,19 @@
+module Cheers
+ class Texture < ImageComponent
+
+ IMAGES = %w( texture.png )
+
+ attr_reader :color, :image
+
+ def initialize(canvas, color_randomizer, element_randomizer = nil)
+ super
+
+ @image = IMAGES.sample random: element_randomizer
+ end
+
+ def apply
+ texture = Magick::Image.read(image_path(image))[0]
+ canvas.composite!(texture, 0, 0, Magick::OverCompositeOp)
+ end
+ end
+end
View
30 lib/cheers/upper_glow.rb
@@ -0,0 +1,30 @@
+module Cheers
+ class UpperGlow < ImageComponent
+
+ IMAGES = %w( mouths/1-smile-glow.png
+ mouths/2-smile-glow.png
+ mouths/3-smile-glow.png )
+
+ attr_reader :color, :image
+
+ def initialize(canvas, color_randomizer, element_randomizer = nil)
+ super
+
+ @color = ContrastingColorPicker.new(Avatar::COMPONENT_COLORS, canvas.background_color).pick
+ @image = IMAGES.sample random: element_randomizer
+ end
+
+ def apply
+ color = self.color
+ glow = Magick::Image.new(512, 512) do
+ self.background_color = color
+ end
+
+ mask = Magick::Image.read(image_path(image))[0]
+
+ canvas.add_compose_mask(mask)
+ canvas.composite!(glow, 0, 0, Magick::OverCompositeOp)
+ canvas.delete_compose_mask
+ end
+ end
+end

0 comments on commit 9d7ad5f

Please sign in to comment.
Something went wrong with that request. Please try again.