@reekon-tools/react-native-pdf-canvas 0.1.0
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/PdfCanvas.podspec +80 -0
- package/README.md +1391 -0
- package/android/build.gradle +175 -0
- package/android/consumer-rules.pro +3 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/android/gradle.properties +2 -0
- package/android/gradlew +248 -0
- package/android/gradlew.bat +98 -0
- package/android/settings.gradle +34 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasCancellationTest.java +226 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasConcurrencyTest.java +239 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasDeviceTimingTest.java +251 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasFailureTest.java +221 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasJsiTransportTest.java +783 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPhaseTimingTest.java +1388 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPoisonGuardTest.java +98 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasQuirksTest.java +324 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasRasterizerTest.java +775 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PoisonsTheProcess.java +20 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/TestPdfs.java +558 -0
- package/android/src/jsi/cpp/CMakeLists.txt +33 -0
- package/android/src/jsi/cpp/pdfcanvas-jsi.cpp +469 -0
- package/android/src/jsi/java/tools/reekon/pdfcanvas/jsi/PdfCanvasPixelBridge.java +140 -0
- package/android/src/main/AndroidManifest.xml +7 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PageGeometry.java +45 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasRasterizer.java +564 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfErrorCode.java +33 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPlatformQuirks.java +277 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPreflight.java +214 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRasterException.java +30 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRendererPool.java +234 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterCancellation.java +47 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterPixels.java +143 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterRequest.java +95 -0
- package/android/src/reactnative/java/tools/reekon/pdfcanvas/rn/PdfCanvasModule.java +626 -0
- package/android/src/reactnative/java/tools/reekon/pdfcanvas/rn/PdfCanvasPackage.java +33 -0
- package/android/tools/compile-gate.sh +289 -0
- package/dist/cache.d.ts +161 -0
- package/dist/cache.js +389 -0
- package/dist/clock.d.ts +21 -0
- package/dist/clock.js +31 -0
- package/dist/controller.d.ts +131 -0
- package/dist/controller.js +1002 -0
- package/dist/geometry.d.ts +96 -0
- package/dist/geometry.js +248 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +50 -0
- package/dist/index.native.d.ts +21 -0
- package/dist/index.native.js +23 -0
- package/dist/index.web.d.ts +24 -0
- package/dist/index.web.js +26 -0
- package/dist/layout.d.ts +78 -0
- package/dist/layout.js +152 -0
- package/dist/peer-check.d.ts +83 -0
- package/dist/peer-check.js +183 -0
- package/dist/planner.d.ts +35 -0
- package/dist/planner.js +530 -0
- package/dist/policy.d.ts +14 -0
- package/dist/policy.js +168 -0
- package/dist/rasterizer/android.d.ts +121 -0
- package/dist/rasterizer/android.js +126 -0
- package/dist/rasterizer/buffer.d.ts +18 -0
- package/dist/rasterizer/buffer.js +18 -0
- package/dist/rasterizer/fake.d.ts +92 -0
- package/dist/rasterizer/fake.js +433 -0
- package/dist/rasterizer/index.d.ts +38 -0
- package/dist/rasterizer/index.js +69 -0
- package/dist/rasterizer/index.native.d.ts +19 -0
- package/dist/rasterizer/index.native.js +80 -0
- package/dist/rasterizer/index.web.d.ts +63 -0
- package/dist/rasterizer/index.web.js +75 -0
- package/dist/rasterizer/ingest.d.ts +180 -0
- package/dist/rasterizer/ingest.js +307 -0
- package/dist/rasterizer/ios.d.ts +84 -0
- package/dist/rasterizer/ios.js +155 -0
- package/dist/rasterizer/native-bridge.d.ts +261 -0
- package/dist/rasterizer/native-bridge.js +413 -0
- package/dist/rasterizer/web/client.d.ts +84 -0
- package/dist/rasterizer/web/client.js +359 -0
- package/dist/rasterizer/web/engine.d.ts +69 -0
- package/dist/rasterizer/web/engine.js +308 -0
- package/dist/rasterizer/web/index.d.ts +26 -0
- package/dist/rasterizer/web/index.js +21 -0
- package/dist/rasterizer/web/pdfium.d.ts +213 -0
- package/dist/rasterizer/web/pdfium.js +170 -0
- package/dist/rasterizer/web/protocol.d.ts +138 -0
- package/dist/rasterizer/web/protocol.js +37 -0
- package/dist/rasterizer/web/session.d.ts +106 -0
- package/dist/rasterizer/web/session.js +413 -0
- package/dist/rasterizer/web/worker.d.ts +44 -0
- package/dist/rasterizer/web/worker.js +76 -0
- package/dist/react/PdfContentView.d.ts +98 -0
- package/dist/react/PdfContentView.js +189 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +3 -0
- package/dist/react/usePdfDocument.d.ts +134 -0
- package/dist/react/usePdfDocument.js +275 -0
- package/dist/react/usePdfLayer.d.ts +94 -0
- package/dist/react/usePdfLayer.js +388 -0
- package/dist/skia/index.d.ts +26 -0
- package/dist/skia/index.js +25 -0
- package/dist/skia/index.native.d.ts +14 -0
- package/dist/skia/index.native.js +16 -0
- package/dist/skia/index.web.d.ts +12 -0
- package/dist/skia/index.web.js +14 -0
- package/dist/skia/resolve.native.d.ts +18 -0
- package/dist/skia/resolve.native.js +22 -0
- package/dist/skia/resolve.web.d.ts +41 -0
- package/dist/skia/resolve.web.js +62 -0
- package/dist/skia/skia-api.d.ts +94 -0
- package/dist/skia/skia-api.js +113 -0
- package/dist/testing/index.d.ts +27 -0
- package/dist/testing/index.js +28 -0
- package/dist/testing/scenes.d.ts +100 -0
- package/dist/testing/scenes.js +267 -0
- package/dist/types.d.ts +611 -0
- package/dist/types.js +21 -0
- package/dist/web-init.d.ts +68 -0
- package/dist/web-init.js +64 -0
- package/ios/Package.swift +58 -0
- package/ios/Sources/PdfCanvasBridge/PdfCanvasModule.mm +743 -0
- package/ios/Sources/PdfCanvasBridge/include/PdfCanvasModule.h +36 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasCancellation.m +38 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasDocumentPool.m +389 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasErrorCode.m +57 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageGeometry.m +44 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageTransform.m +82 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasPixelSink.m +37 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasPreflight.m +158 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterPixels.m +80 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterRequest.m +65 -0
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterizer.m +548 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCancellation.h +48 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCore.h +26 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasDocumentPool.h +122 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasErrorCode.h +80 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageGeometry.h +79 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageTransform.h +129 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPixelSink.h +100 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPreflight.h +65 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterPixels.h +111 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterRequest.h +85 -0
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterizer.h +163 -0
- package/ios/Sources/PdfCanvasSlots/PdfCanvasSlots.mm +297 -0
- package/ios/Sources/PdfCanvasSlots/include/PdfCanvasSlots.h +140 -0
- package/ios/Tests/PdfCanvasCoreTests/ConcurrencyTests.swift +358 -0
- package/ios/Tests/PdfCanvasCoreTests/FailureTests.swift +262 -0
- package/ios/Tests/PdfCanvasCoreTests/GeometryTests.swift +173 -0
- package/ios/Tests/PdfCanvasCoreTests/PreviewTests.swift +114 -0
- package/ios/Tests/PdfCanvasCoreTests/RasterAssertions.swift +158 -0
- package/ios/Tests/PdfCanvasCoreTests/RasterizerTests.swift +544 -0
- package/ios/Tests/PdfCanvasCoreTests/SinkTests.swift +287 -0
- package/ios/Tests/PdfCanvasCoreTests/SlotsTests.swift +396 -0
- package/ios/Tests/PdfCanvasCoreTests/TestPdfs.swift +639 -0
- package/ios/Tests/PdfCanvasCoreTests/TimingTests.swift +179 -0
- package/ios/Tests/PdfCanvasCoreTests/TransformTests.swift +283 -0
- package/package.json +144 -0
- package/react-native.config.js +40 -0
- package/scripts/check-skia-peer.mjs +86 -0
- package/scripts/skia-peer-check.mjs +363 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PDFium half of the web backend: open a document, measure its pages,
|
|
3
|
+
* render an arbitrary doc-space rect.
|
|
4
|
+
*
|
|
5
|
+
* PURE IN THE SAME SENSE `../android.ts` IS. It takes a `PdfiumBinding` and
|
|
6
|
+
* imports nothing else — no worker, no DOM, no `@embedpdf/pdfium`. Which means
|
|
7
|
+
* the interesting half of this backend (rect registration, stride, the
|
|
8
|
+
* background fill, `/Rotate`, the error codes) is exercised in vitest under
|
|
9
|
+
* plain node against the REAL WASM module, not against a mock of it. See
|
|
10
|
+
* `__tests__/web-rasterizer.test.ts`.
|
|
11
|
+
*
|
|
12
|
+
* ------------------------------------------------------------------------
|
|
13
|
+
* THE RECT MECHANISM — negative offsets, not a matrix
|
|
14
|
+
* ------------------------------------------------------------------------
|
|
15
|
+
*
|
|
16
|
+
* PDFium's public way to draw part of a page is to describe the WHOLE page at
|
|
17
|
+
* the target scale and then slide it: `FPDF_RenderPageBitmap(bitmap, page,
|
|
18
|
+
* -x*s, -y*s, pageW*s, pageH*s, 0, flags)` into a bitmap that is only the tile's
|
|
19
|
+
* size. Everything outside the bitmap is clipped away by the bitmap itself.
|
|
20
|
+
*
|
|
21
|
+
* The alternative, `FPDF_RenderPageBitmapWithMatrix` with
|
|
22
|
+
* `FS_MATRIX{a:s, b:0, c:0, d:s, e:-x*s, f:-y*s}` and an `FS_RECTF(0,0,w,h)`
|
|
23
|
+
* clip, was MEASURED to be byte-identical to this on every rect tested —
|
|
24
|
+
* including a rect whose device offset is fractional (x*s = 33.6999…), where the
|
|
25
|
+
* two might plausibly have rounded differently and do not. The matrix form also
|
|
26
|
+
* has a trap this one does not: passing a NULL clip renders NOTHING AT ALL
|
|
27
|
+
* (measured: an all-white bitmap, no error). The simpler mechanism with no null
|
|
28
|
+
* case is the one that ships.
|
|
29
|
+
*
|
|
30
|
+
* ------------------------------------------------------------------------
|
|
31
|
+
* WHY THE OFFSET IS `-round(x*s)` AND NOT `round(-x*s)`
|
|
32
|
+
* ------------------------------------------------------------------------
|
|
33
|
+
*
|
|
34
|
+
* Because the tile's origin inside a hypothetical full-page render is
|
|
35
|
+
* `round(x*s)`, and the registration property is that the tile equals that
|
|
36
|
+
* region exactly. Negating the rounded origin makes those two the same integer
|
|
37
|
+
* by construction. `Math.round(-0.5)` is `-0` while `-Math.round(0.5)` is `-1`,
|
|
38
|
+
* so the two spellings genuinely differ on half-pixel boundaries — which is
|
|
39
|
+
* exactly where a misregistration would be least likely to be noticed and most
|
|
40
|
+
* likely to be real.
|
|
41
|
+
*/
|
|
42
|
+
import { FPDF_ANNOT, FPDF_BITMAP_BGRA, FPDF_REVERSE_BYTE_ORDER, loadError, } from './pdfium.js';
|
|
43
|
+
import { PdfError } from '../../types.js';
|
|
44
|
+
/**
|
|
45
|
+
* MEASURED, not inherited from the other backends. An antialiased opaque-white
|
|
46
|
+
* edge over a transparent page reads `[255, 255, 255, 50]` and
|
|
47
|
+
* `[255, 255, 255, 178]` out of PDFium; premultiplied would have been
|
|
48
|
+
* `[50, 50, 50, 50]` and `[178, 178, 178, 178]`. So the web backend declares
|
|
49
|
+
* `'straight'` and Android declares `'premultiplied'`, which is the entire
|
|
50
|
+
* reason `RasterPixels.alpha` is a required field rather than a constant in
|
|
51
|
+
* `ingest.ts`.
|
|
52
|
+
*
|
|
53
|
+
* INVISIBLE UNDER `background: 'white'` — every pixel is opaque there and the
|
|
54
|
+
* two encodings are byte-identical — so this can only ever be caught by a test
|
|
55
|
+
* that renders `background: 'transparent'`. There is one.
|
|
56
|
+
*/
|
|
57
|
+
const PDFIUM_ALPHA = 'straight';
|
|
58
|
+
/** See `FPDF_REVERSE_BYTE_ORDER`: the flag is always passed, so this follows. */
|
|
59
|
+
const PDFIUM_FORMAT = 'rgba8888';
|
|
60
|
+
/** ARGB. Both of the two values used are symmetric under an R/B swap, which is
|
|
61
|
+
* what makes filling BEFORE a reverse-byte-order render correct rather than
|
|
62
|
+
* lucky: `FPDFBitmap_FillRect` writes in the bitmap's own BGRA order. */
|
|
63
|
+
const OPAQUE_WHITE = 0xffffffff;
|
|
64
|
+
const TRANSPARENT = 0x00000000;
|
|
65
|
+
/** PDFium's ints are 32-bit; a request past this cannot be expressed at all. */
|
|
66
|
+
const MAX_INT32 = 0x7fffffff;
|
|
67
|
+
const ROTATIONS = [0, 90, 180, 270];
|
|
68
|
+
/* ------------------------------------------------------------------ *
|
|
69
|
+
* Open
|
|
70
|
+
* ------------------------------------------------------------------ */
|
|
71
|
+
/**
|
|
72
|
+
* Read every page's size and rotation without loading a single page.
|
|
73
|
+
*
|
|
74
|
+
* This is what makes `RasterizerHandle.pageGeometry` synchronous. Both calls
|
|
75
|
+
* work off the page DICTIONARY — no content stream is parsed — so the cost is
|
|
76
|
+
* proportional to the page tree and not to what is drawn on it.
|
|
77
|
+
*
|
|
78
|
+
* A page that cannot be measured fails the OPEN rather than being papered over
|
|
79
|
+
* with a zero size. A `PageGeometry` is what the layout function turns into the
|
|
80
|
+
* document's whole coordinate space; a wrong one there is not a missing page,
|
|
81
|
+
* it is every page after it in the wrong place.
|
|
82
|
+
*/
|
|
83
|
+
function readGeometry(api, document, pageCount) {
|
|
84
|
+
const sizeOut = api.malloc(8);
|
|
85
|
+
try {
|
|
86
|
+
const pages = [];
|
|
87
|
+
for (let index = 0; index < pageCount; index++) {
|
|
88
|
+
if (!api.FPDF_GetPageSizeByIndexF(document, index, sizeOut)) {
|
|
89
|
+
throw new PdfError('corrupt', `PDFium could not read the size of page ${index} of ${pageCount}.`);
|
|
90
|
+
}
|
|
91
|
+
const rotationIndex = api.EPDF_GetPageRotationByIndex(document, index);
|
|
92
|
+
pages.push({
|
|
93
|
+
index,
|
|
94
|
+
// ALREADY POST-ROTATION, and measured to be so — see
|
|
95
|
+
// `FPDF_GetPageSizeByIndexF`. Swapping width and height here for a
|
|
96
|
+
// 90/270 page would rotate it twice.
|
|
97
|
+
width: api.getFloat(sizeOut),
|
|
98
|
+
height: api.getFloat(sizeOut + 4),
|
|
99
|
+
// -1 is PDFium's "no such page", which the size read above has already
|
|
100
|
+
// ruled out; anything else outside 0..3 would be a new return
|
|
101
|
+
// convention. Both fall back to 0 rather than failing the open: an
|
|
102
|
+
// unrotated page whose dimensions are right still draws correctly, and
|
|
103
|
+
// `PageGeometry.rotation` is informational to this package.
|
|
104
|
+
rotation: ROTATIONS[rotationIndex] ?? 0,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return pages;
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
api.free(sizeOut);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Open a document from bytes.
|
|
115
|
+
*
|
|
116
|
+
* THE BYTES ARE COPIED INTO THE WASM HEAP AND STAY THERE. `FPDF_LoadMemDocument`
|
|
117
|
+
* does not take ownership and does not copy: PDFium reads the buffer lazily for
|
|
118
|
+
* the whole life of the document, so freeing it early is a use-after-free inside
|
|
119
|
+
* the WASM heap — which does not crash, it produces wrong pixels. `close()`
|
|
120
|
+
* frees it, after `FPDF_CloseDocument` and never before.
|
|
121
|
+
*/
|
|
122
|
+
export function openPdfiumDocument(api, bytes, password) {
|
|
123
|
+
if (bytes.byteLength === 0) {
|
|
124
|
+
throw new PdfError('corrupt', 'The document is empty (0 bytes).');
|
|
125
|
+
}
|
|
126
|
+
const dataPointer = api.malloc(bytes.byteLength);
|
|
127
|
+
if (dataPointer === 0) {
|
|
128
|
+
throw new PdfError('out-of-memory', `Could not allocate ${bytes.byteLength} bytes in the PDFium heap for ` +
|
|
129
|
+
'the document.');
|
|
130
|
+
}
|
|
131
|
+
api.heapU8().set(bytes, dataPointer);
|
|
132
|
+
const document = api.FPDF_LoadMemDocument(dataPointer, bytes.byteLength, password ?? '');
|
|
133
|
+
if (document === 0) {
|
|
134
|
+
const error = api.FPDF_GetLastError();
|
|
135
|
+
api.free(dataPointer);
|
|
136
|
+
throw loadError(error, password !== undefined && password !== '');
|
|
137
|
+
}
|
|
138
|
+
let pages;
|
|
139
|
+
const pageCount = api.FPDF_GetPageCount(document);
|
|
140
|
+
try {
|
|
141
|
+
pages = readGeometry(api, document, pageCount);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
api.FPDF_CloseDocument(document);
|
|
145
|
+
api.free(dataPointer);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
return createDocument(api, document, dataPointer, pages);
|
|
149
|
+
}
|
|
150
|
+
/* ------------------------------------------------------------------ *
|
|
151
|
+
* Render
|
|
152
|
+
* ------------------------------------------------------------------ */
|
|
153
|
+
function createDocument(api, document, dataPointer, pages) {
|
|
154
|
+
let closed = false;
|
|
155
|
+
/**
|
|
156
|
+
* ONE loaded page, cached.
|
|
157
|
+
*
|
|
158
|
+
* `FPDF_LoadPage` is the call that parses the content stream, and an epoch is
|
|
159
|
+
* several tiles of the same page — so caching turns N parses into one. It is
|
|
160
|
+
* capped at ONE rather than being an LRU on purpose: a parsed page lives in
|
|
161
|
+
* the Emscripten heap, and that heap only ever grows (it never returns pages
|
|
162
|
+
* to the OS), so "how many parsed pages may be resident" is a permanent floor
|
|
163
|
+
* on the tab's memory and not a cache-tuning question. Alternating between two
|
|
164
|
+
* pages costs a reparse; holding both costs the session.
|
|
165
|
+
*/
|
|
166
|
+
let loadedIndex = -1;
|
|
167
|
+
let loadedPage = 0;
|
|
168
|
+
const releasePage = () => {
|
|
169
|
+
if (loadedPage !== 0) {
|
|
170
|
+
api.FPDF_ClosePage(loadedPage);
|
|
171
|
+
loadedPage = 0;
|
|
172
|
+
loadedIndex = -1;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const requirePage = (index) => {
|
|
176
|
+
const geometry = pages[index];
|
|
177
|
+
if (geometry === undefined) {
|
|
178
|
+
throw new PdfError('not-found', `Document has ${pages.length} pages; asked for ${index}.`);
|
|
179
|
+
}
|
|
180
|
+
return geometry;
|
|
181
|
+
};
|
|
182
|
+
const loadPage = (index) => {
|
|
183
|
+
if (loadedIndex === index && loadedPage !== 0)
|
|
184
|
+
return loadedPage;
|
|
185
|
+
releasePage();
|
|
186
|
+
const page = api.FPDF_LoadPage(document, index);
|
|
187
|
+
if (page === 0) {
|
|
188
|
+
// Not `FPDF_GetLastError` — see `PDFIUM_ERR`, it is stale here. The index
|
|
189
|
+
// was already bounds-checked against the geometry read at open, so a
|
|
190
|
+
// failure at this point is a page whose content PDFium refuses.
|
|
191
|
+
throw new PdfError('corrupt', `PDFium could not load page ${index}. The page exists (its size was ` +
|
|
192
|
+
'read at open) but its content could not be parsed.');
|
|
193
|
+
}
|
|
194
|
+
loadedIndex = index;
|
|
195
|
+
loadedPage = page;
|
|
196
|
+
return page;
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
pageCount: pages.length,
|
|
200
|
+
pages,
|
|
201
|
+
render(request) {
|
|
202
|
+
if (closed) {
|
|
203
|
+
throw new PdfError('backend-failure', 'The document is closed.');
|
|
204
|
+
}
|
|
205
|
+
const geometry = requirePage(request.page);
|
|
206
|
+
const { docRect, scale } = request;
|
|
207
|
+
if (!Number.isFinite(scale) || scale <= 0) {
|
|
208
|
+
throw new PdfError('backend-failure', `Scale must be a positive finite number, got ${scale}.`);
|
|
209
|
+
}
|
|
210
|
+
if (!Number.isFinite(docRect.x) ||
|
|
211
|
+
!Number.isFinite(docRect.y) ||
|
|
212
|
+
!(docRect.width > 0) ||
|
|
213
|
+
!(docRect.height > 0)) {
|
|
214
|
+
throw new PdfError('backend-failure', `Doc rect must be finite and have positive extent, got ` +
|
|
215
|
+
`${docRect.width}x${docRect.height} at ` +
|
|
216
|
+
`(${docRect.x}, ${docRect.y}).`);
|
|
217
|
+
}
|
|
218
|
+
// At least one pixel: a sub-pixel rect is a legitimate ask at low zoom,
|
|
219
|
+
// and a zero-sized bitmap is not a thing PDFium (or Skia) accepts.
|
|
220
|
+
const width = Math.max(1, Math.round(docRect.width * scale));
|
|
221
|
+
const height = Math.max(1, Math.round(docRect.height * scale));
|
|
222
|
+
// See the header: the negation of the ROUNDED origin, not the rounding of
|
|
223
|
+
// the negated one.
|
|
224
|
+
const startX = -Math.round(docRect.x * scale);
|
|
225
|
+
const startY = -Math.round(docRect.y * scale);
|
|
226
|
+
const pageWidth = Math.round(geometry.width * scale);
|
|
227
|
+
const pageHeight = Math.round(geometry.height * scale);
|
|
228
|
+
if (width * height > MAX_INT32 / 4 ||
|
|
229
|
+
pageWidth > MAX_INT32 ||
|
|
230
|
+
pageHeight > MAX_INT32) {
|
|
231
|
+
throw new PdfError('out-of-memory', `A ${width}x${height} raster of a ${pageWidth}x${pageHeight} page ` +
|
|
232
|
+
'cannot be expressed in PDFium’s 32-bit ints. Lower ' +
|
|
233
|
+
'`RasterPolicy.maxPieceDimension` or `maxRasterPixels`.');
|
|
234
|
+
}
|
|
235
|
+
const bitmap = api.FPDFBitmap_CreateEx(width, height, FPDF_BITMAP_BGRA, 0, 0);
|
|
236
|
+
if (bitmap === 0) {
|
|
237
|
+
throw new PdfError('out-of-memory', `PDFium could not allocate a ${width}x${height} bitmap ` +
|
|
238
|
+
`(${width * height * 4} bytes).`);
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
// BEFORE THE RENDER, ALWAYS, AND NOT OPTIONAL. PDFium composites onto
|
|
242
|
+
// the destination and never clears it; a freshly allocated buffer is
|
|
243
|
+
// transparent black, which under the app's annotation layers reads as a
|
|
244
|
+
// BLACK page rather than a blank one. Ingest cannot repair this — it
|
|
245
|
+
// has no way to tell "the PDF painted black here" from "nothing painted
|
|
246
|
+
// here".
|
|
247
|
+
// The return is CHECKED, not discarded: the comment above says the fill
|
|
248
|
+
// is not optional, and a silently-failed fill is exactly the failure it
|
|
249
|
+
// describes — a black page that ingest cannot tell from painted black.
|
|
250
|
+
const filled = api.FPDFBitmap_FillRect(bitmap, 0, 0, width, height, request.background === 'white' ? OPAQUE_WHITE : TRANSPARENT);
|
|
251
|
+
if (!filled) {
|
|
252
|
+
throw new PdfError('backend-failure', `PDFium refused to clear the ${width}x${height} destination ` +
|
|
253
|
+
`bitmap before rendering page ${request.page}. Rendering into it ` +
|
|
254
|
+
'would composite onto uninitialised memory.');
|
|
255
|
+
}
|
|
256
|
+
const page = loadPage(request.page);
|
|
257
|
+
api.FPDF_RenderPageBitmap(bitmap, page, startX, startY, pageWidth, pageHeight,
|
|
258
|
+
// Device rotation, NOT the page's `/Rotate`. PDFium applies the
|
|
259
|
+
// page's own rotation itself, and `geometry` is already post-rotation
|
|
260
|
+
// — passing anything but 0 here would rotate a second time.
|
|
261
|
+
0, FPDF_REVERSE_BYTE_ORDER | (request.annotations ? FPDF_ANNOT : 0));
|
|
262
|
+
// READ, NEVER ASSUMED. Measured tight (`width * 4`) at 1, 3, 7, 13, 1023
|
|
263
|
+
// and 1025 px — but "tight today" is not "tight always", and a wrong
|
|
264
|
+
// stride shears the image instead of failing.
|
|
265
|
+
const rowBytes = api.FPDFBitmap_GetStride(bitmap);
|
|
266
|
+
const buffer = api.FPDFBitmap_GetBuffer(bitmap);
|
|
267
|
+
if (buffer === 0 || rowBytes < width * 4) {
|
|
268
|
+
throw new PdfError('backend-failure', `PDFium reported an unusable bitmap: buffer ${buffer}, stride ` +
|
|
269
|
+
`${rowBytes} for a ${width}px row.`);
|
|
270
|
+
}
|
|
271
|
+
// `slice` and not `subarray`: this must LEAVE the WASM heap. A view
|
|
272
|
+
// would be invalidated by the next allocation (Emscripten replaces
|
|
273
|
+
// HEAPU8 wholesale when memory grows) and would be neither tight nor
|
|
274
|
+
// transferable. The copy is the price of getting the pixels out, and
|
|
275
|
+
// it is the only one — the result owns an exactly-sized ArrayBuffer,
|
|
276
|
+
// so `isTightBuffer` holds and ingest's `tighten()` has nothing to do.
|
|
277
|
+
//
|
|
278
|
+
// The WHOLE stride of the last row, not Skia's `computeByteSize`
|
|
279
|
+
// minimum. The two are the same for a tight stride (which is every
|
|
280
|
+
// width measured) and differ only by the final row's padding; carrying
|
|
281
|
+
// it costs nothing and keeps `bytes[y * rowBytes + …]` in range for
|
|
282
|
+
// every row, which is how every reader here and in the tests indexes.
|
|
283
|
+
const bytes = api.heapU8().slice(buffer, buffer + rowBytes * height);
|
|
284
|
+
return {
|
|
285
|
+
bytes,
|
|
286
|
+
width,
|
|
287
|
+
height,
|
|
288
|
+
rowBytes,
|
|
289
|
+
format: PDFIUM_FORMAT,
|
|
290
|
+
alpha: PDFIUM_ALPHA,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
api.FPDFBitmap_Destroy(bitmap);
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
close() {
|
|
298
|
+
if (closed)
|
|
299
|
+
return;
|
|
300
|
+
closed = true;
|
|
301
|
+
releasePage();
|
|
302
|
+
api.FPDF_CloseDocument(document);
|
|
303
|
+
// AFTER the close, never before: PDFium reads this buffer for the whole
|
|
304
|
+
// life of the document.
|
|
305
|
+
api.free(dataPointer);
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The web backend's MAIN-THREAD surface.
|
|
3
|
+
*
|
|
4
|
+
* `./worker.ts` is deliberately NOT re-exported. It is an ENTRY POINT, not a
|
|
5
|
+
* module a host imports for its values — it binds itself to `self` at
|
|
6
|
+
* evaluation, and it is the only file that names `@embedpdf/pdfium`, so pulling
|
|
7
|
+
* it in here would drag an optional peer into every web bundle that merely
|
|
8
|
+
* touches the rasterizer registry. It is reached through the package's
|
|
9
|
+
* `./worker` subpath, by a bundler, as a worker.
|
|
10
|
+
*
|
|
11
|
+
* `./engine.ts` and `./session.ts` are re-exported because they are the seam a
|
|
12
|
+
* different host might want: a caller who already owns a PDFium module (a
|
|
13
|
+
* Node-side thumbnail service, an Electron main process) can drive
|
|
14
|
+
* `openPdfiumDocument` directly with no worker at all, which is exactly what the
|
|
15
|
+
* tests do.
|
|
16
|
+
*/
|
|
17
|
+
export { createWebRasterizer } from './client.js';
|
|
18
|
+
export type { WebRasterizerOptions, WorkerLike } from './client.js';
|
|
19
|
+
export { openPdfiumDocument } from './engine.js';
|
|
20
|
+
export type { PdfiumDocument, PdfiumRasterBytes } from './engine.js';
|
|
21
|
+
export { bindPdfium, loadError, mapLoadError, FPDF_ANNOT, FPDF_BITMAP_BGRA, FPDF_REVERSE_BYTE_ORDER, PDFIUM_ERR, } from './pdfium.js';
|
|
22
|
+
export type { PdfiumBinding, PdfiumHeap, PdfiumWasmModule } from './pdfium.js';
|
|
23
|
+
export { createWorkerSession } from './session.js';
|
|
24
|
+
export type { FetchLike, FetchResponseLike, WorkerSession, WorkerSessionDeps, } from './session.js';
|
|
25
|
+
export { isWorkerResponse } from './protocol.js';
|
|
26
|
+
export type { CancelRequest, CloseRequest, ErrorResponse, OpenRequest, OpenedResponse, PdfiumDocumentSource, PdfiumWasmSource, RenderRequest, RenderedResponse, WorkerRequest, WorkerResponse, } from './protocol.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The web backend's MAIN-THREAD surface.
|
|
3
|
+
*
|
|
4
|
+
* `./worker.ts` is deliberately NOT re-exported. It is an ENTRY POINT, not a
|
|
5
|
+
* module a host imports for its values — it binds itself to `self` at
|
|
6
|
+
* evaluation, and it is the only file that names `@embedpdf/pdfium`, so pulling
|
|
7
|
+
* it in here would drag an optional peer into every web bundle that merely
|
|
8
|
+
* touches the rasterizer registry. It is reached through the package's
|
|
9
|
+
* `./worker` subpath, by a bundler, as a worker.
|
|
10
|
+
*
|
|
11
|
+
* `./engine.ts` and `./session.ts` are re-exported because they are the seam a
|
|
12
|
+
* different host might want: a caller who already owns a PDFium module (a
|
|
13
|
+
* Node-side thumbnail service, an Electron main process) can drive
|
|
14
|
+
* `openPdfiumDocument` directly with no worker at all, which is exactly what the
|
|
15
|
+
* tests do.
|
|
16
|
+
*/
|
|
17
|
+
export { createWebRasterizer } from './client.js';
|
|
18
|
+
export { openPdfiumDocument } from './engine.js';
|
|
19
|
+
export { bindPdfium, loadError, mapLoadError, FPDF_ANNOT, FPDF_BITMAP_BGRA, FPDF_REVERSE_BYTE_ORDER, PDFIUM_ERR, } from './pdfium.js';
|
|
20
|
+
export { createWorkerSession } from './session.js';
|
|
21
|
+
export { isWorkerResponse } from './protocol.js';
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PDFium surface this package uses, and the adapter that produces it.
|
|
3
|
+
*
|
|
4
|
+
* ------------------------------------------------------------------------
|
|
5
|
+
* WHY A STRUCTURAL INTERFACE INSTEAD OF `@embedpdf/pdfium`'s OWN TYPE
|
|
6
|
+
* ------------------------------------------------------------------------
|
|
7
|
+
*
|
|
8
|
+
* Same discipline as `AndroidPdfNativeModule` in `../android.ts`, and for the
|
|
9
|
+
* same two reasons.
|
|
10
|
+
*
|
|
11
|
+
* 1. THE ENGINE STAYS PURE AND TESTABLE. `./engine.ts` takes a
|
|
12
|
+
* `PdfiumBinding` and never names the package, so the whole open/geometry/
|
|
13
|
+
* render/error path runs in vitest against the real WASM module — or
|
|
14
|
+
* against a stub — with no worker, no DOM and no bundler in the loop.
|
|
15
|
+
* 2. THE PUBLISHED TYPES CARRY NO PEER. `@embedpdf/pdfium` is an OPTIONAL peer
|
|
16
|
+
* dependency: a consumer who only ships native must not have their build
|
|
17
|
+
* break on a missing module referenced from our `.d.ts`. Nothing in this
|
|
18
|
+
* file imports it, not even as a type. `./worker.ts` is the one module that
|
|
19
|
+
* names it at all, and it exports nothing typed by it.
|
|
20
|
+
*
|
|
21
|
+
* The obvious risk of a hand-written structural type is that it drifts from the
|
|
22
|
+
* real module and nobody notices until runtime. It cannot here: `./worker.ts`
|
|
23
|
+
* calls `bindPdfium(await init(...))` with the genuine `WrappedPdfiumModule`,
|
|
24
|
+
* and that file IS type-checked by `tsc --noEmit`. A wrong arity or a renamed
|
|
25
|
+
* export fails the build.
|
|
26
|
+
*
|
|
27
|
+
* ------------------------------------------------------------------------
|
|
28
|
+
* EVERY CONSTANT AND SEMANTIC BELOW WAS MEASURED AGAINST 2.15.0, NOT READ
|
|
29
|
+
* ------------------------------------------------------------------------
|
|
30
|
+
*
|
|
31
|
+
* The notes that say "measured" mean a script that called the real WASM module
|
|
32
|
+
* under node and printed the answer. See each one.
|
|
33
|
+
*/
|
|
34
|
+
import { PdfError } from '../../types.js';
|
|
35
|
+
import type { PdfErrorCode } from '../../types.js';
|
|
36
|
+
/**
|
|
37
|
+
* `FPDFBitmap_BGRA`. The only four-channel format PDFium's public bitmap API
|
|
38
|
+
* offers, and the one every render path below creates.
|
|
39
|
+
*
|
|
40
|
+
* It describes the BUFFER, not the render: adding `FPDF_REVERSE_BYTE_ORDER` to
|
|
41
|
+
* the render flags leaves the bitmap tagged BGRA while the bytes come out RGBA.
|
|
42
|
+
* That is not a contradiction to fix — the flag is documented as acting on the
|
|
43
|
+
* composite, and it is why `renderPage` derives `PixelFormat` from the FLAGS it
|
|
44
|
+
* passed rather than from the bitmap format it asked for.
|
|
45
|
+
*/
|
|
46
|
+
export declare const FPDF_BITMAP_BGRA = 4;
|
|
47
|
+
/** Draw PDF-embedded annotations. Answers `RasterRequest.annotations`. */
|
|
48
|
+
export declare const FPDF_ANNOT = 1;
|
|
49
|
+
/**
|
|
50
|
+
* Write RGBA instead of BGRA.
|
|
51
|
+
*
|
|
52
|
+
* MEASURED: with the flag, a `0.2 0.4 0.9 rg` fill reads `[51, 102, 230, 255]`;
|
|
53
|
+
* without it, `[230, 102, 51, 255]`. Same bitmap format, swapped R and B.
|
|
54
|
+
*
|
|
55
|
+
* THE WEB BACKEND ALWAYS PASSES IT, and that is a deliberate choice about the
|
|
56
|
+
* INGEST side rather than about PDFium. `imageFromPixels` maps `'bgra8888'` to
|
|
57
|
+
* `ColorType.BGRA_8888`, which CanvasKit exposes but which a GPU-backed build
|
|
58
|
+
* may still refuse from `MakeImage` — and the recovery for that is a full extra
|
|
59
|
+
* pass over the buffer swizzling R and B in JS. RGBA is the configuration every
|
|
60
|
+
* Skia backend accepts, PDFium produces it for free inside the composite it was
|
|
61
|
+
* already doing, and the JS-side fallback pass never runs.
|
|
62
|
+
*/
|
|
63
|
+
export declare const FPDF_REVERSE_BYTE_ORDER = 16;
|
|
64
|
+
/**
|
|
65
|
+
* `FPDF_GetLastError()`'s codes.
|
|
66
|
+
*
|
|
67
|
+
* ONLY MEANINGFUL IMMEDIATELY AFTER A FAILED DOCUMENT LOAD. MEASURED: after
|
|
68
|
+
* loading an encrypted document without a password (which sets 4), a subsequent
|
|
69
|
+
* `FPDF_GetPageSizeByIndexF` for an out-of-range index returns false and leaves
|
|
70
|
+
* the error at 4 — the stale value from the earlier call. So this table is
|
|
71
|
+
* consulted in exactly one place, `mapLoadError`, and every other failure in
|
|
72
|
+
* this backend is decided by its own bounds check or return value.
|
|
73
|
+
*/
|
|
74
|
+
export declare const PDFIUM_ERR: {
|
|
75
|
+
readonly SUCCESS: 0;
|
|
76
|
+
readonly UNKNOWN: 1;
|
|
77
|
+
readonly FILE: 2;
|
|
78
|
+
readonly FORMAT: 3;
|
|
79
|
+
readonly PASSWORD: 4;
|
|
80
|
+
readonly SECURITY: 5;
|
|
81
|
+
readonly PAGE: 6;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The WASM heap, reached through FUNCTIONS rather than a captured view.
|
|
85
|
+
*
|
|
86
|
+
* `heapU8()` is a call and must stay one. Emscripten REPLACES `Module.HEAPU8`
|
|
87
|
+
* whenever the heap grows, so a reference captured at bind time detaches the
|
|
88
|
+
* moment a large bitmap is allocated and every read after that is out of a dead
|
|
89
|
+
* buffer. This is the single easiest way to write a web PDF backend that works
|
|
90
|
+
* on small documents and silently produces garbage on big ones.
|
|
91
|
+
*/
|
|
92
|
+
export interface PdfiumHeap {
|
|
93
|
+
heapU8(): Uint8Array;
|
|
94
|
+
malloc(byteLength: number): number;
|
|
95
|
+
free(pointer: number): void;
|
|
96
|
+
/** Reads an `FS_SIZEF` component — PDFium's float32. */
|
|
97
|
+
getFloat(pointer: number): number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Exactly the PDFium entry points this backend calls. Nothing speculative:
|
|
101
|
+
* text, search, links and form filling are all absent because none of them is
|
|
102
|
+
* implemented, and `RasterizerCapabilities` says so.
|
|
103
|
+
*/
|
|
104
|
+
export interface PdfiumBinding extends PdfiumHeap {
|
|
105
|
+
/**
|
|
106
|
+
* Does NOT copy — the buffer must stay allocated and untouched for the whole
|
|
107
|
+
* life of the document. `./engine.ts` owns that lifetime and frees the
|
|
108
|
+
* pointer in `close()`.
|
|
109
|
+
*/
|
|
110
|
+
FPDF_LoadMemDocument(dataPointer: number, byteLength: number, password: string): number;
|
|
111
|
+
FPDF_CloseDocument(document: number): void;
|
|
112
|
+
FPDF_GetLastError(): number;
|
|
113
|
+
FPDF_GetPageCount(document: number): number;
|
|
114
|
+
/**
|
|
115
|
+
* Writes an `FS_SIZEF` (two float32s) and does NOT parse the page's content
|
|
116
|
+
* stream — PDFium builds a bare `CPDF_Page` from the page dictionary and reads
|
|
117
|
+
* its dimensions. That is what makes `RasterizerHandle.pageGeometry`
|
|
118
|
+
* synchronous and cheap: every page is measured once at open.
|
|
119
|
+
*
|
|
120
|
+
* MEASURED, and it is the whole reason `/Rotate` needs no arithmetic here: for
|
|
121
|
+
* a 200x100 MediaBox with `/Rotate 90` it reports 100x200, and for a 280x360
|
|
122
|
+
* CropBox with `/Rotate 270` it reports 360x280. CropBox, intersected with
|
|
123
|
+
* MediaBox, AFTER rotation — which is precisely what `PageGeometry.width` and
|
|
124
|
+
* `.height` are defined as.
|
|
125
|
+
*
|
|
126
|
+
* Contrast `EPDF_GetPageSizeByIndexNormalized`, which sounds like the one you
|
|
127
|
+
* want and is the opposite: it normalises the rotation AWAY and reports
|
|
128
|
+
* 200x100 for the same rotated page.
|
|
129
|
+
*/
|
|
130
|
+
FPDF_GetPageSizeByIndexF(document: number, index: number, sizeOut: number): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* `@embedpdf/pdfium`'s extension. Returns PDFium's rotation INDEX — 0, 1, 2 or
|
|
133
|
+
* 3 for 0/90/180/270 — or -1 for an index the document does not have
|
|
134
|
+
* (measured). The plain `FPDFPage_GetRotation` would need a loaded page, which
|
|
135
|
+
* is exactly what `pageGeometry` is forbidden to do.
|
|
136
|
+
*/
|
|
137
|
+
EPDF_GetPageRotationByIndex(document: number, index: number): number;
|
|
138
|
+
FPDF_LoadPage(document: number, index: number): number;
|
|
139
|
+
FPDF_ClosePage(page: number): void;
|
|
140
|
+
/**
|
|
141
|
+
* `firstScan: 0` lets PDFium allocate; `stride: 0` lets it choose. Returns 0
|
|
142
|
+
* when the allocation fails, which is the only out-of-memory signal there is
|
|
143
|
+
* (measured: a 100000x100000 request returns 0 rather than throwing).
|
|
144
|
+
*/
|
|
145
|
+
FPDFBitmap_CreateEx(width: number, height: number, format: number, firstScan: number, stride: number): number;
|
|
146
|
+
FPDFBitmap_Destroy(bitmap: number): void;
|
|
147
|
+
/** `color` is ARGB, so 0xFFFFFFFF is opaque white and 0 is transparent. */
|
|
148
|
+
FPDFBitmap_FillRect(bitmap: number, left: number, top: number, width: number, height: number, color: number): boolean;
|
|
149
|
+
FPDFBitmap_GetBuffer(bitmap: number): number;
|
|
150
|
+
FPDFBitmap_GetStride(bitmap: number): number;
|
|
151
|
+
FPDF_RenderPageBitmap(bitmap: number, page: number, startX: number, startY: number, sizeX: number, sizeY: number, rotate: number, flags: number): void;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The shape of `@embedpdf/pdfium`'s `WrappedPdfiumModule`, restated as the
|
|
155
|
+
* subset this package touches.
|
|
156
|
+
*
|
|
157
|
+
* `PdfiumRuntimeMethods.wasmExports` is where `malloc` / `free` live; the FPDF_*
|
|
158
|
+
* entries are `cwrap`ped onto the wrapper object itself.
|
|
159
|
+
*/
|
|
160
|
+
export interface PdfiumWasmModule {
|
|
161
|
+
pdfium: {
|
|
162
|
+
HEAPU8: Uint8Array;
|
|
163
|
+
/**
|
|
164
|
+
* `number | bigint` because Emscripten's `getValue` reads `i64` too. This
|
|
165
|
+
* backend only ever asks for `'float'`, so the bigint arm is unreachable —
|
|
166
|
+
* but the declaration is the real one, and `bindPdfium` narrows rather than
|
|
167
|
+
* asserting. (This is the drift check working: the first hand-written
|
|
168
|
+
* signature said `number`, and `tsc` refused the real module.)
|
|
169
|
+
*/
|
|
170
|
+
getValue(pointer: number, type: string): number | bigint;
|
|
171
|
+
wasmExports: {
|
|
172
|
+
malloc(byteLength: number): number;
|
|
173
|
+
free(pointer: number): void;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
/** Initialises the library. Must be called once before anything else. */
|
|
177
|
+
PDFiumExt_Init(): null;
|
|
178
|
+
FPDF_LoadMemDocument(dataPointer: number, byteLength: number, password: string): number;
|
|
179
|
+
FPDF_CloseDocument(document: number): null;
|
|
180
|
+
FPDF_GetLastError(): number;
|
|
181
|
+
FPDF_GetPageCount(document: number): number;
|
|
182
|
+
FPDF_GetPageSizeByIndexF(document: number, index: number, sizeOut: number): boolean;
|
|
183
|
+
EPDF_GetPageRotationByIndex(document: number, index: number): number;
|
|
184
|
+
FPDF_LoadPage(document: number, index: number): number;
|
|
185
|
+
FPDF_ClosePage(page: number): null;
|
|
186
|
+
FPDFBitmap_CreateEx(width: number, height: number, format: number, firstScan: number, stride: number): number;
|
|
187
|
+
FPDFBitmap_Destroy(bitmap: number): null;
|
|
188
|
+
FPDFBitmap_FillRect(bitmap: number, left: number, top: number, width: number, height: number, color: number): boolean;
|
|
189
|
+
FPDFBitmap_GetBuffer(bitmap: number): number;
|
|
190
|
+
FPDFBitmap_GetStride(bitmap: number): number;
|
|
191
|
+
FPDF_RenderPageBitmap(bitmap: number, page: number, startX: number, startY: number, sizeX: number, sizeY: number, rotate: number, flags: number): null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Turn an initialised `@embedpdf/pdfium` module into a `PdfiumBinding`.
|
|
195
|
+
*
|
|
196
|
+
* Deliberately mechanical. The only judgement in here is `heapU8`, which reads
|
|
197
|
+
* `HEAPU8` off the module on EVERY call rather than closing over it — see
|
|
198
|
+
* `PdfiumHeap`.
|
|
199
|
+
*/
|
|
200
|
+
export declare function bindPdfium(module: PdfiumWasmModule): PdfiumBinding;
|
|
201
|
+
/**
|
|
202
|
+
* `FPDF_GetLastError()` after a failed load -> the frozen `PdfErrorCode` union.
|
|
203
|
+
*
|
|
204
|
+
* `passwordSupplied` is what tells the two password outcomes apart, and it has
|
|
205
|
+
* to: MEASURED, PDFium returns 4 both for an encrypted document opened with no
|
|
206
|
+
* password and for one opened with the WRONG password. There is no code that
|
|
207
|
+
* distinguishes them, so the caller's own knowledge does — and the distinction
|
|
208
|
+
* matters, because one of them means "prompt the user" and the other means
|
|
209
|
+
* "tell them they got it wrong".
|
|
210
|
+
*/
|
|
211
|
+
export declare function mapLoadError(error: number, passwordSupplied: boolean): PdfErrorCode;
|
|
212
|
+
/** The load failure, as the error a host can branch on. */
|
|
213
|
+
export declare function loadError(error: number, passwordSupplied: boolean): PdfError;
|