You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
9.3 KiB
Racket
262 lines
9.3 KiB
Racket
#lang racket/base
|
|
(require
|
|
"core.rkt"
|
|
"reference.rkt"
|
|
"page.rkt"
|
|
racket/match
|
|
racket/string)
|
|
(provide (all-defined-out))
|
|
|
|
(define (do-opacity doc [fill-arg #f] [stroke-arg #f])
|
|
(define fill-opacity (and fill-arg (bounded 0 fill-arg 1)))
|
|
(define stroke-opacity (and stroke-arg (bounded 0 stroke-arg 1)))
|
|
(when (or fill-opacity stroke-opacity)
|
|
(define key (format "~a_~a"
|
|
(if fill-opacity (numberizer fill-opacity) "")
|
|
(if stroke-opacity (numberizer stroke-opacity) "")))
|
|
(match-define (list dictionary name)
|
|
(hash-ref! (pdf-opacity-registry doc) key
|
|
(λ ()
|
|
(define dictionary (make-hasheq '((Type . ExtGState))))
|
|
(when fill-opacity
|
|
(hash-set! dictionary 'ca fill-opacity))
|
|
(when stroke-opacity
|
|
(hash-set! dictionary 'CA stroke-opacity))
|
|
(define ref-dict (make-ref dictionary))
|
|
(ref-end ref-dict)
|
|
(define opacity-index (add1 (length (hash-keys (pdf-opacity-registry doc)))))
|
|
(list ref-dict (string->symbol (format "Gs~a" opacity-index))))))
|
|
(hash-set! (page-ext_gstates (current-page doc)) name dictionary)
|
|
(add-content doc (format "/~a gs" name))))
|
|
|
|
(define (fill-color doc color [opacity 1])
|
|
(unless (normalize-color color)
|
|
(raise-argument-error 'fill-color "valid color string" color))
|
|
(when (set-color doc color #f) (fill-opacity doc opacity))
|
|
;; save this for text wrapper, which needs to reset
|
|
;; the fill color on new pages
|
|
(set-pdf-current-fill-color! doc (list color opacity))
|
|
doc)
|
|
|
|
(define (fill-opacity doc opacity)
|
|
(do-opacity doc opacity #f)
|
|
doc)
|
|
|
|
(define (set-color doc color-in stroke)
|
|
(define color (normalize-color color-in))
|
|
(define op (if stroke "SCN" "scn"))
|
|
(cond
|
|
[(not color)]
|
|
#;[(is-a? color PDFGradient)
|
|
(set-color-space "Pattern" stroke)
|
|
(send color apply op)
|
|
#true] ; todo
|
|
[else
|
|
(define color-space
|
|
(case (length color)
|
|
[(3) 'DeviceRGB]
|
|
[(4) 'DeviceCMYK]
|
|
[else (raise-argument-error 'set-color "color of length 3 or 4" color)]))
|
|
(set-color-space doc color-space stroke)
|
|
|
|
;; 181126 don't round, to be consistent with pdfkit behavior
|
|
(add-content doc (format "~a ~a" (string-join (map (λ (num) (numberizer num #:round #false)) color) " ") op))
|
|
#true]))
|
|
|
|
(define (set-color-space doc space stroke)
|
|
(define op (if stroke "CS" "cs"))
|
|
(add-content doc (format "/~a ~a" space op)))
|
|
|
|
(define (stroke-color doc color [opacity 1])
|
|
(unless (normalize-color color)
|
|
(raise-argument-error 'stroke-color "valid color string" color))
|
|
(when (set-color doc color #t) (stroke-opacity doc opacity))
|
|
doc)
|
|
|
|
(define (stroke-opacity doc opacity)
|
|
(do-opacity doc #f opacity)
|
|
doc)
|
|
|
|
(define (normalize-color color)
|
|
;; parses color string into list of values
|
|
(match color
|
|
#;[(is-a? color PDFGradient) color] ; todo
|
|
[(? string?)
|
|
(cond
|
|
[(regexp-match #px"^#(?i:[0-9A-F]){3}$" color) ; change #rgb to #rrggbb
|
|
(normalize-color
|
|
(match-let ([(list hsh r g b) (string->list color)])
|
|
(list->string (list hsh r r g g b b))))]
|
|
;; 6-digit hexish string becomes list of hex numbers and maybe #f vals
|
|
[(and (= 7 (string-length color)) (string-prefix? color "#"))
|
|
(normalize-color
|
|
; match two at a time and convert to hex
|
|
(match-let ([(list hsh r r2 g g2 b b2) (string->list color)])
|
|
(map (λ (str) (string->number str 16)) (list (string r r2) (string g g2) (string b b2)))))]
|
|
[(hash-ref named-colors (string-downcase color) #f) => normalize-color]
|
|
[else #false])]
|
|
[(list (? number?) ...) (for/list ([c (in-list color)])
|
|
(define x (/ c (case (length color)
|
|
[(3) 255.0] ; RGB
|
|
[(4) 100.0] ; CMYK
|
|
[else 1.0])))
|
|
(if (integer? x) (inexact->exact x) x))]
|
|
[_ #false]))
|
|
|
|
(define named-colors
|
|
(hash "aliceblue" '(240 248 255)
|
|
"antiquewhite" '(250 235 215)
|
|
"aqua" '(0 255 255)
|
|
"aquamarine" '(127 255 212)
|
|
"azure" '(240 255 255)
|
|
"beige" '(245 245 220)
|
|
"bisque" '(255 228 196)
|
|
"black" '(0 0 0)
|
|
"blanchedalmond" '(255 235 205)
|
|
"blue" '(0 0 255)
|
|
"blueviolet" '(138 43 226)
|
|
"brown" '(165 42 42)
|
|
"burlywood" '(222 184 135)
|
|
"cadetblue" '(95 158 160)
|
|
"chartreuse" '(127 255 0)
|
|
"chocolate" '(210 105 30)
|
|
"coral" '(255 127 80)
|
|
"cornflowerblue" '(100 149 237)
|
|
"cornsilk" '(255 248 220)
|
|
"crimson" '(220 20 60)
|
|
"cyan" '(0 255 255)
|
|
"darkblue" '(0 0 139)
|
|
"darkcyan" '(0 139 139)
|
|
"darkgoldenrod" '(184 134 11)
|
|
"darkgray" '(169 169 169)
|
|
"darkgreen" '(0 100 0)
|
|
"darkgrey" '(169 169 169)
|
|
"darkkhaki" '(189 183 107)
|
|
"darkmagenta" '(139 0 139)
|
|
"darkolivegreen" '(85 107 47)
|
|
"darkorange" '(255 140 0)
|
|
"darkorchid" '(153 50 204)
|
|
"darkred" '(139 0 0)
|
|
"darksalmon" '(233 150 122)
|
|
"darkseagreen" '(143 188 143)
|
|
"darkslateblue" '(72 61 139)
|
|
"darkslategray" '(47 79 79)
|
|
"darkslategrey" '(47 79 79)
|
|
"darkturquoise" '(0 206 209)
|
|
"darkviolet" '(148 0 211)
|
|
"deeppink" '(255 20 147)
|
|
"deepskyblue" '(0 191 255)
|
|
"dimgray" '(105 105 105)
|
|
"dimgrey" '(105 105 105)
|
|
"dodgerblue" '(30 144 255)
|
|
"firebrick" '(178 34 34)
|
|
"floralwhite" '(255 250 240)
|
|
"forestgreen" '(34 139 34)
|
|
"fuchsia" '(255 0 255)
|
|
"gainsboro" '(220 220 220)
|
|
"ghostwhite" '(248 248 255)
|
|
"gold" '(255 215 0)
|
|
"goldenrod" '(218 165 32)
|
|
"gray" '(128 128 128)
|
|
"grey" '(128 128 128)
|
|
"green" '(0 128 0)
|
|
"greenyellow" '(173 255 47)
|
|
"honeydew" '(240 255 240)
|
|
"hotpink" '(255 105 180)
|
|
"indianred" '(205 92 92)
|
|
"indigo" '(75 0 130)
|
|
"ivory" '(255 255 240)
|
|
"khaki" '(240 230 140)
|
|
"lavender" '(230 230 250)
|
|
"lavenderblush" '(255 240 245)
|
|
"lawngreen" '(124 252 0)
|
|
"lemonchiffon" '(255 250 205)
|
|
"lightblue" '(173 216 230)
|
|
"lightcoral" '(240 128 128)
|
|
"lightcyan" '(224 255 255)
|
|
"lightgoldenrodyellow" '(250 250 210)
|
|
"lightgray" '(211 211 211)
|
|
"lightgreen" '(144 238 144)
|
|
"lightgrey" '(211 211 211)
|
|
"lightpink" '(255 182 193)
|
|
"lightsalmon" '(255 160 122)
|
|
"lightseagreen" '(32 178 170)
|
|
"lightskyblue" '(135 206 250)
|
|
"lightslategray" '(119 136 153)
|
|
"lightslategrey" '(119 136 153)
|
|
"lightsteelblue" '(176 196 222)
|
|
"lightyellow" '(255 255 224)
|
|
"lime" '(0 255 0)
|
|
"limegreen" '(50 205 50)
|
|
"linen" '(250 240 230)
|
|
"magenta" '(255 0 255)
|
|
"maroon" '(128 0 0)
|
|
"mediumaquamarine" '(102 205 170)
|
|
"mediumblue" '(0 0 205)
|
|
"mediumorchid" '(186 85 211)
|
|
"mediumpurple" '(147 112 219)
|
|
"mediumseagreen" '(60 179 113)
|
|
"mediumslateblue" '(123 104 238)
|
|
"mediumspringgreen" '(0 250 154)
|
|
"mediumturquoise" '(72 209 204)
|
|
"mediumvioletred" '(199 21 133)
|
|
"midnightblue" '(25 25 112)
|
|
"mintcream" '(245 255 250)
|
|
"mistyrose" '(255 228 225)
|
|
"moccasin" '(255 228 181)
|
|
"navajowhite" '(255 222 173)
|
|
"navy" '(0 0 128)
|
|
"oldlace" '(253 245 230)
|
|
"olive" '(128 128 0)
|
|
"olivedrab" '(107 142 35)
|
|
"orange" '(255 165 0)
|
|
"orangered" '(255 69 0)
|
|
"orchid" '(218 112 214)
|
|
"palegoldenrod" '(238 232 170)
|
|
"palegreen" '(152 251 152)
|
|
"paleturquoise" '(175 238 238)
|
|
"palevioletred" '(219 112 147)
|
|
"papayawhip" '(255 239 213)
|
|
"peachpuff" '(255 218 185)
|
|
"peru" '(205 133 63)
|
|
"pink" '(255 192 203)
|
|
"plum" '(221 160 221)
|
|
"powderblue" '(176 224 230)
|
|
"purple" '(128 0 128)
|
|
"red" '(255 0 0)
|
|
"rosybrown" '(188 143 143)
|
|
"royalblue" '(65 105 225)
|
|
"saddlebrown" '(139 69 19)
|
|
"salmon" '(250 128 114)
|
|
"sandybrown" '(244 164 96)
|
|
"seagreen" '(46 139 87)
|
|
"seashell" '(255 245 238)
|
|
"sienna" '(160 82 45)
|
|
"silver" '(192 192 192)
|
|
"skyblue" '(135 206 235)
|
|
"slateblue" '(106 90 205)
|
|
"slategray" '(112 128 144)
|
|
"slategrey" '(112 128 144)
|
|
"snow" '(255 250 250)
|
|
"springgreen" '(0 255 127)
|
|
"steelblue" '(70 130 180)
|
|
"tan" '(210 180 140)
|
|
"teal" '(0 128 128)
|
|
"thistle" '(216 191 216)
|
|
"tomato" '(255 99 71)
|
|
"turquoise" '(64 224 208)
|
|
"violet" '(238 130 238)
|
|
"wheat" '(245 222 179)
|
|
"white" '(255 255 255)
|
|
"whitesmoke" '(245 245 245)
|
|
"yellow" '(255 255 0)
|
|
"yellowgreen" '(154 205 50)))
|
|
|
|
(module+ test
|
|
(require rackunit)
|
|
(check-equal? (normalize-color "#6699Cc") '(0.4 0.6 0.8))
|
|
(check-false (normalize-color "#88aaCCC"))
|
|
(check-equal? (normalize-color "#69C") '(0.4 0.6 0.8))
|
|
(check-equal? (normalize-color "#69c") '(0.4 0.6 0.8))
|
|
(check-false (normalize-color "#8aCC"))
|
|
(check-equal? (normalize-color "aqua") '(0 1 1))) |