@reportwright/pdf 0.1.0-beta.2 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -4
- package/dist/index.js +547 -274
- package/examples/bulk.mjs +19 -0
- package/index.d.ts +30 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -249,6 +249,26 @@ const { bytes } = await doc.saveIncremental(); // the origin
|
|
|
249
249
|
[`examples/merge-split.mjs`](./examples/merge-split.mjs). `save()` rewrites the file (and strips active content);
|
|
250
250
|
`saveIncremental()` appends (and refuses files with active content): see [Security model](#security-model).
|
|
251
251
|
|
|
252
|
+
### Bulk: many files in worker threads
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
import { bulk } from '@reportwright/pdf';
|
|
256
|
+
|
|
257
|
+
const files = fs.readdirSync('in').map((f) => fs.readFileSync(`in/${f}`));
|
|
258
|
+
const texts = await bulk(files, 'extractText', { workers: 4 }); // [{ ok: true, value } | { ok: false, error }]
|
|
259
|
+
const locked = await bulk(files, 'encrypt', { encrypt: { userPassword: 'u', ownerPassword: 'o' } });
|
|
260
|
+
const pages = await bulk(files, 'split'); // value: one Uint8Array per page
|
|
261
|
+
const joined = await bulk([[a, b], [c, d]], 'merge'); // each input: the files to merge
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Tasks are names (`extractText`, `merge`, `split`, `encrypt`; `BULK_TASKS`), never functions, so only bytes and plain
|
|
265
|
+
options cross to a worker. Results come back in input order; a file that fails (malformed, wrong password, over the
|
|
266
|
+
budget) gives `{ ok: false, error: { name, code, message } }` and the batch goes on. Each worker's heap is capped
|
|
267
|
+
(`memoryMb`, default 512): a file that exhausts it kills only that worker, its item fails with `E_WORKER`, and a new
|
|
268
|
+
worker takes the next. `workers` defaults to `os.availableParallelism() - 1`. Node only: in browsers (no
|
|
269
|
+
`node:worker_threads`), and with `workers: 1`, the same tasks run one at a time in the calling thread, without the
|
|
270
|
+
heap cap. [`examples/bulk.mjs`](./examples/bulk.mjs).
|
|
271
|
+
|
|
252
272
|
## Examples
|
|
253
273
|
|
|
254
274
|
| file | what it shows | run |
|
|
@@ -263,6 +283,7 @@ const { bytes } = await doc.saveIncremental(); // the origin
|
|
|
263
283
|
| [`invoice-facturx.mjs`](./examples/invoice-facturx.mjs) | self-contained Factur-X PDF/A-3a invoice | `node examples/invoice-facturx.mjs font.ttf out.pdf` |
|
|
264
284
|
| [`factur-x.mjs`](./examples/factur-x.mjs) | Factur-X from your own CII XML | `node examples/factur-x.mjs invoice.xml font.ttf out.pdf` |
|
|
265
285
|
| [`merge-split.mjs`](./examples/merge-split.mjs) | merge, split, extractText, saveIncremental | `node examples/merge-split.mjs outDir` |
|
|
286
|
+
| [`bulk.mjs`](./examples/bulk.mjs) | extractText and encrypt over many files in worker threads | `node examples/bulk.mjs outDir` |
|
|
266
287
|
|
|
267
288
|
Run from `node_modules/@reportwright/pdf` (or the package folder of the repository).
|
|
268
289
|
|
|
@@ -301,7 +322,7 @@ PDF/A levels and the reader. The most used:
|
|
|
301
322
|
| `createPdf(sink, o)` / `toBytes(build, o)` | `title`, `author`, `creationDate`, `compress`, `metadata`, `pdfa`, `tagged`, `encrypt`, `sign`, `form.flatten`, `signal`, `timeoutMs`, `id` ([table](#createpdfsink-options)) |
|
|
302
323
|
| `pdf.embedFont(bytes, o)` | `subset`, `shaper`, `textMapping` ([Fonts](#fonts), [Shaping](#shaping)) |
|
|
303
324
|
| `page.text` / `page.textBox` | `x`, `y`, `font`, `size`, `color`, `width`, `align`, `maxLines`, `fallback`, `direction`, `kerning` ([Text options](#pages)) |
|
|
304
|
-
| `pdf.embedImage` / `page.image` | `colorSpace`, `maxDecodedBytes` / `width`, `height`, `fit`, `opacity`, `alt` ([Images](#images)) |
|
|
325
|
+
| `pdf.embedImage` / `page.image` | `colorSpace`, `maxDecodedBytes`, `compression` / `width`, `height`, `fit`, `opacity`, `alt` ([Images](#images)) |
|
|
305
326
|
| `page.fill` / `stroke` | `fill`, `stroke`, `width`, `dash`, `cap`, `join`, `opacity`, `blendMode`, `rule` ([Vector graphics](#vector-graphics)) |
|
|
306
327
|
| `encrypt` | `userPassword`, `ownerPassword`, `algorithm`, `permissions`, `encryptMetadata` ([Encryption](#encryption-1)) |
|
|
307
328
|
| `pdf.sign(field, o)` | `signer`, `reason`, `location`, `name`, `certify`, `timestamp`, `subFilter`, `reserve` ([Signatures](#signatures)) |
|
|
@@ -552,10 +573,12 @@ const logo = await pdf.embedImage(fs.readFileSync('logo.png')); // alpha
|
|
|
552
573
|
for (const y of [400, 500, 600]) page.image(logo, { x: 40, y, height: 24, opacity: 0.6 }); // written once
|
|
553
574
|
```
|
|
554
575
|
|
|
555
|
-
- `await pdf.embedImage(bytes, { colorSpace, maxDecodedBytes })` — a JPEG or PNG, written to the file at once as an image XObject;
|
|
576
|
+
- `await pdf.embedImage(bytes, { colorSpace, maxDecodedBytes, compression })` — a JPEG or PNG, written to the file at once as an image XObject;
|
|
556
577
|
returns a handle with `width` and `height` (pixels, after the EXIF orientation). `colorSpace`: an ICC colour space
|
|
557
578
|
(`pdf.iccColorSpace`) with the image's number of components, instead of the device space. `maxDecodedBytes`: the
|
|
558
|
-
decoded size allowed for a PNG that needs decoding (default 64 MB, 67,108,864 bytes).
|
|
579
|
+
decoded size allowed for a PNG that needs decoding (default 64 MB, 67,108,864 bytes). `compression`: the zlib level
|
|
580
|
+
for a PNG that is re-compressed (alpha or interlacing): `'default'` is 6, or 3 above 2 megapixels (about half the
|
|
581
|
+
time for 2–3% more bytes on photos); `'fast'` is 1; or a level 1–9. JPEGs and passed-through PNGs are not affected.
|
|
559
582
|
- **JPEG**: baseline and progressive, gray, RGB and CMYK, embedded unchanged (DCTDecode, no re-encoding). Adobe's
|
|
560
583
|
inverted CMYK (an APP14 "Adobe" segment) is drawn with `/Decode [1 0 1 0 1 0 1 0]`. The EXIF orientation (1–8)
|
|
561
584
|
is honoured. 12-bit, lossless, hierarchical and arithmetic-coded JPEGs are refused.
|
|
@@ -575,7 +598,7 @@ for (const y of [400, 500, 600]) page.image(logo, { x: 40, y, height: 24, opacit
|
|
|
575
598
|
PDFs: `alt` makes the image a `Figure` with that alternate text; without `alt` it is an artifact (decoration).
|
|
576
599
|
- Images are deduplicated automatically: `embedImage` called again with the same bytes (and the same options) in the
|
|
577
600
|
same document returns the same handle and writes nothing new (keyed by a SHA-256 of the bytes; Node's `node:crypto`,
|
|
578
|
-
else WebCrypto, else a fast hash confirmed byte for byte). A different option (`colorSpace`, `maxDecodedBytes`)
|
|
601
|
+
else WebCrypto, else a fast hash confirmed byte for byte). A different option (`colorSpace`, `maxDecodedBytes`, `compression`)
|
|
579
602
|
embeds it again.
|
|
580
603
|
- An image drawn any number of times, on any pages, is one XObject in the file. Images are always XObjects, never
|
|
581
604
|
inline images: an inline image would be repeated in every content stream and cannot have a soft mask.
|