Skip to content

Commit

Permalink
Merge branch 'Nathanaela-Fix_PDF_Object_Output'
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Mar 20, 2015
2 parents a797c1a + 22a9bfd commit fa5e6c2
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 57 deletions.
2 changes: 1 addition & 1 deletion lib/document.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class PDFDocument extends stream.Readable
@_info = @ref()
for key, val of @info
if typeof val is 'string'
val = PDFObject.s val, true
val = new String val

@_info.data[key] = val

Expand Down
20 changes: 9 additions & 11 deletions lib/mixins/annotations.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
PDFObject = require '../object'

module.exports =
annotate: (x, y, w, h, options) ->
options.Type = 'Annot'
Expand All @@ -9,7 +7,7 @@ module.exports =
delete options.color

if typeof options.Dest is 'string'
options.Dest = PDFObject.s options.Dest
options.Dest = new String options.Dest

# Capitalize keys
for key, val of options
Expand All @@ -22,7 +20,7 @@ module.exports =

note: (x, y, w, h, contents, options = {}) ->
options.Subtype = 'Text'
options.Contents = PDFObject.s contents, true
options.Contents = new String contents
options.Name = 'Comment'
options.color ?= [243, 223, 92]
@annotate x, y, w, h, options
Expand All @@ -31,15 +29,15 @@ module.exports =
options.Subtype = 'Link'
options.A = @ref
S: 'URI'
URI: PDFObject.s url
URI: new String url

options.A.end()
@annotate x, y, w, h, options

_markup: (x, y, w, h, options = {}) ->
[x1, y1, x2, y2] = @_convertRect x, y, w, h
options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1]
options.Contents = PDFObject.s ''
options.Contents = new String
@annotate x, y, w, h, options

highlight: (x, y, w, h, options = {}) ->
Expand All @@ -57,24 +55,24 @@ module.exports =

lineAnnotation: (x1, y1, x2, y2, options = {}) ->
options.Subtype = 'Line'
options.Contents = PDFObject.s ''
options.Contents = new String
options.L = [x1, @page.height - y1, x2, @page.height - y2]
@annotate x1, y1, x2, y2, options

rectAnnotation: (x, y, w, h, options = {}) ->
options.Subtype = 'Square'
options.Contents = PDFObject.s ''
options.Contents = new String
@annotate x, y, w, h, options

ellipseAnnotation: (x, y, w, h, options = {}) ->
options.Subtype = 'Circle'
options.Contents = PDFObject.s ''
options.Contents = new String
@annotate x, y, w, h, options

textAnnotation: (x, y, w, h, text, options = {}) ->
options.Subtype = 'FreeText'
options.Contents = PDFObject.s text, true
options.DA = PDFObject.s ''
options.Contents = new String text
options.DA = new String
@annotate x, y, w, h, options

_convertRect: (x1, y1, w, h) ->
Expand Down
107 changes: 62 additions & 45 deletions lib/object.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,75 @@ By Devon Govett
class PDFObject
pad = (str, length) ->
(Array(length + 1).join('0') + str).slice(-length)

escapableRe = /[\n\r\t\b\f\(\)\\]/g
escapable =
'\n': '\\n'
'\r': '\\r'
'\t': '\\t'
'\b': '\\b'
'\f': '\\f'
'\\': '\\\\'
'(': '\\('
')': '\\)'

# Convert little endian UTF-16 to big endian
swapBytes = (buff) ->
l = buff.length
if l & 0x01
throw new Error("Buffer length must be even")
else
for i in [0...l - 1] by 2
a = buff[i]
buff[i] = buff[i + 1]
buff[i+1] = a

return buff

@convert: (object) ->
if Array.isArray object
items = (PDFObject.convert e for e in object).join(' ')
'[' + items + ']'

else if typeof object is 'string'
# String literals are converted to the PDF name type
if typeof object is 'string'
'/' + object

else if object?.isString
'(' + object + ')'

# String objects are converted to PDF strings (UTF-16)
else if object instanceof String
# Escape characters as required by the spec
string = object.replace escapableRe, (c) ->
return escapable[c]

# Detect if this is a unicode string
isUnicode = false
for i in [0...string.length] by 1
if string.charCodeAt(i) > 0x7f
isUnicode = true
break

# If so, encode it as big endian UTF-16
if isUnicode
string = swapBytes(new Buffer('\ufeff' + string, 'utf16le')).toString('binary')

'(' + string + ')'

# Buffers are converted to PDF hex strings
else if Buffer.isBuffer(object)
'<' + object.toString('hex') + '>'

else if object instanceof PDFReference
object.toString()

else if object instanceof Date
'(D:' + pad(object.getUTCFullYear(), 4) +
pad(object.getUTCMonth(), 2) +
pad(object.getUTCDate(), 2) +
pad(object.getUTCHours(), 2) +
pad(object.getUTCMinutes(), 2) +
pad(object.getUTCSeconds(), 2) +
'(D:' + pad(object.getUTCFullYear(), 4) +
pad(object.getUTCMonth(), 2) +
pad(object.getUTCDate(), 2) +
pad(object.getUTCHours(), 2) +
pad(object.getUTCMinutes(), 2) +
pad(object.getUTCSeconds(), 2) +
'Z)'

else if Array.isArray object
items = (PDFObject.convert e for e in object).join(' ')
'[' + items + ']'

else if {}.toString.call(object) is '[object Object]'
out = ['<<']
for key, val of object
Expand All @@ -40,34 +85,6 @@ class PDFObject

else
'' + object

# Convert Big-endian UCS-2 to Little-endian to support most PDFRreaders
swapBytes = (buff) ->
l = buff.length
if l & 0x01
throw new Error("Buffer length must be even")
else
for i in [0...l - 1] by 2
a = buff[i]
buff[i] = buff[i+1]
buff[i+1] = a
return buff

@s: (string, swap = false) ->
string = string.replace(/\\/g, '\\\\\\\\')
.replace(/\(/g, '\\(')
.replace(/\)/g, '\\)')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')

if swap
string = swapBytes(new Buffer('\ufeff' + string, 'ucs-2')).toString('binary')

return {
isString: yes
toString: -> string
}


module.exports = PDFObject
PDFReference = require './reference'
PDFReference = require './reference'

0 comments on commit fa5e6c2

Please sign in to comment.