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.
typesetting/pitfall/pitfall/document.rkt

112 lines
3.7 KiB
Racket

6 years ago
#lang debug racket/base
(require
6 years ago
"core.rkt"
racket/class
racket/format
6 years ago
racket/dict
racket/list
sugar/unstable/dict
"reference.rkt"
"object.rkt"
"page.rkt"
"vector.rkt"
"color.rkt"
"fonts.rkt"
"text.rkt"
"images.rkt"
"annotations.rkt")
8 years ago
(provide PDFDocument)
6 years ago
(define PDFDocument
6 years ago
(class (annotation-mixin (image-mixin (text-mixin (fonts-mixin (vector-mixin (color-mixin object%))))))
(set-current-ref-id! 1)
6 years ago
(register-ref-listener (λ (ref) (send this store-ref ref)))
6 years ago
6 years ago
(super-new)
(init-field [(@options options) (mhasheq)])
(field [@pages null]
[@refs null]
6 years ago
[@root (make-ref (mhasheq 'Type "Catalog"
'Pages (make-ref (mhasheq 'Type "Pages"))))]
6 years ago
;; initialize the metadata
[@info (mhasheq 'Producer "PITFALL"
'Creator "PITFALL"
6 years ago
'CreationDate (seconds->date (if (test-mode) 0 (current-seconds)) #f))])
6 years ago
6 years ago
;; initialize mixins
6 years ago
(inherit-field @ctm) ; from vector mixin
(inherit-field @font-families) (inherit font) ; from font mixin
6 years ago
(inherit-field [@x x] [@y y])
6 years ago
;; initialize params
(current-compress-streams? (hash-ref @options 'compress #t))
(current-auto-first-page (hash-ref @options 'autoFirstPage #t))
6 years ago
(when (current-auto-first-page) (add-page))
6 years ago
(when (current-auto-helvetica) (font "Helvetica"))
6 years ago
6 years ago
;; copy options
(for ([(key val) (in-hash (hash-ref @options 'info (hasheq)))])
6 years ago
(hash-set! @info key val))
6 years ago
6 years ago
(define/public (store-ref ref)
6 years ago
(set! @refs (cons ref @refs)))
6 years ago
6 years ago
(define/public (page) (first @pages))
6 years ago
6 years ago
(define/public (add-page [options-arg @options])
6 years ago
;; create a page object
6 years ago
(define page-parent (dict-ref @root 'Pages))
(set! @pages (cons (make-object PDFPage page-parent options-arg) @pages))
6 years ago
6 years ago
;; reset x and y coordinates
6 years ago
(set! @x (margin-left (get-field margins (page))))
(set! @y (margin-right (get-field margins (page))))
6 years ago
;; flip PDF coordinate system so that the origin is in
;; the top left rather than the bottom left
6 years ago
(set! @ctm default-ctm-value)
6 years ago
(send this transform 1 0 0 -1 0 (get-field height (page)))
this)
(define/public (addContent data)
(send (page) write data)
this)
6 years ago
(define/public (end)
6 years ago
(write-bytes-out (format "%PDF-~a" (current-pdf-version)))
(write-bytes-out "%ÿÿÿÿ")
6 years ago
6 years ago
(for ([page (in-list @pages)])
6 years ago
(send page end))
6 years ago
6 years ago
(define doc-info (make-ref))
6 years ago
(for ([(key val) (in-hash @info)])
6 years ago
(dict-set! doc-info key (if (string? val) (String val) val)))
6 years ago
(send doc-info end)
6 years ago
6 years ago
(for ([font (in-hash-values @font-families)])
6 years ago
(send font end))
6 years ago
6 years ago
(send* (dict-ref @root 'Pages)
6 years ago
[set-key! 'Count (length @pages)]
[set-key! 'Kids (map (λ (page) (get-field dictionary page)) (reverse @pages))]
[end])
(send @root end)
6 years ago
(define xref-offset (file-position (current-output-port)))
(write-bytes-out "xref")
(write-bytes-out (format "0 ~a" (add1 (length @refs))))
(write-bytes-out "0000000000 65535 f ")
(for ([ref (in-list (reverse @refs))])
6 years ago
(write-bytes-out
(string-append (~r (get-field offset ref) #:min-width 10 #:pad-string "0") " 00000 n ")))
6 years ago
(write-bytes-out "trailer")
(write-bytes-out (convert (mhasheq 'Size (add1 (length @refs))
'Root @root
'Info doc-info)))
(write-bytes-out "startxref")
(write-bytes-out (numberizer xref-offset))
(write-bytes-out "%%EOF"))))
6 years ago
(module+ test
(define d (new PDFDocument)))