UNPKG

@ironsoftware/ironpdf

Version:

IronPDF for Node

309 lines 13.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.saveAsLinearizedFromBytes = exports.linearizeCoreFromId = exports.linearizeCoreFromBytes = exports.linearizeInMemoryFromBytes = exports.linearizeInMemoryFromIdStream = exports.linearizeInMemoryFromId = exports.isLinearizedFromBytes = void 0; const buffer_1 = require("buffer"); const fs = __importStar(require("fs")); const os = __importStar(require("os")); const path = __importStar(require("path")); const stream_1 = require("stream"); const access_1 = require("../../access"); const render_1 = require("../../../public/render"); const util_1 = require("../util"); /** * Check if the given PDF bytes represent a linearized ("Fast Web View") PDF. */ function isLinearizedFromBytes(pdfBytes, password = "") { return __awaiter(this, void 0, void 0, function* () { const client = yield access_1.Access.ensureConnection(); return new Promise((resolve, reject) => { const stream = client.QPdf_Linearization_IsLinearized((err, value) => { var _a; if (err) { reject(`${err.name}/n${err.message}`); } else if (value) { if (value.exception) { (0, util_1.handleRemoteException)(value.exception, reject); return; } resolve((_a = value.result) !== null && _a !== void 0 ? _a : false); } else { reject("No response from IronPdfEngine for isLinearized"); } }); stream.write({ info: { password: password !== null && password !== void 0 ? password : "" } }); (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => { stream.write({ pdfBytesChunk: chunk }); }); stream.end(); }); }); } exports.isLinearizedFromBytes = isLinearizedFromBytes; /** * Linearize a PDF held by the engine (by document id) and return the linearized bytes * via the {@code QPdf_Linearization_LinearizeInMemoryFromId} unary-request/server-streaming RPC. */ function linearizeInMemoryFromId(id, password = "") { return __awaiter(this, void 0, void 0, function* () { const client = yield access_1.Access.ensureConnection(); return new Promise((resolve, reject) => { const stream = client.QPdf_Linearization_LinearizeInMemoryFromId({ document: { documentId: id }, password: password !== null && password !== void 0 ? password : "", }); const buffers = []; stream.on("data", (data) => { if (data.exception) { (0, util_1.handleRemoteException)(data.exception, reject); } else if (data.resultChunk) { buffers.push(data.resultChunk); } }); stream.on("error", (err) => { reject(`${err.name}/n${err.message}`); }); stream.on("end", () => { resolve(buffer_1.Buffer.concat(buffers)); }); }); }); } exports.linearizeInMemoryFromId = linearizeInMemoryFromId; /** * Linearize a PDF held by the engine (by document id) and stream the linearized bytes * as a {@link Readable}. Useful for piping to HTTP responses or file streams without * buffering the entire PDF in memory. */ function linearizeInMemoryFromIdStream(id, password = "") { return __awaiter(this, void 0, void 0, function* () { const client = yield access_1.Access.ensureConnection(); const passThrough = new stream_1.PassThrough(); const stream = client.QPdf_Linearization_LinearizeInMemoryFromId({ document: { documentId: id }, password: password !== null && password !== void 0 ? password : "", }); stream.on("data", (data) => { if (data.exception) { passThrough.destroy(new Error(`${data.exception.message}/n${data.exception.remoteStackTrace}`)); } else if (data.resultChunk) { passThrough.write(data.resultChunk); } }); stream.on("error", (err) => { passThrough.destroy(err); }); stream.on("end", () => { passThrough.end(); }); return passThrough; }); } exports.linearizeInMemoryFromIdStream = linearizeInMemoryFromIdStream; /** * Linearize a PDF provided as raw bytes and return the linearized bytes via the * bidirectional streaming {@code QPdf_Linearization_LinearizeInMemory} RPC. */ function linearizeInMemoryFromBytes(pdfBytes, password = "") { return __awaiter(this, void 0, void 0, function* () { const client = yield access_1.Access.ensureConnection(); return new Promise((resolve, reject) => { const stream = client.QPdf_Linearization_LinearizeInMemory(); const buffers = []; stream.on("data", (data) => { if (data.exception) { (0, util_1.handleRemoteException)(data.exception, reject); } else if (data.resultChunk) { buffers.push(data.resultChunk); } }); stream.on("error", (err) => { reject(`${err.name}/n${err.message}`); }); stream.on("end", () => { resolve(buffer_1.Buffer.concat(buffers)); }); stream.write({ info: { password: password !== null && password !== void 0 ? password : "" } }); (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => { stream.write({ pdfBytesChunk: chunk }); }); stream.end(); }); }); } exports.linearizeInMemoryFromBytes = linearizeInMemoryFromBytes; /** * Core linearization logic shared across all linearization entry points. Implements the * {@link LinearizationMode} strategy pattern. Mirrors {@code PdfDocument.LinearizePdfCore} * on the C# side. */ function linearizeCoreFromBytes(pdfBytes, password = "", mode = render_1.LinearizationMode.Automatic) { return __awaiter(this, void 0, void 0, function* () { if (!pdfBytes || pdfBytes.length === 0) { throw new Error("The PDF bytes cannot be null or empty."); } if (mode === render_1.LinearizationMode.InMemory) { return linearizeInMemoryFromBytes(pdfBytes, password); } if (mode === render_1.LinearizationMode.FileBased) { // Explicit FileBased — let any disk error bubble up. return linearizeViaTempFile(pdfBytes, password); } // Automatic mode if (canWriteToTemp()) { try { return yield linearizeViaTempFile(pdfBytes, password); } catch (e) { console.warn(`Automatic Linearization: Disk attempt failed (${e.message}). ` + "Falling back to Memory linearization."); return linearizeInMemoryFromBytes(pdfBytes, password); } } console.warn("Automatic Linearization: No write permission detected. Using Memory linearization."); return linearizeInMemoryFromBytes(pdfBytes, password); }); } exports.linearizeCoreFromBytes = linearizeCoreFromBytes; /** * Variant of {@link linearizeCoreFromBytes} that starts from an open document on the engine. * For {@link LinearizationMode.InMemory} we use the cheap document-id RPC; for the disk-based * paths we have to fetch the bytes once and delegate to {@link linearizeCoreFromBytes}. */ function linearizeCoreFromId(id, getBytes, password = "", mode = render_1.LinearizationMode.Automatic) { return __awaiter(this, void 0, void 0, function* () { if (mode === render_1.LinearizationMode.InMemory) { return linearizeInMemoryFromId(id, password); } const pdfBytes = yield getBytes(); return linearizeCoreFromBytes(pdfBytes, password, mode); }); } exports.linearizeCoreFromId = linearizeCoreFromId; /** * Linearize via the engine's file-based RPC and persist the result through a client-side * temporary file. The client-side disk write is the difference between this and * {@link linearizeInMemoryFromBytes} — when the client filesystem is read-only, * {@code FileBased} mode fails here so {@link LinearizationMode.Automatic} can fall back. * * Mirrors C# {@code PdfDocument.LinearizeViaTempFile}. */ function linearizeViaTempFile(pdfBytes, password) { return __awaiter(this, void 0, void 0, function* () { const linearized = yield saveAsLinearizedFromBytes(pdfBytes, "", password); const tempPath = path.join(os.tmpdir(), `ironpdf-linearize-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.pdf`); try { fs.writeFileSync(tempPath, linearized); return fs.readFileSync(tempPath); } finally { try { if (fs.existsSync(tempPath)) { fs.unlinkSync(tempPath); } } catch (_a) { // best-effort cleanup } } }); } /** * Probe whether the current process can create files in the system temp directory. */ function canWriteToTemp() { const probePath = path.join(os.tmpdir(), `ironpdf-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.tmp`); try { fs.writeFileSync(probePath, ""); return true; } catch (_a) { return false; } finally { try { if (fs.existsSync(probePath)) { fs.unlinkSync(probePath); } } catch (_b) { // best-effort cleanup } } } /** * Linearize a PDF provided as raw bytes and save the result to disk via the file-based * streaming {@code QPdf_Linearization_SaveAsLinearizedFromBytes} RPC. * * Mirrors the in-memory behavior used by {@link compressInMemory} in {@code compress.ts}: * the engine streams the linearized bytes back, and we concatenate and persist them * locally at {@code outputPath}. */ function saveAsLinearizedFromBytes(pdfBytes, outputPath, password = "") { return __awaiter(this, void 0, void 0, function* () { const client = yield access_1.Access.ensureConnection(); return new Promise((resolve, reject) => { const stream = client.QPdf_Linearization_SaveAsLinearizedFromBytes(); const buffers = []; stream.on("data", (data) => { if (data.exception) { (0, util_1.handleRemoteException)(data.exception, reject); } else if (data.resultChunk) { buffers.push(data.resultChunk); } }); stream.on("error", (err) => { reject(`${err.name}/n${err.message}`); }); stream.on("end", () => { resolve(buffer_1.Buffer.concat(buffers)); }); stream.write({ info: { outputPath: outputPath, password: password !== null && password !== void 0 ? password : "" }, }); (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => { stream.write({ pdfBytesChunk: chunk }); }); stream.end(); }); }); } exports.saveAsLinearizedFromBytes = saveAsLinearizedFromBytes; //# sourceMappingURL=linearize.js.map