├── .gitignore ├── .travis.yml ├── AUTHORS ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── alpha.rs ├── channel.rs ├── hsv.rs ├── lib.rs ├── rgb.rs ├── srgb.rs └── ycbcr.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | /target/ 3 | /test/ 4 | /doc/ 5 | Cargo.lock 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2013 The GLFW-RS Developers. For a full listing of the authors, 2 | # refer to the AUTHORS file at the top-level directory of this distribution. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | language: rust 17 | env: 18 | global: 19 | - secure: d0ai0sK6NFiz+822DaAKAGcJXjC6dBFLGOjqjACcsoqDtRH85HR9IVUnwCsNVPvH05frEutD5Ebd9SzrjqPriTNnzM0iwZZBxHgiHV+SAYcL/D+qyeEAB/IYU5jZxjYgq/6fHA2VhXI56rGqBRwoXe1sLsEAaTfDmo9gVi6xhQo= 20 | script: 21 | - cargo test 22 | - cargo doc 23 | after_script: 24 | # the doc directory needs to be in the root for rust-ci 25 | - mv target/doc doc 26 | - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh 27 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Initial author: 2 | 3 | Brendan Zabarauskas 4 | 5 | 6 | With help and contributions from: 7 | 8 | Luqman Aden 9 | Arturo Castro 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "color" 4 | version = "0.0.2" 5 | authors = ["Brendan Zabarauskas ", "Luqman Aden", "Arturo Castro"] 6 | description = "A library that provides types and conversions for working with various color formats." 7 | 8 | [lib] 9 | 10 | name = "color" 11 | path = "src/lib.rs" 12 | 13 | [dependencies] 14 | num = "0.1" 15 | angle = "0.1" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | color-rs 2 | ======== 3 | 4 | ![travis-ci status](https://travis-ci.org/bjz/color-rs.svg?branch=master) 5 | 6 | A library that provides types and conversions for working with various color formats. 7 | -------------------------------------------------------------------------------- /src/alpha.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | use std::ops::{Mul, Div, Add, Sub, Index, IndexMut}; 17 | use std::slice; 18 | use num::Saturating; 19 | use {Color, Channel, FloatChannel}; 20 | use {Rgb, Rg, ToRgb, Hsv, Srgb, YCbCr}; 21 | 22 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 23 | pub struct AlphaColor { pub c: C, pub a: T } 24 | 25 | pub type Rgba = AlphaColor>; 26 | pub type Hsva = AlphaColor>; 27 | pub type Srgba = AlphaColor>; 28 | pub type YCbCra = AlphaColor>; 29 | 30 | impl> Color for AlphaColor { 31 | /// Clamps the components of the color to the range `(lo,hi)`. 32 | #[inline] 33 | fn clamp_s(self, lo: T, hi: T) -> AlphaColor { 34 | AlphaColor { 35 | c: self.c.clamp_s(lo, hi), 36 | a: self.a.clamp(lo, hi), 37 | } 38 | } 39 | 40 | /// Clamps the components of the color component-wise between `lo` and `hi`. 41 | #[inline] 42 | fn clamp_c(self, lo: AlphaColor, hi: AlphaColor) -> AlphaColor { 43 | AlphaColor { 44 | c: self.c.clamp_c(lo.c, hi.c), 45 | a: self.a.clamp(lo.a, hi.a), 46 | } 47 | } 48 | 49 | /// Inverts the color. 50 | #[inline] 51 | fn inverse(self) -> AlphaColor { 52 | AlphaColor { 53 | c: self.c.inverse(), 54 | a: self.a.invert_channel(), 55 | } 56 | } 57 | 58 | #[inline] 59 | fn mix(self, other: Self, value: T) -> Self { 60 | AlphaColor { 61 | c: self.c.mix(other.c, value), 62 | a: self.a.mix(other.a, value) 63 | } 64 | } 65 | } 66 | 67 | #[macro_export] 68 | macro_rules! rgba{ 69 | ( $r: expr, $g: expr, $b: expr, $a: expr ) => ({ 70 | use $crate::{Rgba,Rgb}; 71 | Rgba{ c: Rgb{ r: $r, g: $g, b: $b }, a: $a } 72 | }); 73 | ( $to_rgb: expr, $a: expr ) => ({ 74 | use $crate::{Rgba,ToRgb}; 75 | Rgba{ c: $to_rgb.to_rgb(), a: $a } 76 | }); 77 | } 78 | 79 | impl Rgba { 80 | #[inline] 81 | pub fn rg(&self) -> Rg { 82 | self.c.rg() 83 | } 84 | 85 | #[inline] 86 | pub fn rb(&self) -> Rg { 87 | self.c.rb() 88 | } 89 | 90 | #[inline] 91 | pub fn gr(&self) -> Rg { 92 | self.c.gr() 93 | } 94 | 95 | #[inline] 96 | pub fn gb(&self) -> Rg { 97 | self.c.gb() 98 | } 99 | 100 | #[inline] 101 | pub fn br(&self) -> Rg { 102 | self.c.br() 103 | } 104 | 105 | #[inline] 106 | pub fn bg(&self) -> Rg { 107 | self.c.bg() 108 | } 109 | 110 | #[inline] 111 | pub fn ar(&self) -> Rg { 112 | Rg{r: self.a, g: self.c.r} 113 | } 114 | 115 | #[inline] 116 | pub fn ag(&self) -> Rg { 117 | Rg{r: self.a, g: self.c.g} 118 | } 119 | 120 | #[inline] 121 | pub fn ab(&self) -> Rg { 122 | Rg{r: self.a, g: self.c.b} 123 | } 124 | 125 | #[inline] 126 | pub fn ra(&self) -> Rg { 127 | Rg{r: self.c.r, g: self.a} 128 | } 129 | 130 | #[inline] 131 | pub fn ga(&self) -> Rg { 132 | Rg{r: self.c.g, g: self.a} 133 | } 134 | 135 | #[inline] 136 | pub fn ba(&self) -> Rg { 137 | Rg{r: self.c.b, g: self.a} 138 | } 139 | 140 | #[inline] 141 | pub fn rgb(&self) -> Rgb { 142 | self.c.rgb() 143 | } 144 | 145 | #[inline] 146 | pub fn rbg(&self) -> Rgb { 147 | self.c.rbg() 148 | } 149 | 150 | #[inline] 151 | pub fn bgr(&self) -> Rgb { 152 | self.c.bgr() 153 | } 154 | 155 | #[inline] 156 | pub fn brg(&self) -> Rgb { 157 | self.c.brg() 158 | } 159 | 160 | #[inline] 161 | pub fn grb(&self) -> Rgb { 162 | self.c.grb() 163 | } 164 | 165 | #[inline] 166 | pub fn gbr(&self) -> Rgb { 167 | self.c.gbr() 168 | } 169 | 170 | #[inline] 171 | pub fn rga(&self) -> Rgb { 172 | rgb!(self.c.r,self.c.g,self.a) 173 | } 174 | 175 | #[inline] 176 | pub fn rba(&self) -> Rgb { 177 | rgb!(self.c.r,self.c.b,self.a) 178 | } 179 | 180 | #[inline] 181 | pub fn bra(&self) -> Rgb { 182 | rgb!(self.c.b,self.c.r,self.a) 183 | } 184 | 185 | #[inline] 186 | pub fn bga(&self) -> Rgb { 187 | rgb!(self.c.b,self.c.g,self.a) 188 | } 189 | 190 | #[inline] 191 | pub fn gra(&self) -> Rgb { 192 | rgb!(self.c.g,self.c.r,self.a) 193 | } 194 | 195 | #[inline] 196 | pub fn gba(&self) -> Rgb { 197 | rgb!(self.c.g,self.c.b,self.a) 198 | } 199 | 200 | #[inline] 201 | pub fn arg(&self) -> Rgb { 202 | rgb!(self.a,self.c.r,self.c.g) 203 | } 204 | 205 | #[inline] 206 | pub fn arb(&self) -> Rgb { 207 | rgb!(self.a,self.c.r,self.c.b) 208 | } 209 | 210 | #[inline] 211 | pub fn agr(&self) -> Rgb { 212 | rgb!(self.a,self.c.g,self.c.r) 213 | } 214 | 215 | #[inline] 216 | pub fn agb(&self) -> Rgb { 217 | rgb!(self.a,self.c.g,self.c.b) 218 | } 219 | 220 | #[inline] 221 | pub fn abr(&self) -> Rgb { 222 | rgb!(self.a,self.c.b,self.c.r) 223 | } 224 | 225 | #[inline] 226 | pub fn abg(&self) -> Rgb { 227 | rgb!(self.a,self.c.b,self.c.g) 228 | } 229 | 230 | #[inline] 231 | pub fn rag(&self) -> Rgb { 232 | rgb!(self.c.r,self.a,self.c.g) 233 | } 234 | 235 | #[inline] 236 | pub fn rab(&self) -> Rgb { 237 | rgb!(self.c.r,self.a,self.c.b) 238 | } 239 | 240 | #[inline] 241 | pub fn gar(&self) -> Rgb { 242 | rgb!(self.c.g,self.a,self.c.r) 243 | } 244 | 245 | #[inline] 246 | pub fn gab(&self) -> Rgb { 247 | rgb!(self.c.g,self.a,self.c.b) 248 | } 249 | 250 | #[inline] 251 | pub fn bar(&self) -> Rgb { 252 | rgb!(self.c.b,self.a,self.c.r) 253 | } 254 | 255 | #[inline] 256 | pub fn bag(&self) -> Rgb { 257 | rgb!(self.c.b,self.a,self.c.g) 258 | } 259 | 260 | #[inline] 261 | pub fn rgba(&self) -> Rgba { 262 | rgba!(self.c, self.a) 263 | } 264 | 265 | #[inline] 266 | pub fn rbga(&self) -> Rgba { 267 | rgba!(self.c.r, self.c.b, self.c.g, self.a) 268 | } 269 | 270 | #[inline] 271 | pub fn grba(&self) -> Rgba { 272 | rgba!(self.c.g, self.c.r, self.c.b, self.a) 273 | } 274 | 275 | #[inline] 276 | pub fn gbra(&self) -> Rgba { 277 | rgba!(self.c.g, self.c.b, self.c.r, self.a) 278 | } 279 | 280 | #[inline] 281 | pub fn brga(&self) -> Rgba { 282 | rgba!(self.c.b, self.c.r, self.c.g, self.a) 283 | } 284 | 285 | #[inline] 286 | pub fn bgra(&self) -> Rgba { 287 | rgba!(self.c.b, self.c.g, self.c.r, self.a) 288 | } 289 | 290 | #[inline] 291 | pub fn argb(&self) -> Rgba { 292 | rgba!(self.a, self.c.r, self.c.g, self.c.b) 293 | } 294 | 295 | #[inline] 296 | pub fn arbg(&self) -> Rgba { 297 | rgba!(self.a, self.c.r, self.c.b, self.c.g) 298 | } 299 | 300 | #[inline] 301 | pub fn agrb(&self) -> Rgba { 302 | rgba!(self.a, self.c.g, self.c.r, self.c.b) 303 | } 304 | 305 | #[inline] 306 | pub fn agbr(&self) -> Rgba { 307 | rgba!(self.a, self.c.g, self.c.b, self.c.r) 308 | } 309 | 310 | #[inline] 311 | pub fn abrg(&self) -> Rgba { 312 | rgba!(self.a, self.c.b, self.c.r, self.c.g) 313 | } 314 | 315 | #[inline] 316 | pub fn abgr(&self) -> Rgba { 317 | rgba!(self.a, self.c.b, self.c.g, self.c.r) 318 | } 319 | 320 | #[inline] 321 | pub fn ragb(&self) -> Rgba { 322 | rgba!(self.c.r, self.a, self.c.g, self.c.b) 323 | } 324 | 325 | #[inline] 326 | pub fn rabg(&self) -> Rgba { 327 | rgba!(self.c.r, self.a, self.c.b, self.c.g) 328 | } 329 | 330 | #[inline] 331 | pub fn garb(&self) -> Rgba { 332 | rgba!(self.c.g, self.a, self.c.r, self.c.b) 333 | } 334 | 335 | #[inline] 336 | pub fn gabr(&self) -> Rgba { 337 | rgba!(self.c.g, self.a, self.c.b, self.c.r) 338 | } 339 | 340 | #[inline] 341 | pub fn barg(&self) -> Rgba { 342 | rgba!(self.c.b, self.a, self.c.r, self.c.g) 343 | } 344 | 345 | #[inline] 346 | pub fn bagr(&self) -> Rgba { 347 | rgba!(self.c.b, self.a, self.c.g, self.c.r) 348 | } 349 | 350 | #[inline] 351 | pub fn rgab(&self) -> Rgba { 352 | rgba!(self.c.r, self.c.g, self.a, self.c.b) 353 | } 354 | 355 | #[inline] 356 | pub fn rbag(&self) -> Rgba { 357 | rgba!(self.c.r, self.c.b, self.a, self.c.g) 358 | } 359 | 360 | #[inline] 361 | pub fn grab(&self) -> Rgba { 362 | rgba!(self.c.g, self.c.r, self.a, self.c.b) 363 | } 364 | 365 | #[inline] 366 | pub fn gbar(&self) -> Rgba { 367 | rgba!(self.c.g, self.c.b, self.a, self.c.r) 368 | } 369 | 370 | #[inline] 371 | pub fn brag(&self) -> Rgba { 372 | rgba!(self.c.b, self.c.r, self.a, self.c.g) 373 | } 374 | 375 | #[inline] 376 | pub fn bgar(&self) -> Rgba { 377 | rgba!(self.c.b, self.c.g, self.a, self.c.r) 378 | } 379 | } 380 | 381 | 382 | pub trait ToRgba{ 383 | fn to_rgba(&self) -> Rgba; 384 | } 385 | 386 | impl ToRgba for AlphaColor{ 387 | #[inline] 388 | fn to_rgba(&self) -> Rgba{ 389 | Rgba{c: self.c.to_rgb(), a: self.a.to_channel()} 390 | } 391 | } 392 | 393 | impl ToRgba for Rgb { 394 | #[inline] 395 | fn to_rgba(&self) -> Rgba{ 396 | Rgba{c: self.to_rgb(), a: 1.0f32.to_channel()} 397 | } 398 | } 399 | 400 | impl ToRgba for Hsv { 401 | #[inline] 402 | fn to_rgba(&self) -> Rgba{ 403 | Rgba{c: self.to_rgb(), a: 1.0f32.to_channel()} 404 | } 405 | } 406 | 407 | impl> Mul for AlphaColor { 408 | type Output = AlphaColor; 409 | 410 | #[inline] 411 | fn mul(self, rhs: AlphaColor) -> AlphaColor { 412 | AlphaColor{ c: self.c.mul(rhs.c), 413 | a: self.a.normalized_mul(rhs.a) } 414 | } 415 | } 416 | 417 | impl, C: Mul> Mul for AlphaColor { 418 | type Output = AlphaColor; 419 | 420 | #[inline] 421 | fn mul(self, rhs: T) -> AlphaColor { 422 | let color = self.c * rhs; 423 | AlphaColor{ c: color, 424 | a: self.a * rhs } 425 | } 426 | } 427 | 428 | impl> Div for AlphaColor { 429 | type Output = AlphaColor; 430 | 431 | #[inline] 432 | fn div(self, rhs: AlphaColor) -> AlphaColor { 433 | AlphaColor{ c: self.c.div(rhs.c), 434 | a: self.a.normalized_div(rhs.a) } 435 | } 436 | } 437 | 438 | impl, C: Div> Div for AlphaColor { 439 | type Output = AlphaColor; 440 | 441 | #[inline] 442 | fn div(self, rhs: T) -> AlphaColor { 443 | let color = self.c / rhs; 444 | AlphaColor{ c: color, 445 | a: self.a / rhs } 446 | } 447 | } 448 | 449 | impl, C: Add> Add for AlphaColor{ 450 | type Output = AlphaColor; 451 | 452 | #[inline] 453 | fn add(self, rhs: AlphaColor) -> AlphaColor { 454 | AlphaColor{ c: self.c + rhs.c, 455 | a: self.a + rhs.a } 456 | } 457 | } 458 | 459 | impl, C: Sub> Sub for AlphaColor{ 460 | type Output = AlphaColor; 461 | 462 | #[inline] 463 | fn sub(self, rhs: AlphaColor) -> AlphaColor { 464 | AlphaColor{ c: self.c - rhs.c, 465 | a: self.a - rhs.a } 466 | } 467 | } 468 | 469 | impl Saturating for AlphaColor{ 470 | fn saturating_add(self, v: AlphaColor) -> AlphaColor { 471 | AlphaColor{ c: self.c.saturating_add(v.c), 472 | a: self.a.saturating_add(v.a) } 473 | } 474 | 475 | fn saturating_sub(self, v: AlphaColor) -> AlphaColor { 476 | AlphaColor{ c: self.c.saturating_sub(v.c), 477 | a: self.a.saturating_sub(v.a) } 478 | } 479 | } 480 | 481 | impl> Index for AlphaColor { 482 | type Output = T; 483 | fn index<'a>(&'a self, index: usize) -> &'a T { 484 | self.as_ref().index(index) 485 | } 486 | } 487 | 488 | impl + AsMut<[T]>> IndexMut for AlphaColor { 489 | fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut T { 490 | self.as_mut().index_mut(index) 491 | } 492 | } 493 | 494 | impl> AsRef<[T]> for AlphaColor { 495 | fn as_ref(&self) -> &[T] { 496 | unsafe{ slice::from_raw_parts(&self.c.as_ref()[0], 4) } 497 | } 498 | } 499 | 500 | impl> AsMut<[T]> for AlphaColor { 501 | fn as_mut(&mut self) -> &mut [T] { 502 | unsafe{ slice::from_raw_parts_mut(&mut self.c.as_mut()[0], 4) } 503 | } 504 | } 505 | -------------------------------------------------------------------------------- /src/channel.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //! Color channel conversions and utility methods 17 | 18 | use num::{Float, NumCast, Num, zero, one}; 19 | use std::{u8, u16}; 20 | 21 | pub trait Channel: Copy + Sized + Clone + PartialOrd + Num + NumCast { 22 | fn from(chan: T) -> Self; 23 | fn to_channel(self) -> T { Channel::from(self) } 24 | fn to_channel_u8(self) -> u8; 25 | fn to_channel_u16(self) -> u16; 26 | fn to_channel_f32(self) -> f32; 27 | fn to_channel_f64(self) -> f64; 28 | 29 | fn invert_channel(self) -> Self; 30 | 31 | fn clamp(self, lo: Self, hi: Self) -> Self { 32 | if self < lo { 33 | lo 34 | } else if self > hi { 35 | hi 36 | } else { 37 | self 38 | } 39 | } 40 | 41 | #[inline] 42 | fn normalized_mul(self, rhs: Self) -> Self { 43 | Channel::from(self.to_channel_f32() * rhs.to_channel_f32()) 44 | } 45 | 46 | #[inline] 47 | fn normalized_div(self, rhs: Self) -> Self { 48 | Channel::from(self.to_channel_f32() / rhs.to_channel_f32()) 49 | } 50 | 51 | fn max() -> Self; 52 | 53 | #[inline] 54 | fn mix(self, rhs: Self, value: Self) -> Self { 55 | (self + (rhs - self).normalized_mul(value)) 56 | } 57 | } 58 | 59 | impl Channel for u8 { 60 | #[inline] fn from(chan: T) -> u8 { chan.to_channel_u8() } 61 | #[inline] fn to_channel_u8(self) -> u8 { self } 62 | #[inline] fn to_channel_u16(self) -> u16 { ((self as u16) << 8) | self as u16 } 63 | #[inline] fn to_channel_f32(self) -> f32 { (self as f32) / (0xFF_u8 as f32) } 64 | #[inline] fn to_channel_f64(self) -> f64 { (self as f64) / (0xFF_u8 as f64) } 65 | 66 | #[inline] fn invert_channel(self) -> u8 { !self } 67 | 68 | #[inline] fn max() -> u8{ u8::MAX } 69 | } 70 | 71 | impl Channel for u16 { 72 | #[inline] fn from(chan: T) -> u16 { chan.to_channel_u16() } 73 | #[inline] fn to_channel_u8(self) -> u8 { (self >> 8) as u8 } 74 | #[inline] fn to_channel_u16(self) -> u16 { self } 75 | #[inline] fn to_channel_f32(self) -> f32 { (self / 0xFFFF) as f32 } 76 | #[inline] fn to_channel_f64(self) -> f64 { (self / 0xFFFF) as f64 } 77 | 78 | #[inline] fn invert_channel(self) -> u16 { !self } 79 | 80 | #[inline] fn max() -> u16{ u16::MAX } 81 | } 82 | 83 | impl Channel for f32 { 84 | #[inline] fn from(chan: T) -> f32 { chan.to_channel_f32() } 85 | #[inline] fn to_channel_u8(self) -> u8 { (self * (0xFF_u8 as f32)) as u8 } 86 | #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF_u16 as f32)) as u16 } 87 | #[inline] fn to_channel_f32(self) -> f32 { self } 88 | #[inline] fn to_channel_f64(self) -> f64 { self as f64 } 89 | 90 | #[inline] fn invert_channel(self) -> f32 { 1.0 - self } 91 | 92 | #[inline] 93 | fn normalized_mul(self, rhs: Self) -> Self { 94 | self * rhs 95 | } 96 | 97 | #[inline] 98 | fn normalized_div(self, rhs: Self) -> Self { 99 | self / rhs 100 | } 101 | 102 | #[inline] fn max() -> f32{ 1.0 } 103 | } 104 | 105 | impl Channel for f64 { 106 | #[inline] fn from(chan: T) -> f64 { chan.to_channel_f64() } 107 | #[inline] fn to_channel_u8(self) -> u8 { (self * (0xFF_u8 as f64)) as u8 } 108 | #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF_u16 as f64)) as u16 } 109 | #[inline] fn to_channel_f32(self) -> f32 { self as f32 } 110 | #[inline] fn to_channel_f64(self) -> f64 { self } 111 | 112 | #[inline] fn invert_channel(self) -> f64 { 1.0 - self } 113 | 114 | #[inline] 115 | fn normalized_mul(self, rhs: Self) -> Self { 116 | self * rhs 117 | } 118 | 119 | #[inline] 120 | fn normalized_div(self, rhs: Self) -> Self { 121 | self / rhs 122 | } 123 | 124 | #[inline] fn max() -> f64{ 1.0 } 125 | } 126 | 127 | pub trait FloatChannel: Float + Channel { 128 | #[inline] 129 | fn saturate(self) -> Self { 130 | Channel::clamp(self, zero(), one()) 131 | } 132 | } 133 | 134 | impl FloatChannel for f32 {} 135 | impl FloatChannel for f64 {} 136 | 137 | #[cfg(test)] 138 | mod tests { 139 | use super::Channel; 140 | 141 | #[test] 142 | fn test_to_channel_u8() { 143 | assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8); 144 | assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8); 145 | assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8); 146 | assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8); 147 | assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8); 148 | 149 | assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16); 150 | assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16); 151 | assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16); 152 | assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16); 153 | assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16); 154 | 155 | assert_eq!(0x00_u8.to_channel_f32(), 0f32); 156 | assert_eq!(0xFF_u8.to_channel_f32(), 1f32); 157 | 158 | assert_eq!(0x00_u8.to_channel_f64(), 0f64); 159 | assert_eq!(0xFF_u8.to_channel_f64(), 1f64); 160 | } 161 | 162 | #[test] 163 | fn test_invert_channel_u8() { 164 | assert_eq!(0x00_u8.invert_channel(), 0xFF_u8); 165 | assert_eq!(0x66_u8.invert_channel(), 0x99_u8); 166 | assert_eq!(0xFF_u8.invert_channel(), 0x00_u8); 167 | } 168 | 169 | #[test] 170 | fn test_to_channel_u16() { 171 | assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8); 172 | assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8); 173 | assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8); 174 | assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8); 175 | assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8); 176 | 177 | assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16); 178 | assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16); 179 | assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16); 180 | assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16); 181 | assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16); 182 | 183 | assert_eq!(0x0000_u16.to_channel_f32(), 0f32); 184 | assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32); 185 | 186 | assert_eq!(0x0000_u16.to_channel_f64(), 0f64); 187 | assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64); 188 | } 189 | 190 | #[test] 191 | fn test_invert_channel_u16() { 192 | assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16); 193 | assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16); 194 | assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16); 195 | } 196 | 197 | #[test] 198 | fn test_to_channel_f32() { 199 | assert_eq!(0.00f32.to_channel_u8(), 0x00); 200 | assert_eq!(0.25f32.to_channel_u8(), 0x3F); 201 | assert_eq!(0.50f32.to_channel_u8(), 0x7F); 202 | assert_eq!(0.75f32.to_channel_u8(), 0xBF); 203 | assert_eq!(1.00f32.to_channel_u8(), 0xFF); 204 | 205 | assert_eq!(0.00f32.to_channel_u16(), 0x0000); 206 | assert_eq!(0.25f32.to_channel_u16(), 0x3FFF); 207 | assert_eq!(0.50f32.to_channel_u16(), 0x7FFF); 208 | assert_eq!(0.75f32.to_channel_u16(), 0xBFFF); 209 | assert_eq!(1.00f32.to_channel_u16(), 0xFFFF); 210 | 211 | assert_eq!(0.00f32.to_channel_f32(), 0.00f32); 212 | assert_eq!(1.00f32.to_channel_f32(), 1.00f32); 213 | 214 | assert_eq!(0.00f32.to_channel_f64(), 0.00f64); 215 | assert_eq!(1.00f32.to_channel_f64(), 1.00f64); 216 | } 217 | 218 | #[test] 219 | fn test_invert_channel_f32() { 220 | assert_eq!(0.00f32.invert_channel(), 1.00f32); 221 | assert_eq!(0.50f32.invert_channel(), 0.50f32); 222 | assert_eq!(1.00f32.invert_channel(), 0.00f32); 223 | } 224 | 225 | #[test] 226 | fn test_to_channel_f64() { 227 | assert_eq!(0.00f64.to_channel_u8(), 0x00); 228 | assert_eq!(0.25f64.to_channel_u8(), 0x3F); 229 | assert_eq!(0.50f64.to_channel_u8(), 0x7F); 230 | assert_eq!(0.75f64.to_channel_u8(), 0xBF); 231 | assert_eq!(1.00f64.to_channel_u8(), 0xFF); 232 | 233 | assert_eq!(0.00f64.to_channel_u16(), 0x0000); 234 | assert_eq!(0.25f64.to_channel_u16(), 0x3FFF); 235 | assert_eq!(0.50f64.to_channel_u16(), 0x7FFF); 236 | assert_eq!(0.75f64.to_channel_u16(), 0xBFFF); 237 | assert_eq!(1.00f64.to_channel_u16(), 0xFFFF); 238 | 239 | assert_eq!(0.00f64.to_channel_f32(), 0.00f32); 240 | assert_eq!(1.00f64.to_channel_f32(), 1.00f32); 241 | 242 | assert_eq!(0.00f64.to_channel_f64(), 0.00f64); 243 | assert_eq!(1.00f64.to_channel_f64(), 1.00f64); 244 | } 245 | 246 | #[test] 247 | fn test_invert_channel_f64() { 248 | assert_eq!(0.00f64.invert_channel(), 1.00f64); 249 | assert_eq!(0.50f64.invert_channel(), 0.50f64); 250 | assert_eq!(1.00f64.invert_channel(), 0.00f64); 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/hsv.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | use num::{self, zero}; 17 | use num::traits::{Float, Zero}; 18 | use angle::*; 19 | 20 | use {Color, FloatColor}; 21 | use {Channel, FloatChannel}; 22 | use {Rgb, ToRgb}; 23 | 24 | #[inline] 25 | fn cast(n: T) -> U { 26 | num::traits::cast(n).unwrap() 27 | } 28 | 29 | #[derive(Clone, Copy, PartialEq, Debug)] 30 | pub struct Hsv { pub h: Deg, pub s: T, pub v: T } 31 | 32 | impl Hsv { 33 | pub fn new(h: Deg, s: T, v: T) -> Hsv { 34 | Hsv { h: h, s: s, v: v } 35 | } 36 | } 37 | 38 | impl Color for Hsv { 39 | /// Clamps the components of the color to the range `(lo,hi)`. 40 | #[inline] 41 | fn clamp_s(self, lo: T, hi: T) -> Hsv { 42 | Hsv::new(self.h, // Should the hue component be clamped? 43 | self.s.clamp(lo, hi), 44 | self.v.clamp(lo, hi)) 45 | } 46 | 47 | /// Clamps the components of the color component-wise between `lo` and `hi`. 48 | #[inline] 49 | fn clamp_c(self, lo: Hsv, hi: Hsv) -> Hsv { 50 | Hsv::new(self.h, 51 | self.s.clamp(lo.s, hi.s), 52 | self.v.clamp(lo.v, hi.v)) 53 | } 54 | 55 | /// Inverts the color. 56 | #[inline] 57 | fn inverse(self) -> Hsv { 58 | Hsv::new((self.h + Deg(cast(180))).wrap(), 59 | self.s.invert_channel(), 60 | self.v.invert_channel()) 61 | } 62 | 63 | #[inline] 64 | fn mix(self, other: Self, value: T) -> Self { 65 | self.to_rgb().mix(other.to_rgb(),value).to_hsv() // TODO: can we mix the hsv directly? 66 | } 67 | } 68 | 69 | impl FloatColor for Hsv { 70 | /// Normalizes the components of the color. Modulo `360` is applied to the 71 | /// `h` component, and `s` and `v` are clamped to the range `(0,1)`. 72 | #[inline] 73 | fn saturate(self) -> Hsv { 74 | Hsv::new(self.h.wrap(), 75 | self.s.saturate(), 76 | self.v.saturate()) 77 | } 78 | } 79 | 80 | pub trait ToHsv { 81 | fn to_hsv(&self) -> Hsv; 82 | } 83 | 84 | impl ToHsv for u32 { 85 | #[inline] 86 | fn to_hsv(&self) -> Hsv { 87 | panic!("Not yet implemented") 88 | } 89 | } 90 | 91 | impl ToHsv for u64 { 92 | #[inline] 93 | fn to_hsv(&self) -> Hsv { 94 | panic!("Not yet implemented") 95 | } 96 | } 97 | 98 | impl ToHsv for Hsv { 99 | #[inline] 100 | fn to_hsv(&self) -> Hsv { 101 | Hsv::new(Deg(cast(self.h.value())), 102 | self.s.to_channel(), 103 | self.v.to_channel()) 104 | } 105 | } 106 | 107 | impl ToRgb for Hsv { 108 | fn to_rgb(&self) -> Rgb { 109 | if self.v.is_zero() { 110 | rgb!(zero(), zero(), zero()) 111 | } else if self.s.is_zero() { 112 | let gray = Channel::from(self.v); 113 | rgb!(gray, gray, gray) 114 | } else { 115 | let max_f: f64 = cast(T::max()); 116 | let hue: f64 = cast(self.h.wrap().value()); 117 | let hue_six: f64 = hue / 360f64 * 6f64; 118 | let hue_six_cat: usize = cast(hue_six); 119 | let hue_six_rem: T = cast(hue_six.fract() * max_f); 120 | let pv = Channel::from((T::max() - self.s).normalized_mul(self.v)); 121 | let qv = Channel::from((T::max() - self.s.normalized_mul(hue_six_rem)).normalized_mul(self.v)); 122 | let tv = Channel::from((T::max() - self.s.normalized_mul(T::max() - hue_six_rem)).normalized_mul(self.v)); 123 | let b: U = Channel::from(self.v); 124 | match hue_six_cat { 125 | 0 | 6 => rgb!(b,tv,pv), 126 | 1 => rgb!(qv, b, pv), 127 | 2 => rgb!(pv, b, tv), 128 | 3 => rgb!(pv, qv, b), 129 | 4 => rgb!(tv, pv, b), 130 | 5 => rgb!(b, pv, qv), 131 | _ => panic!("Unreachable code") 132 | } 133 | } 134 | } 135 | } 136 | 137 | #[cfg(test)] 138 | mod tests { 139 | use {Hsv, ToHsv}; 140 | use {Rgb, ToRgb}; 141 | use angle::*; 142 | 143 | #[test] 144 | fn test_hsv_to_hsv() { 145 | assert_eq!(Hsv::::new(Deg(0.0), 0.0, 1.0).to_hsv::(), Hsv::::new(Deg(0.0), 0.0, 1.0)); 146 | assert_eq!(Hsv::::new(Deg(0.0), 1.0, 0.6).to_hsv::(), Hsv::::new(Deg(0.0), 1.0, 0.6)); 147 | assert_eq!(Hsv::::new(Deg(120.0), 1.0, 0.6).to_hsv::(), Hsv::::new(Deg(120.0), 1.0, 0.6)); 148 | assert_eq!(Hsv::::new(Deg(240.0), 1.0, 0.6).to_hsv::(), Hsv::::new(Deg(240.0), 1.0, 0.6)); 149 | } 150 | 151 | #[test] 152 | fn test_hsv_to_rgb() { 153 | assert_eq!(Hsv::::new(Deg(0.0), 0.0, 1.0).to_rgb::(), Rgb::::new(0xFF, 0xFF, 0xFF)); 154 | assert_eq!(Hsv::::new(Deg(0.0), 1.0, 0.6).to_rgb::(), Rgb::::new(0x99, 0x00, 0x00)); 155 | assert_eq!(Hsv::::new(Deg(120.0), 1.0, 0.6).to_rgb::(), Rgb::::new(0x00, 0x99, 0x00)); 156 | assert_eq!(Hsv::::new(Deg(240.0), 1.0, 0.6).to_rgb::(), Rgb::::new(0x00, 0x00, 0x99)); 157 | assert_eq!(Hsv::::new(Deg(0), 0, 65535).to_rgb::(), Rgb::::new(0xFF, 0xFF, 0xFF)); 158 | assert_eq!(Hsv::::new(Deg(0), 65535, 39321).to_rgb::(), Rgb::::new(0x99, 0x00, 0x00)); 159 | assert_eq!(Hsv::::new(Deg(120), 65535, 39321).to_rgb::(), Rgb::::new(0x00, 0x99, 0x00)); 160 | assert_eq!(Hsv::::new(Deg(240), 65535, 39321).to_rgb::(), Rgb::::new(0x00, 0x00, 0x99)); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | extern crate num; 16 | extern crate angle; 17 | 18 | pub use alpha::AlphaColor; 19 | pub use alpha::{Rgba, Hsva, Srgba, YCbCra, ToRgba}; 20 | pub use channel::{Channel, FloatChannel}; 21 | pub use hsv::{Hsv, ToHsv}; 22 | pub use rgb::{Rgb, Rg, ToRgb, consts}; 23 | pub use srgb::Srgb; 24 | pub use ycbcr::YCbCr; 25 | 26 | #[macro_use] mod rgb; 27 | #[macro_use] mod alpha; 28 | mod channel; 29 | mod hsv; 30 | mod srgb; 31 | mod ycbcr; 32 | 33 | pub trait Color: Copy { 34 | fn clamp_s(self, lo: T, hi: T) -> Self; 35 | fn clamp_c(self, lo: Self, hi: Self) -> Self; 36 | fn inverse(self) -> Self; 37 | fn mix(self, other: Self, value: T) -> Self; 38 | // fn saturation(&self, value: T) -> Self; 39 | // fn exposure(&self, value: T) -> Self; 40 | // fn brightness(&self, value: T) -> Self; 41 | } 42 | 43 | pub trait FloatColor: Color { 44 | fn saturate(self) -> Self; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/rgb.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | use num; 17 | use num::traits::{self, Float, Zero, Saturating}; 18 | use std::ops::{Mul, Div, Add, Sub, Index, IndexMut}; 19 | use std::slice; 20 | 21 | use angle::*; 22 | 23 | use AlphaColor; 24 | use {Color, FloatColor}; 25 | use {Channel, FloatChannel}; 26 | use {Hsv, ToHsv}; 27 | 28 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 29 | pub struct Rgb { pub r: T, pub g: T, pub b: T } 30 | 31 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 32 | pub struct Rg { pub r: T, pub g: T } 33 | 34 | fn cast(n: T) -> U { 35 | traits::cast(n).unwrap() 36 | } 37 | 38 | impl Rgb { 39 | #[inline] 40 | pub fn new(r: T, g: T, b: T) -> Rgb { 41 | Rgb { r: r, g: g, b: b } 42 | } 43 | 44 | #[inline] 45 | pub fn rg(&self) -> Rg { 46 | Rg{r: self.r, g: self.g} 47 | } 48 | 49 | #[inline] 50 | pub fn rb(&self) -> Rg { 51 | Rg{r: self.r, g: self.b} 52 | } 53 | 54 | #[inline] 55 | pub fn gr(&self) -> Rg { 56 | Rg{r: self.g, g: self.r} 57 | } 58 | 59 | #[inline] 60 | pub fn gb(&self) -> Rg { 61 | Rg{r: self.g, g: self.b} 62 | } 63 | 64 | #[inline] 65 | pub fn br(&self) -> Rg { 66 | Rg{r: self.b, g: self.r} 67 | } 68 | 69 | #[inline] 70 | pub fn bg(&self) -> Rg { 71 | Rg{r: self.b, g: self.g} 72 | } 73 | 74 | #[inline] 75 | pub fn rgb(&self) -> Rgb { 76 | Rgb{r: self.r, g: self.g, b: self.b} 77 | } 78 | 79 | #[inline] 80 | pub fn rbg(&self) -> Rgb { 81 | Rgb{r: self.r, g: self.b, b: self.g} 82 | } 83 | 84 | #[inline] 85 | pub fn bgr(&self) -> Rgb { 86 | Rgb{r: self.b, g: self.g, b: self.r} 87 | } 88 | 89 | #[inline] 90 | pub fn brg(&self) -> Rgb { 91 | Rgb{r: self.b, g: self.r, b: self.g} 92 | } 93 | 94 | #[inline] 95 | pub fn grb(&self) -> Rgb { 96 | Rgb{r: self.g, g: self.r, b: self.b} 97 | } 98 | 99 | #[inline] 100 | pub fn gbr(&self) -> Rgb { 101 | Rgb{r: self.g, g: self.b, b: self.r} 102 | } 103 | } 104 | 105 | #[macro_export] 106 | macro_rules! rgb{ 107 | ( $r: expr, $g: expr, $b: expr ) => { 108 | Rgb{ r: $r, g: $g, b: $b } 109 | }; 110 | ( $rg: expr, $b: expr ) => { 111 | Rgb{ r: $rg.r, g: $rg.g, b: $b } 112 | }; 113 | ( $r: expr, $gb: expr ) => { 114 | Rgb{ r: $r, g: $gb.r, b: $gb.g } 115 | }; 116 | } 117 | 118 | impl Color for Rgb { 119 | /// Clamps the components of the color to the range `(lo,hi)`. 120 | #[inline] 121 | fn clamp_s(self, lo: T, hi: T) -> Rgb { 122 | Rgb::new(self.r.clamp(lo, hi), 123 | self.g.clamp(lo, hi), 124 | self.b.clamp(lo, hi)) 125 | } 126 | 127 | /// Clamps the components of the color component-wise between `lo` and `hi`. 128 | #[inline] 129 | fn clamp_c(self, lo: Rgb, hi: Rgb) -> Rgb { 130 | Rgb::new(self.r.clamp(lo.r, hi.r), 131 | self.g.clamp(lo.g, hi.g), 132 | self.b.clamp(lo.b, hi.b)) 133 | } 134 | 135 | /// Inverts the color. 136 | #[inline] 137 | fn inverse(self) -> Rgb { 138 | Rgb::new(self.r.invert_channel(), 139 | self.g.invert_channel(), 140 | self.b.invert_channel()) 141 | } 142 | 143 | #[inline] 144 | fn mix(self, other: Self, value: T) -> Self { 145 | rgb!(self.r.mix(other.r, value), 146 | self.g.mix(other.g, value), 147 | self.b.mix(other.b, value)) 148 | } 149 | } 150 | 151 | impl FloatColor for Rgb { 152 | /// Clamps the components of the color to the range `(0,1)`. 153 | #[inline] 154 | fn saturate(self) -> Rgb { 155 | Rgb::new(self.r.saturate(), 156 | self.g.saturate(), 157 | self.b.saturate()) 158 | } 159 | } 160 | 161 | pub trait ToRgb { 162 | fn to_rgb(&self) -> Rgb; 163 | } 164 | 165 | impl ToRgb for u32 { 166 | #[inline] 167 | fn to_rgb(&self) -> Rgb { 168 | let r: u8 = cast((*self >> 16) & 0xff); 169 | let g: u8 = cast((*self >> 8) & 0xff); 170 | let b: u8 = cast((*self >> 0) & 0xff); 171 | let r: U = Channel::from(r); 172 | let g: U = Channel::from(g); 173 | let b: U = Channel::from(b); 174 | rgb!(r, g, b) 175 | } 176 | } 177 | 178 | impl ToRgb for Rgb { 179 | #[inline] 180 | fn to_rgb(&self) -> Rgb { 181 | Rgb::new(self.r.to_channel(), 182 | self.g.to_channel(), 183 | self.b.to_channel()) 184 | } 185 | } 186 | 187 | impl ToRgb for AlphaColor { 188 | #[inline] 189 | fn to_rgb(&self) -> Rgb { 190 | self.c.to_rgb() 191 | } 192 | } 193 | 194 | impl Mul for Rgb { 195 | type Output = Rgb; 196 | 197 | #[inline] 198 | fn mul(self, rhs: Rgb) -> Rgb { 199 | Rgb::new(self.r.normalized_mul(rhs.r), 200 | self.g.normalized_mul(rhs.g), 201 | self.b.normalized_mul(rhs.b)) 202 | } 203 | } 204 | 205 | impl> Mul for Rgb { 206 | type Output = Rgb; 207 | 208 | #[inline] 209 | fn mul(self, rhs: T) -> Rgb { 210 | Rgb::new(self.r * rhs, 211 | self.g * rhs, 212 | self.b * rhs) 213 | } 214 | } 215 | 216 | 217 | impl Div for Rgb { 218 | type Output = Rgb; 219 | 220 | #[inline] 221 | fn div(self, rhs: Rgb) -> Rgb { 222 | Rgb::new(self.r.normalized_div(rhs.r), 223 | self.g.normalized_div(rhs.g), 224 | self.b.normalized_div(rhs.b)) 225 | } 226 | } 227 | 228 | impl> Div for Rgb { 229 | type Output = Rgb; 230 | 231 | #[inline] 232 | fn div(self, rhs: T) -> Rgb { 233 | Rgb::new(self.r / rhs, 234 | self.g / rhs, 235 | self.b / rhs) 236 | } 237 | } 238 | 239 | impl> Add for Rgb { 240 | type Output = Rgb; 241 | 242 | #[inline] 243 | fn add(self, rhs: Rgb) -> Rgb { 244 | Rgb::new(self.r + rhs.r, 245 | self.g + rhs.g, 246 | self.b + rhs.b) 247 | } 248 | } 249 | 250 | impl> Sub for Rgb { 251 | type Output = Rgb; 252 | 253 | #[inline] 254 | fn sub(self, rhs: Rgb) -> Rgb { 255 | Rgb::new(self.r - rhs.r, 256 | self.g - rhs.g, 257 | self.b - rhs.b) 258 | } 259 | } 260 | 261 | impl Saturating for Rgb { 262 | fn saturating_add(self, v: Rgb) -> Rgb { 263 | Rgb::new(self.r.saturating_add(v.r), 264 | self.g.saturating_add(v.g), 265 | self.b.saturating_add(v.b)) 266 | } 267 | 268 | fn saturating_sub(self, v: Rgb) -> Rgb { 269 | Rgb::new(self.r.saturating_sub(v.r), 270 | self.g.saturating_sub(v.g), 271 | self.b.saturating_sub(v.b)) 272 | } 273 | } 274 | 275 | impl Index for Rgb { 276 | type Output = T; 277 | fn index<'a>(&'a self, index: usize) -> &'a T { 278 | self.as_ref().index(index) 279 | } 280 | } 281 | 282 | impl IndexMut for Rgb { 283 | fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut T { 284 | self.as_mut().index_mut(index) 285 | } 286 | } 287 | 288 | impl AsRef<[T]> for Rgb { 289 | fn as_ref(&self) -> &[T] { 290 | unsafe{ slice::from_raw_parts(&self.r, 3) } 291 | } 292 | } 293 | 294 | impl AsMut<[T]> for Rgb { 295 | fn as_mut(&mut self) -> &mut [T] { 296 | unsafe{ slice::from_raw_parts_mut(&mut self.r, 3) } 297 | } 298 | } 299 | 300 | impl ToHsv for Rgb { 301 | #[inline] 302 | fn to_hsv(&self) -> Hsv { 303 | // Algorithm taken from the Wikipedia article on HSL and Hsv: 304 | // http://en.wikipedia.org/wiki/HSL_and_Hsv#From_Hsv 305 | 306 | let rgb_u = self.to_rgb::(); 307 | 308 | let mx = cast(cast::(rgb_u.r).max(cast(rgb_u.g)).max(cast(rgb_u.b))); 309 | let mn = cast(cast::(rgb_u.r).min(cast(rgb_u.g)).min(cast(rgb_u.b))); 310 | let chr = mx - mn; 311 | 312 | if chr != Zero::zero() { 313 | let h = 314 | if rgb_u.r == mx { ((rgb_u.g - rgb_u.b) / chr) % cast(6u8) } 315 | else if rgb_u.g == mx { ((rgb_u.b - rgb_u.r) / chr) + cast(2u8) } 316 | else /* rgb_u.b == mx */ { ((rgb_u.r - rgb_u.g) / chr) + cast(4u8) } 317 | * cast(60u8); 318 | 319 | let s = chr / mx; 320 | 321 | Hsv::new(Deg(h), s, mx) 322 | 323 | } else { 324 | Hsv::new(Zero::zero(), Zero::zero(), mx) 325 | } 326 | } 327 | } 328 | 329 | /// SVG 1.0 color constants: http://www.w3.org/TR/SVG/types.html#ColorKeywords 330 | pub mod consts { 331 | use Rgb; 332 | 333 | pub static ALICEBLUE: Rgb = Rgb { r: 0xF0, g: 0xF8, b: 0xFF }; 334 | pub static ANTIQUEWHITE: Rgb = Rgb { r: 0xFA, g: 0xEB, b: 0xD7 }; 335 | pub static AQUA: Rgb = Rgb { r: 0x00, g: 0xFF, b: 0xFF }; 336 | pub static AQUAMARINE: Rgb = Rgb { r: 0x7F, g: 0xFF, b: 0xD4 }; 337 | pub static AZURE: Rgb = Rgb { r: 0xF0, g: 0xFF, b: 0xFF }; 338 | pub static BEIGE: Rgb = Rgb { r: 0xF5, g: 0xF5, b: 0xDC }; 339 | pub static BISQUE: Rgb = Rgb { r: 0xFF, g: 0xE4, b: 0xC4 }; 340 | pub static BLACK: Rgb = Rgb { r: 0x00, g: 0x00, b: 0x00 }; 341 | pub static BLANCHEDALMOND: Rgb = Rgb { r: 0xFF, g: 0xEB, b: 0xCD }; 342 | pub static BLUE: Rgb = Rgb { r: 0x00, g: 0x00, b: 0xFF }; 343 | pub static BLUEVIOLET: Rgb = Rgb { r: 0x8A, g: 0x2B, b: 0xE2 }; 344 | pub static BROWN: Rgb = Rgb { r: 0xA5, g: 0x2A, b: 0x2A }; 345 | pub static BURLYWOOD: Rgb = Rgb { r: 0xDE, g: 0xB8, b: 0x87 }; 346 | pub static CADETBLUE: Rgb = Rgb { r: 0x5F, g: 0x9E, b: 0xA0 }; 347 | pub static CHARTREUSE: Rgb = Rgb { r: 0x7F, g: 0xFF, b: 0x00 }; 348 | pub static CHOCOLATE: Rgb = Rgb { r: 0xD2, g: 0x69, b: 0x1E }; 349 | pub static CORAL: Rgb = Rgb { r: 0xFF, g: 0x7F, b: 0x50 }; 350 | pub static CORNFLOWERBLUE: Rgb = Rgb { r: 0x64, g: 0x95, b: 0xED }; 351 | pub static CORNSILK: Rgb = Rgb { r: 0xFF, g: 0xF8, b: 0xDC }; 352 | pub static CRIMSON: Rgb = Rgb { r: 0xDC, g: 0x14, b: 0x3C }; 353 | pub static CYAN: Rgb = Rgb { r: 0x00, g: 0xFF, b: 0xFF }; 354 | pub static DARKBLUE: Rgb = Rgb { r: 0x00, g: 0x00, b: 0x8B }; 355 | pub static DARKCYAN: Rgb = Rgb { r: 0x00, g: 0x8B, b: 0x8B }; 356 | pub static DARKGOLDENROD: Rgb = Rgb { r: 0xB8, g: 0x86, b: 0x0B }; 357 | pub static DARKGRAY: Rgb = Rgb { r: 0xA9, g: 0xA9, b: 0xA9 }; 358 | pub static DARKGREEN: Rgb = Rgb { r: 0x00, g: 0x64, b: 0x00 }; 359 | pub static DARKKHAKI: Rgb = Rgb { r: 0xBD, g: 0xB7, b: 0x6B }; 360 | pub static DARKMAGENTA: Rgb = Rgb { r: 0x8B, g: 0x00, b: 0x8B }; 361 | pub static DARKOLIVEGREEN: Rgb = Rgb { r: 0x55, g: 0x6B, b: 0x2F }; 362 | pub static DARKORANGE: Rgb = Rgb { r: 0xFF, g: 0x8C, b: 0x00 }; 363 | pub static DARKORCHID: Rgb = Rgb { r: 0x99, g: 0x32, b: 0xCC }; 364 | pub static DARKRED: Rgb = Rgb { r: 0x8B, g: 0x00, b: 0x00 }; 365 | pub static DARKSALMON: Rgb = Rgb { r: 0xE9, g: 0x96, b: 0x7A }; 366 | pub static DARKSEAGREEN: Rgb = Rgb { r: 0x8F, g: 0xBC, b: 0x8F }; 367 | pub static DARKSLATEBLUE: Rgb = Rgb { r: 0x48, g: 0x3D, b: 0x8B }; 368 | pub static DARKSLATEGRAY: Rgb = Rgb { r: 0x2F, g: 0x4F, b: 0x4F }; 369 | pub static DARKTURQUOISE: Rgb = Rgb { r: 0x00, g: 0xCE, b: 0xD1 }; 370 | pub static DARKVIOLET: Rgb = Rgb { r: 0x94, g: 0x00, b: 0xD3 }; 371 | pub static DEEPPINK: Rgb = Rgb { r: 0xFF, g: 0x14, b: 0x93 }; 372 | pub static DEEPSKYBLUE: Rgb = Rgb { r: 0x00, g: 0xBF, b: 0xFF }; 373 | pub static DIMGRAY: Rgb = Rgb { r: 0x69, g: 0x69, b: 0x69 }; 374 | pub static DODGERBLUE: Rgb = Rgb { r: 0x1E, g: 0x90, b: 0xFF }; 375 | pub static FIREBRICK: Rgb = Rgb { r: 0xB2, g: 0x22, b: 0x22 }; 376 | pub static FLORALWHITE: Rgb = Rgb { r: 0xFF, g: 0xFA, b: 0xF0 }; 377 | pub static FORESTGREEN: Rgb = Rgb { r: 0x22, g: 0x8B, b: 0x22 }; 378 | pub static FUCHSIA: Rgb = Rgb { r: 0xFF, g: 0x00, b: 0xFF }; 379 | pub static GAINSBORO: Rgb = Rgb { r: 0xDC, g: 0xDC, b: 0xDC }; 380 | pub static GHOSTWHITE: Rgb = Rgb { r: 0xF8, g: 0xF8, b: 0xFF }; 381 | pub static GOLD: Rgb = Rgb { r: 0xFF, g: 0xD7, b: 0x00 }; 382 | pub static GOLDENROD: Rgb = Rgb { r: 0xDA, g: 0xA5, b: 0x20 }; 383 | pub static GRAY: Rgb = Rgb { r: 0x80, g: 0x80, b: 0x80 }; 384 | pub static GREEN: Rgb = Rgb { r: 0x00, g: 0x80, b: 0x00 }; 385 | pub static GREENYELLOW: Rgb = Rgb { r: 0xAD, g: 0xFF, b: 0x2F }; 386 | pub static HONEYDEW: Rgb = Rgb { r: 0xF0, g: 0xFF, b: 0xF0 }; 387 | pub static HOTPINK: Rgb = Rgb { r: 0xFF, g: 0x69, b: 0xB4 }; 388 | pub static INDIANRED: Rgb = Rgb { r: 0xCD, g: 0x5C, b: 0x5C }; 389 | pub static INDIGO: Rgb = Rgb { r: 0x4B, g: 0x00, b: 0x82 }; 390 | pub static IVORY: Rgb = Rgb { r: 0xFF, g: 0xFF, b: 0xF0 }; 391 | pub static KHAKI: Rgb = Rgb { r: 0xF0, g: 0xE6, b: 0x8C }; 392 | pub static LAVENDER: Rgb = Rgb { r: 0xE6, g: 0xE6, b: 0xFA }; 393 | pub static LAVENDERBLUSH: Rgb = Rgb { r: 0xFF, g: 0xF0, b: 0xF5 }; 394 | pub static LAWNGREEN: Rgb = Rgb { r: 0x7C, g: 0xFC, b: 0x00 }; 395 | pub static LEMONCHIFFON: Rgb = Rgb { r: 0xFF, g: 0xFA, b: 0xCD }; 396 | pub static LIGHTBLUE: Rgb = Rgb { r: 0xAD, g: 0xD8, b: 0xE6 }; 397 | pub static LIGHTCORAL: Rgb = Rgb { r: 0xF0, g: 0x80, b: 0x80 }; 398 | pub static LIGHTCYAN: Rgb = Rgb { r: 0xE0, g: 0xFF, b: 0xFF }; 399 | pub static LIGHTGOLDENRODYELLOW: Rgb = Rgb { r: 0xFA, g: 0xFA, b: 0xD2 }; 400 | pub static LIGHTGREEN: Rgb = Rgb { r: 0x90, g: 0xEE, b: 0x90 }; 401 | pub static LIGHTGREY: Rgb = Rgb { r: 0xD3, g: 0xD3, b: 0xD3 }; 402 | pub static LIGHTPINK: Rgb = Rgb { r: 0xFF, g: 0xB6, b: 0xC1 }; 403 | pub static LIGHTSALMON: Rgb = Rgb { r: 0xFF, g: 0xA0, b: 0x7A }; 404 | pub static LIGHTSEAGREEN: Rgb = Rgb { r: 0x20, g: 0xB2, b: 0xAA }; 405 | pub static LIGHTSKYBLUE: Rgb = Rgb { r: 0x87, g: 0xCE, b: 0xFA }; 406 | pub static LIGHTSLATEGRAY: Rgb = Rgb { r: 0x77, g: 0x88, b: 0x99 }; 407 | pub static LIGHTSTEELBLUE: Rgb = Rgb { r: 0xB0, g: 0xC4, b: 0xDE }; 408 | pub static LIGHTYELLOW: Rgb = Rgb { r: 0xFF, g: 0xFF, b: 0xE0 }; 409 | pub static LIME: Rgb = Rgb { r: 0x00, g: 0xFF, b: 0x00 }; 410 | pub static LIMEGREEN: Rgb = Rgb { r: 0x32, g: 0xCD, b: 0x32 }; 411 | pub static LINEN: Rgb = Rgb { r: 0xFA, g: 0xF0, b: 0xE6 }; 412 | pub static MAGENTA: Rgb = Rgb { r: 0xFF, g: 0x00, b: 0xFF }; 413 | pub static MAROON: Rgb = Rgb { r: 0x80, g: 0x00, b: 0x00 }; 414 | pub static MEDIUMAQUAMARINE: Rgb = Rgb { r: 0x66, g: 0xCD, b: 0xAA }; 415 | pub static MEDIUMBLUE: Rgb = Rgb { r: 0x00, g: 0x00, b: 0xCD }; 416 | pub static MEDIUMORCHID: Rgb = Rgb { r: 0xBA, g: 0x55, b: 0xD3 }; 417 | pub static MEDIUMPURPLE: Rgb = Rgb { r: 0x93, g: 0x70, b: 0xDB }; 418 | pub static MEDIUMSEAGREEN: Rgb = Rgb { r: 0x3C, g: 0xB3, b: 0x71 }; 419 | pub static MEDIUMSLATEBLUE: Rgb = Rgb { r: 0x7B, g: 0x68, b: 0xEE }; 420 | pub static MEDIUMSPRINGGREEN: Rgb = Rgb { r: 0x00, g: 0xFA, b: 0x9A }; 421 | pub static MEDIUMTURQUOISE: Rgb = Rgb { r: 0x48, g: 0xD1, b: 0xCC }; 422 | pub static MEDIUMVIOLETRED: Rgb = Rgb { r: 0xC7, g: 0x15, b: 0x85 }; 423 | pub static MIDNIGHTBLUE: Rgb = Rgb { r: 0x19, g: 0x19, b: 0x70 }; 424 | pub static MINTCREAM: Rgb = Rgb { r: 0xF5, g: 0xFF, b: 0xFA }; 425 | pub static MISTYROSE: Rgb = Rgb { r: 0xFF, g: 0xE4, b: 0xE1 }; 426 | pub static MOCCASIN: Rgb = Rgb { r: 0xFF, g: 0xE4, b: 0xB5 }; 427 | pub static NAVAJOWHITE: Rgb = Rgb { r: 0xFF, g: 0xDE, b: 0xAD }; 428 | pub static NAVY: Rgb = Rgb { r: 0x00, g: 0x00, b: 0x80 }; 429 | pub static OLDLACE: Rgb = Rgb { r: 0xFD, g: 0xF5, b: 0xE6 }; 430 | pub static OLIVE: Rgb = Rgb { r: 0x80, g: 0x80, b: 0x00 }; 431 | pub static OLIVEDRAB: Rgb = Rgb { r: 0x6B, g: 0x8E, b: 0x23 }; 432 | pub static ORANGE: Rgb = Rgb { r: 0xFF, g: 0xA5, b: 0x00 }; 433 | pub static ORANGERED: Rgb = Rgb { r: 0xFF, g: 0x45, b: 0x00 }; 434 | pub static ORCHID: Rgb = Rgb { r: 0xDA, g: 0x70, b: 0xD6 }; 435 | pub static PALEGOLDENROD: Rgb = Rgb { r: 0xEE, g: 0xE8, b: 0xAA }; 436 | pub static PALEGREEN: Rgb = Rgb { r: 0x98, g: 0xFB, b: 0x98 }; 437 | pub static PALEVIOLETRED: Rgb = Rgb { r: 0xDB, g: 0x70, b: 0x93 }; 438 | pub static PAPAYAWHIP: Rgb = Rgb { r: 0xFF, g: 0xEF, b: 0xD5 }; 439 | pub static PEACHPUFF: Rgb = Rgb { r: 0xFF, g: 0xDA, b: 0xB9 }; 440 | pub static PERU: Rgb = Rgb { r: 0xCD, g: 0x85, b: 0x3F }; 441 | pub static PINK: Rgb = Rgb { r: 0xFF, g: 0xC0, b: 0xCB }; 442 | pub static PLUM: Rgb = Rgb { r: 0xDD, g: 0xA0, b: 0xDD }; 443 | pub static POWDERBLUE: Rgb = Rgb { r: 0xB0, g: 0xE0, b: 0xE6 }; 444 | pub static PURPLE: Rgb = Rgb { r: 0x80, g: 0x00, b: 0x80 }; 445 | pub static RED: Rgb = Rgb { r: 0xFF, g: 0x00, b: 0x00 }; 446 | pub static ROSYBROWN: Rgb = Rgb { r: 0xBC, g: 0x8F, b: 0x8F }; 447 | pub static ROYALBLUE: Rgb = Rgb { r: 0x41, g: 0x69, b: 0xE1 }; 448 | pub static SADDLEBROWN: Rgb = Rgb { r: 0x8B, g: 0x45, b: 0x13 }; 449 | pub static SALMON: Rgb = Rgb { r: 0xFA, g: 0x80, b: 0x72 }; 450 | pub static SANDYBROWN: Rgb = Rgb { r: 0xFA, g: 0xA4, b: 0x60 }; 451 | pub static SEAGREEN: Rgb = Rgb { r: 0x2E, g: 0x8B, b: 0x57 }; 452 | pub static SEASHELL: Rgb = Rgb { r: 0xFF, g: 0xF5, b: 0xEE }; 453 | pub static SIENNA: Rgb = Rgb { r: 0xA0, g: 0x52, b: 0x2D }; 454 | pub static SILVER: Rgb = Rgb { r: 0xC0, g: 0xC0, b: 0xC0 }; 455 | pub static SKYBLUE: Rgb = Rgb { r: 0x87, g: 0xCE, b: 0xEB }; 456 | pub static SLATEBLUE: Rgb = Rgb { r: 0x6A, g: 0x5A, b: 0xCD }; 457 | pub static SLATEGRAY: Rgb = Rgb { r: 0x70, g: 0x80, b: 0x90 }; 458 | pub static SNOW: Rgb = Rgb { r: 0xFF, g: 0xFA, b: 0xFA }; 459 | pub static SPRINGGREEN: Rgb = Rgb { r: 0x00, g: 0xFF, b: 0x7F }; 460 | pub static STEELBLUE: Rgb = Rgb { r: 0x46, g: 0x82, b: 0xB4 }; 461 | pub static TAN: Rgb = Rgb { r: 0xD2, g: 0xB4, b: 0x8C }; 462 | pub static TEAL: Rgb = Rgb { r: 0x00, g: 0x80, b: 0x80 }; 463 | pub static THISTLE: Rgb = Rgb { r: 0xD8, g: 0xBF, b: 0xD8 }; 464 | pub static TOMATO: Rgb = Rgb { r: 0xFF, g: 0x63, b: 0x47 }; 465 | pub static TURQUOISE: Rgb = Rgb { r: 0x40, g: 0xE0, b: 0xD0 }; 466 | pub static VIOLET: Rgb = Rgb { r: 0xEE, g: 0x82, b: 0xEE }; 467 | pub static WHEAT: Rgb = Rgb { r: 0xF5, g: 0xDE, b: 0xB3 }; 468 | pub static WHITE: Rgb = Rgb { r: 0xFF, g: 0xFF, b: 0xFF }; 469 | pub static WHITESMOKE: Rgb = Rgb { r: 0xF5, g: 0xF5, b: 0xF5 }; 470 | pub static YELLOW: Rgb = Rgb { r: 0xFF, g: 0xFF, b: 0x00 }; 471 | pub static YELLOWGREEN: Rgb = Rgb { r: 0x9A, g: 0xCD, b: 0x32 }; 472 | } 473 | 474 | #[cfg(test)] 475 | mod tests { 476 | use {Hsv, ToHsv}; 477 | use {Rgb, ToRgb}; 478 | use FloatColor; 479 | use angle::*; 480 | use num::Saturating; 481 | 482 | #[test] 483 | fn test_rgb_to_rgb() { 484 | assert_eq!(Rgb::::new(0xA0, 0xA0, 0xA0).to_rgb::(), Rgb::::new(0xA0, 0xA0, 0xA0)); 485 | assert_eq!(Rgb::::new(0xA0, 0xA0, 0xA0).to_rgb::(), Rgb::::new(0xA0A0, 0xA0A0, 0xA0A0)); 486 | } 487 | 488 | #[test] 489 | fn test_rgb_to_hsv() { 490 | assert_eq!(Rgb::::new(0xFF, 0xFF, 0xFF).to_hsv::(), Hsv::::new(Deg(0.0), 0.0, 1.0)); 491 | assert_eq!(Rgb::::new(0x99, 0x00, 0x00).to_hsv::(), Hsv::::new(Deg(0.0), 1.0, 0.6)); 492 | assert_eq!(Rgb::::new(0x00, 0x99, 0x00).to_hsv::(), Hsv::::new(Deg(120.0), 1.0, 0.6)); 493 | assert_eq!(Rgb::::new(0x00, 0x00, 0x99).to_hsv::(), Hsv::::new(Deg(240.0), 1.0, 0.6)); 494 | } 495 | 496 | #[test] 497 | fn test_rgb_ops(){ 498 | assert_eq!( rgb!(20u8, 20, 20) + rgb!(20, 20, 20), rgb!(40, 40, 40) ); 499 | assert_eq!( rgb!(254u8, 254, 254).saturating_add( rgb!(20, 20, 20) ), rgb!(255, 255, 255) ); 500 | assert_eq!( rgb!(20u8, 20, 20).saturating_sub( rgb!(50, 50, 50) ), rgb!(0, 0, 0) ); 501 | assert_eq!( rgb!(127u8, 127, 127) * rgb!(255, 255, 255), rgb!(127, 127, 127) ); 502 | assert_eq!( rgb!(127u8, 127, 127) / rgb!(255, 255, 255), rgb!(127, 127, 127) ); 503 | assert_eq!( rgb!(1.0f32, 1.0, 1.0) * 2.0, rgb!(2.0, 2.0, 2.0)); 504 | assert_eq!( (rgb!(1.0f32, 1.0, 1.0) * 2.0).saturate(), rgb!(1.0, 1.0, 1.0)); 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /src/srgb.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 17 | pub struct Srgb { pub r: T, pub g: T, pub b: T } 18 | 19 | impl Srgb { 20 | #[inline] 21 | pub fn new(r: T, g: T, b: T) -> Srgb { 22 | Srgb { r: r, g: g, b: b } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ycbcr.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The color-rs developers. For a full listing of the authors, 2 | // refer to the AUTHORS file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //! http://en.wikipedia.org/wiki/YCbCr 17 | 18 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 19 | pub struct YCbCr { pub y: T, pub cb: T, pub cr: T } 20 | 21 | impl YCbCr { 22 | #[inline] 23 | pub fn new(y: T, cb: T, cr: T) -> YCbCr { 24 | YCbCr { y: y, cb: cb, cr: cr } 25 | } 26 | } 27 | --------------------------------------------------------------------------------