Suppose I'm writing a function that takes a color as a parameter; for example:
drawShape[color_] := Graphics[{Style[Disk[], color]}];
But if the caller inputs an invalid color, bad things happen:
So I want to use a pattern to define drawShape
only for values that are actually colors. Conceptually,
drawShape[color_Color] := ...
The problem is that unlike (say) List
s, Integer
s, Real
s, Complex
es, or Graphics
es, color objects do not share a Color
head. That is,
In[1]:= Red // Head
Out[1]= RGBColor
In[2]:= Hue[0.5] // Head
Out[2]= Hue
In[3]:= GrayLevel[0.5] // Head
Out[3]= GrayLevel
In[4]:= CMYKColor[0, 1, 1, 1/2] // Head
Out[4]= CMYKColor
In[4]:= Opacity[0.5, Purple] // Head
Out[4]= Opacity
In[5]:= Transparent // Head
Out[5]= GrayLevel
So that won't work. I also don't see any ColorQ
function, with which I could write drawShape[color_ ? ColorQ] := ...
.
How can I write a pattern that matches any valid color object? Is there a more robust way than just testing for each of these heads?
Answer
Original method
colorQ = Quiet @ Check[Blend @ {#, Red}; True, False] &;
colorQ /@ {Red, Hue[0.5], GrayLevel[0.5], CMYKColor[0, 1, 1, 1/2], Opacity[0.5, Purple]}
{True, True, True, True, True}
colorQ /@ {17, 1.3, Pi, "not a color", {1, 2, 3}, Hue["bad arg"]}
{False, False, False, False, False, False}
You would use: drawShape[color_?colorQ] := . . .
Inspired by kguler's comment this might also be formulated as:
colorQ = Quiet[Head @ Darker @ # =!= Darker] &;
Or:
colorQ = FreeQ[Quiet @ Darker @ #, Darker] &;
Edit: Darker
works on entire Image
and Graphics
objects and therefore the two forms immediately above will incorrectly return True
in these cases. Blend
solution is still valid.
Version 10 update and analysis
In version 10 there is a built-in function for this: ColorQ
ColorQ[color]
yields True if color is a valid color directive and False otherwise.
A bit of spelunking reveals that the inner definition of this function is (contexts stripped for clarity):
iColorQ[args_?(ColorDirectiveQ[Head[#1[[1]]]] &), opts_] :=
NumberQ[Quiet[ToColor[args[[1]], XYZColor][[1]]]]
This is very similar to my own method, however the inner definition of ColorDirectiveQ
omits Opacity
:
iColorDirectiveQ[args_, opts_] :=
TrueQ[Quiet[
MatchQ[args[[1]],
GrayLevel | RGBColor | CMYKColor | Hue | XYZColor | LUVColor | LABColor | LCHColor]]]
This means that the function will return False
for e.g. Opacity[0.5, Purple]
where mine returns True
.
Comments
Post a Comment