Skip to content

Instantly share code, notes, and snippets.

@YenTheFirst
Created September 22, 2011 00:43
Show Gist options
  • Save YenTheFirst/1233752 to your computer and use it in GitHub Desktop.
Save YenTheFirst/1233752 to your computer and use it in GitHub Desktop.
Selective Coloring
require 'chunky_png'
module ChunkyPNG::Color
LUMA_WEIGHTS = [0.30, 0.59, 0.11]
#based on http://en.wikipedia.org/wiki/HSL_and_HSV
def self.to_hcy_floats(i) #creates hue, chroma, luma tuple
r,g,b = to_truecolor_bytes(i).map {|x| x/255.0}
minx,maxx = [r,g,b].minmax
chroma = maxx-minx
hue = if chroma == 0
0
else
case maxx
when r
((g-b)/chroma) % 6
when g
(b-r)/chroma + 2
when b
(r-g)/chroma + 4
end * 60
end
luma = [r,g,b].zip(LUMA_WEIGHTS).map {|x,w| x*w}.inject(&:+)
[hue,chroma,luma]
end
def self.hcy(hue,chroma,luma)
segment = hue / 60
h2 = (1 - ((segment % 2) - 1).abs) #h2 is the portion of hue from the second-largest component. it gives us the distance from the 'max' component, along a hexagon edge, to the actual hue angle. is a float in 0..1 range.
rgb1 = [
[1,h2,0],
[h2,1,0],
[0,1,h2],
[0,h2,1],
[h2,0,1],
[1,0,h2]
][segment.floor].map {|x| chroma*x }
m = luma - rgb1.zip(LUMA_WEIGHTS).map {|x,w| x*w}.inject(&:+)
r,g,b = rgb1.map {|x| (x+m)}.map {|x| (x*255).to_i}
rgb(r,g,b)
end
end
if __FILE__ == $0 #unless we're being loaded as a library
#TODO: get chunks and prompt
colors = [0,36,75,205,240]
tolerance = 19
colors.each_with_index do |color,i|
image = ChunkyPNG::Image.from_file("input.png")
image.pixels.map! do |p| h,c,y = ChunkyPNG::Color.to_hcy_floats(p)
if (h-color).abs < tolerance || (h-color+360).abs < tolerance
p
else
ChunkyPNG::Color.hcy(h,0,y)
end
end
image.save("output_#{i+1}.png")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment