@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.
@@ -0,0 +1,19 @@
1
+ // Many files at once: extract text and encrypt in worker threads; a broken file fails alone.
2
+ //
3
+ // node examples/bulk.mjs [outDir] writes locked-1.pdf … locked-N.pdf
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { toBytes, bulk } from '../dist/index.js';
7
+
8
+ const dir = process.argv[2] ?? '.';
9
+ const make = (label) => toBytes(async (pdf) => {
10
+ const p = pdf.addPage(); p.text(`${label}: total due 1,250.00`, { x: 40, y: 40, font: pdf.standardFont('Helvetica'), size: 14 }); await p.end();
11
+ });
12
+ const files = [await make('Invoice 1'), new Uint8Array([0x25, 0x50]), await make('Invoice 3')]; // the second is not a PDF
13
+
14
+ const texts = await bulk(files, 'extractText', { workers: 2 });
15
+ texts.forEach((r, i) => console.log(i + 1, r.ok ? r.value : `failed: ${r.error.code} ${r.error.message}`));
16
+
17
+ const locked = await bulk(files, 'encrypt', { workers: 2, encrypt: { userPassword: 'open me', ownerPassword: 'full access' } });
18
+ locked.forEach((r, i) => { if (r.ok) fs.writeFileSync(path.join(dir, `locked-${i + 1}.pdf`), r.value); });
19
+ console.log(`encrypted ${locked.filter((r) => r.ok).length} of ${files.length}`);
package/index.d.ts CHANGED
@@ -650,7 +650,7 @@ export interface Pdf {
650
650
  * textMapping: 'carrier' (default: Firefox, pdf.js, search) or 'actualText' (a shaped cluster's text only in its ActualText: MuPDF, AI pipelines) */
651
651
  embedFont(bytes: Uint8Array | ArrayBuffer, o?: { subset?: boolean | Subsetter; shaper?: Shaper; textMapping?: 'carrier' | 'actualText' }): Promise<Font>;
652
652
  /** a JPEG or PNG, written now as an image XObject. colorSpace: an ICC colour space with the image's component count */
653
- embedImage(bytes: Uint8Array | ArrayBuffer, o?: { colorSpace?: IccColorSpace; /** the decoded size a PNG with alpha or interlacing may have; default 64 MB */ maxDecodedBytes?: number }): Promise<Image>;
653
+ embedImage(bytes: Uint8Array | ArrayBuffer, o?: { colorSpace?: IccColorSpace; /** the decoded size a PNG with alpha or interlacing may have; default 64 MB */ maxDecodedBytes?: number; /** zlib level for a re-compressed PNG (alpha, interlacing): 'default' = 6, or 3 above 2 megapixels; 'fast' = 1; or 1–9 */ compression?: 'default' | 'fast' | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 }): Promise<Image>;
654
654
  /** a spot colour: its name and the device colour (gray, RGB, CMYK) shown for it at full tint. One definition per name */
655
655
  spotColor(name: string, alternate: number | string | readonly number[]): SpotColor;
656
656
  /** an ICC-based colour space from a gray, RGB or CMYK profile (its header is checked) */
@@ -846,3 +846,32 @@ export interface LoadedPdf {
846
846
  export function loadPdf(bytes: Uint8Array | ArrayBuffer, options?: LoadOptions): Promise<LoadedPdf>;
847
847
  /** every page of each document, in order, in a new file (the first one's catalog, with what the others bring) */
848
848
  export function mergePdfs(docs: LoadedPdf[], options?: SaveOptions): Promise<SaveResult & { bytes: Uint8Array }>;
849
+ /** the tasks bulk() runs, by name (no functions cross to a worker) */
850
+ export type BulkTask = 'extractText' | 'merge' | 'split' | 'encrypt';
851
+ export const BULK_TASKS: readonly BulkTask[];
852
+ /** what each task takes per item, and gives back */
853
+ export interface BulkTaskTypes {
854
+ extractText: { input: Uint8Array | ArrayBuffer; value: string };
855
+ merge: { input: (Uint8Array | ArrayBuffer)[]; value: Uint8Array };
856
+ split: { input: Uint8Array | ArrayBuffer; value: Uint8Array[] };
857
+ encrypt: { input: Uint8Array | ArrayBuffer; value: Uint8Array };
858
+ }
859
+ export type BulkResult<V> = { ok: true; value: V } | { ok: false; error: { name: string; code?: string; message: string } };
860
+ export interface BulkOptions {
861
+ /** worker threads; default os.availableParallelism() - 1 (at least 1). 1, or no node:worker_threads (browsers): one at a time, in this thread */
862
+ workers?: number;
863
+ /** each worker's heap cap in MB (resourceLimits.maxOldGenerationSizeMb), default 512: an item past it fails with E_WORKER, alone */
864
+ memoryMb?: number;
865
+ /** loadPdf's options, for every input */
866
+ password?: string;
867
+ budget?: ReadBudget;
868
+ timeoutMs?: number;
869
+ /** the encrypt task's encryption */
870
+ encrypt?: EncryptOptions;
871
+ /** save()'s options for merge, split and encrypt */
872
+ save?: SaveOptions;
873
+ /** each item's result as it finishes (index in inputs) */
874
+ onResult?: (index: number, result: BulkResult<unknown>) => void;
875
+ }
876
+ /** One named task over many inputs, in parallel worker threads (Node); results in input order, a failing item never stops the rest. */
877
+ export function bulk<T extends BulkTask>(inputs: Iterable<BulkTaskTypes[T]['input']>, task: T, options?: BulkOptions): Promise<BulkResult<BulkTaskTypes[T]['value']>[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reportwright/pdf",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "A streaming PDF writer for Node and browsers with no runtime dependencies: flat memory, PDF/A-1b to 3a, PDF/UA-1, Factur-X, embedded TrueType with Unicode text.",
5
5
  "type": "module",
6
6
  "license": "MIT",