;; ;; 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->string write-web-color rgb-color->hex-string write-hex-color rgb-color->string write-rgb-color hsl-color->string write-hsl-color) (: web-color->string (color-list --> string)) (define (web-color->string color) (call-with-output-string (lambda (port) (write-web-color color port)))) (: write-web-color (color-list #!optional port -> undefined)) (define (write-web-color color #!optional (port (current-output-port))) (assert (color-list? color) "Invalid color list" color) (case (car color) ((rgb) (if (= 1 (list-ref color 4)) (write-hex-color color port) (write-rgb-color color port))) ((rgb%) (write-rgb-color color port)) ((hsl) (write-hsl-color color port)))) (: rgb-color->hex-string (color-list --> string)) (define (rgb-color->hex-string color) (call-with-output-string (lambda (port) (write-hex-color color port)))) (: write-hex-color (color-list #!optional port -> undefined)) (define (write-hex-color color #!optional (port (current-output-port))) (let ((bytes (rgb-color->bytes color))) (display "#" port) (%write-hex-byte port (list-ref bytes 0)) (%write-hex-byte port (list-ref bytes 1)) (%write-hex-byte port (list-ref bytes 2)) (if (not (= 255 (list-ref bytes 3))) (%write-hex-byte port (list-ref bytes 3))))) (: %write-hex-byte (output-port fixnum -> undefined)) (define (%write-hex-byte port n) (if (< n 16) (display "0" port)) (display (number->string n 16) port)) (: rgb-color->string (color-list --> string)) (define (rgb-color->string color) (call-with-output-string (lambda (port) (write-rgb-color color port)))) (: write-rgb-color (color-list #!optional port -> undefined)) (define (write-rgb-color color #!optional (port (current-output-port))) (assert (color-list? color '(rgb rgb%)) "Invalid rgb color list" color) (let ((% (if (eq? 'rgb% (car color)) "%" "")) (scale (if (eq? 'rgb% (car color)) 100 1))) (let ((r (%pretty-number (* scale (list-ref color 1)))) (g (%pretty-number (* scale (list-ref color 2)))) (b (%pretty-number (* scale (list-ref color 3)))) (a (list-ref color 4))) (if (= 1 a) (fprintf port "rgb(~A~A, ~A~A, ~A~A)" r % g % b %) (fprintf port "rgba(~A~A, ~A~A, ~A~A, ~A)" r % g % b % (%pretty-number a)))))) (: %pretty-number (number --> number)) (define (%pretty-number n) (if (integer? n) (inexact->exact n) (exact->inexact n))) (: hsl-color->string (color-list --> string)) (define (hsl-color->string color) (call-with-output-string (lambda (port) (write-hsl-color color port)))) (: write-hsl-color (color-list #!optional port -> undefined)) (define (write-hsl-color color #!optional (port (current-output-port))) (assert (and (color-list? color '(hsl))) "Invalid hsl color list" color) (let ((h (%pretty-number (list-ref color 1))) (s (%pretty-number (* 100 (list-ref color 2)))) (l (%pretty-number (* 100 (list-ref color 3)))) (a (list-ref color 4))) (if (= 1 a) (fprintf port "hsl(~A, ~A%, ~A%)" h s l) (fprintf port "hsla(~A, ~A%, ~A%, ~A)" h s l (%pretty-number a)))))