Socket
Socket
Sign inDemoInstall

pdfjs

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pdfjs - npm Package Compare versions

Comparing version 2.0.0-alpha.3 to 2.0.0-alpha.4

lib/object/nametree.js

3

CHANGELOG.md
# Changelog
## 2.0.0-alpha.4
- fix combination of multiple TTF/OTF fonts in one line #81
## 2.0.0-alpha.3

@@ -5,0 +8,0 @@

26

lib/document.js

@@ -9,3 +9,2 @@ 'use strict'

const uuid = require('uuid')
const version = require('../package.json').version
const util = require('./util')

@@ -31,7 +30,3 @@ const ContentChunk = require('./content')

this.version = '1.3'
this.info = {
id: uuid.v4(),
producer: `pdfjs v${version} (github.com/rkusa/pdfjs)`,
creationDate: new Date(),
}
this.info = Object.assign({}, opts.properties, { id: uuid.v4() })
this.width = opts.width || 595.296

@@ -95,6 +90,6 @@ this.height = opts.height || 841.896

const padding = opts.padding >= 0 ? opts.padding : 20
this.paddingTop = opts.paddingTop || padding
this.paddingBottom = opts.paddingBottom || padding
this.paddingLeft = opts.paddingLeft || padding
this.paddingRight = opts.paddingRight || padding
this.paddingTop = util.defaults(opts.paddingTop, padding)
this.paddingBottom = util.defaults(opts.paddingBottom, padding)
this.paddingLeft = util.defaults(opts.paddingLeft, padding)
this.paddingRight = util.defaults(opts.paddingRight, padding)

@@ -111,2 +106,5 @@ this._cursor = new Cursor(

// init destinations name tree
this._destinations = new PDF.NameTree()
// init color space

@@ -304,3 +302,2 @@ this._colorSpace = new PDF.Object()

if (this._header) {
this._aliases.reset('H')
let chunk = ''

@@ -319,3 +316,2 @@ for (const i in this._header._objects) {

if (this._footer) {
this._aliases.reset('F')
let chunk = ''

@@ -529,2 +525,8 @@ for (const i in this._footer._objects) {

catalog.prop('Pages', this._pagesObj.toReference())
if (this._destinations.length > 0) {
const destsObj = new PDF.Object()
destsObj.prop("Dests", this._destinations)
await this._writeObject(destsObj)
catalog.prop('Names', destsObj.toReference())
}
await this._writeObject(catalog)

@@ -531,0 +533,0 @@

@@ -168,2 +168,16 @@ 'use strict'

}
destination(name) {
this._begin(null)
this._pending.push(async () => {
const DestinationRangeStyle = require('./text').DestinationRangeStyle
const self = {
destination: name,
doc: this._doc,
from: this._cursor.x,
y: this._cursor.y,
}
DestinationRangeStyle.prototype._applyStyle.call(self)
})
}
}

@@ -5,2 +5,3 @@ 'use strict'

const PDFImage = require('./pdf')
const PDF = require('../object')

@@ -84,3 +85,38 @@ module.exports = async function(img, doc, parent, opts) {

if (opts.link) {
doc._annotations.push(new PDF.Dictionary({
Type: 'Annot',
Subtype: 'Link',
Rect: new PDF.Array([x, y, x + renderWidth, y + renderHeight]),
Border: new PDF.Array([0, 0, 0]),
A: new PDF.Dictionary({
Type: 'Action',
S: 'URI',
URI: new PDF.String(opts.link),
}),
}))
}
if (opts.goTo) {
doc._annotations.push(new PDF.Dictionary({
Type: 'Annot',
Subtype: 'Link',
Rect: new PDF.Array([x, y, x + renderWidth, y + renderHeight]),
Border: new PDF.Array([0, 0, 0]),
A: new PDF.Dictionary({
S: 'GoTo',
D: new PDF.String(opts.goTo),
}),
}))
}
if (opts.destination) {
doc._destinations.set(opts.destination, new PDF.Array([
doc._currentPage.toReference(),
new PDF.Name('XYZ'),
_cursor.x,
_cursor.y + renderHeight,
null,
]))
}
await doc._write(chunk)
}

@@ -6,2 +6,3 @@ 'use strict'

exports.PDFName = exports.Name = require('./name')
exports.PDFNameTree = exports.NameTree = require('./nametree')
exports.PDFObject = exports.Object = require('./object')

@@ -8,0 +9,0 @@ exports.PDFReference = exports.Reference = require('./reference')

'use strict'
const version = require('../../package.json').version
const PDFDictionary = require('./dictionary')

@@ -7,2 +8,13 @@ const PDFArray = require('./array')

const InfoKeys = {
title: 'Title',
author: 'Author',
subject: 'Subject',
keywords: 'Keywords',
creator: 'Creator',
producer: 'Producer',
creationDate: 'CreationDate',
modDate: 'ModDate'
}
class PDFTrailer extends PDFDictionary {

@@ -17,7 +29,23 @@ constructor(size, root, info) {

this.set('ID', new PDFArray([id, id]))
// Default to now and convert to string
info.creationDate = formatDate(info.creationDate || new Date)
if (!info.producer) {
// Set default producer if not one provided
info.producer = `pdfjs v${version} (github.com/rkusa/pdfjs)`
}
if ('modDate' in info) {
// Convert to string
info.modDate = formatDate(info.modDate)
}
this.set('Info', new PDFDictionary({
Producer: new PDFString(info.producer),
CreationDate: new PDFString(formatDate(info.creationDate || new Date)),
}))
const infoDictionary = {}
for (const key in InfoKeys) {
if (key in info) {
infoDictionary[InfoKeys[key]] = new PDFString(info[key])
}
}
this.set('Info', new PDFDictionary(infoDictionary))
}

@@ -24,0 +52,0 @@

'use strict'
const Fragment = require('./fragment')
const LineBreaker = require('linebreak')
const LineBreaker = require('@rkusa/linebreak')
const unorm = require('unorm')

@@ -14,3 +14,3 @@ const ops = require('./ops')

module.exports = class Text extends Fragment {
const Text = module.exports = class Text extends Fragment {
constructor(doc, parent, opts) {

@@ -41,2 +41,4 @@ super(doc, parent)

this.link = opts.link
this.destination = opts.destination
this.goTo = opts.goTo
}

@@ -71,2 +73,4 @@

const link = opts.link || this.link
const destination = opts.destination || this.destination
const goTo = opts.goTo || this.goTo
const decoration = this.defaultDecoration | (opts.underline ? UNDERLINE_FLAG : 0) | (opts.strikethrough ? STRIKETHROUGH_FLAG : 0)

@@ -93,3 +97,3 @@

}
// when there is no break, there es an orphan word that just has to be rendered,
// when there is no break, there is an orphan word that just has to be rendered,
// i.e., skip to the line rendering

@@ -148,3 +152,9 @@ else if (bk) {

if (this._spaceLeft >= offsetWidth) {
this._line.push({ l: [wordWidth, spaceWidth], w: word.slice(0, i), f: font, s: fontSize, c: color, d: decoration })
this._line.push(
new TextChunk({
wordWidth, spaceWidth, word: word.slice(0, i),
font, fontSize, color, decoration,
link, destination, goTo
})
)
this._spaceLeft -= offsetWidth

@@ -162,3 +172,9 @@

if (!postponeLinebreak && word && (this._spaceLeft - offsetWidth) >= 0) {
this._line.push({ l: [wordWidth, spaceWidth], w: word, f: font, s: fontSize, c: color, d: decoration })
this._line.push(
new TextChunk({
wordWidth, spaceWidth, word, font, fontSize,
color, decoration,
link, destination, goTo
})
)
this._spaceLeft -= offsetWidth

@@ -176,3 +192,3 @@ word = null

for (const w of this._line) {
const h = w.f.lineHeight(w.s, true)
const h = w.font.lineHeight(w.fontSize, true)
if (h > height) {

@@ -182,3 +198,3 @@ height = h

const d = -w.f.descent(w.s)
const d = -w.font.descent(w.fontSize)
if (d > descent) {

@@ -282,71 +298,26 @@ descent = d

let underlineFrom = left
let underlineWidth = 0
const rangeStyleArgs = [this._doc, left, this._cursor.y, height, spacing]
const underlineStyle = new UnderlineRangeStyle(...rangeStyleArgs)
const strikethroughStyle = new StrikethroughRangeStyle(...rangeStyleArgs)
const linkStyle = new LinkRangeStyle(...rangeStyleArgs)
const destinationStyle = new DestinationRangeStyle(...rangeStyleArgs)
const goToStyle = new GoToRangeStyle(...rangeStyleArgs)
const drawUnderline = (fontSize) => {
const underlinePosition = this._cursor.y + font.underlinePosition(fontSize)
const chunk = ops.w(font.underlineThickness(fontSize)) // line width
+ ops.SC(this._previousColor[0], this._previousColor[1], this._previousColor[2]) // stroking color
+ ops.S(underlineFrom, underlinePosition, 'm', underlineFrom + underlineWidth, underlinePosition, 'l') // line
underlineFrom += underlineWidth
underlineWidth = 0
return chunk
}
let strikethroughFrom = left
let strikethroughWidth = 0
const drawStrikethrough = (fontSize) => {
const strikethroughPosition = this._cursor.y + font.ascent(fontSize) * .35
const chunk = ops.w(font.underlineThickness(fontSize)) // line width
+ ops.SC(this._previousColor[0], this._previousColor[1], this._previousColor[2]) // stroking color
+ ops.S(strikethroughFrom, strikethroughPosition, 'm', strikethroughFrom + strikethroughWidth, strikethroughPosition, 'l') // line
strikethroughFrom += strikethroughWidth
strikethroughWidth = 0
return chunk
}
let shouldUnderline = false
let shouldStrikethrough = false
for (const i in this._line) {
const lastIx = this._line.length - 1
for (let i = 0; i < this._line.length; ++i) {
const w = this._line[i]
const fontStyleChanged = w.f !== this._previousFont || w.s !== this._previousFontSize
const colorChanged = !util.rgbEqual(w.c, this._previousColor)
const fontStyleChanged = w.font !== this._previousFont || w.fontSize !== this._previousFontSize
const colorChanged = !util.rgbEqual(w.color, this._previousColor)
if ((!(w.d & UNDERLINE_FLAG) || fontStyleChanged || colorChanged) && shouldUnderline) {
chunk += drawUnderline(this._previousFontSize)
shouldUnderline = false
}
chunk += underlineStyle.applyStyle(w, i === lastIx, fontStyleChanged || colorChanged)
chunk += strikethroughStyle.applyStyle(w, i === lastIx, fontStyleChanged || colorChanged)
chunk += linkStyle.applyStyle(w, i === lastIx, fontStyleChanged || colorChanged)
chunk += destinationStyle.applyStyle(w, i === lastIx, fontStyleChanged || colorChanged)
chunk += goToStyle.applyStyle(w, i === lastIx, fontStyleChanged || colorChanged)
if ((w.d & UNDERLINE_FLAG) && !shouldUnderline) {
shouldUnderline = true
underlineFrom += underlineWidth
underlineWidth = 0
if (i > 0) {
underlineFrom += font.stringWidth(' ', this._previousFontSize)
underlineWidth = -font.stringWidth(' ', w.s)
}
}
if ((!(w.d & STRIKETHROUGH_FLAG) || fontStyleChanged || colorChanged) && shouldStrikethrough) {
chunk += drawStrikethrough(this._previousFontSize)
shouldStrikethrough = false
}
if ((w.d & STRIKETHROUGH_FLAG) && !shouldStrikethrough) {
shouldStrikethrough = true
strikethroughFrom += strikethroughWidth
strikethroughWidth = 0
if (i > 0) {
strikethroughFrom += font.stringWidth(' ', this._previousFontSize)
strikethroughWidth = -font.stringWidth(' ', w.s)
}
}
if (fontStyleChanged || colorChanged) {
if (out.length > 0) {
if (spacing === 0) {
chunk += ops.Tj(font.encode(out.join(' ') + ' '))
chunk += ops.Tj(this._previousFont.encode(out.join('')))
} else {

@@ -358,9 +329,9 @@ chunk += ops.TJ(out)

if (fontStyleChanged) {
this._previousFont = w.f
this._previousFontSize = w.s
this._previousFont = w.font
this._previousFontSize = w.fontSize
const alias = this._doc._fontAlias(w.f)
const alias = this._doc._fontAlias(w.font)
// set font and font size
chunk += ops.Tf(alias, w.s)
chunk += ops.Tf(alias, w.fontSize)
}

@@ -370,4 +341,4 @@

if (colorChanged) {
this._previousColor = w.c
chunk += ops.sc(...w.c)
this._previousColor = w.color
chunk += ops.sc(...w.color)
}

@@ -379,23 +350,12 @@

if (spacing === 0) {
out.push(w.w)
const isLast = i === this._line.length - 1
out.push(w.word + (!isLast && w.spaceWidth > 0 ? ' ' : ''))
} else {
out.push(font.encode(w.w), calcSpaceWidth(spacing, w.f, w.s))
out.push(w.font.encode(w.word), calcSpaceWidth(spacing, w.font, w.fontSize))
}
let shift = w.l[0] + (i > 0 ? (spacing || w.l[1]) : 0)
underlineWidth += shift
strikethroughWidth += shift
}
if (shouldUnderline) {
await this._doc._write(drawUnderline(this._previousFontSize))
}
if (shouldStrikethrough) {
await this._doc._write(drawStrikethrough(this._previousFontSize))
}
if (out.length > 0) {
if (spacing === 0) {
chunk += ops.Tj(font.encode(out.join(' ')))
chunk += ops.Tj(this._previousFont.encode(out.join('')))
} else {

@@ -408,19 +368,2 @@ chunk += ops.TJ(out)

if (link) {
// TODO: implement annotations in a more generic way
const rectWidth = this._cursor.width - freeSpace
const annot = new PDF.Dictionary({
Type: 'Annot',
Subtype: 'Link',
Rect: new PDF.Array([left, this._cursor.y, left + rectWidth, this._cursor.y + height]),
Border: new PDF.Array([0, 0, 0]),
A: new PDF.Dictionary({
Type: 'Action',
S: 'URI',
URI: new PDF.String(link),
}),
})
this._doc._annotations.push(annot)
}
this._cursor.y -= descent

@@ -439,3 +382,10 @@

if (word) {
this._line.push({ l: [wordWidth, spaceWidth], w: word, f: font, s: fontSize, c: color, d: decoration })
this._line.push(
new TextChunk({
wordWidth, spaceWidth, word, font, fontSize,
color, decoration,
link, destination, goTo
})
)
this._spaceLeft -= offsetWidth

@@ -463,6 +413,6 @@ }

this._pending.push(() => {
const word = this._line.pop()
if (word) {
text = word.w + text
this._spaceLeft += word.l
if (this._line.length > 0) {
const w = this._line[this._line.length - 1]
this._spaceLeft += w.spaceWidth
w.spaceWidth = 0 // set space width to zero
}

@@ -491,2 +441,235 @@ return this._render(text, opts || {})

return -(spacing + font.stringWidth(' ', fontSize)) * scaleFactor
}
}
class TextChunk {
constructor(values) {
this.wordWidth = values.wordWidth
this.spaceWidth = values.spaceWidth
this.word = values.word
this.font = values.font
this.fontSize = values.fontSize
this.color = values.color
this.decoration = values.decoration
this.link = values.link
this.destination = values.destination
this.goTo = values.goTo
}
}
class RangeStyle {
constructor(doc, x, y, height, spacing) {
this.doc = doc
this.from = x
this.width = 0
this.y = y
this.height = height
this.spacing = spacing
this.isActive = false
this.lastSpaceWidth = 0
}
applyStyle(textChunk, isLast, fontStyleChanged) {
const shouldApply = this._active(textChunk)
let chunk = ''
if (shouldApply && !fontStyleChanged && this.isActive) {
this.width += this.lastSpaceWidth
}
if (this.isActive && (!shouldApply || fontStyleChanged)) {
chunk += this._applyStyle(textChunk)
this.from += this.width + this.lastSpaceWidth
this.width = 0
}
if ((!this.isActive || shouldApply) || this.isActive && fontStyleChanged) {
this._start(textChunk)
}
this.isActive = shouldApply
this.lastSpaceWidth = this.spacing || textChunk.spaceWidth
if (this.isActive) {
this.width += textChunk.wordWidth
} else {
this.from += textChunk.wordWidth + this.lastSpaceWidth
}
if (this.isActive && isLast) {
chunk += this._applyStyle(textChunk)
}
return chunk
}
_active(textChunk) {
// abstract
}
_start(textChunk) {
// abstract
}
_applyStyle(textChunk) {
// abstract
}
}
class UnderlineRangeStyle extends RangeStyle {
constructor(doc, x, y, height, spacing) {
super(doc, x, y, height, spacing)
this.underlinePosition = 0
this.underlineThickness = 0
this.color = null
}
_active(textChunk) {
return textChunk.decoration & UNDERLINE_FLAG
}
_start(textChunk) {
this.underlinePosition = textChunk.font.underlinePosition(textChunk.fontSize)
this.underlineThickness = textChunk.font.underlineThickness(textChunk.fontSize)
this.color = textChunk.color
}
_applyStyle(textChunk) {
const y = this.y + this.underlinePosition
return ops.w(this.underlineThickness) // line width
+ ops.SC(...this.color) // stroking color
+ ops.S(this.from, y, 'm', this.from + this.width, y, 'l') // line
}
}
class StrikethroughRangeStyle extends RangeStyle {
constructor(doc, x, y, height, spacing) {
super(doc, x, y, height, spacing)
this.ascent = 0
this.lineThickness = 0
this.color = null
}
_active(textChunk) {
return textChunk.decoration & STRIKETHROUGH_FLAG
}
_start(textChunk) {
this.ascent = textChunk.font.ascent(textChunk.fontSize)
this.lineThickness = textChunk.font.underlineThickness(textChunk.fontSize)
this.color = textChunk.color
}
_applyStyle(textChunk) {
const y = this.y + this.ascent * .35
return ops.w(this.lineThickness) // line width
+ ops.SC(...this.color) // stroking color
+ ops.S(this.from, y, 'm', this.from + this.width, y, 'l') // line
}
}
class LinkRangeStyle extends RangeStyle {
constructor(doc, x, y, height, spacing) {
super(doc, x, y, height, spacing)
this.link = null
}
applyStyle(textChunk, isLast, fontStyleChanged) {
if (this.link && textChunk.link !== this.link) {
fontStyleChanged = true
}
return RangeStyle.prototype.applyStyle.call(this, textChunk, isLast, fontStyleChanged)
}
_active(textChunk) {
return textChunk.link !== undefined
}
_start(textChunk) {
this.link = textChunk.link
}
_applyStyle(textChunk) {
this.doc._annotations.push(new PDF.Dictionary({
Type: 'Annot',
Subtype: 'Link',
Rect: new PDF.Array([this.from, this.y, this.from + this.width, this.y + this.height]),
Border: new PDF.Array([0, 0, 0]),
A: new PDF.Dictionary({
Type: 'Action',
S: 'URI',
URI: new PDF.String(this.link),
}),
}))
return ''
}
}
class DestinationRangeStyle extends RangeStyle {
constructor(doc, x, y, height, spacing) {
super(doc, x, y, height, spacing)
this.destination = null
}
applyStyle(textChunk, isLast, fontStyleChanged) {
if (this.destination && textChunk.destination !== this.destination) {
fontStyleChanged = true
}
return RangeStyle.prototype.applyStyle.call(this, textChunk, isLast, fontStyleChanged)
}
_active(textChunk) {
return textChunk.destination !== undefined
}
_start(textChunk) {
this.destination = textChunk.destination
}
_applyStyle(textChunk) {
this.doc._destinations.set(this.destination, new PDF.Array([
this.doc._currentPage.toReference(),
new PDF.Name('XYZ'),
this.from,
this.y,
null,
]))
return ''
}
}
class GoToRangeStyle extends RangeStyle {
constructor(doc, x, y, height, spacing) {
super(doc, x, y, height, spacing)
this.goTo = null
}
applyStyle(textChunk, isLast, fontStyleChanged) {
if (this.goTo && textChunk.goTo !== this.goTo) {
fontStyleChanged = true
}
return RangeStyle.prototype.applyStyle.call(this, textChunk, isLast, fontStyleChanged)
}
_active(textChunk) {
return textChunk.goTo !== undefined
}
_start(textChunk) {
this.goTo = textChunk.goTo
}
_applyStyle(textChunk) {
this.doc._annotations.push(new PDF.Dictionary({
Type: 'Annot',
Subtype: 'Link',
Rect: new PDF.Array([this.from, this.y, this.from + this.width, this.y + this.height]),
Border: new PDF.Array([0, 0, 0]),
A: new PDF.Dictionary({
S: 'GoTo',
D: new PDF.String(this.goTo),
}),
}))
return ''
}
}
Text.DestinationRangeStyle = DestinationRangeStyle

@@ -32,1 +32,5 @@ 'use strict'

}
exports.defaults = function(val, def) {
return val !== undefined ? val : def
}
{
"name": "pdfjs",
"author": "Markus Ast <npm.m@rkusa.st>",
"version": "2.0.0-alpha.3",
"version": "2.0.0-alpha.4",
"description": "A Portable Document Format (PDF) generation library targeting both the server- and client-side.",

@@ -15,7 +15,8 @@ "keywords": [

"scripts": {
"test": "node --harmony-async-await test/index.js test/pdfs/**/*.js"
"test": "node test/index.js test/pdfs/**/*.js"
},
"dependencies": {
"linebreak": "rkusa/linebreak",
"opentype.js": "^0.6.2",
"@rkusa/linebreak": "^1.0.0",
"opentype.js": "^0.7.3",
"pako": "^1.0.6",
"unorm": "^1.4.1",

@@ -22,0 +23,0 @@ "uuid": "^3.0.1"

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc