pdfjs
Advanced tools
Comparing version 2.4.7 to 2.5.0
@@ -9,6 +9,15 @@ # Changelog | ||
### Fixed | ||
- Fixed footer position after changing it #283 | ||
- Fixed graphical state not reset hwen using templates (could lead to rotated/translated pages) #287 | ||
- Fixed importing fonts in ESM context (in TS projects) #309 | ||
### Changed | ||
- Added support for multiple table header rows #293 | ||
## [2.4.7] | ||
### Fixed | ||
- Fixed error when rendering page headers close to the bottom of the page #213 | ||
- Fixed reading PDF `Filter` property when being of type array #268 | ||
## [2.5.6] - 2021-08-23 | ||
## [2.4.6] - 2021-08-23 | ||
### Fixed | ||
@@ -15,0 +24,0 @@ - Fixed images not adding page break |
@@ -70,5 +70,4 @@ 'use strict' | ||
set y(val) { | ||
if (val < 0) { | ||
console.warn('set cursor.y to negative value') | ||
} | ||
// No warning about negative y value as this fine for elements in content objects that are | ||
// later placed with an offset anyway. | ||
this._root.y = val | ||
@@ -75,0 +74,0 @@ } |
@@ -13,2 +13,3 @@ 'use strict' | ||
const Font = require('./font/base') | ||
const version = require('../package.json').version | ||
@@ -584,2 +585,23 @@ // constants | ||
// document info | ||
this.info.creationDate = formatDate( | ||
// Default to now and convert to string | ||
this.info.creationDate || new Date() | ||
); | ||
if (!this.info.producer) { | ||
// Set default producer if not one provided | ||
this.info.producer = `pdfjs v${version} (github.com/rkusa/pdfjs)`; | ||
} | ||
if ("modDate" in this.info) { | ||
this.info.modDate = formatDate(this.info.modDate); | ||
} | ||
const infoObj = new PDF.Object(); | ||
for (const key in InfoKeys) { | ||
if (key in this.info) { | ||
infoObj.prop(InfoKeys[key], new PDF.String(this.info[key])); | ||
} | ||
} | ||
this._writeObject(infoObj); | ||
// to support random access to individual objects, a PDF file | ||
@@ -593,3 +615,3 @@ // contains a cross-reference table that can be used to locate | ||
const objectsCount = this._nextObjectId - 1 | ||
const trailer = new PDF.Trailer(objectsCount + 1, catalog, this.info) | ||
const trailer = new PDF.Trailer(objectsCount + 1, catalog, this.info.id, infoObj) | ||
await this._write(trailer.toString() + '\n') | ||
@@ -814,2 +836,35 @@ | ||
const InfoKeys = { | ||
title: 'Title', | ||
author: 'Author', | ||
subject: 'Subject', | ||
keywords: 'Keywords', | ||
creator: 'Creator', | ||
producer: 'Producer', | ||
creationDate: 'CreationDate', | ||
modDate: 'ModDate' | ||
} | ||
function formatDate(date) { | ||
let str = 'D:' | ||
+ date.getFullYear() | ||
+ ('00' + (date.getMonth() + 1)).slice(-2) | ||
+ ('00' + date.getDate()).slice(-2) | ||
+ ('00' + date.getHours()).slice(-2) | ||
+ ('00' + date.getMinutes()).slice(-2) | ||
+ ('00' + date.getSeconds()).slice(-2) | ||
let offset = date.getTimezoneOffset() | ||
const rel = offset === 0 ? 'Z' : (offset > 0 ? '-' : '+') | ||
offset = Math.abs(offset) | ||
const hoursOffset = Math.floor(offset / 60) | ||
const minutesOffset = offset - hoursOffset * 60 | ||
str += rel | ||
+ ('00' + hoursOffset).slice(-2) + '\'' | ||
+ ('00' + minutesOffset).slice(-2) + '\'' | ||
return str | ||
} | ||
module.exports = Document |
@@ -5,2 +5,3 @@ 'use strict' | ||
const Parser = require('./parser/parser') | ||
const ops = require('./ops') | ||
@@ -110,2 +111,12 @@ const PROPERTIES_TO_COPY = { | ||
// Create content chunks used to save and restore the graphical state so a template cannot mess | ||
// with the page's own graphical state. | ||
await doc._startContentObject() | ||
await doc._write(ops.q()) | ||
await doc._endContentObject() | ||
await doc._startContentObject() | ||
await doc._write(ops.Q()) | ||
await doc._endContentObject() | ||
const [storeGraphicalState, restoreGraphicalState] = doc._contents.splice(doc._contents - 3, 2) | ||
for (const page of this._iterPagesRecursively(doc, kids, filter)) { | ||
@@ -135,6 +146,11 @@ // if the page object does not define its MediaBox, explicitly set its MediaBox to the | ||
} | ||
contents = [ | ||
storeGraphicalState._object.toReference(), | ||
...contents, | ||
restoreGraphicalState._object.toReference() | ||
] | ||
let resources = first.get('Resources') | ||
if (resources instanceof PDF.Reference) { | ||
resources = resources.object.properties | ||
resources = resources.object.properties | ||
} | ||
@@ -141,0 +157,0 @@ |
@@ -34,3 +34,3 @@ 'use strict' | ||
// of the page) below | ||
const innerHeight = this._doc._cursor.startY - this._doc._cursor.bottom | ||
const innerHeight = this._doc._cursor.startY - this._doc.paddingBottom | ||
@@ -37,0 +37,0 @@ await Header.prototype._end.call(this) |
@@ -9,5 +9,4 @@ 'use strict' | ||
const JPEGImage = require('./image/jpeg') | ||
const AlreadyEndedError = require('./errors/already-ended') | ||
const ALREADY_ENDED_ERROR = new Error('already ended') | ||
module.exports = class Fragment { | ||
@@ -42,3 +41,3 @@ constructor(doc, parent) { | ||
if (this._ended) { | ||
throw ALREADY_ENDED_ERROR | ||
throw new AlreadyEndedError() | ||
} | ||
@@ -71,3 +70,3 @@ | ||
if (this._ended) { | ||
throw ALREADY_ENDED_ERROR | ||
throw new AlreadyEndedError() | ||
} | ||
@@ -74,0 +73,0 @@ |
'use strict' | ||
const version = require('../../package.json').version | ||
const PDFDictionary = require('./dictionary') | ||
const PDFArray = require('./array') | ||
const PDFString = require('./string') | ||
const PDFArray = require('./array') | ||
const PDFString = require('./string') | ||
const InfoKeys = { | ||
title: 'Title', | ||
author: 'Author', | ||
subject: 'Subject', | ||
keywords: 'Keywords', | ||
creator: 'Creator', | ||
producer: 'Producer', | ||
creationDate: 'CreationDate', | ||
modDate: 'ModDate' | ||
} | ||
class PDFTrailer extends PDFDictionary { | ||
constructor(size, root, info) { | ||
constructor(size, root, id, infoObj) { | ||
super() | ||
@@ -26,25 +14,5 @@ | ||
const id = (new PDFString(info.id)).toHexString() | ||
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) | ||
} | ||
const infoDictionary = {} | ||
for (const key in InfoKeys) { | ||
if (key in info) { | ||
infoDictionary[InfoKeys[key]] = new PDFString(info[key]) | ||
} | ||
} | ||
this.set('Info', new PDFDictionary(infoDictionary)) | ||
const encodedId = (new PDFString(id)).toHexString() | ||
this.set('ID', new PDFArray([encodedId, encodedId])) | ||
this.set('Info', infoObj.toReference()) | ||
} | ||
@@ -71,23 +39,1 @@ | ||
module.exports = PDFTrailer | ||
function formatDate(date) { | ||
let str = 'D:' | ||
+ date.getFullYear() | ||
+ ('00' + (date.getMonth() + 1)).slice(-2) | ||
+ ('00' + date.getDate()).slice(-2) | ||
+ ('00' + date.getHours()).slice(-2) | ||
+ ('00' + date.getMinutes()).slice(-2) | ||
+ ('00' + date.getSeconds()).slice(-2) | ||
let offset = date.getTimezoneOffset() | ||
const rel = offset === 0 ? 'Z' : (offset > 0 ? '-' : '+') | ||
offset = Math.abs(offset) | ||
const hoursOffset = Math.floor(offset / 60) | ||
const minutesOffset = offset - hoursOffset * 60 | ||
str += rel | ||
+ ('00' + hoursOffset).slice(-2) + '\'' | ||
+ ('00' + minutesOffset).slice(-2) + '\'' | ||
return str | ||
} |
@@ -49,3 +49,7 @@ 'use strict' | ||
this._header = null | ||
this._headers = [] | ||
// reference to the last header context | ||
// only defined for tables with exclusively headers | ||
this._last_header_cxt = null | ||
this._is_header_rendered = false | ||
} | ||
@@ -64,2 +68,6 @@ | ||
async _end() { | ||
// render headers if there are no rows | ||
if (!this._is_header_rendered && this._headers.length) { | ||
this._pending.push(() => this._renderHeader()) | ||
} | ||
await Fragment.prototype._end.call(this) | ||
@@ -73,3 +81,3 @@ } | ||
async _renderHeader(isPageBreak) { | ||
if (!this._header) { | ||
if (!this._headers.length) { | ||
return | ||
@@ -82,3 +90,5 @@ } | ||
if (!isPageBreak && !this._cursor.doesFit(this._header.height)) { | ||
const headerHeight = this._headers.reduce((total, header) => total + header.height, 0) | ||
if (!isPageBreak && !this._cursor.doesFit(headerHeight)) { | ||
await this._pageBreak(1, false) | ||
@@ -90,22 +100,26 @@ return | ||
const offset = this._cursor.y - this._header.startedAtY | ||
if (offset !== 0) { | ||
// offset header to the top | ||
chunk += ops.q() | ||
+ ops.cm(1, 0, 0, 1, 0, offset) | ||
} | ||
for (const header of this._headers) { | ||
const offset = this._cursor.y - header.startedAtY | ||
if (offset !== 0) { | ||
// offset header to the top | ||
chunk += ops.q() | ||
+ ops.cm(1, 0, 0, 1, 0, offset) | ||
} | ||
for (const obj of this._header._objects) { | ||
const alias = new PDF.Name('TH' + obj.id) | ||
this._doc._currentContent._xobjects[alias] = obj.toReference() | ||
chunk += ops.Do(alias) | ||
} | ||
for (const obj of header._objects) { | ||
const alias = new PDF.Name('TH' + obj.id) | ||
this._doc._currentContent._xobjects[alias] = obj.toReference() | ||
chunk += ops.Do(alias) | ||
} | ||
this._cursor.y -= this._header.height | ||
this._cursor.y -= header.height | ||
if (offset !== 0) { | ||
chunk += ops.Q() | ||
if (offset !== 0) { | ||
chunk += ops.Q() | ||
} | ||
} | ||
await this._doc._write(chunk) | ||
this._is_header_rendered = true; | ||
} | ||
@@ -142,2 +156,3 @@ | ||
const ctx = new Row(this._doc, this, opts) | ||
this._last_header_cxt = isHeader ? ctx : null | ||
this._begin(ctx) | ||
@@ -158,3 +173,4 @@ | ||
ctx._hasTopBorder = this._rowCount === (this._header ? 1 : 0) | ||
// should have a top border if there are only header rows in the table | ||
ctx._hasTopBorder = this._rowCount === (this._headers.length) | ||
} | ||
@@ -173,2 +189,7 @@ | ||
end() { | ||
// if the table only has headers, add a bottom border to the last header row | ||
if (!this._is_header_rendered && this._last_header_cxt && this.borderHorizontalWidths) { | ||
this._last_header_cxt._bottomBorderWidth = this.borderHorizontalWidths(this._rowCount) | ||
this._last_header_cxt._bottomBorderColor = util.colorToRgb(this.borderHorizontalColors(this._rowCount)) | ||
} | ||
return Fragment.prototype.end.call(this) | ||
@@ -178,2 +199,6 @@ } | ||
row(opts) { | ||
// Defer rendering of the headers until either a row is added or _end | ||
if (this._rowCount === this._headers.length) { | ||
this._pending.push(() => this._renderHeader()) | ||
} | ||
return this._row(opts, false) | ||
@@ -183,8 +208,8 @@ } | ||
header(opts) { | ||
if (this._header) { | ||
throw new Error('The table already has a header, add additional rows to the existing table header instead') | ||
// Can only add more headers if there are no rows added yet | ||
if (this._rowCount > this._headers.length) { | ||
throw new Error('The table already has rows, cannot add additional headers') | ||
} | ||
const ctx = this._row(opts, true) | ||
this._header = ctx | ||
this._pending.push(() => this._renderHeader()) | ||
this._headers.push(ctx) | ||
return ctx | ||
@@ -302,2 +327,2 @@ } | ||
} | ||
} | ||
} |
{ | ||
"name": "pdfjs", | ||
"author": "Markus Ast <npm.m@rkusa.st>", | ||
"version": "2.4.7", | ||
"version": "2.5.0", | ||
"description": "A Portable Document Format (PDF) generation library targeting both the server- and client-side.", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
@@ -6,6 +6,4 @@ ![pdfjs](https://cdn.rawgit.com/rkusa/pdfjs/2.x/logo.svg) | ||
[![NPM][npm]](https://npmjs.org/package/pdfjs) | ||
[![Dependency Status][deps]](https://david-dm.org/rkusa/pdfjs) | ||
[![Build Status][travis]](https://travis-ci.org/rkusa/pdfjs) | ||
[Documentation](docs) | [Playground](http://pdfjs.rkusa.st/) | ||
[Documentation](docs) | [Playground](https://stackblitz.com/edit/js-hkxfhq?file=index.js) | ||
@@ -12,0 +10,0 @@ ```bash |
@@ -639,2 +639,7 @@ declare module "pdfjs" { | ||
declare module "pdfjs/font/Courier-Bold.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Courier-BoldOblique" { | ||
@@ -645,2 +650,7 @@ const font: Font; | ||
declare module "pdfjs/font/Courier-BoldOblique.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Courier-Oblique" { | ||
@@ -651,2 +661,7 @@ const font: Font; | ||
declare module "pdfjs/font/Courier-Oblique.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Courier" { | ||
@@ -657,2 +672,7 @@ const font: Font; | ||
declare module "pdfjs/font/Courier.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Helvetica-Bold" { | ||
@@ -663,2 +683,7 @@ const font: Font; | ||
declare module "pdfjs/font/Helvetica-Bold.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Helvetica-BoldOblique" { | ||
@@ -669,2 +694,7 @@ const font: Font; | ||
declare module "pdfjs/font/Helvetica-BoldOblique.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Helvetica-Oblique" { | ||
@@ -675,2 +705,7 @@ const font: Font; | ||
declare module "pdfjs/font/Helvetica-Oblique.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Helvetica" { | ||
@@ -681,2 +716,7 @@ const font: Font; | ||
declare module "pdfjs/font/Helvetica.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Symbol" { | ||
@@ -687,2 +727,7 @@ const font: Font; | ||
declare module "pdfjs/font/Symbol.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Times-Bold" { | ||
@@ -693,2 +738,7 @@ const font: Font; | ||
declare module "pdfjs/font/Times-Bold.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Times-BoldItalic" { | ||
@@ -699,2 +749,7 @@ const font: Font; | ||
declare module "pdfjs/font/Times-BoldItalic.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Times-Italic" { | ||
@@ -705,2 +760,7 @@ const font: Font; | ||
declare module "pdfjs/font/Times-Italic.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/Times-Roman" { | ||
@@ -711,5 +771,15 @@ const font: Font; | ||
declare module "pdfjs/font/Times-Roman.js" { | ||
const font: Font; | ||
export = font; | ||
} | ||
declare module "pdfjs/font/ZapfDingbats" { | ||
const font: Font; | ||
export = font; | ||
} | ||
} | ||
declare module "pdfjs/font/ZapfDingbats.js" { | ||
const font: Font; | ||
export = font; | ||
} |
346491
77
6718
42