|
|
|
#lang typed/racket/base
|
|
|
|
(require typed/racket/class racket/file racket/list)
|
|
|
|
(require/typed racket/draw
|
|
|
|
[current-ps-setup (Parameterof (Instance (Class (init-field)
|
|
|
|
[set-margin (Number Number . -> . Void)]
|
|
|
|
[set-scaling (Number Number . -> . Void)])))]
|
|
|
|
[the-color-database (Instance (Class
|
|
|
|
(find-color (String . -> . (Option (Instance (Class)))))))]
|
|
|
|
[pdf-dc% (Class (init [interactive Boolean][use-paper-bbox Boolean][as-eps Boolean]
|
|
|
|
[output Output-Port]
|
|
|
|
[width Float][height Float])
|
|
|
|
(start-doc (String . -> . Void))
|
|
|
|
(set-pen (String Real Symbol . -> . Void))
|
|
|
|
(set-brush (String Symbol . -> . Void))
|
|
|
|
(set-font ((Instance (Class)) . -> . Void))
|
|
|
|
(set-text-foreground ((Instance (Class)) . -> . Void))
|
|
|
|
(set-text-background ((Instance (Class)) . -> . Void))
|
|
|
|
(set-text-mode (Symbol . -> . Void))
|
|
|
|
(draw-text (String Float Float Boolean . -> . Void))
|
|
|
|
(start-page (-> Void))
|
|
|
|
(end-page (-> Void))
|
|
|
|
(end-doc (-> Void)))]
|
|
|
|
[make-font ((#:size Nonnegative-Float) (#:style Symbol) (#:weight Symbol) (#:face String) . -> . (Instance (Class (init-field))))])
|
|
|
|
(require/typed sugar/cache [make-caching-proc ((String Nonnegative-Float Symbol Symbol -> (Instance (Class))) . -> . (String Nonnegative-Float Symbol Symbol -> (Instance (Class))))])
|
|
|
|
(require "utils-typed.rkt" "quads-typed.rkt" "world-typed.rkt")
|
|
|
|
|
|
|
|
(define abstract-renderer%
|
|
|
|
|
|
|
|
(class object%
|
|
|
|
(super-new)
|
|
|
|
|
|
|
|
(define renderable-quads '(word box))
|
|
|
|
|
|
|
|
;; hash implementation
|
|
|
|
(: render (Quad . -> . Any))
|
|
|
|
(define/public (render doc-quad)
|
|
|
|
(finalize
|
|
|
|
(let ([rendering-input (flatten-quad (setup doc-quad))])
|
|
|
|
(define page-quad-hash ((inst make-hash Nonnegative-Integer (Listof Quad))))
|
|
|
|
(for ([q (in-list rendering-input)])
|
|
|
|
(when (member (quad-name q) renderable-quads)
|
|
|
|
((inst hash-update! Nonnegative-Integer (Listof Quad)) page-quad-hash (cast (quad-attr-ref q world:page-key) Nonnegative-Integer) (λ(v) ((inst cons Quad (Listof Quad)) q v)) (λ() (cast null (Listof Quad))))))
|
|
|
|
(map (λ([k : Nonnegative-Integer]) (render-page ((inst hash-ref Nonnegative-Integer (Listof Quad) (Listof Quad)) page-quad-hash k))) (sort (hash-keys page-quad-hash) <)))))
|
|
|
|
|
|
|
|
(: render-element (Quad . -> . Any))
|
|
|
|
(define/public (render-element q)
|
|
|
|
(cond
|
|
|
|
[(word? q) (render-word q)]
|
|
|
|
[else q]))
|
|
|
|
|
|
|
|
(: setup (Quad . -> . Quad))
|
|
|
|
(define/public (setup q) q)
|
|
|
|
|
|
|
|
;; use in lieu of 'abstract' definition
|
|
|
|
(: render-page ((Listof Quad) . -> . Void))
|
|
|
|
(define/public (render-page qs) (void))
|
|
|
|
|
|
|
|
;; use in lieu of 'abstract' definition
|
|
|
|
(: render-word (Quad . -> . Any))
|
|
|
|
(define/public (render-word x) (word))
|
|
|
|
|
|
|
|
(: finalize (Any . -> . Any))
|
|
|
|
(define/public (finalize x) x)))
|
|
|
|
|
|
|
|
(define-syntax-rule (map/send method xs)
|
|
|
|
(map (λ([x : Quad]) (method x)) xs))
|
|
|
|
|
|
|
|
;; this is outside class def'n because if inside,
|
|
|
|
;; (define dc ...) can't see it and type it correctly.
|
|
|
|
;; there may be a better way, but for now this is OK
|
|
|
|
(: dc-output-port Output-Port)
|
|
|
|
(define dc-output-port (open-output-bytes))
|
|
|
|
|
|
|
|
|
|
|
|
(provide pdf-renderer%)
|
|
|
|
(define pdf-renderer%
|
|
|
|
(class abstract-renderer%
|
|
|
|
(super-new)
|
|
|
|
|
|
|
|
(send* (current-ps-setup) (set-margin 0 0) (set-scaling 1.0 1.0))
|
|
|
|
|
|
|
|
(define dc (new pdf-dc% [interactive #f][use-paper-bbox #f][as-eps #f]
|
|
|
|
[output dc-output-port]
|
|
|
|
[width (world:paper-width-default)][height (world:paper-height-default)]))
|
|
|
|
|
|
|
|
|
|
|
|
(define/override (setup tx)
|
|
|
|
(send* dc
|
|
|
|
(start-doc "boing")
|
|
|
|
(set-pen "black" 1 'solid)
|
|
|
|
(set-brush "black" 'transparent)) ; no fill by default
|
|
|
|
tx)
|
|
|
|
|
|
|
|
(inherit render-element)
|
|
|
|
|
|
|
|
|
|
|
|
(define font-cache ((inst make-hash (List String Nonnegative-Flonum Symbol Symbol) (Instance (Class (init-field)))) '()))
|
|
|
|
(: get-cached-font (String Nonnegative-Flonum Symbol Symbol . -> . (Instance (Class (init-field)))))
|
|
|
|
(define (get-cached-font font size style weight)
|
|
|
|
(hash-ref! font-cache (list font size style weight) (λ () (make-font #:face font #:size size #:style style #:weight weight))))
|
|
|
|
|
|
|
|
|
|
|
|
(define/override (render-word w)
|
|
|
|
(define word-font (cast (quad-attr-ref/parameter w world:font-name-key) String))
|
|
|
|
(define word-size (cast (quad-attr-ref/parameter w world:font-size-key) Nonnegative-Float))
|
|
|
|
(define word-style (cast (quad-attr-ref/parameter w world:font-style-key) Symbol))
|
|
|
|
(define word-weight (cast (quad-attr-ref/parameter w world:font-weight-key) Symbol))
|
|
|
|
(define word-color (cast (quad-attr-ref/parameter w world:font-color-key) String))
|
|
|
|
(define word-background (cast (quad-attr-ref/parameter w world:font-background-key) String))
|
|
|
|
(send dc set-font (get-cached-font word-font word-size word-style word-weight))
|
|
|
|
(define foreground-color (send the-color-database find-color word-color))
|
|
|
|
(when foreground-color
|
|
|
|
(send dc set-text-foreground foreground-color))
|
|
|
|
(define background-color (send the-color-database find-color word-background))
|
|
|
|
(if background-color ; all invalid color-string values will return #f
|
|
|
|
(send* dc (set-text-mode 'solid) (set-text-background background-color))
|
|
|
|
(send dc set-text-mode 'transparent))
|
|
|
|
|
|
|
|
(define word-text (cast (quad-car w) String))
|
|
|
|
(send dc draw-text word-text (cast (quad-attr-ref w world:x-position-key) Float)
|
|
|
|
;; we want to align by baseline rather than top of box
|
|
|
|
;; thus, subtract ascent from y to put baseline at the y coordinate
|
|
|
|
(- (cast (quad-attr-ref w world:y-position-key) Float) (cast (quad-attr-ref w world:ascent-key 0) Float)) #t))
|
|
|
|
|
|
|
|
(define/override (render-page elements)
|
|
|
|
(send dc start-page)
|
|
|
|
(map/send render-element (filter-not whitespace/nbsp? elements))
|
|
|
|
(send dc end-page))
|
|
|
|
|
|
|
|
(define/override (finalize xs)
|
|
|
|
(send dc end-doc)
|
|
|
|
(get-output-bytes dc-output-port))
|
|
|
|
|
|
|
|
(: render-to-file (Quad Path-String . -> . Void))
|
|
|
|
(define/public (render-to-file doc-quad path)
|
|
|
|
(define result-bytes (send this render doc-quad))
|
|
|
|
(display-to-file result-bytes path #:exists 'replace #:mode 'binary))
|
|
|
|
|
|
|
|
|
|
|
|
))
|