|
|
|
@ -51,11 +51,10 @@
|
|
|
|
|
addContent
|
|
|
|
|
_refEnd
|
|
|
|
|
pipe
|
|
|
|
|
end
|
|
|
|
|
_finalize)
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
(for ([(key val) (in-hash (hash-ref options 'info (hash)))]) ; if no 'info key, nothing will be copied from (hash)
|
|
|
|
|
(hash-set! info key val))
|
|
|
|
|
(hash-set! info key val))
|
|
|
|
|
|
|
|
|
|
;; Write the header
|
|
|
|
|
(_write this (format "%PDF-~a" version)) ; PDF version
|
|
|
|
@ -77,8 +76,8 @@
|
|
|
|
|
(set-field! page this (make-object PDFPage this options-arg))
|
|
|
|
|
(push-end-field! _pageBuffer this (· this page))
|
|
|
|
|
;; add the page to the object store
|
|
|
|
|
(define pages (· this _root data Pages data))
|
|
|
|
|
(hash-update! pages 'Kids (curry cons (· this page dictionary)) null)
|
|
|
|
|
(define pages (· this _root payload Pages payload))
|
|
|
|
|
(hash-update! pages 'Kids (curry cons (· this page dictionary)))
|
|
|
|
|
(hash-update! pages 'Count add1)
|
|
|
|
|
|
|
|
|
|
;; reset x and y coordinates
|
|
|
|
@ -100,22 +99,23 @@
|
|
|
|
|
(define pages (· this _pageBuffer))
|
|
|
|
|
(set-field! _pageBuffer this empty)
|
|
|
|
|
(increment-field! _pageBufferStart this (length pages))
|
|
|
|
|
(·map end pages))
|
|
|
|
|
(for/list ([p (in-list pages)])
|
|
|
|
|
(· p end)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; every js function argument is 'undefined' by default
|
|
|
|
|
;; so even a function defined without default values
|
|
|
|
|
;; can be called without arguments
|
|
|
|
|
(define/contract (ref this [data (mhash)])
|
|
|
|
|
(define/contract (ref this [payload (mhash)])
|
|
|
|
|
(() (hash?) . ->*m . (is-a?/c PDFReference))
|
|
|
|
|
(define newref (make-object PDFReference this (add1 (length (· this _offsets))) data))
|
|
|
|
|
(define newref (make-object PDFReference this (add1 (length (· this _offsets))) payload))
|
|
|
|
|
(push-end-field! _offsets this #f) ; placeholder for this object's offset once it is finalized
|
|
|
|
|
(increment-field! _waiting this)
|
|
|
|
|
newref)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define/contract (push this chunk)
|
|
|
|
|
(any/c . ->m . void?)
|
|
|
|
|
(isBuffer? . ->m . void?)
|
|
|
|
|
(push-field! byte-strings this chunk))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -138,9 +138,9 @@
|
|
|
|
|
(define/contract (_refEnd this ref)
|
|
|
|
|
((is-a?/c PDFReference) . ->m . void?)
|
|
|
|
|
(set-field! _offsets this (for/list ([(offset idx) (in-indexed (· this _offsets))])
|
|
|
|
|
(if (= (· ref id) (add1 idx))
|
|
|
|
|
(· ref offset)
|
|
|
|
|
offset)))
|
|
|
|
|
(if (= (· ref id) (add1 idx))
|
|
|
|
|
(· ref offset)
|
|
|
|
|
offset)))
|
|
|
|
|
(increment-field! _waiting this -1)
|
|
|
|
|
(if (and (zero? (· this _waiting)) (· this _ended))
|
|
|
|
|
(· this _finalize)
|
|
|
|
@ -157,52 +157,48 @@
|
|
|
|
|
(flushPages this)
|
|
|
|
|
(set-field! _info this (ref this))
|
|
|
|
|
(for ([(key val) (in-hash (· this info))])
|
|
|
|
|
;; upgrade string literal to String struct
|
|
|
|
|
(hash-set! (· this _info data) key (if (string? val) (String val) val)))
|
|
|
|
|
;; upgrade string literal to String struct
|
|
|
|
|
(hash-set! (· this _info payload) key (if (string? val) (String val) val)))
|
|
|
|
|
(· this _info end)
|
|
|
|
|
|
|
|
|
|
(for ([font (in-hash-values (· this _fontFamilies))])
|
|
|
|
|
(· font finalize))
|
|
|
|
|
(· font finalize))
|
|
|
|
|
|
|
|
|
|
(· this _root end)
|
|
|
|
|
(· this _root data Pages end)
|
|
|
|
|
|
|
|
|
|
(if (zero? (· this _waiting))
|
|
|
|
|
(· this _finalize)
|
|
|
|
|
(set-field! _ended this #t))
|
|
|
|
|
|
|
|
|
|
(· this _root payload Pages end)
|
|
|
|
|
|
|
|
|
|
(cond
|
|
|
|
|
[(positive? (· this _waiting)) (set-field! _ended this #t)]
|
|
|
|
|
[else
|
|
|
|
|
;; generate xref
|
|
|
|
|
(define xref-offset (· this _offset))
|
|
|
|
|
(with-method ([this-write (this _write)])
|
|
|
|
|
(define this-offsets (· this _offsets))
|
|
|
|
|
(this-write "xref")
|
|
|
|
|
(this-write (format "0 ~a" (add1 (length this-offsets))))
|
|
|
|
|
(this-write "0000000000 65535 f ")
|
|
|
|
|
(for ([offset (in-list this-offsets)])
|
|
|
|
|
(this-write @string-append{@(~r offset #:min-width 10 #:pad-string "0") 00000 n }))
|
|
|
|
|
(this-write "trailer") ;; trailer
|
|
|
|
|
(this-write (convert
|
|
|
|
|
(mhash 'Size (add1 (length this-offsets))
|
|
|
|
|
'Root (· this _root)
|
|
|
|
|
'Info (· this _info))))
|
|
|
|
|
(this-write "startxref")
|
|
|
|
|
(this-write (number xref-offset))
|
|
|
|
|
(this-write "%%EOF"))
|
|
|
|
|
|
|
|
|
|
;; end the stream
|
|
|
|
|
;; in node you (@push null) which signals to the stream
|
|
|
|
|
;; to copy to its output port
|
|
|
|
|
;; here we'll do it manually
|
|
|
|
|
(define this-op (· this op))
|
|
|
|
|
(copy-port (open-input-bytes
|
|
|
|
|
(apply bytes-append (reverse (· this byte-strings)))) this-op)
|
|
|
|
|
(close-output-port this-op)])
|
|
|
|
|
#t)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define/contract (_finalize this [fn #f])
|
|
|
|
|
(() ((or/c procedure? #f)) . ->*m . void?)
|
|
|
|
|
;; generate xref
|
|
|
|
|
(define xref-offset (· this _offset))
|
|
|
|
|
(with-method ([this-write (this _write)])
|
|
|
|
|
(define this-offsets (· this _offsets))
|
|
|
|
|
(this-write "xref")
|
|
|
|
|
(this-write (format "0 ~a" (add1 (length this-offsets))))
|
|
|
|
|
(this-write "0000000000 65535 f ")
|
|
|
|
|
(for ([offset (in-list this-offsets)])
|
|
|
|
|
(this-write (string-append
|
|
|
|
|
(~r offset #:min-width 10 #:pad-string "0")
|
|
|
|
|
" 00000 n ")))
|
|
|
|
|
(this-write "trailer") ;; trailer
|
|
|
|
|
(this-write (convert
|
|
|
|
|
(mhash 'Size (add1 (length this-offsets))
|
|
|
|
|
'Root (· this _root)
|
|
|
|
|
'Info (· this _info))))
|
|
|
|
|
(this-write "startxref")
|
|
|
|
|
(this-write (number xref-offset))
|
|
|
|
|
(this-write "%%EOF"))
|
|
|
|
|
|
|
|
|
|
;; end the stream
|
|
|
|
|
;; in node you (@push null) which signals to the stream
|
|
|
|
|
;; to copy to its output port
|
|
|
|
|
;; here we'll do it manually
|
|
|
|
|
(define this-op (· this op))
|
|
|
|
|
(copy-port (open-input-bytes (apply bytes-append (reverse (· this byte-strings)))) this-op)
|
|
|
|
|
(close-output-port this-op))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|