Comparing version 0.3.1 to 0.4.0
@@ -12,4 +12,4 @@ module.exports = function(op) { | ||
Operation.prototype.render = function(page, width) { | ||
Operation.prototype.render = function(page) { | ||
page.contents.writeLine(this.op) | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = function(opts, definition) { | ||
@@ -8,3 +10,3 @@ var table = new Table(this, opts, definition) | ||
var utils = require('../utils') | ||
var defaults = { | ||
@@ -27,11 +29,11 @@ size: 12, | ||
} | ||
this.doc = doc.doc || doc | ||
this.opts = opts || {} | ||
mergeOption(defaults, this.opts) | ||
this.rows = [] | ||
this._beforeBreak = this._afterBreak = null | ||
if (definition) definition.call(this, this) | ||
@@ -55,4 +57,4 @@ } | ||
Table.prototype.render = function(page, width) { | ||
var columns = [], self = this | ||
, maxWidth = minWidth = width | ||
var columns = [] | ||
var maxWidth = width, minWidth = width | ||
@@ -64,3 +66,3 @@ if (Array.isArray(this.opts.width)) { | ||
widths.forEach(function(width, i) { | ||
if (!!~width.toString().indexOf('%')) | ||
if (width.toString().indexOf('%') > -1) | ||
return | ||
@@ -72,3 +74,3 @@ absolute += (columns[i] = parseFloat(width)) | ||
widths.forEach(function(width, i) { | ||
if (!!~width.toString().indexOf('%')) { | ||
if (width.toString().indexOf('%') > -1) { | ||
columns[i] = utils.resolveWidth(width, remaining) | ||
@@ -88,8 +90,8 @@ } | ||
})) | ||
if (highestRowWidth > maxWidth) { | ||
var widthPerCell = maxWidth / columns.length | ||
, toShrink = [] | ||
, unused = 0 | ||
var toShrink = [] | ||
var unused = 0 | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
@@ -99,3 +101,3 @@ if (columns[i] < widthPerCell) unused += widthPerCell - columns[i] | ||
} | ||
widthPerCell += unused / toShrink.length | ||
@@ -106,8 +108,8 @@ toShrink.forEach(function(i) { | ||
} | ||
if (minWidth && highestRowWidth < minWidth) { | ||
var widthPerCell = minWidth / columns.length | ||
, toExtend = [] | ||
, used = 0 | ||
var toExtend = [] | ||
var used = 0 | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
@@ -117,3 +119,3 @@ if (columns[i] < widthPerCell) toExtend.push(i) | ||
} | ||
var add = (minWidth - used) / toExtend.length | ||
@@ -125,10 +127,19 @@ toExtend.forEach(function(i) { | ||
} | ||
var left = page.cursor.x, transactions = [] | ||
for (var i = 0; i < this.rows.length; ++i) { | ||
var y = page.cursor.y | ||
, row = this.rows[i] | ||
var transaction = transactions[i] = this.doc.startTransaction() | ||
var row = this.rows[i] | ||
var transaction | ||
if (this.opts.header && i === 1) { | ||
// if headers are enabled, use the one transaction for the header and | ||
// first row | ||
transaction = transactions[0] | ||
} else { | ||
transaction = this.doc.startTransaction() | ||
} | ||
transactions[i] = transaction | ||
var height = row.render(page, columns, { table: { row: i }, doc: this.doc }) | ||
@@ -141,5 +152,11 @@ | ||
transaction.rollback() | ||
row.allowBreak = pagebreak = true | ||
row.allowBreak = true | ||
--i | ||
// if headers enabled and we've reverted the first row, we have reverted | ||
// the header row, too, i.e., render the header row again | ||
if (this.opts.header && i === 0) { | ||
--i | ||
} | ||
// before break | ||
@@ -178,3 +195,3 @@ if (this._beforeBreak) { | ||
// header | ||
if (this.opts.header === true) { | ||
if (this.opts.header === true && i > 0) { | ||
page.cursor.x = left | ||
@@ -197,11 +214,11 @@ height += this.rows[0].render(page, columns, context) | ||
} | ||
this.table = table | ||
this.doc = table.doc | ||
this.opts = mergeOption(table.opts, opts || {}) | ||
this.cells = [] | ||
this.allowBreak = false | ||
if (definition) definition.call(this, this) | ||
@@ -237,12 +254,16 @@ } | ||
Row.prototype.render = function(page, columns, context) { | ||
var left = page.cursor.x | ||
, y = page.cursor.y | ||
, heights = [] | ||
, borders = [] | ||
, pagebreak = false | ||
, column = 0 | ||
var y = page.cursor.y | ||
var heights = [] | ||
var borders = [] | ||
var column = 0 | ||
function addBorder(x, y, width) { | ||
borders.push(function(height) { | ||
cell.drawBorder(page, x, y, width, height) | ||
}) | ||
} | ||
for (var i = 0, len = this.cells.length; i < len; ++i) { | ||
var cell = this.cells[i] | ||
var width = columns[column++] | ||
@@ -255,12 +276,8 @@ if (cell.opts.colspan > 1) { | ||
} | ||
!function(x, y, width) { | ||
borders.push(function(height) { | ||
cell.drawBorder(page, x, y, width, height) | ||
}) | ||
}(page.cursor.x, page.cursor.y, width) | ||
addBorder(page.cursor.x, page.cursor.y, width) | ||
var paddingLeft = cell.borderLeftWidth + cell.opts.padding.left | ||
, paddingRight = cell.opts.padding.right + cell.borderRightWidth | ||
, innerWidth = width - paddingLeft - paddingRight | ||
var paddingRight = cell.opts.padding.right + cell.borderRightWidth | ||
var innerWidth = width - paddingLeft - paddingRight | ||
page.cursor.x += paddingLeft | ||
@@ -279,3 +296,3 @@ page.cursor.y -= cell.borderTopWidth + cell.opts.padding.top // padding top | ||
page.cursor.x += innerWidth + paddingRight | ||
if (this.doc.cursor !== page && !this.allowBreak) { | ||
@@ -290,16 +307,15 @@ return false | ||
}) | ||
return height | ||
} | ||
var Text = require('./text').Text | ||
, Fragment = require('../fragment') | ||
var Fragment = require('../fragment') | ||
var Cell = function(row, text, opts) { | ||
if (!opts) opts = {} | ||
this.row = row | ||
this.doc = row.doc | ||
this.opts = mergeOption(row.opts, opts) | ||
if (text instanceof Fragment) { | ||
@@ -316,6 +332,6 @@ this.content = text | ||
} | ||
this.innerWidth = this.content.maxWidth | ||
this.innerHeight = this.content.minHeight | ||
this.isFirstColumn = this.row.cells.length === 0 | ||
@@ -349,4 +365,4 @@ this.isLastColumn = true | ||
} | ||
var border | ||
@@ -365,7 +381,7 @@ // border bottom | ||
} | ||
var downTo = y - height | ||
if (downTo < this.doc.padding.bottom) | ||
downTo = this.doc.padding.bottom | ||
// border right | ||
@@ -377,3 +393,3 @@ if (this.borderRightWidth > 0) { | ||
} | ||
// border left | ||
@@ -406,3 +422,3 @@ if (this.borderLeftWidth > 0) { | ||
}) | ||
Object.defineProperties(Cell.prototype, { | ||
@@ -473,3 +489,3 @@ borderTopWidth: { | ||
into[key] = mergeOption(from[key], val) | ||
} | ||
} | ||
} | ||
@@ -490,3 +506,3 @@ return into | ||
} else { | ||
return { top: option, right: option, bottom: option, left: option } | ||
return { top: option, right: option, bottom: option, left: option } | ||
} | ||
@@ -500,2 +516,2 @@ } | ||
page.contents.writeLine('') | ||
} | ||
} |
@@ -0,3 +1,5 @@ | ||
'use strict' | ||
var PDFString = require('../objects/string') | ||
, utils = require('../utils') | ||
var utils = require('../utils') | ||
@@ -7,3 +9,3 @@ module.exports = function(string, opts) { | ||
if (typeof string === 'function') | ||
string.call(text, text.textFn) | ||
string.call(text, text.textFn) | ||
else | ||
@@ -47,3 +49,3 @@ text.text(string) | ||
Text.prototype.text.br = function() { | ||
this.contents.push(new Word('\n', this.opts.font ? this.doc.registerFont(opts.font) : this.doc.defaultFont.regular, { | ||
this.contents.push(new Word('\n', this.opts.font ? this.doc.registerFont(this.opts.font) : this.doc.defaultFont.regular, { | ||
size: this.opts.size | ||
@@ -56,3 +58,3 @@ })) | ||
this.text(function() { | ||
if (!this.pages && !this.doc) return | ||
if (!this.pages && !this.doc) return null | ||
return (this.pages || this.doc.pages).count | ||
@@ -65,8 +67,6 @@ }) | ||
var self = this | ||
, spaceLeft = width | ||
, finishedAt = this.contents.length - 1 | ||
, line = [] | ||
, self = this | ||
, lastFont, lastSize | ||
var spaceLeft = width | ||
var line = [] | ||
var lastFont, lastSize | ||
function renderLine(line, textWidth, isLastLine) { | ||
@@ -76,3 +76,3 @@ var lineHeight = Math.max.apply(Math, line.map(function(word) { | ||
})) | ||
// only a line break | ||
@@ -83,6 +83,7 @@ if (line.length === 1 && line[0].word === '\n') { | ||
} | ||
var left = page.cursor.x | ||
// page break | ||
if (round(page.spaceLeft) < round(lineHeight)) { | ||
var left = page.cursor.x | ||
page = self.doc.pagebreak() | ||
@@ -92,40 +93,43 @@ page.cursor.x = left | ||
} | ||
page.cursor.y -= lineHeight | ||
var spaceLeft = width - textWidth | ||
, left = page.cursor.x | ||
, wordCount = line.length | ||
, toPrint = '' | ||
var remainingSpace = width - textWidth | ||
var wordCount = line.length | ||
var wordSpacing | ||
// begin text | ||
page.contents.writeLine('BT') | ||
// alignement | ||
switch (self.opts.align) { | ||
case 'right': | ||
left += spaceLeft | ||
left += remainingSpace | ||
break | ||
case 'center': | ||
left += width / 2 - (width - spaceLeft) / 2 | ||
left += width / 2 - (width - remainingSpace) / 2 | ||
break | ||
case 'justify': | ||
if (isLastLine && 100 * spaceLeft / width > 20) break | ||
var wordSpacing = spaceLeft / (wordCount - 1) | ||
// set word spacing | ||
page.contents.writeLine(wordSpacing + ' Tw') | ||
if (isLastLine && 100 * remainingSpace / width > 20) break | ||
wordSpacing = remainingSpace / (wordCount - 1) | ||
break | ||
} | ||
// position the text in user space | ||
page.contents.writeLine(left + ' ' + page.cursor.y + ' Td') | ||
page.contents.writeLine('1 0 0 1 ' + left + ' ' + page.cursor.y + ' Tm') | ||
var offset = 0 | ||
line.forEach(function(word, i) { | ||
if (word.word === '\n') return | ||
var str = (i > 0 && !word.isStartingWithPunctuation ? ' ' : '') + word.font.encode(word.word) | ||
, size = word.opts.size || 10 | ||
// move cursor manually for word spacing, since Tw does not work for | ||
// multi byte fonts | ||
if (wordSpacing) { | ||
page.contents.writeLine(offset + ' 0 Td') | ||
} | ||
var str = word.font.encode(word.word) | ||
var size = word.opts.size || 10 | ||
if (lastFont !== word.font || lastSize !== size) { | ||
if (toPrint.length) { | ||
page.contents.writeLine((new PDFString(toPrint)).toHexString() + ' Tj') | ||
toPrint = '' | ||
} | ||
page.contents.writeLine([word.font.id, size, 'Tf'].join(' ')) | ||
@@ -135,18 +139,20 @@ lastFont = word.font | ||
} | ||
toPrint += str | ||
offset = word.width + word.spacing + (wordSpacing || 0) | ||
if (i > 0 && !word.isStartingWithPunctuation && !wordSpacing) { | ||
str = ' ' + str | ||
} | ||
page.contents.writeLine((new PDFString(str)).toHexString() + ' Tj') | ||
}) | ||
if (toPrint.length) { | ||
page.contents.writeLine((new PDFString(toPrint)).toHexString() + ' Tj') | ||
toPrint = '' | ||
} | ||
page.contents.writeLine('ET') | ||
page.cursor.y -= lineHeight * ((self.opts.lineSpacing || 1) - 1) | ||
} | ||
this.contents.forEach(function(word, i) { | ||
this.contents.forEach(function(word) { | ||
word.context = context || (self.doc.doc || self.doc) | ||
var wordWidth = word.width, wordSpacing = !line.length || word.isStartingWithPunctuation ? 0 : word.spacing | ||
if (word.word === '\n' || (line.length > 0 && spaceLeft - (wordWidth + wordSpacing) < 0)) { | ||
@@ -160,7 +166,7 @@ wordSpacing = 0 | ||
} | ||
spaceLeft -= wordWidth + wordSpacing | ||
line.push(word) | ||
}) | ||
if (line.length) { | ||
@@ -239,3 +245,3 @@ renderLine(line, width - spaceLeft, true) | ||
} | ||
return this._word | ||
@@ -259,2 +265,2 @@ } | ||
return Math.round(num * 100) / 100 | ||
} | ||
} |
@@ -0,14 +1,14 @@ | ||
'use strict' | ||
var PDFObject = require('./objects/object') | ||
, Pages = require('./pages') | ||
, Font = require('./font') | ||
, TTFFont = require('./fonts/ttf') | ||
, PDFName = require('./objects/name') | ||
, utils = require('./utils') | ||
var Pages = require('./pages') | ||
var Font = require('./font') | ||
var utils = require('./utils') | ||
var Document = module.exports = function Document(font, opts) { | ||
this.version = 1.7 | ||
this.version = 1.3 | ||
// list of all objects in this document | ||
this.objects = [] | ||
// list of all fonts in this document | ||
@@ -18,3 +18,3 @@ this.fonts = [] | ||
this.defaultFont = this.registerFont(font) | ||
// call parents constructor | ||
@@ -25,3 +25,3 @@ if (!opts) opts = {} | ||
this.height = this.opts.height || 792 | ||
// the catalog and pages tree | ||
@@ -31,3 +31,3 @@ this.catalog = this.createObject('Catalog') | ||
this.catalog.prop('Pages', this.pages.toReference()) | ||
this.areas = { header: null, footer: null } | ||
@@ -37,7 +37,8 @@ } | ||
var Fragment = require('./fragment') | ||
utils.inherits(Document, Fragment); | ||
utils.inherits(Document, Fragment) | ||
Document.Font = Font | ||
;['header', 'footer'].forEach(function(area) { | ||
var areas = ['header', 'footer'] | ||
areas.forEach(function(area) { | ||
Document.prototype[area] = function(opts, definition) { | ||
@@ -90,4 +91,4 @@ if (typeof opts !== 'object') { | ||
var footer = this.areas.footer | ||
, transaction = this.startTransaction() | ||
, y = page.cursor.y | ||
var transaction = this.startTransaction() | ||
var y = page.cursor.y | ||
footer.height = 0 | ||
@@ -106,8 +107,8 @@ footer.render(page, this.width) | ||
Document.prototype.toDataURL = function() { | ||
return 'data:application/pdf;base64,' + Base64.encode(this.toString()) | ||
return 'data:application/pdfbase64,' + Base64.encode(this.toString()) | ||
} | ||
var PDFDictionary = require('./objects/dictionary') | ||
, PDFArray = require('./objects/array') | ||
, PDFString = require('./objects/string') | ||
var PDFArray = require('./objects/array') | ||
var PDFString = require('./objects/string') | ||
@@ -117,3 +118,3 @@ Document.prototype.toString = function() { | ||
this.objects = [this.catalog, this.pages.tree] | ||
this.pagebreak() | ||
@@ -124,8 +125,8 @@ this.render(this.cursor) | ||
}) | ||
var buf = '', xref = [], startxref | ||
// header | ||
buf += '%PDF-' + this.version.toString() + '\n' | ||
// The PDF format mandates that we add at least 4 commented binary characters | ||
@@ -141,3 +142,3 @@ // (ASCII value >= 128), so that generic tools have a chance to detect | ||
}) | ||
// body | ||
@@ -148,3 +149,3 @@ this.objects.forEach(function(object) { | ||
}) | ||
// to support random access to individual objects, a PDF file | ||
@@ -158,8 +159,8 @@ // contains a cross-reference table that can be used to locate | ||
xref.forEach(function(ref) { | ||
buf += '0000000000'.substr(ref.toString().length) + ref + ' 00000 n \n' | ||
buf += '0000000000'.substr(ref.toString().length) + ref + ' 00000 n \n' | ||
}) | ||
// trailer | ||
var id = (new PDFString(uuid4())).toHexString() | ||
, trailer = new PDFDictionary({ | ||
var trailer = new PDFDictionary({ | ||
Size: (this.objects.length + 1), | ||
@@ -174,3 +175,3 @@ Root: this.catalog.toReference(), | ||
buf += '%%EOF' | ||
return buf | ||
@@ -196,5 +197,5 @@ } | ||
if (this.length < this.doc.cursor.contents.content.length) { | ||
this.doc.cursor.contents.content = this.doc.cursor.contents.content.slice(0, this.length) | ||
this.doc.cursor.contents.slice(0, this.length) | ||
} | ||
this.doc.cursor.cursor.y = this.y | ||
@@ -214,26 +215,26 @@ } | ||
// private property | ||
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", | ||
_keyStr : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', | ||
// public method for encoding | ||
encode : function (input) { | ||
var output = ""; | ||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4; | ||
var i = 0; | ||
var output = '' | ||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4 | ||
var i = 0 | ||
input = Base64._utf8_encode(input); | ||
input = Base64._utf8Encode(input) | ||
while (i < input.length) { | ||
chr1 = input.charCodeAt(i++); | ||
chr2 = input.charCodeAt(i++); | ||
chr3 = input.charCodeAt(i++); | ||
chr1 = input.charCodeAt(i++) | ||
chr2 = input.charCodeAt(i++) | ||
chr3 = input.charCodeAt(i++) | ||
enc1 = chr1 >> 2; | ||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); | ||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); | ||
enc4 = chr3 & 63; | ||
enc1 = chr1 >> 2 | ||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4) | ||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6) | ||
enc4 = chr3 & 63 | ||
if (isNaN(chr2)) { | ||
enc3 = enc4 = 64; | ||
enc3 = enc4 = 64 | ||
} else if (isNaN(chr3)) { | ||
enc4 = 64; | ||
enc4 = 64 | ||
} | ||
@@ -243,36 +244,35 @@ | ||
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + | ||
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); | ||
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4) | ||
} | ||
return output; | ||
return output | ||
}, | ||
// private method for UTF-8 encoding | ||
_utf8_encode : function (string) { | ||
string = string.replace(/\r\n/g,"\n"); | ||
var utftext = ""; | ||
_utf8Encode : function (string) { | ||
string = string.replace(/\r\n/g,'\n') | ||
var utftext = '' | ||
for (var n = 0; n < string.length; n++) { | ||
var c = string.charCodeAt(n); | ||
var c = string.charCodeAt(n) | ||
// workaround to not encode UTF8 characters | ||
// TODO: improve ... | ||
utftext += String.fromCharCode(Math.min(c, 0xff)) | ||
continue | ||
if (c < 128) { | ||
utftext += String.fromCharCode(c); | ||
} | ||
else if((c > 127) && (c < 2048)) { | ||
utftext += String.fromCharCode((c >> 6) | 192); | ||
utftext += String.fromCharCode((c & 63) | 128); | ||
} | ||
else { | ||
utftext += String.fromCharCode((c >> 12) | 224); | ||
utftext += String.fromCharCode(((c >> 6) & 63) | 128); | ||
utftext += String.fromCharCode((c & 63) | 128); | ||
} | ||
// if (c < 128) { | ||
// utftext += String.fromCharCode(c) | ||
// } | ||
// else if((c > 127) && (c < 2048)) { | ||
// utftext += String.fromCharCode((c >> 6) | 192) | ||
// utftext += String.fromCharCode((c & 63) | 128) | ||
// } | ||
// else { | ||
// utftext += String.fromCharCode((c >> 12) | 224) | ||
// utftext += String.fromCharCode(((c >> 6) & 63) | 128) | ||
// utftext += String.fromCharCode((c & 63) | 128) | ||
// } | ||
} | ||
return utftext; | ||
return utftext | ||
} | ||
@@ -291,3 +291,3 @@ } | ||
* 16 // a random number from | ||
>> a/4 // 8 to 11 | ||
>> a / 4 // 8 to 11 | ||
).toString(16) // in hexadecimal | ||
@@ -304,2 +304,2 @@ : ( // or otherwise a concatenated string: | ||
) | ||
} | ||
} |
@@ -0,4 +1,5 @@ | ||
'use strict' | ||
var TTFFont = require('./fonts/ttf') | ||
, PDFName = require('./objects/name') | ||
, fs = require('fs') | ||
var PDFName = require('./objects/name') | ||
@@ -13,4 +14,10 @@ var TYPES = ['regular', 'italic', 'bold', 'boldItalic', 'light', 'lightItalic'] | ||
if (type in opts) { | ||
if (!(opts[type] instanceof ArrayBuffer) && !(opts[type] instanceof Buffer)) | ||
// GLOBAL[('Buffer').toString()] is used instead of Buffer to trick browserify | ||
// to not load a Buffer polyfill just for instance testing. The `toString()` part | ||
// is used to trick eslint to not throw | ||
var isArrayBuffer = opts[type] instanceof ArrayBuffer | ||
var isBuffer = typeof GLOBAL !== 'undefined' && opts[type] instanceof GLOBAL[('Buffer').toString()] | ||
if (!isArrayBuffer && !isBuffer) { | ||
throw new Error('Property `' + type + '` must be a Buffer or a Arraybuffer.') | ||
} | ||
self[type] = new TTFFont(opts[type]) | ||
@@ -60,3 +67,2 @@ self.subsets[type] = self[type].subset() | ||
function typeFromOpts(opts) { | ||
var subtype | ||
if (opts.bold === true) { | ||
@@ -76,2 +82,2 @@ if (opts.italic === true) return 'boldItalic' | ||
} | ||
} | ||
} |
@@ -0,5 +1,9 @@ | ||
'use strict' | ||
var TTFFont = module.exports = require('ttfjs') | ||
var PDFArray = require('../objects/array') | ||
, PDFStream = require('../objects/stream') | ||
var PDFArray = require('../objects/array') | ||
var PDFStream = require('../objects/stream') | ||
var PDFDictionary = require('../objects/dictionary') | ||
var PDFString = require('../objects/string') | ||
@@ -9,22 +13,36 @@ var embed = TTFFont.Subset.prototype.embed | ||
embed.call(this) | ||
var font = this.object | ||
font.prop('Subtype', 'TrueType') | ||
font.prop('Subtype', 'Type0') | ||
font.prop('BaseFont', this.font.fontName) | ||
font.prop('Encoding', 'MacRomanEncoding') | ||
font.prop('Encoding', 'Identity-H') | ||
doc.objects.push(font) | ||
var descendant = doc.createObject('Font') | ||
descendant.prop('Subtype', 'CIDFontType2') | ||
descendant.prop('BaseFont', this.font.fontName) | ||
descendant.prop('DW', 1000) | ||
descendant.prop('CIDToGIDMap', 'Identity') | ||
descendant.prop('CIDSystemInfo', new PDFDictionary({ | ||
'Ordering': new PDFString('Identity'), | ||
'Registry': new PDFString('Adobe'), | ||
'Supplement': 0 | ||
})) | ||
font.prop('DescendantFonts', new PDFArray([ | ||
descendant.toReference() | ||
])) | ||
// widths array | ||
var widths = doc.createObject(), metrics = [], codeMap = this.cmap() | ||
var metrics = [], codeMap = this.cmap() | ||
for (var code in codeMap) { | ||
if (code < 32) continue | ||
var gid = codeMap[code] | ||
metrics.push(Math.round(this.font.tables.hmtx.metrics[gid] * this.font.scaleFactor)) | ||
var width = Math.round(this.font.tables.hmtx.metrics[gid] * this.font.scaleFactor) | ||
metrics.push(code - 31) | ||
metrics.push(new PDFArray([width])) | ||
} | ||
widths.content = new PDFArray(metrics) | ||
font.prop('Widths', widths.toReference()) | ||
font.prop('FirstChar', 32) | ||
font.prop('LastChar', metrics.length > (222) ? 225 : metrics.length + 33 - 1) | ||
descendant.prop('W', new PDFArray(metrics)) | ||
// font descriptor | ||
@@ -40,4 +58,4 @@ var descriptor = doc.createObject('FontDescriptor') | ||
descriptor.prop('StemV', this.font.stemV) | ||
font.prop('FontDescriptor', descriptor.toReference()) | ||
descendant.prop('FontDescriptor', descriptor.toReference()) | ||
// unicode map | ||
@@ -50,13 +68,13 @@ var cmap = new PDFStream(doc.createObject()) | ||
cmap.writeLine(' /Registry (Adobe)') | ||
cmap.writeLine(' /Ordering (UCS)') | ||
cmap.writeLine(' /Ordering (Identity)') | ||
cmap.writeLine(' /Supplement 0') | ||
cmap.writeLine('>> def') | ||
cmap.writeLine('/CMapName /Adobe-Identity-UCS def') | ||
cmap.writeLine('/CMapName /Identity-H') | ||
cmap.writeLine('/CMapType 2 def') | ||
cmap.writeLine('1 begincodespacerange') | ||
cmap.writeLine('<00><ff>') | ||
cmap.writeLine('<0000><ffff>') | ||
cmap.writeLine('endcodespacerange') | ||
var codeMap = this.subset, lines = [] | ||
for (var code in codeMap) { | ||
var mapping = this.subset, lines = [] | ||
for (code in mapping) { | ||
if (lines.length >= 100) { | ||
@@ -70,7 +88,9 @@ cmap.writeLine(lines.length + ' beginbfchar') | ||
} | ||
var unicode = ('0000' + codeMap[code].toString(16)).slice(-4) | ||
, code = (+code).toString(16) | ||
lines.push('<' + code + '><' + unicode + '>') | ||
lines.push( | ||
'<' + ('0000' + (+code - 31).toString(16)).slice(-4) + '>' + // cid | ||
'<' + ('0000' + mapping[code].toString(16)).slice(-4) + '>' // gid | ||
) | ||
} | ||
if (lines.length) { | ||
@@ -83,3 +103,3 @@ cmap.writeLine(lines.length + ' beginbfchar') | ||
} | ||
cmap.writeLine('endcmap') | ||
@@ -89,9 +109,9 @@ cmap.writeLine('CMapName currentdict /CMap defineresource pop') | ||
cmap.writeLine('end') | ||
font.prop('ToUnicode', cmap.toReference()) | ||
// font file | ||
var data = this.save() | ||
, hex = asHex(data) | ||
var hex = asHex(data) | ||
var file = new PDFStream(doc.createObject()) | ||
@@ -117,4 +137,4 @@ file.object.prop('Length', hex.length + 1) | ||
function toHex(n) { | ||
if (n < 16) return '0' + n.toString(16); | ||
return n.toString(16); | ||
if (n < 16) return '0' + n.toString(16) | ||
return n.toString(16) | ||
} | ||
@@ -121,0 +141,0 @@ |
var Fragment = module.exports = function(doc, opts) { | ||
this.opts = opts || {} | ||
this.doc = doc | ||
this.width = this.opts.width || 612 | ||
if (!this.opts.padding) this.opts.padding = { top: 0, right: 0, bottom: 0, left: 0 } | ||
this.padding = new Padding(this) | ||
this.defaultFont = this.doc.defaultFont | ||
this.areas = {} | ||
@@ -32,3 +32,3 @@ this.contents = [] | ||
// <------- width ----------> | ||
// __________________________ | ||
// __________________________ | ||
// | ______________________ | ^ | ||
@@ -90,3 +90,3 @@ // | | ^ | | | | ||
if (width) width = width - this.padding.right - this.padding.left | ||
if ('top' in this.opts && ((this.doc.height - this.opts.top) < page.cursor.y || this.opts.position === 'force')) { | ||
@@ -102,3 +102,3 @@ page.cursor.y = this.doc.height - this.opts.top | ||
} | ||
page.cursor.x = x | ||
@@ -126,8 +126,8 @@ } | ||
} | ||
var fragment = new Fragment(this.doc, opts) | ||
definition.call(fragment, fragment) | ||
this.contents.push(fragment) | ||
return this | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
var PDFArray = module.exports = function(array) { | ||
module.exports = function(array) { | ||
if (!array) array = [] | ||
@@ -11,4 +11,4 @@ | ||
} | ||
return array | ||
} |
@@ -31,2 +31,2 @@ var PDFName = require('./name') | ||
enumerable: true | ||
}) | ||
}) |
var PDFName = module.exports = function(name) { | ||
if (!name) throw new Error('A Name cannot be undefined') | ||
if (name instanceof PDFName) return name | ||
// white-space characters are not allowed | ||
if (name.match(/[\x00]/)) | ||
throw new Error('A Name mustn\'t contain the null characters') | ||
// delimiter characters are not allowed | ||
@@ -26,3 +26,3 @@ if (name.match(/[\(\)<>\[\]\{\}\/\%]/)) | ||
}) | ||
this.name = name | ||
@@ -33,2 +33,2 @@ } | ||
return '/' + this.name | ||
} | ||
} |
@@ -6,3 +6,3 @@ // > Objects may be labeled so that they can be referred to by other objects. | ||
var PDFReference = require('./reference') | ||
, PDFDictionary = require('./dictionary') | ||
var PDFDictionary = require('./dictionary') | ||
@@ -26,4 +26,2 @@ var PDFObject = module.exports = function(id, rev) { | ||
PDFObject.prototype.toString = function() { | ||
var self = this | ||
return this.id.toString() + ' ' + this.rev + ' obj\n' + | ||
@@ -33,2 +31,2 @@ (this.properties.length ? this.properties.toString() + '\n' : '') + | ||
'endobj' | ||
} | ||
} |
@@ -7,2 +7,2 @@ var PDFReference = module.exports = function(object) { | ||
return this.object.id + ' ' + this.object.rev + ' R' | ||
} | ||
} |
// page 60 | ||
// Filters: page 65 | ||
var PDFObject = require('./name') | ||
var PDFStream = module.exports = function(object) { | ||
@@ -12,2 +10,7 @@ object.content = this | ||
PDFStream.prototype.slice = function(begin, end) { | ||
this.content = this.content.slice(begin, end) | ||
this.object.prop('Length', this.content.length - 1) | ||
} | ||
PDFStream.prototype.writeLine = function(str) { | ||
@@ -26,3 +29,3 @@ this.content += str + '\n' | ||
'endstream' | ||
} | ||
} |
@@ -16,3 +16,4 @@ var PDFString = module.exports = function(str) { | ||
for (var i = 0, len = self.str.length; i < len; ++i) { | ||
results.push(self.str.charCodeAt(i).toString(16)) | ||
var hex = (self.str.charCodeAt(i) - 31).toString(16) | ||
results.push(('0000' + hex).slice(-4)) | ||
} | ||
@@ -25,2 +26,2 @@ return results | ||
return this.toLiteralString() | ||
} | ||
} |
var PDFStream = require('./objects/stream') | ||
, PDFDictionary = require('./objects/dictionary') | ||
, PDFArray = require('./objects/array') | ||
, PDFName = require('./objects/name') | ||
var PDFDictionary = require('./objects/dictionary') | ||
var PDFArray = require('./objects/array') | ||
var PDFName = require('./objects/name') | ||
@@ -12,3 +12,3 @@ var Page = module.exports = function(doc, parent) { | ||
this.pageNumber = 1 | ||
this.cursor = { | ||
@@ -18,3 +18,3 @@ y: this.doc.height - this.doc.opts.padding.top, | ||
} | ||
this.object.addProperty('Parent', parent.toReference()) | ||
@@ -39,2 +39,2 @@ this.object.addProperty('Contents', this.contents.toReference()) | ||
return this.object.toReference() | ||
} | ||
} |
var PDFArray = require('./objects/array') | ||
, Page = require('./page') | ||
var Page = require('./page') | ||
@@ -27,7 +27,7 @@ var Pages = module.exports = function(doc) { | ||
this.tree.addProperty('Count', this.count) | ||
this.doc.subsets.forEach(function(subset) { | ||
subset.addTo(page) | ||
}) | ||
return page | ||
@@ -44,2 +44,2 @@ } | ||
return this.tree.toReference() | ||
} | ||
} |
@@ -10,3 +10,3 @@ exports.extend = function(destination, source) { | ||
exports.inherits = function(ctor, superCtor) { | ||
ctor.super_ = superCtor; | ||
ctor.super_ = superCtor | ||
ctor.prototype = Object.create(superCtor.prototype, { | ||
@@ -27,2 +27,2 @@ constructor: { value: ctor, enumerable: false } | ||
} | ||
} | ||
} |
@@ -7,4 +7,5 @@ { | ||
}, | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/rkusa/pdfjs", | ||
"description": "A Portable Document Format (PDF) generation library targeting both the server- and client-side.", | ||
"keywords": ["pdf", "generator"], | ||
@@ -15,2 +16,3 @@ "license": "MIT", | ||
"test": "mocha", | ||
"prepublish": "npm run-script bundle", | ||
"bundle": "browserify lib/document.js --standalone Pdfjs --detect-globals false > pdfjs.js && npm run-script minify", | ||
@@ -17,0 +19,0 @@ "minify": "uglifyjs --source-map pdfjs.min.map -o pdfjs.min.js pdfjs.js" |
# pdfjs | ||
A Portable Document Format (PDF) generation library targeting both the server- and client-side. | ||
```json | ||
{ "name": "pdfjs", | ||
"version": "0.3.1" } | ||
``` | ||
[![NPM][npm]](https://npmjs.org/package/pdfjs) | ||
[![Dependency Status][deps]](https://david-dm.org/rkusa/pdfjs) | ||
#### Status | ||
#### Features | ||
Early development stage, i.e., not well tested. | ||
- Text (+ formatting) | ||
- Tables | ||
- Header & Footer | ||
- Automatic page breaks | ||
- Font embedding (as CID font, i.e., does supports many characters) | ||
**Implemented:** Text, Tables, Header, Footer, Automatic page breaks | ||
**Missing:** AFM Fonts, Graphics | ||
#### Missing Features | ||
AFM fonts and graphics are currently not implemented. If you are missing a feature, feel free to ask or to submit a PR. | ||
#### Contents | ||
@@ -114,3 +118,3 @@ | ||
* **borderWidth** - | ||
* **borderWidth** - | ||
* **width** - total width (absolute or relative) or an array of column widths | ||
@@ -227,3 +231,3 @@ * + [Text Options](#texttext-opts) | ||
* **borderWidth** - | ||
* **borderWidth** - | ||
* + [Text Options](#texttext-opts) | ||
@@ -292,4 +296,4 @@ | ||
* **borderWidth** - | ||
* **colspan** - | ||
* **borderWidth** - | ||
* **colspan** - | ||
* + [Text Options](#texttext-opts) | ||
@@ -308,4 +312,4 @@ | ||
* **borderWidth** - | ||
* **colspan** - | ||
* **borderWidth** - | ||
* **colspan** - | ||
* + [Text Options](#texttext-opts) | ||
@@ -320,11 +324,11 @@ | ||
* **normal** - | ||
* **italic** - | ||
* **bold** - | ||
* **boldItalic** - | ||
* **light** - | ||
* **lightItalic** - | ||
* **normal** - | ||
* **italic** - | ||
* **bold** - | ||
* **boldItalic** - | ||
* **light** - | ||
* **lightItalic** - | ||
## MIT License | ||
Copyright (c) 2013 Markus Ast | ||
Copyright (c) 2013-2014 Markus Ast | ||
@@ -335,2 +339,5 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
[npm]: http://img.shields.io/npm/v/pdfjs.svg?style=flat | ||
[deps]: http://img.shields.io/gemnasium/rkusa/pdfjs.svg?style=flat |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
296265
25
4465
337
6