farver/0000755000176200001440000000000013610063667011547 5ustar liggesusersfarver/NAMESPACE0000644000176200001440000000046113607317435012770 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(add_to_channel) export(as_white_ref) export(cap_channel) export(compare_colour) export(convert_colour) export(decode_colour) export(encode_colour) export(get_channel) export(multiply_channel) export(raise_channel) export(set_channel) useDynLib(farver) farver/LICENSE.note0000644000176200001440000000245013562215674013524 0ustar liggesusersThis package contains the C++ library ColorSpace developed by Berendea Nicholae and released under the MIT license. The full license for this is reproduced below. ________________________________________________________________________________ MIT License Copyright (c) 2017 Berendea Nicolae 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. farver/LICENSE0000644000176200001440000000006113562215674012554 0ustar liggesusersYEAR: 2018 COPYRIGHT HOLDER: Thomas Lin Pedersen farver/README.md0000644000176200001440000001634613562774421013043 0ustar liggesusers # farver [![Travis-CI Build Status](https://travis-ci.org/thomasp85/farver.svg?branch=master)](https://travis-ci.org/thomasp85/farver) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/thomasp85/farver?branch=master&svg=true)](https://ci.appveyor.com/project/thomasp85/farver) [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version-ago/farver)](https://cran.r-project.org/package=farver) [![CRAN\_Download\_Badge](http://cranlogs.r-pkg.org/badges/farver)](https://cran.r-project.org/package=farver) [![Coverage Status](https://img.shields.io/codecov/c/github/thomasp85/farver/master.svg)](https://codecov.io/github/thomasp85/farver?branch=master) The goal of farver is to provide very fast, vectorised functions for conversion of colours between different colour spaces, colour comparisons (distance between colours), encoding/decoding, and channel manipulation in colour strings. To this end it provides an interface to a modified version of the [ColorSpace](https://github.com/berendeanicolae/ColorSpace) C++ library developed by Berendea Nicolae. ## Installation farver can be installed from CRAN using `install.packages('farver')`. The development version can be installed from Github using `devtools`: ``` r # install.packages('devtools') devtools::install_github('thomasp85/farver') ``` ## Use farver provides an alternative to the `grDevices::rgb()` and `grDevices::col2rgb()` for encoding and decoding colours strings. The farver functions are superficially equivalent but provides a uniform output format, and the option to encode and decode directly from/to other colour spaces. ``` r library(farver) codes <- rainbow(10) codes #> [1] "#FF0000FF" "#FF9900FF" "#CCFF00FF" "#33FF00FF" "#00FF66FF" #> [6] "#00FFFFFF" "#0066FFFF" "#3300FFFF" "#CC00FFFF" "#FF0099FF" spectrum <- decode_colour(codes) spectrum #> r g b #> [1,] 255 0 0 #> [2,] 255 153 0 #> [3,] 204 255 0 #> [4,] 51 255 0 #> [5,] 0 255 102 #> [6,] 0 255 255 #> [7,] 0 102 255 #> [8,] 51 0 255 #> [9,] 204 0 255 #> [10,] 255 0 153 encode_colour(spectrum) #> [1] "#FF0000" "#FF9900" "#CCFF00" "#33FF00" "#00FF66" "#00FFFF" "#0066FF" #> [8] "#3300FF" "#CC00FF" "#FF0099" ``` It also provides an alternative to `grDevices::convertColor()` to switch between colours spaces. If the origin is a colour string it is possible to decode directly into the given colour space. Conversely, if the endpoint is a colour string it is also possible to encode directly from a given colour space. ``` r spectrum_lab <- convert_colour(spectrum, 'rgb', 'lab') spectrum_lab #> l a b #> [1,] 53.24079 80.09246 67.203197 #> [2,] 72.26072 30.16539 77.224482 #> [3,] 93.60533 -41.94504 90.274226 #> [4,] 88.07403 -83.10813 83.593379 #> [5,] 88.19634 -80.27943 57.926987 #> [6,] 91.11322 -48.08753 -14.131186 #> [7,] 47.90478 35.19678 -82.006104 #> [8,] 33.81896 79.70044 -105.279006 #> [9,] 51.90416 90.99470 -74.834222 #> [10,] 55.65103 86.52861 -9.719051 decode_colour(codes, to = 'lab') #> l a b #> [1,] 53.24079 80.09246 67.203197 #> [2,] 72.26072 30.16539 77.224482 #> [3,] 93.60533 -41.94504 90.274226 #> [4,] 88.07403 -83.10813 83.593379 #> [5,] 88.19634 -80.27943 57.926987 #> [6,] 91.11322 -48.08753 -14.131186 #> [7,] 47.90478 35.19678 -82.006104 #> [8,] 33.81896 79.70044 -105.279006 #> [9,] 51.90416 90.99470 -74.834222 #> [10,] 55.65103 86.52861 -9.719051 encode_colour(spectrum_lab, from = 'lab') #> [1] "#FF0000" "#FF9900" "#CCFF00" "#33FF00" "#00FF66" "#00FFFF" "#0066FF" #> [8] "#3300FF" "#CC00FF" "#FF0099" ``` If colours are given as strings, manipulation of channels will normally require decoding, conversion to the correct colour space, manipulation of the given channel, converting back to rgb and the encoding to string. farver provides a range of functions that allow you to change any channel in the supported spaces directly in colour strings: ``` r # Add a value to the channel add_to_channel(codes, channel = 'l', value = 1:10, space = 'lab') #> [1] "#FF0C03FF" "#FF9E0EFF" "#D5FF1CFF" "#48FF20FF" "#33FF74FF" #> [6] "#3CFFFFFF" "#3D77FFFF" "#5A25FFFF" "#E839FFFF" "#FF41B4FF" # Set a channel to a specific value set_channel(codes, 'alpha', c(0.3, 0.7)) #> [1] "#FF00004C" "#FF9900B2" "#CCFF004C" "#33FF00B2" "#00FF664C" #> [6] "#00FFFFB2" "#0066FF4C" "#3300FFB2" "#CC00FF4C" "#FF0099B2" # Limit a channel to a given value cap_channel(codes, 'r', 200) #> [1] "#C80000FF" "#C89900FF" "#C8FF00FF" "#33FF00FF" "#00FF66FF" #> [6] "#00FFFFFF" "#0066FFFF" "#3300FFFF" "#C800FFFF" "#C80099FF" ``` Lastly, farver also provides utilities for calculating the distance between colours, based on a range of different measures ``` r spectrum2 <- t(col2rgb(heat.colors(10))) compare_colour(spectrum, spectrum2, 'rgb', method = 'cie2000')[1:6, 1:6] #> [,1] [,2] [,3] [,4] [,5] [,6] #> [1,] 0.00000 1.95065 7.130898 15.53837 27.08237 39.88958 #> [2,] 29.50083 27.56585 22.402612 13.98117 2.41602 10.31341 #> [3,] 72.33606 70.32974 64.926436 55.98592 43.59987 30.24747 #> [4,] 85.84698 83.68842 77.854648 68.19997 55.06314 41.59064 #> [5,] 85.92110 83.79762 78.073545 68.67184 56.07682 43.42965 #> [6,] 70.95853 69.55274 65.907013 60.35739 53.72218 47.94387 ``` ## Supported colour spaces `farver` currently supports the following colour spaces: - CMY - CMYK - HSL - HSB - HSV - CIE L\*AB - Hunter LAB - LCH(ab) - LCH(uv) - LUV - RGB - XYZ - YXY ## Supported distance measures `farver` supports the following colour distance metrics - Euclidean - CIE1976 - CIE94 - CIE2000 - CMC ## White References `farver` allows you to set the white point for relative colour spaces, either based on a standard illuminant (A-F series supported) or by specifying chromaticity coordinates or tristimulus values directly ## Benchmark `farver` is faster than its `grDevices` counterpart but less so than it was at its first release, as the colour conversion in grDevices has been improved since. ``` r library(ggplot2) test <- matrix(runif(300000, min = 0, max = 255), ncol = 3) timing <- bench::mark( farver = convert_colour(test, 'rgb', 'lab'), grDevices = convertColor(test, 'sRGB', 'Lab', scale.in = 255), check = FALSE, min_iterations = 100 ) plot(timing, type = 'ridge') ``` ![](man/figures/README-unnamed-chunk-7-1.png) Still, if the start- and/or endpoint are colour strings the ability to decode and encode directly from/to any colour space will give a huge speed up. ``` r colour_strings <- colours() timing <- bench::mark( farver = decode_colour(colour_strings, to = 'lab'), grDevices = convertColor(t(col2rgb(colour_strings)), 'sRGB', 'Lab', scale.in = 255), check = FALSE, min_iterations = 100 ) plot(timing, type = 'ridge') ``` ![](man/figures/README-unnamed-chunk-8-1.png) ## Code of Conduct Please note that the ‘farver’ project is released with a [Contributor Code of Conduct](https://farver.data-imaginist.com/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. farver/man/0000755000176200001440000000000013562472166012326 5ustar liggesusersfarver/man/decode_colour.Rd0000644000176200001440000000606113607061751015420 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/decode.R \name{decode_colour} \alias{decode_colour} \title{Decode RGB hex-strings into colour values} \usage{ decode_colour(colour, alpha = FALSE, to = "rgb", white = "D65", na_value = NA) } \arguments{ \item{colour}{A character vector of hex-encoded values or a valid colour name as given in \code{\link[grDevices:colours]{grDevices::colours()}}.} \item{alpha}{If \code{TRUE} the alpha channel will be returned as well (scaled between 0 and 1). If no alpha channel exists in the colour it will be assumed 1. If \code{FALSE} any alpha channel is ignored.} \item{to}{The output colour space. Allowed values are: \code{"cmy"}, \code{"cmyk"}, \code{"hsl"}, \code{"hsb"}, \code{"hsv"}, \code{"lab"} (CIE L*ab), \code{"hunterlab"} (Hunter Lab), \code{"lch"} (CIE Lch(ab) / polarLAB), \code{"luv"}, \code{"rgb"} (sRGB), \code{"xyz"}, \code{"yxy"} (CIE xyY), or \code{"hcl"} (CIE Lch(uv) / polarLuv)} \item{white}{The white reference of the output colour space. Will only have an effect for relative colour spaces such as Lab and luv. Any value accepted by \code{\link[=as_white_ref]{as_white_ref()}} allowed.} \item{na_value}{A valid colour string or \code{NA} to use when \code{colour} contains \code{NA} elements. The general approach in farver is to carry \code{NA} values over, but if you want to mimick \code{\link[=col2rgb]{col2rgb()}} you should set \code{na_value = 'transparent'}, i.e. treat \code{NA} as transparent white.} } \value{ A numeric matrix with a row for each element in \code{colour} and either 3, 4, or 5 columns depending on the value of \code{alpha} and \code{to}. } \description{ This is a version of \code{\link[grDevices:col2rgb]{grDevices::col2rgb()}} that returns the colour values in the standard form expected by farver (matrix with a row per colour). As with \code{\link[=encode_colour]{encode_colour()}} it can do colour conversion on the fly, meaning that you can decode a hex string directly into any of the supported colour spaces. } \section{Handling of non-finite and out of bounds values}{ \code{NA}, \code{NaN}, \code{-Inf}, and \code{Inf} are treated as invalid input and will result in \code{NA} values for the colour. If a given colourspace has finite bounds in some of their channels, the input will be capped before conversion, and the output will be capped before returning, so that both input and output colours are valid colours in their respective space. This means that converting back and forth between two colourspaces may result in a change in the colour if the gamut of one of the spaces is less than the other. } \examples{ # basic use decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4')) # Return alpha as well (no alpha value is interpreted as 1) decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4'), alpha = TRUE) # Decode directly into specific colour space decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4'), to = 'lch') } \seealso{ Other encoding and decoding functions: \code{\link{encode_colour}()}, \code{\link{manip_channel}} } \concept{encoding and decoding functions} farver/man/farver-package.Rd0000644000176200001440000000250113607061751015463 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/farver-package.R \docType{package} \name{farver-package} \alias{farver} \alias{farver-package} \title{farver: High Performance Colour Space Manipulation} \description{ \if{html}{\figure{logo.png}{options: align='right' alt='logo' width='120'}} The encoding of colour can be handled in many different ways, using different colour spaces. As different colour spaces have different uses, efficient conversion between these representations are important. The 'farver' package provides a set of functions that gives access to very fast colour space conversion and comparisons implemented in C++, and offers speed improvements over the 'convertColor' function in the 'grDevices' package. } \seealso{ Useful links: \itemize{ \item \url{https://farver.data-imaginist.com} \item \url{https://github.com/thomasp85/farver} \item Report bugs at \url{https://github.com/thomasp85/farver/issues} } } \author{ \strong{Maintainer}: Thomas Lin Pedersen \email{thomasp85@gmail.com} (\href{https://orcid.org/0000-0002-5147-4711}{ORCID}) Authors: \itemize{ \item Berendea Nicolae (Author of the ColorSpace C++ library) \item Romain François \email{romain@purrple.cat} (\href{https://orcid.org/0000-0002-2444-4226}{ORCID}) } } \keyword{internal} farver/man/encode_colour.Rd0000644000176200001440000000531013607061751015426 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/encode.R \name{encode_colour} \alias{encode_colour} \title{Encode colours into RGB hex-strings} \usage{ encode_colour(colour, alpha = NULL, from = "rgb", white = "D65") } \arguments{ \item{colour}{A numeric matrix (or an object coercible to one) with colours encoded in the rows and the different colour space values in the columns. For all colourspaces except \code{'cmyk'} this will mean a matrix with three columns - for \code{'cmyk'} it means four columns.} \item{alpha}{A numeric vector between 0 and 1. Will be recycled to the number of rows in \code{colour}. If \code{NULL} or a single \code{NA} it will be ignored.} \item{from}{The input colour space. Allowed values are: \code{"cmy"}, \code{"cmyk"}, \code{"hsl"}, \code{"hsb"}, \code{"hsv"}, \code{"lab"} (CIE L*ab), \code{"hunterlab"} (Hunter Lab), \code{"lch"} (CIE Lch(ab) / polarLAB), \code{"luv"}, \code{"rgb"} (sRGB), \code{"xyz"}, \code{"yxy"} (CIE xyY), or \code{"hcl"} (CIE Lch(uv) / polarLuv)} \item{white}{The white reference of the input colour space. Will only have an effect for relative colour spaces such as Lab and luv. Any value accepted by \code{\link[=as_white_ref]{as_white_ref()}} allowed.} } \value{ A character vector with colours encoded as \verb{#RRGGBB(AA)} } \description{ This is a version of \code{\link[grDevices:rgb]{grDevices::rgb()}} that works with the standard colour format used in farver (matrix or data.frame with colours in rows). It further support taking input from any colour space. } \note{ The output may differ slightly from that of \code{\link[grDevices:rgb]{grDevices::rgb()}} since \code{rgb()} doesn't round numeric values correctly. } \section{Handling of non-finite and out of bounds values}{ \code{NA}, \code{NaN}, \code{-Inf}, and \code{Inf} are treated as invalid input and will result in \code{NA} values for the colour. If a given colourspace has finite bounds in some of their channels, the input will be capped before conversion, and the output will be capped before returning, so that both input and output colours are valid colours in their respective space. This means that converting back and forth between two colourspaces may result in a change in the colour if the gamut of one of the spaces is less than the other. } \examples{ spectrum <- decode_colour(rainbow(10)) encode_colour(spectrum) # Attach alpha values encode_colour(spectrum, alpha = c(0.5, 1)) # Encode from a different colour space spectrum_hcl <- convert_colour(spectrum, 'rgb', 'hcl') encode_colour(spectrum_hcl, from = 'hcl') } \seealso{ Other encoding and decoding functions: \code{\link{decode_colour}()}, \code{\link{manip_channel}} } \concept{encoding and decoding functions} farver/man/figures/0000755000176200001440000000000013562622625013767 5ustar liggesusersfarver/man/figures/README-unnamed-chunk-7-1.png0000644000176200001440000007141013562622624020471 0ustar liggesusersPNG  IHDRz4iCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATx_z&HGz.EQwc"JD1FFcKb" Ҥ)R)Hrm|>s̞3Nm&#A @ OJ @#D @+h^qS @s @ yMa @P@ ("^تUlӦM2-[6nM㒰*/_vlْ`;lѢEΈ5kڅ^hݺu3ר|:| prdɒVD w~ XgYL6~W[m-M_H|nذ!9w+V4=@5ի͛#]|tA_ly=vG+bx`luK$k7fp TR=o9AG믷kڵ^k5zW_m-[s=ז,Y:S!@ m[, L0}];SF۩.]uۿy@ &L|&p}Y:uW^;Dk};}@ U g϶aÆ1cRXݻկ_¾f (jb 0`$ۯ%L;8mĉEE-@ `W_=zUo}5ezGۍ d4+@|g?[Ϟ=wY9s9CmРAx]2!̈́B0Y͚5Kx/RR t @%qL@+ɛٵkW'*jʕݪHdh h&8@@ (%@SIp6nܸTc_@)@!'|bZO+ڷooUV7x#@J)bg@ ڶm[Vt*5VH}W7> @. @sA?~URԩq-:wls̱>@"h" C9`ԼyX!2$+  #+ ظqM<F)ivsbvСȎ< l'ݎ7M`ڴi&-*;vtׯ_n8h@Hĉ]y&MϤ߰ay |G@i@ W_}e 4rer7ʕ+ó'A@r@y@%=?䓈P @ Ah@ CWo֚6maN;.:k,[d_@i@@A#0i$W\ Pe>rȠM} @6 DSLҥK[Æ 7g}5nݺge%?2   HH{}駹Ț)!N[Β7|Ӛ7o"F^{ζmR!@g'2k׮M{@I@&R%qF7Kcǎo\)So   6؜9s)a6'NL{@I@&R%0n8[no~a)S>xG@KpJ{W[T\9Ɓz@xR"M ;'K@"RJִihۑif3}beK*e͚5C&B= 4hҨ1&Lpc?Kk۶aO@4KpVSj|嗶u¾f " ܍/ M(kE&9cƌ2do@`~y?fl| T @SžIXhXY7n4iRRy P8/Sg\(| B -M760h ^z,͙Iv@-[,7VZbEA@%WD4ʭm~آVgv (!/֩Ny?h0px]' ymҤ͜9Ӎ $O@ҥK[ݺu?(G{*,\0G%- E(6}7Ez?U5Mؼy sU)$ H4^nx[!.pW(j;o޼bhf =TA#5jH4J4K,ETFիW7M^J.$@ 5=Û!knxƁ&= +]hmjW!P A 5~mڴ8唽%@5.u˔ H@Fyoܹs]k.puk" H@f{5ݶm[+  @w)Zb/`y@-ݲeKq P; =3Znm͘1#ub@0 @+W.){qF[hQRL@|@N@E?6 @PB1v+/\@ӡ1q#ôpCg{m`7Fz@x$- _J@v}T 42v1u+Y~ 4zh%A(H4|*u"@+Ud*T@ cI@Tm29^?۬Y\MLsDŋ[S2Ix@SB1%0y{?4jQbR $C %%+VUPR3%^v9[bj|eГ7~_)te9Ȝ#~PP!hӦJ<d @F`JZj)UGPٽ$@paʂmۚzEMVAlbOS ;4S)ħ'`Sr@h~[UV aZI5}g/O,Q]^|z(t0;C &&Mw5 J?bĈfB@J %j&/oN%A;$`jҤ_xǎ&'T 'Q+VTAʕҝШؓ-vZkڴiK>ڵs˼G!@ @^h!|? $@&},Y h90$@5VJ*V6lXMe!@sKQ˗/0LB)q?~|=s;t`ӧO7/JW@P΁ h͛7͘$@`G7nt45k!$D7|HjB yբ.]LK7F (P̊+ڞ{s ˗wovdl@ }q/_8 @9 =iBE)6sL%H@nOl Pfg zkRЀΝ;xA 3G6Ϫ%jY h͛m۶!}UV(|w[ƍMQ[4?mH(Q­d!LL)r| 943M8 ! ({u׹^MСA/grJ'{Ap\fcZjF_8fƈ#܍RvQL Jx ڵkMĦ7o|ɶxb;ìQF /&ʱ 4un $IPAr %A`Æ 6|p$8={K86cc~̝;>;McKZR%馛ۍr@q~Z|:h lhBb+U4l}I?wBI'djhX.'_&@D(؝J+AY͚5MqHfp8/r<5jKTVP!R5&nݺnf|RSV @1IHQj< vO{eZ*Q HHB.?ގ=t>}c6”D xP-ř$4[4' }]7]!㘴4bŊMcHH>zunn8[nM;L49NUy@uPEbjR q /Z֭wZ%{6jn=x.Y+&ۇ~~jBQ&I^  Iñ&YK:0y@9I4Tr#i L:uz]ۿ PMycf9f3%4Qz-۴iSX͠y$1w>s!4oS#}.w}s1xkOmHE=k׮55.[urCU5F&ۓ'c@x 3f͚TfÇSwM>RZ Ы~ڵsyo%. T3T[lk<ꨣbe{~G19Y`1O+g^z3Z&vʔ)6gΜqn lW7R.<͠q84xwC;s )TLT805n޼ys_~LW~ٲeahF=[O ^^Qg} 󩕏Hf _8i1cX^rC;vhovNˉkи|v{]ϰq8B@F1iD:eʕ+NsUKzOu׊4@NVvRZ1K+V̹;wv|>jh"G J*06[ i…Κ Wѯ_?[`/پW^+4}nV*琀<=ecd)OD(CJmhjrރ[\9މ^H@:,4i]uU{ nx@o}5Lk[4c,Gfh\4?B1y$x #>s8/IGi4b.]LZPg*E ԡCG7|v[ors*@']>72ŧE@Hjш#LShI N:!@SG# DhϞ=jk̩5p].L<;"a_r%6tPӄ##O@sΥ3}:^Mղm5,lر.:!@#۴5.%pk]^I%Z{Ɏofpd$($ȑ#қ~1cHH#@2V9CZu ,Ɔ=c 3<-!eN@]ݺus][n# _Kdbhvy"7Oꂐ%*T@|osϵ͛7W\֦8S2(`xPd MB2enEY)@f0v9x4]*/\#A n&ʑ-yQ<׷7x# `C n;؟EUFֶm[7ᰨ}؞hr+'@s" !)bZ TݢZu}2Ϩ6pviQ:uEEͽ{vN6-GDh3_hBʖ-"/I@!޽yiaUロR+W?GiX9`^xᅂ_9`4O$J&κ XztZn?lӦ#FXk R4MZfM @C\hRp~c_ }eqZ]H%q&Lo&S/^~e7޲f͚_\t71.8J-B@43"U O 4?x`lРUm +ĖA\ ={}WDk׮?1=R'MYȗS-0xqgo`+W΅Q7ƃKॗ^2RAM~k>)uԙ~)o]4F}c#_K.?Prz^'fb@aÆ;lb{,4M򀪫M]M823oد_?kڴ]pVD2 4osO{2΋ I@rt+LGmFr66 $ ˎ)U&"!@wϧ;vt1{=1!R4dĈwR$kHZ{=G{ƈR#MW^v{$[@ϟ{/ŚWߍEo (8 ˣz.tE>}BQRJZ$AH@&ϊ=%w|aR9  R>lذ;u](_*aL^wS Zx ,I1A5+oKQOh !<ȷUE1c3U9餓#݃ۜj+,%]{Mښ$/&(j,СCRm UTWR˗/(j~馐*:nfץƄ`7Hą7xgo=P4$V @s 8j{|#@v&g֖V>y,}Y;#\yu+%X}_P\r%^{sS%o]$@jMuwvyD[-@ΝMAo6ҧo?Sݽ+γ{.l4ed>`ʕy{챇Lx{X؅^h{キ[JL2>"pi&((8Cw۰'N7|~߅jt:t嗛֌߿ټys:YEh3Ƭ^-yofkYDhn7<.ԩ Xa+ W\a[nSN9e|j뮻ׯorHk*)Թkz=3v'ڏ?B#4DwU g3#kA۽}v饗ms0zq5ŋݍ^!H!O"T(TQ~JrAgΜaR"2#@#Ӕ7D3UG >9k۶YPSOy2=CVnۭJ*.)̚5+լB?44MEBY-#Wӧ 5 еDs-[͒?CcqJUoذa[xGRww*RAFWxVL WCOZ٢riWDMVD7,|iƅ0HbCNcǎ.lرcs7oI&ʃ^ |Ro?ڵ}n믿<Țt6%@Ǐou<_dh-?-_[RT ]63wh~P>Z@Dt. rtw_и;?a{v^;yyIv>;.м4k, s;9ϼa Cu^~MCįpBSl5k8-[L.z-Ij 2ĭ{wl'|b? /1ZbMDHhnR^RSnX˗w_i_+7wXF+y6lCk͖T0cլ=Tݢ4COۏt6xײ^Bb_>Z){osb\rqm#˗a_|WNIQ9F:t`ZMpyV`j>SN1cƘP'zp? !09r,IZC%F%9~k(*E~n~:a_~e7oifğb߾}wficϞ=M^R,P^ZIK.qN8z)wÒ=餓\ZZ]s777T.sO=i?c!q1=䓮Ag̘d$v#6|l5#W6I^b|~]:|C.rW^yeW=$eKӵ>'PP*pY ~(\cߡ5wxzdx7=iX~]yf͚&+wM&/uw>{M?{sM5rf'.jyd/d~쳏"uT_eʕ6Sӹ)!*( $gqN)qG4r~覣׿D 4g|Mo[>wkl~ 0'- F*.-ȉI]+Ww7puq_[-q^x I%2/<5Ia|'!<; ÊqQԫ~p:▼H|ֻf$.EP7i]5]yIO]{' Lj$4QcϟD$4ID@"Ӄ<1(<ϔU=9m{Pџ~z@sH=1Yt)&MsS>yuϔ^H<74i4Nk2K9-46]cVyL$.5&Lst&a((MLzZţK.n~0{Jv]<4nTGyi8˻?/Is4ď$Tv}=.h?3 Y]K䙍cfae_IC? Slw%Fv΍-"rKhLʇV9rJi@IL&^..ys˓"no5$5yA$>=z2U)3NGD<=\bY7g=FWTIOs~D 8(k5{PQ %`D,| V)ty&=zJm׫l?Ra4~TI]Mq KtM7.r kPrzc*N>d駟v%-_T +/Jۼ~z@6zѰ @%Yvj^i,gẴ3,A$h:I NtgSy4[cUiAӈ#HT~x=P$l ̦]wdƀ&{b07~84yg#?9 Ôs~VL5MDtŧ-(>Mħ$'$$⟑ @/ PRj5\}F|xůP* ջVb@@8$@ս.%E%y ]Qplԋ$gL ¼ ) 75&NA٨Q#i˖-^~ {6-jB>9UIH @Ћ.T|͂J 'pZҹĀ @fk. N̤ƙ4Tv^K @'5 \k~ᴒZgL@Рx| A NIy@eY+"\+K@VRh/Ř4Wt[ @%Pp?wo߾;_ >H׻!-J @ \ TZ"]jwo5 X)ҬYAu @ yI P-$/؀܍_p:wl}2e$_"{<[n vn:T wI ɓ'aw.]j-#8z-'0jP,YҭG/J @ |/?[=~pkq/X&L`3f̰|0|S M믓!@ڵk]o4hjꂿꪫlذad^(e{ [lG @!"U&HLk֬͛7T7l`Z@@$%@a޽kq9108 z=pYMmS" zXbJrg/sY yC I Pc Hݻw7B֚GuuծT,B@Pu){5Ҡ YB= @HzV3C qԩɗƞ$ РU^@Ak@5bرcKl1􄧲V7СCG]v.=BI QF6qP2 8(Vs9 >ǻ8 RQ6TR jܸ <ؖ/_n'A  PyqK,)"MP!E<$E"  p(V9jҥO-[֊ 2UA킯W;'NI@Zܸq|=n~:q7GW\9pH @_os[]cBלּW^ 4%zAZ)р&M0)!@! }G>0<~裏wyn{C`*UL& )U6m.\h˖-K< @I PUVY޽mݺu6|p;\u5k߇W.xKW_}^@@ $%@Wa9rnG₪otkthݺuB tç@@a(ƀ~H^zթS~ߙkxR4 sq< K )*5#ti=x/>A]1{@e6lm۶m{ڌ '@rF .x.Es&0L<9O@Puq9֫(Ϟ=` ]HZi,#&ٽ{wwӧvivAe]H@Њ+n{ꩧln`}4sA@!6l1!IHÇ @ I{@+;l޼yn%K(ԍĨܑC[)laвճC+ @HzEY^L+L>ݖ.]և3f=[B J@? H @ր0az_ֆ֭]{6xXDMB`ٲe.0 P-1:wI @RT?wYv;mgC DpL !6dȐp7 D@RT6_vZĎ5q:'AJ ?y@@.I ^а  Hzҍ74%?Nj/~yN@O<-Z֭vs? @ /.2' $-@5HA=P }&/ĉNT<mZTsсN!@q -[zvQGc= H[%ڤIv`@@ $-@?sӌqoa|v}L[6:yG*P@@ $-@l۶M2~۫<7|]zYYM d ڌ3 ~g@L iX۫د_?4ihb6ބ@/hO, HZ۷Pk7nf%CI@3k kX+ @GI PQ_~e[\w_~O/WE{4Jc@JǏo?sБ/ @IHZN>ڴicgyvmn;L(v uWX JIt֭b$@#=sG 6t5~gdɒK/g%g8JZjY @@RTay -[vm> Ol\W 4|p۲e_U\@@ $%@5{XN_0M6}Wp;K@4PWXa&LoQs@@ $%@5+0}Q;#B'P|T=Z *СCM= @y$U}T{6w\ӧvivAe]*ST hRT=J34'C!Pv^z6f9r[MF^QugׯիWGV4'tԩ@@H$-@eO%t!jH[)PU6lz= @W%J>ZjF g8~!k%('yAGa6m@$h ſJiR.{mM x@Ƴ݋Zʕ+bF95kI7|[ @ Am%hԽBڵk8P3 x@ƻw^(O@J4X@gϞmO{@rLca^4PB)  @u(JKCc]5tȐ!h* @ hTZ2 vlݺբ ga:t`F 65 @h5˟~ɶlbիW )[֭sK̦|0@ hZآyP\'^ӦMݤ'n= @9$!ܰe?*e$$uak. @-hh._htw~Q"͝;̙ZR5@@t @Ӗ["nfe˖80eо}{aj5 @a& seq~ aŊuGe(A PhaTbM]q/lժUy@@ @s5Y.\0V!۩sζyf>|xfC @ kqW{խ[}am> @ hh*]~\2c@=: @@ @49z1@ R{}7n\ @@ @3Yy1@,@[li+WA); @ oTPjԨXJɒ%M6U H@F97fV\9>\d.]L,M~c PЀ6L`Yf \yZIB| D4*-q\ 6-C^ @@ @2٨9?ۯ{ڬY7 ,@f dس رw~;@F5H׮]MX|ySL7|3J!@& pj~*Ͼ;8qoy@@V @1ܙxY𿵣f+(kFA Ь` w&);kҥK7l @ cЌ? PuKt~#ЫW/_X7$ d4+Ý:s6lК7on<_ @FUVt ʢ%r}_g1W ě4ﬗc= Q}ǪVjO>d!߲  t @ӡc/_b"@ o2eءjo-\ @@J)?3.VTBG)z' @ iФQEsGM@RZtVTɎ8{MH dF=w\ғժU -4ਣ+7ߜb  X4sF~VNwGB v'~!T @Ȁ4xQ8tΜ9Vv(s<@k׮]uUhѢG @FeKh~ .m۶ٟ'JRG' @G"?\֭C3YcejЅN84@@j~*Z6iҥKO>v7ɓm˖-e (S1W zw;c/?%K&+5nvm7}MuzK$ D4zmEfrLJ,R'Lr08q-^تTbׯyѣg}]z饦$@@ @cM׏1^lY7;^3 KZmO>G}^{5{Ǭ[n6@@,04\3f̰z%[FaÆ֯_?;]0{yLuO ĕ4-n:?5h o]p ֥K袋%( tٳ] ԨQy@n,@py@0/ٳvm[J 4OTw}gVBQ8 +_]s5Հ 4|ߕyD觟~jof0*E- @9$!ܠf%#\d͚5Zի{֩S'曝w:v0bE?cǍg͛76Y%X`WA2$`߸qMpTZB MZQlҤI͈lSN> Y;1 M9r5k̭3Cc>cmڴn֯_zSQ@@ɒ~6m1cX۶m#`MMЄ c=mCbIf?~[{]v1:6l>`{衇l4ZC -L7k *.(5Nl[du]0 + @ 19^u^bŘX3իg'pcF0, @Ơ̙3MݹpZ}177+3ΰ7|^xHۊq mh=Syf;"ni<ݻJhr IH6l2DKj"liLӬx=3m֬Y2k!@ h;l۶mnu{5ʔ)cW]u)P}߾}o bLtmZ9_vcVi[h&]wu?ލ eYn(L4-pB_l˖-f{챇5nk/kժ)h 3f̰/ڵkςp"z^Na5j[uĈĔJ.m5jp³dɒ~g[f^t}:4h~#P.m} ߻1cشi#43iƹnF~N?tPx㍮Pv lܸX:MBt=L`Y:uتU܊SÆ :OFsmڴ͛,tw}bꚤ[nu}vQGY- ΡhӦMO+6֪cK|u벛1 ѷ|@(WE-Tx:íf͚E/ׯy6lh_|zp?uY*c=ĜliSW<F4/rw?<'ïtذ\6n8Gok_^<#Z;^25usU*iԭu3KO{u/q{?=xTKIJ=8Ο?ce~RW׺&ibW>_~squU[vm7Hz0CHs絑l)Ri+'tl#a@!T~ؾ2u^h)gFI:O)tުGCr.Vzx8¾6]Wh'!5u陿A|wXG#ϟVR @,$6x`7~T^Py^u=|]e]ݏGۼ)kVo]zGWR:ur]y4Weoh+%q;c/vG"MbM57_;HS'%t=@ӨR?3={ᄒ_,X`ͶWc굑.H%o \'[K~Ӟ|I7_7ԸnRGq}G֯_?>|1rH]C1J;vˠmXI^ B7\+E.ꗷ,I]+*yKz{ձ`E啋7OޟI|yW^}&{:ydrlH^x#vEd&!yW,l'/Ο(_2aB^tx?N'ٙz[Cj*I*N8ܱ`##@|Af;ت UݿWDԈJ¼#h5՛v,,Ʋ_@l/!f~:>ؑe7xV \v%%8F/nYDg=9~xkܸm?(doJ:S]@ExիSO=e˗-[ںu쬳β5kبQO>?܉"3P۪2c w衇:;~{mƍ#~ժUCg#ۍ7hf2<-Z5qD+Zj㏻[6mB h(JCD>nfر_>^yg}[Ǟ6vXwlʕ&!?ZŊJ*..>7h`{Q){K̞=ێ;8ӟC͛g#G_J,i/vuڵktҶi&[bկ_pBQ+Wn{^ڦ^z_)3gosדUzL׶N:=\w}9-1[B?;uNZ=p<-^؝ú~\@ ԵC|%& kk77|c%u~Ny֡C[|DH|VR%'NIws}=8!eRKjK+uF :=p|{nOj,#kڵk>|uCtNAI^yzٗ0xwt<z_}16mU_yGN@ H\駟wyJ*ê!FUwԥ$ƌJ|*}ҥnҳ>v5Y@O(PVy4vzэ]cծʕ+m}=z؁h*zEP]4]Ï֭ħ:?:gGiwq{:|~a  \2fgD^S.xIuRM}aZ3^c4T]ePk^lYwCGi=ةզ^JlmӱiLKO܅Ș@Q*TWf{):V917x O=_|^VyE9B"J=}u1QFֳgO4hѣG[Ν՘?ú]H {>}k[ ?8Oлwtu?ӝׯp nXF#$PԵJWn\& u!IIr|;U4Ȑ! Ki#{㎳ /̙}ݿk"Aw)lD0" Xu "Ҥ v66k+;EĻ{sxaNμϙ}tFh4$NKR`@ eb gݙ@@ѨiZ\.h~ߔԺZo4I6|>oib(\$ֵrT&3. _S' hr D$Z}svM2 P(ӓߛKáAS%]VjJIi$Z&rlX# $ _ ~׵Bty|>ks8L:ldX&4@ eb Wz'#{>P}T*I %@jK8 ]?JL&nKٔ[]y!G }ٮ@>!y8#]vgX M@@_,$  X M0@@P@@$V   @3  `U*7@@H@y@@ Z&  w$)4IENDB`farver/man/figures/README-unnamed-chunk-8-1.png0000644000176200001440000006204313562622625020475 0ustar liggesusersPNG  IHDRz4iCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATx\U_&g I&*HQB#UEi" H҉IH m?dfwʝ[?f{yߞv* @@   @y#  *@*7! @@U4Tn2C@ =  @PsKyf/իWֲI&֬Y3[bEs|Mƍ&ԺVEfU$TTkw}:vh^zmfͯЋWUU٪U =R*дiSWb[nh^_?\-[ZvlƌM6t(]|y6u@׮]mɒ%tr= >ܾڋ/h;wgyrq:؂ 8C( UV6k֬TUyV]]N @ z֯_?;c_o$Z &  @.ӧۨQ\lݺu{'<! MV  mei0C _~yᕈ@ z @R%[=Ls-}4h[oxD@#@'K@ (z˨nq$@ :@Bsq; 8p%ږ[ni]4tr2Dرc]{(+Ge˖mO @88  @ @ٽ{r|M!BFN ?~ >u S>}Ld{@ $А@ <1cXϞ=sf$v|Ay*/@Zycr@Y`ܸq֫W>:/ @e@+@B={-]/k3g^x V#+0eaΝfTII h PAv)o.|Icx*'@Z9[ Ъ*wǣ|kuЏ?8!< .F_@h}DZ7L. ! L::v`nlݺu  h\ @ bɓ'[}?}X@ \p @ӦM+h^DBp@&7@ ̝;V\YPh׮]M@+ \<y`x@ yfrСCoܸ۬A*@ pI  @T>m߾}AE޽}A hp\ @ b݆S[n6a„KMdO4{mN@ EJt…,A @1 @-d/z@"<"h8 z@۵kWpNU"-D4F. bVZY6m?C) LSSQ@  @'N~j@@c@<-tI35xD p@_~ZK._Tt\ {@ ̙3ǕEH:A=K,' &(/ @Ny絨Pɓ's"@eq* @| @'MPR.@z @Vz۶m7o<Т8@l@tM6f͚]"eh6N@dВ8@ N-v/N c@!  @ZjHSL|!(o@Tt̙VSS *@@B@ sT3 ʋ@<8@ &SNIm( MwR;@ 3 ,b`8U6mGhq4 @8˖-+W<ߺuk= @{@ ~W*T !Py @4RSǎ @K< -@'oYNP׶(lWjdJ`…lÔw R4J}FDZ*z @WXaZ%_@A8@ ڲeKkܸ_k @OR>/POjN@"^R I!yhl2 @H-g]С+-=!5dZ4O@tVUU^Tt'E@>@嬀Yh!x# -WFI PU>F#L f<  {@O{Z[4C@Xn-Z(!xΚ5y -W@"Xx]6tٲedɒHD]4-L@ ; ڷofΜr5@; @*x(e6 #Ѐh@ o {@}Jhۜ%_4mH @L |嗮A iӦ,D;ʇ!@2y TL T&Xkqa#@;@ o޼ "Z|\mx@  b* VΖ+#  j!=^G*#@ZW @z@gϞRl fݩ5  l2(]rK$he\* @HAkΕCj@ɤh&J#:UҜ9s҃DMh '! !ځ(F-E@MM-Y$M6ָqc"Ū)L@֢ȐE\mmԨi(Cz#Q@C''C@ /<"h\@ $-@R TS({J@e@+U@BTP,2+@٦ @*5P oP2@|䝐z@,X`k֬i9 |-iӦ iܹ^!@y' $V M=ߌ+@'WCQRh۶m]-@ClLʔh">^ދ@zr5@$_J7oݐBlKʖhڛ"J7@ek@zr5@*5TU<@@: @ PM4{L9/4k̭EE hnEVjW]@ @'@%WBQ@=W@+@'WCI t֬Y!ՈlȎhvښ"|= mCeb"@  5kFB8@ vcҪUu)v &(6 uwCbhm?hРE @.]jk֬ T!xA@3TH|{@;tXw uhZ $JWwD9sfA (L0'B@+*5>EIh*J ?p6m*^q 9g& f. Vz^Ve> '8eA(H@ߛ4iR-GsXtcAym۶R(s@C& f* 1./˗/ŋz hM@@Ph TjW3f[LG<y`x@ QӧO/%C a k0 `!xz@y' \%G2+fڢE kٲ%[1eF+!@Z Ք]a5(A K,իW*.eh8?Vjxfٲe駟W( dV@Ja +/mF !h0'|bcǎuu5jT*H@ yQ%M{W4myƍ0p@#/@$Ja2@L߅ٹsgSP 9sbk.(/݆eJFX4ō[nƌc={>}-O]A賨ya;MV@@SݼUN={M7]^<9PEAaN:Lf@j@S۴ULs,Xݻ[ƍm„ ]@9"K (oCVs@|m'$ YB@\SN d@@ݾ%NJ۷}dX@E)̢h(hf4nuRr* P@TZvq(ooժiIIyO"!,]m8!,@k)@&Lps@ $ (q݇ ڳ7 @jeڵkS[g*#1QZn:n %Lh)"CqGQD$eh.]\#L4=.@Z]TZw?S]y*>}5mm v!_5!:5i0|Ϻ=r(O@ i;Fw֢L=q+@ZW_~iVZ/( x @> g>*}MhZ3av˶l {i! J@pbFQ(3il24|wm>_7n.\X)GBm@'Oj 4 Uˬ2}ݤ> @K,Eya+]HQcx m(sG S=u5?D!ehn\'Ly"4epY`٢E.PFBR?< D 5i* {?uu3J PK )?̫4 ߴ%z9 ͥ@( {k62i4 4  ) V @(>̴(Te!!@ۥ|ŋۺuR[w*Pc#/ʠH׬YyY(I MjU ]̞K# Xt >'F,@Z0UvT ~PSZ@_)e0|@I Mz VZhԦMnD Pafz@ TfO?p< MoۖTUVٲer.B(+K$(C@rjƍTz@" h競̵ <-0vXٳ4kr=Ď?S9 m.}YEz@j=)W^afYo^ W^콨HJPmܼys!emAT`զ9 ⒴iɒ%6k֬r (D5W h"I˖-sfKB xm{PHa 'mik2P&?̬8(H@Jq @KOZPr nD' wh.CJ (JfSԵmAYT#P+@ZK7P閭ٵH!\2<P<"P@(pFJW=Tx*)`d\[@/Es`& zG0}|TH@7=2͝;A*\6􀦻}|+u1&(C?X-@A1^G  -*G*U/ŋ{@@ƍ烽@/^VL,D*3)@f_怲h~;^Ai^zxW;vdhMl{Z74Tzy  @PV5l ǵu(W@:Tb>!K2(k&M ZFʅ@@*IeCT<ȐnP>}-[,CBU(_|\aҥni}45NE3t P=$(\pAf 4TOB*)-jJU|恖*yY j稷*}-g.C Ik׮A^6kiڶmkl(+ˀh*>X-+N:YUUUz< B&!*mѢ5nܘEHAs W@ܹsE8eHhZ-$U P,F L<ٺt{*+b_V @\@1(_Ic @ n:ʭ7#,ruTK חtl"!7o[3)=r`CJn4XcW@h}?J*!JI@۵kV;\T YKmllԐ#@9I @U^zh9-ιY ZS_j64S3D^B@4Sj$$GNBQ)# E3ģƣ(iH x{vgtȋ@dUmB1!5xDJL2Ū+q\S=J WP4Zjt'BZ0!@ @u$*3&)ED*@)2BVv4M@{jN>=Q0֭}Gik@E@+š̋YV\̊Rj9slՉ @ڧOX(\@m\?y6Y#b +%.HuA W 43o*@SNu%i T#Cܒ3Է %T4 t^Ts|? @@ @5k=@}em2J1(CzkPYBPFw9ꖜ;vQFsE h+{3 %mؓ#@t 䒘o~NUi1inˬY6Zܺuk޽{1ؘ hPBPcx hR=Y؃>~O6ol;#h%%[e}iڴ>%^CR4tof֤I7 ;B9dBTٳWu%0YXNױ~h֬/TN [0y*ׯ38?#l P|۶mMս{"`:P#%w.BRٷrK{뭷lڵ/ rj袋L*OfmyL@"\@c4S]]/V[meO==ڶv ojnΙgё{[ < 2WHz @ ( >vru7vaO @ҺurOI(64M$U B_~eF"(8~f .ƏdilСiׄ%PlP怖E C/HLu?n˖-+j~}k=i(hs+v-ذa#+V(u ,=Jq#M;w\)Փ'@TCڂk^z97R~7d (-vCnsJ@T4h=syOY((j>-@R a_)555ESRCiՠ ɓ]i @lsqwEʔ|@A>v%ػ|g\8 \픊و^h?J ȒC@~Zo)@ oݴ.b]vus[9_x_|1 hC?7է jdZS=;'d(&1a|0‹/Wtw}k %)I@+9 @uoI @Yڂ)-b]wW_}խ2dG2/Poo[֭m6>𔜆_z%#^򽘥LB0aBB k6mڴ'x@"!.zi3]m>>u+\[qRIs]"J>xMNm))Q`ڵP Y)i^=]~剾hڅD/Po:j(vKJg[ZM'%Ws[{Jq>}^:SzsOǁ2 @cfjZ|_MF^I P{5??R-Dc@!?9 p>#zк цaa|@b*,' lp@ &NFܺtҕ_7o^ @?}߰3f9?]?|_VKJS32 5G H:ur#mA^7.׿nyR$ʁ@v=3s=v衇U}W^y=VPYOPz@ Pg}vT)q>C;Gƹ 0 @ϟzt7˗Gu+_mܹa<*$PJPѸ,dD`ֻwTvذa=i: /7#GGyСCk&0_"@> ;=b-L zzAx>39t|v}s˦GRrԋYjJhr۝#1cƸlq)RqǛ{oaY~-\pi(x$-::ݏt?x .UVisT}D&z@x%']8zT=[{a#Fns}7}u+vᇻR ʤVT~}u+  >@Rz-k׮ѣS}nFzRl  SzTP[1Akf~jһk/  ((U߷7|n&Wemäۧm &v}h)_#ےiŞ jꫭ&3(8,8q=}tkӦMI595>,>h%-Fc@ ͝" p^x/F_|aw̙c/ BZݤD>^%0a㏻SiTR77l3tl @ek?ϮWצk׮vwqGիMzrի,+W4~+CdJ:gڴi\:K,}]he7_:VoM4ѡ.zkxy֬YnkixTT/&|r@]76klkV{]|'?A~jPʫny뭷g6oݺ? iR{֥Kwg--V{]Gޱks?5-(U 7uv=|뫡V9Wr]ĺx4i|ͦOyl4tPw̿o׿B]qZƍs~?T=3t 7TAm.nvq 96tS{;t Iԝhz7̷|db6ӗa@>@> q]JRFJKsϹ3 sT>ջߕSLqAM^_SNu~gwn]ɽ_ǡs}͓K~FVZ8AnРv 8ݶUISk7ginv۹Gjgu|,(UA5D~?2IZ!/ TW1bDKMJڠx{ǝU _?ri8BI'MnҜU +ԜGyĕI=îA׃:,S`WvO%\R2{>UMTRopI?\s*Pύ(LɎT3[:n]w3fس>v8q|EC;찃]z饶>4<*n9S Os}HsxTX_*(4~QGkHA"vKQ/)Tdyc=Ý;ww{^Cj5^Lݽ_/]zMAiݤOaiMV0O^< )4os~_SO=e{z:V]'~_M=]?GU(A$,eBU4w\wk\so|B{YU/^(wY6z뭭YfQ6AlVfC(zCDB~nPQ?#SD@D:]۷w?3MZ8Gw[=ԩSqIe^vFVEKL> nO?E:N .fKD^WJ _\ֽ~z05Vi]0tAnnV=w}wa֗OD9|7TR/pݹ^Wsp5+LC~&E#?4w]ssMiC*]}P|} sHsEE:rTeR9Dz{0wur},8VρzqneC2RpQsW&  X5WT}Yk6lף>C{ z 7xí́Պ{-nl k\жVTEջ4Ԯ^G!MI7G@}M=k  |z@k.{rO}u ߃ê Wz5iv嗻*z4TIr߹'u5?[ͯ\Sq '@W~NzLnF뮻$ +w|PnԳ.}  P@z#rnmUu{4@s*s%]^+Ջ!pu1k3 i+,5i>zDKI[:ճ@{ÞS M] L5__7Glkw\;vP&: 0&kd}>k]_};LHhh>:4|P6 ܴ|äE+s%>ZMs|*ROaԳ+kZD-~ *y dWT,mhXϥվ?яjWg=5f-POmT9C@  44_vۙhޥԶJ %m urPM;WC+­! @\ @U/6}5Ot#k/*՝ϛܯUjh?WY@Ț@06{キTw-+5S{tMYsKE}}R? r ((Ն|ۓS{z*iE11ug"R|ZN@ 4yO@JTAVk5inC s@}YJq (xOS>l0w9Mگz{WzHM̈́&).  1_U7y晵=s7M&UUU%d:ND@ Q}@u!ߋОa!R B-U@Ȟ@As@riawRןg~PhrD @}f9V˹" @6 @'L6>v]x^JW- @M{  PIP-2ҦpuYvټylԨQ6|JkWH uֶ` " @ *W]uiۥoݪtW$R2kSc "Ppoi;#~g n֮][H^3AmӦ hږ  gC9Ķf裏裏|^qvyŹ-@ui Ai@H;z |o1AAUԚ՞" @T{l2׭"OV@eWEي)M@@J x+m{13VYxa}EHJ/ (x1c3gS{^venGnݺe1R@@{@O=T}M]OV_ɂ(7/V@cKS&@'PPzo۶mm-vj\p=3M2|h&)% q((ӹtҍ'6z'b- 5kf-Z`h[! P.mDWn͆ Q|2T/(Cs (x=ꨣl]vFСCmv矟yȤhzsDJx $ (8ѣ[6rH;vWtwt_gJ_ ) 3gN .Pp^{KC|hm֬Yց@@ Mf(u} bσK  6$t`7/8dT @ 2i}ۃ@e<Ф(/  o+1NY$@@>tRZЫ;tX7 UC@ Ѐ v瀶kwE@ |#ϱ*mt;N]4 ^4M|5"$]O K  ׂ֧gb/P/# '@ZNJ_h=;vɓ'Tj! @PAI&:T)9^Νmʔ)  K*tٲe6Q3@([l]R*M:5y(@B :>)նIUUU ! :5iRںu,oڴ)@tp@&@Z$16j-D4o* @E`Pԩ[1y @@ hNt?J=zqƥ! @Ye%J KW^6}t[dI2q(5 T\ˠjL/hڝ! иD*xUA=Jcǎu l(@Hn:[xqEVnM61-D?~|% *@Z\BSvڊbٳ=:B@*-@Zi]_JW6j(O  Rd-@Rd[زeO>*D@@JRJH=7~;`@ 4h%{@[ha}wy'@" =L,X2d zk{lU@@ lJ=UUUr 2mW2   M`Sd-Bjݺu9(~Yǎg-xB@f]M @5jzA|I">cT@ '/͟?[05olѢE裏}@@ {hR yݻvmgwyG@ȶh_hs@=n~=c)@@ {5ԳnV۵^k˗/O  X*Oo#G4}`!H@U4Th3m87onM6 _实kza^xn?ɭҏp@**@ZQx]\=m۶Mtb_|]~v'?}ؔ  @ͳs 0GTڲ顇u(! @ @SЈVAh[0Z>}e]5,SOz*! @ 5=u]V\i\pwT'! @zMO[6X$DƍUWW@@ =ikUqZT_[hO?n5@HhX–/_EHԯ_?;)%! @:@ю BJq\__"}6bĈ5;>g#IDAT@Hhj]))C8㏷W_}^x4  `7^1EOj꨻$ 8Ю [fM1X@h EJr*O<&L`{o%x& (@"vYi^j*bUOu]g/.:  FڨQPD&w >oJ\k" @H!AGܹs]vQ;wltq6y䲮  ht<{ĭtGX˖-+2! @@HAq֬Yc=֞y9rd4\@B < Ӑ{o߿]z饶jժ4T:  )Ќ4!%}o*-:SlҤIv뭷yD@&)`iE߾}݂oF]" @!Gݜ9s\i sX?# \4 DVUUgm?k  @! G )iޛnfv '=m:=  \iGPhӦM{Ά96lv!4t # @FV$߆!ÇN;dgymp^G@@#+3gZ.|4ibwnvE/m=EB@ 06 DӦMsCӁ_8f4: `>=Sv1Ǹ!(Ŭ@L fnvxؐ!Cg'|nS[om{ HwyxPQ@&|Z$]t;|x_N+:[n}&vsŻ@ ҆ xIó7nlڪI_Æ 駟6-\c=kuY D!@h!9}t[z@k(~РA6b l~n@  q9~ӟ<@{NqC;`ַnf͚%\b5Z/ :s-\Z|UA@@S&7o͜9c*^?V^mr+vG[֭m„ oۨQL[_ml^xz@ȤhJ?v5۷oJkMo' }~LӶzk7v6f{Nv oV\@hL"b(P"+vۙjjjܢ$9J;w6}^}gx >j @, 5w֤I0jɶPAٶn/?~;X-lٲe6|tR7!~nfkM @(_|X^i!)>UUUn^{>3Cǂ swyg;蠃쨣r=A PW&6^5Â&HZremQ[liڵ33̤y]|ŶN;5y!=EMnMگU=mڴM6]Is̱/>=zWlO=dCuc%KzI4'e[@ZJN;:o&/9 %mظqc7MBS%%m~{;lѢEkً/w7wG@ NqBg? v\*N=}w] oEUonC qm۶S)Kdljj?uT{njDE6P鮻{g;n kaÆGan@"`>"JeZ{T* 3m9Jǎk뮳_n?mF$@H[ogo{^F== viQ;&ZĤ4i觟~:>/m 曻-bRL!L4sAd |>+eF~YN]'Wرe ^G@;1 :}֬oe?_{.]F{es%ݜtǧ|ɂo@(Z Ck֬1eW+ӖG ڴ_-fϞ쓶wYpC+Es5~8q1b5t u>zOO4b޼ya{EIs[l[߱cGsQF"(m /U/[%! W^Pe]V4]v TqjAVkF/XݓW_\s{v 믿-Т8~xw+ .9vO>^('/oVU z~{3Y(G`ɓM=PԤQ <(φVhTQ׹:O(Zq:j(Uԣ%3Qǩ+vժUb [|#BHN+yC';Q:{R u.8}\Y[,oR*}oZ=sWG_뽫UGSYDR1l_^/%&bӸq\: M}s=K>N[n,P G5-Po@nQHz? 4{9xC /`?~?_=1Yf#}{_Hd; GiC9m`d>\+8Yû҆\Bz]piuٺ@IAQA\>|Wϯy\z{2@}_N*/jhX_d6З U_UWsSLIϞGYQK4Yy~u1zq N =/ouL?LiNФ9 N/%6ݰRGyiAҝwz`֭;4w'?`ڼ]?Z5pusז6a?0zR֗OOzS臲srU\Ie&S@z嵐%WRa!5l#XQ,B :.UCq\߮+ @of0afF7xzu9nnueQRss   fUcj^т !i^]w冮5!mƦLb_:@@xxz!4jC Kz[t}Ҿ}{-,O8WC%%! +U4QY [u뼺i´&3ןL9Z@ʶ)v׭=s@jd(怆9yJjy"|\  @ @.G  D-@u ?  1Ќ58E@ @Șh" Q F dL4c Nu@@@nG@2&@  @Q#  XS]@@ jШ[@@ f.  h-@  @@3T@Z4 @@ ckp D-@u ?  1Ќ58E@ @Șh" Q F dL4c Nu@@@nG@2&@  @Q#  XS]@@ jШ[@@ f.  h-@  @@3T@Z4 @@ ckp D-@u ?  1Ќ58E@ @Șh" Q F dL4c Nu@@@nG@2&@  @Q#  XS]@@ jШ[@@ f.  h-@  @@3T@Z4 @@ ckp D-@u ?  1Ќ58E@ @Șh" Q F dL4c Nu@@@nG@2&@  @Q#  XS]@@ jШ[@@ f.  h-@  @@3T@Z4 @@ ckp D-@u ?  1Ќ58E@ @Șh" Q F dL4c Nu@@@nG@2&hW)cu]uU6f̘$#A쬳βO?=t nwuۡL`K]EB ^G>jjj2A&  @ӧ 69piHhKZ)/TH`W,s@6 @H=lV* W;vM4i3V\ioիWڸq矷s7YO&Nh_|z[*-_ܾ+b{G?2Ս7h]w5N=T䓜I@jjN, 2q?@sܣFZ_z%3z.޽@ᨷ4>AM6n8cwk/vm<"@wOUA}uԩ-X |_{tlV;j:^\Ϩ)3?tߧ3EHYKGo ׋˥s=_@>iOz֫W/ݼS \aZ7UUUOtiႆ_{5;sK<"@4sҥn|X=3n׿u{g k+vɆ bM2]v٥}i yO:$Kr'QGZ1A ?Oܰz9.7K=$$HW'tW)m 9ӭ 'f#8 7tKO< r9k׮޽{uj&QϨr!!@6.3gwy섑B-@K!Gf8i跿m{M[<@@Ò&@hVJK gʐ!CoݺwnZ%z?@}*G(C@׬YoqN#  A@C&@@0;@@ TP @@  @r  (@@P@C&3@@P   Mf  3IENDB`farver/man/figures/logo.png0000644000176200001440000031047113562215674015445 0ustar liggesusersPNG  IHDRiCCPsRGB IEC61966-2.1(u+DQ? RfFiI<ͨzo&V*JlZUJ)X<359s~={G4?39# gݵϸpBb#SSa*Uvڵ*\K@U9qJNy[MIƖO{ Njbs_6(8݉_JH Syt% jffZbx&Bq3cH^Ɋ IȬ2 5/U誌v|.݂¦e}ZV"SeͳMpvY;pz̈HMhk_(=D䫮`w|7{.gfL pHYs   IDATxweu9wӋ{fz"f0  H@ 2rMS %HlYRʲUr%Eڲ++QV$R")QI1g$3<ś~g],]J$ Tׯ{}ޓ{]Wk<|K[[+vor}uoyJ>( ~÷w~{?W=Wv b֟Kb[m| VMDvƝV$Iq]7k{{?{|b!F$j~b qY؋Ǐ={끟/oO7>/F  ϡb 0&OZ7_vof~k$~p$_f_o۩&ZvLA#V"G$1Dz}~AQYf8 ZV!btm#lOChmmZMEy}t ҩߴ+}vi3^7 Lu!9U 70zF4ai7Xaq~/*3`&'.mTZ,(kL p :DDGl/fIZWo>O+yvi wbbkʹ{qSp5h"6 DsXԢ>~f~Om09ͨwD`!~]6_ ܇ZW>nw{=3?3Bct\"@Ai/f}Hg! V?UW?`\ĪM(JC-\sruy_Z "B)wB Ze7Jc|WX>Wm7*ѝo6pBh G$ EąpǡxM̶2D{F\qW!:A8FI>$B4כa-3= V(#{#R_Dʋh#׮Z/ȫ7ݶtw}w_C] ?ÿ?o0 aAKDm# @Rn^c8CDrGS$E\у&!E@|xq)$bav,ϑL9c":RFHuWĖ恢+΍{#]cW>l_'{?8v8v3dAFL@Vq)H Ii\5s-JS*A庈[xqsy EjK4xfFHFI\w8M L59#I@ #@d55I;z/ܼ‡9akEPv9bXÊ!b QC\.%\;w7,J;EdԴyNE$C}EpBڰƨϑZ |HuP<YLZ<ln}ֈ(u9r)<:ћ^x+{m_#*3ߩ/V^$wbŬl> >Իesu*TgaD(D9D [@Bd5EbjDs$1$>FNѼ@F_D_dK|N,!r-! ⦈+(F,0_4֧~ "ߘ ு=NO{ķE5xNYHϟ?JNdjĝFBJ#r ta@ \.z9L$o 6Rƈ$vh2EB#tFCzt &ZHVsU(E Zkg؞T_'>u?o8WѾydGӰ~,Z(G4xĦk'X?"IWZ4D c*iSۈn!:FT!# #ѤQHCj1 QD;pWhYr Ռ,3c^$*@\ܼ8Nincj/w/kcm;}l_{lpAiOYG'`i3crF$sl@lceG&%LFF3[ Nۈ*#DMzq{pQ} h#>!e(Hۃ$!-h-(yuQ9?D]Tp ARan]|m/?'+=mK{ ~'~#,C kPVM*uR$"i L^Ar1D56D4Et!-@#! GoMuHuR"6bf蚐:-7T#4h|݊D xNYr*.M=@ttU3D}ui<{'ԧgl] eGzwN*3@4GMEO쀚9čݬ D8F=4oz IzH2B!- !@v皶b H FH5EsHdn]@[hqAuۏF 4CSEKQZrɋiC\'\L\@Tbq9y7>vJFۥR5eGUsx@,!ց5FTȢ>G;װ{iN>Av/#qD[e5|p d Bb>0#dBL& "BCI }6֚\| >wvq K=+pn7uzo7weo#GO J'OLA"mp'App|NK7NoH#⇨̡ ơt$ioT#Qx* n0Q7YЬ)&MGSQߙC?[e#h4E6 ;4h&%+.<4{#qLq8mrV8C$&'{g%'>l{8,' jI <}̷PV ZM:Gt/":H#hE(P9i !tIirѹ,=e/"pKN9hAy4[Eh&QPw)"<},-衃V56U "|.j5x\L_\sK>ɏ쪁%yV嶉]A}ӳƓW7G{駭@T)A|kT1d)2]AQDDb]E/] @ %|胕'+r aDPN_g aJݴ<5įl`4-oM~{o~vC诰W^KuP\/qOOOЕeDu߄EƩZЪF- .H2BUh%$qh /qքˈۋHc&ُ´Dwh'xow>>ԏviVh:&H.D hhh(P=<" *1:HC4DI}$X(cvE뛫AV}#m!zܧy9a<{hկ?=QA ^:W!u91OzK?u"tNXu V(<*5Ѩ@DlVRBpךN>4;d'$Fк D:E(0!Gm#Dh|7"l QDXGH"hvi ]F 4=E[Dϡ)Ze̠Ei5m)=D8E$ E [k{g y1fk{k R1)Z|"Lw^3\{?][vH)]܁ঠYDgGru, Up30Mи&h Iϡ( '9)qh a4 U zH]A9*4R?$[:x25v@$7 2$_Fˈ[Ea=(D P^ Y$> >H)5DpL2H%>/J`Lm?t9 ]vFoa^&D!ה ”X=[,%H݆TI(YPyj4>$}4-stF@Wfc=E{ҚGHA$^F%GJ+H)sN"(CZ[B87uH< dQIHUL@ eU@5=nix !Dc̸ѵĩ|SNˠkSM:  @K53N?9){ _dmCՂv1Qp FjKj@PQg\=DBf^Vf:hP5Fh" ѡըhZ>Z[H}$>D euV]ZF6R]F H}:xgB>cRnIo@[H lCZ_B[g,B>Ѵ޿̡6ZW&LCK(G;^@̀DDcpyS3PW4+]L9v28aCES7΁8NƓ-/zKo>s u^_OuOtir)+j@O9;|2#>E}iqb?U$>FQHy JTJ43C['-$] _hGe~V1RA oSAꓨ#H| D&dH| iui4}N: }^"~V'9JGC\ DKӺm&M{lD\JPT8f"xl vJL"B%/֞ 1& HKǣo|8?sF9+Ѿ Ę̅Ofqy@GOQ״g؟-iXPP+̠u@|kP`*% 1p:A[iQ?f3&-!RUg1_F6!c}$ًJh6B/I49dkhB9- Us'{n7P' (q58oS K$#,ƘQ)>󓞚$hmһ룟/|eϼ}CC6}r5A} Hh@$:l pmbH{c2TO5DB5-TrT'@H4Bu"j :mU!qf#E-h;h]Qb?Z5#h}STE2N"zi%k7^)$~MvB!o~rSPz@\s˚P9E*WHS1"0LcäMuYM]A8]5O*$S$"/G^;n٧+w~m·I7ZQD G(VH QV^24]Q!d~.^QF$:$7QzzctF ytv mB.)hG>D@RXA=HU C?ԃ:bnhۨ IB u":4~!E4ًdxhD{GMF)I@o݀X{ 纲 h]}DMss϶0bǴՄANwvi͵u*dlM D^0o󞛫_R̾|=pau8f-2\rD&~?b=*>y:@4>jn/@[[ ުV@&c}dh"jG.dhrq}m) REFAE0#ZDm?Gf1͢ # h6sHrDjԖۇZ1Ae   $ h4\" p#pcQDSL۠}9L)4|)&,hq>m[P6T*W=S|nM;x?ȧ?o(o*=7X>7_*>pB+E ΃'b9-7Hl )▚w R{ė!_!"aj sim#d qcm95BRA4@]Ⱥk\@}h *Z!r"R"gJDHZBA (AC"~|P3G@eN^ *?m79 ۴B\9ir';li !bmm 0l1S: w>0˥3𹏞gY4`jU⦽`D:co7vۿ!=K{:x'IX"Ԇ̚ bY{1~:Hv$TrA#*R7E,;@9Ѿ贏c"4J*yFPʊ )\ Ѳb!"R7-㈻t_!Ho?<@#?AgCDpZD T}Zj*hY0˘˱H1W@p XdΓ-]dԀw1l6Ũ{CC9`)Ƭm`>3Ļמ?¿W+xYB[K{&*j94!g _yڬ)A*D\mooc&IhD)\L-(W(4GMD&4T ?贋#u ںAPuvPer.*>G؏5뢮B"jPjTgx ]BM2$B[GVm]@=a/ BG81BմHR@p!|9ڂhY nMkH2݆uUac 1v0`'k"V r[#|7ژjF0fhOnw|-}W|ڳo:||xAj7̤1RLPZӉU7h22Ey)jC속2Ft,3H|A^ )2vBZiE}h\.CP?Ey6 "/Bf^ &6^Xtfxlc&c/1a! ;"69OcDZiP.bU>MlzsbzM>32E2 \:6X]V;~}wW ;nstM!,0[= p,gbH.f)|@kv'h%EN$%ǚޗ"!=$L^ ûaFr"EH9d4H/ HGZ;"Յ@·J+Gu6dS(Nnu$A"A [ϑn ӐN>tig.ΡXՇz%>l#o'%xLf,bz &Ob/cG,6NJyl[m`c /G%DS|N0 5p&1낏:L1?Ƙ$iv?C۞q9oJ5,nZ E\7Ѵ2E$i71?CaPY$j13 W~ZhT¾o!v[$RC[-t&RDa}gtɮE2CGREumĝG]#,~Z Z=֗PGcaXPهHJ u5DdF#C"-H5təmrV: VWPC3&gA4UQ ..#:&~<`&bb6|6 ?]Š>VGx_}LV0 -'?*owN|7\3duC<|L ,9M53 F7M/;w7ί3J;[rOV'o$@y [?sEt *CQGB#HArF;עG o ZB5o47p`o!¾0a$Pr%֐8G?G ɗd7@Hkd9h5].vpQX= i@=mBY +kBUV\dnC&b#v :*t+a20?lāy O*gu#/xbw9uTv1Te!H\QS2]Mk헿q6cIq=#|}FԞ S%xkSd\B".)p^Q o%Ie4B$dh-G|) B HMMH5lb$@ELLd dOܵH5@'B^PڈތRtakh $$1<$] w"i^ sQ!X/goM X>Uvȵu]gM#L]]x+x_cf7Wc|,+Wq'A70.D)Fb$ +=_+ ۊ՟;+V#M |MN,_EZ7E;sH~#kYs=M@ۡ ~RQsՙ0ģ*5 $ !h#1+D ;yC HA-ZC\d&rj$:H'L5+mˈ΁QPm9U'n DH뻐 H|Y=*a z`&-i[nAY4,}-"]`"& kNоAi1 zխ0=c_˰u s'6^Ħobr.an(u~%lX}_aL1oM?/0bEWg3:EX0I&\BŚ@j{e{~,uo+&{{E|/ruS_'2ua5I.?ւՄju` sHDBT, R\1!B#)s)9JG@HR$j Hڨ{DqȠ ṯzQX˨433!.Q7?Bǐdd5A*C4ªPPz}{kB.s)qddI0΂}Aր6v\ϻvm-`wc%ȇ?,Xr`N1-ڥM_mLCY_Nj~z_);r՝S>4xLxzRV_:݉{~i2?z۾_Wd4>ԏP]j RY\Ajlhޣj,b%oA`z#|D̡6I6hAYCa+_cxnVuYUx?ȕU\me+gX c{9zg1O Jb4??enK S_7?_>× !B`UVO@=e3Md\%}ABdePC۠X 2:kiER)*G K 1C)A񴺌IMp% X>:`m ;([Ţ1XzˮŒ.O0w5n )ޥx'TW äa5jۡ]W J߳*9}i[ C aA6f[{}Ӈ>_zk=7U[HBy :c&ehavNބ]8Cg1:$y"ZGh|H}x kDsIC4cDDT9, օ@r&K h1En^e{tʇ.QY@B-mY$Πliym_o3*{fa+=~zߒ.HyѰn,fi\#d4++\# X؋T~z=ɌH [HH}}X P} @Aȫtd H>E R_HETtnCbJnd854Os y"d$:[6LQ4uo!GHqTHGHBq h^O}lsњ|Ej:6r~D>XvoM;%=Wߚ0;ɻpV٧ B>CcK rƇҢ3} ddy,jDNiBS٥3+Q}@CF+{<>m@f>Q4Gaԅ4\//G"{Gn??l&햁%v&VvdiR[n)^}r:C ]vh{hiHg",)7HnԼ&ҝBuOȂ@=ъ@'oe R} JۏdMבi}JHxbz:B92IPJo}UBDh/@bP-ǐZ!;7o3Nǰ< 0)#- jWm޶y^uj!d@בb5 Ȧ[KmOX7HS!@D).Jk\ 3H E|gY"2خ#9 MM2>s,Oaז13!>2jh!>‡F3 ]OM9։m^Tu9",e%99ci7С;h$x,k 0߃7a)C}ģx 6a0A-xKU * n d9!s2"k&Pdf(52:$;dPsmO!Ǽ3o`֭_+uqf۝7n߬O;^2G4QR<2!Ct )ptC;$J6+B|/,JWx׶#иK:,goD  *cFd@GPvԉ-"B% D; O̘)fH*R~U(M}BOMB7 aLf3*]| O@ޫ0šQ|lY_--|葋mQʏ ~5(*kuǫ!YS;ha]4(A| * fm,ņt%ty@-c(wJCoCyxIІgjAS1VMd "CCGui-{-Z!5umTO@dSs 4 S2,%9#s6bFoz 4?@Y%t4k*(SK5YDULc`P٨:=欙3 24[UDj8%7׿wO_7c1?gnY~CC\zHc h )GؼpcH B";o!ZCm:J҂ѼDMkVA;'nɦ" k웦MzV^ IDATe5A*Kq aZFRX;$Hei0 `0=Y;Oom*,%E`\ڊڅ=- hN׺vXW$9nb4i43V 3We1@$;(<-USH>GFhSMaP(ZC>c/ +ڣ*ꪞE^ei [lA4.Agd0GZJ̫d}5{`fiH)=iAg(%RL=d&~GA@b9Bm|M__zpg~/O(yZ{F%BS@Bd)PA :Fk.zUB"Asr9mAh|L! R46#NGM":'NPrkA1uE5Z.,U$^i 񭎐"tW!Ome[ ,x-Kz˦<¸i9מ.T([*5b/4C0pr=2U ҳȜD"̆ ({(ZQN!5 Q!HG&q eg7bϊk&O9c$Z$ gFJYG2/}o_/?рܟ?[y EF# PΡqxɂr7DmrS@'P7qP"W`8h2 lVtm1 ($Lx33K}Q$3nf3;ԧP?.2?Bc%uvOP9Ad2ơcKpt)+EST3"j*e{Gs$ȁ*>|8)E#3-lMheD 2J4=A%4'rmm݄<6HԜ\X gZ 3/Eq<>sEPk PVEm6ʘs=KL+K&^.]Zo5{,Dvׯ>b؂G(J(K frt2o_/ί㲷?`;?T=*ıM=_5$N 1OyCN"-_G-Sh[8'j! vqƆh8hb+ (Ĺ*>2#̊0DA4JPJajYWC$D3U肃N d dAd1Iqh1i1&XBri9DEKZ[SJZmۓ(,Po]E2|4+?w^π,…Gri`L>EB \RFk=EZmmcnDs :qcabctI r fLvjFcTE]*T]lxo/]Yl#L=$=$JϪw#BYpe%G=2`*ht եۈPжѯ|粷/ ӢB9b C֚yY`u ?̆)2b߄廄8&ztCBۑ!"16&OdꞍ~u)kіCk5kŏHKQA4!G}C4qH~CEʡ@}{ 4Z!Ǡ{qEH) $^O L"CȲ ^'+hcQ@JdR=׷-QZLC-ͧ!_GrabA_K[r#v\a G#LW-9@=VYA mZo 003\)R9Ryd+0U\S26\*vo4W|(_9)GZ4؞nYɣᨹέ̈́?h_ ߢX0nq.9q0iȚ1dfh!8GT]~x?_O_lOfJa;;@ P В~ H4@8]'O*| h@ h}OU$?"gh3pqR}d*Q]AS`sq\&{ \-(&3^`%D1};G?kᨳ#0[^SU}PWp̈zb$yr='hٞ]b=±ܢac`ud]Tɣn\=y0>٦k|g" ~IATkpgi0OJs Ɩ٘?p|V&ȓ m8ہfבe ]r~Hl>GN5D ۢ ڮSE[&>&9@J A‘}OY" H }d6Cu ץt7DhXC4]4̐!f:2ň'5[bXn`|܄H-D1I';4?@mI QaDsbN!ylp ϟXlxtC>tC+{،8c}&{6G7geko0ԟO y9x*P6Pf2eT^pvΈ.+``O0 Zx (]{E*kϦyCsNtqK z33>= 4 o%>29#[0]C&'O߆ه2˄\WCBdF 8AZ5$9O-P, 8N0$xjۅ|tEGgS༟-=sI \룧Ն}*Kq^.dlR y=q+xbP{A90nv;0z}u_ K<-J.M9`utOpg@9q 1f?PRئmdtzs4Gh!Ci_E;FTOw{H 1i+א0@O3I#?D7 -5e.\ra(M:%}?!T $ܷ~kf%BBE.p? ɿG!4*{Xڤ{H6<.[ɠHyo[%ЖmKDU6 ٖ kf+wH~SQkMFe܎q(, ͫFv,~MC&װUǨ|p& q㲁K ֯]xyO}tX!@@R_>?\"ֹ87bA^r\*&7/\PB2t`9*^2>/ʓ7zPH(u[<=~@cZO懨zz#VO_zc;D'C#i"-*%}2.c4oS@]LE e}=4 T-:Um^_b3-,KsDc`Z-P\r ~Ɨ ~R}CH3 .&hF&Zj[9R\6X"1Õ@Y hEUY@ZY mRmql t]hg-Pu``  vMK--t^!PTP a cX'FhP=2By ,CzSqA55BH-Hl|6hg6XfesB*SȚA޷{tx%,":-l-kɍ#t+h hz[Q @@3 /Fume&t{)P_m2I+Vg7(w}#D sdtN wP <;tcD EnasyA<(_YO!rk8W@Q#Q(YZr`Qs~x⪹ 'xLP*k7y*j1dDt̞Q3Z?jՈ`dW@ ]ia+O mf ݶB(HcBL2>'3jMSc$1 ڎm{mvh. /Pu. qmKvbud62Jv &{: hu$M7X@O[ѰVOǫGH {hS>$\FWN0<ʏ؅7Av H{vM6\Y+hV nLK3gݼDH`10#:yrlK=}U:7liaVQO:!tyDZuphd$P ($n>5SXxR pv`&kVzKdCTOR2}44`֯::@Oi>3l5O>-7ڗNN֡޲ÁPV .:ن E˶: MDHb5r hIKeZ>鋖{P졒MARZ""AC߇H*!=<4GHb,(fHR'vtKH߫ K(Vtt GHCER[tFl!F?-Y"t X^Fa"P-$m [J*+tf ]BwjVg !il<ע>Wz}PRN1CkkH6i!)g!-3rPϑZrDL,oMB!;? ic/W)4AJgʈK4m -&X95>3P{Td. IDATj{ey[3'ٰ:@E 9/|.v E 5h9eF0<he!l"Ś-_ p6^G~@\@r[HmJO/` >vd Xݷח=kLu'WrYHC:2^v t5#sF\A44@IKh@ǿ,s &'P!=ھ4{&4 *En54\&v`&ԍ{ CU{ r4|# ^4Yz9S`ĊSvf9tWF޲=Ed$-RBK6a>CѹmIsˮtn* U6 1yzab49d^1s@\~t/=CSg h{ҥ8ag:)}/ԤZ*Nl]{`ia@!egv7 ޵/ar5k{h"_ ߃p̠H9;WPy).A*W!ݱ._*H}tRX%!*ªEphC)O1dׅ6`kD-j˔j[ H#:\nߵFh6B{| Yn"#XYZ/[=2 M~>8G]٢)w+ ?Z7hũ_| DOԄ{L!<ދ.A_F" %J4fR3BM_' _% x@LgCPhNZOY l AI 3`܀SϮ'bPT'*xاT!lA-VG.w %ZVP[ڝK#'kk@j {&GHuV⟅5CQs2Qwl g밼cD{v=ˠw@m-jAfȒl1(2sk8.|t _[%t$hX@ݱQYcΦ{P @^YE [\4B;Bڄ'PӖaeYh'Nҩ팩 ͠t.[6vVZ$;V:+o=1\zqG'/7j;3djPjjP0$a>!=%4 ]tH>t:мno4w樞Yp4V}sa.@~^ L<=%oD<2M8s/iX+7U#CNۉEa#ZGuX4ʝamriO3ʰjmD*%>wrb=†֋.תH.By4O ͌Ker2!]B9",m%!&B0|> _"PmB='V-< ,O gFXGR@H&> )#C Ex"B8҈Eċsm# SOH0u)HA gH=BʈOm0)jG SHx`o@KCSAz3Ҙkb) M6,bvږss $ ߼uq\:(=gF1NK`@m _Bqb\V,k^j("8vi5lc,Ŏk0@^Bu 巠!}ƨ f-y!hA HȋH{KmO!ʩsgH׀ -(:CIN/Mu#"֨/#(r_ 9$#PH~ɟ@݌6Czф#hϐp"ZYC^"f ,' tK$gTj`yr:PAWȘcT)ɒN:;K>;H fH?fyY}3\uyf("j# ="gb!l@RK,J$v7dwnuyasoӾ@w{y^k=yLP baǪ@:>VUZTAj3Tb 2i֡:CD@62:0 Yդi1I?j/PsKyUOCF,dkIgKx,ѿ9Xݛ q<yXBl=%&Qp)7i B]?j 6QTu`xE }FCa.^p0}F+hjp34VhP!v !1J?hfX49^WR~q<`8yUUቕ7A=K kטS'&گCh%vq{.ƨ#;gx~qDfI"U!'d LF8+†Je*&bCjY=JM[LMxN{4'L8PEh$FM}h4&6a ix'\EgsR'kLA䰓HibLJԗU°Rnrdv6QΑkHHkz nsHNˁ [hj,=FŚh2&_U UAj(niV{פ*Zr}8(~̸&砿 prRh,мP@u vmŨZ%T/1 TO`tVܯ $:?K0{S"Q o&5^F[hPwps`!GZH`ym!VU/eoXOAdC8V; ~OO| G{H o =)G^yxMpkV۸oeitHj@/Jeo[fY_G2A<"zZ`VR\/a3+htF#-k]&W!_a%l֒:ül`FEOuWSSri qՅ0_aɥbpi ȎPz V#pl561qFhO)$lB:Fͫ@%8싖%(Dք W_,]0lJJ6[T=T v TFQqbJ<|ڪ6>;X6ԝ3>Pj*`+guP-e't^bmBiCT$R:b_mT<؃9C:y"ɝh81bć$^MQǜ)Ǽ96Dɓ>4-4y2d?EObdði(UC4<L0Na]}:_6 #dgN |`HxމT:9<-첗a@<@|[;B-74V![+^f]R<[ 5 S)a?T֛#")crxuPXXq}V0#P53hۥn ob֝bCiX 6*HZDwP5cT*XX^AVxeo8<|Bpu? ߊ?D_;h&l>B5 -փg(#ѳ@}5..v>Өet+4ÃO@4i`dXƳ r)_M̽Z,WTP9K!+>\^&#]Ds4&Ml< l&iz6{Ghqu3uh8Cyjb~? _bs}b] 6"pq6W5f9{θܜ,Wy _:KFq\JPKz9>zkA^FqKO%Q}/`H lza1H'I'i9I*)Ɖ|V+Q˳OJwWY!jWH >fZafGNW ִX 2f 9滤H?%Fmn6Koa&_bkC%VG]`2,us6a?Ba0j)mL0EH (rn Sd#m: Ne/0VXfV'T;1%C /BibP}fX{[lvO ygAz4-+;!a~q"?mpwn@c 8A-f]`]pJ5jDH&,w!Sv0Y:7+硉In~<l}:AJW!rˀ8JYf jy>fHg^Pu5jhbI&[X)ij#ɛ3└[.xG&;]κw1Voch| Xs'{Zv/$ΝkTͱEvC_`!F$!vZ&}l<&ֿ]V4}[5lu[bHMz:EKZ b =fhU"G586Eta<`U(jٳ@7݈RA*ف=[Q^A*㉥b-4AO{:z P9J?Fu4}1VOPXcN1[4 P~Gz7K!  /P9꟠.c&VQ!>B mPPח qx _,"; ZjᶃawK;Uo '5)7PxRf3>^V.ѡ`)ife&>˅dc/ / q[@ڇQ CqIɘT I}J:α)w$]WIsc*ir4)gM4Q}2/G0yUcX_lOocs4?%u-X=7軤iVVv%Sl=E]=[:"CFH+k s pWa,!84nZR0l7~)/ DB("߯ZQ$(?6wJSh؋HәcXGHЮ`:h?EiaEfVs" `Ǽg(+ R3G!= J%OCb+j~4>H邴8"垤Kjiz4`ƻvwyq0E-4zY瘷$}+eRTaXݘXz bcOM^0_lKXN.`_bxTa:,Fy& 0l|f lw5*Q"DɄe -sCr,>rE՛Av(^$P떽}xCud/Q bLoX{ -% T}-l7C Dz 5{PڨҕfF*6ڥ=Qϡ {DŽeѰ""x)xr9ڊCn`b`0rK5 $^*nA3*%&piz&K5X(߇1rp}gP=A j%|%l; Hۤӎ8)meiz8iCx||ݗE PM9RekUͷ ocêDBv6UR8 Ȱa8`Qc3lgq01 #4X`A5 /Y-rqY$=s'7p_E xHa:"m 'C3Ҹ@Bt ݧpZ&v1+> ])QQX[ !i5&4fiWp1ZI/dO{[Ԗ'!c{`w䴉yv8q<;ltNu 1>@6ɫszdmlaRtaPcALt[g:VX~9Y@ Γ VbHlHDZZq_rx.#BPw0-d P' `Xq/+X[&aCm+lcm0R\9<,i$PV_zo佐 AuvF~c7d)kKŎejvJ.0*cGkP_9t`ݏ]dUhށ|-hiu/|wPU/и¦-"~QoEDمFzhc1>%>&7q@ ~_Q-(\M&c`5K "x6FkOWc]|<\߅9op ulx~DC?q嵌Xe tPWTh6EFٷ zm,MjW9l4j[ml=Kp#sr GYwG?曘,\+X(D _f-_Ca5zŞa;MҮ+*p 琘OK[ RCl L%pư8M¿dtH- P nm.~61-Wm5L?+AY8t 1oS4A+Z\pdd;"11!`U< __@3tȜlQ^-^W7%Οv ɬᜂZø}^}vl#'䍸0wC|% < pϰP_[|0u|A wxnle*C M3J:uhE0Q~'W79ZaĦ4!UXhzn!%In!{J<#_BӁ}l7Hy5.kt1^"|?}A'Xk I$. \/u{P^ 0{1E&7` zl/]|x /'<;R,7i9| ; t֣8>lclir62lhvM?ëS X \5U%tdZ+ՀH7V?CC 2"1h8YN0k OO[F݄Wivc'|ޖ^v*YQ*X%RrW^s9ˉ`h*:oA3~I`G.?5d[ʪsB]}kCU ۨj-[QCyZ\-Y/q6+_f]n(,k[B Ъq{)Q}+>)b#H7HW.yh1߁&!Ϝaz^P݋57fp < =@qVb !M’}? .b6ТBzMtFj:4 696Z{xw8 υ$3Byt5T* L+^ٛ](1Wл(a7/1`uBqW1K/+WBۯ`J4GiB6.D:j/Q{9B} ƐmB5`=U# gjJ "i-f,5arw 6 } _0G Чleflyh}Iƚ f7[)l hBMh[pX}C!Y0[ ZTp>Ǵu o>@p&̡GAϠe\? ^ x&ֵ3LO>"~!YFw_ǽH &Z { 9CQ7C*}ͰA<fbs6[ X4~nbNg(w/-Dj_vp[]TQ1A\^VXZ!Wufa*'|3ixBGGXc<̑up7P~:p4R? ~ jbWjZ/3nM@Z Vh|!T2:DS?.vCIc44d렽F? a&W!-`wK 0ܾt^6?ǘJ%"V0d5}T~PC[7+2:D/iGu9A73ޯ~\@6Bo&o*CҲ. /bļ밅C{CIna3lx57tMϣɽ[ x߿*ܾIv pAPRKe{]]|MR;nfSdc|_r!XAk1[·c)bn)fh =p!V};#F`BgST ~VreT< AMsAur< <ء9raixRf-NOop/mBp?( 4ЌƨjGP?LJZ-4^ k8l'^FD\aTCbeT1nw0kWq2CLUÅƘ&Q x Ó,9kRCC? Ɛ!y asN)a%r}=b>jNq#.2m-ڛh~{zl38ͥX=9>@7hyhe$ -UlP.WqPKrWOJhxJ)~QvC)q=U^W%?D 5\Dڝ⑻Ɇ.p!芬B-lWq0uaVrIʪIShrP .NIG)W0~Ԍzf^RB⽊,,]i'DoR ȶcNw9{ xm>~vjgz90^'4w7ˮ&{0xxlܠ|5?}41(bkPk=8ay#ܿXCW?.Eڧa)(VǾʟhNMBq ݳBؼd٫ ڍWo$E/D/G~׋*#<捰˙|UVBMd@Q%BX Qn6 VQea(hH3LA{{l9\f+ThɁCP H`|=v-RuRmRM1 28#z0B0 J| ˿$h@ E4B!>CjM]AZT}' . \atdrtd #8ߢ'lpA*"bJ`F 9},>V짐}?Ƹn@uDX6DT1x!|Ld+эkqcG"!"Δw]Bma1QHHqQ7ZOh5FOj485nYl=t A'T-0蕹Tbmi^ЩUbW!!]~R] Bӿ9wF4U٥1E^RKrw &BuC Lok9`i O+XeO=r:śp0_f31|N'=C54.!{6[(!&!͠hwCgP$ N@>BBׇu7 6[n".41L܆B0&4 q综Yꔷ.fRH1ׁ/Ss?:ŘC:t$v5QYRU꽲?@JHrflڇ}W?`݃S 1Eca%ԆMuC4Bys 0u܇;PU T SP VQFxѪd {PuUn\yTfEAWnQUFO ƶ9z/0TÄǦUT'^Ʈ1?&|iT7~:Eu&uS04*QkupwA~k+Ƈ)P1k%rT57CWooQ:)X2Z*7#02M7dj-_ܚqs/;!;>Xd'k:ilv8Z1 -g(]DԧЬ?vtm4QiRr_\&x%p}y\ gIKA0ƇOP^GOF'qg[X2taq".,+Th n^9\C9EQ}QV^9)(A4gx^"2gAxVft TShF7y3/qVoTac>fգmT]ƚ]Z̎(fhQySEZ`+fj+`DVKUwR.Woћ*+0!/$|2P!~ʮԠH3*.ek;zR.aS ^zh'hKkȊ)AuM}>R.DbUzVfp葏#"+_#8u{{]A6"!KDG5*qsBmphB:J렟?p ߇ˠD1p9n#ܦ`'|6T+1=H#ih=dx!^8y]py(Na[C4g<+%ܔe"ثQ_:"ʻJ&bBV~M6Kj P \W,cuњ 9f* @Wbѭ1,6Fi Q} ՗$D}6@ U TΩGiʤ/_bkY{X66e(vh+JB4Lecmky K9h@J}1htc0xtlkQ}+WgynN!2-j kztTF̘_N`qVxk1TwO@ϴ;]IH2Me1ȣ{8C(&b?u\6,Fg.c\GfC\c $ΠPХ\KDxjQ ꛐn"]`/p _ٿoaا"lwG[No!o,JQvM?[okYbxY9VfUf]UMH%ؒ 6d ~?h64 R!EJ.U]ՕUYyg?:fSAV}vHFJA/kF=oRsu$ jI>3 CȜ2r>,l[:?:͇<ŮXIInܴp. !_#P)gL%89'nܷj &SXERvxSc 2}, IDAT;|I"fnLaIAb-XpV"PB:$d>R}\`O{8HҰxG#2j:y7bIkHz!5 -턧)u5(\L[LVjB{ޗ j@Z v3f3v\2i 9cojey2 T}DN64;z|vL7WeFZ" 3HK _l/gÁĬO4F1$l !bx$~0{HU8>:ht xFR,Bx[fwzـY3a 38G=wr (I!q+D 9%e+cn`BEl+5$:Egp 9^]ygHU{GlC#)Plnc׌t4c,\p }dg'r  V3W aCЛHŏw{mEfB 40 ;„?p`0U2ֱx O0x>f+}% CBD'"h4p"_ÊKX >êƻXdž簡6z <N"HCP _MQ;!!9ť\OZjY2KS #d೫8x2Tx s|Ad ēd6 xjH{/(}$IQ`I^<=⪣q9M>WsRTfap-gjb@b!tY*"CH~dd?Q$W)PAjGBou8ċHT(bn 78q!fyHXh(sԂ;>c >MaOm,0 ,g;4aB)L~G˘1S\>x>*Gf{8 cuBSĪljذ[pegAN>zNѱ\A- [*Gi3Lpݸ)5 2V'i'PXj1cv,> 9՜=zâLTtb@s9 Xle9eE6q ZP4x{PAyUĞR:$rKr̙jsaSz0*bN~,2Kf+ğc#u=`%"cW6}vՓeځX!Dsn]u,, šoD,6;X[> $Eb@9[o3L8|@5(`&l<r w!ət 6c/471tk}fTS,&n4a.#D4H HKhg.Rl΃BDe׫)uhPg3Atԇ(ܾ֟{d5,eBM(߅-({^ʙfYRgjFspF8qhGX*j{g..V\b L0kai -#FVmLo6@y c!*;X4Q0ibH4U)#Z= c)Zhqڅ BqF+1CFXM7'WZf@nc;nk]D`45)̆vɒM耙2 k _۩] S4ѽ~ ;j?NG,V >E)?#lA{ӧ_l#UA,2Yd+gZYH8V3. jq">;1ݩ3s|ӶLollyL9`M >I#B2H4f cvf3 A V!aP,wS;űj!!ԸT{@l DŽKVW8 n ?867|(ۼNv_r?+ } rFxwHjGhU %޶[קyqK?ŪStbUK[Afr~*#=>zt;tE͗ױ"ayX6[t)w0m,cq: ڻ?E >]g`\U @L&3i7[F6 -cn?n>!/в!? _Eu[ GN]B'a& ^PDB0A'<=0ٰm22¬iRpqU~irP͏ड़5?i".>J("]hY32?.ϐʃ'7-5v")"]6z,pg&ȬW+uVsA,_C)ҞkCr&Kh`44 VYYOCcyIbmBRѓ2D*>!p# 8W rx0B퇜fXyO…/=g!_B y"4Z}hXG訁)TFXx L4b26|~TXᘝQsgkfx^|tP-Rm`16 >g`9"!4 t`Z@R, Qr>/$.{$ G\==P3Jbq.$\ ~NfLDpNHr,pp &v;-#9!g\[񻿾bۈwU^srn7p49Arq[Owb4_kN$3[wJjcH僮+YP8Wci|41aŔ($uߟT q(A܄8̹D8t /QRh_9^@sX|e.4CMϼV栝x?!t \>+4!F}atF{-e`:!Ad(Fqy Kh {,Q ,7}*[Am!n V6)cX #=B1CA Bȸ*BU% ZH/'Ak9xcޔ ϐ>HY r fZI;׏yoQ S+dϨi0*B3,"{/{Y^\IHL:k?rϼ'Hn:+K']| d5h#>&*PkwoA-0cv<->}3(FAxaXz88xϤ"d;"2ga/M9^BvrNNI2CQqBM E cCz=BKFWBSvkf=JÉbUW0DU:P;ԏ֪KYC篜lf_'ݘFg_9 rT>hpůM?5_U|Pv``>n3HX#> 3BBo^9.V|x1_<"j?M:| Cf||2vt7/o~C+ak^>j!ls@;?&IEW)e6Iwv Po77h^+'{xgl||d=ՐOozSUQߤY`Zd>elXGeDǘa&)WY 9 }|/ ir=1Yz\0Od"\||7BoL=Ezcp"g;9b-%)U4 %(p+wqo3/oMGt+fZ~*Hul4Pcc}캃Ls0|OMSGL+/* _!r3{ߺzO8 ̓pŗkq` c>uKϸū*?[ro tFW.k$Ys{ ]8tޕ>p؃jEvNfbYb26VFr1v0r +[ΦI絳x$OI$ Z.Ht0čta'8yp?S\ {Qb8\>2&mD(;D9Cff+Or Ȭ=˔d]&sS%H<'> iz~;<{;0c:O Va3 ]> rwT7:Fh+,a {qb h=`'WN EvטɥlSЇv(*B5'ero)p+O) )]Q7(XV·)gq/K!t RBBǸ{\My^=dzƾWx |gFz{=zag%Oz@ǁ&WvIv%T(€KM~"<7$uQ4Jn//=-!:ExzL*GZaaz[ظ9@"ne~@#-.}7]juiE5^JWIHk6IDH$i6ƼMvIZPUUhX#9z u֟g}t@SqƧ\~UWzaLV7oqwp$6p=HXP!!̸9XQa/Cw64Y"#y+> \"fuvWbЇ8F Η-1qYk􅙨5{vOe]\H8~:HͲ=>Nx 9<^9wLgI HlUU{5{ dn'BV~-Qͳ_<Οy7LH[[as~ '6', IDATc Hm_tJ̷J޸tiګ{:*;.44O Yۯ]dПO!3${qb)33XQ=c[X{I&u!jh\"јH!i")A #$ ).(R5]:FZ}9#`tdV`3QjM^rYZ@HK5Rc7,axQQB)`Z#U;9p[060(%N%$kw \|"PUմ_-^r%w*nĖ"}@,d*dyO{'Z3uuAO b,$d!ҨuPc2PhkT7w_Uz"Μ&·z/ny0l?!v؅χ,x>WhP㝋߅ey7jP5d4F"ħi kskUѰ{hF &_b(5mtdKkݦvr uu${S *)'82ѩmc2VvНHW=A"k>B7xfl7lAmN8İ3A3K+pbA׃Waߥf1()WoDOX8'VLJVz6Ђ A lҸNY]`T $t @(ս\\`ݽ<ᣝ[ݣ(;imvv򨚅 ܫ4Ys1njskx/MgNNBB"pA5,Hrlw*LVXgqa86ɠڂѿK/E9gb+ߠݚp|?Zi`i&1qxn̙|3(Ǯq~ Ξf2Zq~&8"PZOhۜ682bV> (*& L6Id$Āc82t0v1jGA* 7\wrC*T%;,zdw4Ɖ;p@yfq(w=`q͝鵻e>x=bޗtNM4"DMUq0C5ʙP#>v10e4Ǘf)7NX;sj?grf761'?Dw59̲߻flo_2[/Y2Lxԋ'HfIln k V #hEԫV 3@=,&XZ:I$1>jqRfJRQR5b+7b+#uԺ6֩bOC@zWjNL%&` T3?la aOٖj2Vm`q0etPdG@!!= dE=o){a/-+^ڲQt_,F7O Cv]#@}L/pVLy/9ix'ɽGT*+~0\z*r&מo"[{ o.9e_[NJ3c9UIidHAeʶ=ޒIPpbv&&2۬KXH95ڂcrw`dg7>+~XT=-U~%AToq 5L`UcK* !XhX-r(ڋQJT^@cTH#.wI;1+IV#ɘ$<*mR ) Dcjh3}Zmy-`st(fg_u9TC>0&"MBSVѸKrlB*fG@("3maJυ\~f"z KE;cH}2>'%4*f[Lj[#3oQ@[R֧b]`K\0/o !pE~}~I~w˥ׯɟ8-!= LeyƓ{ElǵyUW2R8' ֞}R ~-'o@ȿ .OR;; Z2eLCŕS[4.Q~9\8Ɲ?Ҙ寎`;(ϙM&b}18w LT;2b^:U*_֥EY~Ո݀67r&fB -mD_XW73̸Ͼ^c{s\%?tExmG<}2Xz@_>hX+Xu9*l!kh)a]la1#?Bc,%К`e* =oRF gIM$6|1,8,--jGfML܇ ;`י;3zYX`X q!$fM7^6wDdtEN P/!EBq@¤dIO, g ,Hu;_ȣ))opK^]ake5?.t /s'өriڼp/ <{^[dt2%nt{,;[ȗ@|/Z9o{={ց&%8{3@=,52 o:mbUOh /Q0]lt6g٭@߳4cL6rrAb+zXynZ2Dc +gbYXb %{cR< E&Lݢf)F4")R#?G4,yYV8rGP`2!C0Ƃ1,]6CVdfB{sKGQKq9=cBCBVCKB_ij]5IPac X\$x3y&,R:3Ē%rgȲ83Cj9Lorgj&n<>5IWIv tVmn}lZ¶[M[yc_sEessgmq|L@m&E|CEҾ۽N~"rk2U>&#̵'"a޿{MkLpdX[AUaVDZ0GrRv=x޽|&:[拇H:t'ҩ&͏  #*T:XzmWc/+χUM'Lvm4,@})6Y4()l.)7 <4)ȁHu&J)8)N f_G&]>8v|4&U Ê -hyUhTZamVu,az֙b#Ry;IGP&]: b%c\/r=gsSF0]Ԕif&aqavbfLhpS|ӖCe}=C[ŗ/a=n]C,//A/g=^}-^6d7׹ʫ?U&Zbu!R#ծ[%gx hu IQ37fasR@K>_\3z>y΂\>}Wy\MtBۗ^Γp^wν_|3? ߺen<ۥ3+z/PϠMcT+hkmcCkXl,$;qr`̶pˤBFz_]qs$y+o|[?Dl,*Wm<iepvA{=!I1mz'aJ P{49|P$GɘN ip˚ H;v/yCa$ea4!+TS3)k:o30C{Ý[\3*w/7-.CRCmDfxW?-A8:8'|ipuN}:~ #>Ǿ>Q y(~YPRi"xJ}|/8|oe|6ed 4`k>^8=w/g _ywᗏ/ye+_z,PV0V/ai7n>ּw>67oՓ@I8k.S4XJySЪ!/,}~xEKOkA_w`M[͒!韙gs79q4OsGu:_Y0Jh{ȻH>, F?ˠ`-LM?][_Z(*(y/?KoK9 r%` ?ʵ+Dˁg?3Uy}=!|_=V^C|kh556bs}lx1,%:`[uچ_L)UXuEZ/E;(#tX)@UYsX@:,=w@bllΉo'93,u! 7P*bcfVeeP+$ (֜.>[$.[~dkF52%"z٭ $3HVa1a Z=]9炪^է€tRij6'xLz[)x͋:HInݜf ^p}v`\Qw x9 Yhi޸WM&OɹǼƫ %=$~' Ud_أە.sl/-1?;3; ܅|y;4Uw *!GAg[pvyGk W7W_"f>y?B29cyQ0 2ZbFf)6;5A[d`T7ƃR2favȕ y|CrsH6P'5q_|K)P(ˢNC*8oz ѺLA5o=a䐹ϟ6>>3g3Z^X @^hIsW&>b{VQ1Y-adXdl}£X>p :{SWȉ+ OP[D2 uW ˱EdN>y TF袡 IDATxsOY9vw7Ouct԰~OPf"Z]GPHf쥲>U+}?*c#qof$ߝVX

trWCuwG,-ҭ޼~b"o _&ûX·Op"Kָ|Ǿ[j"!Ǘs 3I4ik?Ԍ玢ʏn}?;|E퟾3y\Vp~o/`cy, EqpKX3՗`Ⴕ߉gTG 5d;itv>[멧=b*\"i\$-N@ Lcle i^?~70Kwd}k'9l>H{vow&cs/i,c@.tXzs vgV1,5#Du0\cM]ӈ? ;=k!Bmb3_!ClĄFZ/Ftw^AǓxH Rk&Sg3T8 94tL|%#.8xxw<0f|z7L-06/L'p%N9pēxrtѽҦ  ߴ|NuG;v(g3WѝvXd}tRU-Ӗ"p*Kx‡,p/Y=qiaev1u8X[WTgO:z+B#ѪCGG.`Cz Nl&<WYyC_:2yvNӨM%c= k FIXul o}ڵOqXTV]B{vp:Ə;;4vawZ?C=. gPYܗZṃf wHfp`xUzR=a}ӆ " d`/_+^Jn*)L+3g3־{Z rd؏0 zp䈇O[.'G|<08HU2S$UƦTPTѶ-{H;i?7C>#.XKP$B)伻>_wܔ.9ܜ}->zpcAQ{U&k4mjo>Χnqb !{Xߚ2n=VՋ>b<ˁ[d7gp•Y,/:'HcԎP@crsL‡\c1yOn1EpW]1 fի<^*>!X1ѽ[ZV3 ~Kn>_bzwuPeZwX:^LΡ< `ߍ c2o6poV`ʶNJF44_$K;TҐd\)]E XGҸdqIVUZj e6qK/Ճx\&^,^]ѿ`3AS 3CNm $F/7SqT ^9q =a$'(-WP};`РK? 7C?@3sl6lsIjP:\d/bRc];`AˆX#:[THǭUTWxiYg_d?PI<ȴ|K(ZO-X[k )\?T/dT-E 7$E ѧ$DzJ^x4!K)ɑtN RiyHikRjj *hi ~e )^AB6̃_,se0en߻BHM5nֶ$ *A>F3\үf/qPf#ܺ vhBpN_z2SbJ/n.^j8]"nsK%3?1[l}['[LP_By PEL`:Ѐh98: 8<.ev΀[P[B3TBof"TITly+D(!>H"U3RoizEQd 8 ta5 K ^>)I< 1IC>D`S@sюw<~NoL2}TDJ/<$v2]~+xծL) R:~*$$*ym>Qѐ|Db6gHrH߳(ZƘob,m5vQa*ꯠ~/\MR)J܉޼0ĺ3C}{hȃo:;GFxl{ AR1u ?m8k,>,YĆ.6WXc3ꨀ !C5m Pux5kx& ^*hM>U#L09☩CW]N7FE~K_<-7UC#d8a@HsH4OIrx&FC:'#*yFj֨MQ #oP=Ϡшy_P:*oXjfIuR[&v'I6sC-:RQgd?@w9:1HF&}RէrHT0(R4`R1DӤv$!a%0ʖF Tt0ϟ UW㓘iL(/RAG^׮o>De`RF84i,ۅ4| CA'ϣ:;K_*KnF9t&1zCr6y{}{#?x@> =ȺC&r܍v -6yϡ&cmtc?AWwziRa6^ug>%@[3Hg)/%Cd=STTKImj&-*@UCoQIR>IħHX T>+Ȼ<6Uj/P8ӃG]Tz KT;HT62eNƍ]y>2 [E9$oEvMwXU ⛈"r`g*C158P4jć<:YR :)n>1.)sdx6Ԑ .+*. ď@6AOi I1‰YmiJ^Sq !ΏH)+8!x-eL&XNhc!ڽ&GG^zF'3"z\j=m7nww?Oޜ'wABwyyrwмirr$|tu0ks^z#,s+M2ұa\`q s HII5Z^cr2^_43!>aK`^dIw?'ɧCeLV +BlDq9}eDvZD~dj i_j]t2eK IyB4 !,IH$FN)m4*VE\D`z?2Vu(':-Sl xZߓbP.mhyMA: bq/EhB@^Fzt‘*؀NIkqeI dPu8w=Gsb{_ [z0prc]~2-c2bcd9!Nb/Q9 CrGm, Cy;o> O%y.yȶɓy{FZero .vPװ,< cLq?Ǹoaq)Ȭ|>pnP Tֽ p2VIPkfLB86yH/,Enp+q->>ɍQ20%0R+ d-# =DҳEL{CD73AAb62:"ml/}>Dt]蝋.u@HK NA|lZpl )cʅ꘮ ,@tLf~ϓaQ3~+Iz@M, h7/(MZfRA !.U \\Pǔ@R+9;ܓB ŒX:Gmt 5{LEb6ɩ#}7 $|_;B yghGGٞ70 * 󺴋էéai{hFop}-!㲈qXc,ML!i)ԋiFtY$=D)=!p' ?ߑȔl1` NnpBm g>U{,"|6Ij6K6CTuy ~JbHn33d)I$#Ԩ7w ;.EϧN{B$.IǦq>Liv  -MvJI7Ӕ gƪ< 2uL'8;%(H8\9m\d/.@%ZøSå_.zs^v,3ͼSSu)(.;1ºul˫hD{`uh19)j}T\7hEn~BL1 <?ufyj =L ]Jc!b>AZ^Ac!2cD&pi%tFRت2%E[$U?7*sREIm!MT1Jy-7H;[+?#AJ# HObvؙ͆&(-F,ƪ4N A !7#=6tB;*K)qKv<)&ʂs.mα֏|#Ċ$p[]ơCH҃MԶhmV<3{cYIq#`ආɶ$cm mV9{^ڠj,+?B'{?A7.̑}=ퟢkCS&4@n_!O":J1n#T^E,'1z ܿy ˸!^\ڣN'21R:(_UV.̗6p;?|X>./Er?d X;Xd hd$s${ Ǭ\B/Nd:,q*yeo ]d!!0 z%r}_ K:GEd\!-v9l=LѻS: ]/PՔo[^,f!TRw E.WA6z8asB <ƒD&ǎV *X+D5x'} 5=J$9EOB[ LibFX !wDI^FG#ihDlOCF@ƻȸ#ǤA"(f(Nx07kㄬFD{  6:5d")"peW KerK}0:b'?Zڒ \zy}NQBqߥ)$| x?skCf-޵XV,pCml9`vS4]4zI>XAGg*c):ɨ+6 r6hTNUGӣ0:I~CPUSHW'uDmN! GY :J1^Za:}륲~+x[[tOK'i\ςK3W$ޖ?qʽeӇPG|.P z U@셃5@ Q #ς/m it2^D&3HO42@Ƨɱ@`7&XբY^ N2u f>­l)U>S8-O =suvsɽGAcx6,cMY^ ƲMn<$ l\`yB 2D¹fr`)|v%6 >fO!R uA}웨ZSh"Z͉|P-dF?Dmg(/shh5BMKh-h4)lR+{j"],[jTC琦2?"308 "m[ IDAT*Z&qxAwAw?x>w'tZjjz#1%30 %.k'FP̖{!4/j63Rzi .2&-I7tDH-d4tR*12x?[plUg}Bd#c35H cT q bt.vu%%XfhEcXʨm6 'xk%\#\G`=K{B;j(tQ/yc9zTR1 W?ϩ~<' ׋Yz[{C aV5hUcCe.*0G!W hs\+jQ=2ޠ'ۇhhlE4_#O29ZmA+a$tcc%V$-8B8cV#&eZ\03kȠO@=iQf&phpBpiwq9:Bm}~Ala=&>)9vVbPvwʩ2)d0&O@Ģe%O6im!##ME [@'AH"{HR#Fkd1bi.24Q6ܭAqD#xG,6CﳠG!Гxzt=- TR,JГzy"CZ}6ƭ|AO]SfGQpY<ا*’拢B,zUPWzl>`F3)l K=Er,zm:-G/'5*%Xm^G{ȮdmGh %r<**sE0ePĈKlӕ|ַ[d1Xx:<o!0 30snu 琪.L?&Ӑ;\{( M\!ɫ!O6~w"1P"H䨐 ?; y!f2A;Rkp"ud#vHZ!rtٹl=@WAz[HTB mDiN2)3^@yMjbȠ)cD)A{b ʅL]j'Ɯ>&3 $V1԰¥{|!cKW8#fSkJf1 rs+^RY… ʰjKMx-WAof"'hU6ZGur)S d^C4:DǏ޻ǖA0_kX{Oc=]Y9 7&q2'"OK !@:~7QJD K 'l 0 0z[:^=E&sx&Vg,`ds`2PwJL`t$%ܧ.>ˁy ykv@ `? F2>;i"CdgɊ֑wtTDegn=I[+mL|,bTF*{8$~êǦ!['>tt~ H8v娈Nr{ŮY⩇ѐ},=#U #ȷEzQ+# x+ίg翖Y~L|9:矇q L, VYih4>oEۧCtj M];ذF} m}=C''B8xέs?džw KX~a^|+C KCG1> @05x5@+НB&`H|h31C˽U#x&a"{1b/ޯޫ5-!V#6 ަ\R!4OťLi uJ@:JjhHgHZF>AKH9sɛA3,8 I)VqfzetPI2XDU삤&2N7#iHb9w!эmDOa?W6S$[$dG,qjh5K+XjmFQ L0iP zM:O+czc^bY,ߎ%zfoeYxLJ>>ϧZȲT)U8L"<83\# ͺN1ցe y n/#u7p9-&K_.d3t2n ޔ`jO |Oex~ { ]?mCw0%Bh{+Qn"@nrdɕ{PKwuUiJᐚь3Y@C/MlB4R G;Tuppy23boH%UY 3"|򵖿*+V;3?8=-kVqPop;ǸesVyiJ,- B}kUk߃v;>ѓJK PLjz;H{@K{G672cP lR9[!T(>F v9;T:UJvd/tX6h]B5-cߒ!/m{mk`ZhS'h{"_ڂZnhLwC|6_Lj}C3=g yJo̠ ]f@B׺6KX+H%f'Z|Tl Y\@:0q?8P3|->/h.: W'? _ú]`6=w9;%aBe:ЪQڀ^A$b,U`L+NX(bz:UNQ01ўa7}Y+2@2Zb7fvf[?3ϡ&av}Hw\9o,`5No?̨& AcXkִ!]udލ$il]x&/ieI )n?Bi lhZinh~3!m0WK߄7sVi\G0.^wЮٍH: W@;즥Z\f% i?ΰ4҈[̮C=6G-MV \=Q"8%jn!5!}vU^OHef8Gy<wpN~ْ9NYrI_ Ms͎i@23}Z6CZpB۾i\アy+qWS{q[D6)Te~k8?1ڒG ݏfoIƁ5Zh/C,=aJ-ezx޸ũff?vXҤH#n\뾥k:'/*~ ~': n xrV!{a*3rt ܂{{LS!ci77$7&1!شS Mq;!Nvo%Vo>͟Hw.b9:UG78b ,8Xi} L~qm[c(F% `!Hycjc(z:UiyO˖q>QyJ)><!ElB= ^2x+g8 <[h]fڀ&b#kLt!Id)+MfX9n32.am6 .`82޿J/fXh3!f>u/`'0{N M(͵(I8&GR\bD?2>ŒX%̵V{X9XVm<ئSmh7'Zw ;csRmOw r-% vRzJb*}4}'@j-Tc9M `W!{Cת\)=--?CM'WfU60Q0.i 2 \A^D8nHCLO|&cmI_cW$ڞ| <=R~E++//H=I nHyqd'Ԫa7.oO@ʘ|L:l'|Γ`sv_jkPG<9tzZzR){R{Lk/c{(XpE#1!kG f_EccCp\xÅV&luhRGi)zhSN5/Q^G`/K „&>>E䓮5RQmHǐ~.oOs[AT5=gTXI94̓Cյ K1w,b;c@+h '״֫MbV7X{M/ ϰ4Wsh7( W nmŇk\V1h,1_rIN1_F# x쌵d<=+-JIY#Q_`.>6oacVaPYg 8WrV}O.t,Կ`Cb^=:t;!ی*"M< QGJ.?}ϩB."O}Oˤsɀ=Rk)_x]zrDPz694ghv&i(zB"Jg"tި;K1Kemڞ6`kj+0b SZi_Kd(SXD^~tH|ʄX+h'Lz#|ATpm->~1~{Gx.pn# +4O$h$:Z1ߗ`ڈF5)'ЃD~߷ iqڶ*G+cǵ<~9i=iL1'*8N!)2 iq=(凞<{U&hiiבU بjx.K(§J!ƅVX+zoTohȭe9F ))ovn[)ZC]9'_L>܈pH1Ij0#S0F.~|!״XGeAKZ܉|d+_Q&o$C] E&kNl:`=KʏiIg}0kfx^iLcHVƙйmz;0+ȡxd]M5@Y[mܠ}Sm' p9fslZ2^T+^G HiK?%uhYU~&U{~_ A uZXJ8h5)(M`TQ~ π9)B JG6Yfv ЎGL=I49^oZn Kl[}c6ū; ڪJBN,]`A5s\:P1 ikdm |/0<^"zZH X;F &PN5>S]4V3d/"%\}or >ƽ8ٯ%b¬`v$t3̷rC(E. fA 7Ab!A89f/1E7HF/>&R="4+_Hް>]̚9- IDAT&Xx!_A_a/w (S:wmu?H2>Gqh3KU]vr-ziT :}&2^GX39b6͗UA lri[,*S͠׈? ~Ql4iӦ6chwqn}W4f!^*q,Θ*F6JB>7XϚF%cic%VgظR˨+̅||`7nMz-8AkZKt$]rN,O[eԢ: 1qni6j1F#ӱs^).t9ō+XqY,:P!TB?!y˦-ԗw{&&IjpH | ]|xE¶S_?Kg1{&:,^--5nk&!$!ʾ@N#{ZRT3^D@K:쵂.+xY2#nw(m~o1&:X,v4{AU8B%FtļԖK3HC 6 6Kh`,;KzlhʮΣ2وZ kGoZ,PuiZ(VoWi=̵R_ -^F50;tR19v ƱtHE%6c~xWS~ Wm2)!bGhd\3])ɿ´}[!5cx _!9^:\,]`.*Kbxѧ^e O(lsI<1UrPO(g"q 9^.dfhj{UTCd.*'tw3XE;*٠p' BKXq /Zb>Wr9V^`':-بVJ6%t=Ov"hq2JLmR)KP=lGYz3|PV_cn"cZV 0:]\{ZZ[38iڠc,^bǂ)Cd!vLu6`8؈4m]Æ)d=tX頜c˧bdC(QDMHaNa< Hb96v5W6 7w+&K`Oûlx,JWuaHJv--eI=喣<_Xuxj]ldA3̗Q{@BKwZ Lؓիm m`bIK ҄8运Nk{=^``3J [!au#+qCs}!tSQ=o}>kj`-?׵0oKĸA.ïn(={;툏O\r>>7=Ἣ.Cݳm.p 4G|a`eyZL[ S 71R:+]'=B0t'P`ݏtXu+"}90pHrDM)RgZ[%%+_IGX++Gf2H zt^ vRZKH`o2Lb^[?Zhuɚ-6kUW15ogF[blV\vnQB +gТfwet-LpOlOH; ܗJ`iKT?9*5'[^8ES6^A@w>wT56b٩>oYbegX-~J }`#BAoE\V߾^:z72]| c6]a源 xiiS69xm>r V[M1n 6|}>Y_CS,OdP6?CO`/n$Ce{O1lVKRF7 Zpj[&b,2}hJ} R%u*q  lm€oj/䓙Pϐ$*չd𙎂M[daK@h, X1X|@nzɸAj^)kB%2tѓ&s2E)& Ns6% Vv 3{r]Ul.=#@ri߲cn3,*dXavCYP8 ES=Tn)S3جax #ܞ=5<z6r78AF?^lNB(, *.pe xAGu@Y emcBdTcX`0lS| F+ c#չ!LKg$he :0H G,!V{Fㇶcs;P~xlL4e-4Ӹ--}7afאMv-@WkUS%vl[v[}hYn@fXX'hܣ/šTe "r, ZV NFu]6hG1q7&F ϥuW;PAwн(=jsn=?LhOnYvPP)K F ~} T٬:Ƈ >'+|ҞFDRv*Cϸ7&"sJbƋn5̦~' >a0qJu\EH*pz k>6b~lmhc&5Y|$$i-琾Cc}hyWnq*(=rrm(qx|)Ԣ+vPQZR_^x5{=YOWB,aIekqkggA~^b]%VF݉䲔Kjƿƿ%`0}CY@+E~=C@;ј.a;kCaxG0>m5 I$Wx1 >[Hx8G)rAg$ؓ'%`5dnSH(b5| 뿀m(X  vR>C$،P`8-zX>ImيuEbGVIyOBid^hZC|ǽbuZ Z5W,X~eef52;0eŲөa|%:o( X4j[~Ї?IJH՜: Ow=LY,1B԰Ұ֟ka.<8҉@Eҥx)i{AmzHܪY+l Hxz ;o4 w{x -#L@pʭٵIV t{~UBV2)>։fjv+I(x7C x$cŸyҙ1D+1ށnk螩)wi#5,7S50_ 3Wl V q=n ɳ V~yHׁpm_ߐ V4/I )-b@JM6" DD{gx=v ^Mz>j~ᅥ/no29f䕤%S̎!1R ` h_12=!=;WiCu>edʰa"D`]%UToz8>[/.;ku cn$lH& D!^sLRiYk!}y8E72D \L635>ćvn/7P A0SN+Z dj[*!*ľiedjw+b3gbjq=RIE ,gxv!rt^wuPp B 9(xx}ܜSut{: S`? P_!BQN!p~FUf[6_"0ІHkZ$gҢH^50HQ#-*^.܂Jޛ/`#'גα"2رfЎ5w 򷘏&YsQS21wW< `q7o|0~ #{@Woꉞoe$ȃ8@}|1v5mM,@2uY>º X xB_r⍷$|.щߝV_OO#̣Vp$wcۣpz7:%|J:r8+Z*;=S)p{b;Dq ~pP=wcO]t >n%59-׌4ņ3>f[WD6|=m)*m,0 ͪJ>6` `AL1TTLLQDo1v3<!10U:Dpb#xt$sKK_\DYeG`*S*ɪ<]Aǰ4+ /i쀵 KT%F hӡ _1L+[α^_c0 &A7߁|wIefXN3ݷ֊Q*%1 m0Qؙ l/uz%<ŭ(x9la`Vg\@>^5hol^3|{.9wx*iZeD,}Hϰ=?W*.klP7XBPG ȠXX;V hŽ9ިl+ ,ۜiEJv9{!UǃaqZ9zh&i1ϓFwzP!Ճ<'N+H>Kbn!Qblv൦9V|u#%;YT6ۂ_I++X;,ֲuz /i SbS|6eމ:USY4U=8ݶ1/kQø=Ң%/tW}̴: ޟЖ*ʇ1+Dռ^Pb7:\ayv?CڻU߇ZxU$=y ) ^xsk6ø\c }5&o-SXṇ N؃ rL{HKEBõ'B'lp?~ K| X~a..X{+|8ya|AE<; m|[lL|G-BϨdNHY@Ō*֦j[<]`fX0f_a~l (`|/A-p,Vfmy6ע\z} (6/EyYˎޮ1~+&31.v\evֆck(Nr* 2,~Dh|mH/P2M<,uAv{Ml_(GT\0'pns?wa1n~~/^ Ogʼ|+l Ըa}UD\aN>3H +alԻ#@} KS@9V2p(x'tx̑\c$61jZ㞥! ;d:ė~cV]H"YS)މxTm5C`1E2/cT[zjX- l i3劥{XǺ{XYAO㧒SuX3c~ wH'G{ $c{8ɧтeI6g^?# k9]*T/深3Yj ^;l8.w*_μ0kLK3J8[\k`(wDiysLٓ\@U H`Mރ-+-~gEkc\ /×Byx%\HC>z?eS}z [Xc@lOG$ϡ܇xw//JºUn_EjV6U7Zg6S Z#꿂~X*EkաAXA*n > z O6Pkhbb6 Z|K`G..=m=:IJfFeYkoMeŅy;9ֻLftaV^=Kn2?8 "B{a~3׶'Oud:(eї/ O!(;x IDAT!=RKj:}7A6,MkORJA;k(dm;@qoLIMLj oii1nς -\V׀ПB:X=En#=wۏ:Mdž]=O5C|QX7ߛSϐaBs709V} ?tc̿v嵲@gߨRsaͫ/Ϲn.5wPDm=|LueݰױHa+t.lWOe LkESԨg i ,n)0wAj ' Id.p9q΀UW-zCRFQ skbrzCNSlvwDf1ר9r<lZlA]G! xv`<62,*Y'F[ȼk<]%^!'xZHםx];?/|± ]}\F}ԙJ DWΐ/㽄^>mcIXX7Bw(ϰ~Bw1$ƭmgln_q:m`Łk@BFShmخggnN,IAYD+Gl7?gkAO*,ՄyB~B}Mn¹ͷX>  N"S9P7 <~~Ovka~FdfXC|Xz݅O{O׳X /lUBVTU[)>8g%PkCa .!܉HhHq) 1"YpK.٭a&֗1ér4ɚȺX(  :FU; /*ÛVit>j={ :C_7u?]ŏi{N>ul-!F;[LXyė)F$vpZTKHn,}{d.zY7B1įWT9 z ~ \p !{0>0T^ ez*drh&hZڴ3Ϡ3Յ=gkieAnT8"'*C&FN=4+ IQ=T.Ҏڥ=f &52}ܲ uCнG哰1ڃl0혂Nh{e>_́UTT3#@da;|+Ϣ*}ua}l՗~YU )-J$M޼M0HmhPpoavYH~ ɗF1'49; ղrFR-^`EN1\)PsɆe,#>n?3 ;~&=u]\)R[ 7bJ*' $ixphn1%Aqje$d d`#* P?ޝ74cLy1 Qe^s%mDFt'g쇪_/ 9[7 55Ԧ1)M:Qߒ_Je v-8}S@iN~h<@PvFWVpnj2OJCpߵreT6.xyeߐX">;6Eu^?g-!a,Om 443!>mߗ6bٺIQCށ2G4߳ymiE۬$t^3f ##˦o#6Ȟ=ySPL>tN{ɖ$6R2O_bg7hb Qy[dWk?oF)M^+w_&V>$Y' 70"]7f+"ͼwF:Mi\|Kna? n`S! 6zidl((f}pgmo8ox9Y@-k5gWq.mP#1vne?Jr1$ 12Y( 91{l(C{ZC@ϡq BelL4MWmPCbPW[< &Ic˴.s4P^\W,Ɨ9m]+A_y8o弴6Ok8VVŊM5[C1C1Gg.hU\AG+ae3I=)Hul ͯ!$hIhS4˨G|ikb490Bq )rܷ5QkHtD4{CvMH/#"@eG}'.^o7l~u8)H+kiwD8Rt+[Qf\Z}N.ΗL*Ol$Gт#If*I`~N~ z Ѧǒ3ݐ׈c%2̗`ACífm(vb2M]3d!&%l0;.`\5L z.лQNe$ 2Cey&ҤB6%6HD8AcEFj1FpZ@񗡌P> y^ǡX=f=20~u'./CvP_x/P?e ,v`\B˝m qd$U$߅|VN MY43;nZ?7vu_7w4g9gmq)X1Uʬ`@ѕHXAӶ<-l8iO\wtC~׏;:}`c㟱Ϝ-R܋4i2Hvd$n11q n\JI\^ y?#-p,.IZ60AƦ $! LHA?CBi(f4]"MZ@U¢=# {nQ u"㤰d$0JYqk% lVkc$A*!f]Ce =p@Dx pTOSJLnkDYF=4+,\Q>B!f1 M֊VXh#6KIĆb}~7b֛xwXL8Mu@fֻ¤$? ZoCsDeb\q`QjT36h8vb(b-_ ok}hs-w8|d/?A.ζ-Bs=0#$N2"n Js 疑l WM^7iYPۥKG['6l=[qx㐳;ZĴk3oM DF~d &L0ICHص~Z 6ts{M  *oun+Q+M$;o}7FD.l q߰qĎs?Mesj& +vqZc}67@3\݂(J 2C5eA!!'CKD["Eie"&-@@]X9ٷcӰo 2yfga  Ȯy4;g eegI ovA`ƆE]P Ŧ!{գ,*#:h2Ҭ;*]#KaIjDl%[ދ߆7d` b?&s*1}e^۶tزOIJ%62ZNW߯!@!MNlj[.Qix4%CԍloܢJpKkK:CV$g 0 !@16vYl4;cF:-[uľix94 tEkM<6gLn5͔2Y${W}džXtN멝.2Dz9['Icl3߾bSGeR%b~>_hL;[מQ~HC̪A!M|ndT!{/ ^ Y`?m.s{Cz M$2 < #hH$tT]SKv76uDM/K"~ɟ"n9_K+!ƤYHrsLNG"czY:AJ Vj"_ArUxuqFM$UuPisWuHPrC›Sivzރ"qnE&3Õ| FgL,蓸G4|C 7S朁e{-'s ʺ_R\|wغtS|?+*V7y7ͧ_&Q"-.'s%šɩ̭Lpn=i\jh]Tp.ql"#ڟ+2Ѵ8N?N()g2 Cuw^-ER 5.0`@j_XPg] ^ tq}C0AZ4Ғ4aB(Ɉ##MM4'1[B}nܕv$JH@wۺǛFu@hpG@Udh ˨\GuTWff jv*U@:MT']+4[F~,N+ul[G /r$,#1yМ8 HJj wf%I)•˸K2ǘj,'m-W7"adZ\1=rR "iŢoMuC!(HE*J[i/O! it}I>13{0uaPOpN){}'a;Z+QwWQwugmfhwG#h9'D&Z(1_B'JC޲b86'ibs 'PI:BebDa惭rӋR@<0z`nd۴} :RFo@AE .R4C\,])$?+B:;rB=;`2*[lJk3oJFE=Oc׍՗_R흛/o9#?a`D"ۭ$H'_`By$6lR&.5[ % SHCg4"S@JL+iU]U${V@ ]1S4tR(lņ_يaU˴.Tꮡn FMV u )n} w:Z8@]I̔m=4}7*Z/E.rXdhѺgO}[CѷݭϬtFs{7иzolg5 'o@ " 0waZ9&NgL֬;= |R ވTw¢Aڂʑfi $qtwq9\9#']@_[H"-7^Rfzk?o㟼̋_p{?½\;]{Pl]uVmey>5V84~1X~1.N¸ >H}o}'R!uaGue+ĺ@d]C!Negldw8a^=Ei-i# $aweSrʻrܗ5>9kOm~?N$H%rzS40{e<+3K~ih.dA2kO3uchˆ)#-r+xՊIs*&nMu'ނX|Ztm!u|tu4EN9Z/B=Bm2b\A≾]m~4_%zwXsEgwg%qv_7Ŷ] ͔ݯІIͱh &$ssPTC؃p`lZ!a& r89,lbN P\i^Z 2](Զ4̾ZK4h:Sv]N̴Lq=gK@87`1/ %kRuQ\e,9o:K+Ow|Kg>/K9_nƣO̮={7+ LѬR3D7ܦP0Վ[ X_t sc d"@\d^%.A9Kt,x.5xq8-4AH+r L>/ a] IDATDB%eYJ-9oME 1(Qh33t,HMK,h884:3_Ph}( :hT Ad˖=NCv܆yq>* + K22E[V]a]0  '4Us2fKmMT˂ѥOAP'ǑEH kf{ٲD@mxR;纈 ~^;Ov׎_şcNӗ|=W{g.|۳G4芴b:1ݍ,FSz+d-%y@0jm;P~%[yZ.2.~m^m3إL+IndI(5%CEШ8C&lSTyA}#+D_]cΏ8LhӺ O{IX[ZThgP]&h4RjiK ֒tOpbT=\P+öi5)x Weh?#Υ`m,~ؓՈJyD 6bcAZU4;vH"q^bto| riE!0j~dgFw~˟|揷\ygW]h o Sa6sy_!!m:˶qhY:ΑWHVg)R[pǜVrK `ګ fnpLlqL$$Xz&2*%wr4}  9M|b fDL ܦs JI TF.9^<_2-?oXb0[ bJG}!YfzF*k;OYs$ ѱEZY73N^r{P_c18""aW\>w~z]|'Z\Ï+O=Q$S/p=٭IGѨؽz]Yv?bab/qY)2kkXn+Sr xfOϒ-+KcD+}>#cby+6(*QD.qѪB+fhL!MiUeCMmfm?:5*~,Y0)0ѹK6'T& f(m-SC`3%S%7ZU Ezbk鞟ЂU͎u8EKHVrjg~W~㟎_pW5sǦϾ{D7&>([V9C`&]z+ݾEI %Im> ^ vӤ;gUrA"nSVZeoGA_:UKA.MY Յ*O54C yM994zϡu@X*xuq)x=bʌCLG~sse#6Y6V9,q.6(RME EgC0 CjJ ҳEKh57?KI6ؚ#a0|K`=C+i8\b@=tϾSOOB'W$ݸKGt!(KKN5;/_M魝Ƅ֚ڸu㻕5p ̰˄4Raҭ8$yc~v6æ.Z Y& 31QPh^91U{I3)G&,EJ59[}P}Q>r+uԪ:`9!t>d8@rֿ ~W#.ڂEfVV@?Ƨm c@BU&W~? CL!΁ ~$#(\wWO ˿缢ܞOy[L=f.mk +Cv.]"VnbOMg[fipg>B<qħ[ Kx{,)@mvklٰnVB+ƙ >e䭔W1s̨{Ʈj! ѦUhs,xn/1eAu0 Por#E@FKC + -[1$nɄH'ΰlmF)&E['ݾǤOHt߷iXfN9`/t;\cC+0#_Sϫ".=Tԓ|ۿMU6m _WZۈC#6۸BQxn0||uG)hƒhx ܅ n4Bx-5DT짠6OtsKY!VL)6AܣzYw !kiŒ 3˴5hd{⠶mh}#v VE$!@Uz ڔ6؂)ѦN6¼uθƸYA>oO1RΦa(OMuԍe'ЬBnz`M7Lw%2eݱNH`;#84q{_ z.ë֐זpc}?3WM?q ;Z#*oءfd@RP^;^tW$WY9KE 3 3CX@, ,=T@Q(SNF x/#D--ӧ0D+mO hvP"ChZHY07MTи0k37{FhlfhabbnV^68l12Xoq!@ F\>7y6gmTI0X%9Yev/)>go82>WTSP6LKAÄ0)B=h;R!M3U,ޥݫ_Շ8nϕ?z?yzHij ΍k$фt=гh|&GTWeTQ nK]N|Y{ PLt˨[%qG$ӨDQr(Q:RU77gƭ-ֈG뢋f@!j4-{zfEm Yy )D ҳGf[`2bbƻ+e]↞۱AtPLo^Rw{n1s}C.|V,q>EW] ·~.ΟN3ߟ!%V{DO {U9u1V8bH",MSXXwJ*Ӿ~@M\'s_bQ)KW!x$dzn|Ft|CX,0GDot9j106W|- Z+50q $oY+}w,huVGBFsOkm#iF[CUi=*T{#Ǥ (Atzn+-]cqKfP5nZ=15d_#k"g-Cܳ>NEs擌O]]RvΥ{8Ye0l~aTr}vXASSϥjYE{AW1BnY:͇&a[t̆8LUbZ8ıv@H|3!rz@s)eS.0{e#|ee7.(R)tiVͭϴ7F.Mk!NN sAuKlà9G|t#\Y_y.|+Ϋ|gws͢frRf1|!M]EoD*:kǠ37I9.G{ Wu@{ w힀qs ,4h9Bbq#b1G1kUViR]z8Ae*zdws=0*C._ņqtٴ%D[ gAk>AHysJ9Rt LL|dz@g+*I1KhL Ħꈽ {E]x̱=^eӝ|eߞxso>ϟxx#>|{6f9 Wz +1¡Y4?a@l ~QuՔz4+YT5Mv[@~)%=wF!E Wh>0Sq/Bc(3.ѺcyNv (Cs̄ly#9KHK<}?3uǘb ~ .,i_Gҁ8'P߅02T;C.M߬Z3FEZZؿEw4o|ET_5o?W>{/+{{Q'iJ|85il3:ئ8d^vhg-7-3S4Rol=p5Ks4n5bQQuvSωN&e*e܈ge h.[&V6v%]'ެQ:d+yy[n6y |WFCB .H q?xg vDFq)"_qRs@7iU\av0en2O4N=A]>R3z=~|w/w5s}\ 4X1"X-pʂoPRq|{fpql(d`Rcd $7SH R\5w/1 A3Ej߄2WWuذ5Si`74eZx#jzVFX}TV9D]$4E43$[kft`"Oۤ!C= Û0{vnL13,FNb`ՑbfzYg-^̻O~Q5?xɋ{? a6 .զ-88pXko OU]L:@}`IOCg :/S|E+&${CY>q{\a(oE 'sשN+| %Cǹ.̑]˼KąƸ5"$ӔfZN:]d%yzu^Xۊn9s/_l\Z'b4ArcYε1H6(m%{^:8cPf`е}kFBh\.@]4 -+IZ+2g=tXťeA!e*'LsKYMC ]d.[P7fH@;x3";R8'݊qc]0"#;Ǡ?b06,l=!{0-pyM=ׄMP٠ǟ+~ϟnϛ5逸;.Ҧ1#6  T{Y_\} XC7n["83B,.C _@)WJ?b lڇP=H#U mdAuTgȢ.71[h'Gf_dv!Yrd!dʍıKs-bǑY `423s阛/b:LIjQmzDfV}G~}tW?s%;= |=#iR04!1h\&jW:ܤX:dHE1q QO\iz)w ٠w:,$9"A nEK{9f4a< F3zHv Fb)RB Wq 8 MkHqԸl)OʛlRsdZLJYxXیɔ[rӞ SsNC/O\|Yd[_"۳}#[֝3$T< A,PtLj@v7d1 ʙ1rB-ЎIW[9i}թ|ꮘC6@)R?Q&FdnJ@lm% 2~kbd+~5G6Hqבb W4H>&[QT.C\"yW>\Cq,H&2W;snld4 5^k=4x Y;O_VW `O>gI/6/0fU ,ٞ; L]dzmeb@ ֌+7OT\+FH>#8Hϲ\lpM 3$9+HMU\N:H8"2/! p Lv!zD;䷂rH4Ѥi:/~>׶3~=[Oh{?>NMHmr .ulϓvq;?+6۳o;_:lGŊ::\jէh;d'ռJ͢/Lָ9{$GJ;mu?7+Aڕ.9BbbYok,]]@0IdlM'_ >"YW@""q$[ǹNboQmpqwp{q!ݧqGpp>ZLps4̣ܼ𻄹"q5D"Ve ):/6zkwG˶}g={_ 0zXݸMP7VO@p H0*91p9fjeu` P1.B]QM]%H]B5DkH!Np~>ǹ.^}C R7DiDK;@ȐF,_녹T%fdʎF|Gʻs? $ޏ4Ǡ!>^&oDB+[JT,l*_W3|<ڿ}W{tV@NV'! f|oh}M sI+`p?ǰ`e"foIDAT47sCa"u]g \6)33 8MqG%$_ǹ[&qUw ʇNŧq[kvO_e#xER[V2&nqt{?+ϟs7 ' ?qdi&Y2˕V8_0xhVEĂI2ۭmED wӆF{#N/FɩfH[$EN]/y6KRTNKg]$q8uF&Bn@.sw/һqz ܃8rn<4E$nAՌm>ֈȊp}"?yWT~.$q2.W K^>1Wy!q p? ^%yt}>пd;Y-/ӝ :kN)Z_G砹lЇp/*}7Ӄw_M@zfi fnԼg`7 F7jF6I"n8 H.8'mPM]6C ߰8K6OoSMW6Zުt~($egl>ٲ!,dVSTt.VY9ٸa ⼉k\c:36clj!4NCV**"D?m$ZQ"UAnVU%R@JM%RHMbNm^fό`uf5-r6b搠jRCY4ߏ!e~p ?\ \aU/Y,;gOo[lvפFm|{30-$AxiR~OՉ:uUv8*^?jBy~b "N렍jz8ބ?93 FLYDJmwB{:Rۏ$)ʸFuҢ6@]cg"ƌV0pf ĸu%K/#I{+c,櫵G~x3v WNA)(W\&U!w.ll3CM4*l  * ͻV3H4nd~@S:0y R,Ǥ&y)sLCV^dY 7n5{|>9Ĭ/MFK/㰭]G@Ǘ_}߼h1d{0yS` O  C^]T^r'޻bA7}5l͇طw4ukRIRqe` qJX]vTVWIKMHD)&(py3އIZA16 ]MX?%>l~Ov4.nߨ7ήmGM 2|eaۯ6G$`AE,q4 k|Jx+aXT]TB41Aϡ&k0`/fĔb˓l퓬 [-*ޯDŽ%B:1ۺ5)m^qnouY%] U*AZܳ9 Doi 2ERb\9G>u2:BYCIO(S$)(fd<5w{bc[&ᄏXK>Ƽރ*r#ՐO_`sMԮ5L@t GH6DQmcl 3>-q1:ՐahqaY{B yp|s_D^f}跌 ZrQXYz3 bj itH4O~bw2Hб 77 aרG S_?^_a˧IoSMo̖glxe*ŹO jIHPZxb4K6Q2?e.Փ"h@FMZh^nw6֤w$V0OĄ`aՀ6ixk_M则G5A"ih?Bo˳S=~e?DM;D'^8ÈwHIz3!g<{?D?& 4pYF[;@gCѥa farver/man/figures/README-unnamed-chunk-4-1.png0000644000176200001440000005546213562215674020502 0ustar liggesusersPNG  IHDRz4iCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATxTW&J `GQ FQ%nQb,# MHg˲:23{\Ϟv- @@ u   N@@ 9b    9 )7C@ @@ȩ@^-[jUj*VTɶmf[nW"P *ؖ-["PSU{>QbEۼys +]F&7@Ϋ^zƥIM6w"g-PV-۰aa6a'VZ֭[@͚5~2଴tϯ]691=2dMz~{!LZs@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@R M@@2 Ds@@`'k֭[wz(.@Z\@@ -cou֥'EC4L-@ȪM{}/^l#F<n?J /Əok֬C^зz˶m拲Q M( PڦMk۶ 0V^mSL \=(pn@sU@;쫯>}:^VfM4iRhL2 ̏@9s{Ϟ=EٲeW^6yPh. I L6ٽ{3{o9siq E@R(((͛[Z 0!M>=A &@@POgNv:CV|ySpJBhq~F@˩9;v霊+U NI -.  … m֮]]Q/Yvy7 @@TR{m˖-iω gR+@r"0ovlx?Zjoj g *6lh*Ugl潐  ^Tg 7nl 6)SxK4XEi@ȋz@۶mw_o=͓̂!@v M`ǎ6w\k׮eٳ)]z@F@ ,]ԭ:ݻ7|q ޜ+" (ѕ}Yf֨Q#=͗/@6 U@hժUiӦ/|nJ @f͚e,SeQxb[hy@6 @_(رcVʲvҤIYɟL)@vT B`ڵdСCVSvm֭JdOP B@3gtܹsӧO}{Wπ/rzm޼پ꫒> Q ^ wYRsOhǗ1P4J@J~]z]|?pl۶mq-   hҲe,?cׯ/6eʔ[X4čK@D`˖-ʕ+gMR޶nl`G@ kx>^a˖-kGy7ζn0hHj  ;β=X[z5,U) ޽5kyׅ .@Z" @hڎI= m  rh @z[P4J@B s@Uw-Fz, ߋ@@ wyrJ{7"oVа,B@ z4Gm< sAچMH@@ ^{i _Ws % Q s@cN 4{.";3mРA. ]|RGV\iD4 E1@!o66lڵkۆ _5gu[)e+͙3Ǿ[6m㏶h"۸qլY:u xٺ|lSL~jԨaݺu:uꤜON ͖," @=~7_n]S}v'۴jϷ^ze|Me_~}gnQjݺu `իWe˖LJxֵkW_b7 db { cy(pׯ]p.W|s]@|.!4j-쳏;4Փ: k߾֨Q#ZNz꫶pB-T] ՛X<]y.P[L+| _~e{W|vi UVt̘1ɓ^jYɜ4%A@ ؈>fz*`Oܫkf T!-) նO:oԨQO>v7z\ 3M߾}mkn&7gU= ~gm„ G^[ӟvnWޫ\VqR7{*)@@o~Md`YsFr/Yϟos6'NhUP:zUsw߹v Swq? 'f57Gyz!7E`Ȑ!nhcyԩz(;wnU 6?vg9x׌PE+DbŊ[+2A{mjժs}@(&b6[~ݻwZ<gͫs͚5nQ {챦9$]/v7p^UTm޼y9r)+@6msI~jO8N4i&Κ5M4_${f/d8@ h'i7| >Q55'Si>J*X\TEzJS:֏l wm7\*W׷C"8 ۶ms4MիWkڴk5Vס_V G]ֱŋCѤnʗn͏@@ ?ܗb j}رnFzAZۮThZT{g e?n/s9Lϖ5հw+rUW S鳿oHF|-] \Dl_Kʭ%aܖ&ZWuw#=E+$ov'/Sƍx1bN[&sMj]=^Xh*;ҽu^i)'Vi¬+PPz>cI*ޏk*_өm5C-.j^%j+Hȭg;!V j:WVZʊ34:shRN=T;CK*󊉊N,^gTf(_s!sZ=|,ף:^jY})0)sJ={t0b6㿴ՁnM9sҏW|} V@JW5)=汫ak܋?3ږ-[/ph% sKOPPu)Wܣ^jVZEhX;tyѥ?->Vqi;&i&*|KjPMOs5~iV"j_si_W0{a٤I\ iYغԫ@@  b03ĜLSO-4#%:A~񤹢mKrXGj~bm-Vٞ{zG;u .Ho]R+"=JIfϞGJPy*(W C0$(1HCOJX\@b>)ᄏiHH= MAv)7]M;̘1c'!)|^ZcM39x^*6:t[gk$UzT>jM(MtB.+3mR/7UAֹ$ҽKֳP@ nc%= +'Y ;ShbllAT|mTV > ] ޺|U/{|r 4tZP\v{\# ̔^ƆSy:ֻhWls, 5T_ǍGW;hђjkIO~ZP(B>yTt_q3=oz@sob5=z@s⬨AՂmTG-FVogQdm矻!s +89U'XѤޭY=h \&9O`]= p:nj4 NhU-[)   < ;KFSPK ?|7?2K:VS|=H{{n'V]T++S6sEZi}uylȐ!h|!JD@@~W )ƛ9zڡ2:iADzz6=^=G͛{]Czx[_UN@@<4M8NC@ h>9MGNPWOzDsG'H񧤭R#[fK|@@>{@˨ջGmk]"3G?)>$T@-׿ԪrR@צ@@ hQYE3&O4|mJ@k'@  X@OOj; h蛘 " m*GeD m 6KF;mSؔ@S`@Ȗ8}>><[" ן# [\oZ sξ5`zH. N`ǎ9͛>C=r欒\Po@@@lεk};+O8֭[KY_kJ /I&6eʔsuI SC@СC۷G}dx`` (- 9PYlƍY7|cV"͚2&_P"@|#о}{Y+رcZjֵk׬]%@4 JunUԩSV?w_+_|֮A W{P@|%PJk֬Y)O?d3f̰^ze%2?ۅR! 6md-?~gϞ=}S_ }s@-t̙n.QڪU+mݼΚ|,@ơh A@T4gO'-i|o#J @^Ii鞖C#3`D@ oճ5kB^bҤIV\9_5 y(& hٲeVжmۚIhڛ" @-BNsҗ_~iݻw)oY4̭K@H@= .쑜gv?tQ &HAj-ʊ @7onZы_l:uEv0Ѐ5E@ Wk|7ִiS]vYq~@h@\ ԩSjԨY:ydСC|"@꓆ ]@^ _;v{)_@K M@C^ n>{6"ꓤhP @5kfͳ۷gD1uT+_ŞQfH@6F@  @lb- @S 2ʇ+@ܶ TI&zso߾}Fypr@~@ VlY;wnܰaoӦMypb@߆@hfÆ 3 @O  F9 ) h^ M @4]=5G@ e V9!<iKj @<.^حOb3pC6 dU@=t…i]gƌ֪U-  YPSҥKmݺu)˅)5B@ kZY4sLW.<ɘ40MEA@ȿbjРAZ= @˕+!&  Pqi?5m=>զ zIV DA@@5kh" D1h >F@h"~OJI=͛7/ >h$J" z@lbZ՞lZl]4YGz x-P $z?M,y  4je^g϶2eʘ6'!@= ) 9kNi%P!ZR gR+@*y +L$$@} ) P@C۴T @ (MtÆ n|fͲW rh" k֬_~%aΝa>!Ud LSSQ@PdVk]P? r  @@ @̙cիWu|Nh8ەZ! UUTI6G2' \Q`@!^y%,{BH@榲 x'y;v!z@Њ@<豚E٦M@>~$[! c\֭[~WbD4N@\ ^Pʕت̯Ja C+R@ !xF%A{˗1ET4 O@T@[1UZb̙͗3E%}{ pSu@2vm4/͚54N'pSu@2P[hT}0\ @B/|8q~ak۶]tEwyvo֭+|o@@L@3 _~6d+WN6l >54OB@ J29Znmv.5hҤqk٪Uv7@@t@Q 9K,I& L2%7}@ x!@b@xr6`5[ 4ƌ\иJ| c{gիZs96mdoF!  h2J!:y6e={vJq0  PTFDiӦֵkהj|QGYڵmԨQ)  @QТ~ƍ6a7ju+Vh'|~TOx@@ FF?~)=cӪw:@@ЈSNT]ӧ=:9@0+V/Ҏ?j}]^e  I5_R1<К7onl@R ME+n۶|M߿թS')Sƴ%ĉm  =ЈVћ>"ժU L@@ bi_|Ѻtb{キ'5^ے߶uy'  @4@#*/(( /ڞuYi&3f [4kz>jݺu}zZƍ+@ @B+@ڦ >mt7f\pZ4OB@ MF)L<ٞ{9;sR~{Un۶4tɞq  aА6ܹsnrW^Z^z饦MG9 C4S-͛g :իg y%*[oesСV\Dʕ+X瞜\  @p@VTOғ?pѣ. :l0^gQ6 LCqR.,rwMS~akӦM\ @J4/ڷoےjj@ΝcA5$OB@@z7Ζ.]j{ϩbŊC^z_\\ʆ 9 r6.1rH޽F^MO >lR.y! <൙}VPPm!ҥ{BĉHA@ aLb˗#8"Pׯ]wu6j(@" g2iOJ?تUG *i ! A# zd0}ݢs=7hU  hx^kUVu+'ꪫRJgș  WK/nv裏/y慯@v ݅7r)pI'و#lƍvySO=e6le X4\nW]ژ1cO_|N974x; ]9l;vԥZjn38Þ~i{7W^q'U\m;uV&+ڠAOmEI  U$JڴiSx=sڴi6c [r)ާzJ?}nO^zELE$ @@؈eʔ `S+M +^ڶm;v=Dl (3}@  e,Q@G}[.׿M@?ځRd PJ6l=6uT_|E9r* dS4S=k~֬Y3\ӧ \ @ ~|ֺuk;8GqWҤI>|?q[9]pָqck׮nn}ٲeskժeGy$O` |@HR _k[nIV.S{xO>ĭ5kmڴmuYFLI  ;@Zlxb뮻aÆNM[=nիWϽ-|p5>׻-~zuVakXҵWe\Z|;9 * WpB۷ F  ]@k5w2SN=Q{ hjժ0W4Ү' s'zvТMkqƹ@s̙ws˖-0Tޑv @0uQcǺoݽna,޽.k5k9Nf@F@=ݹh3oJ\tkD[5k~ |uEuc(QP҅J#94ƍZ E%v 8(WSǏo^xaq={iASƢyNcߺWf;łl_' o޼tgYcbzrϧY rg*ZWSZ M|rB/- -)W3dva6i$T op yWOmo &L0XpꞈZ'G" W @6mjr^awv.)ie#@@-.I'1%}R@TЩ-Fe[hzT0m*OB@ v)aX{@x;mh!^N*8ݾ}~OXP(O6 @|+@ۦ_^چq_u1>  @@|/zE :߿+E @@T~ʇdQ@O:Lϙ} >hM IO;Su>C{DT@h FR{-6+wp1Q^ E@@ 97 Jxm4dٳ|nu7" A4(-UM4͛7ɓogΜ;t@梄 dM4kx 3EO=T6/Iޚw٭j7$O2A@ Ufw+b _W_}.2֭oI@@ wJ 2=y{7|cyQG`ً<@/@6]x6|p[hj?_nZ+We0  _g|u=ʲjժv]wek׮[n*Ve  xV^moG[;ѼOꫯFL@#@ꟶH$ZߣGliʼnϷ;o}"K@@ A믷m۶%\b6m[nFS쥗^2pa@'n-ٲeKzuѣMzע#$@@$ВT^׮]nO> tn!~gx`@)6 B49AdÆ qƹP "=.\\k  @@x~СCJtmrJ{fM4@.P>q]>hݻww94q۱cyE  ~z@CC=n6駟RS#F?ԩk) K4\Km"\rno]> @IDATgy~r)F  АrZ϶z˦Mim׭[gz6§SZ2C@ nܱk׷Gyڎ96l` 4_2C@p }]*T`"L"i{{δ{!J DG4"m}GZժUݐUV0d;餓Ȏ<@@ BilW_}6oޜqyk߾u9@%@>cl͚5gTӧ_|սE3* '# @}<uֶm[{3^ڵk=F3ʈ@@ kۄ lŊi|ڵo*VV  XvaovZ5lӦM6`$@@4b@ݺuGo\s=]4h H4A߾}o T>Νk'pBJq0  PTFDڜ>ax->jҤ>  l<ի[^l̘1ITcǎueʔI<D@ χ~͚5 íJ*'*@@L@3 UVF֭#GSOT"! fs+U6WuRk_*! $+@T;ꨣlʕnngO= V5j0G@ M*|vxN^~e[|~}@@ %Дwmĉ6mڴ]*׿\gVv7@@t@Q 9Gqկ_]jښ5kl|  @ʅ   4@>k6nh۷o[oպu7/5@@wkhذav75\ }BoF+_[$?-U@Ex6i͛gʕs|O)F@ M**5o<*U  '! " Q jSo@@ Oy  @T@@ȓh,  UШ# x+@'! $(s>F]wj夀x%0d_Wّ ݼg&-Ф8@@ P$@@@@? h륹sT$m4al˖-;}Q|Ŋw{Lǐo[nݩ~;g7n-4$̙\Ҽ϶mۺ3~W;sl.;vʔ)DJ'Oڵkc=f+W:{6j(ۼy=vXZW1J@W_}N;3|[>/|s\o}&"$5)]`O?֗_~zU\`ݻ  Ļ>۬[nn;ώ>h[x}+Xٲe^Çz9 O.*@*U't=E{7g͚e{WY~ڴi? A(>.\h]vuUѓVj-ٳg|*q;m\z닦xK;h|/PI Я_?mQE"tRYf |,P}l2VNJ4ľj*[dN>n\xXJ/XOmB(W/X_E"!\@V^=祝=Ԙ48mEIKW ^ƍ~ _ 8bߨQa"xK;'0`A @#aAdmƍn mԣG0V:ET@+n̘1NO>:u긯}צNj ,po3RT;~ϗvN-^vV#R?mޭ>Se˖=ՌE]d\s>*b%&@#SE@@OSkP@@ hd IOAY@@F"  'P?eA@" >hd@TnV۱cG|zEcӦMsޅzQ*s]PywaiӦ[K/혎9Tű?=vUWɓ 7?#lE)$4G @@>SO۝wY[b)?9hn۶--u7' )#SxS',]kݺuGxH z@VRx ϸW^?7~jy.ҫʚLy_{ {6}}A,>eF F<|vW8=Ih6sL7$QGmz*z-4h]~6eʔw^~\^/~gmĉvgI'dz֭[{s=O-oi> /oqM=߀{u/_|aW^y|4LKꫯ63ϴw}7~~}v>E{7ol=wqv… 7j?so߾yҤI;} <%Ff͚冮'x͡,WwkW K}~b)UصkWK6ULr޽UP让V95ĬJE+CI?}rȐ!vA)b*K 5߲m۶XR͞=N8Sʨ?^{n߾4_r~w L5OU=_ Js@_ FO?G.ӧU\eʔ8 @#P^Iӧۈ#<&M{kذ;ڥKlGy;FǫU7׫+WF^ѣGۆ  G) BW &>z0)54r޼y-Uݔ|*7nr!guVa}`7XASO=ez69sbŊv%{a_\\[RZhizz&?6uTرSN. z_r[`СC\& uP8ȇXjݺu|*իWϽjLvoF}?=Րs|֭[7wz@S^XJ%K~LSOuAr6mV_z饦몜 p5ĮRg|'Vv,@_zS|ƒԻzJ*~n֬ņѕw O}GVIjW`xvsS!`F, ԭ[wkԨQzci͚5nYZٲe %Pl:vlijrAk]f͚5 LC= D5,OիݗJ*_uQ׻ժU+,J<ϪU]'=ʠa:P%*XUzBuUVlرCxE ȧz&(6n ʢtd%iQh-җ-RkGS-WTؼQWc[?꫟D8i⯚vl2 }\t3fYRЯP-ZR`MB` v cƌq=~_T5/ICZAiжۻk {a5U{*"!WOkӟ( k.cUM4A=zhVkN?i@[h)0VO*; +@hpێ# 憨pG~~֖DZte^OW!vCIH4\U c]o[|?]ZjcEJZD9Cu ^2I|M:_JJU{7EMZ83 +P淿?. @N40c]\õzsg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATxTD&E" J%5D11[L,ޢ]clIw ""M:4P&[Ν9s̜9ufw{R~,F @OJT@ @@r!@ J+n* @@r @ J+n* @@r @ Jż۶mbgeҥTRcǎXV\XK>Pmݺv_-[]{qkO-[O۷o{J2eC+ʗ/yUWҋ8bB׊TmUT) ϰ*+d~*Ud6lI(яWmͱI>Skݺu(Ĝwy6j(;3w6}tlʔ)OӒV?T7n,"gw]K6)@ 8]~@"p=ȑ#K.c=݈v?/r@ @@ `3gδ~~_X׮]hufrKZ{ @ 9!D~*[|6^]>nx  L @31bJ_Yfo[8JZ'x"m@v @˓A,M뮻C֮]B0`}6lذBM@@GmHW_ŋ)R7Mڋ/X@ /h^" @JCgf"LcƌK?;A @=lA1#o@q!K/Ν;͕M-Z Sr^Ĉ4F@.]~Wn%~" .,8 _ &ŋ裏޽-OI9!K H@4h`JˢjڵݲsC&h= " ,ZֺEUؼys"EA}$4C'3ϸe2{勱ꆟ3giO   @6@1!/ӉP?L;v@Fq4@:~m[fojSƍ]BzD h~T@ &4HKd6l7R&MlԩIE@ @/Z @ mZ]"ЯG D$h*C4x@ F}YZuw$@;[luS! ~B(6@#0wD$iӦ]5A h" x7\}Ь۾K7|Vhrď4~>"@sY۶mnݺh֬40T p@?@ |6c *5Xt̙sNo( P*UX.]L@5u޼y!@'@&vaL>Jmf«) !@r@Çڵkwށ[UreW3 @ @Z@ c/[Hah(Kr" ?h  (ѣ>P@GG@'[Rϰ"Y O @z$x q|nͰe˖>, hHA3 ٳmΜ9֫W&J|6mu&h= G@*UN:I: J(~* Prv2˗/ |%_|-Y$gt@T @9 @Olҥ| PTxd@&XĀoiժU:(ԪU˪Wn'Oeh ?̩@ر~mڵ.ޯtEf'oȣ@'0~x[ru=-[ڬYLkS  @!ۿ/{mƍJ!onժU͑ݾ}; C%*jO/^lr-[4{w6x`[. bP!C\V@ sQ.PU7 P d lb^kׯ;[v]tES  >u^ںuAY\9^3)\Lgyx֯_.B8q 4׶PNwqx`$LQ7<49hSA*'|5jGB]ݡC{yO`Ν6tP;CB==_~@ @Lo죏>~ՄO>~P)@&Md񔊀@ ֫]va{ի͚5~M@7kUV6mfHv!7!m"͂|" 4՘ 6̭Բ>䋣w6f w6B Hv)2^5^u„ K!@&~|rO?=z4-ZՅL@ ݗ,YwϚ֭[ۢE6$4NU۱cWdTkY+!(k+VvSHߑU! R,DW3vXkذKS.]شi\=$ߕ=B5VjժeSS  \WHgΝ;vyS_Ie ڼyL7kQ-ꦔ$4rU[tiZZj֤I}kA J4L2VpӶm[ tŊao*rD#g'Ҿ}{79f3x4S &G Pqƅ !hrL2ōYfZH$@Vڟ +Wɓ'Տlƀ֮]n(;C%E1cV/zϟPT+.1K #Fخ]+eh@ oVk?Xlٲ&N[;Q Z1,ބ0ۤR_ s;i p_~i7o.ա1@lӦM.b*DAA qsk&?l/NQ7ƁΙ38/bK`Ѷe˖ȏu7n@&~+ZzuoUu˖-TRnEdgĔmw :Du+=q(v@ }YgΝk 4(J1S~}:ujčR{|eXv-T(<@B @Td&E-㘸4i^:ҫP92Ę4 ڴ 6ط~LxMbXP L@Vj.VJ^@E,j֫V4*#J@ HvJWvXUV%߷Y\^=PYհaC^Ӳlűn4G-^C1&s6MT33]L2Nz!%8IM؉cѲ+Wz(a Ph`\r_}իWD'RЙ3g (:t˗cǎd۾}{& 2tH֩SD]piBI#h"={vfGVz0aB޷x Ĕ4 ,:O? $ꇀ4HCQ4N2ΥEFg3 H!MPw֭[K,@5I3=p2dm֍NR}%%)@2 @g߭TJݺuc'pݐ Eʡ;eڵk_6r!n(F$h$F{TkW( T4$JmԺY@ q .X`JIR:i=l Bwޱ֭[[jaf|Y@ q *߸qc۲eiV=I ĉ[nI0wn0g ,7hu_vԯP *D.]`nlٲDAw K_j7|5ZF R 4PR|M;0? .vAP x@ۿX~z[nil뻮l@ /_nJ޽{61Ұ3fŋsZ'% ,kWS%[]:W lܹzJ@ n{zNU:&e2GGē4~ Ԫ\ P-K?jC 'e{^nt%kċ4^ 5`hf5)c:%@賣I~ɓM)@< @@ҏh͚5j7^@)+_OjWM"@$_J9ITZ%fh4h)f'. ?I =qpIf3Akh73gδ/z72GQO>Ĕď4~> ܢK.l7^zlC|!k|Rlww}@ @c MҒ+W̉D$u MndmL?5H+Qo?kժ)-h|E˖-skRΝ;Y':`9_}[j~ၷ%L JʯZ  /x3pk 1*u#/y1h6n:^q@ TrG \LB9+UD._&XB`Ŋh޽STt#ۢE 1q9?AR2В<,Yb+Vʕ+y';/5I3) _~ٙ=(1clݺuV䘀1 0>SO>֮];{ꩧ\>غ6$@sY#jH N@Q^xr_R& }v9ro9&OI'dW/_jvUWgmׯq+yz[ӯY.\t{IN6{#"M`رpB;#mG._n]JhJt'* =H|tMv1Yg{uFYNlԩ裏o~{WxA4 H>͂ϵݴiyo{B |y}k\Z(Q~QhJ z9眳[|ܹsg?wQƅ)9hFQ իW/՛ 8qcomذa֯_?+UTin+,ЯY&N:/,5 pԤIU阊FY ȧ~."+]ht衇;-Z$EMΝ%]˗ڵk4 Ф'|ͪZj`Rs1ݜQZڪ*٩Z`Ɓ>vuEZ |ej \EA$̹sM`nGbs~ukE$&!ƥ4owގC%:OF&>٨h.S0yf ^nxQ! ;~R<:tpY0Xxػhݍf(sqǹ5?Ӓ*"@cb K*z? Y KܟPƀ-Z{W9䶷~VڥN{sMqR0hlx$@s=^M8u/X-dwG`ݺuϛ~j,%3;vtlx饗\z/ lHto5q8Gd}2TL9j3&͛$@5qܸq@V⋦e5U$}1 @bذaq#I-=0L2Cɜ@ƍM](e%%KuGT{kTtIɟ4.l-&/_T]nb:!UCp 'R*U:&&"ͫأ"]4Fe5Þ7Lؒ)@U… @@h h־}{SRr \/8Cb l۶M>RD.R:}˸0ὴ U i"0|p/~fA&#5*gTI#dW6`"QۣG{뭷X8%|ՇMiR(_t6b6ul֬I4QC@Y<@sBΒH`F.=lڵޗto&lɀ)׫ yMS=bhV&Lp}i̞*%e6lu֭k|j7xX%agh샍~``J~FK.l_u.0~(A"7\<% L=y*Cj4TLPb̞=ukmi-@.?0'l 0dSiӦ9WgȞVܓ2$  x,)]G0PS^zYik׎x?C ~ĈL4hׯfgekBGh+ "q$/v3_Qreƪ^śt h؆&94k׮n~!f~?h]{KMf#bʽo!3=UP8* -e˖ަ?JNcO)?@r%*~R1 .Y$j*{T J֤Ih۱cG+k j 9DʕPbA P}yM|] H`1f~䞀V3fر#QC ̚5˖-[frﶨN=Z =K0~zpIuÓ>~TT-R?7!)QeVv+mڴi%='05klĉ ]ТGYb*9+;z\UXn$_Ű]TcEwi؈P\%& ZR%wWYJj(Y'n5M>ܹpY??'̟@ٲeM6,u?Њ}ԩSV*:t&h ƛ h"o[7 ~ƌ.o%#GtnP,YbZ"+ +n ѫ0>ԙJG1u/MDڹs}VLm"06{㳽邏ԇ'U4 HTLc&|Xdkܸqkg0֍2b5*Pk (%$o԰aB, $k 8TcjC4ZMms?CX7MQPh]\"t(ƫ~̙nB=G&9 ^0>Ni7o[|&N Q@5D@ /uW^-\=_{"XmJrA&Y}˖-aÆe(@LNG}]zxmZ2efg"סCP$j j )P-ȇ0~P AQGH^A?m {]J `|A؛J|&0g[ti(=դ9-^ԂMd'@/3$@we_u4H_uO@&LHz^_ d V?*VER䣏>*hoGŹ50U蒜k#J G]lk" %y$:vW*UeB~75CfgN6qt'ڹs脢0@ ?M܏I*3og}zúuʲTڪ%)ON-q.xTL@o?ӧO.N9sD@QPuj*Jr;nu>kUCɒEF a;ªUuhѢPFăr~[n{aTBd1Mb1f>~UZD_Oqu ؕLR1-X r~%AT oѢլY @G@УGYf%f(4]T u=~JŤ. Gǒ1c/iʕ+8g޽K>7xíŅ" _B4hP@/Xզ1a~XEb"bujm33P7;6lRhDz5x`ڵk$' *)rꫦDq/и{8eTIŔJ%!JsꩧzIűhܸ5h^yA;=zK>߫W/_E%jŋm„ 8}Ή ;ueGN@K%Ȉ;o6!T.%U7^h[C "/֭[Kk" okI-)/ zٷ~k7oNg0y?uY%=LJ@Ϟ=]^{- j*7^;OqP20iڵks*4Djȶml̄uꮻ2lٲeHI@9\;ud>l1dPS={J llol܇ @ x0^WV&!e"Rah⑾8v㽈8#E挘h&BxWE]a8p`'#!@}u [|5\ hh/P7lܸqH)Pq۷wY2\3ȑ#$G}te…6j("cR& M*И\h>i&_j͚5c9ǚn_~:![Fm۶TC-$yj h0#_kX#\̄%wq-Y?fu/!ļBg}LӦM3\wq0( 4~x>}zꨣ\eˠDoť7/d=SԮ|IhPV$@׬YCο9&K]VҬl0`[%_WNy"x≱\,BKKk`尝lS^-"*}Q1 @#`w-ÙJCi+Tϟ #z*Oڼ+k sO8oQkq#FE"jԨaLȒZTc͛7w_,aj L ԩ$gYe˖a25mBT]kBFR˸ק%n_ly.URɁ&piߜgyƥyUV6:ikk>ؔ.MYN^i4yNcAO?mO=[5)JlB%@LbuͶon˗/vuYϞ=3矻|oЌ{'@Ua٨nxhXvhȅƈ6h [vr!n kj8cqƮ;^7-!?7_{֭[g(S+W?;}3vX9ckڴi$0&@mfK.  ,jC]dvrZhB=Ѭ;{}ܸwEuk?{n,R~9GR4k C4 .2?QԩS;أ5կ7-I(f+\su!y ;餓\^T&Iu:u`̙n|Ye~+Vp5jh`Z̙3.b7k7x`數7w?;4%'N{28]^7 !Vu-d]wũ7tٲ-Rt}O>џnZuL?}WH]^Qou)X,M>&MdMS+Svmoܪp!P-_tzߟޣw^:N~X?`~3>6=곬G;,볫z(YVOgsܱcG, zYS5VV-'!&.}asE~]@nzL-ZQѦ~yw8剮eó=MݗkPϞYO^N=TTТEvѣW ~ iW+/m*0@-\JDW$0܇vb@]ۺ,E9L]>MQ C%Е>|I}4 VcTƖ*J vu;K/ ࢱ mkv>ꨣܟ;Ċ(gd}ؼ)ҵ]_p*7t^9d=d}.u3_{Q+$Qk6۫VKą(~9E$$BKjF :Ļ -hl5F]?D8T~V"kI-EôE#1z5+UGI$zT$RŻKRчVw[kgj=S?ԺΓh@ƠhDy,IflЍ5TcZ @x߽5R35Q(O!"2UCSE`AI.PIui4vA(eWEQύ+Z$&U4FBZ=G!S>8EW k@邢0 'Zظ` "LD Gh @'iE@%64J[vmRKgI=N$/1cG:+P.^xE/Əh2&h@~EnF3KaT:UkukYM8pZW|AίnSoG) @ڳ%4\bRb4U)ʩa~EN0WQ)o뺴e̴h<" ԢȦFN"fV4ARǀjlagkH܄hoi_~c h=syП}lKǀFM:Rl}yl֟VTh ۅ^z{^$$Ы[y4߷s=ijV3jp^mOhښJT(?ʛ!׬8? @H[*rYMVW_}{$E*GU <i PRF]ԡGZ]92Nb_a^ xic Tre2~9l@@-@Sl ՌtYw35N^4a a^i$@) @jR?T"תԵl6&%$@5+zC@@@8%@H^)nv]M"u_yZsT 9od $@c  @HK* Hk4HZ PF=7vׯVD@ <wǭ4i$c}]{衇Z#=xhAHFe[^ZQ @@ZT|$L%0\Tto -@TցOefJ = e˖.ȑ##EE;vh={ ; P-(qD@5 @q%P8q[Rl=ڍ􄧀^+)Ԯ]2®Q7j-Q@ (Tw9?|[3? [3MZvÆ *ښ sZiӦt Ą@tڴiE˗//d͒ğ*QY>#M4q/g͚Ms@@ UZbSh/_?oO>ጢY@%PMmΝ;mذanX{u80u7ǘ@ܢnx-)K @ Xi v '5&ku-_ jU\=QO}aE% L m裏СC]g?|M[쥗^*މ E@˔)c+WMWŋG4 i PE֯_VCڼy}vI'9͛77k6.P#sTHת# @@Zzdƌc r@o߾Z}%YժUlVVV-'٤ʹ @'Ph&tJܭ1{i2ҥ^juֵ_Wd\s+1&h*U"mr* %@.]춑' C - > ƍ G @ Phv뭷ҥK݄J*yocVPEҥKnx P  @H;:{lou9AO3^E-_iU$Ɓ:@~9_b&Mr)* /VHRNPJ ajժܹ3[ @ '0nݺ}:g]vYȩ&k.jXqi֭m(> =nݺnܘ1clΜ9hǎ_.IDATݟͥ H|ر#VQʔ)۷oZ $@]vvw/~ ;# +FkJ0ɞ+q]xD @iu+]͗_~&Oƭ ^۶m"R @@ZPvW_mK,-[Z Hjղ6mbjf-*$@l3gδN:i HK 7|[K.٫Iv+{mgC<(4\UTA)VfJ?#h BrI mȧfCWX0?*[)W$z< @rʶflƌVfMҥva4FerƱ# v rKs- H;5}tEy)vuݲeKv[BEQYlAd۶m'f  -@/bݻ-^fϞmᵖp}۶m!@"h[o;{1۾}֭[g9*lTϜ9tsE @ 7ǏwKqN4ɭ}GZΝs6r<4 }7fV&ۑ7T@ $US̚5N>d"ZK/M dhZA6rd8+!@H[>ꫯZ5v7sα3fX˖-woIH&!S4^Pc@ }i N;-ڛ4if&#M@Lc!4Tر[taԩ @T(K/dr-]&OL(BVZ tg" |-@gϞmmڴ;n6H_˾|Nͦ4tLڵ#S/`@%o=zp fSO=咔⋡5eN@?U&@efgFK) d@ZtӦM'Ԕ6IVb} П}AYr @@f. ?B ֶm[{~3@2"[ڲeYh7~ԩ$@2'͜]l$hԩiQF[!@H4-LI?Ukժe 6~O, %K}Iٓ?۾}o  @F%@5J*1:MK a8qbG @y @-]ԭ hªVj#FM@ hZ(?yҥMÇB P$hs_ۼy މw @(@4}.}߾}{+[,Q1. @@$M6ڵkZ+VhZw-d/ނ @ Ђ$t*t~tŦOn}];. @{@$/^(:`ZT) F;  @ D7ZjLtçNj @4xnW˗Fvjcǎucfؕ!@H!MSo~OJ8P-{w{A  @ _֤I{w ܇7 @؛to&ޢ.ڵk'AqW7Q9}!@I&MؾuV[|9]yCm۶10H@CH_*]Ÿ֭zbŮ d@&{X*t~͚5E !@ v&P'УG7~СĞ @&yM_pU^yZi<@4hP{6 @":M@nzҳgO?~K_ @: -Z-Nۻwneʔ=y (n2i7b=\?$P 0Є9 sW\i7n:u ۋ p?`ƍ+bOކ $4m=3wֆ{.sp  @ Ir6~Wn/%VdFTRֻwo2dX"p @  pr:&JjcժUٝ} зo_Q #(#_ZzQBiFO?m[n-8 OxVI^ll0`[| <8@H:hүo Y7nlڵGyLYbi @ ^gF|i&3A'p͟?X>>l d@&zu0a?E@>}G4+D9  ĉ4NЖyR14Cv'ٳ7(`6CILaܹs H˗c;/JF@Q۝wi[l)8 #93SS$@ׯW38Ö.]j=X!{ @ YwJ6h X25~ك>h-*8 И82S3r͚5D@3q~>vW2!) ^@' PO ofN@Ϸۣ>8 И82S3>s+S )2q;vc9MH8qbG @ kV͚5ˍ,[lǰcf@ <,թw…֢E4)(_?6vXӧ ><<0OkivhxأG;ܢK/uˤ* 4p|O>*W!sR͚5M3%@ b{#F4 P2Вj͂1mxR#qJ`nݺZY 4ФyG{7nhJԶmZk׮m^{{[oY߾}X@K!@@%[ckӦM팃q}nl5viv뭷ڶm`6@@B @>ȪVj$ԩ5| '` , B#)OGi۷gg^tiUe˖#fͅ !@v|_Zǎfy|mٲ~n _foٲ%>b  Ğ4.@E?I;|W"ZW\q} //~  (x)m|]%MhD@뮳%KQGen@=h]~i|ȳ6lhwy睶sۅ _v/˔KRi}v{l6e5]W=cguZ*Fz@-hl]a+ءCw}~-'~]y6yd;clڴi  @ ~iM4͛Vw6Ɔ@Ν]/K{'cc@@< @"k5k$Rⱃ֐#o-I|<|@/a~j\ "vPϷK.ĭ!߯_?cbf@@ @4ۮI))BIe=;FvgJׯO, @i7tK8*"FI&Zjw'@_y5@@AP΍7M6eO\f+O?O?On҄ rm۶͛mǎ9C@^iq:velٲenF"PN~)SLГO>ٺtƋjp J"s6sLmh"[bQCիg-Zۻ:9g}U;C@ @|-[]׻\w6&_NXÆ /$5VW^֮];JժUe˺Hf7_89c L"TEp~VR%+Sm߾6l`-XMy=P;]&MMԏ]Q6Q݇TF?|A8F|h~5綾^7v ' 4fXL=/Abq֬Y3'n4SK*JϮ3g[>UV5>`GJ*Z"6.E\rNŦL n|֭[)bsnteEիի"۪kv֭o< ;7M_ *\zvg۱khd Z5|\ps9zbxݛ6m%Kʕ+Mc%5MbP3ϊ+fJաhVp 8#<}|~R?{3 , ZW4DT&:ḥ~, Uڵk˝ݙy?nk֬qwjz׏P?v})GoV:j޼tMFWfn|la;0|%2⋮ ʓ(Rȫ' *w-Den췿]N *j'xrfSt;jn==c6tPkР@qZFp݅ZRk_~X!u~u MKk S[)Mӧ[TRn燀ogW?}/^;^׺n Ȭ/Vn0M>O7k:tp5)Oۼ?]mzȎSIjI.zU戰o7$&v&LT+*1 ՝4QԶJd#M~wy\Zr_c\`۷o_g&UHP_ |񣊂{k/wyl]v;^BOR/ӧ.o#W7hР=>Yh ) ȝz9o +yկ~墑O>Qjtcǎ.ڡMp1bp4I3fʻݩn@1UQ$oDI>׏a床=/q+tWG3x!{tg!q)us8ENB+͞n&?]7&t1 ''~b1lwIHF7U:1/|о+;][q_{nƒNNTDTB6z>J# }^{֢CX!ٕzuD|X  @@b%@6= @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B @C @& @& @F0c. @4hP? @Hh @ hР=@ @ a s8B c _m{=֫W37hӧO7|3gup^9Ff7iZj#CM?X+ҦNfK?ָqc͛7~;۸q;F/IR'b ;?~9Ҏ9אߔZg֭#XϞ=Zj7}'}v;smڵ6g״iSSI^q~?n+V6mF*@I!PO?$l}Y"$/u^~e;C޼ ]K.H"/vbU;TfݵQQ9!rd߷SN9[x^wtذa裏vu3DWEQ H]H3{'7o"_|D4Jޢ!7S"QЫ/!"A=.G.sDy'4e0jѢr-N P9(|`]tc)!.?IpzE̵j"ʿzT[QUKv]zԸAG0܏3UsO=P !3Ntw:a:۷> 7 Z| @&~7STʔ)e^Qjz{pjW^r5i駟v4&Q]ODEh_M~(OH0ի;V"_͘1êVZvi֣G;#LC) =y-MFR4TJES>a| `wq9ѲD?Si<*HO={/?v '_EĦ'Dʗ/F[(ۥ^Ƈj )PɋljX>}\Yy$^)Wz8~u>6pԷybROߨQ#7Bc|՞^q?{ 4 Ϗ>}GM@ba#%֫ԭۻw=sۻƄjqYNا:Vc 5iI:ͮWw1%3&M2T8]uk"͚L4Zp ]-%g}hs9vI'_0 {̵B-4GuKtg .;MFR;ύGX*0J$^TLZ r ^]{+Ik|Eh{IVv) .2M-Mh*47x}5٬8EyRD\VoFj✋}! >G9;;#Sn1J3ZՕuS})ÃS(D񜞞:t9@d2v| `CԆ21@)ù.HDMphF4:μht:-zER)3OSbrqq!;;;V2FX\ZX&il&Ve@ {{{RTX,sAS%Fr{{kJ{i(R$rތ 2H@ʘ %h4jO aK|donnu6u<`0M`i P@$fd]~M&qݲ&r{} JЯd,@fӒ% vEgJi -mE$ t7?1n>ewf>, %PKЄA@- Description: The encoding of colour can be handled in many different ways, using different colour spaces. As different colour spaces have different uses, efficient conversion between these representations are important. The 'farver' package provides a set of functions that gives access to very fast colour space conversion and comparisons implemented in C++, and offers speed improvements over the 'convertColor' function in the 'grDevices' package. License: MIT + file LICENSE Encoding: UTF-8 SystemRequirements: C++11 RoxygenNote: 7.0.2 URL: https://farver.data-imaginist.com, https://github.com/thomasp85/farver BugReports: https://github.com/thomasp85/farver/issues Suggests: testthat (>= 2.1.0), covr NeedsCompilation: yes Packaged: 2020-01-16 10:42:44 UTC; thomas Author: Thomas Lin Pedersen [cre, aut] (), Berendea Nicolae [aut] (Author of the ColorSpace C++ library), Romain François [aut] () Repository: CRAN Date/Publication: 2020-01-16 13:40:07 UTC farver/tests/0000755000176200001440000000000013562215674012714 5ustar liggesusersfarver/tests/testthat/0000755000176200001440000000000013610063667014551 5ustar liggesusersfarver/tests/testthat/test-conversion.R0000644000176200001440000000256513562215674020051 0ustar liggesuserscontext("conversion") spectrum <- unname(t(col2rgb(rainbow(10)))) reconvert <- function(data, space) { unname(round(convert_colour(convert_colour(data, 'rgb', space), space, 'rgb'))) } test_that("basic io works", { expect_error(convert_colour(spectrum, 'test', 'lab')) expect_error(convert_colour(spectrum, 'rgb', 'test')) expect_equal(nrow(spectrum), nrow(convert_colour(spectrum, 'rgb', 'lab'))) }) test_that("cmy works", { expect_equal(spectrum, reconvert(spectrum, 'cmy')) }) test_that("cmyk works", { expect_equal(spectrum, reconvert(spectrum, 'cmyk')) }) test_that("hsl works", { expect_equal(spectrum, reconvert(spectrum, 'hsl')) }) test_that("hsb works", { expect_equal(spectrum, reconvert(spectrum, 'hsb')) }) test_that("hsv works", { expect_equal(spectrum, reconvert(spectrum, 'hsv')) }) test_that("lab works", { expect_equal(spectrum, reconvert(spectrum, 'lab')) }) test_that("hunterlab works", { expect_equal(spectrum, reconvert(spectrum, 'hunterlab')) }) test_that("lch works", { expect_equal(spectrum, reconvert(spectrum, 'lch')) }) test_that("luv works", { expect_equal(spectrum, reconvert(spectrum, 'luv')) }) test_that("rgb works", { expect_equal(spectrum, reconvert(spectrum, 'rgb')) }) test_that("xyz works", { expect_equal(spectrum, reconvert(spectrum, 'xyz')) }) test_that("yxy works", { expect_equal(spectrum, reconvert(spectrum, 'yxy')) }) farver/tests/testthat/test-comparison.R0000644000176200001440000000164313607033717020026 0ustar liggesuserscontext("comparison") spectrum <- unname(t(col2rgb(rainbow(10)))) spectrum2 <- unname(t(col2rgb(heat.colors(5)))) reconvert <- function(data, space) { round(convert_colour(convert_colour(data, 'rgb', space), space, 'rgb')) } test_that("basic io works", { expect_error(compare_colour(spectrum, from_space = 'test', to_space = 'lab', method = 'cmc')) expect_error(compare_colour(spectrum, from_space = 'rgb', to_space = 'test', method = 'cmc')) expect_error(compare_colour(spectrum, from_space = 'rgb', to_space = 'lab', method = 'test')) expect_equal(rep(nrow(spectrum), 2), dim(compare_colour(spectrum, from_space = 'rgb'))) expect_equal(c(nrow(spectrum), nrow(spectrum2)), dim(compare_colour(spectrum, spectrum2, from_space = 'rgb'))) }) test_that("blue is included in Euclidean comparison (#20)", { expect_equal( compare_colour(decode_colour("#000000"), decode_colour("#0000FF"), "rgb")[1, 1], 255 ) }) farver/tests/testthat/test-manip.R0000644000176200001440000000516113563206542016756 0ustar liggesuserscodes <- c("#404040", "#8FBC8F", "#FFFFE0", "#7AC5CD", "#66CDAA", "#1E90FF", "#CDC0B0", "#CD0000", "#7A67EE", "#FFFACD") codes_alpha <- paste0(codes, c('', '1f', '44', 'fe', '', '9e', 'aa', 'b2', '0c', '21')) cols <- decode_colour(codes) alpha <- decode_colour(codes_alpha, TRUE)[, 'alpha'] cols_mod <- cols cols_lch <- convert_colour(cols, 'rgb' ,'lch') cols_lch_mod <- cols_lch test_that("setting channel works", { cols_mod[, 'g'] <- 1:10 expect_equal(set_channel(codes, 'g', 1:10), encode_colour(cols_mod)) cols_lch_mod[, 'l'] <- 1:10 expect_equal(set_channel(codes, 'l', 1:10, 'lch'), encode_colour(cols_lch_mod, from = 'lch')) expect_equal(set_channel(codes_alpha, 'alpha', (1:10)/10), encode_colour(cols, alpha = (1:10)/10)) }) test_that("adding channel works", { cols_mod[, 'r'] <- cols_mod[, 'r'] + 1:10 expect_equal(add_to_channel(codes, 'r', 1:10), encode_colour(cols_mod)) cols_lch_mod[, 'c'] <- cols_lch_mod[, 'c'] + 1:10 expect_equal(add_to_channel(codes, 'c', 1:10, 'lch'), encode_colour(cols_lch_mod, from = 'lch')) skip_on_os('linux') # Rounding difference on someones aarch64/ppc64le processor expect_equal(add_to_channel(codes_alpha, 'alpha', (1:10)/10), encode_colour(cols, alpha = alpha + (1:10)/10)) }) test_that("multiply channel works", { cols_mod[, 'b'] <- cols_mod[, 'b'] * 1:10 expect_equal(multiply_channel(codes, 'b', 1:10), encode_colour(cols_mod)) cols_lch_mod[, 'h'] <- cols_lch_mod[, 'h'] * 1:10 expect_equal(multiply_channel(codes, 'h', 1:10, 'lch'), encode_colour(cols_lch_mod, from = 'lch')) expect_equal(multiply_channel(codes_alpha, 'alpha', 1:10), encode_colour(cols, alpha = alpha * 1:10)) }) test_that("raising channel works", { cols_mod[, 'g'] <- ifelse(cols_mod[, 'g'] < 200, 200, cols_mod[, 'g']) expect_equal(raise_channel(codes, 'g', 200), encode_colour(cols_mod)) cols_lch_mod[, 'l'] <- ifelse(cols_lch_mod[, 'l'] < 50, 50, cols_lch_mod[, 'l']) expect_equal(raise_channel(codes, 'l', 50, 'lch'), encode_colour(cols_lch_mod, from = 'lch')) expect_equal(raise_channel(codes_alpha, 'alpha', 0.5), encode_colour(cols, alpha = ifelse(alpha < 0.5, 0.5, alpha))) }) test_that("capping channel works", { cols_mod[, 'g'] <- ifelse(cols_mod[, 'g'] > 200, 200, cols_mod[, 'g']) expect_equal(cap_channel(codes, 'g', 200), encode_colour(cols_mod)) cols_lch_mod[, 'l'] <- ifelse(cols_lch_mod[, 'l'] > 50, 50, cols_lch_mod[, 'l']) expect_equal(cap_channel(codes, 'l', 50, 'lch'), encode_colour(cols_lch_mod, from = 'lch')) expect_equal(cap_channel(codes_alpha, 'alpha', 0.5), encode_colour(cols, alpha = ifelse(alpha > 0.5, 0.5, alpha))) }) farver/tests/testthat/test-encoding.R0000644000176200001440000000300513562535235017436 0ustar liggesuserscols <- c("#404040", "#8FBC8F", "#FFFFE0", "#7AC5CD", "#66CDAA", "#1E90FF", "#CDC0B0", "#CD0000", "#7A67EE", "#FFFACD") cols_dec <- decode_colour(cols) test_that("colours can be encoded", { expect_equal(encode_colour(cols_dec), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'cmy'), from = 'cmy'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'cmyk'), from = 'cmyk'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'hsl'), from = 'hsl'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'hsb'), from = 'hsb'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'hsv'), from = 'hsv'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'lab'), from = 'lab'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'hunterlab'), from = 'hunterlab'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'lch'), from = 'lch'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'luv'), from = 'luv'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'xyz'), from = 'xyz'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'yxy'), from = 'yxy'), cols) expect_equal(encode_colour(convert_colour(cols_dec, 'rgb', 'hcl'), from = 'hcl'), cols) }) test_that("alpha gets encoded correctly", { alpha_col <- encode_colour(cols_dec[1:6,], alpha = seq(0, 1, length.out = 6)) expect_equal(substr(alpha_col, 8, 9), c("00", "33", "66", "99", "CC", "")) })farver/tests/testthat/test-non-finite.R0000644000176200001440000000175613577152745017740 0ustar liggesusersbad_codes <- c('#345', '#e51f87', 'steelblue', 'test', NA) bad_colours <- cbind( c(34, NaN, Inf, NA, -Inf, 67), c(34, 0, 0, 0, 0, 67), c(34, 0, 0, 0, 0, 67) ) test_that("non-finite values are treated correctly", { expect_error(decode_colour(bad_codes), 'Malformed colour string `#345`') expect_error(decode_colour(bad_codes[-1]), 'Unknown colour name: test') expect_true(all(is.na(decode_colour(bad_codes[-c(1, 4)]))[3, ])) expect_false(any(is.na(decode_colour(bad_codes[-c(1, 4)]))[1:2, ])) expect_true(all(is.na(encode_colour(bad_colours))[2:5])) expect_false(any(is.na(encode_colour(bad_colours))[c(1,6)])) expect_true(all(is.na(convert_colour(bad_colours, 'rgb', 'lab')[2:5, ]))) expect_false(any(is.na(convert_colour(bad_colours, 'rgb', 'lab')[c(1,6), ]))) col_compare <- compare_colour(bad_colours, from_space = 'rgb') col_compare <- col_compare[upper.tri(col_compare)] expect_true(all(is.na(col_compare[-11]))) expect_false(any(is.na(col_compare[11]))) }) farver/tests/testthat/test-decoding.R0000644000176200001440000000334113562535271017427 0ustar liggesuserscols <- c("#404040", "#8FBC8F", "#FFFFE0", "#7AC5CD", "#66CDAA", "#1E90FF", "#CDC0B0", "#CD0000", "#7A67EE", "#FFFACD") truth <- matrix(c(64L, 143L, 255L, 122L, 102L, 30L, 205L, 205L, 122L, 255L, 64L, 188L, 255L, 197L, 205L, 144L, 192L, 0L, 103L, 250L, 64L, 143L, 224L, 205L, 170L, 255L, 176L, 0L, 238L, 205L), ncol = 3, dimnames = list(NULL, c("r", "g", "b"))) test_that("colours can be decoded", { expect_equal(decode_colour(cols), truth) expect_equal(decode_colour(cols, to = 'cmy'), convert_colour(truth, 'rgb', 'cmy')) expect_equal(decode_colour(cols, to = 'cmyk'), convert_colour(truth, 'rgb', 'cmyk')) expect_equal(decode_colour(cols, to = 'hsl'), convert_colour(truth, 'rgb', 'hsl')) expect_equal(decode_colour(cols, to = 'hsb'), convert_colour(truth, 'rgb', 'hsb')) expect_equal(decode_colour(cols, to = 'hsv'), convert_colour(truth, 'rgb', 'hsv')) expect_equal(decode_colour(cols, to = 'lab'), convert_colour(truth, 'rgb', 'lab')) expect_equal(decode_colour(cols, to = 'hunterlab'), convert_colour(truth, 'rgb', 'hunterlab')) expect_equal(decode_colour(cols, to = 'lch'), convert_colour(truth, 'rgb', 'lch')) expect_equal(decode_colour(cols, to = 'luv'), convert_colour(truth, 'rgb', 'luv')) expect_equal(decode_colour(cols, to = 'xyz'), convert_colour(truth, 'rgb', 'xyz')) expect_equal(decode_colour(cols, to = 'yxy'), convert_colour(truth, 'rgb', 'yxy')) expect_equal(decode_colour(cols, to = 'hcl'), convert_colour(truth, 'rgb', 'hcl')) }) test_that("alpha gets decoded correctly", { alpha <- decode_colour( paste0(cols[1:6], c("00", "33", "66", "99", "CC", "")), alpha = TRUE )[, 'alpha'] expect_equal(alpha, seq(0, 1, length.out = 6)) })farver/tests/testthat/test-names.R0000644000176200001440000000136513562536106016760 0ustar liggesusersnames <- c("#404040", "#8FBC8F", "#FFFFE0", "#7AC5CD", "#66CDAA", "#1E90FF", "#CDC0B0", "#CD0000", "#7A67EE", "#FFFACD") cols <- decode_colour(names) cols_named <- cols rownames(cols_named) <- names codes_named <- names names(codes_named) <- names test_that("names gets transfered", { expect_equal(names(encode_colour(cols_named)), names) expect_null(names(encode_colour(cols))) expect_equal(rownames(decode_colour(codes_named)), names) expect_null(rownames(decode_colour(names))) expect_equal(rownames(convert_colour(cols_named, 'rgb', 'lab')), names) expect_null(rownames(convert_colour(cols, 'rgb', 'lab'))) col_dist <- compare_colour(cols, cols_named, 'rgb') expect_equal(dimnames(col_dist), list(NULL, names)) }) farver/tests/testthat.R0000644000176200001440000000007013562215674014674 0ustar liggesuserslibrary(testthat) library(farver) test_check("farver") farver/src/0000755000176200001440000000000013610037044012324 5ustar liggesusersfarver/src/farver.cpp0000644000176200001440000003060013577153035014327 0ustar liggesusers#include "farver.h" #include "Comparison.h" #include //------------------------------------------------------------------------------ //--- Conversions -------------------------------------------------------------- //------------------------------------------------------------------------------ // this is where the real work happens, // the template parameters Space_From and Space_To give us the types of the // from and to colours. template SEXP convert_dispatch_impl(SEXP colour, SEXP white_from, SEXP white_to) { int ncol = dimension(); // check that the dimensions of the input match the colour space if (ncol > Rf_ncols(colour)) { Rf_errorcall(R_NilValue, "colourspace requires %d values", ncol); } int ncol_out = dimension(); double wf1 = REAL(white_from)[0]; double wf2 = REAL(white_from)[1]; double wf3 = REAL(white_from)[2]; double wt1 = REAL(white_to)[0]; double wt2 = REAL(white_to)[1]; double wt3 = REAL(white_to)[2]; // make the result matrix int n = Rf_nrows(colour); SEXP out = PROTECT(Rf_allocMatrix(REALSXP, n, ncol_out)); double* out_p = REAL(out); ColorSpace::Rgb rgb; Space_To to; int offset1 = 0; int offset2 = offset1 + n; int offset3 = offset2 + n; int offset4 = offset3 + n; double* colour_d = NULL; int* colour_i = NULL; bool colour_is_int = Rf_isInteger(colour); if (colour_is_int) { colour_i = INTEGER(colour); } else { colour_d = REAL(colour); } for (int i = 0; i < n; ++i) { // fill `rgb` based on the input color in the `from` color space ColorSpace::XyzConverter::SetWhiteReference(wf1, wf2, wf3); if (colour_is_int) { fill_rgb(&rgb, colour_i[offset1 + i], colour_i[offset2 + i], colour_i[offset3 + i], ncol == 4 ? colour_i[offset4 + i] : 0); } else { fill_rgb(&rgb, colour_d[offset1 + i], colour_d[offset2 + i], colour_d[offset3 + i], ncol == 4 ? colour_d[offset4 + i] : 0.0); } // ... convert the color to the `to` color space ColorSpace::XyzConverter::SetWhiteReference(wt1, wt2, wt3); ColorSpace::IConverter::ToColorSpace(&rgb, &to); // ... and move it to the row of the `out` matrix to.Cap(); grab(to, out_p + offset1 + i, out_p + offset2 + i, out_p + offset3 + i, ncol_out == 4 ? out_p + offset4 + i : out_p); } copy_names(colour, out); UNPROTECT(1); return out; } // this is a trick to do a runtime fake compile time dispatch // the idea is to call the right instantiation of the convert_dispatch_impl template // where the real work happens, based on `to` template SEXP convert_dispatch_to(SEXP colour, int to, SEXP white_from, SEXP white_to) { switch (to) { case CMY: return convert_dispatch_impl(colour, white_from, white_to); case CMYK: return convert_dispatch_impl(colour, white_from, white_to); case HSL: return convert_dispatch_impl(colour, white_from, white_to); case HSB: return convert_dispatch_impl(colour, white_from, white_to); case HSV: return convert_dispatch_impl(colour, white_from, white_to); case LAB: return convert_dispatch_impl(colour, white_from, white_to); case HUNTERLAB: return convert_dispatch_impl(colour, white_from, white_to); case LCH: return convert_dispatch_impl(colour, white_from, white_to); case LUV: return convert_dispatch_impl(colour, white_from, white_to); case RGB: return convert_dispatch_impl(colour, white_from, white_to); case XYZ: return convert_dispatch_impl(colour, white_from, white_to); case YXY: return convert_dispatch_impl(colour, white_from, white_to); case HCL: return convert_dispatch_impl(colour, white_from, white_to); } // never happens return colour ; } // same trick, but for the `from` SEXP convert_dispatch_from(SEXP colour, int from, int to, SEXP white_from, SEXP white_to) { switch (from) { case CMY: return convert_dispatch_to(colour, to, white_from, white_to); case CMYK: return convert_dispatch_to(colour, to, white_from, white_to); case HSL: return convert_dispatch_to(colour, to, white_from, white_to); case HSB: return convert_dispatch_to(colour, to, white_from, white_to); case HSV: return convert_dispatch_to(colour, to, white_from, white_to); case LAB: return convert_dispatch_to(colour, to, white_from, white_to); case HUNTERLAB: return convert_dispatch_to(colour, to, white_from, white_to); case LCH: return convert_dispatch_to(colour, to, white_from, white_to); case LUV: return convert_dispatch_to(colour, to, white_from, white_to); case RGB: return convert_dispatch_to(colour, to, white_from, white_to); case XYZ: return convert_dispatch_to(colour, to, white_from, white_to); case YXY: return convert_dispatch_to(colour, to, white_from, white_to); case HCL: return convert_dispatch_to(colour, to, white_from, white_to); } // never happens so we just return the input to quiet the compiler return colour; } SEXP convert_c(SEXP colour, SEXP from, SEXP to, SEXP white_from, SEXP white_to) { return convert_dispatch_from(colour, INTEGER(from)[0], INTEGER(to)[0], white_from, white_to); } //------------------------------------------------------------------------------ //--- Comparisons -------------------------------------------------------------- //------------------------------------------------------------------------------ double get_colour_dist(ColorSpace::Rgb& from, ColorSpace::Rgb& to, int dist) { switch (dist) { case EUCLIDEAN: return ColorSpace::EuclideanComparison::Compare(&from, &to); case CIE1976: return ColorSpace::Cie1976Comparison::Compare(&from, &to); case CIE94: return ColorSpace::Cie94Comparison::Compare(&from, &to); case CIE2000: return ColorSpace::Cie2000Comparison::Compare(&from, &to); case CMC: return ColorSpace::CmcComparison::Compare(&from, &to); } // Never happens return 0.0; } template SEXP compare_dispatch_impl(SEXP from, SEXP to, int dist, bool sym, SEXP white_from, SEXP white_to){ int from_col = dimension(); int to_col = dimension(); // check that the dimensions of the input match the colour space if (from_col > Rf_ncols(from)) { Rf_errorcall(R_NilValue, "colourspace requires %d values", from_col); } if (to_col > Rf_ncols(to)) { Rf_errorcall(R_NilValue, "colourspace requires %d values", to_col); } double wf1 = REAL(white_from)[0]; double wf2 = REAL(white_from)[1]; double wf3 = REAL(white_from)[2]; double wt1 = REAL(white_to)[0]; double wt2 = REAL(white_to)[1]; double wt3 = REAL(white_to)[2]; int n = Rf_nrows(from); int m = Rf_nrows(to); int noffset1 = 0; int noffset2 = noffset1 + n; int noffset3 = noffset2 + n; int noffset4 = noffset3 + n; int moffset1 = 0; int moffset2 = moffset1 + m; int moffset3 = moffset2 + m; int moffset4 = moffset3 + m; double* from_d = NULL; double* to_d = NULL; int* from_i = NULL; int* to_i = NULL; bool from_is_int = Rf_isInteger(from); bool to_is_int = Rf_isInteger(to); if (from_is_int) { from_i = INTEGER(from); } else { from_d = REAL(from); } if (to_is_int) { to_i = INTEGER(to); } else { to_d = REAL(to); } SEXP out = PROTECT(Rf_allocMatrix(REALSXP, n, m)); double* out_p = REAL(out); double temp = 0.0; ColorSpace::Rgb from_rgb, to_rgb; for (int i = 0; i < n; ++i) { ColorSpace::XyzConverter::whiteReference = {wf1, wf2, wf3}; if (from_is_int) { fill_rgb(&from_rgb, from_i[noffset1 + i], from_i[noffset2 + i], from_i[noffset3 + i], from_col == 4 ? from_i[noffset4 + i] : 0); } else { fill_rgb(&from_rgb, from_d[noffset1 + i], from_d[noffset2 + i], from_d[noffset3 + i], from_col == 4 ? from_d[noffset4 + i] : 0.0); } ColorSpace::XyzConverter::whiteReference = {wt1, wt2, wt3}; for (int j = 0; j < m; ++j) { if (sym && j <= i) { out_p[n * j + i] = 0.0; continue; } if (to_is_int) { fill_rgb(&to_rgb, to_i[moffset1 + j], to_i[moffset2 + j], to_i[moffset3 + j], to_col == 4 ? to_i[moffset4 + j] : 0); } else { fill_rgb(&to_rgb, to_d[moffset1 + j], to_d[moffset2 + j], to_d[moffset3 + j], to_col == 4 ? to_d[moffset4 + j] : 0.0); } temp = get_colour_dist(from_rgb, to_rgb, dist); out_p[n * j + i] = temp < 0 ? R_NaReal : temp; } } copy_names(from, to, out); UNPROTECT(1); return out; } template SEXP compare_dispatch_to(SEXP from, SEXP to, int to_space, int dist, bool sym, SEXP white_from, SEXP white_to) { switch (to_space) { case CMY: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case CMYK: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case HSL: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case HSB: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case HSV: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case LAB: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case HUNTERLAB: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case LCH: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case LUV: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case RGB: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case XYZ: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case YXY: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case HCL: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); } // never happens return from; } SEXP compare_dispatch_from(SEXP from, SEXP to, int from_space, int to_space, int dist, bool sym, SEXP white_from, SEXP white_to) { switch (from_space) { case CMY: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case CMYK: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case HSL: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case HSB: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case HSV: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case LAB: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case HUNTERLAB: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case LCH: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case LUV: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case RGB: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case XYZ: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case YXY: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); } // never happens so we just return the input to quiet the compiler return from; } SEXP compare_c(SEXP from, SEXP to, SEXP from_space, SEXP to_space, SEXP dist, SEXP sym, SEXP white_from, SEXP white_to) { return compare_dispatch_from(from, to, INTEGER(from_space)[0], INTEGER(to_space)[0], INTEGER(dist)[0], LOGICAL(sym)[0], white_from, white_to); } farver/src/init.cpp0000644000176200001440000000162313607062112013775 0ustar liggesusers#include "farver.h" #include "encode.h" #include #define R_NO_REMAP #include #include // for NULL #include static ColourMap* named_colours; ColourMap& get_named_colours() { return *named_colours; } static const R_CallMethodDef CallEntries[] = { {"convert_c", (DL_FUNC) &convert_c, 5}, {"compare_c", (DL_FUNC) &compare_c, 8}, {"encode_c", (DL_FUNC) &encode_c, 4}, {"decode_c", (DL_FUNC) &decode_c, 5}, {"encode_channel_c", (DL_FUNC) &encode_channel_c, 7}, {"decode_channel_c", (DL_FUNC) &decode_channel_c, 5}, {"load_colour_names_c", (DL_FUNC) &load_colour_names_c, 2}, {NULL, NULL, 0} }; extern "C" void R_init_farver(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); named_colours = new ColourMap(); } extern "C" void R_unload_farver(DllInfo *dll) { delete named_colours; } farver/src/encode.h0000644000176200001440000002055713607061621013747 0ustar liggesusers#ifndef ENCODE_INCLUDED #define ENCODE_INCLUDED #include #include #include "ColorSpace.h" #include #define R_NO_REMAP #include #define OP_SET 1 #define OP_ADD 2 #define OP_MULT 3 #define OP_LEAST 4 #define OP_MOST 5 inline double mod_val(double val, double mod, int op) { switch (op) { case OP_SET: return mod; case OP_ADD: return val + mod; case OP_MULT: return val * mod; case OP_LEAST: return val < mod ? mod : val; case OP_MOST: return val > mod ? mod : val; } return val; } struct rgb_colour { int r; int g; int b; int a; }; typedef std::unordered_map ColourMap; // Defined in init.cpp ColourMap& get_named_colours(); SEXP encode_c(SEXP colour, SEXP alpha, SEXP from, SEXP white); SEXP decode_c(SEXP codes, SEXP alpha, SEXP to, SEXP white, SEXP na); SEXP encode_channel_c(SEXP codes, SEXP channel, SEXP value, SEXP space, SEXP op, SEXP white, SEXP na); SEXP decode_channel_c(SEXP codes, SEXP channel, SEXP space, SEXP white, SEXP na); SEXP load_colour_names_c(SEXP name, SEXP value); template inline void modify_channel(Space&, double value, int channel, int op); template <> inline void modify_channel(ColorSpace::Rgb& color, double value, int channel, int op){ switch (channel) { case 1: color.r = mod_val(color.r, value, op); break; case 2: color.g = mod_val(color.g, value, op); break; case 3: color.b = mod_val(color.b, value, op); break; } } template <> inline void modify_channel(ColorSpace::Xyz& color, double value, int channel, int op){ switch (channel) { case 1: color.x = mod_val(color.x, value, op); break; case 2: color.y = mod_val(color.y, value, op); break; case 3: color.z = mod_val(color.z, value, op); break; } } template <> inline void modify_channel(ColorSpace::Hsl& color, double value, int channel, int op){ switch (channel) { case 1: color.h = mod_val(color.h, value, op); break; case 2: color.s = mod_val(color.s, value, op); break; case 3: color.l = mod_val(color.l, value, op); break; } } template <> inline void modify_channel(ColorSpace::Lab& color, double value, int channel, int op){ switch (channel) { case 1: color.l = mod_val(color.l, value, op); break; case 2: color.a = mod_val(color.a, value, op); break; case 3: color.b = mod_val(color.b, value, op); break; } } template <> inline void modify_channel(ColorSpace::Lch& color, double value, int channel, int op){ switch (channel) { case 1: color.l = mod_val(color.l, value, op); break; case 2: color.c = mod_val(color.c, value, op); break; case 3: color.h = mod_val(color.h, value, op); break; } } template <> inline void modify_channel(ColorSpace::Luv& color, double value, int channel, int op){ switch (channel) { case 1: color.l = mod_val(color.l, value, op); break; case 2: color.u = mod_val(color.u, value, op); break; case 3: color.v = mod_val(color.v, value, op); break; } } template <> inline void modify_channel(ColorSpace::Yxy& color, double value, int channel, int op){ switch (channel) { case 1: color.y1 = mod_val(color.y1, value, op); break; case 2: color.x = mod_val(color.x, value, op); break; case 3: color.y2 = mod_val(color.y2, value, op); break; } } template <> inline void modify_channel(ColorSpace::Cmy& color, double value, int channel, int op){ switch (channel) { case 1: color.c = mod_val(color.c, value, op); break; case 2: color.m = mod_val(color.m, value, op); break; case 3: color.y = mod_val(color.y, value, op); break; } } template <> inline void modify_channel(ColorSpace::Cmyk& color, double value, int channel, int op){ switch (channel) { case 1: color.c = mod_val(color.c, value, op); break; case 2: color.m = mod_val(color.m, value, op); break; case 3: color.y = mod_val(color.y, value, op); break; case 4: color.k = mod_val(color.k, value, op); break; } } template <> inline void modify_channel(ColorSpace::Hsv& color, double value, int channel, int op){ switch (channel) { case 1: color.h = mod_val(color.h, value, op); break; case 2: color.s = mod_val(color.s, value, op); break; case 3: color.v = mod_val(color.v, value, op); break; } } template <> inline void modify_channel(ColorSpace::Hsb& color, double value, int channel, int op){ switch (channel) { case 1: color.h = mod_val(color.h, value, op); break; case 2: color.s = mod_val(color.s, value, op); break; case 3: color.b = mod_val(color.b, value, op); break; } } template <> inline void modify_channel(ColorSpace::HunterLab& color, double value, int channel, int op){ switch (channel) { case 1: color.l = mod_val(color.l, value, op); break; case 2: color.a = mod_val(color.a, value, op); break; case 3: color.b = mod_val(color.b, value, op); break; } } template <> inline void modify_channel(ColorSpace::Hcl& color, double value, int channel, int op){ switch (channel) { case 1: color.h = mod_val(color.h, value, op); break; case 2: color.c = mod_val(color.c, value, op); break; case 3: color.l = mod_val(color.l, value, op); break; } } template inline double grab_channel(Space&,int channel); template <> inline double grab_channel(ColorSpace::Rgb& color, int channel){ switch (channel) { case 1: return color.r; case 2: return color.g; case 3: return color.b; } return 0.0; } template <> inline double grab_channel(ColorSpace::Xyz& color, int channel){ switch (channel) { case 1: return color.x; case 2: return color.y; case 3: return color.z; } return 0.0; } template <> inline double grab_channel(ColorSpace::Hsl& color, int channel){ switch (channel) { case 1: return color.h; case 2: return color.s; case 3: return color.l; } return 0.0; } template <> inline double grab_channel(ColorSpace::Lab& color, int channel){ switch (channel) { case 1: return color.l; case 2: return color.a; case 3: return color.b; } return 0.0; } template <> inline double grab_channel(ColorSpace::Lch& color, int channel){ switch (channel) { case 1: return color.l; case 2: return color.c; case 3: return color.h; } return 0.0; } template <> inline double grab_channel(ColorSpace::Luv& color, int channel){ switch (channel) { case 1: return color.l; case 2: return color.u; case 3: return color.v; } return 0.0; } template <> inline double grab_channel(ColorSpace::Yxy& color, int channel){ switch (channel) { case 1: return color.y1; case 2: return color.x; case 3: return color.y2; } return 0.0; } template <> inline double grab_channel(ColorSpace::Cmy& color, int channel){ switch (channel) { case 1: return color.c; case 2: return color.m; case 3: return color.y; } return 0.0; } template <> inline double grab_channel(ColorSpace::Cmyk& color, int channel){ switch (channel) { case 1: return color.c; case 2: return color.m; case 3: return color.y; case 4: return color.k; } return 0.0; } template <> inline double grab_channel(ColorSpace::Hsv& color, int channel){ switch (channel) { case 1: return color.h; case 2: return color.s; case 3: return color.v; } return 0.0; } template <> inline double grab_channel(ColorSpace::Hsb& color, int channel){ switch (channel) { case 1: return color.h; case 2: return color.s; case 3: return color.b; } return 0.0; } template <> inline double grab_channel(ColorSpace::HunterLab& color, int channel){ switch (channel) { case 1: return color.l; case 2: return color.a; case 3: return color.b; } return 0.0; } template <> inline double grab_channel(ColorSpace::Hcl& color, int channel){ switch (channel) { case 1: return color.h; case 2: return color.c; case 3: return color.l; } return 0.0; } #endif farver/src/ColorSpace.cpp0000755000176200001440000002260513563052201015071 0ustar liggesusers#include "ColorSpace.h" #include "Conversion.h" #include #define R_NO_REMAP #include namespace ColorSpace { Rgb::Rgb() {} Rgb::Rgb(double r, double g, double b) : r(r), g(g), b(b) { valid = R_finite(r) && R_finite(g) && R_finite(b); } Rgb::Rgb(int r, int g, int b) : r(r), g(g), b(b) { valid = !(r == R_NaInt || g == R_NaInt || b == R_NaInt); } void Rgb::Initialize(Rgb *color) { RgbConverter::ToColorSpace(color, this); } void Rgb::ToRgb(Rgb *color) { RgbConverter::ToColor(color, this); } void Rgb::Copy(IColorSpace *color) { Rgb *rgb = static_cast(color); rgb->r = r; rgb->g = g; rgb->b = b; rgb->valid = valid; } void Rgb::Cap() { if (!valid) return; r = r < 0.0 ? 0.0 : (r > 255.0 ? 255.0 : r); g = g < 0.0 ? 0.0 : (g > 255.0 ? 255.0 : g); b = b < 0.0 ? 0.0 : (b > 255.0 ? 255.0 : b); } Xyz::Xyz() {} Xyz::Xyz(double x, double y, double z) : x(x), y(y), z(z) { valid = R_finite(x) && R_finite(y) && R_finite(z); } Xyz::Xyz(int x, int y, int z) : x(x), y(y), z(z) { valid = !(x == R_NaInt || y == R_NaInt || z == R_NaInt); } void Xyz::Initialize(Rgb *color) { XyzConverter::ToColorSpace(color, this); } void Xyz::ToRgb(Rgb *color) { XyzConverter::ToColor(color, this); } void Xyz::Copy(IColorSpace *color) { Xyz *xyz = static_cast(color); xyz->x = x; xyz->y = y; xyz->z = z; xyz->valid = valid; } void Xyz::Cap() { if (!valid) return; x = x < 0.0 ? 0.0 : x; y = y < 0.0 ? 0.0 : y; z = z < 0.0 ? 0.0 : z; } Hsl::Hsl() {} Hsl::Hsl(double h, double s, double l) : h(h), s(s), l(l) { valid = R_finite(h) && R_finite(s) && R_finite(l); } Hsl::Hsl(int h, int s, int l) : h(h), s(s), l(l) { valid = !(h == R_NaInt || s == R_NaInt || l == R_NaInt); } void Hsl::Initialize(Rgb *color) { HslConverter::ToColorSpace(color, this); } void Hsl::ToRgb(Rgb *color) { HslConverter::ToColor(color, this); } void Hsl::Copy(IColorSpace *color) { Hsl *hsl = static_cast(color); hsl->h = h; hsl->s = s; hsl->l = l; hsl->valid = valid; } void Hsl::Cap() { if (!valid) return; h = h < 0.0 ? 0.0 : (h > 360.0 ? 360.0 : h); s = s < 0.0 ? 0.0 : (s > 100.0 ? 100.0 : s); l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); } Lab::Lab() {} Lab::Lab(double l, double a, double b) : l(l), a(a), b(b) { valid = R_finite(l) && R_finite(a) && R_finite(b); } Lab::Lab(int l, int a, int b) : l(l), a(a), b(b) { valid = !(l == R_NaInt || a == R_NaInt || b == R_NaInt); } void Lab::Initialize(Rgb *color) { LabConverter::ToColorSpace(color, this); } void Lab::ToRgb(Rgb *color) { LabConverter::ToColor(color, this); } void Lab::Copy(IColorSpace *color) { Lab *lab = static_cast(color); lab->l = l; lab->a = a; lab->b = b; lab->valid = valid; } void Lab::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); } Lch::Lch() {} Lch::Lch(double l, double c, double h) : l(l), c(c), h(h) { valid = R_finite(l) && R_finite(c) && R_finite(h); } Lch::Lch(int l, int c, int h) : l(l), c(c), h(h) { valid = !(l == R_NaInt || c == R_NaInt || h == R_NaInt); } void Lch::Initialize(Rgb *color) { LchConverter::ToColorSpace(color, this); } void Lch::ToRgb(Rgb *color) { LchConverter::ToColor(color, this); } void Lch::Copy(IColorSpace *color) { Lch *lch = static_cast(color); lch->l = l; lch->c = c; lch->h = h; lch->valid = valid; } void Lch::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); c = c < 0.0 ? 0.0 : c; h = h < 0.0 ? 0.0 : (h > 360.0 ? 360.0 : h); } Luv::Luv() {} Luv::Luv(double l, double u, double v) : l(l), u(u), v(v) { valid = R_finite(l) && R_finite(u) && R_finite(v); } Luv::Luv(int l, int u, int v) : l(l), u(u), v(v) { valid = !(l == R_NaInt || u == R_NaInt || v == R_NaInt); } void Luv::Initialize(Rgb *color) { LuvConverter::ToColorSpace(color, this); } void Luv::ToRgb(Rgb *color) { LuvConverter::ToColor(color, this); } void Luv::Copy(IColorSpace *color) { Luv *luv = static_cast(color); luv->l = l; luv->u = u; luv->v = v; luv->valid = valid; } void Luv::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); } Yxy::Yxy() {} Yxy::Yxy(double y1, double x, double y2) : y1(y1), x(x), y2(y2) { valid = R_finite(y1) && R_finite(x) && R_finite(y2); } Yxy::Yxy(int y1, int x, int y2) : y1(y1), x(x), y2(y2) { valid = !(y1 == R_NaInt || x == R_NaInt || y2 == R_NaInt); } void Yxy::Initialize(Rgb *color) { YxyConverter::ToColorSpace(color, this); } void Yxy::ToRgb(Rgb *color) { YxyConverter::ToColor(color, this); } void Yxy::Copy(IColorSpace *color) { Yxy *yxy = static_cast(color); yxy->y1 = y1; yxy->x = x; yxy->y2 = y2; yxy->valid = valid; } void Yxy::Cap() { if (!valid) return; y1 = y1 < 0.0 ? 0.0 : (y1 > 100.0 ? 100.0 : y1); x = x < 0.0 ? 0.0 : x; y2 = y2 < 0.0 ? 0.0 : y2; } Cmy::Cmy() {} Cmy::Cmy(double c, double m, double y) : c(c), m(m), y(y) { valid = R_finite(c) && R_finite(m) && R_finite(y); } Cmy::Cmy(int c, int m, int y) : c(c), m(m), y(y) { valid = !(c == R_NaInt || m == R_NaInt || y == R_NaInt); } void Cmy::Initialize(Rgb *color) { CmyConverter::ToColorSpace(color, this); } void Cmy::ToRgb(Rgb *color) { CmyConverter::ToColor(color, this); } void Cmy::Copy(IColorSpace *color) { Cmy *cmy = static_cast(color); cmy->c = c; cmy->m = m; cmy->y = y; cmy->valid = valid; } void Cmy::Cap() { if (!valid) return; c = c < 0.0 ? 0.0 : (c > 1.0 ? 1.0 : c); m = m < 0.0 ? 0.0 : (m > 1.0 ? 1.0 : m); y = y < 0.0 ? 0.0 : (y > 1.0 ? 1.0 : y); } Cmyk::Cmyk() {} Cmyk::Cmyk(double c, double m, double y, double k) : c(c), m(m), y(y), k(k) { valid = R_finite(c) && R_finite(m) && R_finite(y) && R_finite(k); } Cmyk::Cmyk(int c, int m, int y, int k) : c(c), m(m), y(y), k(k) { valid = !(c == R_NaInt || m == R_NaInt || y == R_NaInt || k == R_NaInt); } void Cmyk::Initialize(Rgb *color) { CmykConverter::ToColorSpace(color, this); } void Cmyk::ToRgb(Rgb *color) { CmykConverter::ToColor(color, this); } void Cmyk::Copy(IColorSpace *color) { Cmyk *cmyk = static_cast(color); cmyk->c = c; cmyk->m = m; cmyk->y = y; cmyk->k = k; cmyk->valid = valid; } void Cmyk::Cap() { if (!valid) return; c = c < 0.0 ? 0.0 : (c > 1.0 ? 1.0 : c); m = m < 0.0 ? 0.0 : (m > 1.0 ? 1.0 : m); y = y < 0.0 ? 0.0 : (y > 1.0 ? 1.0 : y); k = k < 0.0 ? 0.0 : (k > 1.0 ? 1.0 : k); } Hsv::Hsv() {} Hsv::Hsv(double h, double s, double v) : h(h), s(s), v(v) { valid = R_finite(h) && R_finite(s) && R_finite(v); } Hsv::Hsv(int h, int s, int v) : h(h), s(s), v(v) { valid = !(h == R_NaInt || s == R_NaInt || v == R_NaInt); } void Hsv::Initialize(Rgb *color) { HsvConverter::ToColorSpace(color, this); } void Hsv::ToRgb(Rgb *color) { HsvConverter::ToColor(color, this); } void Hsv::Copy(IColorSpace *color) { Hsv *hsv = static_cast(color); hsv->h = h; hsv->s = s; hsv->v = v; hsv->valid = valid; } void Hsv::Cap() { if (!valid) return; h = h < 0.0 ? 0.0 : (h > 360.0 ? 360.0 : h); s = s < 0.0 ? 0.0 : (s > 1.0 ? 1.0 : s); v = v < 0.0 ? 0.0 : (v > 1.0 ? 1.0 : v); } Hsb::Hsb() {} Hsb::Hsb(double h, double s, double b) : h(h), s(s), b(b) { valid = R_finite(h) && R_finite(s) && R_finite(b); } Hsb::Hsb(int h, int s, int b) : h(h), s(s), b(b) { valid = !(h == R_NaInt || s == R_NaInt || b == R_NaInt); } void Hsb::Initialize(Rgb *color) { HsbConverter::ToColorSpace(color, this); } void Hsb::ToRgb(Rgb *color) { HsbConverter::ToColor(color, this); } void Hsb::Copy(IColorSpace *color) { Hsb *hsb = static_cast(color); hsb->h = h; hsb->s = s; hsb->b = b; hsb->valid = valid; } void Hsb::Cap() { if (!valid) return; h = h < 0.0 ? 0.0 : (h > 360.0 ? 360.0 : h); s = s < 0.0 ? 0.0 : (s > 1.0 ? 1.0 : s); b = b < 0.0 ? 0.0 : (b > 1.0 ? 1.0 : b); } HunterLab::HunterLab() {} HunterLab::HunterLab(double l, double a, double b) : l(l), a(a), b(b) { valid = R_finite(l) && R_finite(a) && R_finite(b); } HunterLab::HunterLab(int l, int a, int b) : l(l), a(a), b(b) { valid = !(l == R_NaInt || a == R_NaInt || b == R_NaInt); } void HunterLab::Initialize(Rgb *color) { HunterLabConverter::ToColorSpace(color, this); } void HunterLab::ToRgb(Rgb *color) { HunterLabConverter::ToColor(color, this); } void HunterLab::Copy(IColorSpace *color) { HunterLab *lab = static_cast(color); lab->l = l; lab->a = a; lab->b = b; lab->valid = valid; } void HunterLab::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); } Hcl::Hcl() {} Hcl::Hcl(double h, double c, double l) : h(h), c(c), l(l) { valid = R_finite(h) && R_finite(c) && R_finite(l); } Hcl::Hcl(int h, int c, int l) : h(h), c(c), l(l) { valid = !(h == R_NaInt || c == R_NaInt || l == R_NaInt); } void Hcl::Initialize(Rgb *color) { HclConverter::ToColorSpace(color, this); } void Hcl::ToRgb(Rgb *color) { HclConverter::ToColor(color, this); } void Hcl::Copy(IColorSpace *color) { Hcl *hcl = static_cast(color); hcl->l = l; hcl->c = c; hcl->h = h; hcl->valid = valid; } void Hcl::Cap() { if (!valid) return; h = h < 0.0 ? 0.0 : (h > 360.0 ? 360.0 : h); c = c < 0.0 ? 0.0 : c; l = l < 0.0 ? 0.0 : (l > 100.0 ? 100.0 : l); } } farver/src/Conversion.cpp0000755000176200001440000003263213563052164015175 0ustar liggesusers#include "Conversion.h" #include "ColorSpace.h" #include "Utils.h" #define _USE_MATH_DEFINES #include #include #include #define R_NO_REMAP #include namespace ColorSpace { double Hue_2_RGB(double v1, double v2, double vh) { if (vh < 0) vh += 1; if (vh > 1) vh -= 1; if (6 * vh < 1) return v1 + (v2 - v1) * 6 * vh; if (2 * vh < 1) return v2; if (3 * vh < 2) return v1 + (v2 - v1)*(2.0 / 3.0 - vh) * 6; return v1; } void RgbConverter::ToColorSpace(Rgb *color, Rgb *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; item->r = color->r; item->g = color->g; item->b = color->b; } void RgbConverter::ToColor(Rgb *color, Rgb *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; color->r = item->r; color->g = item->g; color->b = item->b; } void XyzConverter::ToColorSpace(Rgb *color, Xyz *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; double r = color->r / 255.0; double g = color->g / 255.0; double b = color->b / 255.0; r = ((r > 0.04045) ? std::pow((r + 0.055) / 1.055, 2.4) : (r / 12.92)) * 100.0; g = ((g > 0.04045) ? std::pow((g + 0.055) / 1.055, 2.4) : (g / 12.92)) * 100.0; b = ((b > 0.04045) ? std::pow((b + 0.055) / 1.055, 2.4) : (b / 12.92)) * 100.0; item->x = r*0.4124564 + g*0.3575761 + b*0.1804375; item->y = r*0.2126729 + g*0.7151522 + b*0.0721750; item->z = r*0.0193339 + g*0.1191920 + b*0.9503041; } void XyzConverter::ToColor(Rgb *color, Xyz *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; double x = item->x / 100.0; double y = item->y / 100.0; double z = item->z / 100.0; double r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314; double g = x * -0.9692660 + y * 1.8760108 + z * 0.0415560; double b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252; r = ((r > 0.0031308) ? (1.055*std::pow(r, 1 / 2.4) - 0.055) : (12.92*r)) * 255.0; g = ((g > 0.0031308) ? (1.055*std::pow(g, 1 / 2.4) - 0.055) : (12.92*g)) * 255.0; b = ((b > 0.0031308) ? (1.055*std::pow(b, 1 / 2.4) - 0.055) : (12.92*b)) * 255.0; color->r = r; color->g = g; color->b = b; } const double XyzConverter::eps = 216.0 / 24389.0; const double XyzConverter::kappa = 24389.0 / 27.0; Xyz XyzConverter::whiteReference(95.047, 100.000, 108.883); // D65 void XyzConverter::SetWhiteReference(double x, double y, double z) { return; whiteReference.x = x; whiteReference.y = y; whiteReference.z = z; } void HslConverter::ToColorSpace(Rgb *color, Hsl *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; double r = color->r / 255.0; double g = color->g / 255.0; double b = color->b / 255.0; double min = std::min(r, std::min(g, b)); double max = std::max(r, std::max(g, b)); double delta = max - min; item->l = (max + min) / 2; if (delta == 0) { item->h = item->s = 0; } else { if (item->l < 0.5) { item->s = delta / (max + min) * 100; } else { item->s = delta / (1 - std::abs(2 * item->l - 1)) * 100; } if (r == max) { item->h = (g - b) / delta; } else if (g == max) { item->h = (b - r) / delta + 2; } else if (b == max) { item->h = (r - g) / delta + 4; } item->h = std::fmod(60 * item->h + 360, 360); } item->l *= 100; } void HslConverter::ToColor(Rgb *color, Hsl *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; double h = item->h / 360; double s = item->s / 100; double l = item->l / 100; if (item->s == 0) { color->r = color->g = color->b = item->l / 100 * 255; } else { double temp1, temp2; temp2 = (l < 0.5) ? (l*(1 + s)) : (l + s - (s*l)); temp1 = 2 * l - temp2; color->r = 255 * Hue_2_RGB(temp1, temp2, h + 1.0 / 3.0); color->g = 255 * Hue_2_RGB(temp1, temp2, h); color->b = 255 * Hue_2_RGB(temp1, temp2, h - 1.0 / 3.0); } } void LabConverter::ToColorSpace(Rgb *color, Lab *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; const Xyz &white = XyzConverter::whiteReference; Xyz xyz; XyzConverter::ToColorSpace(color, &xyz); double x = xyz.x / white.x; double y = xyz.y / white.y; double z = xyz.z / white.z; x = (x > 0.008856) ? std::cbrt(x) : (7.787 * x + 16.0 / 116.0); y = (y > 0.008856) ? std::cbrt(y) : (7.787 * y + 16.0 / 116.0); z = (z > 0.008856) ? std::cbrt(z) : (7.787 * z + 16.0 / 116.0); item->l = (116.0 * y) - 16; item->a = 500 * (x - y); item->b = 200 * (y - z); } void LabConverter::ToColor(Rgb *color, Lab *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; const Xyz &white = XyzConverter::whiteReference; double y = (item->l + 16.0) / 116.0; double x = item->a / 500.0 + y; double z = y - item->b / 200.0; double x3 = POW3(x); double y3 = POW3(y); double z3 = POW3(z); x = ((x3 > 0.008856) ? x3 : ((x - 16.0 / 116.0) / 7.787)) * white.x; y = ((y3 > 0.008856) ? y3 : ((y - 16.0 / 116.0) / 7.787)) * white.y; z = ((z3 > 0.008856) ? z3 : ((z - 16.0 / 116.0) / 7.787)) * white.z; Xyz xyz(x, y, z); XyzConverter::ToColor(color, &xyz); } void LchConverter::ToColorSpace(Rgb *color, Lch *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Lab lab; LabConverter::ToColorSpace(color, &lab); double l = lab.l; double c = std::sqrt(lab.a*lab.a + lab.b*lab.b); double h = std::atan2(lab.b, lab.a); h = h / M_PI * 180; if (h < 0) { h += 360; } else if (h >= 360) { h -= 360; } item->l = l; item->c = c; item->h = h; } void LchConverter::ToColor(Rgb *color, Lch *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; Lab lab; item->h = item->h * M_PI / 180; lab.l = item->l; lab.a = std::cos(item->h)*item->c; lab.b = std::sin(item->h)*item->c; LabConverter::ToColor(color, &lab); } void LuvConverter::ToColorSpace(Rgb *color, Luv *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; const Xyz &white = XyzConverter::whiteReference; Xyz xyz; XyzConverter::ToColorSpace(color, &xyz); double y = xyz.y / white.y; double temp = (xyz.x + 15 * xyz.y + 3 * xyz.z); double tempr = (white.x + 15 * white.y + 3 * white.z); item->l = (y > XyzConverter::eps) ? (116 * std::cbrt(y) - 16) : (XyzConverter::kappa*y); item->u = 52 * item->l * (((temp > 1e-3) ? (xyz.x / temp) : 0) - white.x / tempr); item->v = 117 * item->l * (((temp > 1e-3) ? (xyz.y / temp) : 0) - white.y / tempr); } void LuvConverter::ToColor(Rgb *color, Luv *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; const Xyz &white = XyzConverter::whiteReference; Xyz xyz; if (item->l == 0.0) { xyz.x = 0.0; xyz.y = 0.0; xyz.z = 0.0; } else { double y = (item->l > XyzConverter::eps*XyzConverter::kappa) ? POW3((item->l + 16) / 116) : (item->l / XyzConverter::kappa); double tempr = white.x + 15 * white.y + 3 * white.z; double up = 4 * white.x / tempr; double vp = 9 * white.y / tempr; double a = 1. / 3. * (52 * item->l / (item->u + 13 * item->l*up) - 1); double b = -5 * y; double x = (y*(39 * item->l / (item->v + 13 * item->l*vp) - 5) - b) / (a + 1. / 3.); double z = x*a + b; /* Weird things can happen at the edge of 0.0*/ if (!ISNAN(z)) { xyz.x = x * 100; xyz.y = y * 100; xyz.z = z * 100; } else { xyz.x = 0.0; xyz.y = 0.0; xyz.z = 0.0; } } XyzConverter::ToColor(color, &xyz); } void YxyConverter::ToColorSpace(Rgb *color, Yxy *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Xyz xyz; XyzConverter::ToColorSpace(color, &xyz); double temp = xyz.x + xyz.y + xyz.z; item->y1 = xyz.y; item->x = (temp==0) ? 0 : (xyz.x / temp); item->y2 = (temp==0) ? 0 : (xyz.y / temp); } void YxyConverter::ToColor(Rgb *color, Yxy *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; Xyz xyz; xyz.x = item->x*(item->y1 / item->y2); xyz.y = item->y1; xyz.z = (1 - item->x - item->y2)*(item->y1 / item->y2); XyzConverter::ToColor(color, &xyz); } void CmyConverter::ToColorSpace(Rgb *color, Cmy *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; item->c = 1 - color->r / 255; item->m = 1 - color->g / 255; item->y = 1 - color->b / 255; } void CmyConverter::ToColor(Rgb *color, Cmy *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; color->r = (1 - item->c) * 255; color->g = (1 - item->m) * 255; color->b = (1 - item->y) * 255; } void CmykConverter::ToColorSpace(Rgb *color, Cmyk *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Cmy cmy; CmyConverter::ToColorSpace(color, &cmy); double k = 1.0; k = std::min(k, cmy.c); k = std::min(k, cmy.m); k = std::min(k, cmy.y); item->k = k; if (std::abs(item->k - 1) < 1e-3) { item->c = 0; item->m = 0; item->y = 0; } else { item->c = (cmy.c - k) / (1 - k); item->m = (cmy.m - k) / (1 - k); item->y = (cmy.y - k) / (1 - k); } } void CmykConverter::ToColor(Rgb *color, Cmyk *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; Cmy cmy; cmy.c = item->c * (1 - item->k) + item->k; cmy.m = item->m * (1 - item->k) + item->k; cmy.y = item->y * (1 - item->k) + item->k; CmyConverter::ToColor(color, &cmy); } void HsvConverter::ToColorSpace(Rgb *color, Hsv *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; double r = color->r / 255.0; double g = color->g / 255.0; double b = color->b / 255.0; double min = std::min(r, std::min(g, b)); double max = std::max(r, std::max(g, b)); double delta = max - min; item->v = max; item->s = (max > 1e-3) ? (delta / max) : 0; if (delta == 0) { item->h = 0; } else { if (r == max) { item->h = (g - b) / delta; } else if (g == max) { item->h = 2 + (b - r) / delta; } else if (b == max) { item->h = 4 + (r - g) / delta; } item->h *= 60; item->h = std::fmod(item->h + 360, 360); } } void HsvConverter::ToColor(Rgb *color, Hsv *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; int range = (int)std::floor(item->h / 60); double c = item->v*item->s; double x = c*(1 - std::abs(std::fmod(item->h / 60, 2) - 1)); double m = item->v - c; switch (range) { case 0: color->r = (c + m) * 255; color->g = (x + m) * 255; color->b = m * 255; break; case 1: color->r = (x + m) * 255; color->g = (c + m) * 255; color->b = m * 255; break; case 2: color->r = m * 255; color->g = (c + m) * 255; color->b = (x + m) * 255; break; case 3: color->r = m * 255; color->g = (x + m) * 255; color->b = (c + m) * 255; break; case 4: color->r = (x + m) * 255; color->g = m * 255; color->b = (c + m) * 255; break; default: // case 5: color->r = (c + m) * 255; color->g = m * 255; color->b = (x + m) * 255; break; } } void HsbConverter::ToColorSpace(Rgb *color, Hsb *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Hsv hsv; HsvConverter::ToColorSpace(color, &hsv); item->h = hsv.h; item->s = hsv.s; item->b = hsv.v; } void HsbConverter::ToColor(Rgb *color, Hsb *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; Hsv hsv; hsv.h = item->h; hsv.s = item->s; hsv.v = item->b; HsvConverter::ToColor(color, &hsv); } void HunterLabConverter::ToColorSpace(Rgb *color, HunterLab *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Xyz xyz; XyzConverter::ToColorSpace(color, &xyz); item->l = 10.0*std::sqrt(xyz.y); item->a = (xyz.y != 0) ? (17.5*(1.02*xyz.x - xyz.y) / std::sqrt(xyz.y)) : 0; item->b = (xyz.y != 0) ? (7.0*(xyz.y - 0.847*xyz.z) / std::sqrt(xyz.y)) : 0; } void HunterLabConverter::ToColor(Rgb *color, HunterLab *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; double x = (item->a / 17.5) *(item->l / 10.0); double y = item->l*item->l / 100; double z = item->b / 7.0 * item->l / 10.0; Xyz xyz((x+y)/1.02, y, -(z-y)/0.847); XyzConverter::ToColor(color, &xyz); } void HclConverter::ToColorSpace(Rgb *color, Hcl *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; Luv luv; LuvConverter::ToColorSpace(color, &luv); double l = luv.l; double c = std::sqrt(luv.u*luv.u + luv.v*luv.v); double h = std::atan2(luv.v, luv.u); h = h / M_PI * 180; if (h < 0) { h += 360; } else if (h >= 360) { h -= 360; } item->l = l; item->c = c; item->h = h; } void HclConverter::ToColor(Rgb *color, Hcl *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; Luv luv; item->h = item->h * M_PI / 180; luv.l = item->l; luv.u = std::cos(item->h)*item->c; luv.v = std::sin(item->h)*item->c; LuvConverter::ToColor(color, &luv); } } farver/src/Makevars0000644000176200001440000000002013562215674014025 0ustar liggesusersCXX_STD = CXX11 farver/src/farver.h0000644000176200001440000001632213563052160013771 0ustar liggesusers#ifndef FARVER_INCLUDED #define FARVER_INCLUDED #include "ColorSpace.h" #include #define R_NO_REMAP #include // these are used in the dispatcher functions // this is one-based in the same order as the `colourspaces` // vector define in aaa.R #define CMY 1 #define CMYK 2 #define HSL 3 #define HSB 4 #define HSV 5 #define LAB 6 #define HUNTERLAB 7 #define LCH 8 #define LUV 9 #define RGB 10 #define XYZ 11 #define YXY 12 #define HCL 13 #define EUCLIDEAN 1 #define CIE1976 2 #define CIE94 3 #define CIE2000 4 #define CMC 5 SEXP convert_c(SEXP colour, SEXP from, SEXP to, SEXP white_from, SEXP white_to); SEXP compare_c(SEXP from, SEXP to, SEXP from_space, SEXP to_space, SEXP dist, SEXP sym, SEXP white_from, SEXP white_to); inline void copy_names(SEXP from, SEXP to) { SEXP names; bool from_matrix = Rf_isMatrix(from); if (from_matrix) { names = PROTECT(Rf_getAttrib(from, Rf_install("dimnames"))); if (!Rf_isNull(names)) { names = VECTOR_ELT(names, 0); } } else { names = PROTECT(Rf_getAttrib(from, R_NamesSymbol)); } if (!Rf_isNull(names)) { if (Rf_isMatrix(to)) { SEXP dn = PROTECT(Rf_allocVector(VECSXP, 2)); SET_VECTOR_ELT(dn, 0, names); Rf_setAttrib(to, Rf_install("dimnames"), dn); UNPROTECT(1); } else { Rf_namesgets(to, names); } } UNPROTECT(1); } inline void copy_names(SEXP from1, SEXP from2, SEXP to) { SEXP names1, names2, names; bool from1_matrix = Rf_isMatrix(from1); bool from2_matrix = Rf_isMatrix(from2); if (from1_matrix) { names1 = PROTECT(Rf_getAttrib(from1, Rf_install("dimnames"))); if (!Rf_isNull(names1)) { names1 = VECTOR_ELT(names1, 0); } } else { names1 = PROTECT(Rf_getAttrib(from1, Rf_install("names"))); } if (from2_matrix) { names2 = PROTECT(Rf_getAttrib(from2, Rf_install("dimnames"))); if (!Rf_isNull(names2)) { names2 = VECTOR_ELT(names2, 0); } } else { names2 = PROTECT(Rf_getAttrib(from2, Rf_install("names"))); } if ((!Rf_isNull(names1) || !Rf_isNull(names2)) && Rf_isMatrix(to)) { names = PROTECT(Rf_allocVector(VECSXP, 2)); if (!Rf_isNull(names1)) { SET_VECTOR_ELT(names, 0, names1); } if (!Rf_isNull(names2)) { SET_VECTOR_ELT(names, 1, names2); } Rf_setAttrib(to, Rf_install("dimnames"), names); UNPROTECT(1); } UNPROTECT(2); } // returns the number of dimensions for a color space type // with a special case for Cmyk template inline int dimension(){ return 3 ; } template <> inline int dimension(){ return 4 ; } // read a color from a color space in the row, and convert it to rgb template inline void fill_rgb(ColorSpace::Rgb* rgb, double x1, double x2, double x3, double x4=0.0){ Space col(x1, x2, x3); col.Cap(); col.ToRgb(rgb); } template <> inline void fill_rgb(ColorSpace::Rgb* rgb, double x1, double x2, double x3, double x4){ ColorSpace::Cmyk col(x1, x2, x3, x4); col.Cap(); col.ToRgb(rgb); } template inline void fill_rgb(ColorSpace::Rgb* rgb, int x1, int x2, int x3, int x4=0){ Space col(x1, x2, x3); col.Cap(); col.ToRgb(rgb); } template <> inline void fill_rgb(ColorSpace::Rgb* rgb, int x1, int x2, int x3, int x4){ ColorSpace::Cmyk col(x1, x2, x3, x4); col.Cap(); col.ToRgb(rgb); } // these grab values from the Space type and use them to fill `row` // unfortunately, given how the `ColorSpace` C++ library is written, // this has to do lots of special casing template inline void grab(const Space&, double* x1, double* x2, double* x3, double* x4) ; template <> inline void grab(const ColorSpace::Rgb& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.r ; *x2 = color.g ; *x3 = color.b ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Xyz& color, double* x1, double* x2, double* x3, double* x4){ *x1 = color.x ; *x2 = color.y ; *x3 = color.z ; } template <> inline void grab(const ColorSpace::Hsl& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.h ; *x2 = color.s ; *x3 = color.l ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Lab& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.l ; *x2 = color.a ; *x3 = color.b ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Lch& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.l ; *x2 = color.c ; *x3 = color.h ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Luv& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.l ; *x2 = color.u ; *x3 = color.v ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Yxy& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.y1 ; *x2 = color.x ; *x3 = color.y2 ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Cmy& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.c ; *x2 = color.m ; *x3 = color.y ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Cmyk& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.c ; *x2 = color.m ; *x3 = color.y ; *x4 = color.k ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; *x4 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Hsv& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.h ; *x2 = color.s ; *x3 = color.v ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Hsb& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.h ; *x2 = color.s ; *x3 = color.b ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::HunterLab& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.l ; *x2 = color.a ; *x3 = color.b ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } template <> inline void grab(const ColorSpace::Hcl& color, double* x1, double* x2, double* x3, double* x4){ if (color.valid) { *x1 = color.h ; *x2 = color.c ; *x3 = color.l ; } else { *x1 = R_NaReal ; *x2 = R_NaReal ; *x3 = R_NaReal ; } } #endif farver/src/Conversion.h0000755000176200001440000000564013562215674014647 0ustar liggesusers#ifndef RGB_CONVERTER_H #define RGB_CONVERTER_H namespace ColorSpace { struct Rgb; struct Xyz; struct Hsl; struct Lab; struct Lch; struct Luv; struct Yxy; struct Cmy; struct Cmyk; struct Hsv; struct Hsb; struct HunterLab; struct Hcl; template struct IConverter { static void ToColorSpace(Rgb *color, TColorSpace *item); static void ToColor(Rgb *color, TColorSpace *item); }; template <> struct IConverter { static void ToColorSpace(Rgb *color, Rgb *item); static void ToColor(Rgb *color, Rgb *item); }; typedef IConverter RgbConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Xyz *item); static void ToColor(Rgb *color, Xyz *item); static const double eps; static const double kappa; static Xyz whiteReference; static void SetWhiteReference(double x, double y, double z); }; typedef IConverter XyzConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Hsl *item); static void ToColor(Rgb *color, Hsl *item); }; typedef IConverter HslConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Lab *item); static void ToColor(Rgb *color, Lab *item); }; typedef IConverter LabConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Lch *item); static void ToColor(Rgb *color, Lch *item); }; typedef IConverter LchConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Luv *item); static void ToColor(Rgb *color, Luv *item); }; typedef IConverter LuvConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Yxy *item); static void ToColor(Rgb *color, Yxy *item); }; typedef IConverter YxyConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Cmy *item); static void ToColor(Rgb *color, Cmy *item); }; typedef IConverter CmyConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Cmyk *item); static void ToColor(Rgb *color, Cmyk *item); }; typedef IConverter CmykConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Hsv *item); static void ToColor(Rgb *color, Hsv *item); }; typedef IConverter HsvConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Hsb *item); static void ToColor(Rgb *color, Hsb *item); }; typedef IConverter HsbConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, HunterLab *item); static void ToColor(Rgb *color, HunterLab *item); }; typedef IConverter HunterLabConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, Hcl *item); static void ToColor(Rgb *color, Hcl *item); }; typedef IConverter HclConverter; } #endif // RGB_CONVERTER_H farver/src/Utils.h0000755000176200001440000000042113562215674013612 0ustar liggesusers#ifndef UTILS_H #define UTILS_H #define SQR(x) ((x)*(x)) #define POW2(x) SQR(x) #define POW3(x) ((x)*(x)*(x)) #define POW4(x) (POW2(x)*POW2(x)) #define POW7(x) (POW3(x)*POW3(x)*(x)) #define DegToRad(x) ((x)*M_PI/180) #define RadToDeg(x) ((x)/M_PI*180) #endif // UTILS_H farver/src/encode.cpp0000644000176200001440000010163213607315417014301 0ustar liggesusers#include "encode.h" #include "ColorSpace.h" #include "farver.h" #include #include #include static char hex8[] = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; static char buffer[] = "#000000"; static char buffera[] = "#00000000"; #ifdef WORDS_BIGENDIAN #include inline int double2int(double d) { return (int)std::round(d); } #else inline int double2int(double d) { d += 6755399441055744.0; return reinterpret_cast(d); } #endif inline int cap0255(int x) { return x < 0 ? 0 : (x > 255 ? 255 : x); } inline int hex2int(const int x) { if (!std::isxdigit(x)) { Rf_errorcall(R_NilValue, "Invalid hexadecimal digit"); } return (x & 0xf) + (x >> 6) + ((x >> 6) << 3); } inline std::string prepare_code(const char* col) { std::string code(col); if (isdigit(col[0])) { int col_num = atoi(col); if (col_num == 0) { code = "0"; } else { code = std::to_string(((col_num - 1) % 8) + 1); } } // Remove whitespace code.erase(std::remove(code.begin(), code.end(), ' '), code.end()); std::transform(code.begin(), code.end(), code.begin(), [](unsigned char c){ return std::tolower(c); }); return code; } template SEXP encode_impl(SEXP colour, SEXP alpha, SEXP white) { int n_channels = dimension(); if (Rf_ncols(colour) < n_channels) { Rf_errorcall(R_NilValue, "Colour in this format must contain at least %i columns", n_channels); } static ColorSpace::Rgb rgb; ColorSpace::XyzConverter::SetWhiteReference(REAL(white)[0], REAL(white)[1], REAL(white)[2]); int n = Rf_nrows(colour); SEXP codes = PROTECT(Rf_allocVector(STRSXP, n)); bool has_alpha = !Rf_isNull(alpha); char alpha1 = '\0'; char alpha2 = '\0'; bool alpha_is_int = false; bool one_alpha = false; char* buf = NULL; int* alpha_i = NULL; double* alpha_d = NULL; if (has_alpha) { buf = buffera; alpha_is_int = Rf_isInteger(alpha); one_alpha = Rf_length(alpha) == 1; int first_alpha; if (alpha_is_int) { alpha_i = INTEGER(alpha); first_alpha = alpha_i[0]; first_alpha = first_alpha == R_NaInt ? 255 : first_alpha; } else { alpha_d = REAL(alpha); if (!R_finite(alpha_d[0])) { first_alpha = 255; } else { first_alpha = double2int(alpha_d[0]); } } first_alpha = cap0255(first_alpha) * 2; alpha1 = hex8[first_alpha]; alpha2 = hex8[first_alpha + 1]; } else { buf = buffer; } int offset1 = 0; int offset2 = offset1 + n; int offset3 = offset2 + n; int offset4 = offset3 + n; int* colour_i = NULL; double* colour_d = NULL; bool colour_is_int = Rf_isInteger(colour); int num; if (colour_is_int) { colour_i = INTEGER(colour); } else { colour_d = REAL(colour); } for (int i = 0; i < n; ++i) { if (colour_is_int) { fill_rgb(&rgb, colour_i[offset1 + i], colour_i[offset2 + i], colour_i[offset3 + i], n_channels == 4 ? colour_i[offset4 + i] : 0); } else { fill_rgb(&rgb, colour_d[offset1 + i], colour_d[offset2 + i], colour_d[offset3 + i], n_channels == 4 ? colour_d[offset4 + i] : 0.0); } if (!rgb.valid) { SET_STRING_ELT(codes, i, R_NaString); continue; } num = double2int(rgb.r); num = cap0255(num) * 2; buf[1] = hex8[num]; buf[2] = hex8[num + 1]; num = double2int(rgb.g); num = cap0255(num) * 2; buf[3] = hex8[num]; buf[4] = hex8[num + 1]; num = double2int(rgb.b); num = cap0255(num) * 2; buf[5] = hex8[num]; buf[6] = hex8[num + 1]; if (has_alpha) { if (one_alpha) { buf[7] = alpha1; buf[8] = alpha2; } else { if (alpha_is_int) { num = alpha_i[i]; } else { num = double2int(alpha_d[i]); } num = cap0255(num) * 2; if (num == 510) { // opaque buf[7] = '\0'; } else { buf[7] = hex8[num]; buf[8] = hex8[num + 1]; } } } SET_STRING_ELT(codes, i, Rf_mkChar(buf)); } copy_names(colour, codes); UNPROTECT(1); return codes; } template<> SEXP encode_impl(SEXP colour, SEXP alpha, SEXP white) { if (Rf_ncols(colour) < 3) { Rf_errorcall(R_NilValue, "Colour in RGB format must contain at least 3 columns"); } int n = Rf_nrows(colour); SEXP codes = PROTECT(Rf_allocVector(STRSXP, n)); bool has_alpha = !Rf_isNull(alpha); char alpha1 = '\0'; char alpha2 = '\0'; bool alpha_is_int = false; bool one_alpha = false; char* buf = NULL; int* alpha_i = NULL; double* alpha_d = NULL; if (has_alpha) { buf = buffera; alpha_is_int = Rf_isInteger(alpha); one_alpha = Rf_length(alpha) == 1; int first_alpha; if (alpha_is_int) { alpha_i = INTEGER(alpha); first_alpha = alpha_i[0]; first_alpha = first_alpha == R_NaInt ? 255 : first_alpha; } else { alpha_d = REAL(alpha); if (!R_finite(alpha_d[0])) { first_alpha = 255; } else { first_alpha = double2int(alpha_d[0]); } } first_alpha = cap0255(first_alpha) * 2; alpha1 = hex8[first_alpha]; alpha2 = hex8[first_alpha + 1]; } else { buf = buffer; } int offset1 = 0; int offset2 = offset1 + n; int offset3 = offset2 + n; int* colour_i = NULL; double* colour_d = NULL; bool colour_is_int = Rf_isInteger(colour); int num; if (colour_is_int) { int r, g, b; colour_i = INTEGER(colour); for (int i = 0; i < n; ++i) { r = colour_i[offset1 + i]; g = colour_i[offset2 + i]; b = colour_i[offset3 + i]; if (r == R_NaInt || g == R_NaInt || b == R_NaInt) { SET_STRING_ELT(codes, i, R_NaString); continue; } num = cap0255(r) * 2; buf[1] = hex8[num]; buf[2] = hex8[num + 1]; num = cap0255(g) * 2; buf[3] = hex8[num]; buf[4] = hex8[num + 1]; num = cap0255(b) * 2; buf[5] = hex8[num]; buf[6] = hex8[num + 1]; if (has_alpha) { if (one_alpha) { buf[7] = alpha1; buf[8] = alpha2; } else { if (alpha_is_int) { num = alpha_i[i]; } else { num = double2int(alpha_d[i]); } num = cap0255(num) * 2; if (num == 510) { // opaque buf[7] = '\0'; } else { buf[7] = hex8[num]; buf[8] = hex8[num + 1]; } } } SET_STRING_ELT(codes, i, Rf_mkChar(buf)); } } else { double r, g, b; colour_d = REAL(colour); for (int i = 0; i < n; ++i) { r = colour_d[offset1 + i]; g = colour_d[offset2 + i]; b = colour_d[offset3 + i]; if (!(R_finite(r) && R_finite(g) && R_finite(b))) { SET_STRING_ELT(codes, i, R_NaString); continue; } num = cap0255(double2int(r)) * 2; buf[1] = hex8[num]; buf[2] = hex8[num + 1]; num = cap0255(double2int(g)) * 2; buf[3] = hex8[num]; buf[4] = hex8[num + 1]; num = cap0255(double2int(b)) * 2; buf[5] = hex8[num]; buf[6] = hex8[num + 1]; if (has_alpha) { if (one_alpha) { buf[7] = alpha1; buf[8] = alpha2; } else { if (alpha_is_int) { num = alpha_i[i]; } else { num = double2int(alpha_d[i]); } num = cap0255(num) * 2; if (num == 510) { // opaque buf[7] = '\0'; } else { buf[7] = hex8[num]; buf[8] = hex8[num + 1]; } } } SET_STRING_ELT(codes, i, Rf_mkChar(buf)); } } copy_names(colour, codes); UNPROTECT(1); return codes; } SEXP encode_c(SEXP colour, SEXP alpha, SEXP from, SEXP white) { switch (INTEGER(from)[0]) { case CMY: return encode_impl(colour, alpha, white); case CMYK: return encode_impl(colour, alpha, white); case HSL: return encode_impl(colour, alpha, white); case HSB: return encode_impl(colour, alpha, white); case HSV: return encode_impl(colour, alpha, white); case LAB: return encode_impl(colour, alpha, white); case HUNTERLAB: return encode_impl(colour, alpha, white); case LCH: return encode_impl(colour, alpha, white); case LUV: return encode_impl(colour, alpha, white); case RGB: return encode_impl(colour, alpha, white); case XYZ: return encode_impl(colour, alpha, white); case YXY: return encode_impl(colour, alpha, white); case HCL: return encode_impl(colour, alpha, white); } // never happens return R_NilValue; } SEXP load_colour_names_c(SEXP name, SEXP value) { ColourMap& named_colours = get_named_colours(); int n = Rf_length(name); if (n != Rf_ncols(value)) { Rf_errorcall(R_NilValue, "name and value must have the same length"); } int* values = INTEGER(value); int it = 0; for (int i = 0; i < n; ++i) { std::string colour_name(Rf_translateCharUTF8(STRING_ELT(name, i))); rgb_colour col; col.r = values[it++]; col.g = values[it++]; col.b = values[it++]; col.a = values[it++]; named_colours[colour_name] = col; } return R_NilValue; } template SEXP decode_impl(SEXP codes, SEXP alpha, SEXP white, SEXP na) { bool get_alpha = LOGICAL(alpha)[0]; int n_channels = dimension(); int n_cols = get_alpha ? n_channels + 1 : n_channels; int n = Rf_length(codes); ColourMap& named_colours = get_named_colours(); SEXP colours = PROTECT(Rf_allocMatrix(REALSXP, n, n_cols)); double* colours_p = REAL(colours); SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; int offset1 = 0; int offset2 = offset1 + n; int offset3 = offset2 + n; int offset4 = offset3 + n; int offset5 = offset4 + n; ColorSpace::Rgb rgb; ColorSpace::XyzConverter::SetWhiteReference(REAL(white)[0], REAL(white)[1], REAL(white)[2]); To to; int nchar; double a; bool has_alpha; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { colours_p[offset1 + i] = R_NaReal; colours_p[offset2 + i] = R_NaReal; colours_p[offset3 + i] = R_NaReal; if (n_cols > 3) colours_p[offset4 + i] = R_NaReal; if (n_cols > 4) colours_p[offset5 + i] = R_NaReal; continue; } code = na_code; } const char* col = Rf_translateCharUTF8(code); if (col[0] == '#') { nchar = strlen(col); has_alpha = nchar == 9; if (!has_alpha && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } rgb.r = hex2int(col[1]) * 16 + hex2int(col[2]); rgb.g = hex2int(col[3]) * 16 + hex2int(col[4]); rgb.b = hex2int(col[5]) * 16 + hex2int(col[6]); if (has_alpha) { a = hex2int(col[7]) * 16 + hex2int(col[8]); a /= 255; } else { a = 1.0; } } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); colours_p[offset1 + i] = R_NaReal; colours_p[offset2 + i] = R_NaReal; colours_p[offset3 + i] = R_NaReal; if (n_cols > 3) colours_p[offset4 + i] = R_NaReal; if (n_cols > 4) colours_p[offset5 + i] = R_NaReal; continue; } else { rgb.r = it->second.r; rgb.g = it->second.g; rgb.b = it->second.b; a = it->second.a; } } ColorSpace::IConverter::ToColorSpace(&rgb, &to); grab(to, colours_p + offset1 + i, colours_p + offset2 + i, colours_p + offset3 + i, n_channels == 4 ? colours_p + offset4 + i : colours_p); if (get_alpha) { colours_p[n_cols == 4 ? offset4 + i : offset5 + i] = a; } } copy_names(codes, colours); UNPROTECT(1); return colours; } template <> SEXP decode_impl(SEXP codes, SEXP alpha, SEXP white, SEXP na) { bool get_alpha = LOGICAL(alpha)[0]; int n = Rf_length(codes); ColourMap& named_colours = get_named_colours(); SEXP colours; double* colours_d = NULL; int* colours_i = NULL; SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; if (get_alpha) { colours = PROTECT(Rf_allocMatrix(REALSXP, n, 4)); colours_d = REAL(colours); } else { colours = PROTECT(Rf_allocMatrix(INTSXP, n, 3)); colours_i = INTEGER(colours); } int offset1 = 0; int offset2 = offset1 + n; int offset3 = offset2 + n; int offset4 = offset3 + n; int r, g, b, nchar; double a; bool has_alpha; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { if (get_alpha) { colours_d[offset1 + i] = R_NaReal; colours_d[offset2 + i] = R_NaReal; colours_d[offset3 + i] = R_NaReal; colours_d[offset4 + i] = R_NaReal; } else { colours_i[offset1 + i] = R_NaInt; colours_i[offset2 + i] = R_NaInt; colours_i[offset3 + i] = R_NaInt; } continue; } code = na_code; } const char* col = Rf_translateCharUTF8(code); if (col[0] == '#') { nchar = strlen(col); has_alpha = nchar == 9; if (!has_alpha && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } r = hex2int(col[1]) * 16 + hex2int(col[2]); g = hex2int(col[3]) * 16 + hex2int(col[4]); b = hex2int(col[5]) * 16 + hex2int(col[6]); if (has_alpha) { a = hex2int(col[7]) * 16 + hex2int(col[8]); a /= 255; } else { a = 1.0; } } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); if (get_alpha) { colours_d[offset1 + i] = R_NaReal; colours_d[offset2 + i] = R_NaReal; colours_d[offset3 + i] = R_NaReal; colours_d[offset4 + i] = R_NaReal; } else { colours_i[offset1 + i] = R_NaInt; colours_i[offset2 + i] = R_NaInt; colours_i[offset3 + i] = R_NaInt; } continue; } else { r = it->second.r; g = it->second.g; b = it->second.b; a = it->second.a; } } if (get_alpha) { colours_d[offset1 + i] = (double) r; colours_d[offset2 + i] = (double) g; colours_d[offset3 + i] = (double) b; colours_d[offset4 + i] = a; } else { colours_i[offset1 + i] = r; colours_i[offset2 + i] = g; colours_i[offset3 + i] = b; } } copy_names(codes, colours); UNPROTECT(1); return colours; } SEXP decode_c(SEXP codes, SEXP alpha, SEXP to, SEXP white, SEXP na) { switch (INTEGER(to)[0]) { case CMY: return decode_impl(codes, alpha, white, na); case CMYK: return decode_impl(codes, alpha, white, na); case HSL: return decode_impl(codes, alpha, white, na); case HSB: return decode_impl(codes, alpha, white, na); case HSV: return decode_impl(codes, alpha, white, na); case LAB: return decode_impl(codes, alpha, white, na); case HUNTERLAB: return decode_impl(codes, alpha, white, na); case LCH: return decode_impl(codes, alpha, white, na); case LUV: return decode_impl(codes, alpha, white, na); case RGB: return decode_impl(codes, alpha, white, na); case XYZ: return decode_impl(codes, alpha, white, na); case YXY: return decode_impl(codes, alpha, white, na); case HCL: return decode_impl(codes, alpha, white, na); } // never happens return R_NilValue; } template SEXP encode_channel_impl(SEXP codes, SEXP channel, SEXP value, SEXP op, SEXP white, SEXP na) { int chan = INTEGER(channel)[0]; int operation = INTEGER(op)[0]; int n = Rf_length(codes); bool one_value = Rf_length(value) == 1; int first_value_i = 0; double first_value_d = 0.0; int* value_i = NULL; double* value_d = NULL; bool value_is_int = Rf_isInteger(value); if (value_is_int) { value_i = INTEGER(value); first_value_i = value_i[0]; } else { value_d = REAL(value); first_value_d = value_d[0]; } SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; SEXP ret = PROTECT(Rf_allocVector(STRSXP, n)); ColorSpace::Rgb rgb; ColorSpace::XyzConverter::SetWhiteReference(REAL(white)[0], REAL(white)[1], REAL(white)[2]); Space colour; int num, nchar; ColourMap& named_colours = get_named_colours(); for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { SET_STRING_ELT(ret, i, R_NaString); continue; } code = na_code; } if ((value_is_int && (one_value ? first_value_i : value_i[i]) == R_NaInt) || (!value_is_int && !R_finite(one_value ? first_value_d : value_d[i]))) { SET_STRING_ELT(ret, i, R_NaString); continue; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); if (nchar != 9 && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } rgb.r = hex2int(col[1]) * 16 + hex2int(col[2]); rgb.g = hex2int(col[3]) * 16 + hex2int(col[4]); rgb.b = hex2int(col[5]) * 16 + hex2int(col[6]); strcpy(buffera, col); } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); SET_STRING_ELT(ret, i, R_NaString); continue; } rgb.r = it->second.r; rgb.g = it->second.g; rgb.b = it->second.b; strcpy(buffera, buffer); if (it->second.a == 0) { buffera[7] = '0'; buffera[8] = '0'; } } ColorSpace::IConverter::ToColorSpace(&rgb, &colour); if (value_is_int) { modify_channel(colour, one_value ? first_value_i : value_i[i], chan, operation); } else { modify_channel(colour, one_value ? first_value_d : value_d[i], chan, operation); } colour.Cap(); colour.ToRgb(&rgb); if (!(R_finite(rgb.r) && R_finite(rgb.g) && R_finite(rgb.b))) { SET_STRING_ELT(ret, i, R_NaString); continue; } num = cap0255(double2int(rgb.r)) * 2; buffera[1] = hex8[num]; buffera[2] = hex8[num + 1]; num = cap0255(double2int(rgb.g)) * 2; buffera[3] = hex8[num]; buffera[4] = hex8[num + 1]; num = cap0255(double2int(rgb.b)) * 2; buffera[5] = hex8[num]; buffera[6] = hex8[num + 1]; SET_STRING_ELT(ret, i, Rf_mkChar(buffera)); } copy_names(codes, ret); UNPROTECT(1); return ret; } template <> SEXP encode_channel_impl(SEXP codes, SEXP channel, SEXP value, SEXP op, SEXP white, SEXP na) { int chan = INTEGER(channel)[0]; int operation = INTEGER(op)[0]; int n = Rf_length(codes); bool one_value = Rf_length(value) == 1; int first_value_i = 0; double first_value_d = 0.0; int* value_i = NULL; double* value_d = NULL; bool value_is_int = Rf_isInteger(value); if (value_is_int) { value_i = INTEGER(value); first_value_i = value_i[0]; } else { value_d = REAL(value); first_value_d = value_d[0]; } SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; SEXP ret = PROTECT(Rf_allocVector(STRSXP, n)); int num, nchar; double new_val; ColourMap& named_colours = get_named_colours(); for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { SET_STRING_ELT(ret, i, R_NaString); continue; } code = na_code; } if ((value_is_int && (one_value ? first_value_i : value_i[i]) == R_NaInt) || (!value_is_int && !R_finite(one_value ? first_value_d : value_d[i]))) { SET_STRING_ELT(ret, i, R_NaString); continue; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); if (nchar != 9 && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } strcpy(buffera, col); } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); SET_STRING_ELT(ret, i, R_NaString); continue; } num = cap0255(it->second.r) * 2; buffera[1] = hex8[num]; buffera[2] = hex8[num + 1]; num = cap0255(it->second.g) * 2; buffera[3] = hex8[num]; buffera[4] = hex8[num + 1]; num = cap0255(it->second.b) * 2; buffera[5] = hex8[num]; buffera[6] = hex8[num + 1]; if (it->second.a == 1) { buffera[7] = '\0'; } else { num = cap0255(it->second.a * 255) * 2; buffera[7] = hex8[num]; buffera[8] = hex8[num + 1]; } } switch (chan) { case 1: new_val = mod_val(hex2int(buffera[1]) * 16 + hex2int(buffera[2]), value_is_int ? (one_value ? first_value_i : value_i[i]) : (one_value ? first_value_d : value_d[i]), operation); // Sometimes I really hate myself num = cap0255(new_val) * 2; buffera[1] = hex8[num]; buffera[2] = hex8[num + 1]; break; case 2: new_val = mod_val(hex2int(buffera[3]) * 16 + hex2int(buffera[4]), value_is_int ? (one_value ? first_value_i : value_i[i]) : (one_value ? first_value_d : value_d[i]), operation); num = cap0255(new_val) * 2; buffera[3] = hex8[num]; buffera[4] = hex8[num + 1]; break; case 3: new_val = mod_val(hex2int(buffera[5]) * 16 + hex2int(buffera[6]), value_is_int ? (one_value ? first_value_i : value_i[i]) : (one_value ? first_value_d : value_d[i]), operation); num = cap0255(new_val) * 2; buffera[5] = hex8[num]; buffera[6] = hex8[num + 1]; break; } SET_STRING_ELT(ret, i, Rf_mkChar(buffera)); } copy_names(codes, ret); UNPROTECT(1); return ret; } SEXP encode_alpha_impl(SEXP codes, SEXP value, SEXP op, SEXP na) { int operation = INTEGER(op)[0]; int n = Rf_length(codes); bool one_value = Rf_length(value) == 1; int first_value_i = 0; double first_value_d = 0.0; int* value_i = NULL; double* value_d = NULL; bool value_is_int = Rf_isInteger(value); if (value_is_int) { value_i = INTEGER(value); first_value_i = value_i[0]; } else { value_d = REAL(value); first_value_d = value_d[0]; } SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; SEXP ret = PROTECT(Rf_allocVector(STRSXP, n)); int alpha, num, nchar; ColourMap& named_colours = get_named_colours(); for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { SET_STRING_ELT(ret, i, R_NaString); continue; } code = na_code; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); if (nchar != 9 && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } strcpy(buffera, col); if (strlen(buffera) == 7) { alpha = 255; } else { alpha = hex2int(buffera[7]) * 16 + hex2int(buffera[8]); } } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); SET_STRING_ELT(ret, i, R_NaString); continue; } num = cap0255(it->second.r) * 2; buffera[1] = hex8[num]; buffera[2] = hex8[num + 1]; num = cap0255(it->second.g) * 2; buffera[3] = hex8[num]; buffera[4] = hex8[num + 1]; num = cap0255(it->second.b) * 2; buffera[5] = hex8[num]; buffera[6] = hex8[num + 1]; alpha = it->second.a * 255; } if (value_is_int) { alpha = double2int(mod_val(alpha / 255.0, one_value ? first_value_i : value_i[i], operation) * 255.0); } else { alpha = double2int(mod_val(alpha / 255.0, one_value ? first_value_d : value_d[i], operation) * 255.0); } alpha = cap0255(alpha); if (alpha == 255) { buffera[7] = '\0'; } else { num = alpha * 2; buffera[7] = hex8[num]; buffera[8] = hex8[num + 1]; } SET_STRING_ELT(ret, i, Rf_mkChar(buffera)); } copy_names(codes, ret); UNPROTECT(1); return ret; } SEXP encode_channel_c(SEXP codes, SEXP channel, SEXP value, SEXP space, SEXP op, SEXP white, SEXP na) { if (INTEGER(channel)[0] == 0) { return encode_alpha_impl(codes, value, op, na); } switch (INTEGER(space)[0]) { case CMY: return encode_channel_impl(codes, channel, value, op, white, na); case CMYK: return encode_channel_impl(codes, channel, value, op, white, na); case HSL: return encode_channel_impl(codes, channel, value, op, white, na); case HSB: return encode_channel_impl(codes, channel, value, op, white, na); case HSV: return encode_channel_impl(codes, channel, value, op, white, na); case LAB: return encode_channel_impl(codes, channel, value, op, white, na); case HUNTERLAB: return encode_channel_impl(codes, channel, value, op, white, na); case LCH: return encode_channel_impl(codes, channel, value, op, white, na); case LUV: return encode_channel_impl(codes, channel, value, op, white, na); case RGB: return encode_channel_impl(codes, channel, value, op, white, na); case XYZ: return encode_channel_impl(codes, channel, value, op, white, na); case YXY: return encode_channel_impl(codes, channel, value, op, white, na); case HCL: return encode_channel_impl(codes, channel, value, op, white, na); } // never happens return R_NilValue; } template SEXP decode_channel_impl(SEXP codes, SEXP channel, SEXP white, SEXP na) { int chan = INTEGER(channel)[0]; int n = Rf_length(codes); SEXP ret = PROTECT(Rf_allocVector(REALSXP, n)); double* ret_p = REAL(ret); ColorSpace::Rgb rgb; ColorSpace::XyzConverter::SetWhiteReference(REAL(white)[0], REAL(white)[1], REAL(white)[2]); Space colour; ColourMap& named_colours = get_named_colours(); int nchar; SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { ret_p[i] = R_NaReal; continue; } code = na_code; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); if (nchar != 9 && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } rgb.r = hex2int(col[1]) * 16 + hex2int(col[2]); rgb.g = hex2int(col[3]) * 16 + hex2int(col[4]); rgb.b = hex2int(col[5]) * 16 + hex2int(col[6]); } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); ret_p[i] = R_NaReal; continue; } rgb.r = it->second.r; rgb.g = it->second.g; rgb.b = it->second.b; } ColorSpace::IConverter::ToColorSpace(&rgb, &colour); colour.Cap(); ret_p[i] = grab_channel(colour, chan); } copy_names(codes, ret); UNPROTECT(1); return ret; } template <> SEXP decode_channel_impl(SEXP codes, SEXP channel, SEXP white, SEXP na) { int chan = INTEGER(channel)[0]; int n = Rf_length(codes); SEXP ret = PROTECT(Rf_allocVector(INTSXP, n)); int* ret_p = INTEGER(ret); ColourMap& named_colours = get_named_colours(); int val = 0; int nchar = 0; SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { ret_p[i] = R_NaInt; continue; } code = na_code; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); if (nchar != 9 && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } switch (chan) { case 1: val = hex2int(col[1]) * 16 + hex2int(col[2]); break; case 2: val = hex2int(col[3]) * 16 + hex2int(col[4]); break; case 3: val = hex2int(col[5]) * 16 + hex2int(col[6]); break; } } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); ret_p[i] = R_NaInt; continue; } switch (chan) { case 1: val = it->second.r; break; case 2: val = it->second.g; break; case 3: val = it->second.b; break; } } ret_p[i] = val; } copy_names(codes, ret); UNPROTECT(1); return ret; } SEXP decode_alpha_impl(SEXP codes, SEXP na) { int n = Rf_length(codes); SEXP ret = PROTECT(Rf_allocVector(REALSXP, n)); double* ret_p = REAL(ret); ColourMap& named_colours = get_named_colours(); int nchar; bool has_alpha; double val; SEXP na_code = STRING_ELT(na, 0); bool na_is_na = na_code == R_NaString; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(codes, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { if (na_is_na) { ret_p[i] = R_NaInt; continue; } code = na_code; } const char* col = CHAR(code); if (col[0] == '#') { nchar = strlen(col); has_alpha = nchar == 9; if (!has_alpha && nchar != 7) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 6 or 8 hex values", col); } if (has_alpha) { val = (hex2int(col[7]) * 16 + hex2int(col[8])) / 255.0; } else { val = 1.0; } } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); ret_p[i] = R_NaReal; continue; } val = it->second.a; } ret_p[i] = val; } copy_names(codes, ret); UNPROTECT(1); return ret; } SEXP decode_channel_c(SEXP codes, SEXP channel, SEXP space, SEXP white, SEXP na) { if (INTEGER(channel)[0] == 0) { return decode_alpha_impl(codes, na); } switch (INTEGER(space)[0]) { case CMY: return decode_channel_impl(codes, channel, white, na); case CMYK: return decode_channel_impl(codes, channel, white, na); case HSL: return decode_channel_impl(codes, channel, white, na); case HSB: return decode_channel_impl(codes, channel, white, na); case HSV: return decode_channel_impl(codes, channel, white, na); case LAB: return decode_channel_impl(codes, channel, white, na); case HUNTERLAB: return decode_channel_impl(codes, channel, white, na); case LCH: return decode_channel_impl(codes, channel, white, na); case LUV: return decode_channel_impl(codes, channel, white, na); case RGB: return decode_channel_impl(codes, channel, white, na); case XYZ: return decode_channel_impl(codes, channel, white, na); case YXY: return decode_channel_impl(codes, channel, white, na); case HCL: return decode_channel_impl(codes, channel, white, na); } // never happens return R_NilValue; } farver/src/ColorSpace.h0000755000176200001440000001032013562465332014541 0ustar liggesusers#ifndef COLOR_SPACE_H #define COLOR_SPACE_H #include #include "Conversion.h" namespace ColorSpace { struct IColorSpace { IColorSpace() {} virtual ~IColorSpace() {} virtual void Initialize(Rgb *color) = 0; virtual void ToRgb(Rgb *color) = 0; virtual void Copy(IColorSpace *color) = 0; virtual void Cap() = 0; template void To(TColorSpace *color); bool valid = true; }; struct Rgb : public IColorSpace { double r, g, b; Rgb(); Rgb(double r, double g, double b); Rgb(int r, int g, int b); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; template void IColorSpace::To(TColorSpace *color) { Rgb rgb; if (typeid(*this) == typeid(*color)) { this->Copy(color); } else { this->ToRgb(&rgb); IConverter::ToColorSpace(&rgb, color); } } struct Xyz : public IColorSpace { double x, y, z; Xyz(); Xyz(double x, double y, double z); Xyz(int x, int y, int z); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Hsl : public IColorSpace { double h, s, l; Hsl(); Hsl(double h, double s, double l); Hsl(int h, int s, int l); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Lab : public IColorSpace { double l, a, b; Lab(); Lab(double l, double a, double b); Lab(int l, int a, int b); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Lch : public IColorSpace { double l, c, h; Lch(); Lch(double l, double c, double h); Lch(int l, int c, int h); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Luv : public IColorSpace { double l, u, v; Luv(); Luv(double l, double u, double v); Luv(int l, int u, int v); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Yxy : public IColorSpace { double y1, x, y2; Yxy(); Yxy(double y1, double x, double y2); Yxy(int y1, int x, int y2); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Cmy : public IColorSpace { double c, m, y; Cmy(); Cmy(double c, double m, double y); Cmy(int c, int m, int y); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Cmyk : public IColorSpace { double c, m, y, k; Cmyk(); Cmyk(double c, double m, double y, double k); Cmyk(int c, int m, int y, int k); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Hsv : public IColorSpace { double h, s, v; Hsv(); Hsv(double h, double s, double v); Hsv(int h, int s, int v); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Hsb : public IColorSpace { double h, s, b; Hsb(); Hsb(double h, double s, double b); Hsb(int h, int s, int b); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct HunterLab : public IColorSpace { double l, a, b; HunterLab(); HunterLab(double l, double a, double b); HunterLab(int l, int a, int b); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; struct Hcl : public IColorSpace { double h, c, l; Hcl(); Hcl(double h, double c, double l); Hcl(int h, int c, int l); virtual void Initialize(Rgb *color); virtual void ToRgb(Rgb *color); virtual void Copy(IColorSpace *color); virtual void Cap(); }; } #endif // COLOR_SPACE_H farver/src/Comparison.cpp0000755000176200001440000001112113607033717015152 0ustar liggesusers#include "Comparison.h" #include "Utils.h" #define _USE_MATH_DEFINES #include namespace ColorSpace { double EuclideanComparison::Compare(IColorSpace *a, IColorSpace *b) { if (!a->valid || !b->valid) return -1.0; Rgb rgb_a; Rgb rgb_b; a->ToRgb(&rgb_a); b->ToRgb(&rgb_b); return std::sqrt(SQR(rgb_a.r - rgb_b.r) + SQR(rgb_a.g - rgb_b.g) + SQR(rgb_a.b - rgb_b.b)); } double Cie1976Comparison::Compare(IColorSpace *a, IColorSpace *b) { if (!a->valid || !b->valid) return -1.0; Lab lab_a; Lab lab_b; a->To(&lab_a); b->To(&lab_b); return std::sqrt(SQR(lab_a.l - lab_b.l) + SQR(lab_a.a - lab_b.a) + SQR(lab_a.b - lab_b.b)); } Cie94Comparison::Application::Application(Cie94Comparison::APPLICATION appType) { switch (appType) { case GRAPHIC_ARTS: kl = 1.0; k1 = 0.045; k2 = 0.015; break; case TEXTILES: kl = 2.0; k1 = 0.048; k2 = 0.014; break; } } double Cie94Comparison::Compare(IColorSpace *a, IColorSpace *b, APPLICATION appType) { if (!a->valid || !b->valid) return -1.0; Application app(appType); Lab lab_a; Lab lab_b; a->To(&lab_a); b->To(&lab_b); double deltaL = lab_a.l - lab_b.l; double deltaA = lab_a.a - lab_b.a; double deltaB = lab_a.b - lab_b.b; double c1 = std::sqrt(SQR(lab_a.a) + SQR(lab_a.b)); double c2 = std::sqrt(SQR(lab_b.a) + SQR(lab_b.b)); double deltaC = c1 - c2; double deltaH = SQR(deltaA) + SQR(deltaB) - SQR(deltaC); double sl = 1.0; double sc = 1.0 + app.k1*c1; double sh = 1.0 + app.k2*c1; deltaL /= app.kl*sl; deltaC /= sc; return std::sqrt(SQR(deltaL) + SQR(deltaC) + deltaH/SQR(sh)); } double Cie2000Comparison::Compare(IColorSpace *a, IColorSpace *b) { if (!a->valid || !b->valid) return -1.0; const double eps = 1e-5; Lab lab_a; Lab lab_b; a->To(&lab_a); b->To(&lab_b); // calculate ci, hi, i=1,2 double c1 = std::sqrt(SQR(lab_a.a) + SQR(lab_a.b)); double c2 = std::sqrt(SQR(lab_b.a) + SQR(lab_b.b)); double meanC = (c1 + c2) / 2.0; double meanC7 = POW7(meanC); double g = 0.5*(1 - std::sqrt(meanC7 / (meanC7 + 6103515625.))); // 0.5*(1-sqrt(meanC^7/(meanC^7+25^7))) double a1p = lab_a.a * (1 + g); double a2p = lab_b.a * (1 + g); c1 = std::sqrt(SQR(a1p) + SQR(lab_a.b)); c2 = std::sqrt(SQR(a2p) + SQR(lab_b.b)); double h1 = std::fmod(std::atan2(lab_a.b, a1p) + 2*M_PI, 2*M_PI); double h2 = std::fmod(std::atan2(lab_b.b, a2p) + 2*M_PI, 2*M_PI); // compute deltaL, deltaC, deltaH double deltaL = lab_b.l - lab_a.l; double deltaC = c2 - c1; double deltah; if (c1*c2 < eps) { deltah = 0; } if (std::abs(h2 - h1) <= M_PI) { deltah = h2 - h1; } else if (h2 > h1) { deltah = h2 - h1 - 2* M_PI; } else { deltah = h2 - h1 + 2 * M_PI; } double deltaH = 2 * std::sqrt(c1*c2)*std::sin(deltah / 2); // calculate CIEDE2000 double meanL = (lab_a.l + lab_b.l) / 2; meanC = (c1 + c2) / 2.0; meanC7 = POW7(meanC); double meanH; if (c1*c2 < eps) { meanH = h1 + h2; } if (std::abs(h1 - h2) <= M_PI + eps) { meanH = (h1 + h2) / 2; } else if (h1 + h2 < 2*M_PI) { meanH = (h1 + h2 + 2*M_PI) / 2; } else { meanH = (h1 + h2 - 2*M_PI) / 2; } double T = 1 - 0.17*std::cos(meanH - DegToRad(30)) + 0.24*std::cos(2 * meanH) + 0.32*std::cos(3 * meanH + DegToRad(6)) - 0.2*std::cos(4 * meanH - DegToRad(63)); double sl = 1 + (0.015*SQR(meanL - 50)) / std::sqrt(20 + SQR(meanL - 50)); double sc = 1 + 0.045*meanC; double sh = 1 + 0.015*meanC*T; double rc = 2 * std::sqrt(meanC7 / (meanC7 + 6103515625.)); double rt = -std::sin(DegToRad(60 * std::exp(-SQR((RadToDeg(meanH) - 275) / 25)))) * rc; return sqrt(SQR(deltaL / sl) + SQR(deltaC / sc) + SQR(deltaH / sh) + rt * deltaC / sc * deltaH / sh); } const double CmcComparison::defaultLightness = 2.; const double CmcComparison::defaultChroma = 1.; double CmcComparison::Compare(IColorSpace *a, IColorSpace *b) { if (!a->valid || !b->valid) return -1.0; Lch lch_a; Lch lch_b; a->To(&lch_a); b->To(&lch_b); double deltaL = lch_a.l - lch_b.l; double deltaC = lch_a.c - lch_b.c; double deltaH = 0; double f = std::sqrt(POW4(lch_a.c) / (POW4(lch_a.c) + 1900)); double t = (164 <= lch_a.h && lch_a.h <= 345) ? (0.56 + std::abs(0.2*std::cos(lch_a.h + 168))) : (0.36 + std::abs(0.4*std::cos(lch_a.h + 35))); double sl = (lch_a.l < 16) ? 0.511 : (0.040975*lch_a.l / (1 + 0.01765*lch_a.l)); double sc = 0.0638*lch_a.c / (1 + 0.0131*lch_a.c) + 0.638; double sh = sc*(f*t + 1 - f); return std::sqrt(SQR(deltaL / (defaultLightness*sl)) + SQR(deltaC / (defaultChroma*sc)) + SQR(deltaH / sh)); } } farver/src/Comparison.h0000755000176200001440000000154113562772161014627 0ustar liggesusers#ifndef COMPARISON_H #define COMPARISON_H #include "ColorSpace.h" namespace ColorSpace { struct EuclideanComparison { static double Compare(IColorSpace *a, IColorSpace *b); }; struct Cie1976Comparison { static double Compare(IColorSpace *a, IColorSpace *b); }; struct Cie94Comparison { enum APPLICATION { GRAPHIC_ARTS = 0, TEXTILES }; struct Application { double kl = 0.0; double k1 = 0.0; double k2 = 0.0; Application(APPLICATION appType); }; static double Compare(IColorSpace *a, IColorSpace *b, APPLICATION appType=GRAPHIC_ARTS); }; struct Cie2000Comparison { static double Compare(IColorSpace *a, IColorSpace *b); }; struct CmcComparison { static const double defaultLightness; static const double defaultChroma; static double Compare(IColorSpace *a, IColorSpace *b); }; } #endif // COMPARISON_H farver/R/0000755000176200001440000000000013562255054011747 5ustar liggesusersfarver/R/encode.R0000644000176200001440000000412413562612243013325 0ustar liggesusers#' Encode colours into RGB hex-strings #' #' This is a version of [grDevices::rgb()] that works with the standard colour #' format used in farver (matrix or data.frame with colours in rows). It further #' support taking input from any colour space. #' #' @inheritSection convert_colour Handling of non-finite and out of bounds values #' #' @inheritParams convert_colour #' @param alpha A numeric vector between 0 and 1. Will be recycled to the number #' of rows in `colour`. If `NULL` or a single `NA` it will be ignored. #' @param from The input colour space. Allowed values are: `"cmy"`, #' `"cmyk"`, `"hsl"`, `"hsb"`, `"hsv"`, `"lab"` (CIE L*ab), `"hunterlab"` #' (Hunter Lab), `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, `"rgb"` (sRGB), #' `"xyz"`, `"yxy"` (CIE xyY), or `"hcl"` (CIE Lch(uv) / polarLuv) #' @param white The white reference of the input colour space. Will only have an #' effect for relative colour spaces such as Lab and luv. Any value accepted by #' [as_white_ref()] allowed. #' #' @return A character vector with colours encoded as `#RRGGBB(AA)` #' #' @family encoding and decoding functions #' #' @note The output may differ slightly from that of [grDevices::rgb()] since #' `rgb()` doesn't round numeric values correctly. #' #' @export #' #' @examples #' spectrum <- decode_colour(rainbow(10)) #' #' encode_colour(spectrum) #' #' # Attach alpha values #' encode_colour(spectrum, alpha = c(0.5, 1)) #' #' # Encode from a different colour space #' spectrum_hcl <- convert_colour(spectrum, 'rgb', 'hcl') #' encode_colour(spectrum_hcl, from = 'hcl') #' encode_colour <- function(colour, alpha = NULL, from = 'rgb', white = 'D65') { if (from != 'rgb') { white <- as_white_ref(white) } encode_c(colour, alpha, colourspace_match(from), white) } encode_c <- function(colour, alpha, from, white) { if (!is.null(alpha)) { alpha <- alpha * 255 if (length(alpha) != 1) { alpha = rep_len(alpha, nrow(colour)) } else if (is.na(alpha) || alpha == 1) { alpha = NULL } } .Call('encode_c', as.matrix(colour), alpha, as.integer(from), white, PACKAGE = 'farver') } farver/R/sysdata.rda0000644000176200001440000001145113607041146014104 0ustar liggesusers\$WY}ٍA ([gaC"G'(njLwgID""$F! *165ʢI@DبA8a(g{Uǿo{zᆵ^u~n9J3};qNf̤w%n_MnΓZqڛ*N:M͢UJ9/֓Fou\rDdC)%>\S#bby9{e3-¶uOt4:dRGH,I޹Bm7?wwYb11 ;s`:6 8P+I \J(yG46(+(l(šTs,i 8P!'m#bbdO:aׇujm<* ,eA4t$Fߟn$uQ8Ĝm7\=$FTJY'[ڌ;L[:RDH\g੺!U˶Z|~lWDdC)Rf 84zMk#Ej;sJUb\%Α(3Fg!(CbTJ5T `čffۨzN>ՕGe,W+[X1UhB+6g36vJJ6P}w|}B(6P@-5ԛڵZ t]  1,5Qy!Hb$y >Z<g=zp&>$$F2dE$KHu)t%#6Ol"%b\,b)KXR.r\,S.1S.1S.1S.1S.12GQ.s2GQ.s2GQ.<2OS.<2OS.<@,P. @,P. @,P."H,R."H,R."D,Q.KD,Q.KD,Q.˔2L,S.˔2L,S.˔˲R˼XQ:h )|vؖk;0xCwh ޡ;4x#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#wd ޑ;2xG#w`nm5,ز­ⴧQKQ;9: |Vyz?9hzqQj+ոR:6fku5%E-mWʼn[kMکͅ(Plā2G {fmz.Db%|ctU˶Ze=y,SY5n^mUHZυ(Plā}#@*4[Ziy}YԢ*Vqȗ*nJй6DjT-j9И RT -`VodI=Jܖx\].,bjL5ҹ$3(3vgQD[%UiQhĸJq&f^7yvZd/g{{f]QV[lKB(6P@ɗۍJ2hi:ɡ.n)lWhf鴟Zd%F?9 ȅ(PlāOzS75~tS65~d3Q(r! (q@0jBbHfw7q-[cۭ,\ Bp]&j̤6?B(6P@[ V!\J(y1HPMXrƕ`AiPLSܙܙۙ[9hE0QYe!. ZIfX2w\NR};]*mKULyůB(6P@xo<zX{\VO :yu;)#$IAuBZ\9zP׃RT9oq'ͭ>@6B)wiO%x>‡ݍd̓X271U#_c!rOx۞?FϟxO)>=KϧCh?)=Ǘ{ יoxڞwxaCmOn_Lq_CGSLq3'NWMv=N$_)~گˌ:ޔxSM#)Z)+1하υJJo.})~] K14SK5'1\OY߇hk ϯ*o|3U}.cK.c)BGS!bo4|^x3?9<ϱ|Wz^ \Ǘr_u|)55?7xz%y?ګ_Mq6~{~̟s_9Z_F/bx2<.7<{^= |sm;C</x ?y)o'@$@4@x | |/@;|^ ak9\_`/@ _  ' K/1\߼ "W_ ~ @ 5r$@ gU@_tR7~ @V 7tR~ @~:@ w ~@   @g a5@?E$@WŸ@) ?O@ףz<.%;G=~]ή_gׯc:ߟåL~= \b]e{>ѯ_ П+L.,{'!W2/$ֿox>xr_8 O_r}!:Nb%923o C#2~1QޏS^9R1\o2!S#c}~0zY}'9z| 5xd>zo^w*ŵ?Vd᷎r>Y;ԟe? 'K ίccK[o:uoךb|2{3c;hzǥ?~xsXϷRKxR/?ԗ_}Z'wp>7</7<!b&cx=MF量=rMnRR|)=zX3yc>TZ_kK߿cėZ}im*u<^=>]ou\ǿ>o;9%֕_ \]TX3E(d}: d Ix2K-Iu:<? w>jx}|̷| #&WF.}1\Nڈ띬 >~C̥!<{Hm\j;_}5>V>i%7E=*6A|E_/^l뙾v(G}֨{>9n7F}>?߫?dkW|e?{L6yMQHܛW3oL1$v˞j<)j$rs~+9}2Rk#d,k}Za!|v ē ׄ7*q^?kʼ0\W%qW]'޺亽^ zox.ZX`=* Qgk1\p= _R48.1u ɮ?r~W|/_AG|,>Wgݟ{{°b.^ф1|۷Ƿ[ڬ"_A䅿J^{(=^oxd:=lO,G/;:6Q^_jSfarver/R/compare_colour.R0000644000176200001440000000456213562612053015106 0ustar liggesusers#' Calculate the distance between colours #' #' There are many ways to measure the distance between colours. `farver` #' provides 5 different algorithms, ranging from simple euclidean distance in #' RGB space, to different perceptual measures such as CIE2000. #' #' @inheritSection convert_colour Handling of non-finite and out of bounds values #' #' @param from,to Numeric matrices with colours to compare - the format is the #' same as that for [convert_colour()]. If `to` is not set `from` will be #' compared with itself and only the upper triangle will get calculated #' #' @param from_space,to_space The colour space of `from` and `to` respectively. #' `to_space` defaults to be the same as `from_space`. #' #' @param method The method to use for comparison. Either `'euclidean'`, #' `'cie1976'`, `'cie94'`, `'cie2000'`, or `'cmc'` #' #' @param white_from,white_to The white reference of the from and to colour #' space. Will only have an effect for relative colour spaces such as Lab and #' luv. Any value accepted by [as_white_ref()] allowed. #' #' @return A numeric matrix with the same number of rows as colours in `from` #' and the same number of columns as colours in `to`. If `to` is not given, only #' the upper triangle will be returned. #' #' @export #' #' @examples #' r <- decode_colour(rainbow(10)) #' h <- decode_colour(heat.colors(15)) #' #' # Compare two sets of colours #' compare_colour(r, h, 'rgb', method = 'cie2000') #' #' # Compare a set of colours with itself #' compare_colour(r, from_space = 'rgb', method = 'cmc') #' #' # Compare colours from different colour spaces #' h_luv <- convert_colour(h, 'rgb', 'luv') #' compare_colour(r, h_luv, 'rgb', 'luv') #' compare_colour <- function(from, to = NULL, from_space, to_space = from_space, method = 'euclidean', white_from = 'D65', white_to = white_from) { sym <- FALSE if (is.null(to)) { to <- from; sym <- TRUE } compare_c(from, to, colourspace_match(from_space), colourspace_match(to_space), distance_match(method), sym, as_white_ref(white_from), as_white_ref(white_to)) } compare_c <- function(from, to, from_space, to_space, method, symmetric, white_from, white_to) { .Call('compare_c', as.matrix(from), as.matrix(to), as.integer(from_space), as.integer(to_space), as.integer(method), as.logical(symmetric), as.numeric(white_from), as.numeric(white_to), PACKAGE = 'farver') } farver/R/zzz.R0000644000176200001440000000214513607314156012730 0ustar liggesusersdef_palette <- NULL def_palette_values <- NULL old_palette <- c("black", "red", "green3", "blue", "cyan", "magenta", "yellow", "gray") old_palette_values <- matrix( c(0L, 0L, 0L, 1L, 255L, 0L, 0L, 1L, 0L, 205L, 0L, 1L, 0L, 0L, 255L, 1L, 0L, 255L, 255L, 1L, 255L, 0L, 255L, 1L, 255L, 255L, 0L, 1L, 190L, 190L, 190L, 1L), nrow = 4 ) modern_palette <- c("black", "#DF536B", "#61D04F", "#2297E6", "#28E2E5", "#CD0BBC", "#F5C710", "gray62") modern_palette_values <- matrix( c(0L, 0L, 0L, 1L, 223L, 83L, 107L, 1L, 97L, 208L, 79L, 1L, 34L, 151L, 230L, 1L, 40L, 226L, 229L, 1L, 205L, 11L, 188L, 1L, 245L, 199L, 16L, 1L, 158L, 158L, 158L, 1L), nrow = 4 ) .onLoad <- function(...) { if (getRversion() < "4.0.0") { def_palette <<- c("transparent", old_palette) def_palette_values <<- cbind(c(255L, 255L, 255L, 0L), old_palette_values) } else { def_palette <<- c("transparent", modern_palette) def_palette_values <<- cbind(c(255L, 255L, 255L, 0L), modern_palette_values) } load_colour_names() } farver/R/decode.R0000644000176200001440000000511413607311164013311 0ustar liggesusers#' Decode RGB hex-strings into colour values #' #' This is a version of [grDevices::col2rgb()] that returns the colour values in #' the standard form expected by farver (matrix with a row per colour). As with #' [encode_colour()] it can do colour conversion on the fly, meaning that you can #' decode a hex string directly into any of the supported colour spaces. #' #' @inheritSection convert_colour Handling of non-finite and out of bounds values #' #' @param colour A character vector of hex-encoded values or a valid colour name #' as given in [grDevices::colours()]. #' @param alpha If `TRUE` the alpha channel will be returned as well (scaled #' between 0 and 1). If no alpha channel exists in the colour it will be #' assumed 1. If `FALSE` any alpha channel is ignored. #' @param to The output colour space. Allowed values are: `"cmy"`, #' `"cmyk"`, `"hsl"`, `"hsb"`, `"hsv"`, `"lab"` (CIE L*ab), `"hunterlab"` #' (Hunter Lab), `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, `"rgb"` (sRGB), #' `"xyz"`, `"yxy"` (CIE xyY), or `"hcl"` (CIE Lch(uv) / polarLuv) #' @param white The white reference of the output colour space. Will only have #' an effect for relative colour spaces such as Lab and luv. Any value accepted #' by [as_white_ref()] allowed. #' @param na_value A valid colour string or `NA` to use when `colour` contains #' `NA` elements. The general approach in farver is to carry `NA` values over, #' but if you want to mimick [col2rgb()] you should set #' `na_value = 'transparent'`, i.e. treat `NA` as transparent white. #' #' #' @return A numeric matrix with a row for each element in `colour` and either #' 3, 4, or 5 columns depending on the value of `alpha` and `to`. #' #' @family encoding and decoding functions #' #' @export #' #' @examples #' # basic use #' decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4')) #' #' # Return alpha as well (no alpha value is interpreted as 1) #' decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4'), alpha = TRUE) #' #' # Decode directly into specific colour space #' decode_colour(c('#43e1f6', 'steelblue', '#67ce9fe4'), to = 'lch') #' decode_colour <- function(colour, alpha = FALSE, to = 'rgb', white = 'D65', na_value = NA) { if (to != 'rgb') { white <- as_white_ref(white) } alpha <- isTRUE(alpha) colours <- decode_c(colour, alpha, colourspace_match(to), white, na_value) colnames(colours) <- c(colour_dims[[to]], if (alpha) 'alpha' else NULL) colours } decode_c <- function(colour, alpha, to, white, na_value) { .Call('decode_c', as_colour_code(colour), alpha, as.integer(to), white, as.character(na_value), PACKAGE = 'farver') } farver/R/aaa.R0000644000176200001440000001221213607315234012607 0ustar liggesuserscolourspaces <- c( "cmy", # 0 "cmyk", # 1 "hsl", # 2 "hsb", # 3 "hsv", # 4 "lab", # 5 "hunterlab", # 6 "lch", # 7 "luv", # 8 "rgb", # 9 "xyz", # 10 "yxy", # 11 "hcl" # 11 ) colour_dims <- list( cmy = c('c', 'm', 'y'), cmyk = c('c', 'm', 'y', 'k'), hsl = c('h', 's', 'l'), hsb = c('h', 's', 'b'), hsv = c('h', 's', 'v'), lab = c('l', 'a', 'b'), hunterlab = c('l', 'a', 'b'), lch = c('l', 'c', 'h'), luv = c('l', 'u', 'v'), rgb = c('r', 'g', 'b'), xyz = c('x', 'y', 'z'), yxy = c('y1', 'x', 'y2'), hcl = c('h', 'c', 'l') ) colour_channel_index <- list( cmy = c('c' = 1L, 'm' = 2L, 'y' = 3L), cmyk = c('c' = 1L, 'm' = 2L, 'y' = 3L, 'k' = 4L), hsl = c('h' = 1L, 's' = 2L, 'l' = 3L), hsb = c('h' = 1L, 's' = 2L, 'b' = 3L), hsv = c('h' = 1L, 's' = 2L, 'v' = 3L), lab = c('l' = 1L, 'a' = 2L, 'b' = 3L), hunterlab = c('l' = 1L, 'a' = 2L, 'b' = 3L), lch = c('l' = 1L, 'c' = 2L, 'h' = 3L), luv = c('l' = 1L, 'u' = 2L, 'v' = 3L), rgb = c('r' = 1L, 'g' = 2L, 'b' = 3L), xyz = c('x' = 1L, 'y' = 2L, 'z' = 3L), yxy = c('y1' = 1L, 'x' = 2L, 'y2' = 3L), hcl = c('h' = 1L, 'c' = 2L, 'l' = 3L) ) distances <- c( "euclidean", "cie1976", "cie94", "cie2000", "cmc" ) operations <- c( "set", "add", "multiply", "least", "most" ) colourspace_match <- function(colour) { m <- pmatch(tolower(colour), colourspaces) if (is.na(m)) stop("Unknown colour space", call. = FALSE) m } distance_match <- function(dist) { m <- pmatch(match.arg(tolower(dist), distances), distances) if (is.na(m)) stop("Unknown distance measure", call. = FALSE) m } operation_match <- function(op) { m <- pmatch(match.arg(tolower(op), operations), operations) if (is.na(m)) stop("Unknown operation", call. = FALSE) m } white_references <- list( "2" = list( A = c(0.44757, 0.40745), B = c(0.34842, 0.35161), C = c(0.31006, 0.31616), D50 = c(0.34567, 0.35850), D55 = c(0.33242, 0.34743), D65 = c(0.31271, 0.32902), D75 = c(0.29902, 0.31485), E = c(1/3, 1/3), F1 = c(0.31310, 0.33727), F2 = c(0.37208, 0.37529), F3 = c(0.40910, 0.39430), F4 = c(0.44018, 0.40329), F5 = c(0.31379, 0.34531), F6 = c(0.37790, 0.38835), F7 = c(0.31292, 0.32933), F8 = c(0.34588, 0.35875), F9 = c(0.37417, 0.37281), F10 = c(0.34609, 0.35986), F11 = c(0.38052, 0.37713), F12 = c(0.43695, 0.40441) ), "10" = list( A = c(0.45117, 0.40594), B = c(0.34980, 0.35270), C = c(0.31039, 0.31905), D50 = c(0.34773, 0.35952), D55 = c(0.33411, 0.34877), D65 = c(0.31382, 0.33100), D75 = c(0.29968, 0.31740), E = c(1/3, 1/3), F1 = c(0.31811, 0.33559), F2 = c(0.37925, 0.36733), F3 = c(0.41761, 0.38324), F4 = c(0.44920, 0.39074), F5 = c(0.31975, 0.34246), F6 = c(0.38660, 0.37847), F7 = c(0.31569, 0.32960), F8 = c(0.34902, 0.35939), F9 = c(0.37829, 0.37045), F10 = c(0.35090, 0.35444), F11 = c(0.38541, 0.37123), F12 = c(0.44256, 0.39717) ) ) #' Convert value to a tristimulus values normalised to Y=100 #' #' This function can take either the name of a standardised illuminants, x #' and y chromaticity coordinates or X, Y, and Z tristimulus values and converts #' it to tristimulus values normalised to Y=100. All Illuminant series A-F are #' supported and can be queried both on the CIE 1931 2° and CIE 1964 10° #' chromaticity coordinates. #' #' @param x A string giving the name of the standardized illuminant or a #' 2 (chromaticity) or 3 (trsitimulus) length numeric vector. #' #' @param fow The field-of-view for the illuminant - either `2` or `10` #' #' @return A 3-length vector with tristimulus values #' #' @keywords internal #' #' @export #' #' @examples #' # Using names #' as_white_ref('D65') #' #' # Using chromaticity values #' as_white_ref(c(0.3, 0.4)) as_white_ref <- function(x, fow = 2) { if (is.character(x)) { x <- white_references[[as.character(fow)]][[toupper(x)]] if (is.null(x)) stop('Unknown white reference', call. = FALSE) } if (is.integer(x)) x <- as.numeric(x) if (!is.numeric(x)) stop('White reference must be a numeric vector', call. = FALSE) if (length(x) == 2) { tmp <- 100/x[2] x <- c( tmp * x[1], 100, tmp * (1 - sum(x)) ) } else if (length(x) == 3) { if (x[2] != 100) { x <- x * 100 / x[2] } } else { stop('White reference must be of length 2 (chromaticity) or 3 (tristimulus)', call. = FALSE) } structure(x, names = c('X', 'Y', 'Z')) } load_colour_names <- function() { .Call('load_colour_names_c', c(all_colours, as.character(seq_along(def_palette) - 1L)), cbind(all_values, def_palette_values), PACKAGE = 'farver') invisible() } as_colour_code <- function(x) { if (is.character(x)) return(x) n <- names(x) if (is.numeric(x)) { if (any(x <= 0, na.rm = TRUE)) { stop("colours encodes as numbers must be positive", call. = FALSE) } x <- as.integer(x) x <- ifelse(x == 0, 1, ((x - 1) %% (length(def_palette) - 1)) + 2) x <- def_palette[x] } else { x <- as.character(x) } names(x) <- n x } farver/R/farver-package.R0000644000176200001440000000006513562613171014747 0ustar liggesusers#' @useDynLib farver #' @keywords internal '_PACKAGE'farver/R/convert_colour.R0000644000176200001440000000613013562612342015132 0ustar liggesusers#' Convert between colour spaces #' #' This function lets you convert between different representations of colours. #' The API is reminiscent of [grDevices::convertColor()], but the performance is #' much better. It is not assured that `grDevices::convertColor()` and #' `convert_colour()` provide numerically equivalent conversion at 16bit level as #' the formula used are potentially slightly different. For all intend and #' purpose, the resulting colours will be equivalent though. #' #' @section Handling of non-finite and out of bounds values: #' `NA`, `NaN`, `-Inf`, and `Inf` are treated as invalid input and will result #' in `NA` values for the colour. If a given colourspace has finite bounds in #' some of their channels, the input will be capped before conversion, and the #' output will be capped before returning, so that both input and output colours #' are valid colours in their respective space. This means that converting back #' and forth between two colourspaces may result in a change in the colour if #' the gamut of one of the spaces is less than the other. #' #' @param colour A numeric matrix (or an object coercible to one) with colours #' encoded in the rows and the different colour space values in the columns. For #' all colourspaces except `'cmyk'` this will mean a matrix with three columns - #' for `'cmyk'` it means four columns. #' #' @param from,to The input and output colour space. Allowed values are: `"cmy"`, #' `"cmyk"`, `"hsl"`, `"hsb"`, `"hsv"`, `"lab"` (CIE L*ab), `"hunterlab"` #' (Hunter Lab), `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, `"rgb"` (sRGB), #' `"xyz"`, `"yxy"` (CIE xyY), or `"hcl"` (CIE Lch(uv) / polarLuv) #' #' @param white_from,white_to The white reference of the from and to colour #' space. Will only have an effect for relative colour spaces such as Lab and #' luv. Any value accepted by [as_white_ref()] allowed. #' #' @return A numeric matrix with the same number of rows as `colour` and either #' 3 or 4 columns depending on the value of `to`. If `colour` is given as a #' `data.frame` the output will be a data.frame as well #' #' @note This function and [convertColor()] are not #' numerically equivalent due to rounding errors, but for all intend and purpose #' they give the same results. #' #' @seealso [grDevices::convertColor()], [grDevices::col2rgb()] #' #' @export #' #' @examples #' spectrum <- decode_colour(rainbow(10)) #' spec_lab <- convert_colour(spectrum, 'rgb', 'lab') #' spec_lab #' #' # Convert between different white references #' convert_colour(spec_lab, 'lab', 'lab', white_from = 'D65', white_to = 'F10') #' convert_colour <- function(colour, from, to, white_from = 'D65', white_to = white_from) { res <- convert_c(colour, colourspace_match(from), colourspace_match(to), as_white_ref(white_from), as_white_ref(white_to)) colnames(res) <- colour_dims[[to]] if (is.data.frame(colour)) res <- as.data.frame(res) res } convert_c <- function(colour, from, to, white_from, white_to) { .Call('convert_c', as.matrix(colour), as.integer(from), as.integer(to), as.numeric(white_from), as.numeric(white_to), PACKAGE = 'farver') } farver/R/modify.R0000644000176200001440000001206513607313626013365 0ustar liggesusers#' Modify colour space channels in hex-encoded colour strings #' #' This set of functions allows you to modify colours as given by strings, #' whithout first decoding them. For large vectors of colour values this should #' provide a considerable speedup. #' #' @param colour A character string giving colours, either as hexadecimal #' strings or accepted colour names. #' @param channel The channel to modify or extract as a single letter, or #' `'alpha'` for the alpha channel. #' @param value The value to modify with #' @param space The colour space the channel pertains to. Allowed values are: #' `"cmy"`, `"cmyk"`, `"hsl"`, `"hsb"`, `"hsv"`, `"lab"` (CIE L*ab), `"hunterlab"` #' (Hunter Lab), `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, `"rgb"` (sRGB), #' `"xyz"`, `"yxy"` (CIE xyY), or `"hcl"` (CIE Lch(uv) / polarLuv) #' @param white The white reference of the channel colour space. Will only have #' an effect for relative colour spaces such as Lab and luv. Any value accepted #' by [as_white_ref()] allowed. #' @param na_value A valid colour string or `NA` to use when `colour` contains #' `NA` elements. The general approach in farver is to carry `NA` values over, #' but if you want to mimick [col2rgb()] you should set #' `na_value = 'transparent'`, i.e. treat `NA` as transparent white. #' #' @return A character vector of the same length as `colour` (or a numeric #' vector in the case of `get_channel()`) #' #' @family encoding and decoding functions #' #' @rdname manip_channel #' @name manip_channel #' #' @examples #' spectrum <- rainbow(10) #' #' # set a specific channel #' set_channel(spectrum, 'r', c(10, 50)) #' set_channel(spectrum, 'l', 50, space = 'lab') #' set_channel(spectrum, 'alpha', c(0.5, 1)) #' #' # Add value to channel #' add_to_channel(spectrum, 'r', c(10, 50)) #' add_to_channel(spectrum, 'l', 50, space = 'lab') #' #' # Multiply a channel #' multiply_channel(spectrum, 'r', c(10, 50)) #' multiply_channel(spectrum, 'l', 50, space = 'lab') #' #' # set a lower bound on a channel #' raise_channel(spectrum, 'r', c(10, 50)) #' raise_channel(spectrum, 'l', 20, space = 'lab') #' #' # set an upper bound on a channel #' cap_channel(spectrum, 'r', c(100, 50)) #' cap_channel(spectrum, 'l', 20, space = 'lab') #' NULL #' @rdname manip_channel #' @export set_channel <- function(colour, channel, value, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } if (length(value) != 1) value <- rep_len(value, length(colour)) encode_channel_c(colour, channel, value, space, 1L, white, na_value) } #' @rdname manip_channel #' @export add_to_channel <- function(colour, channel, value, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } if (length(value) != 1) value <- rep_len(value, length(colour)) encode_channel_c(colour, channel, value, space, 2L, white, na_value) } #' @rdname manip_channel #' @export multiply_channel <- function(colour, channel, value, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } if (length(value) != 1) value <- rep_len(value, length(colour)) encode_channel_c(colour, channel, value, space, 3L, white, na_value) } #' @rdname manip_channel #' @export raise_channel <- function(colour, channel, value, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } if (length(value) != 1) value <- rep_len(value, length(colour)) encode_channel_c(colour, channel, value, space, 4L, white, na_value) } #' @rdname manip_channel #' @export cap_channel <- function(colour, channel, value, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } if (length(value) != 1) value <- rep_len(value, length(colour)) encode_channel_c(colour, channel, value, space, 5L, white, na_value) } #' @rdname manip_channel #' @export get_channel <- function(colour, channel, space = 'rgb', white = 'D65', na_value = NA) { if (space != 'rgb') { white <- as_white_ref(white) } decode_channel_c(colour, channel, space, white, na_value) } encode_channel_c <- function(colour, channel, value, space, op, white, na_value) { if (channel == 'alpha') { channel <- 0L space <- 0L } else { space <- colourspace_match(space) channel <- colour_channel_index[[space]][channel] if (is.na(channel)) stop('Invalid channel for this colourspace', call. = FALSE) } .Call('encode_channel_c', as_colour_code(colour), as.integer(channel), value, as.integer(space), as.integer(op), white, as.character(na_value), PACKAGE = 'farver') } decode_channel_c <- function(colour, channel, space, white, na_value) { if (channel == 'alpha') { channel <- 0L space <- 0L } else { space <- colourspace_match(space) channel <- colour_channel_index[[space]][channel] if (is.na(channel)) stop('Invalid channel for this colourspace', call. = FALSE) } .Call('decode_channel_c', as_colour_code(colour), as.integer(channel), as.integer(space), white, as.character(na_value), PACKAGE = 'farver') } farver/NEWS.md0000644000176200001440000000273213610036734012644 0ustar liggesusers# farver 2.0.3 * Fixed a bug in colour comparison where the blue channel got ignored (#20, @krlmlr) * Allowing `"NA"` and `"transparent"` as valid colour names * How NA should be treated can now be set in all functions accepting colour names * farver now accepts legacy colour specifications as integers indexing into `palette()` as well as integers represented as characters # farver 2.0.2 * Small adjustments to support super weird architectures (#15, #16) * `decode_colour()` now allows you to specify how `NA` should get interpreted * Fixed a major bug in colour comparison * Colour names are now stripped of whitespace and converted to lower-case before conversion, making it behave like `col2rgb()` * An error is now emitted if an unknown colour name is passed into any decoding function # farver 2.0.1 * Fixed symbol remapping issues on Solaris * UPPER and Title case for colour names are now supported alongside lower case # farver 2.0.0 * Added a `NEWS.md` file to track changes to the package. * Remove Rcpp dependency for faster compilation. (#6) * Add support for Lch(uv) (Hcl) for parallel to `grDevices::hcl()` (#9) * Add `encode_colour()` for converting colours in any colourspace into `#RRGGBB` format (#7) * Add `decode_colour()` for converting hexstrings into any colourspace * Fix bug in luv conversion where 0 in the l channel resulted in `NaN` results (#12) * Provide a family of channel manipulation functions to directly manipulate encodes strings farver/MD50000644000176200001440000000511613610063667012062 0ustar liggesusers93ab1f4ff81eb0034e7bcee4a5e67ff5 *DESCRIPTION 928d886d4e8454f3db823a37d4de465f *LICENSE f6212f6fee1f564be1f7c93c06a2baab *LICENSE.note 2a6be4254858a607ce7ea496e237c319 *NAMESPACE 4f51927ae0c0cc07cc3d8c9ee76400f3 *NEWS.md f22832e26b0eef73e6b492b89e70e3d4 *R/aaa.R ea1d417d063ae2ba86d465bddb567082 *R/compare_colour.R dcd06099c9a3c56c07adcfa508e1b384 *R/convert_colour.R ee4b75352988a6acca111ffbbdc851fd *R/decode.R fdcf4350f47aca3d7ee4e086477e00ac *R/encode.R f22b6a10e6409266e1ad6358b702e499 *R/farver-package.R 47ab841ff599bea6b3c4b3dddf522392 *R/modify.R 8f910200bcf81fd218debefd97d8d364 *R/sysdata.rda 8cd108e1de56e977d37940ec3773475f *R/zzz.R 1baabee3e22c942ec1465ab62c6179c2 *README.md 9b08166f6f749e6f8dfdf47ec0b93787 *man/as_white_ref.Rd 51eb58c96bac693b18d40dd76af70c70 *man/compare_colour.Rd fb29d59fe5c2d59d337098d7d74aa4fc *man/convert_colour.Rd cd58f77a07af0b5d0fbede116b402c25 *man/decode_colour.Rd 5a945f529bfd7f6f3132bb2e800a9f03 *man/encode_colour.Rd cc35e26fe810617f3af9c62c2b327421 *man/farver-package.Rd 42d8c41b852e55ff90463ddd02f76ee7 *man/figures/README-unnamed-chunk-4-1.png cf060568a294df113221db0fa6336faf *man/figures/README-unnamed-chunk-5-1.png 89f8d4ee3bb0151db3b228d220f57c87 *man/figures/README-unnamed-chunk-7-1.png 5c229b624b63b959ffbbee167d9538a7 *man/figures/README-unnamed-chunk-8-1.png b12dccad3f106522e2b8c27d2da5db96 *man/figures/logo.png 302477b3e810fb39ae0d592a43b7edd1 *man/figures/logo.svg 98eea2c24fd93543b7a617b373a7b463 *man/manip_channel.Rd e69a94bc02a80803bc198ff16016755d *src/ColorSpace.cpp 3802eaa4a493e55b132b4f9c92654245 *src/ColorSpace.h 3e6ba26e5c67cbb3727be8b89ff2339c *src/Comparison.cpp 96d43e443c981c53b68acc63ca0533d9 *src/Comparison.h 77ae79d5523e8d8f0b20637b034357d5 *src/Conversion.cpp e07278a017af38364d6a7654a8a3d2e5 *src/Conversion.h e3d3cb360fbfdb3c6974e14eb5f09870 *src/Makevars d3bba1d5fc947aebfa39bda1cca79eb2 *src/Utils.h f85ca2e27fe37976a50bb3378d25bad2 *src/encode.cpp e3e5d61b431efa54d9b2f094c793c232 *src/encode.h 2269be547dcd404e007ea21317800e11 *src/farver.cpp 6299d16c938d3a9ddc1ede260847f418 *src/farver.h 19824f3605f9f9e236e5359dd480b623 *src/init.cpp 7a8d7507d0eb35d18b65febf3717119f *tests/testthat.R 48b19c2749c0a8f4b251ea9b7af4a1db *tests/testthat/test-comparison.R 7bdd3ae432a9118b54116dfb1b306a1b *tests/testthat/test-conversion.R 2dadbee83e0efd269f3ebe0cc8ceb660 *tests/testthat/test-decoding.R fb6bc5e80147a4f2aeaa44c47e868e8b *tests/testthat/test-encoding.R b2e35bec6122bb857dcdaf1b2b0017d1 *tests/testthat/test-manip.R ce64e1ca6570df0ca110c4c8c5662562 *tests/testthat/test-names.R c3daed397cca6fb3acff33452356dcef *tests/testthat/test-non-finite.R