@reekon-tools/react-native-pdf-canvas 0.1.1 → 0.2.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/LICENSE +202 -0
- package/NOTICE +57 -0
- package/PdfCanvas.podspec +68 -39
- package/README.md +213 -1316
- package/android/build.gradle +67 -54
- package/android/consumer-rules.pro +7 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasNativeTest.java +254 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/TestPdfs.java +60 -468
- package/android/src/main/cpp/CMakeLists.txt +54 -0
- package/android/src/main/cpp/pdfcanvas-jni.cpp +262 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasNative.java +167 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfErrorCode.java +14 -4
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRasterException.java +10 -4
- package/android/src/reactnative/java/tools/reekon/pdfcanvas/rn/PdfCanvasModule.java +160 -376
- package/android/tools/compile-gate.sh +81 -101
- package/dist/controller.d.ts +14 -0
- package/dist/controller.js +4 -3
- package/dist/rasterizer/index.native.d.ts +8 -12
- package/dist/rasterizer/index.native.js +15 -21
- package/dist/rasterizer/native-bridge.d.ts +51 -75
- package/dist/rasterizer/native-bridge.js +49 -33
- package/dist/rasterizer/native.d.ts +45 -0
- package/dist/rasterizer/native.js +123 -0
- package/dist/react/usePdfDocument.d.ts +5 -5
- package/dist/react/usePdfLayer.d.ts +10 -1
- package/dist/react/usePdfLayer.js +10 -2
- package/dist/testing/scenes.d.ts +3 -3
- package/dist/testing/scenes.js +4 -4
- package/dist/types.d.ts +36 -42
- package/ios/Sources/PdfCanvasBridge/PdfCanvasModule.mm +234 -536
- package/native/.clangd +5 -0
- package/native/CMakeLists.txt +89 -0
- package/native/core/include/pdfcanvas/document.h +90 -0
- package/native/core/include/pdfcanvas/error.h +47 -0
- package/native/core/include/pdfcanvas/jsi.h +18 -0
- package/native/core/include/pdfcanvas/jsi_config.h +30 -0
- package/native/core/include/pdfcanvas/library.h +28 -0
- package/native/core/include/pdfcanvas/pixels.h +92 -0
- package/native/core/include/pdfcanvas/service.h +87 -0
- package/native/core/include/pdfcanvas/slots.h +113 -0
- package/native/core/include/pdfcanvas/types.h +110 -0
- package/native/core/pdfcanvas-core.cmake +22 -0
- package/native/core/src/document.cpp +516 -0
- package/native/core/src/error.cpp +29 -0
- package/native/core/src/jsi.cpp +66 -0
- package/native/core/src/library.cpp +52 -0
- package/native/core/src/pixels.cpp +45 -0
- package/native/core/src/service.cpp +156 -0
- package/native/core/src/slots.cpp +139 -0
- package/native/tests/fixtures.cpp +451 -0
- package/native/tests/fixtures.h +96 -0
- package/native/tests/harness.h +122 -0
- package/native/tests/main.cpp +64 -0
- package/native/tests/pixels_util.h +126 -0
- package/native/tests/test_document.cpp +485 -0
- package/native/tests/test_service.cpp +130 -0
- package/native/tests/test_slots.cpp +250 -0
- package/package.json +27 -7
- package/react-native.config.js +5 -2
- package/scripts/fetch-pdfium.mjs +487 -0
- package/scripts/pdfium-manifest.json +46 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasCancellationTest.java +0 -226
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasConcurrencyTest.java +0 -239
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasDeviceTimingTest.java +0 -251
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasFailureTest.java +0 -221
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasJsiTransportTest.java +0 -783
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPhaseTimingTest.java +0 -1388
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPoisonGuardTest.java +0 -98
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasQuirksTest.java +0 -324
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasRasterizerTest.java +0 -775
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PoisonsTheProcess.java +0 -20
- package/android/src/jsi/cpp/CMakeLists.txt +0 -33
- package/android/src/jsi/cpp/pdfcanvas-jsi.cpp +0 -469
- package/android/src/jsi/java/tools/reekon/pdfcanvas/jsi/PdfCanvasPixelBridge.java +0 -140
- package/android/src/main/java/tools/reekon/pdfcanvas/PageGeometry.java +0 -45
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasRasterizer.java +0 -564
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPlatformQuirks.java +0 -277
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPreflight.java +0 -214
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRendererPool.java +0 -234
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterCancellation.java +0 -47
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterPixels.java +0 -143
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterRequest.java +0 -95
- package/dist/rasterizer/android.d.ts +0 -121
- package/dist/rasterizer/android.js +0 -126
- package/dist/rasterizer/ios.d.ts +0 -84
- package/dist/rasterizer/ios.js +0 -155
- package/ios/Package.swift +0 -58
- package/ios/Sources/PdfCanvasCore/PdfCanvasCancellation.m +0 -38
- package/ios/Sources/PdfCanvasCore/PdfCanvasDocumentPool.m +0 -389
- package/ios/Sources/PdfCanvasCore/PdfCanvasErrorCode.m +0 -57
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageGeometry.m +0 -44
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageTransform.m +0 -82
- package/ios/Sources/PdfCanvasCore/PdfCanvasPixelSink.m +0 -37
- package/ios/Sources/PdfCanvasCore/PdfCanvasPreflight.m +0 -158
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterPixels.m +0 -80
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterRequest.m +0 -65
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterizer.m +0 -548
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCancellation.h +0 -48
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCore.h +0 -26
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasDocumentPool.h +0 -122
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasErrorCode.h +0 -80
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageGeometry.h +0 -79
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageTransform.h +0 -129
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPixelSink.h +0 -100
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPreflight.h +0 -65
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterPixels.h +0 -111
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterRequest.h +0 -85
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterizer.h +0 -163
- package/ios/Sources/PdfCanvasSlots/PdfCanvasSlots.mm +0 -297
- package/ios/Sources/PdfCanvasSlots/include/PdfCanvasSlots.h +0 -140
- package/ios/Tests/PdfCanvasCoreTests/ConcurrencyTests.swift +0 -358
- package/ios/Tests/PdfCanvasCoreTests/FailureTests.swift +0 -262
- package/ios/Tests/PdfCanvasCoreTests/GeometryTests.swift +0 -173
- package/ios/Tests/PdfCanvasCoreTests/PreviewTests.swift +0 -114
- package/ios/Tests/PdfCanvasCoreTests/RasterAssertions.swift +0 -158
- package/ios/Tests/PdfCanvasCoreTests/RasterizerTests.swift +0 -544
- package/ios/Tests/PdfCanvasCoreTests/SinkTests.swift +0 -287
- package/ios/Tests/PdfCanvasCoreTests/SlotsTests.swift +0 -396
- package/ios/Tests/PdfCanvasCoreTests/TestPdfs.swift +0 -639
- package/ios/Tests/PdfCanvasCoreTests/TimingTests.swift +0 -179
- package/ios/Tests/PdfCanvasCoreTests/TransformTests.swift +0 -283
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Fetches the pinned PDFium binaries this package renders with.
|
|
4
|
+
*
|
|
5
|
+
* ONE SCRIPT, THREE CONSUMERS, ONE MANIFEST.
|
|
6
|
+
*
|
|
7
|
+
* node scripts/fetch-pdfium.mjs android [--abis arm64-v8a,armeabi-v7a,x86,x86_64]
|
|
8
|
+
* -> native/.pdfium/android/include/*.h
|
|
9
|
+
* native/.pdfium/android/jniLibs/<abi>/libpdfium.so
|
|
10
|
+
* Called by android/build.gradle before CMake configures. The ABI list is
|
|
11
|
+
* whatever the app asked for (`reactNativeArchitectures`), so the AAR never
|
|
12
|
+
* carries an ABI the app does not.
|
|
13
|
+
*
|
|
14
|
+
* node scripts/fetch-pdfium.mjs ios
|
|
15
|
+
* -> native/.pdfium/ios/include/*.h
|
|
16
|
+
* native/.pdfium/ios/PDFium.xcframework (device arm64 + simulator arm64/x64)
|
|
17
|
+
* Called from PdfCanvas.podspec while CocoaPods evaluates it. Needs macOS:
|
|
18
|
+
* the xcframework is assembled with `lipo`, `install_name_tool` and
|
|
19
|
+
* `xcodebuild -create-xcframework`, which exist wherever `pod install` runs.
|
|
20
|
+
*
|
|
21
|
+
* node scripts/fetch-pdfium.mjs host [--target win-x64|mac-arm64|mac-x64|linux-x64]
|
|
22
|
+
* -> native/.pdfium/host/{include,lib,bin}
|
|
23
|
+
* For `native/tests`, the laptop proof of the C++ core. Defaults to the
|
|
24
|
+
* machine it runs on.
|
|
25
|
+
*
|
|
26
|
+
* EVERY DOWNLOAD IS VERIFIED against the SHA-256 in `pdfium-manifest.json`
|
|
27
|
+
* before a single byte of it is extracted, and a mismatch deletes the file and
|
|
28
|
+
* fails the build. The digests come from the release's own SLSA attestation
|
|
29
|
+
* (`pdfium-attestation.json`), not from a first download — a manifest that
|
|
30
|
+
* records whatever the network happened to return is a manifest that pins
|
|
31
|
+
* nothing.
|
|
32
|
+
*
|
|
33
|
+
* IDEMPOTENT AND CHEAP WHEN DONE. A `.stamp` file records the release tag each
|
|
34
|
+
* output was produced from; a run that finds a matching stamp does nothing, so
|
|
35
|
+
* calling this from every Gradle configure and every `pod install` costs a stat.
|
|
36
|
+
*
|
|
37
|
+
* OFFLINE / AIR-GAPPED BUILDS. `PDFCANVAS_PDFIUM_MIRROR` replaces the GitHub
|
|
38
|
+
* base URL (same file names, e.g. an internal artifact store), and
|
|
39
|
+
* `PDFCANVAS_PDFIUM_CACHE` names a directory of already-downloaded `.tgz` files
|
|
40
|
+
* that is consulted before the network. Both still verify the digest.
|
|
41
|
+
*
|
|
42
|
+
* NO DEPENDENCIES, by the same rule as the rest of `scripts/`: this runs from a
|
|
43
|
+
* consumer's install where none of this package's devDependencies exist.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import {createHash} from 'node:crypto';
|
|
47
|
+
import {
|
|
48
|
+
createWriteStream,
|
|
49
|
+
existsSync,
|
|
50
|
+
mkdirSync,
|
|
51
|
+
readFileSync,
|
|
52
|
+
renameSync,
|
|
53
|
+
rmSync,
|
|
54
|
+
statSync,
|
|
55
|
+
writeFileSync,
|
|
56
|
+
cpSync,
|
|
57
|
+
readdirSync,
|
|
58
|
+
} from 'node:fs';
|
|
59
|
+
import {tmpdir} from 'node:os';
|
|
60
|
+
import {dirname, join, resolve} from 'node:path';
|
|
61
|
+
import {execFileSync} from 'node:child_process';
|
|
62
|
+
import {fileURLToPath} from 'node:url';
|
|
63
|
+
import {pipeline} from 'node:stream/promises';
|
|
64
|
+
import {Readable} from 'node:stream';
|
|
65
|
+
|
|
66
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
67
|
+
const root = resolve(here, '..');
|
|
68
|
+
const manifestPath = join(here, 'pdfium-manifest.json');
|
|
69
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
70
|
+
|
|
71
|
+
/** Where every output lands. Gitignored; the stamp files make it self-healing. */
|
|
72
|
+
const outputRoot =
|
|
73
|
+
process.env.PDFCANVAS_PDFIUM_OUT ?? join(root, 'native', '.pdfium');
|
|
74
|
+
|
|
75
|
+
const baseUrl = (
|
|
76
|
+
process.env.PDFCANVAS_PDFIUM_MIRROR ?? manifest.baseUrl
|
|
77
|
+
).replace(/\/+$/, '');
|
|
78
|
+
|
|
79
|
+
/* ------------------------------------------------------------------ *
|
|
80
|
+
* Arguments
|
|
81
|
+
* ------------------------------------------------------------------ */
|
|
82
|
+
|
|
83
|
+
const [, , command, ...rest] = process.argv;
|
|
84
|
+
const flags = new Map();
|
|
85
|
+
for (let i = 0; i < rest.length; i++) {
|
|
86
|
+
const arg = rest[i];
|
|
87
|
+
if (arg.startsWith('--')) {
|
|
88
|
+
const key = arg.slice(2);
|
|
89
|
+
const value =
|
|
90
|
+
rest[i + 1] !== undefined && !rest[i + 1].startsWith('--')
|
|
91
|
+
? rest[++i]
|
|
92
|
+
: 'true';
|
|
93
|
+
flags.set(key, value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function usage(code) {
|
|
98
|
+
console.error(
|
|
99
|
+
'usage: fetch-pdfium.mjs android [--abis a,b] | ios | host [--target t] | print-version',
|
|
100
|
+
);
|
|
101
|
+
process.exit(code);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ------------------------------------------------------------------ *
|
|
105
|
+
* Download + verify
|
|
106
|
+
* ------------------------------------------------------------------ */
|
|
107
|
+
|
|
108
|
+
function sha256File(path) {
|
|
109
|
+
const hash = createHash('sha256');
|
|
110
|
+
hash.update(readFileSync(path));
|
|
111
|
+
return hash.digest('hex');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function artifactUrl(name) {
|
|
115
|
+
return `${baseUrl}/${manifest.release}/pdfium-${name}.tgz`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns the path of a verified `.tgz` for `name`, downloading if needed.
|
|
120
|
+
*
|
|
121
|
+
* Downloads go to a temp file and are renamed into place only after the digest
|
|
122
|
+
* matches, so a half-written or tampered file can never be mistaken for a good
|
|
123
|
+
* one on the next run.
|
|
124
|
+
*/
|
|
125
|
+
async function fetchArtifact(name) {
|
|
126
|
+
const entry = manifest.artifacts[name];
|
|
127
|
+
if (!entry) {
|
|
128
|
+
throw new Error(`pdfium-manifest.json has no artifact named "${name}".`);
|
|
129
|
+
}
|
|
130
|
+
const cacheDir =
|
|
131
|
+
process.env.PDFCANVAS_PDFIUM_CACHE ?? join(outputRoot, 'downloads');
|
|
132
|
+
mkdirSync(cacheDir, {recursive: true});
|
|
133
|
+
const fileName = `pdfium-${name}-${manifest.release.replace('/', '-')}.tgz`;
|
|
134
|
+
const cached = join(cacheDir, fileName);
|
|
135
|
+
|
|
136
|
+
if (existsSync(cached)) {
|
|
137
|
+
const digest = sha256File(cached);
|
|
138
|
+
if (digest === entry.sha256) return cached;
|
|
139
|
+
console.warn(
|
|
140
|
+
`[pdfium] cached ${fileName} has digest ${digest}; re-downloading`,
|
|
141
|
+
);
|
|
142
|
+
rmSync(cached);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const url = artifactUrl(name);
|
|
146
|
+
console.log(`[pdfium] downloading ${url}`);
|
|
147
|
+
const response = await fetch(url, {redirect: 'follow'});
|
|
148
|
+
if (!response.ok || response.body === null) {
|
|
149
|
+
throw new Error(`Could not download ${url}: HTTP ${response.status}`);
|
|
150
|
+
}
|
|
151
|
+
const partial = `${cached}.part`;
|
|
152
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(partial));
|
|
153
|
+
|
|
154
|
+
const digest = sha256File(partial);
|
|
155
|
+
if (digest !== entry.sha256) {
|
|
156
|
+
rmSync(partial);
|
|
157
|
+
throw new Error(
|
|
158
|
+
`SHA-256 mismatch for ${url}:\n expected ${entry.sha256}\n got ${digest}\n` +
|
|
159
|
+
'Refusing to use it. If the release was re-uploaded, update ' +
|
|
160
|
+
'scripts/pdfium-manifest.json from the release attestation.',
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
renameSync(partial, cached);
|
|
164
|
+
return cached;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The tar to extract with.
|
|
169
|
+
*
|
|
170
|
+
* On Windows this is ALWAYS the system bsdtar, named by absolute path. A
|
|
171
|
+
* developer shell here usually has MSYS (Git Bash) tar first on PATH, and GNU
|
|
172
|
+
* tar reads `C:\...` as `host:path` and tries to connect to a machine called
|
|
173
|
+
* `C` — the failure reads "Cannot connect to C: resolve failed", which is a
|
|
174
|
+
* long way from "wrong tar". Windows 10 1803+ ships bsdtar at System32.
|
|
175
|
+
*/
|
|
176
|
+
function tarBinary() {
|
|
177
|
+
if (process.platform === 'win32') {
|
|
178
|
+
const system = join(
|
|
179
|
+
process.env.SystemRoot ?? 'C:\\Windows',
|
|
180
|
+
'System32',
|
|
181
|
+
'tar.exe',
|
|
182
|
+
);
|
|
183
|
+
if (existsSync(system)) return system;
|
|
184
|
+
}
|
|
185
|
+
return 'tar';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function extract(tgz, into) {
|
|
189
|
+
mkdirSync(into, {recursive: true});
|
|
190
|
+
// `tar` exists on every platform this runs on: macOS and Linux natively, and
|
|
191
|
+
// Windows 10+ ships bsdtar. Node has no built-in tar and this script may not
|
|
192
|
+
// take a dependency.
|
|
193
|
+
execFileSync(tarBinary(), ['-xzf', tgz, '-C', into], {stdio: 'inherit'});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* ------------------------------------------------------------------ *
|
|
197
|
+
* Stamps
|
|
198
|
+
* ------------------------------------------------------------------ */
|
|
199
|
+
|
|
200
|
+
function stampPath(dir) {
|
|
201
|
+
return join(dir, '.stamp');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function isFresh(dir, key) {
|
|
205
|
+
const stamp = stampPath(dir);
|
|
206
|
+
return existsSync(stamp) && readFileSync(stamp, 'utf8').trim() === key;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function writeStamp(dir, key) {
|
|
210
|
+
writeFileSync(stampPath(dir), `${key}\n`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function resetDir(dir) {
|
|
214
|
+
rmSync(dir, {recursive: true, force: true});
|
|
215
|
+
mkdirSync(dir, {recursive: true});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Copies PDFium's public headers, dropping the `.orig` file the release carries. */
|
|
219
|
+
function copyHeaders(from, to) {
|
|
220
|
+
mkdirSync(to, {recursive: true});
|
|
221
|
+
for (const name of readdirSync(from)) {
|
|
222
|
+
if (name.endsWith('.orig')) continue;
|
|
223
|
+
cpSync(join(from, name), join(to, name), {recursive: true});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* ------------------------------------------------------------------ *
|
|
228
|
+
* android
|
|
229
|
+
* ------------------------------------------------------------------ */
|
|
230
|
+
|
|
231
|
+
const ANDROID_ARTIFACT_BY_ABI = Object.fromEntries(
|
|
232
|
+
Object.entries(manifest.artifacts)
|
|
233
|
+
.filter(([, value]) => typeof value.abi === 'string')
|
|
234
|
+
.map(([name, value]) => [value.abi, name]),
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
async function android() {
|
|
238
|
+
const abis = (
|
|
239
|
+
flags.get('abis') ?? Object.keys(ANDROID_ARTIFACT_BY_ABI).join(',')
|
|
240
|
+
)
|
|
241
|
+
.split(',')
|
|
242
|
+
.map(s => s.trim())
|
|
243
|
+
.filter(Boolean);
|
|
244
|
+
for (const abi of abis) {
|
|
245
|
+
if (!ANDROID_ARTIFACT_BY_ABI[abi]) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
`No PDFium build for ABI "${abi}". Known: ${Object.keys(ANDROID_ARTIFACT_BY_ABI).join(', ')}`,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const out = join(outputRoot, 'android');
|
|
252
|
+
const key = `${manifest.release} ${[...abis].sort().join(',')}`;
|
|
253
|
+
if (isFresh(out, key)) {
|
|
254
|
+
console.log(
|
|
255
|
+
`[pdfium] android: ${manifest.release} for ${abis.join(', ')} already present`,
|
|
256
|
+
);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
resetDir(out);
|
|
260
|
+
let headersCopied = false;
|
|
261
|
+
for (const abi of abis) {
|
|
262
|
+
const tgz = await fetchArtifact(ANDROID_ARTIFACT_BY_ABI[abi]);
|
|
263
|
+
const scratch = join(out, `.extract-${abi}`);
|
|
264
|
+
extract(tgz, scratch);
|
|
265
|
+
const libDir = join(out, 'jniLibs', abi);
|
|
266
|
+
mkdirSync(libDir, {recursive: true});
|
|
267
|
+
cpSync(join(scratch, 'lib', 'libpdfium.so'), join(libDir, 'libpdfium.so'));
|
|
268
|
+
if (!headersCopied) {
|
|
269
|
+
copyHeaders(join(scratch, 'include'), join(out, 'include'));
|
|
270
|
+
cpSync(join(scratch, 'LICENSE'), join(out, 'LICENSE'));
|
|
271
|
+
cpSync(join(scratch, 'licenses'), join(out, 'licenses'), {
|
|
272
|
+
recursive: true,
|
|
273
|
+
});
|
|
274
|
+
headersCopied = true;
|
|
275
|
+
}
|
|
276
|
+
rmSync(scratch, {recursive: true, force: true});
|
|
277
|
+
}
|
|
278
|
+
writeStamp(out, key);
|
|
279
|
+
console.log(`[pdfium] android: ready at ${out}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* ------------------------------------------------------------------ *
|
|
283
|
+
* ios
|
|
284
|
+
* ------------------------------------------------------------------ */
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Wraps a bare dylib as an iOS `PDFium.framework` (shallow bundle) so it can be
|
|
288
|
+
* embedded and code-signed like any other framework. Mirrors what
|
|
289
|
+
* espresso3389/pdfium-xcframework's build.sh does, minus the macOS/Catalyst
|
|
290
|
+
* slices this package does not ship.
|
|
291
|
+
*/
|
|
292
|
+
function makeIosFramework(dylib, frameworkDir, headersDir, platform) {
|
|
293
|
+
resetDir(frameworkDir);
|
|
294
|
+
const binary = join(frameworkDir, 'PDFium');
|
|
295
|
+
cpSync(dylib, binary);
|
|
296
|
+
execFileSync('chmod', ['+w', binary]);
|
|
297
|
+
execFileSync(
|
|
298
|
+
'install_name_tool',
|
|
299
|
+
['-id', '@rpath/PDFium.framework/PDFium', binary],
|
|
300
|
+
{
|
|
301
|
+
stdio: 'inherit',
|
|
302
|
+
},
|
|
303
|
+
);
|
|
304
|
+
copyHeaders(headersDir, join(frameworkDir, 'Headers'));
|
|
305
|
+
const shortVersion = manifest.version.split('.').slice(0, 3).join('.');
|
|
306
|
+
writeFileSync(
|
|
307
|
+
join(frameworkDir, 'Info.plist'),
|
|
308
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
309
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
310
|
+
<plist version="1.0">
|
|
311
|
+
<dict>
|
|
312
|
+
<key>CFBundleExecutable</key>
|
|
313
|
+
<string>PDFium</string>
|
|
314
|
+
<key>CFBundleIdentifier</key>
|
|
315
|
+
<string>tools.reekon.pdfcanvas.PDFium</string>
|
|
316
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
317
|
+
<string>6.0</string>
|
|
318
|
+
<key>CFBundleName</key>
|
|
319
|
+
<string>PDFium</string>
|
|
320
|
+
<key>CFBundlePackageType</key>
|
|
321
|
+
<string>FMWK</string>
|
|
322
|
+
<key>CFBundleShortVersionString</key>
|
|
323
|
+
<string>${shortVersion}</string>
|
|
324
|
+
<key>CFBundleVersion</key>
|
|
325
|
+
<string>${manifest.version}</string>
|
|
326
|
+
<key>CFBundleSupportedPlatforms</key>
|
|
327
|
+
<array>
|
|
328
|
+
<string>${platform}</string>
|
|
329
|
+
</array>
|
|
330
|
+
<key>MinimumOSVersion</key>
|
|
331
|
+
<string>13.0</string>
|
|
332
|
+
</dict>
|
|
333
|
+
</plist>
|
|
334
|
+
`,
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function ios() {
|
|
339
|
+
if (process.platform !== 'darwin') {
|
|
340
|
+
throw new Error(
|
|
341
|
+
'The iOS target assembles an xcframework with lipo/install_name_tool/xcodebuild ' +
|
|
342
|
+
'and must run on macOS (it is invoked by `pod install`).',
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
const out = join(outputRoot, 'ios');
|
|
346
|
+
const key = manifest.release;
|
|
347
|
+
if (isFresh(out, key)) {
|
|
348
|
+
console.log(`[pdfium] ios: ${manifest.release} already present`);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
resetDir(out);
|
|
352
|
+
const work = join(out, '.work');
|
|
353
|
+
mkdirSync(work, {recursive: true});
|
|
354
|
+
|
|
355
|
+
const slices = {};
|
|
356
|
+
for (const name of [
|
|
357
|
+
'ios-device-arm64',
|
|
358
|
+
'ios-simulator-arm64',
|
|
359
|
+
'ios-simulator-x64',
|
|
360
|
+
]) {
|
|
361
|
+
const dir = join(work, name);
|
|
362
|
+
extract(await fetchArtifact(name), dir);
|
|
363
|
+
slices[name] = dir;
|
|
364
|
+
}
|
|
365
|
+
copyHeaders(
|
|
366
|
+
join(slices['ios-device-arm64'], 'include'),
|
|
367
|
+
join(out, 'include'),
|
|
368
|
+
);
|
|
369
|
+
cpSync(join(slices['ios-device-arm64'], 'LICENSE'), join(out, 'LICENSE'));
|
|
370
|
+
cpSync(join(slices['ios-device-arm64'], 'licenses'), join(out, 'licenses'), {
|
|
371
|
+
recursive: true,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Both simulator architectures have to be ONE fat dylib: an xcframework holds
|
|
375
|
+
// one library per (platform, variant), so two simulator slices must be lipo'd.
|
|
376
|
+
const simulatorFat = join(work, 'libpdfium-simulator.dylib');
|
|
377
|
+
execFileSync(
|
|
378
|
+
'lipo',
|
|
379
|
+
[
|
|
380
|
+
'-create',
|
|
381
|
+
join(slices['ios-simulator-arm64'], 'lib', 'libpdfium.dylib'),
|
|
382
|
+
join(slices['ios-simulator-x64'], 'lib', 'libpdfium.dylib'),
|
|
383
|
+
'-output',
|
|
384
|
+
simulatorFat,
|
|
385
|
+
],
|
|
386
|
+
{stdio: 'inherit'},
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const deviceFramework = join(work, 'device', 'PDFium.framework');
|
|
390
|
+
const simulatorFramework = join(work, 'simulator', 'PDFium.framework');
|
|
391
|
+
makeIosFramework(
|
|
392
|
+
join(slices['ios-device-arm64'], 'lib', 'libpdfium.dylib'),
|
|
393
|
+
deviceFramework,
|
|
394
|
+
join(out, 'include'),
|
|
395
|
+
'iPhoneOS',
|
|
396
|
+
);
|
|
397
|
+
makeIosFramework(
|
|
398
|
+
simulatorFat,
|
|
399
|
+
simulatorFramework,
|
|
400
|
+
join(out, 'include'),
|
|
401
|
+
'iPhoneSimulator',
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
const xcframework = join(out, 'PDFium.xcframework');
|
|
405
|
+
execFileSync(
|
|
406
|
+
'xcodebuild',
|
|
407
|
+
[
|
|
408
|
+
'-create-xcframework',
|
|
409
|
+
'-framework',
|
|
410
|
+
deviceFramework,
|
|
411
|
+
'-framework',
|
|
412
|
+
simulatorFramework,
|
|
413
|
+
'-output',
|
|
414
|
+
xcframework,
|
|
415
|
+
],
|
|
416
|
+
{stdio: 'inherit'},
|
|
417
|
+
);
|
|
418
|
+
rmSync(work, {recursive: true, force: true});
|
|
419
|
+
writeStamp(out, key);
|
|
420
|
+
console.log(`[pdfium] ios: ready at ${xcframework}`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* ------------------------------------------------------------------ *
|
|
424
|
+
* host
|
|
425
|
+
* ------------------------------------------------------------------ */
|
|
426
|
+
|
|
427
|
+
function defaultHostTarget() {
|
|
428
|
+
const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
|
|
429
|
+
switch (process.platform) {
|
|
430
|
+
case 'win32':
|
|
431
|
+
return 'win-x64';
|
|
432
|
+
case 'darwin':
|
|
433
|
+
return `mac-${arch}`;
|
|
434
|
+
case 'linux':
|
|
435
|
+
return 'linux-x64';
|
|
436
|
+
default:
|
|
437
|
+
throw new Error(
|
|
438
|
+
`No PDFium host build for ${process.platform}/${process.arch}.`,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function host() {
|
|
444
|
+
const target = flags.get('target') ?? defaultHostTarget();
|
|
445
|
+
const out = join(outputRoot, 'host');
|
|
446
|
+
const key = `${manifest.release} ${target}`;
|
|
447
|
+
if (isFresh(out, key)) {
|
|
448
|
+
console.log(`[pdfium] host: ${manifest.release} ${target} already present`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
resetDir(out);
|
|
452
|
+
extract(await fetchArtifact(target), out);
|
|
453
|
+
// The release's headers dir carries `fpdfview.h.orig`; drop it so an include
|
|
454
|
+
// path sweep never picks up the wrong one.
|
|
455
|
+
const orig = join(out, 'include', 'fpdfview.h.orig');
|
|
456
|
+
if (existsSync(orig)) rmSync(orig);
|
|
457
|
+
writeStamp(out, key);
|
|
458
|
+
console.log(`[pdfium] host: ready at ${out}`);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* ------------------------------------------------------------------ *
|
|
462
|
+
* main
|
|
463
|
+
* ------------------------------------------------------------------ */
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
switch (command) {
|
|
467
|
+
case 'android':
|
|
468
|
+
await android();
|
|
469
|
+
break;
|
|
470
|
+
case 'ios':
|
|
471
|
+
await ios();
|
|
472
|
+
break;
|
|
473
|
+
case 'host':
|
|
474
|
+
await host();
|
|
475
|
+
break;
|
|
476
|
+
case 'print-version':
|
|
477
|
+
process.stdout.write(`${manifest.version}\n`);
|
|
478
|
+
break;
|
|
479
|
+
default:
|
|
480
|
+
usage(command === undefined ? 1 : 2);
|
|
481
|
+
}
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error(
|
|
484
|
+
`[pdfium] ${error instanceof Error ? error.message : String(error)}`,
|
|
485
|
+
);
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "THE ONE PLACE THE PDFIUM BUILD IS NAMED. `scripts/fetch-pdfium.mjs` downloads exactly these artifacts, verifies exactly these digests, and refuses anything else. Bumping PDFium is a one-file change: new tag, new digests (taken from the release's `pdfium-attestation.json` subjects, never from a download you have not verified), then `yarn pdfium:fetch host && yarn native:test` before the bump is trusted. Every platform — Android, iOS, the host test suite — is built from the SAME release, which is what makes a tile byte-identical across all of them rather than merely similar.",
|
|
3
|
+
"release": "chromium/8044",
|
|
4
|
+
"version": "144.0.8044.0",
|
|
5
|
+
"baseUrl": "https://github.com/bblanchon/pdfium-binaries/releases/download",
|
|
6
|
+
"//artifacts": "Keyed by the bblanchon artifact name minus the `pdfium-` prefix and `.tgz` suffix. The android/ios/mac/win/linux entries are the plain (non-V8, non-XFA) builds: this package runs no JavaScript inside a PDF and XFA forms are out of scope, and the V8 builds are ~4x the size for nothing.",
|
|
7
|
+
"artifacts": {
|
|
8
|
+
"android-arm": {
|
|
9
|
+
"sha256": "7fba2fd334c9591e659c69263ff6c43b986f3db2200f6c156c848bb625f5364a",
|
|
10
|
+
"abi": "armeabi-v7a"
|
|
11
|
+
},
|
|
12
|
+
"android-arm64": {
|
|
13
|
+
"sha256": "37686e64fa005484d619550a78805500de4c5a6f4df7aa06d8576145bfbee98f",
|
|
14
|
+
"abi": "arm64-v8a"
|
|
15
|
+
},
|
|
16
|
+
"android-x64": {
|
|
17
|
+
"sha256": "e7e3072b8ad6f36ef58db999c2d91a22fa165a904d69385f13db4537c233d736",
|
|
18
|
+
"abi": "x86_64"
|
|
19
|
+
},
|
|
20
|
+
"android-x86": {
|
|
21
|
+
"sha256": "5a7bf631adac4d01c24e234172b8dc98d9e8e611c3d9b52135498d1b8c61e052",
|
|
22
|
+
"abi": "x86"
|
|
23
|
+
},
|
|
24
|
+
"ios-device-arm64": {
|
|
25
|
+
"sha256": "52be735d07b6c498ed8ce68b7f0cb5a209bbe61593c7a86c556756b80abbb938"
|
|
26
|
+
},
|
|
27
|
+
"ios-simulator-arm64": {
|
|
28
|
+
"sha256": "544537fce5257146e0df501c632d490d1aa95768737770f1912c8e23b1dd238d"
|
|
29
|
+
},
|
|
30
|
+
"ios-simulator-x64": {
|
|
31
|
+
"sha256": "8d4e33e415e29894aa98481bc9a9162a42039a1672796db14c9fed9cd545c881"
|
|
32
|
+
},
|
|
33
|
+
"mac-arm64": {
|
|
34
|
+
"sha256": "61424884d4a7f153b808deba6437848e4400834ce30aaf95d3050da44df8f420"
|
|
35
|
+
},
|
|
36
|
+
"mac-x64": {
|
|
37
|
+
"sha256": "a93d44238e05de20028446561b951d50988b849efbbe56fe40c0d376c05b45e8"
|
|
38
|
+
},
|
|
39
|
+
"win-x64": {
|
|
40
|
+
"sha256": "78a17d9a5f14467631c26a3ac8741b27a0471ecc05bd6a119b523598160a0537"
|
|
41
|
+
},
|
|
42
|
+
"linux-x64": {
|
|
43
|
+
"sha256": "eb142f416aed3a72fc5a02dbd5884868a16cb99dc0cf53e6bdd64afbf67b05f4"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|