|
| 1 | +// Copyright 2025 Nutrient. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +function getSingleJsonReplyFromResult(result) { |
| 6 | + if (result.getRepliesCount() !== 1) { |
| 7 | + throw new Error( |
| 8 | + `Expected 1 reply, but got ${result.getRepliesCount()} replies` |
| 9 | + ); |
| 10 | + } |
| 11 | + if (!result.hasJSONReply(0)) { |
| 12 | + throw new Error("Expected JSON reply"); |
| 13 | + } |
| 14 | + return JSON.parse(result.getJSONReply(0)); |
| 15 | +} |
| 16 | + |
| 17 | +function setupPrerequisites() { |
| 18 | + Module.ENVIRONMENT_IS_SHELL = |
| 19 | + typeof document === "undefined" && typeof window === "undefined"; |
| 20 | + Module.ENVIRONMENT_IS_WEB = !Module.ENVIRONMENT_IS_SHELL; |
| 21 | + |
| 22 | + if (Module.ENVIRONMENT_IS_SHELL) { |
| 23 | + // Nutrient WASM requires a location to be set. In shell mode, this isn't available by default. |
| 24 | + if (!globalThis.location) { |
| 25 | + globalThis.location = { |
| 26 | + origin: "http://localhost:8010", |
| 27 | + href: "http://localhost:8010/index.html", |
| 28 | + protocol: "http:", |
| 29 | + host: "localhost:8010", |
| 30 | + hostname: "localhost", |
| 31 | + port: "8010", |
| 32 | + pathname: "/", |
| 33 | + search: "", |
| 34 | + hash: "", |
| 35 | + }; |
| 36 | + } |
| 37 | + |
| 38 | + if (!globalThis.crypto) { |
| 39 | + globalThis.crypto = {}; |
| 40 | + } |
| 41 | + if (!globalThis.crypto.getRandomValues) { |
| 42 | + globalThis.crypto.getRandomValues = function (array) { |
| 43 | + if ( |
| 44 | + !( |
| 45 | + array instanceof Int8Array || |
| 46 | + array instanceof Uint8Array || |
| 47 | + array instanceof Int16Array || |
| 48 | + array instanceof Uint16Array || |
| 49 | + array instanceof Int32Array || |
| 50 | + array instanceof Uint32Array || |
| 51 | + array instanceof Uint8ClampedArray |
| 52 | + ) |
| 53 | + ) |
| 54 | + throw new TypeError("Expected an integer array"); |
| 55 | + |
| 56 | + if (array.byteLength > 65536) |
| 57 | + throw new RangeError("Can only request a maximum of 65536 bytes"); |
| 58 | + |
| 59 | + var i = 0, |
| 60 | + r; |
| 61 | + |
| 62 | + for (; i < array.length; i++) { |
| 63 | + if ((i & 0x03) === 0) r = Math.random() * 0x100000000; |
| 64 | + array[i] = (r >>> ((i & 0x03) << 3)) & 0xff; |
| 65 | + } |
| 66 | + |
| 67 | + return array; |
| 68 | + }; |
| 69 | + } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +async function initializeNutrient() { |
| 74 | + await PSPDFModuleInit(Module); |
| 75 | + |
| 76 | + const rawResult = await Module.initPSPDFKit( |
| 77 | + "", // License key - not required. |
| 78 | + "JetStream", // Origin - not required. |
| 79 | + "", // Fonts path - not required. |
| 80 | + "", // Analytics - not required. |
| 81 | + "NodeJS", // Environment - "NodeJS" also works in the browser. |
| 82 | + JSON.stringify([]) // Feature flags - not required. |
| 83 | + ); |
| 84 | + |
| 85 | + const result = JSON.parse(rawResult); |
| 86 | + if (!result.success) { |
| 87 | + throw new Error("Failed to initialize Nutrient: " + result.error); |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +function openDocument(path) { |
| 92 | + const result = Module.openDocument( |
| 93 | + path, |
| 94 | + JSON.stringify({ |
| 95 | + password: undefined, |
| 96 | + initialPageIndex: undefined, |
| 97 | + }) |
| 98 | + ); |
| 99 | + |
| 100 | + // Check if document loading failed |
| 101 | + if (result && result.error) { |
| 102 | + throw new Error("Document loading failed:", result.error); |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +function renderPage(pageIndex, width, height) { |
| 107 | + const result = Module.dispatchCommand( |
| 108 | + JSON.stringify({ |
| 109 | + type: "render_page", |
| 110 | + page: pageIndex, |
| 111 | + format: "png", |
| 112 | + page_width: width, |
| 113 | + page_height: height, |
| 114 | + }) |
| 115 | + ); |
| 116 | + |
| 117 | + if (result && result.hasError()) { |
| 118 | + throw new Error("Failed to render page: " + result.getErrorMessage()); |
| 119 | + } |
| 120 | + |
| 121 | + if (result.getRepliesCount() !== 1) { |
| 122 | + throw new Error( |
| 123 | + `Expected 1 reply, but got ${result.getRepliesCount()} replies` |
| 124 | + ); |
| 125 | + } |
| 126 | + |
| 127 | + if (!result.hasBinaryReply(0)) { |
| 128 | + throw new Error("Expected binary reply for rendered page"); |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +function createTextAnnotation(boundingBox, text) { |
| 133 | + const annotationJson = { |
| 134 | + bbox: boundingBox, |
| 135 | + borderStyle: "solid", |
| 136 | + borderWidth: 1, |
| 137 | + font: "Helvetica", |
| 138 | + fontColor: "#000000", |
| 139 | + fontSize: 14, |
| 140 | + horizontalAlign: "left", |
| 141 | + opacity: 1, |
| 142 | + pageIndex: 0, |
| 143 | + text: text, |
| 144 | + type: "pspdfkit/text", |
| 145 | + v: 1, |
| 146 | + verticalAlign: "top", |
| 147 | + }; |
| 148 | + |
| 149 | + const result = Module.dispatchCommand( |
| 150 | + JSON.stringify({ |
| 151 | + type: "add_annotation", |
| 152 | + annotation: annotationJson, |
| 153 | + }) |
| 154 | + ); |
| 155 | + |
| 156 | + if (result && result.hasError()) { |
| 157 | + throw new Error( |
| 158 | + "Failed to create text annotation: " + result.getErrorMessage() |
| 159 | + ); |
| 160 | + } |
| 161 | + |
| 162 | + return getSingleJsonReplyFromResult(result).annotation_id; |
| 163 | +} |
| 164 | + |
| 165 | +function renderAnnotation(annotationId) { |
| 166 | + result = Module.dispatchCommand( |
| 167 | + JSON.stringify({ |
| 168 | + type: "render_annotation", |
| 169 | + annotation_id: annotationId, |
| 170 | + page: 0, |
| 171 | + format: "png", |
| 172 | + bitmap_width: 350, |
| 173 | + bitmap_height: 250, |
| 174 | + }) |
| 175 | + ); |
| 176 | + |
| 177 | + if (result && result.hasError()) { |
| 178 | + throw new Error("Failed to render annotation: " + result.getErrorMessage()); |
| 179 | + } |
| 180 | +} |
| 181 | + |
| 182 | +// Page width and height for the assets/example.pdf document. |
| 183 | +const PAGE_WIDTH = 1190; |
| 184 | +const PAGE_HEIGHT = 841; |
| 185 | + |
| 186 | +class Benchmark { |
| 187 | + async init() { |
| 188 | + Module.wasmBinary = await getBinary(wasmBinary); |
| 189 | + |
| 190 | + setupPrerequisites(); |
| 191 | + injectRequiredGlobals(globalThis); |
| 192 | + } |
| 193 | + |
| 194 | + async runIteration() { |
| 195 | + if (!Module.initPSPDFKit) { |
| 196 | + await initializeNutrient(); |
| 197 | + } |
| 198 | + |
| 199 | + Module.FS.writeFile("/document.pdf", await getBinary(pdfDocument)); |
| 200 | + openDocument("/document.pdf"); |
| 201 | + |
| 202 | + var renderScale = 0.3; |
| 203 | + renderPage(0, PAGE_WIDTH * renderScale, PAGE_HEIGHT * renderScale); |
| 204 | + |
| 205 | + var textAnnotationId = createTextAnnotation( |
| 206 | + [50, 50, 300, 200], |
| 207 | + "This is a text annotation created by the benchmark." |
| 208 | + ); |
| 209 | + |
| 210 | + renderAnnotation(textAnnotationId); |
| 211 | + } |
| 212 | +} |
0 commit comments