#lang racket/base (require racket/match racket/port racket/dict racket/struct) (provide (all-defined-out)) ;; structs (define verbose-pitfall-printing? (make-parameter #f)) (struct pdf (pages refs root info opacity-registry current-fill-color ctm ctm-stack font-families current-font-features current-font-size current-font registered-fonts font-count line-gap x y image-registry output-path) #:transparent #:mutable #:methods gen:custom-write [(define write-proc (make-constructor-style-printer (λ (obj) 'pitfall-pdf) (λ (obj) (append (list (pdf-output-path obj)) (if (verbose-pitfall-printing?) (list 'other-pdf-fields) null)))))]) (struct pdf-font (name id ascender descender underline-position underline-thickness line-gap bbox ref embedded embed encode measure-string) #:transparent #:mutable #:methods gen:custom-write [(define write-proc (make-constructor-style-printer (λ (obj) 'pitfall-font) (λ (obj) (append (list (pdf-font-name obj)) (if (verbose-pitfall-printing?) (list 'other-pdf-font-fields) null)))))]) ;; for JPEG and PNG (struct $img (data label width height ref embed-proc) #:transparent #:mutable) ;; for reference (struct $ref (id payload offset port) #:transparent #:mutable #:methods gen:dict [(define (dict-ref ref key [thunk (λ () (error 'dict-ref-key-not-found))]) (hash-ref ($ref-payload ref) key)) (define (dict-ref! ref key thunk) (hash-ref! ($ref-payload ref) key thunk)) (define (dict-set! ref key val) (hash-set! ($ref-payload ref) key val)) (define (dict-update! ref key updater [failure-result (λ () (error 'update-no-key))]) (hash-update! ($ref-payload ref) key updater failure-result))]) ;; params (define test-mode (make-parameter #f)) (define current-compress-streams (make-parameter #f)) (define current-pdf-version (make-parameter 1.3)) (define current-auto-first-page (make-parameter #t)) (define current-auto-helvetica (make-parameter #t)) (define current-font (make-parameter #f)) (define current-font-size (make-parameter 12)) ;; helpers (define (round-js-style n) ;; always round up on 0.5 ;; contra racket, which rounds toward even on 0.5 (let* ([n (* n 1e6)] [r (round n)]) (/ (if (= .5 (- n r)) (add1 r) r) 1e6))) (define (numberizer x #:round [round? #true]) (unless (and (number? x) (< -1e21 x 1e21)) (raise-argument-error 'number "valid number" x)) (let ([x (if round? (round-js-style x) x)]) (number->string (if (integer? x) (inexact->exact x) x)))) (define (to-bytes x) (match x [(? bytes?) x] [(? input-port?) (port->bytes x)] [_ (string->bytes/latin-1 (string-append x "\n"))])) (define (write-bytes-out x) (void (write-bytes (to-bytes x)))) (define (bounded low x high) (if (high . < . low) (bounded high x low) (max low (min high x)))) (module+ test (require rackunit) (check-equal? (bounded 0 2 1) 1) (check-equal? (bounded 1 2 0) 1) (check-equal? (bounded 0 -2 1) 0) (check-equal? (bounded 1 -2 0) 0) (check-equal? (bounded 0 .5 1) 0.5) (check-equal? (bounded 0 0 1) 0) (check-equal? (bounded 0 1 1) 1))