;; ;; chicken-web-colors: ;; Parse and write HTML/CSS color strings in CHICKEN Scheme. ;; ;; Copyright © 2019 John Croisant. ;; All rights reserved. ;; ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions ;; are met: ;; ;; - Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; ;; - Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ;; COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ;; OF THE POSSIBILITY OF SUCH DAMAGE. (export +web-color-types+ color-list? normalize-web-color rgb-color->bytes) (define +web-color-types+ '(rgb rgb% hsl)) (: color-list? (any #!optional (list-of symbol) --> boolean)) (define (color-list? x #!optional (types +web-color-types+)) (and (list? x) (= 5 (length x)) (memq (car x) types) (real? (list-ref x 1)) (real? (list-ref x 2)) (real? (list-ref x 3)) (real? (list-ref x 4)))) (: normalize-web-color (color-list --> color-list)) (define (normalize-web-color color) (assert (color-list? color) "Invalid color list" color) (case (car color) ((rgb) (list 'rgb (%byte (list-ref color 1)) (%byte (list-ref color 2)) (%byte (list-ref color 3)) (%clamp (list-ref color 4) 0 1))) ((rgb%) (list 'rgb% (%clamp (list-ref color 1) 0 1) (%clamp (list-ref color 2) 0 1) (%clamp (list-ref color 3) 0 1) (%clamp (list-ref color 4) 0 1))) ((hsl) (list 'hsl (%wrap (inexact->exact (round (list-ref color 1))) 360) (%clamp (list-ref color 2) 0 1) (%clamp (list-ref color 3) 0 1) (%clamp (list-ref color 4) 0 1))))) (: rgb-color->bytes (color-list --> (list fixnum fixnum fixnum fixnum))) (define (rgb-color->bytes color) (assert (color-list? color '(rgb rgb%)) "Invalid rgb color list" color) (let ((scale (if (eq? 'rgb% (car color)) 255 1))) (list (%byte (* scale (list-ref color 1))) (%byte (* scale (list-ref color 2))) (%byte (* scale (list-ref color 3))) (%byte (* 255 (list-ref color 4)))))) (: %byte (number --> number)) (define (%byte n) (%clamp (inexact->exact (round n)) 0 255)) (: %clamp (number number number --> number)) (define (%clamp n lower upper) (cond ((<= n lower) lower) ((<= upper n) upper) (else n))) (: %wrap (number number --> number)) (define (%wrap n upper) (let loop ((n n)) (cond ((and (<= 0 n) (< n upper)) n) ((< n 0) (loop (+ n upper))) ((<= upper n) (loop (- n upper))))))