farver/0000755000176200001440000000000014620357125011544 5ustar liggesusersfarver/NAMESPACE0000644000176200001440000000056314616657233012777 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(decode_native) export(encode_colour) export(encode_native) export(get_channel) export(multiply_channel) export(raise_channel) export(set_channel) useDynLib(farver, .registration = TRUE) farver/LICENSE.note0000644000176200001440000000245014616657233013526 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/LICENSE0000644000176200001440000000006114616657233012556 0ustar liggesusersYEAR: 2018 COPYRIGHT HOLDER: Thomas Lin Pedersen farver/README.md0000644000176200001440000001620714616707636013044 0ustar liggesusers # farver [![R-CMD-check](https://github.com/thomasp85/farver/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/thomasp85/farver/actions/workflows/R-CMD-check.yaml) [![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) [![Codecov test coverage](https://codecov.io/gh/thomasp85/farver/branch/main/graph/badge.svg)](https://app.codecov.io/gh/thomasp85/farver?branch=main) 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] "#FF0000" "#FF9900" "#CCFF00" "#33FF00" "#00FF66" "#00FFFF" "#0066FF" #> [8] "#3300FF" "#CC00FF" "#FF0099" 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.09796 67.20432 #> [2,] 72.26072 30.17136 77.22610 #> [3,] 93.60533 -41.93879 90.27635 #> [4,] 88.07403 -83.10282 83.59544 #> [5,] 88.19634 -80.27407 57.92961 #> [6,] 91.11322 -48.08151 -14.12690 #> [7,] 47.90478 35.20130 -82.00196 #> [8,] 33.81896 79.70472 -105.27489 #> [9,] 51.90416 91.00028 -74.83009 #> [10,] 55.65103 86.53436 -9.71618 decode_colour(codes, to = 'lab') #> l a b #> [1,] 53.24079 80.09796 67.20432 #> [2,] 72.26072 30.17136 77.22610 #> [3,] 93.60533 -41.93879 90.27635 #> [4,] 88.07403 -83.10282 83.59544 #> [5,] 88.19634 -80.27407 57.92961 #> [6,] 91.11322 -48.08151 -14.12690 #> [7,] 47.90478 35.20130 -82.00196 #> [8,] 33.81896 79.70472 -105.27489 #> [9,] 51.90416 91.00028 -74.83009 #> [10,] 55.65103 86.53436 -9.71618 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] "#FF0C03" "#FF9E0E" "#D5FF1C" "#48FF20" "#33FF74" "#3CFFFF" "#3D77FF" #> [8] "#5A25FF" "#E839FF" "#FF41B4" # Set a channel to a specific value set_channel(codes, 'alpha', c(0.3, 0.7)) #> [1] "#FF00004C" "#FF9900B2" "#CCFF004C" "#33FF00B2" "#00FF664C" "#00FFFFB2" #> [7] "#0066FF4C" "#3300FFB2" "#CC00FF4C" "#FF0099B2" # Limit a channel to a given value cap_channel(codes, 'r', 200) #> [1] "#C80000" "#C89900" "#C8FF00" "#33FF00" "#00FF66" "#00FFFF" "#0066FF" #> [8] "#3300FF" "#C800FF" "#C80099" ``` 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 - OK LAB - LCH(ab) - LCH(uv) - LCH(OK) - 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 ) #> Warning: Some expressions had a GC in every iteration; so filtering is disabled. 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/0000755000176200001440000000000014616657233012327 5ustar liggesusersfarver/man/decode_colour.Rd0000644000176200001440000000614614616657233015433 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:colors]{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{"oklab"}, \code{"lch"} (CIE Lch(ab) / polarLAB), \code{"luv"}, \code{"rgb"} (sRGB), \code{"xyz"}, \code{"yxy"} (CIE xyY), \code{"hcl"} (CIE Lch(uv) / polarLuv), or \code{"oklch"} (Polar form of oklab)} \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.Rd0000644000176200001440000000260114620347561015466 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: style='float: 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{thomas.pedersen@posit.co} (\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}) } Other contributors: \itemize{ \item Posit, PBC [copyright holder, funder] } } \keyword{internal} farver/man/encode_colour.Rd0000644000176200001440000000537614616657233015451 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{"oklab"}, \code{"lch"} (CIE Lch(ab) / polarLAB), \code{"luv"}, \code{"rgb"} (sRGB), \code{"xyz"}, \code{"yxy"} (CIE xyY), \code{"hcl"} (CIE Lch(uv) / polarLuv), or \code{"oklch"} (Polar form of oklab)} \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/native_encoding.Rd0000644000176200001440000000326614616702521015750 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/native.R \name{native-encoding} \alias{native-encoding} \alias{encode_native} \alias{decode_native} \title{Convert to and from the R native colour representation} \usage{ encode_native(colour, ...) decode_native(colour) } \arguments{ \item{colour}{For \code{encode_native} either a vector of hex-encoded colours/colour names or a matrix encoding colours in any of the supported colour spaces. If the latter, the colours will be encoded to a hex string using \code{\link[=encode_colour]{encode_colour()}} first. For \code{decode_native} it is a vector of integers.} \item{...}{Arguments passed on to \code{\link[=encode_colour]{encode_colour()}}} } \value{ \code{encode_native()} returns an integer vector and \code{decode_native()} returns a character vector, both matching the length of the input. } \description{ Colours in R are internally encoded as integers when they are passed around to graphics devices. The encoding splits the 32 bit in the integer between red, green, blue, and alpha, so that each get 8 bit, equivalent to 256 values. It is very seldom that an R user is subjected to this representation, but it is present in the \code{nativeRaster} format which can be obtained from e.g. capturing the content of a graphic device (using \code{dev.capture()}) or reading in PNG files using \code{png::readPNG(native = TRUE)}. It is very rare that you might need to convert back and forth between this format, but it is provided here for completeness. } \examples{ # Get native representation of navyblue and #228B22 native_col <- encode_native(c('navyblue', '#228B22')) native_col # Convert back decode_native(native_col) } farver/man/figures/0000755000176200001440000000000014616707636013776 5ustar liggesusersfarver/man/figures/README-unnamed-chunk-7-1.png0000644000176200001440000006347514616707636020515 0ustar liggesusersPNG  IHDRz4iCCPkCGColorSpaceGenericRGB8U]hU>+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i_@IDATxtD"*",Xbbg%hb%%FTFCXQ{=ɹ.m ݙ3gMd$@@"hq8   N @@ RH9  (  @rs0@@P@@HGzlΜ9dɒ2;֮J_s5l;M4K:^sL+-[Z~}W?qӦMGZ4h`5r<sIh…-9|X.ZhJlٲ2I z W.W_}ՙwqV[%fV"IY+m׮͘1z(@}ܹlKZr!iqҗƍoC͛775 5kѢ /^?(25ϗ5IŒB&gY߾}Yf6lذ69@(C2c) $K4Y+10aoޕ$M飠 *@*of>qDڶmZB@@PP&O\j@ 5" 8ĝxnb-Ɓz ~" P}Cߕ2Pj]P  @5I\Z@85" HDxu6{lwOx! @a aoӦߪU+Ƈ>s馛 :kC@'Y@LB-J @;u.ȑ#Ce˖-]zv)/  @xg[9/N[@M* OV[ikeiѲd @e 2} {ǦLb't5k̵6mnVX~" @ @cxR^$u?*]p 49hvyg{'M$@h  3ИǷplٲFU @[Ϭ5'zmÇw3k݀'@@%O}Z}jT3MJ+ٖ[nYkVj;wi}P O4~$%h]]b*T+\k6=zp۵Γ  PZ>-Uhc@ժO?[o]bZwuުs^@@ >GVڠA$R j\ftM馛֛o|UTTԻ/" @ћ @hj٥ItꖙͫRΏ˚4iR>ݻw9sرcݎ@@ zQBe)P{mb]Mg͚UP5]V[muuYm駟fݖ @@ ZhS4Z[E}:{^܋/&e~WFm۶vhVV6@@ r}3f.j.xB[@_xh\n?4@@%>i;KYnBZ@Nɺ~,=V_k{@@D%Oa\@z/n-m\sMw[mx@ ֡Cg!H> ٝ}@@ P5K߲ ٜ4H/2ҷi@?@(hAjJKgmg^RP[זUih\l @*zu%s̩駭cǎn^4[㏛u܂hTVYe76@R@hoeƏ@nd ǾUZhY5jdM6ں,X`Oh믿sQAsδI )@Z$ Ww{9 )3C%c@ ͋'U C?Ö́ϗ @@ ?غ|3Ѕ ڐ!CVR:sLӝH  P:٧>, 矷ٳgN;k4Tf2G@ hV"6Ê=zs9^!ۨAt> (@ f9g.xwj%رcwߵΧ;&<@@tOՑP*T-e>nm&nVP@(@@ cL>N.[M>zsj9<^떜 X >T端jSL~EqӧOg&|d@5Mx|Z@8QuQTk׮PG@ Vaa~ h.{tذaK`ۨ ^/˓@@ ?غ:6zzVr/^ض~q^Qhs @j ݅g( ^ꂏ:/@'@ʥflY&ҥK3w@H4"Fh]~uY$,k-YJA@0#*D`yYԭ[7w؏? h_.Esd h9O%?3lm)ݻ7|n Ky@ βls$|Pu×2]o\_獊# P*RɧZT)Tۖj ʺkZVlĈzHB@@#N| \K=KߠAٳ'h.'m@X4`r ^i7vwD6mZ96 @@KF2 I삗~^Ixs2    MI{8Tڵ 7О|ɸS>@R%@Y.$Rl{6~x?@@ dА!{ >6rsӷo_k֬~p# =bEq)D3Iu(,xؼys}m ! [.Ya??{챇m֎;81c  hHm!Z@,YFTj+{6n8߿]wu - i M뙍^*bƁk]{[t?cn >\@@ C6e,4k-P@!oN;4_~ž{WC .>82  xğW@; )3-} V,n١CO4=v׻qs̊@ >o2v._XK}7Rvv饗ڨQKD@@ c_t+NPl5.c@/Gm;vs9ǖ.]ms^G@z@2=V>ܮiӦv 'ѣ.eQ86  M),}!r=lv7۔)SJO @HhBO\`>o[$K.袺x@V ] TV?ꨣ_K3{= @ 4.ۚS@=⮻jpwĉn-ZK& Q4 IHՉw_;餓lСN;ëoc@(BQʧYW^y[#?&M N (S7a h:w.R;7tK5I$@UW ~+@@-̀ס^ ogϞvgtz @ %P@hgn?3֝ @~2I%Kk hu=Znmwu[n @(+в:WVhӦM XҥKM] 1~ww}{n @S?'(U( ^Ks7|ymvWo# PVeuܹsjU|?|E;0[wug̘l @*@SqKWbZ@r @5jٳg_\Ǒ@(h phh!ucG)SM-O=kб  M+}|Kg/^8]l׷ /G> !@(v&Xn-?cm„ 6h =EB@l@TS JUݵkWo&OH hYp*YQQP]W: nIB@\@LPO~*@2C9mٲ6do%d{@)@B6ič,Tgrw6m) @[2 -TQ~ۨQ ad@%@2L;c@R'@S]>3wbZ@W-Blܸk}W̻Fw&9  F띪 6էT.\0U.Vfv; 7Ph @"@qWH-o.Jtt}uOw)  Ynټ{6m4WbPWr کS'W|G H4E'3ʪ4hPp@k5l9mС57@.@u-[f?l-pK~e]*, @@|JQt駟lrc7@_*?j͟ZIA;czk  )*%-7|cGqkTEqUV W ʣvtMϷoݶn;;O-4sL[t6|k֬[uUW]x# @~&Vp|Az֭ /(hԽ܋Ih1þ={k֞}Y2d[+ t^J2{; % -)>k,{㏮cuRN1wAR @ڴicGuk>}͞=۵JR9N6_ O/@[nz7ߴz^x[d[j㎳u]N ZN/}_mGR׻Z?wi'Zz5׸;0h@(h)K|슊 wO[nžkر>֯_U-nm9"/.y-h{o?i* @ ~3fp A-[1~%.D%~#GqZ\{D|;P߅OZ`nۭ'z7Q 9KIZzԩ+0z}߶m[[mύ66l3k׮]Τͳ7x&zcᄏ{nժUy}Cи7w\7H`x>f]kRD){+ͤ?#MC,.dHz>335|wS_=irLW~6iĔioO>dUਡknm֫W/aSJ .+ްav(\opAVdR5 ۳{OqZ5YjM6qyd.[sJ$jM;v{xY}p jlqP0]}Q)֫ h=RAo$V7wN8Ѿ[3f УJ姠U~* -߸VSW_}Օ_ݧvzꩉoP QQWy>?JY~{.+.xֱsETuպg}mVEY݇~^(*#vK@A?ノWͧE}#WWހs.)eh7-7j}0a}n“X%zC~ZToz3c 6 r׵ʨYL7bw `LAb\sZR6M#. 'GЗRVVyEAԛ/ԺVx{Z&뾐>a%gzTWf:n|/O? F~v%| r{5PBAr] u7!V>F\tD10i^4Zoq$-6雤ƍjI-&x≶^{:$y_zTpBoީY _Bzso2еPRwkNjԭ]7SMz7ĨY_v+-֯ReѱUFL ,莫񱙉4S @|4S#^smS7:.ң-IGӗ}*fR_llM!Tv5VG`RHz\k ;%ՇSO=e rո nj(袋K/uF1Ϣ D] (\`fRKg] Fz-U7SfmW5@Z5DԗT_^z%7@Z֧kZh}:}]]v-K^kh-;p J@uQh|9(@R+je`S(X>#bnH_nJGXj~VWQ ] T+(8m}5-s Z妉pU됚̳*>LU~u}n`nNDl&\}n M1wsc`O@O?je-uX? /tByrt]wsMԺDޠQW_twvaMG JI5@k hm*q嗻3}hؽR}5M:tј/}ii Rknɍ{W\nc.G ձ|zo]>NR(12U돆-CqCKp m?Mnoܒ>du={&[I];S/Uv҄/Ryw\-}I >F3]=I\54Fclq(e(|t_RO蟮s})O|n{>v|ʧTew{d*|/A%O13ΕRUʍ Zh']XAmI~'յT;S)`T2AIu8 }[Rםʤ_i]'Ljs?t7Z.$MPKڕ(6n/~{1$nIׄaʗdЛ&"S}KzK>]*zlU.?XK su9P`"j'}i }l_QՓ?5Y*gF&*uIy*?﷾rs]ޙd}۟r)e'hzZwR25zS]X 6VE"lcu+LWRCMbQTU]`SRg}]jS҇uUVqKX[Î_OP7䓧>*0o۪Q]!Azz T1 f~VfB@ղOR`R>)/)ҝh>4Y@?= IUefR^Ye|'͘R (V-~]ۖcfrqū  !Pz&"Oxuk<;0誕VTRW_ܘ0uUjV{I&@@<B_^aVDi,K[AfIA"ZHҘ%Z6 WTi @I@Kʟ܃<}>܎3%G@ |ضJ 1V   M rAςWI"g@$@ " Phx庫ϊ &!@@(RHrݷTC||  oxXΏ j nJM@\4pgŠP~Aj @y />P 2U^>߂ N  Ĝ9'@$ &lŤ>pXH $C4)V(-:-@&TŧajMƧ@ C5y@1Pfz df`kn @|6h rJ͛7/-@.@3X4C+-AK^  ?ؗ4" kXxN rj->YkJ A %YFZF'" hi2tɒ%lٲQ?@^/y$w+o [47څr@X t$0ZS h R@hO,KG h,O B@ 1)Elʔ)e˖je>)c&ߢݐR|P5@'sO '`3gάwې!Cj<4 B@6N;;S]v+PR2|j @Nٳmԩv[ǎQ+c Z2( %@+$֭[[nlȑ %D2(  _Z@U=\?~ F7uWnF%% L>` * }AK>  ?_,eYf'\cK&! Ĩ-AK^  /P-TQQQk5jT<>Bt ?}r@@-4x`믭sζۀI&>?~\DS=@B9lvs o?ۤIlSO%bɺ@EF/9>n  f'tƍg~M0>#3fz *E B&y  P9jLW_}NA γaÆ^ڷPΝ; U2 %S%r4Dj[tiSbodRd|Т @<r @v|х  /`_m]wg(UF w^p2D@ rc:urs=w.6 ( cJ4G A Y=z?^}U7HAfmfm]A"PV|kQ8  D$Po{Y˖-m6_u7*_{5"GTdSJ0JZʳ˱@F7o?w+ڊŭ8kSIsj k ]h-_MtJ B@zЏ?شܒԩSҬhRyjժ<@% e(PoyͦM!U.f @V1 ȹRݢ/-^otw_z4IV0'!} 9袋lvט?N嬳βG}4Bl(Z@ @W  9fCZ|Akg+yP @iݜg@H@NmΜ9nH ,?v8ݻ/6Sοؤ৛5k`BvD@ NB5XeUy6bqt낪}~S~\@|tU$s5! @r @ƀn3<:wl￿iz#~ѹtP$E_K@r @EIG{챇tg~oѢ{o ZKk,! /ƀZiҤI曻 -bC W(Mh6a* @C;d @,r@Y)竤TSpSrp@M eB;طLJK" P@N(0d|`f}:@* N IH,"(ƀr! ~PaJK h"8m@@ y90%]b5֝T^[$@H@Nc@}[o=+'ZVB+?&?#IZ32Laɒ/ ȹtn!ɓ'5AgKl֬YO;#ŧZ$ 9IeVtq@ܔu[߾}mԩֵkWWߵ=% M@hXf' )߮ kݺuFN8ZW P?> @)mܸq/BXާ'^c@,Z@u yF@ 6mvm7;s>pU+MwH8p` P h3Uůc@@ 9OB>}0`-Y=P;묳ҩCVP Wx!~վ}s&+@@hΝwߵ#Fؘ1cLmPpv1ԃd@@d9o]wuZ~JV`\:&!t@ 4mΜ9a|@@9G-Z3gڰaO?UW]zmnmacY F O>q{O>?p{C_4< D5o i{iYm6zh6-ܒjR@-x'@@ 9G 7`]tqnذmVv؋/h ]HF @@@ 9٦Mk믿N:x'%e 4]A@ S 1]tp vGݝj^z%즛nÇ|BzeS (Z@5tƌ)P   P@襗^M2'\Oo1C@-v%N r駰C  P")SԹn[XDg2êT-Q$]K?q @V 1*5I{ΫzL h @.E  @رcW^믻RN:g;slv1RHF.^ؖ,Yi9 D#sIFZt~]wSO=6d6m}єL PO+hN7F@ TǀjɕW^iZviРA֮];w$~vE-:3 K wy6|s'wٶb mR65Whqx@T瞶F٨Q!C/>SѣG,C= @}x=?-p  9=k-kf"OF .x:k֬Q@U ThGyĮ 8q9Z7[&î.͜93C? @ YG=&ONz%s>ֹsCF!0|[lYdh ]fϞE8 D,s o}5-@ߵkWWߵT=E)-ZDvX.ȸ9  w][*`N϶CV=/E 4@@ zP]c4z/k՟qz|Kd叛Ij )]vm7;sBQo6p@=EJo 4B@R IHZ>}& 0,YbzuY`XDF`w„ )Vj @ꫯn1ƌcjlܿ+ШP2D@|r@E~CDM9Pߨq@@ ƀFSWQ~A]y@@ ]:ԦT*C7|(L@(hIqpQ& #@Vn 0{b'  MϹ & }@AeGZ  @4'1*(]aPnE @z@s.CI&!iٯ3fV/2F@=QG3gN] 6-[eEa@@ hvb…n-Ψ'! /=* b `*:tG@_4|D~RPiժM6-Cr,@@4$·*:4ju @'] zH@@`8xP]ǯ^.# @r@{")VZɚ6m2VE3w@HhO`WZwˏ;4L D+@w⎦IH@Y>q F@^zyxQ)yr" .tkg%CO@HhNX-PKx  hiȺ6mB df`kMRNBRiN:fx@+@S~睭"IDAT͛gK.-Pհuj @r'`~O&!Id]3@\@sQ*mJ:?\s\@A4Դd?u*)6mUTT@ 4Mťtٲeɗ  PzsZ@W^yekڴi[I۶m]ƾ56+ D)@vŽR?>h. @=K J9S>e-r? @@t6KP-դI2eJ#;@(hp8bZuUmĉ   h.Jef.Rk׎'c# hiNK>*UVYƏZ @ %P;qh sij $U4g.rO<^Eջ/" @2@q"/I15ɗť.G@@K>R'*1g# h0E6nܸu#-) *@(gz2Sk.uZhI?nܸR# @ 1 ơv~  `0>a„ش;v>*7 D$@t{ǥ ^v:u"MEDy@Cr~Zw@Z`APt޼y|j;  Mi ~8 ^qkrC@P1}烾8W]Jlq(e@@@ sK^ gZ@UMرcSmO@(r8yQZ6ѠAҥ}Wyֆ@@ n0&SrG:tka_|EE@@ ?bkZ=ni5״Ζ,YQ@C4rtŦ I?qs׮]mҥƩX@ ,OVQQTGNi~ Z4է7I>z;G6mL>D  h [|Zha۷ewn#Ge( &@Sl_&5z駟ƪ@@ {glkݭ[7w>zrN6Faƍf͚نnh[msS, H!@hNH)'Z,FnҤةZa8o;s-۔6h{o:y0F D$:+#n*Xx6a׿e^VwN:6`2aM7ԵN2|M{   Mι vM75!4iGcA5qGd-eO2a}7|3 %H|?7d >&=-+jh-ΦMos ~)ؠAĠw=sͨCv饗.;?! WD~]~nt!6E]d}78cr?sL%?]2}m쥗^N;c,4VZyꫯv녎5@X$6՚ @]w]7NNwYl?޴V^IKsjL3f̨zu(W픰_T;&r5t ri3;V/rm=]y7 ]&MuQ7}n5V-*ܹsڍ@@1f-]=SKW\aSNuwNر[[ }ֺukj Ew9#t.ղ,n:tHhr>@wȑUdMLݦaÇۤI壥ؤXJ͔Wn׮]m9٨Z^#Y|8ж~X/@n`T3jv~vIP] ?Rn͛7w׈$UgQf*⨝@C}>44Eu90YysKא԰nݺu~U|gjfS;U>Tz7\q7ړO>)-cżѭl9w6~ 4򗿸?R[<.z;v[~G~[]t~.]v٥qX(Ш/~\]U@-[nk5cX[omZH|zчΟpdsVЩ[&%n>b}lŞ @u^V>՗Rjs=k^]ji6s-@_~ٵ?qFZnuyq^j")UOjub{FQ[-}3ѿrJ .BM Ru^3gP+hKA[Rˑ[=.$'z9/rG} JoNz%A9 -W= z>4k]CŴ:g^ 2Vsf@:VʽjL:>)0ј_S+>,@zp gf۞@#PדhV y.WZJ](IKR]t g 5dVi>/r}$vR}gnZ7uUbᆰV28V[6h#7Nz%! 'Y;[c0{146ꆯ+T4yCm۶v![Ԥ|  @'!UM(f֟,X&T?ӧ'nX:뺖5SWkzܹa5䤿-sG[@C}'%Z/c@肯$gMu嘚.xUP >Wj @@ T+  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )@&y! d J  A I^  Y@  @Aj  @VЬDl  h  U4+  )Р2!y!I={mv 7{P7_߮"TxW쬳β_:vXe [o '`/Z9Mh͙ @|_9ԗ:+l2p]35$-ܜ=@@ h\>VI&6p@[}S[G*vmǵwGԩ{_yޗ+о}{gآEH# +@|  ]yq1$Qoq6lc͚5¢Elȑ֠AjL$:u}Gnf{nVѶb S$tsq */b~U/+O6qĪV]uUѣ{a*SQHyt[2!]t qg3-#2|p}]02s=管UVY^Ӹ[Ş~i[xqmڴ du]8lsm.w6p|-o&{7~1cҥKmM7 +͓@T 5#۰a*=\ ^;餓*yx̙I*f͚~_dIEe+jEUV+<σ T~83+{W⨣r@r%k^Kx„ -r;_A/REˊ>j'Ǔ'O\㷢YWVTYW}z}U=7TT~i]=8CuX^A_g$)гgO*_L… cunU/t{?m4c5,/͖Wc/%]׿Uk5WWرcҰUZzk\K5K/u{n*$曭s.]`ʔ)6x`;3ns;o |o޼UD-~~se<@:;x≦޽keTۿo5kGsa6㔾JU;o__` ]͏< LuW$ ?QGPzꩦ1_R3{,5Ti7ܐ4UA*H .poV'ݥ'`U˽NS%jФxj^{Eg}ֵ|3}-mf|goq!C]` LG:BuwfV[z^e[3fpV9}I~Sk\tkdks޽Wxk I Z}UO?}{E- >3>}Qhq`Dt hrѻ*/%j СCkIׇOٮ%mwUW.cuwŽrߝ9 :ThhZ2s3dCy~zӦMf-OS]z?Icn_5\4AiІ^ :uc? a^pcBo2wqzj~f׫+N4hUN>rT7Zk-矻*.>} `rka!z!{?ոlP7nص0ZI*ʗQ.BPo]:mI]uX+?˖ڵA @!CL>ڵkZIve73>6&'ꫦI&jSWU>AGy9fj x8ئVqM:SR* 񂺾~9@w4QNcI hҐ{YOR˴Cmڒ#xzV!'W^yfІ܊3mWA}.B?L,z7^^`D ̝;ZlY̚5n^q-O:$''ԏ.$K_A!y$aMuz ʐ,@@B` hd  P]@@B @@ V1  @9 Pf*MZG l@$ &QvHgaZT[ICNHhO1D$ {UH֤'!I M٣ jn~w;kO1cƸz~wuvꩧرc>Wl? FοmvQGk<@ Bc l֌]t={N&Lr{饗uqZ7ߴ}w!؇~趟7om喦~O{=]@w#-.zFszjѢn%ڵkWwo=\믿ZPxj,Ilȑvj1]oy䑦@(@P @Hz}QԽSlo;w6u)S]' h,ꪫ8B֭k<'f̘a͛7 }V?+}lVC٠AlV3͒ nm y,Р2| G(B@ߗ.]o ji\ hD@@ts%  D*@)7C@ @@T4Rn  @5  h @@k@@ RH9  5,rIENDB`farver/man/figures/README-unnamed-chunk-8-1.png0000644000176200001440000005527214616707636020512 0ustar liggesusersPNG  IHDRz4iCCPkCGColorSpaceGenericRGB8U]hU>+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i_@IDATxe$I. JQ!JI"H JW*x rE EQJ\Z%I{=gfw;I93o}LS˗aC@@ %N)C6  XPN@@T@S&3@@P@@T@S&3@@P@@T[35kYhQkY_uf.\X%=K.fņ+?:wlvjϟ <餓l:DJ+3޻mxoߋ{aOfe^gSSS:Ydɒ؈uݻfz5i?7pތײ#ziЋW_|٫W/lf̘Q[n\|fNK^23g_v"v̙3#>߾fЬ&<|i|)C֫[< -E3SIUM]q?}FA ~Gr&4rF@q@lTpδiWj@@~PȵU!릢p A4"i P'?HJ4)YEbPh7o^ ) hm@ @ @uNmd LԳ P.-BE1\mOm(h[!u(=7'@ r* 9ㆢh I4;# h9隓$/@19 u Y_7#"@@s  w(hQZz @!(s@ T R ٩4" @YKQNH#!G2/LKK֭ҥ ͨ ߔ@XIOJ" 4E@ h] @Y_M@GP[2#@)h׮]-ESI!@Zv @<=lDU@  @04 h|*;wl+/!@5 ОUIh{R< bJ#z@Y_&F4MME@7!xZ"@{ @5TghA h$'gh| f*z@|;!UeAPF PP2#x)z@I^VB#"yp=Z2R@z8HAxPR ML@8 (%P@=Ԧ/.UF" UB@=6.Xu Pnr?G {@I@s` B bG@ ]O M$+@'! T @@ C hO 8z@ @9Eԗ P:j= 4RJ@T c @A#PHD4VE5?O.Ը') @~@h#;mC  G@_|o.e|۝"P22uD/@l6 !@C  @!,Z<@ nиEIIPc%T4S~2Gj (Jhm/A@i+J%[~Z"PPЂ6,B(oOj_ ~eo @X0 h$)\t |¤Y f%O @PEH4x!@E3QH(@pOh@1@ٮ  \QXPN@ z@icQ,$@@X59!@z Z<=r,@ơh PnjC\G(EiI8-\3S!J)@Zf =>eDz@Q@ T= O hd'P9ϝs(ȟhڄ!*t4('EwԈz P6 ;!9 ~" GB 4*B65Blv*y$m=\)-G@ h%ARp=(SnCD@a%Q@1gRc O[P@UV x,@qQt( @/nS3,@Z֧ [jC]v^m1 Q@h/ @= @,XR HN49[RFpC9usr L4g Bq@ ]dIsO+ 7MEA@Lr^al+uE@=o@p=C[+'s>/ @@BJ)z@qN<4x+@mQp( @;4iexW͔)SLB@@jLho>8TAgnlŧMVj -tR9Uj~嗷՜3gե P2В58E?|ph.]l= @l={ Pzҟ @*HհAlcKR&&@ZM@nԩSm)](hƍF Z44;" TuC:Ltܹ@@P@ )j=67]vie5 NTk.-@(!1U.ӧѣa>x@T@Sa&@ %KU9s > @7d(@!>Y#7TW^6ݻqȝh!ƸEHP5kٳb| (+FV @CzFZS"PB4#@ (mjjC{@5PJy { Q>(+.FPr&OȻh[!@)Z9.PTx)@eQh(j=[!xrb = D@*xr+΂4>@%hd  .B J_;Sb*@Z֖ kZzA-ZԺ ^C Z]h+G@?@< I6or.@x PN ~ƌ];~ڴi WEa@,5Z浹Ѳ8QOSv PpNH[K0isCW[9o?@ G9j 8z@t!x]\:D(@VL PzZs@*P x!@E3QH(z@ ^ 2?s{[NlgEoPۏ#@Aj 8u)S~֞_@P""@j +e~mӧOVjc_@ 9nPZm_6}m_@P""@tMwm`]!`ۗР#@^@2 J-sKTO{@[V/u 9 YP@@P]G) sPK sМ7Cr Ժ4\/he.TN1j> ZJ#jP+U(s@KsPQ (<UeT_wPТ M@40U@%?>Su@U!CK0ٳMYԆ?@ ]r\6V[oeWȮu! ڞen7ʇ R"<y4-Sg?xsiy4!@^UKQH#!Ϟ:u3gg P)} ; ~"@@B7m4.Dьȣ@(ackR& %K3g z\ hB% 7мH>}iiiCE /VNVS1ȣh[2i]Cpur9g[q) +@._O~~E@CiM4o-@y\HC@ 2  F4'Ob"Ўs@)^&.eW&ZPعsHŧ4;#@ǝ5s@%=Xh͸T= ^@< u"j!.)[z@1vI ڻ[d<UљaRd%@V{{H 6^)A4S\$&TA  k4F#K$@+;Ϛ5|C=3ToO@ yhʠݻ d@ Ϡ" FΚ7֣G[H>VШ=n(Sp9ȃhZ!2hlssM4&TA zWfXdu ŖσkgQ*;eA4SkRL$@3A%D ĕt4!\rCRDICSLJ,@Z-PR 4]:o޼ҙQaKԯjEHKœZQ/ä655q'\.C <aJ\TP_S #wMVeX Pm'A .uw6R^L"ƾ h bO=& BJ$HI]P^)5 @C `wc.?BIG zz4gL@iJ@T9Q B=<ݐ= $) 9)Ó&@uPEHz:I PlF@8C7#Р@5)ШbYf@,}-\0\HШbYf@KsƸ}$@sl{GUcH[4msXn;HМzH\4!iM46lr>!lۃhD@zP6"ϱ hZ P7.˔p$ [oJh B h$P?z@irE F [@ h)P @ wk Ty!z9 <(.H*oiiCU( PU*S~PMg"$m ף1 hZ | gK F4U@hD@c6! >v wH}gs= ,pAR M9L\|@z=j6z@n%GF@ѱ\@"R)e n he|))!^J|@ 4S9˰O$ Hhm̙@HG4SqCuoq @$mnnyF"ggHY4e nhRڤ@z=qԜ\ٳ @jQ' @r~ɚ:I 4ФZt@ 8s[s" @v*xFgWH]4ud2 .Zps@MƚTHZ@tS'/#1 hZ s(= < .FZDP,"@ cPxۅ P@z@YT< @ZiI'O0u=OHHT+MqHb 1De>v#ыF:wz@ T$Pw't֬YI4@X@ca>j(Cٷ %@d=dz 5A4@N0/n4ApF A8Y`44,%J V>i$wfȐ!=ez@S';ht@ 7h;03}2g}رcz^ ,YbzfRܲyqf=0F2 hSe+nũRc g&@= FP.T> @ZЙ3gɓ'38,i|"Tg|@vE 'uhխ[Ԍb _ ZԧOꫛq}u$J>@/7ǾTԯI T@N=Tsǚ?nWϩWt 6Яl 0<" @Q"$m @pGj3TXI{@K0du к 9<K---UV]W}S*C CГ  k4$1 @wn/t5ט7| < : >՚1֥I! B ׭ɨ0- eC(:}饗̎;h/DF)S &#FoٸoydW}EhZ:M62.7mڴP(@UO~[>ȼO>1=y_!Tz@mKJ^n8^z&CZs#gPܹs%N;4J+MCwy\RM^𪰂Q.D_#{zA @ vrP $*՛ )tz+UPہhT 9*h- @T;n;s 'gy]]we.;$YF!Pm4 38z@U%М5,A6P1fiذafРA~;S|&QH_!ۀC {Q$@b ~6>#n&fmP$]f@|#UeY|gy"eBLSO=eqtGytM=n! ,Y*xz@3l F 7|*{ ; C@ @=Pk~ᄏgp+j*>*t W:}I @C?r @h0cxw5guW`Ö@|坐t+3jG6ȯ@s@UK5%C_f]wלO<ѺuQ/a.^9jw9PcQʧ~R.WJhu_E|@/bswUW]\}f]v1z9Su]ڔC @͛*.>/ ?о}M81D PzPzf͚e6{[s5ԩSK5@G=Y#N@hc'2f/@ EvWrۚR!PfP(a)6UoA]3J@t;Z2\EPh2L7xaO!9*mnnn],F$hǦP_~8# @ 6P Slމ$jS9e1$!@ #zKtV3/B, @TqOP3f̰ݻwϝ;7B"4,z@WV_}u{ G @]~묳~;駟yJaVTC g^@-$P.Y=,D @ O8^9mM7dEhCp]Zz@A  @u8د_b|M+[n|7?xk@u@՜2=9zLe|ݧ"n ƯZ;u]y'ɃD@W<<믿nWTo&Fl-nZiPkxszޚ- Lk1*R:g6y:뮻]HmWj5hpzFZ`ܦCJ v=4XO=Z4ͭ0=˿Ӫ}^z%o~Өt67xg?￿+lP`?S t>ئ_ʬ6TV[meƌc)S>ۮe]ft=GqDT]ܝKTp.VKU(4OL ܦ^[T+kPiZ$ЗٹjG*?>[_Je^{n&]>zO~]DZ^rˮ>hysW״Xzl0`@"Iԓ^szW lGߋYz?LkpB`Q:u^}o6[n9蠃AMk譎Q_o."3j(q}kvs嗛?~szԑ6moS`җBƍ':G.f6CjT| `_cCUaSO5^xƭ7Mm؁]Oڶz?>uW7|s!TCKw< u׿siNAH%ѐf6=ɦ=+|N8և~ߛ߾~ԩSJ  m.@c2?6ȏF~$ۿ[,4_;! ^Z]}uY"L샀/OF)o(HB~l-ux) n FsOsaU &8ܿ7Ob88m51:m *0/K;|D7+}c|Csh 0@OVc o m:um֣-@=w}֠c@"{ @BAip7ak\ʫ7{-zR陼7zG7O?~FO뢪m^=/:к Kd) n2SԫP ofin-[xNԻYLAlX~w}8Էv>6hD.dP}bPU;~cMRݦQ"{tWp3}C6zN=vߕbmzaZztU~\iHk⁷~Y^;:wܦ}5t[S<>_uUo[;XEeqΕ矫~ @"~=6 {ڦ^j85PI d/pbя~d 0駶=ԷUV?,!`êGTn; 2JA=nM"mjP/M=$^7T n:wDVO4/i{^j'}}OvD}xVnkJoq]zZY/ocߧb UIY *3]}ZG^O^;EFm2hlϢZȐ!UVx{yt\0ЮoۈzL wtT *з-{5N߂Їz&0H@~O=[zA9ۈ nk_Zz%UvmgQFNjluwuȑv}„ UO`>Y704w2@_u-JDz! I U$B/aԐzGov\c5Wۅ.@msnd]TViHHVxs+Z__v"sTJC*;a:sa}հ|rIwͫTÑTWWn!@ v_\VWPw[}^UZ 4gB'#^Mr&_{z1xHA#_Nn)O=JdV)U`TZ9(^0,w=ssmʨ@l-F@.AHi~alwymVYՓt/y-D5RL7UQ 8O~jO7VZ[eN @+*{z뭭+ۦ &2D3Q%KSw++j wZup~gh}  @Փ^CdV] V,AZ Vm5Xy,W.j; d!*U~_=ΦPD#;`4<D}ph|L5Wj2< i @u"-ѕ/RnOjoAgP._M@@ -V׺~zu&~Ҫ LClTA+mUM@@ i}K5E,W]u{&&[:=J^Хy@ZD#ؒ:%1coSZr*怆U"JɃ  @TtYmhԨQ?otw"Yj^=@@ s@w3Ҙ1c̀ݍtW$l4S$Ͷ@\'0C5<w馛s9uLش/^zz@ H @ @wyg_~^fر't# #{.@;) " @K/p vݕ6/Y{C@ |׮]m AC% X>SlV+>Ƀ4P Ih*MC&  PE tc5o3rO͸qY5퇢,BJu@*B?~9r8q :u ГO>ޞn2LS2 )!@XJ t衇jzk Я6?Ovk]*aHO@s@hz  @Νk~i;ާO d>hsw>/ D\Q.99" ?B X^۫zL@T9j!h< BZ;c=^^٨Wk1_|1bD9"6(s@ړ9 DIs=ͰaLSS>|YhoQG1[vS u@Pz@lB@(VX<3 b6dl D4"w@.:z>oeS @S R@%jhHmTeL@(hZ2u@U]  zpbT#n\)! @IаwBRO@z.P?ۚR# P"h*  P"4%K" s!4:U@@cPPV;=~" @i'_@#$  M^G:---%C@ i:Ν[S@MԷRިC6gΜ*  hB4  @ 0>=uԧ֥ OmueO@PF,r=*%@ MC9<v%t.n~١aG@@ .и$3LgѢEn|E  `@ pD'-@S@< \ѣMMMF,BrD@4@N(/ Gb(eRB B  Юh<~<Tԏ QV5@[ZZ"-BR @=ox 7wmQ9@@ eДN:w)iH\ 1 ƈER4j|E  Pσz{@r'$#  z@ @ M[<Psc  Ŕߝ.\h %C@m=P ]sS`@ !@y3;gϞf\# oXEyݻMi)'  h^oh^l٦Mx@ 5<P"# PrPOue# ,r=AE~G@4@N z;'577&($  ˓']h[qfZ |ۘ" P4P['0<'G@CP-Xdu J; %@tBzP&0$ 5@kD#=JG;SJ@$@ykt))>  DZt8@#@F)h]s@ @]vY[CМ64B@`7ܹsm @2,c>C5(: "@KKU)g\V/(=Uy@b 4 @ӳ&'@O4>Srh=[ >!@@#ЎrVkktP:yd* 6@HT4Qdw=^T\~MKK @m2RG@/@=> \GJ+d%^}UE(:  @C+(cCb"  hl'gJꪫ_~9# JVڹsgӥKXjW^%-A@j ֒qq\UUԩSjx?@@@M1=q,@rE^c5ƍs@]4v"8~z*J N&T묳y'=V  wмP;K"]wukf̙N< /@Z]G*.H(]xahP@@ N85SNKqUWYel~kCv  PP[:!N:^y@ 潅)_B,Zy @O>\Tz盗^z)  P,PShwBrk[c &@e ix|O>g{k5>{$ zz|G,` 7bR/+  h)ܖ[nDrh_|axD'Q@(m&TJ++<  WмLz̀L׮];س~{SO'xD8@>}'G駟VT4Nn2k9蠃駟n^|E?@gWIDAT@@~m3zh{)^hJ4wW?fmfGik/k] D2 @5Oq]w5}5/6&L0K,1+QmƌW^fvZٳ&ӦM3F{Wn=^+ԩSmK5Q}]Ior:키g}֌;N6F2+2=㏭zO ftkz)St:w\ 9hR>-9._͢SNA |6@̂ ̥^jۡ_xG1\rM{N3_̘1c̝wi*@g}YeUyg74;9ͳ ހ+FGs1[n1gq8p`G… wa.ZS ,.Dml /~RѠA׿uOkݻCUozmB9NL_/[6=/Tellb9sG2,cfϞm/ز#V7?F%Zֳf >s[ubk=L8s̺}tp/x#*6oPUHJYgen&!Pmv9ÍC9x6]t 4=\k֦ HGu @oߠ] PCno&wR?l?,:LWV> *u}k_3lYVO /`>p*wkm6tS*h}猾LMAvmgN*wy=O@h@`W $PG+v"{챇т.+xQM6~P/݈#̽k~aIgiѽ5#o-(tka>sgb?_y啺,СCk&~yMPGz ݹI'N¨*HUЫNjuz5]ge\;=R9׹RM/yQ7<*k+Ou$7J4BVӦ_ދ٣Yl'`j*|2dRg˫κ/WTe]z3ճ\׳'xݤn9}jXl-x{^nS ze.xͱPU5j(_[&T#[!^=K/7njHX=k}[ѼNy\y6Uv[o؀r 60`gFU#[@@Pp 7`F30|M=Ztyv @@ ^!URh:TgXo5ܩab>|P>A1ݼCyCnV ?_|{ 3/LMxm$TZTOc@@:(Tqu@@ kЬ[@@ .  h-@  @@KT@Z4 @@d%kp d-@u ?  P2В58E@ ͺ@(h" Y f Ld Nu@@@nG@J&@Z  @Y# % -YS]@@ kЬ[@@ .  h-@  @@KT@Z4 @@d%kp d-@u ?  P2В58E@ ͺ@(h" Y f Ld Nu@@@nG@J&@Z  @Y# % -YS]@@ kЬ[@@ .  h-@  @@KT@Z4 @@d%kp d-@u ?  P2В58E@ ͺ@(h" Y f Ld Nu@@@nG@J&@Z  @Y# % -YS]@@ kЬ[@@ .  h-@  @@KT@Z4 @@d%kp d-@u ?  P2В58E@ ͺ@(h" Y f Ld Nu@@@nG@J&@Z  @Y# % -YS]@@ kЬ[@@ .  h-@  @@KT@Z4 @@d%kp d-u!Cફ2gyyWH4)p駛{u]5x6h#sqǙ$Y*?O͂ _Y/.=,x$dl$-lIgC_ u]s7  @]R͍@V_}uN;%I#O_vqGvYM7,Zpghᚔ ! `>C@@ Ix_JR~mCye^"`6^ax e@!uǛ{^g]K..O繸ޖ;0/lN:$ۺ4Rӧ_'h$ewMF(jJӷo6s5]tF+?S3p@ӽ{_|aVXa{Lt )S>뮻 6̘1Þ'N4={4}^irX]{5G6xͅ^hvek:|lS5kYp}]ؤIkZmfm\|`e]My4-D@  LSSS.'>(` ?s3a Y71 4(`8s[$^zi+CsIڛoi9s=^z}+LΝ9Zjװ^ڴ4>tվ5L}Zko?e]f\sM{Gava%v/&̹ctlD*o})m찞~^oқ}=ϩS:P~ t}'TnS{oٜ[n13a^~e q9Μ9pv^n|.ꫯý7t`Gw* ѹZ˜r)6״oN@oQQO|rK[ Ii8ue>FP~nw h~3lVkXq:6ߜkRiDn3'|9[} 2JQi0ȑ#Ysv|N;?oSѹ[z'^ӓ4}Su%lqF4<ܺu~ꩧ9f+a!PM@܎=X{pmv k8ׂ\'|>/n ]/fY;tpn:q7GU==^witn=guVka59#Xz/CD4Tx;킆z8:thr#1cMy/]HsW]uU(L*կw]M6ľճKy4tSϰ]we}||lo%)#Z@+Lp衇#ZT JcڹG}tS:43ƹF)3Z@ Tç4-\t3{T|x/-ƺmЪe }ٸ/-E9@a-^ҢK950 P!VΟg6{ngkZǫ7P| @C+QF@@@P*  oE@< )>  o-Fy@@@=o@*_m/]z@@}n=ʎ /[Ohᛝ "Px71Dzv-25 ϭG@g}=oVFlo_tE{5\rm̨Q̻k}gO:$3bsAx!@2y uz֡+Y͒%K_n>=co/zc=L>}w}ͳ>k3gl͌!.ꫯt/H@ QoonFrիO+˜s9c>#UN07ގT=묳/~a<@{HB4 UDRxmO[s5m^wr-g&Nh|p{^&M2 `D MR@T~M6t+gǪc @qj cZ.Zҥ\;ܨ HK૯iH> 9~x;w3A5v( ~÷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.png0000644000176200001440000005546214616657233020504 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@-= 3.0.0) Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.3.1 NeedsCompilation: yes Packaged: 2024-05-13 08:31:27 UTC; thomas Author: Thomas Lin Pedersen [cre, aut] (), Berendea Nicolae [aut] (Author of the ColorSpace C++ library), Romain François [aut] (), Posit, PBC [cph, fnd] Maintainer: Thomas Lin Pedersen Repository: CRAN Date/Publication: 2024-05-13 09:33:09 UTC farver/tests/0000755000176200001440000000000014616657233012716 5ustar liggesusersfarver/tests/testthat/0000755000176200001440000000000014620357125014546 5ustar liggesusersfarver/tests/testthat/test-conversion.R0000644000176200001440000000253614616706745020054 0ustar liggesusersspectrum <- 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.R0000644000176200001440000000161414616706736020035 0ustar liggesusersspectrum <- 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.R0000644000176200001440000000516114616657233016765 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.R0000644000176200001440000000300514616657233017442 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.R0000644000176200001440000000163314616707363017727 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[-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.R0000644000176200001440000000334114616657233017433 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.R0000644000176200001440000000136514616657233016766 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.R0000644000176200001440000000056414616657233014706 0ustar liggesusers# This file is part of the standard setup for testthat. # It is recommended that you do not modify it. # # Where should you do additional test configuration? # Learn more about the roles of various files in: # * https://r-pkgs.org/tests.html # * https://testthat.r-lib.org/reference/test_package.html#special-files library(testthat) library(farver) test_check("farver") farver/src/0000755000176200001440000000000014620347737012343 5ustar liggesusersfarver/src/farver.cpp0000644000176200001440000003266114616705154014340 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); case OKLAB: return convert_dispatch_impl(colour, white_from, white_to); case OKLCH: 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); case OKLAB: return convert_dispatch_to(colour, to, white_from, white_to); case OKLCH: 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); case OKLAB: return compare_dispatch_impl(from, to, dist, sym, white_from, white_to); case OKLCH: 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); case HCL: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case OKLAB: return compare_dispatch_to(from, to, to_space, dist, sym, white_from, white_to); case OKLCH: 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, SEXP lightness, SEXP chroma) { ColorSpace::CmcComparison::defaultLightness = REAL(lightness)[0]; ColorSpace::CmcComparison::defaultChroma = REAL(chroma)[0]; 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.cpp0000644000176200001440000000207514616701406014006 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[] = { {"farver_convert_c", (DL_FUNC) &convert_c, 5}, {"farver_compare_c", (DL_FUNC) &compare_c, 10}, {"farver_encode_c", (DL_FUNC) &encode_c, 4}, {"farver_decode_c", (DL_FUNC) &decode_c, 5}, {"farver_encode_channel_c", (DL_FUNC) &encode_channel_c, 7}, {"farver_decode_channel_c", (DL_FUNC) &decode_channel_c, 5}, {"farver_load_colour_names_c", (DL_FUNC) &load_colour_names_c, 2}, {"farver_encode_native_c", (DL_FUNC) &encode_native_c, 1}, {"farver_decode_native_c", (DL_FUNC) &decode_native_c, 1}, {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.h0000644000176200001440000002302214616657233013750 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); SEXP encode_native_c(SEXP color); SEXP decode_native_c(SEXP native); 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 void modify_channel(ColorSpace::OkLab& 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::OkLch& 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 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; } template <> inline double grab_channel(ColorSpace::OkLab& 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::OkLch& color, int channel){ switch (channel) { case 1: return color.l; case 2: return color.c; case 3: return color.h; } return 0.0; } #endif farver/src/ColorSpace.cpp0000755000176200001440000002530314616657233015107 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); } OkLab::OkLab() {} OkLab::OkLab(double l, double a, double b) : l(l), a(a), b(b) { valid = R_finite(l) && R_finite(a) && R_finite(b); } OkLab::OkLab(int l, int a, int b) : l(l), a(a), b(b) { valid = !(l == R_NaInt || a == R_NaInt || b == R_NaInt); } void OkLab::Initialize(Rgb *color) { OkLabConverter::ToColorSpace(color, this); } void OkLab::ToRgb(Rgb *color) { OkLabConverter::ToColor(color, this); } void OkLab::Copy(IColorSpace *color) { OkLab *lab = static_cast(color); lab->l = l; lab->a = a; lab->b = b; lab->valid = valid; } void OkLab::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 1.0 ? 1.0 : l); } OkLch::OkLch() {} OkLch::OkLch(double l, double c, double h) : l(l), c(c), h(h) { valid = R_finite(l) && R_finite(c) && R_finite(h); } OkLch::OkLch(int l, int c, int h) : l(l), c(c), h(h) { valid = !(l == R_NaInt || c == R_NaInt || h == R_NaInt); } void OkLch::Initialize(Rgb *color) { OkLchConverter::ToColorSpace(color, this); } void OkLch::ToRgb(Rgb *color) { OkLchConverter::ToColor(color, this); } void OkLch::Copy(IColorSpace *color) { OkLch *lch = static_cast(color); lch->l = l; lch->c = c; lch->h = h; lch->valid = valid; } void OkLch::Cap() { if (!valid) return; l = l < 0.0 ? 0.0 : (l > 1.0 ? 1.0 : l); } } farver/src/Conversion.cpp0000755000176200001440000004027214616703164015177 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) { 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); } // Using values reported at https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab // instead of going through xyz. This ensures any whitepoint is ignored void OkLabConverter::ToColorSpace(Rgb *color, OkLab *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)); g = ((g > 0.04045) ? std::pow((g + 0.055) / 1.055, 2.4) : (g / 12.92)); b = ((b > 0.04045) ? std::pow((b + 0.055) / 1.055, 2.4) : (b / 12.92)); double l = 0.4121656120 * r + 0.5362752080 * g + 0.0514575653 * b; double m = 0.2118591070 * r + 0.6807189584 * g + 0.1074065790 * b; double s = 0.0883097947 * r + 0.2818474174 * g + 0.6302613616 * b; l = std::cbrt(l); m = std::cbrt(m); s = std::cbrt(s); item->l = 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s; item->a = 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s; item->b = 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s; } void OkLabConverter::ToColor(Rgb *color, OkLab *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; double l = item->l + 0.3963377774 * item->a + 0.2158037573 * item->b; double m = item->l - 0.1055613458 * item->a - 0.0638541728 * item->b; double s = item->l - 0.0894841775 * item->a - 1.2914855480 * item->b; l = l * l * l; m = m * m * m; s = s * s * s; double r = 4.0767245293 * l - 3.3072168827 * m + 0.2307590544 * s; double g = -1.2681437731 * l + 2.6093323231 * m - 0.3411344290 * s; double b = -0.0041119885 * l - 0.7034763098 * m + 1.7068625689 * s; color->r = ((r > 0.0031308) ? (1.055*std::pow(r, 1 / 2.4) - 0.055) : (12.92*r)) * 255.0; color->g = ((g > 0.0031308) ? (1.055*std::pow(g, 1 / 2.4) - 0.055) : (12.92*g)) * 255.0; color->b = ((b > 0.0031308) ? (1.055*std::pow(b, 1 / 2.4) - 0.055) : (12.92*b)) * 255.0; } void OkLchConverter::ToColorSpace(Rgb *color, OkLch *item) { if (!color->valid) { item->valid = false; return; } item->valid = true; OkLab lab; OkLabConverter::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 OkLchConverter::ToColor(Rgb *color, OkLch *item) { if (!item->valid) { color->valid = false; return; } color->valid = true; OkLab 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; OkLabConverter::ToColor(color, &lab); } } farver/src/farver.h0000644000176200001440000001751514616702074014004 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 OKLAB 14 #define OKLCH 15 #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, SEXP lightness, SEXP chroma); 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 ; } } template <> inline void grab(const ColorSpace::OkLab& 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::OkLch& 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 ; } } #endif farver/src/Conversion.h0000755000176200001440000000650014616657233014645 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; struct OkLab; struct OkLch; 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; template <> struct IConverter { static void ToColorSpace(Rgb *color, OkLab *item); static void ToColor(Rgb *color, OkLab *item); }; typedef IConverter OkLabConverter; template <> struct IConverter { static void ToColorSpace(Rgb *color, OkLch *item); static void ToColor(Rgb *color, OkLch *item); }; typedef IConverter OkLchConverter; } #endif // RGB_CONVERTER_H farver/src/Utils.h0000755000176200001440000000042114616657233013614 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.cpp0000644000176200001440000011132214616667636014314 0ustar liggesusers#include "encode.h" #include "ColorSpace.h" #include "farver.h" #include #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); case OKLAB: return encode_impl(colour, alpha, white); case OKLCH: 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, shrt; 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 || nchar == 5; shrt = nchar < 7; if (!has_alpha && (nchar != 7 && nchar != 4)) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 3, 4, 6 or 8 hex values", col); } rgb.r = shrt ? hex2int(col[1]) * 16 + hex2int(col[1]) : hex2int(col[1]) * 16 + hex2int(col[2]); rgb.g = shrt ? hex2int(col[2]) * 16 + hex2int(col[2]) : hex2int(col[3]) * 16 + hex2int(col[4]); rgb.b = shrt ? hex2int(col[3]) * 16 + hex2int(col[3]) : hex2int(col[5]) * 16 + hex2int(col[6]); if (has_alpha) { a = shrt ? hex2int(col[4]) * 16 + hex2int(col[4]) : 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, shrt; 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 || nchar == 5; shrt = nchar < 7; if (!has_alpha && (nchar != 7 && nchar != 4)) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 3, 4, 6 or 8 hex values", col); } r = shrt ? hex2int(col[1]) * 16 + hex2int(col[1]) : hex2int(col[1]) * 16 + hex2int(col[2]); g = shrt ? hex2int(col[2]) * 16 + hex2int(col[2]) : hex2int(col[3]) * 16 + hex2int(col[4]); b = shrt ? hex2int(col[3]) * 16 + hex2int(col[3]) : hex2int(col[5]) * 16 + hex2int(col[6]); if (has_alpha) { a = shrt ? hex2int(col[4]) * 16 + hex2int(col[4]) : 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); case OKLAB: return decode_impl(codes, alpha, white, na); case OKLCH: 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 && nchar != 5 && nchar != 4) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 3, 4, 6 or 8 hex values", col); } if (nchar < 7) { buffera[1] = buffera[2] = col[1]; buffera[3] = buffera[4] = col[2]; buffera[5] = buffera[6] = col[3]; if (nchar == 5) { buffera[7] = buffera[8] = col[4]; } else { buffera[7] = '\0'; } } else { strcpy(buffera, col); } rgb.r = hex2int(buffera[1]) * 16 + hex2int(buffera[2]); rgb.g = hex2int(buffera[3]) * 16 + hex2int(buffera[4]); rgb.b = hex2int(buffera[5]) * 16 + hex2int(buffera[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); 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 && nchar != 5 && nchar != 4) { Rf_errorcall(R_NilValue, "Malformed colour string `%s`. Must contain either 3, 4, 6 or 8 hex values", col); } if (nchar < 7) { buffera[1] = buffera[2] = col[1]; buffera[3] = buffera[4] = col[2]; buffera[5] = buffera[6] = col[3]; if (nchar == 5) { buffera[7] = buffera[8] = col[4]; } else { buffera[7] = '\0'; } } else { 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); case OKLAB: return encode_channel_impl(codes, channel, value, op, white, na); case OKLCH: 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); case OKLAB: return decode_channel_impl(codes, channel, white, na); case OKLCH: return decode_channel_impl(codes, channel, white, na); } // never happens return R_NilValue; } SEXP encode_native_c(SEXP color) { int n = Rf_length(color); ColourMap& named_colours = get_named_colours(); SEXP natives = PROTECT(Rf_allocVector(INTSXP, n)); int* natives_p = INTEGER(natives); int nchar; bool has_alpha; for (int i = 0; i < n; ++i) { SEXP code = STRING_ELT(color, i); if (code == R_NaString || strcmp("NA", CHAR(code)) == 0) { natives_p[i] = NA_INTEGER; } 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); } natives_p[i] = R_RGBA( hex2int(col[1]) * 16 + hex2int(col[2]), hex2int(col[3]) * 16 + hex2int(col[4]), hex2int(col[5]) * 16 + hex2int(col[6]), has_alpha ? hex2int(col[7]) * 16 + hex2int(col[8]) : 255 ); } else { ColourMap::iterator it = named_colours.find(prepare_code(col)); if (it == named_colours.end()) { Rf_errorcall(R_NilValue, "Unknown colour name: %s", col); natives_p[i] = NA_INTEGER; } else { natives_p[i] = R_RGB(it->second.r, it->second.g, it->second.b); } } } copy_names(color, natives); UNPROTECT(1); return natives; } SEXP decode_native_c(SEXP native) { int n = Rf_length(native); SEXP codes = PROTECT(Rf_allocVector(STRSXP, n)); char* buf = buffera; int* native_p = INTEGER(native); int num; for (int i = 0; i < n; ++i) { if (native_p[i] == R_NaInt) { SET_STRING_ELT(codes, i, R_NaString); continue; } num = R_RED(native_p[i]) * 2; buf[1] = hex8[num]; buf[2] = hex8[num + 1]; num = R_GREEN(native_p[i]) * 2; buf[3] = hex8[num]; buf[4] = hex8[num + 1]; num = R_BLUE(native_p[i]) * 2; buf[5] = hex8[num]; buf[6] = hex8[num + 1]; num = R_ALPHA(native_p[i]) * 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(native, codes); UNPROTECT(1); return codes; } farver/src/ColorSpace.h0000755000176200001440000001143214616657233014552 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(); }; struct OkLab : public IColorSpace { double l, a, b; OkLab(); OkLab(double l, double a, double b); OkLab(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 OkLch : public IColorSpace { double l, c, h; OkLch(); OkLch(double l, double c, double h); OkLch(int l, int c, int h); 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.cpp0000755000176200001440000001154614616705741015171 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); } double CmcComparison::defaultLightness = 2.0; double CmcComparison::defaultChroma = 1.0; double CmcComparison::Compare(IColorSpace *a, IColorSpace *b) { static const double pi = 3.141592653589793115998; if (!a->valid || !b->valid) return -1.0; Lch lch_a; Lch lch_b; Lab lab_a; Lab lab_b; a->To(&lch_a); b->To(&lch_b); a->To(&lab_a); b->To(&lab_b); 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 t = (164 <= lch_a.h && lch_a.h <= 345) ? (0.56 + std::abs(0.2*std::cos(pi * (lch_a.h + 168) / 180.0))) : (0.36 + std::abs(0.4*std::cos(pi * (lch_a.h + 35) / 180.0))); double f = std::sqrt(POW4(lch_a.c) / (POW4(lch_a.c) + 1900)); double sh = sc*(f*t + 1 - f); double deltaL = lch_a.l - lch_b.l; double deltaC = lch_a.c - lch_b.c; double deltaA = lab_a.a - lab_b.a; double deltaB = lab_a.b - lab_b.b; double deltaH2 = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC; return std::sqrt(SQR(deltaL / (defaultLightness*sl)) + SQR(deltaC / (defaultChroma*sc)) + deltaH2 / SQR(sh)); } } farver/src/Comparison.h0000755000176200001440000000152514616701233014622 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 double defaultLightness; static double defaultChroma; static double Compare(IColorSpace *a, IColorSpace *b); }; } #endif // COMPARISON_H farver/R/0000755000176200001440000000000014616657233011755 5ustar liggesusersfarver/R/encode.R0000644000176200001440000000435014616657233013337 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), `"oklab"`, `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, #' `"rgb"` (sRGB), `"xyz"`, `"yxy"` (CIE xyY), `"hcl"` (CIE Lch(uv) / polarLuv), #' or `"oklch"` (Polar form of oklab) #' @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 (nrow(colour) == 0) { return(character()) } if (!is.null(alpha)) { alpha <- alpha * 255 if (length(alpha) == 0) { alpha <- NULL } else if (length(alpha) != 1) { alpha <- rep_len(alpha, nrow(colour)) } else if (is.na(alpha) || alpha == 1) { alpha <- NULL } } .Call(`farver_encode_c`, as.matrix(colour), alpha, as.integer(from), white) } farver/R/sysdata.rda0000644000176200001440000001145114616657233014117 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.R0000644000176200001440000000515214616701752015110 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. #' #' @param lightness,chroma Weight of lightness vs chroma when using CMC. Common #' values are `2` and `1` (default) for acceptability and `1` and `1` for #' imperceptibility #' #' @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, lightness = 2, chroma = 1) { 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), lightness, chroma) } compare_c <- function(from, to, from_space, to_space, method, symmetric, white_from, white_to, lightness, chroma) { .Call(`farver_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), as.numeric(lightness), as.numeric(chroma)) } farver/R/zzz.R0000644000176200001440000000214514616657233012737 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.R0000644000176200001440000000514014616660641013320 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), `"oklab"`, `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, #' `"rgb"` (sRGB), `"xyz"`, `"yxy"` (CIE xyY), `"hcl"` (CIE Lch(uv) / polarLuv), #' or `"oklch"` (Polar form of oklab) #' @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[[tolower(to)]], if (alpha) 'alpha' else NULL) colours } decode_c <- function(colour, alpha, to, white, na_value) { .Call(`farver_decode_c`, as_colour_code(colour), alpha, as.integer(to), white, as.character(na_value)) } farver/R/aaa.R0000644000176200001440000001245314616657233012627 0ustar liggesuserscolourspaces <- c( "cmy", # 1 "cmyk", # 2 "hsl", # 3 "hsb", # 4 "hsv", # 5 "lab", # 6 "hunterlab", # 7 "lch", # 8 "luv", # 9 "rgb", # 10 "xyz", # 11 "yxy", # 12 "hcl", # 13 "oklab", # 14 "oklch" # 15 ) 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'), oklab = c('l', 'a', 'b'), oklch = c('l', 'c', 'h') ) 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), oklab = c('l' = 1L, 'a' = 2L, 'b' = 3L), oklch = c('l' = 1L, 'c' = 2L, 'h' = 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(`farver_load_colour_names_c`, c(all_colours, as.character(seq_along(def_palette) - 1L)), cbind(all_values, def_palette_values)) 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.R0000644000176200001440000000020714616657233014755 0ustar liggesusers#' @useDynLib farver, .registration = TRUE #' @keywords internal "_PACKAGE" ## usethis namespace: start ## usethis namespace: end NULLfarver/R/native.R0000644000176200001440000000362414616657233013373 0ustar liggesusers#' Convert to and from the R native colour representation #' #' Colours in R are internally encoded as integers when they are passed around #' to graphics devices. The encoding splits the 32 bit in the integer between #' red, green, blue, and alpha, so that each get 8 bit, equivalent to 256 #' values. It is very seldom that an R user is subjected to this representation, #' but it is present in the `nativeRaster` format which can be obtained from #' e.g. capturing the content of a graphic device (using `dev.capture()`) or reading #' in PNG files using `png::readPNG(native = TRUE)`. It is very rare that you #' might need to convert back and forth between this format, but it is provided #' here for completeness. #' #' @param colour For `encode_native` either a vector of hex-encoded #' colours/colour names or a matrix encoding colours in any of the supported #' colour spaces. If the latter, the colours will be encoded to a hex string #' using [encode_colour()] first. For `decode_native` it is a vector of #' integers. #' @param ... Arguments passed on to [encode_colour()] #' #' @return `encode_native()` returns an integer vector and `decode_native()` #' returns a character vector, both matching the length of the input. #' #' @export #' @name native-encoding #' @rdname native_encoding #' #' @examples #' #' # Get native representation of navyblue and #228B22 #' native_col <- encode_native(c('navyblue', '#228B22')) #' native_col #' #' # Convert back #' decode_native(native_col) #' encode_native <- function(colour, ...) { if (!is.character(colour)) { colour <- encode_colour(colour, ...) } encode_native_c(colour) } #' @rdname native_encoding #' @export decode_native <- function(colour) { decode_native_c(colour) } encode_native_c <- function(colour) { .Call(`farver_encode_native_c`, colour) } decode_native_c <- function(colour) { .Call(`farver_decode_native_c`, as.integer(colour)) } farver/R/convert_colour.R0000644000176200001440000000614714616660631015147 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), `"oklab"`, `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, #' `"rgb"` (sRGB), `"xyz"`, `"yxy"` (CIE xyY), `"hcl"` (CIE Lch(uv) / polarLuv), #' or `"oklch"` (Polar form of oklab) #' #' @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[[tolower(to)]] if (is.data.frame(colour)) res <- as.data.frame(res) res } convert_c <- function(colour, from, to, white_from, white_to) { .Call(`farver_convert_c`, as.matrix(colour), as.integer(from), as.integer(to), as.numeric(white_from), as.numeric(white_to)) } farver/R/modify.R0000644000176200001440000001171414616657233013373 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), `"oklab"` , `"lch"` (CIE Lch(ab) / polarLAB), `"luv"`, #' `"rgb"` (sRGB), `"xyz"`, `"yxy"` (CIE xyY), `"hcl"` (CIE Lch(uv) / polarLuv), #' or `"oklch"` (Polar form of oklab) #' @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) } 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) } 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) } 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) } 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) } 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 (length(colour) == 0) { return(colour) } if (length(value) == 0) { stop("`value` must not be empty", call. = FALSE) } if (length(value) != 1) value <- rep_len(value, length(colour)) 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(`farver_encode_channel_c`, as_colour_code(colour), as.integer(channel), value, as.integer(space), as.integer(op), white, as.character(na_value)) } 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(`farver_decode_channel_c`, as_colour_code(colour), as.integer(channel), as.integer(space), white, as.character(na_value)) } farver/NEWS.md0000644000176200001440000000373614620340243012644 0ustar liggesusers# farver 2.1.2 * make sure output channels are always named (#23) * farver can now decode short version hex-code colours (#41) * Fix a bug in colour comparison that affected hcl input (#44) # farver 2.1.1 * Added input checking to a range of functions to guard against segfaults with empty input (#31) # farver 2.1.0 * Added support for OKLab and OKLch (polar version of OKLab) colour spaces * Added `encode_native()` and `decode_native()` to convert back and forth between the internal R colour format. # 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/MD50000644000176200001440000000520514620357125012056 0ustar liggesusers2625c81d1b0e56bc61aec5aa08d34983 *DESCRIPTION 928d886d4e8454f3db823a37d4de465f *LICENSE f6212f6fee1f564be1f7c93c06a2baab *LICENSE.note a185c902abab5abc83bf0d50fa975d29 *NAMESPACE 98ad01063cbd8942f76699ff1f9477e3 *NEWS.md 0ab3c161ab0b2222a20a167bb64cf685 *R/aaa.R a3241a6a782ddb1c3c7a5af732c141ca *R/compare_colour.R b76dbcbb403bd02e2436c44c39c09116 *R/convert_colour.R 261199c4668070b3bd3019acfca6a105 *R/decode.R 1f668d9acb2e8f803f8ee4aa11dc68eb *R/encode.R 42b294699b8afbf0d703e1fb87121f4d *R/farver-package.R c9a4759f0090bdc68a6a0a99cad0b6eb *R/modify.R 47fce7827e900a33519c14fc48a239e8 *R/native.R 8f910200bcf81fd218debefd97d8d364 *R/sysdata.rda 8cd108e1de56e977d37940ec3773475f *R/zzz.R 217d223ea4be6a8d94372d7193eed9e6 *README.md 9b08166f6f749e6f8dfdf47ec0b93787 *man/as_white_ref.Rd a6a067cffe25b0a9bf8c5da32c548040 *man/compare_colour.Rd 6788dac2a768544f3a0a87e5ebba7e35 *man/convert_colour.Rd c0f74e7d2ad6305c03210de2926f93e1 *man/decode_colour.Rd 52b9fcc54f819d3094858d613e1ae4f1 *man/encode_colour.Rd c5d64db7d3d5725d12c8d3ae9ad137b4 *man/farver-package.Rd 42d8c41b852e55ff90463ddd02f76ee7 *man/figures/README-unnamed-chunk-4-1.png cf060568a294df113221db0fa6336faf *man/figures/README-unnamed-chunk-5-1.png 67085e70e2b0119825809b927375a3b3 *man/figures/README-unnamed-chunk-7-1.png fe995be5469f2c38a48a6b97aa8dba8f *man/figures/README-unnamed-chunk-8-1.png b12dccad3f106522e2b8c27d2da5db96 *man/figures/logo.png 302477b3e810fb39ae0d592a43b7edd1 *man/figures/logo.svg f0456a67621dde5098bd1a5de9bad01e *man/manip_channel.Rd b5f636ac1b7e96779706c6662437dc17 *man/native_encoding.Rd 9c79808ec485d5c985530bf51fd96223 *src/ColorSpace.cpp cb07bfdc4ee320f18d059a9705dddae1 *src/ColorSpace.h 5c948f538873824b8293a50bc86d0e29 *src/Comparison.cpp cd44727f4563a69c8d5b6ef1af748b2a *src/Comparison.h 31d48ac27b870e6f4ce5d0ade5f1d685 *src/Conversion.cpp c0db82953f3abff064b2c9ad8bc38253 *src/Conversion.h d3bba1d5fc947aebfa39bda1cca79eb2 *src/Utils.h 9e02f22f9a3715c3b09b066667c183f5 *src/encode.cpp 793fcad0abb99a0001f03f4035fe96a9 *src/encode.h 35008bbf404b26e2a232f8c83d92660a *src/farver.cpp 3fad51822ad11b18252bf5276c0f1056 *src/farver.h 3c28d202a5ae412b3ac46007002fba5f *src/init.cpp f46fd7006b71bcd1d37751f9cb8ddbf3 *tests/testthat.R 89ac6a8efd4f97ac68802de228ca7d44 *tests/testthat/test-comparison.R 4bea38a1d131d761045ff8d2869d08d7 *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 444c90a1163ea69e682254cad1f87c42 *tests/testthat/test-non-finite.R