mirror of
https://github.com/foliojs/pdfkit.git
synced 2025-12-08 20:15:54 +00:00
198 lines
4.2 KiB
CoffeeScript
198 lines
4.2 KiB
CoffeeScript
###
|
|
PDFDocument - represents an entire PDF document
|
|
By Devon Govett
|
|
###
|
|
|
|
stream = require 'stream'
|
|
fs = require 'fs'
|
|
PDFObject = require './object'
|
|
PDFReference = require './reference'
|
|
PDFPage = require './page'
|
|
|
|
class PDFDocument extends stream.Readable
|
|
constructor: (@options = {}) ->
|
|
super
|
|
|
|
# PDF version
|
|
@version = 1.3
|
|
|
|
# Whether streams should be compressed
|
|
@compress = yes
|
|
|
|
# The PDF object store
|
|
@_objects = []
|
|
@_waiting = 0
|
|
@_ended = false
|
|
@_offset = 0
|
|
|
|
@_root = @ref
|
|
Type: 'Catalog'
|
|
Pages: @ref
|
|
Type: 'Pages'
|
|
Count: 0
|
|
Kids: []
|
|
|
|
# The current page
|
|
@page = null
|
|
|
|
# Initialize mixins
|
|
@initColor()
|
|
@initVector()
|
|
@initFonts()
|
|
@initText()
|
|
@initImages()
|
|
|
|
# Initialize the metadata
|
|
@info =
|
|
Producer: 'PDFKit'
|
|
Creator: 'PDFKit'
|
|
CreationDate: new Date()
|
|
|
|
if @options.info
|
|
for key, val of @options.info
|
|
@info[key] = val
|
|
|
|
# Write the header
|
|
# PDF version
|
|
@_write "%PDF-#{@version}"
|
|
|
|
# 4 binary chars, as recommended by the spec
|
|
@_write "%\xFF\xFF\xFF\xFF"
|
|
|
|
# Add the first page
|
|
@addPage()
|
|
|
|
mixin = (name) =>
|
|
methods = require './mixins/' + name
|
|
for name, method of methods
|
|
this::[name] = method
|
|
|
|
# Load mixins
|
|
mixin 'color'
|
|
mixin 'vector'
|
|
mixin 'fonts'
|
|
mixin 'text'
|
|
mixin 'images'
|
|
mixin 'annotations'
|
|
|
|
addPage: (options = @options) ->
|
|
# end the current page if needed
|
|
@page?.end()
|
|
|
|
# create a page object
|
|
@page = new PDFPage(this, options)
|
|
|
|
# add the page to the object store
|
|
pages = @_root.data.Pages.data
|
|
pages.Kids.push @page.dictionary
|
|
pages.Count++
|
|
|
|
# reset x and y coordinates
|
|
@x = @page.margins.left
|
|
@y = @page.margins.top
|
|
|
|
# flip PDF coordinate system so that the origin is in
|
|
# the top left rather than the bottom left
|
|
@_ctm = [1, 0, 0, 1, 0, 0]
|
|
@transform 1, 0, 0, -1, 0, @page.height
|
|
|
|
return this
|
|
|
|
ref: (data) ->
|
|
ref = new PDFReference(this, @_objects.length + 1, data)
|
|
@_objects.push ref
|
|
@_waiting++
|
|
return ref
|
|
|
|
_read: ->
|
|
# do nothing, but this method is required by node
|
|
|
|
_write: (data) ->
|
|
unless Buffer.isBuffer(data)
|
|
data = new Buffer(data + '\n', 'binary')
|
|
|
|
@push data
|
|
@_offset += data.length
|
|
|
|
addContent: (data) ->
|
|
@page.write data
|
|
return this
|
|
|
|
_refEnd: ->
|
|
if --@_waiting is 0 and @_ended
|
|
@_finalize()
|
|
@_ended = false
|
|
|
|
write: (filename, fn) ->
|
|
# print a deprecation warning with a stacktrace
|
|
err = new Error '
|
|
PDFDocument#write is deprecated, and will be removed in a future version of PDFKit.
|
|
Please pipe the document into a Node stream.
|
|
'
|
|
|
|
console.warn err.stack
|
|
|
|
@pipe fs.createWriteStream(filename)
|
|
@end()
|
|
@once 'end', fn
|
|
|
|
output: (fn) ->
|
|
# more difficult to support this. It would involve concatenating all the buffers together
|
|
throw new Error '
|
|
PDFDocument#output is deprecated, and has been removed from PDFKit.
|
|
Please pipe the document into a Node stream.
|
|
'
|
|
|
|
end: ->
|
|
@page.end()
|
|
|
|
@_info = @ref()
|
|
for key, val of @info
|
|
if typeof val is 'string'
|
|
val = PDFObject.s val, true
|
|
|
|
@_info.data[key] = val
|
|
|
|
@_info.end()
|
|
|
|
for name, font of @_fontFamilies
|
|
font.embed()
|
|
|
|
@_root.end()
|
|
@_root.data.Pages.end()
|
|
|
|
if @_waiting is 0
|
|
@_finalize()
|
|
else
|
|
@_ended = true
|
|
|
|
_finalize: (fn) ->
|
|
# generate xref
|
|
xRefOffset = @_offset
|
|
@_write "xref"
|
|
@_write "0 #{@_objects.length + 1}"
|
|
@_write "0000000000 65535 f "
|
|
|
|
for ref in @_objects
|
|
offset = ('0000000000' + ref.offset).slice(-10)
|
|
@_write offset + ' 00000 n '
|
|
|
|
# trailer
|
|
@_write 'trailer'
|
|
@_write PDFObject.convert
|
|
Size: @_objects.length
|
|
Root: @_root
|
|
Info: @_info
|
|
|
|
@_write 'startxref'
|
|
@_write "#{xRefOffset}"
|
|
@_write '%%EOF'
|
|
|
|
# end the stream
|
|
@push null
|
|
|
|
toString: ->
|
|
"[object PDFDocument]"
|
|
|
|
module.exports = PDFDocument
|