Skip to content

Commit

Permalink
Merge branch 'master' into pr/1470
Browse files Browse the repository at this point in the history
  • Loading branch information
liborm85 committed Dec 14, 2024
2 parents 3307563 + 75a8dbc commit e5bebdc
Show file tree
Hide file tree
Showing 56 changed files with 4,181 additions and 3,371 deletions.
6 changes: 3 additions & 3 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"modules": false,
"targets": {
"node": "6.10"
"node": "18"
}
}
]
Expand All @@ -17,11 +17,11 @@
"@babel/preset-env",
{
"targets": {
"node": "6.10"
"node": "18"
}
}
]
]
}
}
}
}
25 changes: 12 additions & 13 deletions .github/workflows/lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,22 @@ on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [18.x, 20.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: yarn --frozen-lockfile
- name: Run ESLint
run: npm run lint
- name: Run tests
run: npm test
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: yarn --frozen-lockfile
- name: Run ESLint
run: npm run lint
- name: Run tests
run: npm test
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,32 @@

### Unreleased

- Fix index not counting when rendering ordered lists (#1517)
- Fix PDF/A3 compliance of attachments
- Fix CIDSet generation only for PDF/A1 subset

### [v0.15.1] - 2024-10-30

- Fix browserify transform sRGB_IEC61966_2_1.icc file
- Fix time comparison check equality embedded files

### [v0.15.0] - 2024-03-23

- Add subset for PDF/UA
- Fix for line breaks in list items (#1486)
- Fix for soft hyphen not being replaced by visible hyphen if necessary (#457)
- Optimize output files by ignoring identity transforms
- Fix for Acroforms - setting an option to false will still apply the flag (#1495)
- Fix for text extraction in PDFium-based viewers due to invalid ToUnicodeMap (#1498)
- Remove deprecated `write` method
- Drop support for Node.js < 18 and for browsers released before 2020

### [v0.14.0] - 2023-11-09

- Add support for PDF/A-1b, PDF/A-1a, PDF/A-2b, PDF/A-2a, PDF/A-3b, PDF/A-3a
- Update crypto-js to v4.2.0 (properly fix security issue)

- Add support for EXIF orientation on JPEG images (#626 and #1353)

### [v0.13.0] - 2021-10-24

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Installation uses the [npm](http://npmjs.org/) package manager. Just type the fo
- Transformations
- Linear and radial gradients
- Text
- Line wrapping
- Line wrapping (with soft hyphen recognition)
- Text alignments
- Bulleted lists
- Font embedding
Expand Down Expand Up @@ -129,7 +129,7 @@ complex documents with a very small amount of code. For more, see the `demo` fol
There are three ways to use PDFKit in the browser:

- Use [Browserify](http://browserify.org/). See demo [source code](demo/browser.js) and [build script](https://github.com/foliojs/pdfkit/blob/master/package.json#L56)
- Use [webpack](https://webpack.js.org/). See [complete example](https://github.com/blikblum/pdfkit-webpack-example).
- Use [webpack](https://webpack.js.org/). See [complete example](examples/webpack).
- Use prebuilt version. Distributed as `pdfkit.standalone.js` file in the [releases](https://github.com/foliojs/pdfkit/releases) or in the package `js` folder.

In addition to PDFKit, you'll need somewhere to stream the output to. HTML5 has a
Expand Down
2 changes: 2 additions & 0 deletions docs/accessibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Universal Accessibility) document (which is an extension of Tagged PDF):
* Pass the option `pdfVersion: '1.5'` (or a higher version) when creating your `PDFDocument`
(depending on the features you use, you may only need 1.4; refer to the PDF reference for
details).
* Pass the option `subset: 'PDF/UA'` when creating your `PDFDocument` (if you wish the PDF to
be identified as PDF/UA-1).
* Pass the option `tagged: true` when creating your `PDFDocument` (technically, this sets the
`Marked` property in the `Markings` dictionary to `true` in the PDF).
* Provide a `Title` in the `info` option, and pass `displayTitle: true` when creating your
Expand Down
1 change: 1 addition & 0 deletions docs/attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ There are a few other options for `doc.file`:
* `hidden` - if true, do not show file in the list of embedded files
* `creationDate` - override the date and time the file was created
* `modifiedDate` - override the date and time the file was last updated
* `relationship` - relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.

If you are attaching a file from your file system, creationDate and modifiedDate will be set to the source file's creationDate and modifiedDate.

Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ in your JavaScript source file and create an instance of the
`PDFDocument` class.

const PDFDocument = require('pdfkit');
const doc = new PDFDocument;
const doc = new PDFDocument();

`PDFDocument` instances are readable Node streams. They don't get saved anywhere automatically,
but you can call the `pipe` method to send the output of the PDF document to another
Expand Down
29 changes: 15 additions & 14 deletions docs/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ rendered at the current point in the text flow (below the last line of text).
Otherwise, it is positioned absolutely at the specified point. The image will
be scaled according to the following options.

* Neither `width` or `height` provided - image is rendered at full size
* `width` provided but not `height` - image is scaled proportionally to fit in the provided `width`
* `height` provided but not `width` - image is scaled proportionally to fit in the provided `height`
* Both `width` and `height` provided - image is stretched to the dimensions provided
* `scale` factor provided - image is scaled proportionally by the provided scale factor
* `fit` array provided - image is scaled proportionally to fit within the passed width and height
* `cover` array provided - image is scaled proportionally to completely cover the rectangle defined by the passed width and height
* `link` - a URL to link this image to (shortcut to create an annotation)
* `goTo` - go to anchor (shortcut to create an annotation)
* `destination` - create anchor to this image
- Neither `width` or `height` provided - image is rendered at full size
- `width` provided but not `height` - image is scaled proportionally to fit in the provided `width`
- `height` provided but not `width` - image is scaled proportionally to fit in the provided `height`
- Both `width` and `height` provided - image is stretched to the dimensions provided
- `scale` factor provided - image is scaled proportionally by the provided scale factor
- `fit` array provided - image is scaled proportionally to fit within the passed width and height
- `cover` array provided - image is scaled proportionally to completely cover the rectangle defined by the passed width and height
- `link` - a URL to link this image to (shortcut to create an annotation)
- `goTo` - go to anchor (shortcut to create an annotation)
- `destination` - create anchor to this image
- `ignoreOrientation` - (true/false) ignore JPEG EXIF orientation. By default, images with JPEG EXIF orientation are properly rotated and/or flipped. Defaults to `false`, unless `ignoreOrientation` option set to `true` when creating the `PDFDocument` object (e.g. `new PDFDocument({ignoreOrientation: true})`)

When a `fit` or `cover` array is provided, PDFKit accepts these additional options:

* `align` - horizontally align the image, the possible values are `'left'`, `'center'` and `'right'`
* `valign` - vertically align the image, the possible values are `'top'`, `'center'` and `'bottom'`
- `align` - horizontally align the image, the possible values are `'left'`, `'center'` and `'right'`
- `valign` - vertically align the image, the possible values are `'top'`, `'center'` and `'bottom'`

Here is an example showing some of these options.

Expand All @@ -48,11 +49,11 @@ Here is an example showing some of these options.
.rect(430, 15, 100, 100).stroke()
.text('Centered', 430, 0);

* * *
---

This example produces the following output:

![0](images/images.png "400")
![0](images/images.png '400')

That is all there is to adding images to your PDF documents with PDFKit. Now
let's look at adding outlines.
2 changes: 1 addition & 1 deletion examples/kitchen-sink.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var PDFDocument = require('../js/pdfkit');
var PDFDocument = require('../');
var tiger = require('./tiger');
var fs = require('fs');

Expand Down
14 changes: 7 additions & 7 deletions examples/webpack/package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"license": "MIT",
"dependencies": {
"assert": "^2.0.0",
"assert": "^2.1.0",
"brace": "^0.11.1",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"pdfkit": "^0.12.3",
"pdfkit": "^0.15.0",
"process": "^0.11.10",
"readable-stream": "^3.6.0",
"util": "^0.12.4"
"readable-stream": "^4.5.2",
"util": "^0.12.5"
},
"devDependencies": {
"brfs": "^2.0.2",
"html-webpack-plugin": "^5.3.2",
"html-webpack-plugin": "^5.6.0",
"transform-loader": "^0.2.4",
"webpack": "^5.44.0",
"webpack-cli": "^4.7.2"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
},
"scripts": {
"dev": "webpack --mode development",
Expand Down
19 changes: 3 additions & 16 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ By Devon Govett
*/

import stream from 'stream';
import fs from 'fs';
import PDFObject from './object';
import PDFReference from './reference';
import PDFPage from './page';
Expand Down Expand Up @@ -221,7 +220,9 @@ class PDFDocument extends stream.Readable {
addNamedEmbeddedFile(name, ref) {
if (!this._root.data.Names.data.EmbeddedFiles) {
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({ limits: false });
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
limits: false
});
}

// add filespec to EmbeddedFiles
Expand Down Expand Up @@ -271,20 +272,6 @@ class PDFDocument extends stream.Readable {
}
}

write(filename, fn) {
// print a deprecation warning with a stacktrace
const 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);

this.pipe(fs.createWriteStream(filename));
this.end();
return this.once('end', fn);
}

end() {
this.flushPages();

Expand Down
13 changes: 11 additions & 2 deletions lib/font/embedded.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class EmbeddedFont extends PDFFont {
descriptor.data.FontFile2 = fontFile;
}

if (this.document.subset) {
if (this.document.subset && this.document.subset === 1) {
const CIDSet = Buffer.from('FFFFFFFFC0', 'hex');
const CIDSetRef = this.document.ref();
CIDSetRef.write(CIDSet);
Expand Down Expand Up @@ -252,6 +252,15 @@ class EmbeddedFont extends PDFFont {
entries.push(`<${encoded.join(' ')}>`);
}

const chunkSize = 256;
const chunks = Math.ceil(entries.length / chunkSize);
const ranges = [];
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min((i + 1) * chunkSize, entries.length);
ranges.push(`<${toHex(start)}> <${toHex(end - 1)}> [${entries.slice(start, end).join(' ')}]`);
}

cmap.end(`\
/CIDInit /ProcSet findresource begin
12 dict begin
Expand All @@ -267,7 +276,7 @@ begincmap
<0000><ffff>
endcodespacerange
1 beginbfrange
<0000> <${toHex(entries.length - 1)}> [${entries.join(' ')}]
${ranges.join('\n')}
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
Expand Down
2 changes: 1 addition & 1 deletion lib/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PDFImage {
data = Buffer.from(new Uint8Array(src));
} else {
let match;
if ((match = /^data:.+;base64,(.*)$/.exec(src))) {
if ((match = /^data:.+?;base64,(.*)$/.exec(src))) {
data = Buffer.from(match[1], 'base64');
} else {
data = fs.readFileSync(src);
Expand Down
5 changes: 5 additions & 0 deletions lib/image/jpeg.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import exif from 'jpeg-exif';

const MARKERS = [
0xffc0,
0xffc1,
Expand Down Expand Up @@ -31,6 +33,9 @@ class JPEG {
throw 'SOI not found in JPEG';
}

// Parse the EXIF orientation
this.orientation = exif.fromBuffer(this.data).Orientation || 1;

let pos = 2;
while (pos < this.data.length) {
marker = this.data.readUInt16BE(pos);
Expand Down
20 changes: 18 additions & 2 deletions lib/line_wrapper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { EventEmitter } from 'events';
import LineBreaker from 'linebreak';

const SOFT_HYPHEN = '\u00AD';
const HYPHEN = '-';

class LineWrapper extends EventEmitter {
constructor(document, options) {
super();
Expand Down Expand Up @@ -73,6 +76,13 @@ class LineWrapper extends EventEmitter {
);
}

canFit(word, w) {
if (word[word.length - 1] != SOFT_HYPHEN) {
return w <= this.spaceLeft;
}
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
}

eachWord(text, fn) {
// setup a unicode line breaker
let bk;
Expand Down Expand Up @@ -199,13 +209,13 @@ class LineWrapper extends EventEmitter {
this.spaceLeft = this.lineWidth;
}

if (w <= this.spaceLeft) {
if (this.canFit(word, w)) {
buffer += word;
textWidth += w;
wc++;
}

if (bk.required || w > this.spaceLeft) {
if (bk.required || !this.canFit(word, w)) {
// if the user specified a max height and an ellipsis, and is about to pass the
// max height and max columns after the next line, append the ellipsis
const lh = this.document.currentLineHeight(true);
Expand Down Expand Up @@ -246,6 +256,12 @@ class LineWrapper extends EventEmitter {
this.emit('lastLine', options, this);
}

// Previous entry is a soft hyphen - add visible hyphen.
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
buffer = buffer.slice(0, -1) + HYPHEN;
this.spaceLeft -= this.wordWidth(HYPHEN);
}

emitLine();

// if we've reached the edge of the page,
Expand Down
6 changes: 4 additions & 2 deletions lib/mixins/acroform.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export default {
_fieldDict(name, type, options = {}) {
if (!this._acroform) {
throw new Error(
'Call document.initForms() method before adding form elements to document'
'Call document.initForm() method before adding form elements to document'
);
}
let opts = Object.assign({}, options);
Expand Down Expand Up @@ -299,7 +299,9 @@ export default {
let result = 0;
Object.keys(options).forEach(key => {
if (FIELD_FLAGS[key]) {
result |= FIELD_FLAGS[key];
if (options[key]) {
result |= FIELD_FLAGS[key];
}
delete options[key];
}
});
Expand Down
Loading

0 comments on commit e5bebdc

Please sign in to comment.