24-bit Color Gradients (for TinyMUX)

Submitted by Kyrion on Sat, 2012-07-28 23:42

It’s sure been a while, hasn’t it. I’ve still been working on my existing MUSH and my new one, when I’ve been able, and have some useful gadgets done, but not much building yet. That’s not what I’m about to post, though.

I’ve chatted about this on <Softcode>, and the suggestion I got was to post it here. I wrote this code for TinyMUX, which unlike Penn will display the full 24-bit color space, and was reminded how useful the PennMUSH features are that TinyMUX doesn’t support. As you may recall, my previous project implemented most Tiny* functions missing from Penn in softcode, so that’s less true the other way around.

It will not run on PennMUSH as written, but could be converted to run with the same logic. The major incompatibilities are the @@ final argument to iter() and, especially, the extra backslashes Tiny* forces me to use thorough its illogical, broken-as-designed parsing of nested arguments.

Code and commentary below the cut.

Usage is:
u(gradient,text,left foreground[/left background],right foreground[/right background][, color space])

The code supports the color formats <r g b>, <#xxxxxx> and #xxxxxx. It will mark up text in a color gradient between the two foreground colors you give; if you also specify background colors, it will create a second gradient in the background as well. The color space can be lch_uv/lchuv/lch (the default), luv, lch_ab/lchab/lch_ab, or lab.

Because this function is computationally expensive, you will normally want to call it once, and save the results verbatim with something like translate() rather than recalculating it with the same arguments.

The final version uses the LCHuv color space by default, but allows you to select Luv, Lab, LCHuv or LCHab. This was primarily so that the server’s conversion from millions to hundreds of colors, which apparently uses HSV, would work seamlessly. I learned a lot about color spaces from this project! My first implementation used linear paths in the R,G,B cube. It produced some very ugly gradients, with poor perceptual uniformity. My second converted to spherical coordinates and generated paths as arcs, approximating brightness as distance from the origin. It had two serious problems: that this isn’t really a good approximation of apparent brightness, and that the server used a totally different color space for mapping to fewer colors, so it broke hard whenever you viewed it with the HTML flag off. My third, preliminary to this, used the LAB color space. This solved the first problem, but not the second.

This version does a better job producing gradients that are perceptually uniform and degrade elegantly down to 256 colors on TinyMUX. There are still some quirks, though. One is that the algorithm will sometimes generate imaginary colors and map them back into RGB badly. This particularly happens if you combine a dark primary color, such as blue, with a brighter complementary color. The algorithm will try to come up with a color that’s the same hue as pure blue but brighter, and since no such color exists, you’ll end up with a shade of magenta. You can often get better results by matching a color slightly off from pure black, white or grey: the gradient from <0 0 255> to <0 0 1> or <254 254 255> works better than for a balanced color such as <0 0 0> or <255 255 255>.

It also turned out to be tricky to make the gradients traverse the color wheel in the right direction, for instance blue-cyan-green instead of blue-violet-red-orange-yellow-green. This is essentially an artifact of whether we represent the h parameter of the color space, representing an angle on the color wheel, with a number between π and 2π or between -π and 0. I ended up eyeballing a number of test cases and switching from one to the other where it would be better to transition from blue through green than through red. In this color space, simply taking the shorter way around is not sufficient. This does introduce a discontinuity in the gradients in which subtracting a bit of green or adding a bit of red to a blue-brown transition might give you a gradient with magenta instead of cyan in the middle.

Without further ado, the code:


@@ TinyMUX Gradients, version 1.1.0
@@ Copyright © 2012 Ton Kyrion (Pseudonym). All rights reserved.
@@
@@ I hereby release this code under the MIT license:
@@
@@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
@@ and associated documentation files (the "Software"), to deal in the Software without restriction,
@@ including without limitation the rights to use, copy, modify, merge, publish, distribute,
@@ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
@@ furnished to do so, subject to the following conditions:
@@
@@ The above copyright notice and this permission notice shall be included in all copies or
@@ substantial portions of the Software.
@@
@@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
@@ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
@@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
@@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@
@@ -------------------------------------------------------------------------------------------------
@@
@create Search Function Object=10
&GRADIENT Search Function Object=case(secure(%3),,u(gradient_lch_uv,%0,%1,%2),luv,u(gradient_luv,%0,%1,%2),lch,u(gradient_lch_uv,%0,%1,%2),lch_uv,u(gradient_lch_uv,%0,%1,%2),lchuv,u(gradient_lch_uv,%0,%1,%2),lab,u(gradient_lab,%0,%1,%2),lch_ab,u(gradient_lch_ab,%0,%1,%2),,lchab,u(gradient_lch_ab,%0,%1,%2)#-1 Unsupported Color Space)

&GRADIENT_LUV Search Function Object=localize([case(1,regmatch(secure(%1),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(w,u(f_rgb2luv,%qr %qg %qb))][case(1,regmatch(secure(%2),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(z,u(f_rgb2luv,%qr %qg %qb))],regmatch(secure(%2),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(z,u(f_rgb2luv,%qr %qg %qb))],setq(z,%qw))][ifelse(regmatch(secure(%1),.+/.+),[case(1,regmatch(secure(%1),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(x,u(f_rgb2luv,%qr %qg %qb))][case(1,regmatch(secure(%2),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(y,u(f_rgb2lch_ab,%qr %qg %qb))],regmatch(secure(%2),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(y,u(f_rgb2luv,%qr %qg %qb))],setq(y,%qx))][iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_luv2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>/<[u(f_luv2rgb,u(f_gradientstep3,%qx,%qy,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@)],iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_luv2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@))])

&GRADIENT_LCH_AB Search Function Object=localize([case(1,regmatch(secure(%1),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(w,u(f_rgb2lch_ab,%qr %qg %qb))][case(1,regmatch(secure(%2),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(z,u(f_rgb2lch_ab,%qr %qg %qb))],regmatch(secure(%2),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(z,u(f_rgb2lch_ab,%qr %qg %qb))],setq(z,%qw))][setq(a,extract(%qw,3,1))][setq(b,extract(%qz,3,1))][setq(m,extract(%qw,2,1))][setq(n,extract(%qz,2,1))][if(lt(abs(%qm),0.1),[setq(w,replace(%qw,3,%qb))][setq(a,%qb)])][if(lt(%qn,0.1),[setq(z,replace(%qz,3,%qa))][setq(b,%qa)])][case(1,andbool(gte(%qa,mul(0.375,pi())),lte(%qb,fdiv(pi(),-6))),setq(z,replace(%qz,3,add(%qb,mul(2,pi())))),andbool(gte(%qb,mul(0.375,pi())),lte(%qa,fdiv(pi(),-6))),setq(w,replace(%qw,3,add(%qa,mul(2,pi())))),gt(sub(%qb,%qa),pi()),setq(w,replace(%qw,3,add(%qa,mul(2,pi())))),gt(sub(%qa,%qb),pi()),setq(z,replace(%qz,3,add(%qb,mul(2,pi())))))][ifelse(regmatch(secure(%1),.+/.+),[case(1,regmatch(secure(%1),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(x,u(f_rgb2lch_ab,%qr %qg %qb))][case(1,regmatch(secure(%2),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(y,u(f_rgb2lch_ab,%qr %qg %qb))],regmatch(secure(%2),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(y,u(f_rgb2lch_ab,%qr %qg %qb))],setq(y,%qx))][setq(a,extract(%qx,3,1))][setq(b,extract(%qy,3,1))][setq(m,extract(%qx,2,1))][setq(n,extract(%qy,2,1))][if(lt(abs(%qm),0.1),[setq(x,replace(%qx,3,%qb))][setq(a,%qb)])][if(lt(%qn,0.1),[setq(y,replace(%qy,3,%qa))][setq(b,%qa)])][case(1,andbool(gte(%qa,mul(0.375,pi())),lte(%qb,fdiv(pi(),-6))),setq(y,replace(%qy,3,add(%qb,mul(2,pi())))),andbool(gte(%qb,mul(0.375,pi())),lte(%qa,fdiv(pi(),-6))),setq(x,replace(%qx,3,add(%qa,mul(2,pi())))),gt(sub(%qb,%qa),pi()),setq(x,replace(%qx,3,add(%qa,mul(2,pi())))),gt(sub(%qa,%qb),pi()),setq(y,replace(%qy,3,add(%qb,mul(2,pi())))))][iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lch_ab2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>/<[u(f_lch_ab2rgb,u(f_gradientstep3,%qx,%qy,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@)],iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lch_ab2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@))])

&GRADIENT_LAB Search Function Object=localize([case(1,regmatch(secure(%1),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(w,u(f_rgb2lab,%qr %qg %qb))][case(1,regmatch(secure(%2),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(z,u(f_rgb2lab,%qr %qg %qb))],regmatch(secure(%2),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(z,u(f_rgb2lab,%qr %qg %qb))],setq(z,%qw))][setq(a,extract(%qw,3,1))][setq(b,extract(%qz,3,1))][ifelse(regmatch(secure(%1),.+/.+),[case(1,regmatch(secure(%1),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(x,u(f_rgb2lch_ab,%qr %qg %qb))][case(1,regmatch(secure(%2),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(y,u(f_rgb2lab,%qr %qg %qb))],regmatch(secure(%2),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(y,u(f_rgb2lab,%qr %qg %qb))],setq(y,%qx))][iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lab2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>/<[u(f_lab2rgb,u(f_gradientstep3,%qx,%qy,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@)],iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lab2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@))])

&GRADIENT_LCH_UV Search Function Object=localize([case(1,regmatch(secure(%1),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(w,u(f_rgb2lch_uv,%qr %qg %qb))][case(1,regmatch(secure(%2),^<?#\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)\(\\\\\[a-zA-Z0-9\\\\\]\\\\\{2\\\\\}\)>?(/|$),-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(z,u(f_rgb2lch_uv,%qr %qg %qb))],regmatch(secure(%2),^<(\\\\\\\\d+) (\\\\\\\\d+) (\\\\\\\\d+)>(/|$),-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(z,u(f_rgb2lch_uv,%qr %qg %qb))],setq(z,%qw))][setq(a,extract(%qw,3,1))][setq(b,extract(%qz,3,1))][setq(m,extract(%qw,2,1))][setq(n,extract(%qz,2,1))][if(lt(abs(%qm),0.1),[setq(w,replace(%qw,3,%qb))][setq(a,%qb)])][if(lt(%qn,0.1),[setq(z,replace(%qz,3,%qa))][setq(b,%qa)])][case(1,gt(sub(%qb,%qa),pi()),setq(w,replace(%qw,3,add(%qa,mul(2,pi())))),gt(sub(%qa,%qb),pi()),setq(z,replace(%qz,3,add(%qb,mul(2,pi())))))][ifelse(regmatch(secure(%1),.+/.+),[case(1,regmatch(secure(%1),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))],regmatch(secure(%1),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))])][setq(x,u(f_rgb2lch_uv,%qr %qg %qb))][case(1,regmatch(secure(%2),/<?#\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)\(\\\\\\\\\[a-zA-Z0-9\\\\\\\\\]\\\\\\\\\{2\\\\\\\\\}\)>?$,-1 r g b),[setq(r,baseconv(lcstr(%qr),16,10))][setq(g,baseconv(lcstr(%qg),16,10))][setq(b,baseconv(lcstr(%qb),16,10))][setq(y,u(f_rgb2lch_uv,%qr %qg %qb))],regmatch(secure(%2),/<(\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+) (\\\\\\\\\\\\\\\\d+)>$,-1 r g b),[setq(r,min(%qr,255))][setq(g,min(%qg,255))][setq(b,min(%qb,255))][setq(y,u(f_rgb2lch_uv,%qr %qg %qb))],setq(y,%qx))][setq(a,extract(%qx,3,1))][setq(b,extract(%qy,3,1))][setq(m,extract(%qx,2,1))][setq(n,extract(%qy,2,1))][if(lt(abs(%qm),0.1),[setq(x,replace(%qx,3,%qb))][setq(a,%qb)])][if(lt(%qn,0.1),[setq(y,replace(%qy,3,%qa))][setq(b,%qa)])][case(1,gt(sub(%qb,%qa),pi()),setq(x,replace(%qx,3,add(%qa,mul(2,pi())))),gt(sub(%qa,%qb),pi()),setq(y,replace(%qy,3,add(%qb,mul(2,pi())))))][iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lch_uv2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>/<[u(f_lch_uv2rgb,u(f_gradientstep3,%qx,%qy,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@)],iter(lnum(setr(L,strlen(%0))),ansi(<[u(f_lch_uv2rgb,u(f_gradientstep3,%qw,%qz,%i0,%qL))]>,mid(%0,%i0,1)),%b,@@))])

&F_LAB2RGB Search Function Object=localize([setq(0,secure(%0))][setq(L,extract(%q0,1,1))][setq(a,extract(%q0,2,1))][setq(b,extract(%q0,3,1))][setq(v,fdiv(add(%qL,16),116))][setq(u,add(fdiv(%qa,500),%qv))][setq(w,sub(%qv,fdiv(%qb,200)))][setq(x,ifelse(gt(%qu,0.20689655172413793),power(%qu,3),fdiv(sub(mul(116,%qu),16),903.2962962962963)))][setq(y,ifelse(gt(%qL,8),power(fdiv(add(%qL,16),116),3),fdiv(%qL,903.2962962962963)))][setq(z,ifelse(gt(%qw,0.20689655172413793),power(%qw,3),fdiv(sub(mul(116,%qw),16),903.2962962962963)))][setq(x,fdiv(%qx,3))][setq(y,fdiv(%qy,3))][setq(z,fdiv(%qz,3))][setq(r,add(mul(%qx,2.3706743),mul(%qy,-0.9000405),mul(%qz,-0.4706338)))][setq(g,add(mul(%qx,-0.5138850),mul(%qy,1.4253036),mul(%qz,0.0885814)))][setq(b,add(mul(%qx,0.0052982),mul(%qy,-0.0146949),mul(%qz,1.0093968)))][setq(r,ifelse(lte(%qr,0.008856451679035631),mul(%qr,9.032962962962963),sub(mul(1.16,power(%qr,0.3333333333333333)),0.16)))][setq(g,ifelse(lte(%qg,0.008856451679035631),mul(%qg,9.032962962962963),sub(mul(1.16,power(%qg,0.3333333333333333)),0.16)))][setq(b,ifelse(lte(%qb,0.008856451679035631),mul(%qb,9.032962962962963),sub(mul(1.16,power(%qb,0.3333333333333333)),0.16)))][iter(%qr %qg %qb,max(min(round(mul(%i0,255),0),255),0))])

&F_LCH_AB2RGB Search Function Object=localize([setq(0,secure(%0))][setq(L,extract(%q0,1,1))][setq(c,extract(%q0,2,1))][setq(h,extract(%q0,3,1))][setq(a,mul(%qc,cos(%qh)))][setq(b,mul(%qc,sin(%qh)))][setq(v,fdiv(add(%qL,16),116))][setq(u,add(fdiv(%qa,500),%qv))][setq(w,sub(%qv,fdiv(%qb,200)))][setq(x,ifelse(gt(%qu,0.20689655172413793),power(%qu,3),fdiv(sub(mul(116,%qu),16),903.2962962962963)))][setq(y,ifelse(gt(%qL,8),power(fdiv(add(%qL,16),116),3),fdiv(%qL,903.2962962962963)))][setq(z,ifelse(gt(%qw,0.20689655172413793),power(%qw,3),fdiv(sub(mul(116,%qw),16),903.2962962962963)))][setq(x,fdiv(%qx,3))][setq(y,fdiv(%qy,3))][setq(z,fdiv(%qz,3))][setq(r,add(mul(%qx,2.3706743),mul(%qy,-0.9000405),mul(%qz,-0.4706338)))][setq(g,add(mul(%qx,-0.5138850),mul(%qy,1.4253036),mul(%qz,0.0885814)))][setq(b,add(mul(%qx,0.0052982),mul(%qy,-0.0146949),mul(%qz,1.0093968)))][setq(r,ifelse(lte(%qr,0.008856451679035631),mul(%qr,9.032962962962963),sub(mul(1.16,power(%qr,0.3333333333333333)),0.16)))][setq(g,ifelse(lte(%qg,0.008856451679035631),mul(%qg,9.032962962962963),sub(mul(1.16,power(%qg,0.3333333333333333)),0.16)))][setq(b,ifelse(lte(%qb,0.008856451679035631),mul(%qb,9.032962962962963),sub(mul(1.16,power(%qb,0.3333333333333333)),0.16)))][iter(%qr %qg %qb,max(min(round(mul(%i0,255),0),255),0))])

&F_LUV2RGB Search Function Object=localize([setq(0,secure(%0))][setq(L,extract(%q0,1,1))][setq(u,extract(%q0,2,1))][setq(v,extract(%q0,3,1))][setq(y,ifelse(gt(%qL,8),power(fdiv(add(%qL,16),116),3),fdiv(%qL,903.2962962962963)))][setq(a,fdiv(sub(fdiv(mul(52,%qL),add(%qu,mul(13,%qL,0.21052631578947367))),1),3))][setq(b,mul(-5,%qy))][setq(c,fdiv(-1,3))][setq(d,mul(%qy,sub(fdiv(mul(39,%qL),add(%qv,mul(13,%qL,0.47368421052631576))),5)))][setq(x,fdiv(sub(%qd,%qb),sub(%qa,%qc)))][setq(z,add(mul(%qx,%qa),%qb))][setq(x,fdiv(%qx,3))][setq(y,fdiv(%qy,3))][setq(z,fdiv(%qz,3))][setq(r,add(mul(%qx,2.3706743),mul(%qy,-0.9000405),mul(%qz,-0.4706338)))][setq(g,add(mul(%qx,-0.5138850),mul(%qy,1.4253036),mul(%qz,0.0885814)))][setq(b,add(mul(%qx,0.0052982),mul(%qy,-0.0146949),mul(%qz,1.0093968)))][setq(r,ifelse(lte(%qr,0.008856451679035631),mul(%qr,9.032962962962963),sub(mul(1.16,power(%qr,0.3333333333333333)),0.16)))][setq(g,ifelse(lte(%qg,0.008856451679035631),mul(%qg,9.032962962962963),sub(mul(1.16,power(%qg,0.3333333333333333)),0.16)))][setq(b,ifelse(lte(%qb,0.008856451679035631),mul(%qb,9.032962962962963),sub(mul(1.16,power(%qb,0.3333333333333333)),0.16)))][iter(%qr %qg %qb,max(min(round(mul(%i0,255),0),255),0))])

&F_LCH_UV2RGB Search Function Object=localize([setq(0,secure(%0))][setq(L,extract(%q0,1,1))][setq(c,extract(%q0,2,1))][setq(h,extract(%q0,3,1))][setq(u,mul(%qc,cos(%qh)))][setq(v,mul(%qc,sin(%qh)))][setq(y,ifelse(gt(%qL,8),power(fdiv(add(%qL,16),116),3),fdiv(%qL,903.2962962962963)))][setq(a,fdiv(sub(fdiv(mul(52,%qL),add(%qu,mul(13,%qL,0.21052631578947367))),1),3))][setq(b,mul(-5,%qy))][setq(c,fdiv(-1,3))][setq(d,mul(%qy,sub(fdiv(mul(39,%qL),add(%qv,mul(13,%qL,0.47368421052631576))),5)))][setq(x,fdiv(sub(%qd,%qb),sub(%qa,%qc)))][setq(z,add(mul(%qx,%qa),%qb))][setq(x,fdiv(%qx,3))][setq(y,fdiv(%qy,3))][setq(z,fdiv(%qz,3))][setq(r,add(mul(%qx,2.3706743),mul(%qy,-0.9000405),mul(%qz,-0.4706338)))][setq(g,add(mul(%qx,-0.5138850),mul(%qy,1.4253036),mul(%qz,0.0885814)))][setq(b,add(mul(%qx,0.0052982),mul(%qy,-0.0146949),mul(%qz,1.0093968)))][setq(r,ifelse(lte(%qr,0.008856451679035631),mul(%qr,9.032962962962963),sub(mul(1.16,power(%qr,0.3333333333333333)),0.16)))][setq(g,ifelse(lte(%qg,0.008856451679035631),mul(%qg,9.032962962962963),sub(mul(1.16,power(%qg,0.3333333333333333)),0.16)))][setq(b,ifelse(lte(%qb,0.008856451679035631),mul(%qb,9.032962962962963),sub(mul(1.16,power(%qb,0.3333333333333333)),0.16)))][iter(%qr %qg %qb,max(min(round(mul(%i0,255),0),255),0))])

&F_RGB2LAB Search Function Object=localize([setq(0,iter(secure(%0),fdiv(%i0,255)))][setq(0,iter(%q0,ifelse(lte(%i0,0.08),fdiv(%i0,9.032962962962963),power(fdiv(add(%i0,0.16),1.16),3))))][setq(r,extract(%q0,1,1))][setq(g,extract(%q0,2,1))][setq(b,extract(%q0,3,1))][setq(x,add(mul(%qr,0.4887180),mul(%qg,0.3106803),mul(%qb,0.2006017)))][setq(y,add(mul(%qr,0.1762044),mul(%qg,0.8129847),mul(%qb,0.0108109)))][setq(z,add(mul(%qg,0.0102048),mul(%qb,0.9897952)))][setq(u,mul(3,%qx))][setq(v,mul(3,%qy))][setq(w,mul(3,%qz))][setq(u,ifelse(gt(%qu,0.008856451679035631),power(%qu,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qu),16),116)))][setq(v,ifelse(gt(%qv,0.008856451679035631),power(%qv,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qv),16),116)))][setq(w,ifelse(gt(%qw,0.008856451679035631),power(%qw,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qw),16),116)))][sub(mul(116,%qv),16)] [mul(500,sub(%qu,%qv))] [mul(200,sub(%qv,%qw))])

&F_RGB2LCH_AB Search Function Object=localize([setq(0,iter(secure(%0),fdiv(%i0,255)))][setq(0,iter(%q0,ifelse(lte(%i0,0.08),fdiv(%i0,9.032962962962963),power(fdiv(add(%i0,0.16),1.16),3))))][setq(r,extract(%q0,1,1))][setq(g,extract(%q0,2,1))][setq(b,extract(%q0,3,1))][setq(x,add(mul(%qr,0.4887180),mul(%qg,0.3106803),mul(%qb,0.2006017)))][setq(y,add(mul(%qr,0.1762044),mul(%qg,0.8129847),mul(%qb,0.0108109)))][setq(z,add(mul(%qg,0.0102048),mul(%qb,0.9897952)))][setq(u,mul(3,%qx))][setq(v,mul(3,%qy))][setq(w,mul(3,%qz))][setq(u,ifelse(gt(%qu,0.008856451679035631),power(%qu,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qu),16),116)))][setq(v,ifelse(gt(%qv,0.008856451679035631),power(%qv,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qv),16),116)))][setq(w,ifelse(gt(%qw,0.008856451679035631),power(%qw,0.3333333333333333),fdiv(add(mul(903.2962962962963,%qw),16),116)))][setq(L,sub(mul(116,%qv),16))][setq(a,mul(500,sub(%qu,%qv)))][setq(b,mul(200,sub(%qv,%qw)))]%qL [sqrt(add(power(%qa,2),power(%qb,2)))] [atan2(%qb,%qa)])

&F_RGB2LUV Search Function Object=localize([setq(0,iter(secure(%0),fdiv(%i0,255)))][setq(0,iter(%q0,ifelse(lte(%i0,0.08),fdiv(%i0,9.032962962962963),power(fdiv(add(%i0,0.16),1.16),3))))][setq(r,extract(%q0,1,1))][setq(g,extract(%q0,2,1))][setq(b,extract(%q0,3,1))][setq(x,add(mul(%qr,0.4887180),mul(%qg,0.3106803),mul(%qb,0.2006017)))][setq(y,add(mul(%qr,0.1762044),mul(%qg,0.8129847),mul(%qb,0.0108109)))][setq(z,add(mul(%qg,0.0102048),mul(%qb,0.9897952)))][setq(L,ifelse(gt(%qy,0.0029521505596785437),sub(mul(116,power(mul(%qy,3),0.3333333333333333)),16),mul(%qy,2709.888888888889)))][setq(u,fdiv(mul(4,%qx),add(%qx,mul(15,%qy),mul(3,%qz))))][setq(u,mul(13,%qL,sub(%qu,0.21052631578947367)))][setq(v,fdiv(mul(9,%qy),add(%qx,mul(15,%qy),mul(3,%qz))))][setq(v,mul(13,%qL,sub(%qv,0.47368421052631576)))]%qL %qu %qv)

&F_RGB2LCH_UV Search Function Object=localize([setq(0,iter(secure(%0),fdiv(%i0,255)))][setq(0,iter(%q0,ifelse(lte(%i0,0.08),fdiv(%i0,9.032962962962963),power(fdiv(add(%i0,0.16),1.16),3))))][setq(r,extract(%q0,1,1))][setq(g,extract(%q0,2,1))][setq(b,extract(%q0,3,1))][setq(x,add(mul(%qr,0.4887180),mul(%qg,0.3106803),mul(%qb,0.2006017)))][setq(y,add(mul(%qr,0.1762044),mul(%qg,0.8129847),mul(%qb,0.0108109)))][setq(z,add(mul(%qg,0.0102048),mul(%qb,0.9897952)))][setq(L,ifelse(gt(%qy,0.0029521505596785437),sub(mul(116,power(mul(%qy,3),0.3333333333333333)),16),mul(%qy,2709.888888888889)))][setq(u,fdiv(mul(4,%qx),add(%qx,mul(15,%qy),mul(3,%qz))))][setq(u,mul(13,%qL,sub(%qu,0.21052631578947367)))][setq(v,fdiv(mul(9,%qy),add(%qx,mul(15,%qy),mul(3,%qz))))][setq(v,mul(13,%qL,sub(%qv,0.47368421052631576)))]%qL [sqrt(add(power(%qu,2),power(%qv,2)))] [atan2(%qv,%qu)])

&F_GRADIENTSTEP3 Search Function Object=localize([setq(0,secure(%0))][setq(1,secure(%1))][setq(i,secure(%2))][setq(n,dec(secure(%3)))][setq(a,extract(%q0,1,1))][setq(b,extract(%q0,2,1))][setq(c,extract(%q0,3,1))][setq(x,extract(%q1,1,1))][setq(y,extract(%q1,2,1))][setq(z,extract(%q1,3,1))][add(%qa,mul(%qi,fdiv(sub(%qx,%qa),%qn)))] [add(%qb,mul(%qi,fdiv(sub(%qy,%qb),%qn)))] [add(%qc,mul(%qi,fdiv(sub(%qz,%qc),%qn)))])