#lang debug racket/base (require "core.rkt" racket/match racket/class racket/list "reference.rkt" "font-standard.rkt" "font-embedded.rkt") (provide (all-defined-out)) (define (make-font-ref f) (or (pdf-font-ref f) (and (set-pdf-font-ref! f (make-ref)) (pdf-font-ref f)))) (define (embed f) (define embed-proc (pdf-font-embed f)) (embed-proc f)) (define (encode f str [options #f]) (define encode-proc (pdf-font-encode f)) (encode-proc f str options)) (define (measure-string f str size [options #f]) (define measure-proc (pdf-font-measure-string f)) (measure-proc f str size options)) (define (font-end f) (unless (or (pdf-font-embedded f) (not (pdf-font-ref f))) (embed f) (set-pdf-font-embedded! f #t))) (define (line-height f size [include-gap #f]) (define gap (if include-gap (pdf-font-line-gap f) 0)) (* (/ (+ (pdf-font-ascender f) gap (- (pdf-font-descender f))) #;(pdf-font-upm f) 1000.0) size)) (define (open-pdf-font name id) ((if (standard-font-name? name) make-standard-font make-embedded-font) name id)) (define (current-line-height doc [include-gap #f]) (line-height (pdf-current-font doc) (pdf-current-font-size doc) include-gap)) (define (font doc src [size #f]) ;; check registered fonts if src is a string (define cache-key (match src [(? string?) #:when (hash-has-key? (pdf-registered-fonts doc) src) (define ck src) (set! src (hash-ref (hash-ref (pdf-registered-fonts doc) ck) 'src)) ck] [(? string?) src] [_ #false])) (when size (font-size doc size)) (match (hash-ref (pdf-font-families doc) cache-key #f) ; check if the font is already in the PDF [(? values val) (set-pdf-current-font! doc val)] [_ ; if not, load the font (define font-index (add1 (pdf-font-count doc))) (set-pdf-font-count! doc font-index) (define id (string->symbol (format "F~a" font-index))) (set-pdf-current-font! doc (open-pdf-font src id)) ;; check for existing font families with the same name already in the PDF (match (hash-ref (pdf-font-families doc) (pdf-font-name (pdf-current-font doc)) #f) [(? values font) (set-pdf-current-font! doc font)] [_ ;; save the font for reuse later (when cache-key (hash-set! (pdf-font-families doc) cache-key (pdf-current-font doc))) (hash-set! (pdf-font-families doc) (pdf-font-name (pdf-current-font doc)) (pdf-current-font doc))])]) doc) (define (font-size doc size) (unless (and (number? size) (not (negative? size))) (raise-argument-error 'font-size "non-negative number" size)) (set-pdf-current-font-size! doc size) doc) (define (net-features feats) ;; filter out pairs of features with opposing (0 and 1) values (let loop ([feats (remove-duplicates feats)] [acc null]) (cond [(empty? feats) acc] [(empty? (cdr feats)) (loop empty (cons (car feats) acc))] [else (define first-feat (car feats)) (match (cdr feats) [(list head ... (? (λ (f) (bytes=? (car f) (car first-feat)))) tail ...) (loop (append head tail) acc)] [rest (loop rest (cons first-feat acc))])]))) (define (font-features doc [features-on null] [features-off null]) (unless (and (list? features-on) (andmap bytes? features-on)) (raise-argument-error 'font-features "list of feature byte strings" features-on)) (unless (and (list? features-off) (andmap bytes? features-off)) (raise-argument-error 'font-features "list of feature byte strings" 'features-off)) (define (make-feat-pairs feats val) (for/list ([f (in-list feats)]) (match f [(cons (? bytes?) (? exact-nonnegative-integer?)) f] [(? bytes?) (cons f val)] [else (raise-argument-error 'font-features "byte string or byte string + integer pair" f)]))) (define new-features (append (make-feat-pairs features-on 1) (make-feat-pairs features-off 0))) (set-pdf-current-font-features! doc (net-features (append (pdf-current-font-features doc) new-features))) doc) (define (register-font doc name src) (hash-set! (pdf-registered-fonts doc) name (make-hasheq (list (cons 'src src)))) doc)