1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

[Sass] Support conversion from RGB to HSL.

This commit is contained in:
Nathan Weizenbaum 2009-11-26 16:05:17 -08:00
parent b2354a9836
commit 0ee744bab2
2 changed files with 98 additions and 19 deletions

View file

@ -80,6 +80,7 @@ module Sass::Script
end
@attrs = attrs
@attrs[:hue] %= 360 if @attrs[:hue]
@attrs[:alpha] ||= 1
end
@ -122,6 +123,30 @@ module Sass::Script
@attrs[:blue]
end
# The hue component of the color.
#
# @return [Numeric]
def hue
rgb_to_hsl!
@attrs[:hue]
end
# The saturation component of the color.
#
# @return [Numeric]
def saturation
rgb_to_hsl!
@attrs[:saturation]
end
# The lightness component of the color.
#
# @return [Numeric]
def lightness
rgb_to_hsl!
@attrs[:lightness]
end
# The alpha channel (opacity) of the color.
# This is 1 unless otherwise defined.
#
@ -316,23 +341,6 @@ END
private
def hsl_to_rgb!
return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
h = (@attrs[:hue] % 360) / 360.0
s = @attrs[:saturation] / 100.0
l = @attrs[:lightness] / 100.0
# Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
m1 = l * 2 - m2
@attrs[:red], @attrs[:green], @attrs[:blue] = [
hue_to_rgb(m1, m2, h + 1.0/3),
hue_to_rgb(m1, m2, h),
hue_to_rgb(m1, m2, h - 1.0/3)
].map {|c| (c * 0xff).round}
end
def piecewise(other, operation)
other_num = other.is_a? Number
if other_num && !other.unitless?
@ -352,6 +360,23 @@ END
with(:red => result[0], :green => result[1], :blue => result[2])
end
def hsl_to_rgb!
return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
h = @attrs[:hue] / 360.0
s = @attrs[:saturation] / 100.0
l = @attrs[:lightness] / 100.0
# Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
m1 = l * 2 - m2
@attrs[:red], @attrs[:green], @attrs[:blue] = [
hue_to_rgb(m1, m2, h + 1.0/3),
hue_to_rgb(m1, m2, h),
hue_to_rgb(m1, m2, h - 1.0/3)
].map {|c| (c * 0xff).round}
end
def hue_to_rgb(m1, m2, h)
h += 1 if h < 0
h -= 1 if h > 1
@ -360,5 +385,38 @@ END
return m1 + (m2 - m1) * (2.0/3 - h) * 6 if h * 3 < 2
return m1
end
def rgb_to_hsl!
return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
# Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
max = [r, g, b].max
min = [r, g, b].min
d = max - min
h =
case max
when min; 0
when r; 60 * (g-b)/d
when g; 60 * (b-r)/d + 120
when b; 60 * (r-g)/d + 240
end
l = (max + min)/2.0
s =
if max == min
0
elsif l < 0.5
d/(2*l)
else
d/(2 - 2*l)
end
@attrs[:hue] = h % 360
@attrs[:saturation] = s * 100
@attrs[:lightness] = l * 100
end
end
end

View file

@ -9,10 +9,27 @@ class SassFunctionTest < Test::Unit::TestCase
File.read(File.dirname(__FILE__) + "/data/hsl-rgb.txt").split("\n\n").each do |chunk|
hsls, rgbs = chunk.strip.split("====")
hsls.strip.split("\n").zip(rgbs.strip.split("\n")) do |hsl, rgb|
method = "test_hsl: #{hsl} = #{rgb}"
define_method(method) do
hsl_method = "test_hsl: #{hsl} = #{rgb}"
define_method(hsl_method) do
assert_equal(evaluate(rgb), evaluate(hsl))
end
rgb_to_hsl_method = "test_rgb_to_hsl: #{rgb} = #{hsl}"
define_method(rgb_to_hsl_method) do
rgb_color = perform(rgb)
hsl_color = perform(hsl)
white = hsl_color.lightness == 100
black = hsl_color.lightness == 0
grayscale = white || black || hsl_color.saturation == 0
assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001,
"Hues should be equal") unless grayscale
assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001,
"Saturations should be equal") unless white || black
assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001,
"Lightnesses should be equal")
end
end
end
@ -243,6 +260,10 @@ class SassFunctionTest < Test::Unit::TestCase
Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new).to_s
end
def perform(value)
Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new)
end
def assert_error_message(message, value)
evaluate(value)
flunk("Error message expected but not raised: #{message}")