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:
parent
b2354a9836
commit
0ee744bab2
2 changed files with 98 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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}")
|
||||
|
|
Loading…
Add table
Reference in a new issue