Image Unit Processing Interface. INFO: This is a mirror from GitHub. github.com/sona-tau/iupi
at main 330 lines 15 kB view raw
1#lang plait 2 3(require "utilities.rkt") 4(require "parser.rkt") 5(require "types.rkt") 6(require "combinators.rkt") 7 8;----- Language Implementation -----; 9; Converts a single digit into a number. Basically just returns the number 10; contained inside the digit. 11(define (digit->number [d : Digit]) : Number 12 (type-case Digit d 13 [(digit n) n])) 14 15; Converts a series of digits into a number. 16(define (digits->number [ds : Digits]) : Number 17 (type-case Digits ds 18 [(number first rest) (+ (digit->number first) (* 10 (digits->number rest)))] 19 [(empty-digit) 0])) 20 21; Converts a decimal into a number. 22(define (decimals->number [dc : Decimals]) : Number 23 (type-case Decimals dc 24 [(decimals first rest) (/ (+ (digit->number first) (decimals->number rest)) 10)] 25 [(empty-decimal) 0])) 26 27; Converts a floating point type number into a number. 28(define (float->number [fp : Float]) : Number 29 (type-case Float fp 30 [(float ds) (decimals->number ds)])) 31 32;----- Language Functionality -----; 33; Helper function to create binary operations. 34(define (bin-op-builder [c1 : RGBColor] [c2 : RGBColor] [f : (Number Number -> Number)]) : RGBColor 35 (type-case RGBColor c1 36 [(rgbcolor red1 green1 blue1) (type-case RGBColor c2 37 [(rgbcolor red2 green2 blue2) (let* 38 [(r1 (digits->number red1)) 39 (r2 (digits->number red2)) 40 (g1 (digits->number green1)) 41 (g2 (digits->number green2)) 42 (b1 (digits->number blue1)) 43 (b2 (digits->number blue2)) 44 (r3 (mod256 (f r1 r2))) 45 (g3 (mod256 (f g1 g2))) 46 (b3 (mod256 (f b1 b2)))] 47 (rgbcolor (number->digits r3) (number->digits g3) (number->digits b3)))])])) 48 49; Add two colors 50(define (color-add [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 51 (bin-op-builder c1 c2 +)) 52 53; Multiply two colors 54(define (color-multiply [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 55 (bin-op-builder c1 c2 (λ (n m) (floor (* n m))))) 56 57; Divide two colors (will floor their values and return 0 if divide by 0) 58(define (color-divide [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 59 (bin-op-builder c1 c2 (λ (n m) (if (= m 0) 0 (floor (/ n m)))))) 60 61; Subtract two colors 62(define (color-subtract [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 63 (bin-op-builder c1 c2 -)) 64 65; Invert the luminosity of a color 66(define (color-value-invert [c1 : RGBColor]) : RGBColor 67 (type-case HSVColor (rgb->hsv c1) 68 [(hsvcolor h1 s1 v1) 69 (let [(h2 h1) (s2 s1) (v2 (- 1 v1))] (hsv->rgb [hsvcolor h2 s2 v2]))])) 70 71; Invert each RGB value of a color 72(define (color-linear-invert [c : RGBColor]) : RGBColor 73 (color-subtract [rgbcolor (number->digits 255) (number->digits 255) (number->digits 255)] c)) 74 75; Interpolate a color between two other colors 76(define (color-interpolate [c1 : RGBColor] [c2 : RGBColor] [percent : Float]) : RGBColor 77 (type-case HSVColor (rgb->hsv c1) 78 [(hsvcolor h1 s1 v1) (type-case HSVColor (rgb->hsv c2) 79 [(hsvcolor h2 s2 v2) 80 (let* [(prcnt (float->number percent)) 81 (h3 (interpolate-num h1 h2 prcnt)) 82 (s3 (interpolate-num s1 s2 prcnt)) 83 (v3 (interpolate-num v1 v2 prcnt))] (hsv->rgb (hsvcolor h3 s3 v3)))])])) 84 85; Sums all rgb values of a color 86(define (sumar-color [color : RGBColor] ) : Number 87 (+ 88 (+ 89 (mod256(digits->number(rgbcolor-red color))) 90 (mod256(digits->number(rgbcolor-blue color)))) 91 (mod256(digits->number(rgbcolor-green color))))) 92 93; Choose the color with larger values 94(define (color-max [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 95 (let ((sumc1 (sumar-color c1)) 96 (sumc2 (sumar-color c2))) 97 (cond ((> sumc1 sumc2) c1) 98 (else c2)))) 99 100; Choose the color with smaller values 101(define (color-min [c1 : RGBColor] [c2 : RGBColor]) : RGBColor 102 (let ((sumc1 (sumar-color c1)) 103 (sumc2 (sumar-color c2))) 104 (cond ((< sumc1 sumc2) c1) 105 (else c2)))) 106 107 108; Convert HSVColor to RGB 109(define (hsv->rgb [c : HSVColor]) : RGBColor 110 (type-case HSVColor c 111 [(hsvcolor hue saturation value) (let [(h hue) (s saturation) (v value)] 112 (let* [(chroma (* v s)) 113 (hp (/ h 60)) 114 (x (if (even? (round hp)) 0 chroma)) 115 (c1 [cond 116 [(< hp 1) (list chroma x 0)] 117 [(< hp 2) (list x chroma 0)] 118 [(< hp 3) (list 0 chroma x)] 119 [(< hp 4) (list 0 x chroma)] 120 [(< hp 5) (list x 0 chroma)] 121 [else (list chroma 0 x)]]) 122 (m (- v chroma)) 123 (r (round (* 256 (+ (first c1) m)))) 124 (g (round (* 256 (+ (second c1) m)))) 125 (b (round (* 256 (+ (third c1) m))))] (rgbcolor (number->digits r) (number->digits g) (number->digits b))))])) 126 127; Convert RGB color to HSV color 128(define (rgb->hsv [c : RGBColor]) : HSVColor 129 (type-case RGBColor c 130 [(rgbcolor red green blue) (let* 131 [(r (/ (digits->number red) 255)) 132 (g (/ (digits->number green) 255)) 133 (b (/ (digits->number blue) 255)) 134 (x+ (maxel (list r g b))) 135 (x- (minel (list r g b))) 136 (v x+) 137 (c (- x+ x-)) 138 (l (/ (+ x+ x-) 2)) 139 (h [cond 140 [(= c 0) 0] 141 [(= v r) (* 60 (modulo (round (/ (- g b) c)) 6))] 142 [(= v g) (* 60 (+ (/ (- b r) c) 2))] 143 [(= v b) (* 60 (+ (/ (- r g) c) 4))] 144 [else 0]]) 145 (s (if (= v 0) 0 (/ c v))) 146 ] (hsvcolor h s v))])) 147 148;----- The Parsers -----; 149; Parser that parses a single digit. 150(define (p-digit [s : String]) : (ParseResult Digit) 151 (do ((or/p (list (char/p #\1) 152 (char/p #\2) 153 (char/p #\3) 154 (char/p #\4) 155 (char/p #\5) 156 (char/p #\6) 157 (char/p #\7) 158 (char/p #\8) 159 (char/p #\9) 160 (char/p #\0))) s) 161 (λ (result) (let [(char (snd result)) (cdr (fst result))] (return cdr (digit (char->num char))))))) 162 163; Parser that parses many digits. Will continue consuming digits from the input 164; string until the parser fails. In which case it will return the sequence of 165; digits that have been parsed already. 166(define (p-digits [s : String]) : (ParseResult Digits) 167 (do ((many1/p p-digit) s) 168 (λ (result) (let [(digitlist (snd result)) (cdr (fst result))] (return cdr (digitlist->digits digitlist)))))) 169 170; Parser that parses decimal numbers. 171(define (p-decimals [s : String]) : (ParseResult Decimals) 172 (do ((many1/p p-digit) s) 173 (λ (result) (let [(digitlist (snd result)) (cdr (fst result))] (return cdr (digitlist->decimals digitlist)))))) 174 175; Parser that parses an entire floating point number. 176(define (p-float [s : String]) : (ParseResult Float) 177 (do ((right/p (char/p #\.) p-decimals) s) 178 (λ (result) (let* [(decimals (snd result)) (cdr (fst result))] (return cdr (float decimals)))))) 179 180; Parser that parses an entire color. Returns a (ParseResult RGBColor) where 181; each component of the RGBColor is of type Digits. 182(define (p-color [s : String]) : (ParseResult RGBColor) 183 (do ((right/p (char/p #\() p-digits) s) 184 (λ (result1) (let [(red (snd result1)) (cdr1 (fst result1))] 185 (do ((right/p (char/p #\,) p-digits) cdr1) 186 (λ (result2) (let [(green (snd result2)) (cdr2 (fst result2))] 187 (do ((left/p (right/p (char/p #\,) p-digits) (char/p #\))) cdr2) 188 (λ (result3) (let [(blue (snd result3)) (cdr3 (fst result3))] 189 (return cdr3 (rgbcolor red green blue)))))))))))) 190 191; Parser that parses a unary operation. It will also parse the rest of the 192; source code and use it as an argument for the unary operation argument. 193(define (p-unary-operation [s : String]) : (ParseResult UnaryOperation) 194 (do ((or/p (list (seq/p (string/p "<^>") p-lang) (seq/p (string/p "<|>") p-lang))) s) 195 (λ (result) (let [(op-string (fst (snd result))) (lang (snd (snd result))) (cdr (fst result))] 196 (return cdr (if (string=? op-string "<^>") 197 (value-invert lang) 198 (linear-invert lang))))))) 199 200; Parser that parses an operator symbol and color. This is a helper function for 201; (p-binary-operation). This function is necessary because the symbol in the 202; middle can either be a symbol string or a floating-point number. Wrapping the 203; result in OperatorType means that the data gathered from this parse can then 204; be type-checked by plait correctly. 205(define (p-operator-type [s : String]) : (ParseResult OperatorType) 206 (type-case (ParseResult String) ((or/p (list 207 (string/p "+") 208 (string/p "-") 209 (string/p "*") 210 (string/p "/") 211 (string/p "^") 212 (string/p "!"))) s) 213 [(ok result) (let [(str (snd result)) (cdr (fst result))] (return cdr (string-type str)))] 214 [(err) (do (p-float s) 215 (λ (result) (let [(n (snd result)) (cdr (fst result))](return cdr (floating-type n)))))])) 216 217; Parser that parses a binary operation. The recursive nature of this parser 218; means that it will continue parsing the input string until it cannot continue. 219; In which case it starts evaluating the expression. 220(define (p-binary-operation [s : String]) : (ParseResult BinaryOperation) 221 (do ((seq/p p-color (seq/p p-operator-type p-expr)) s) 222 (λ (result) (let* [(col-type-expr (snd result)) (col (fst col-type-expr)) (op-type (fst (snd col-type-expr))) (expr (snd (snd col-type-expr))) (cdr (fst result))] 223 (return cdr (type-case OperatorType op-type 224 [(floating-type fp) (interpolate col expr fp)] 225 [(string-type str) [cond 226 [(string=? str "+") (add col expr)] 227 [(string=? str "-") (subtract col expr)] 228 [(string=? str "*") (multiply col expr)] 229 [(string=? str "/") (divide col expr)] 230 [(string=? str "^") (max col expr)] 231 [(string=? str "!") (min col expr)]]])))))) 232 233; Parser that parses an entire expression. This type is necessary to separate 234; the (UnaryOperation)'s from the (BinaryOperation)'s. 235(define (p-expr [s : String]) : (ParseResult Expr) 236 (type-case (ParseResult BinaryOperation) (p-binary-operation s) 237 [(ok result) (let [(bin-op (snd result)) (cdr (fst result))] 238 (return cdr (operation bin-op)))] 239 [(err) (type-case (ParseResult RGBColor) (p-color s) 240 [(ok result) (let [(col (snd result)) (cdr (fst result))] 241 (return cdr (color col)))] 242 [(err) (err)])])) 243 244; Parser that parses the entire language. 245(define (p-lang [s : String]) : (ParseResult Language) 246 (type-case (ParseResult UnaryOperation) (p-unary-operation s) 247 [(ok result) (let [(un-op (snd result)) (cdr (fst result))] 248 (return cdr (unary-operation un-op)))] 249 [(err) (type-case (ParseResult BinaryOperation) (p-binary-operation s) 250 [(ok result) (let [(bin-op (snd result)) (cdr (fst result))] 251 (return cdr (binary-operation bin-op)))] 252 [(err) (type-case (ParseResult RGBColor) (p-color s) 253 [(ok result) (let [(col (snd result)) (cdr (fst result))] 254 (return cdr (lang-color col)))] 255 [(err) (err)])])])) 256 257;----- Evaluation -----; 258; Evaluates a parsed language and returns the corresponding (RGBColor) that 259; would result if the expression was computed. 260(define (evaluate [src : Language]) : RGBColor 261 (type-case Language src 262 [(binary-operation op) (eval-binary-operation op)] 263 [(unary-operation op) (eval-unary-operation op)] 264 [(lang-color col) col])) 265 266; Evaluates a unary operation. 267(define (eval-unary-operation [op : UnaryOperation]) : RGBColor 268 (type-case UnaryOperation op 269 [(value-invert col) (color-value-invert (evaluate col))] 270 [(linear-invert col) (color-linear-invert (evaluate col))])) 271 272; Evaluates a binary operation. 273(define (eval-binary-operation [op : BinaryOperation]) : RGBColor 274 (type-case BinaryOperation op 275 [(add col exp) (color-add col (eval-expr exp))] 276 [(subtract col exp) (color-subtract col (eval-expr exp))] 277 [(multiply col exp) (color-multiply col (eval-expr exp))] 278 [(divide col exp) (color-divide col (eval-expr exp))] 279 [(interpolate col exp percent) (color-interpolate col (eval-expr exp) percent)] 280 [(max col exp) (color-max col (eval-expr exp))] 281 [(min col exp) (color-min col (eval-expr exp))])) 282 283; Evaluates an expression. 284(define (eval-expr [e : Expr]) : RGBColor 285 (type-case Expr e 286 [(operation op) (eval-binary-operation op)] 287 [(color col) col])) 288 289;----- Tests -----; 290(define accept1 "(0,000000,010)") 291(define accept2 "<|><^>(0,0,0)") 292(define accept3 "(0,0,0)/(0,0,0)") 293(define accept4 "(400,100,200)+(10,10,10)/(2,2,2)") 294(define accept5 "(0,0,00).32(0100,319,7880).0(400,100,200)") 295 296(define deny1 "(0,0,0.0)") 297(define deny2 "<|>(0,0,00)<^>(100,319,80)") 298(define deny3 "(0,0,00)0.32(0100,319,7880)") 299(define deny4 "(400,100,200)++(10,10,10)") 300(define deny5 "(400,100,200)+") 301 302; Testing function for strings. 303(define (tester [s : String]) : RGBColor 304 (type-case (ParseResult Language) (p-lang s) 305 [(ok lang) (cond 306 [(not (string=? "" (fst lang))) (error 'incompleteParse (fst lang))] 307 [else (evaluate (snd lang))])] 308 [(err) (error 'parseFailed "not a valid string")])) 309 310"Accept 1:" 311(tester accept1) 312"Accept 2:" 313(tester accept2) 314"Accept 3:" 315(tester accept3) 316"Accept 4:" 317(tester accept4) 318"Accept 5:" 319(tester accept5) 320 321;"Deny 1:" 322;(tester deny1) 323;"Deny 2:" 324;(tester deny2) 325;"Deny 3:" 326;(tester deny3) 327;"Deny 4:" 328;(tester deny4) 329;"Deny 5:" 330;(tester deny5)