@ironsoftware/ironpdf 2026.4.1 → 2026.5.1

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.
Files changed (72) hide show
  1. package/package.json +3 -3
  2. package/src/index.d.ts +2 -0
  3. package/src/index.d.ts.map +1 -1
  4. package/src/index.js +2 -0
  5. package/src/index.js.map +1 -1
  6. package/src/index.ts +2 -0
  7. package/src/internal/IronPdfEngine.ProtoFiles/chrome_render.proto +6 -0
  8. package/src/internal/IronPdfEngine.ProtoFiles/iron_pdf_service.proto +2 -1
  9. package/src/internal/IronPdfEngine.ProtoFiles/qpdf.proto +16 -0
  10. package/src/internal/generated_proto/iron_pdf_service.d.ts +614 -305
  11. package/src/internal/generated_proto/iron_pdf_service.d.ts.map +1 -1
  12. package/src/internal/generated_proto/iron_pdf_service.ts +614 -305
  13. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.d.ts +15 -0
  14. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.d.ts.map +1 -1
  15. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.ts +15 -0
  16. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.d.ts +14 -0
  17. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.d.ts.map +1 -1
  18. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.ts +18 -0
  19. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.d.ts +10 -0
  20. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.d.ts.map +1 -0
  21. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.js +4 -0
  22. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.js.map +1 -0
  23. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.ts +13 -0
  24. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.d.ts +18 -0
  25. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.d.ts.map +1 -0
  26. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.js +4 -0
  27. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.js.map +1 -0
  28. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.ts +21 -0
  29. package/src/internal/grpc_layer/chrome/converter.d.ts +10 -0
  30. package/src/internal/grpc_layer/chrome/converter.d.ts.map +1 -1
  31. package/src/internal/grpc_layer/chrome/converter.js +61 -2
  32. package/src/internal/grpc_layer/chrome/converter.js.map +1 -1
  33. package/src/internal/grpc_layer/chrome/converter.ts +67 -0
  34. package/src/internal/grpc_layer/pdfium/annotations.d.ts +30 -0
  35. package/src/internal/grpc_layer/pdfium/annotations.d.ts.map +1 -0
  36. package/src/internal/grpc_layer/pdfium/annotations.js +161 -0
  37. package/src/internal/grpc_layer/pdfium/annotations.js.map +1 -0
  38. package/src/internal/grpc_layer/pdfium/annotations.ts +190 -0
  39. package/src/internal/grpc_layer/pdfium/bookmarks.d.ts +7 -0
  40. package/src/internal/grpc_layer/pdfium/bookmarks.d.ts.map +1 -0
  41. package/src/internal/grpc_layer/pdfium/bookmarks.js +53 -0
  42. package/src/internal/grpc_layer/pdfium/bookmarks.js.map +1 -0
  43. package/src/internal/grpc_layer/pdfium/bookmarks.ts +50 -0
  44. package/src/internal/grpc_layer/pdfium/linearize.d.ts +48 -0
  45. package/src/internal/grpc_layer/pdfium/linearize.d.ts.map +1 -0
  46. package/src/internal/grpc_layer/pdfium/linearize.js +309 -0
  47. package/src/internal/grpc_layer/pdfium/linearize.js.map +1 -0
  48. package/src/internal/grpc_layer/pdfium/linearize.ts +338 -0
  49. package/src/internal/zod/renderSchema.d.ts.map +1 -1
  50. package/src/internal/zod/renderSchema.js +6 -1
  51. package/src/internal/zod/renderSchema.js.map +1 -1
  52. package/src/internal/zod/renderSchema.ts +6 -1
  53. package/src/public/annotation.d.ts +166 -0
  54. package/src/public/annotation.d.ts.map +1 -0
  55. package/src/public/annotation.js +61 -0
  56. package/src/public/annotation.js.map +1 -0
  57. package/src/public/annotation.ts +166 -0
  58. package/src/public/bookmark.d.ts +25 -0
  59. package/src/public/bookmark.d.ts.map +1 -0
  60. package/src/public/bookmark.js +3 -0
  61. package/src/public/bookmark.js.map +1 -0
  62. package/src/public/bookmark.ts +28 -0
  63. package/src/public/pdfDocument.d.ts +168 -1
  64. package/src/public/pdfDocument.d.ts.map +1 -1
  65. package/src/public/pdfDocument.js +341 -17
  66. package/src/public/pdfDocument.js.map +1 -1
  67. package/src/public/pdfDocument.ts +364 -18
  68. package/src/public/render.d.ts +104 -0
  69. package/src/public/render.d.ts.map +1 -1
  70. package/src/public/render.js +35 -1
  71. package/src/public/render.js.map +1 -1
  72. package/src/public/render.ts +101 -0
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.saveAsLinearizedFromBytes = exports.linearizeCoreFromId = exports.linearizeCoreFromBytes = exports.linearizeInMemoryFromBytes = exports.linearizeInMemoryFromIdStream = exports.linearizeInMemoryFromId = exports.isLinearizedFromBytes = void 0;
36
+ const buffer_1 = require("buffer");
37
+ const fs = __importStar(require("fs"));
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
40
+ const stream_1 = require("stream");
41
+ const access_1 = require("../../access");
42
+ const render_1 = require("../../../public/render");
43
+ const util_1 = require("../util");
44
+ /**
45
+ * Check if the given PDF bytes represent a linearized ("Fast Web View") PDF.
46
+ */
47
+ function isLinearizedFromBytes(pdfBytes, password = "") {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const client = yield access_1.Access.ensureConnection();
50
+ return new Promise((resolve, reject) => {
51
+ const stream = client.QPdf_Linearization_IsLinearized((err, value) => {
52
+ var _a;
53
+ if (err) {
54
+ reject(`${err.name}/n${err.message}`);
55
+ }
56
+ else if (value) {
57
+ if (value.exception) {
58
+ (0, util_1.handleRemoteException)(value.exception, reject);
59
+ return;
60
+ }
61
+ resolve((_a = value.result) !== null && _a !== void 0 ? _a : false);
62
+ }
63
+ else {
64
+ reject("No response from IronPdfEngine for isLinearized");
65
+ }
66
+ });
67
+ stream.write({ info: { password: password !== null && password !== void 0 ? password : "" } });
68
+ (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => {
69
+ stream.write({ pdfBytesChunk: chunk });
70
+ });
71
+ stream.end();
72
+ });
73
+ });
74
+ }
75
+ exports.isLinearizedFromBytes = isLinearizedFromBytes;
76
+ /**
77
+ * Linearize a PDF held by the engine (by document id) and return the linearized bytes
78
+ * via the {@code QPdf_Linearization_LinearizeInMemoryFromId} unary-request/server-streaming RPC.
79
+ */
80
+ function linearizeInMemoryFromId(id, password = "") {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ const client = yield access_1.Access.ensureConnection();
83
+ return new Promise((resolve, reject) => {
84
+ const stream = client.QPdf_Linearization_LinearizeInMemoryFromId({
85
+ document: { documentId: id },
86
+ password: password !== null && password !== void 0 ? password : "",
87
+ });
88
+ const buffers = [];
89
+ stream.on("data", (data) => {
90
+ if (data.exception) {
91
+ (0, util_1.handleRemoteException)(data.exception, reject);
92
+ }
93
+ else if (data.resultChunk) {
94
+ buffers.push(data.resultChunk);
95
+ }
96
+ });
97
+ stream.on("error", (err) => {
98
+ reject(`${err.name}/n${err.message}`);
99
+ });
100
+ stream.on("end", () => {
101
+ resolve(buffer_1.Buffer.concat(buffers));
102
+ });
103
+ });
104
+ });
105
+ }
106
+ exports.linearizeInMemoryFromId = linearizeInMemoryFromId;
107
+ /**
108
+ * Linearize a PDF held by the engine (by document id) and stream the linearized bytes
109
+ * as a {@link Readable}. Useful for piping to HTTP responses or file streams without
110
+ * buffering the entire PDF in memory.
111
+ */
112
+ function linearizeInMemoryFromIdStream(id, password = "") {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ const client = yield access_1.Access.ensureConnection();
115
+ const passThrough = new stream_1.PassThrough();
116
+ const stream = client.QPdf_Linearization_LinearizeInMemoryFromId({
117
+ document: { documentId: id },
118
+ password: password !== null && password !== void 0 ? password : "",
119
+ });
120
+ stream.on("data", (data) => {
121
+ if (data.exception) {
122
+ passThrough.destroy(new Error(`${data.exception.message}/n${data.exception.remoteStackTrace}`));
123
+ }
124
+ else if (data.resultChunk) {
125
+ passThrough.write(data.resultChunk);
126
+ }
127
+ });
128
+ stream.on("error", (err) => {
129
+ passThrough.destroy(err);
130
+ });
131
+ stream.on("end", () => {
132
+ passThrough.end();
133
+ });
134
+ return passThrough;
135
+ });
136
+ }
137
+ exports.linearizeInMemoryFromIdStream = linearizeInMemoryFromIdStream;
138
+ /**
139
+ * Linearize a PDF provided as raw bytes and return the linearized bytes via the
140
+ * bidirectional streaming {@code QPdf_Linearization_LinearizeInMemory} RPC.
141
+ */
142
+ function linearizeInMemoryFromBytes(pdfBytes, password = "") {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ const client = yield access_1.Access.ensureConnection();
145
+ return new Promise((resolve, reject) => {
146
+ const stream = client.QPdf_Linearization_LinearizeInMemory();
147
+ const buffers = [];
148
+ stream.on("data", (data) => {
149
+ if (data.exception) {
150
+ (0, util_1.handleRemoteException)(data.exception, reject);
151
+ }
152
+ else if (data.resultChunk) {
153
+ buffers.push(data.resultChunk);
154
+ }
155
+ });
156
+ stream.on("error", (err) => {
157
+ reject(`${err.name}/n${err.message}`);
158
+ });
159
+ stream.on("end", () => {
160
+ resolve(buffer_1.Buffer.concat(buffers));
161
+ });
162
+ stream.write({ info: { password: password !== null && password !== void 0 ? password : "" } });
163
+ (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => {
164
+ stream.write({ pdfBytesChunk: chunk });
165
+ });
166
+ stream.end();
167
+ });
168
+ });
169
+ }
170
+ exports.linearizeInMemoryFromBytes = linearizeInMemoryFromBytes;
171
+ /**
172
+ * Core linearization logic shared across all linearization entry points. Implements the
173
+ * {@link LinearizationMode} strategy pattern. Mirrors {@code PdfDocument.LinearizePdfCore}
174
+ * on the C# side.
175
+ */
176
+ function linearizeCoreFromBytes(pdfBytes, password = "", mode = render_1.LinearizationMode.Automatic) {
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ if (!pdfBytes || pdfBytes.length === 0) {
179
+ throw new Error("The PDF bytes cannot be null or empty.");
180
+ }
181
+ if (mode === render_1.LinearizationMode.InMemory) {
182
+ return linearizeInMemoryFromBytes(pdfBytes, password);
183
+ }
184
+ if (mode === render_1.LinearizationMode.FileBased) {
185
+ // Explicit FileBased — let any disk error bubble up.
186
+ return linearizeViaTempFile(pdfBytes, password);
187
+ }
188
+ // Automatic mode
189
+ if (canWriteToTemp()) {
190
+ try {
191
+ return yield linearizeViaTempFile(pdfBytes, password);
192
+ }
193
+ catch (e) {
194
+ console.warn(`Automatic Linearization: Disk attempt failed (${e.message}). ` +
195
+ "Falling back to Memory linearization.");
196
+ return linearizeInMemoryFromBytes(pdfBytes, password);
197
+ }
198
+ }
199
+ console.warn("Automatic Linearization: No write permission detected. Using Memory linearization.");
200
+ return linearizeInMemoryFromBytes(pdfBytes, password);
201
+ });
202
+ }
203
+ exports.linearizeCoreFromBytes = linearizeCoreFromBytes;
204
+ /**
205
+ * Variant of {@link linearizeCoreFromBytes} that starts from an open document on the engine.
206
+ * For {@link LinearizationMode.InMemory} we use the cheap document-id RPC; for the disk-based
207
+ * paths we have to fetch the bytes once and delegate to {@link linearizeCoreFromBytes}.
208
+ */
209
+ function linearizeCoreFromId(id, getBytes, password = "", mode = render_1.LinearizationMode.Automatic) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ if (mode === render_1.LinearizationMode.InMemory) {
212
+ return linearizeInMemoryFromId(id, password);
213
+ }
214
+ const pdfBytes = yield getBytes();
215
+ return linearizeCoreFromBytes(pdfBytes, password, mode);
216
+ });
217
+ }
218
+ exports.linearizeCoreFromId = linearizeCoreFromId;
219
+ /**
220
+ * Linearize via the engine's file-based RPC and persist the result through a client-side
221
+ * temporary file. The client-side disk write is the difference between this and
222
+ * {@link linearizeInMemoryFromBytes} — when the client filesystem is read-only,
223
+ * {@code FileBased} mode fails here so {@link LinearizationMode.Automatic} can fall back.
224
+ *
225
+ * Mirrors C# {@code PdfDocument.LinearizeViaTempFile}.
226
+ */
227
+ function linearizeViaTempFile(pdfBytes, password) {
228
+ return __awaiter(this, void 0, void 0, function* () {
229
+ const linearized = yield saveAsLinearizedFromBytes(pdfBytes, "", password);
230
+ const tempPath = path.join(os.tmpdir(), `ironpdf-linearize-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.pdf`);
231
+ try {
232
+ fs.writeFileSync(tempPath, linearized);
233
+ return fs.readFileSync(tempPath);
234
+ }
235
+ finally {
236
+ try {
237
+ if (fs.existsSync(tempPath)) {
238
+ fs.unlinkSync(tempPath);
239
+ }
240
+ }
241
+ catch (_a) {
242
+ // best-effort cleanup
243
+ }
244
+ }
245
+ });
246
+ }
247
+ /**
248
+ * Probe whether the current process can create files in the system temp directory.
249
+ */
250
+ function canWriteToTemp() {
251
+ const probePath = path.join(os.tmpdir(), `ironpdf-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.tmp`);
252
+ try {
253
+ fs.writeFileSync(probePath, "");
254
+ return true;
255
+ }
256
+ catch (_a) {
257
+ return false;
258
+ }
259
+ finally {
260
+ try {
261
+ if (fs.existsSync(probePath)) {
262
+ fs.unlinkSync(probePath);
263
+ }
264
+ }
265
+ catch (_b) {
266
+ // best-effort cleanup
267
+ }
268
+ }
269
+ }
270
+ /**
271
+ * Linearize a PDF provided as raw bytes and save the result to disk via the file-based
272
+ * streaming {@code QPdf_Linearization_SaveAsLinearizedFromBytes} RPC.
273
+ *
274
+ * Mirrors the in-memory behavior used by {@link compressInMemory} in {@code compress.ts}:
275
+ * the engine streams the linearized bytes back, and we concatenate and persist them
276
+ * locally at {@code outputPath}.
277
+ */
278
+ function saveAsLinearizedFromBytes(pdfBytes, outputPath, password = "") {
279
+ return __awaiter(this, void 0, void 0, function* () {
280
+ const client = yield access_1.Access.ensureConnection();
281
+ return new Promise((resolve, reject) => {
282
+ const stream = client.QPdf_Linearization_SaveAsLinearizedFromBytes();
283
+ const buffers = [];
284
+ stream.on("data", (data) => {
285
+ if (data.exception) {
286
+ (0, util_1.handleRemoteException)(data.exception, reject);
287
+ }
288
+ else if (data.resultChunk) {
289
+ buffers.push(data.resultChunk);
290
+ }
291
+ });
292
+ stream.on("error", (err) => {
293
+ reject(`${err.name}/n${err.message}`);
294
+ });
295
+ stream.on("end", () => {
296
+ resolve(buffer_1.Buffer.concat(buffers));
297
+ });
298
+ stream.write({
299
+ info: { outputPath: outputPath, password: password !== null && password !== void 0 ? password : "" },
300
+ });
301
+ (0, util_1.chunkBuffer)(pdfBytes).forEach((chunk) => {
302
+ stream.write({ pdfBytesChunk: chunk });
303
+ });
304
+ stream.end();
305
+ });
306
+ });
307
+ }
308
+ exports.saveAsLinearizedFromBytes = saveAsLinearizedFromBytes;
309
+ //# sourceMappingURL=linearize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linearize.js","sourceRoot":"","sources":["linearize.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,mCAA8B;AAC9B,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAC7B,mCAA6C;AAC7C,yCAAoC;AAapC,mDAAyD;AACzD,kCAA2D;AAE3D;;GAEG;AACH,SAAsB,qBAAqB,CAC1C,QAAgB,EAChB,QAAQ,GAAG,EAAE;;QAEb,MAAM,MAAM,GAAyB,MAAM,eAAM,CAAC,gBAAgB,EAAE,CAAC;QAErE,OAAO,IAAI,OAAO,CACjB,CAAC,OAA6B,EAAE,MAAkC,EAAE,EAAE;YACrE,MAAM,MAAM,GACX,MAAM,CAAC,+BAA+B,CACrC,CAAC,GAA6B,EAAE,KAAyC,EAAE,EAAE;;gBAC5E,IAAI,GAAG,EAAE;oBACR,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;iBACtC;qBAAM,IAAI,KAAK,EAAE;oBACjB,IAAI,KAAK,CAAC,SAAS,EAAE;wBACpB,IAAA,4BAAqB,EAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;wBAC/C,OAAO;qBACP;oBACD,OAAO,CAAC,MAAA,KAAK,CAAC,MAAM,mCAAI,KAAK,CAAC,CAAC;iBAC/B;qBAAM;oBACN,MAAM,CAAC,iDAAiD,CAAC,CAAC;iBAC1D;YACF,CAAC,CACD,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,EAAC,IAAI,EAAE,EAAC,QAAQ,EAAE,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,EAAE,EAAC,EAAC,CAAC,CAAC;YACjD,IAAA,kBAAW,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACvC,MAAM,CAAC,KAAK,CAAC,EAAC,aAAa,EAAE,KAAK,EAAC,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC,CACD,CAAC;IACH,CAAC;CAAA;AAhCD,sDAgCC;AAED;;;GAGG;AACH,SAAsB,uBAAuB,CAC5C,EAAU,EACV,QAAQ,GAAG,EAAE;;QAEb,MAAM,MAAM,GAAyB,MAAM,eAAM,CAAC,gBAAgB,EAAE,CAAC;QAErE,OAAO,IAAI,OAAO,CACjB,CAAC,OAA4B,EAAE,MAAkC,EAAE,EAAE;YACpE,MAAM,MAAM,GACX,MAAM,CAAC,0CAA0C,CAAC;gBACjD,QAAQ,EAAE,EAAC,UAAU,EAAE,EAAE,EAAC;gBAC1B,QAAQ,EAAE,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,EAAE;aACxB,CAAC,CAAC;YAEJ,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAgC,EAAE,EAAE;gBACtD,IAAI,IAAI,CAAC,SAAS,EAAE;oBACnB,IAAA,4BAAqB,EAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;iBAC9C;qBAAM,IAAI,IAAI,CAAC,WAAW,EAAE;oBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;iBAC/B;YACF,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBACjC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACrB,OAAO,CAAC,eAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACJ,CAAC,CACD,CAAC;IACH,CAAC;CAAA;AAhCD,0DAgCC;AAED;;;;GAIG;AACH,SAAsB,6BAA6B,CAClD,EAAU,EACV,QAAQ,GAAG,EAAE;;QAEb,MAAM,MAAM,GAAyB,MAAM,eAAM,CAAC,gBAAgB,EAAE,CAAC;QAErE,MAAM,WAAW,GAAG,IAAI,oBAAW,EAAE,CAAC;QAEtC,MAAM,MAAM,GACX,MAAM,CAAC,0CAA0C,CAAC;YACjD,QAAQ,EAAE,EAAC,UAAU,EAAE,EAAE,EAAC;YAC1B,QAAQ,EAAE,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,EAAE;SACxB,CAAC,CAAC;QAEJ,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAgC,EAAE,EAAE;YACtD,IAAI,IAAI,CAAC,SAAS,EAAE;gBACnB,WAAW,CAAC,OAAO,CAClB,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC,CAC1E,CAAC;aACF;iBAAM,IAAI,IAAI,CAAC,WAAW,EAAE;gBAC5B,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;aACpC;QACF,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YACjC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,WAAW,CAAC,GAAG,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC;IACpB,CAAC;CAAA;AAjCD,sEAiCC;AAED;;;GAGG;AACH,SAAsB,0BAA0B,CAC/C,QAAgB,EAChB,QAAQ,GAAG,EAAE;;QAEb,MAAM,MAAM,GAAyB,MAAM,eAAM,CAAC,gBAAgB,EAAE,CAAC;QAErE,OAAO,IAAI,OAAO,CACjB,CAAC,OAA4B,EAAE,MAAkC,EAAE,EAAE;YACpE,MAAM,MAAM,GAGR,MAAM,CAAC,oCAAoC,EAAE,CAAC;YAElD,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAgC,EAAE,EAAE;gBACtD,IAAI,IAAI,CAAC,SAAS,EAAE;oBACnB,IAAA,4BAAqB,EAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;iBAC9C;qBAAM,IAAI,IAAI,CAAC,WAAW,EAAE;oBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;iBAC/B;YACF,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBACjC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACrB,OAAO,CAAC,eAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,EAAC,IAAI,EAAE,EAAC,QAAQ,EAAE,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,EAAE,EAAC,EAAC,CAAC,CAAC;YACjD,IAAA,kBAAW,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACvC,MAAM,CAAC,KAAK,CAAC,EAAC,aAAa,EAAE,KAAK,EAAC,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC,CACD,CAAC;IACH,CAAC;CAAA;AArCD,gEAqCC;AAED;;;;GAIG;AACH,SAAsB,sBAAsB,CAC3C,QAAgB,EAChB,QAAQ,GAAG,EAAE,EACb,OAA0B,0BAAiB,CAAC,SAAS;;QAErD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;SAC1D;QAED,IAAI,IAAI,KAAK,0BAAiB,CAAC,QAAQ,EAAE;YACxC,OAAO,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SACtD;QAED,IAAI,IAAI,KAAK,0BAAiB,CAAC,SAAS,EAAE;YACzC,qDAAqD;YACrD,OAAO,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SAChD;QAED,iBAAiB;QACjB,IAAI,cAAc,EAAE,EAAE;YACrB,IAAI;gBACH,OAAO,MAAM,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;aACtD;YAAC,OAAO,CAAC,EAAE;gBACX,OAAO,CAAC,IAAI,CACX,iDAAkD,CAAW,CAAC,OAAO,KAAK;oBACzE,uCAAuC,CACxC,CAAC;gBACF,OAAO,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;aACtD;SACD;QACD,OAAO,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;QACnG,OAAO,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;CAAA;AAhCD,wDAgCC;AAED;;;;GAIG;AACH,SAAsB,mBAAmB,CACxC,EAAU,EACV,QAA+B,EAC/B,QAAQ,GAAG,EAAE,EACb,OAA0B,0BAAiB,CAAC,SAAS;;QAErD,IAAI,IAAI,KAAK,0BAAiB,CAAC,QAAQ,EAAE;YACxC,OAAO,uBAAuB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;SAC7C;QACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,EAAE,CAAC;QAClC,OAAO,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACzD,CAAC;CAAA;AAXD,kDAWC;AAED;;;;;;;GAOG;AACH,SAAe,oBAAoB,CAAC,QAAgB,EAAE,QAAgB;;QACrE,MAAM,UAAU,GAAG,MAAM,yBAAyB,CAAC,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACzB,EAAE,CAAC,MAAM,EAAE,EACX,qBAAqB,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAC/F,CAAC;QACF,IAAI;YACH,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACvC,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;SACjC;gBAAS;YACT,IAAI;gBACH,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;oBAC5B,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;iBACxB;aACD;YAAC,WAAM;gBACP,sBAAsB;aACtB;SACD;IACF,CAAC;CAAA;AAED;;GAEG;AACH,SAAS,cAAc;IACtB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAC1B,EAAE,CAAC,MAAM,EAAE,EACX,iBAAiB,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAC3F,CAAC;IACF,IAAI;QACH,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;KACZ;IAAC,WAAM;QACP,OAAO,KAAK,CAAC;KACb;YAAS;QACT,IAAI;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;gBAC7B,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;aACzB;SACD;QAAC,WAAM;YACP,sBAAsB;SACtB;KACD;AACF,CAAC;AAED;;;;;;;GAOG;AACH,SAAsB,yBAAyB,CAC9C,QAAgB,EAChB,UAAkB,EAClB,QAAQ,GAAG,EAAE;;QAEb,MAAM,MAAM,GAAyB,MAAM,eAAM,CAAC,gBAAgB,EAAE,CAAC;QAErE,OAAO,IAAI,OAAO,CACjB,CAAC,OAA4B,EAAE,MAAkC,EAAE,EAAE;YACpE,MAAM,MAAM,GAGR,MAAM,CAAC,4CAA4C,EAAE,CAAC;YAE1D,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAgC,EAAE,EAAE;gBACtD,IAAI,IAAI,CAAC,SAAS,EAAE;oBACnB,IAAA,4BAAqB,EAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;iBAC9C;qBAAM,IAAI,IAAI,CAAC,WAAW,EAAE;oBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;iBAC/B;YACF,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;gBACjC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACrB,OAAO,CAAC,eAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC;gBACZ,IAAI,EAAE,EAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,EAAE,EAAC;aACxD,CAAC,CAAC;YACH,IAAA,kBAAW,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACvC,MAAM,CAAC,KAAK,CAAC,EAAC,aAAa,EAAE,KAAK,EAAC,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC,CACD,CAAC;IACH,CAAC;CAAA;AAxCD,8DAwCC"}
@@ -0,0 +1,338 @@
1
+ import * as grpc from "@grpc/grpc-js";
2
+ import {Buffer} from "buffer";
3
+ import * as fs from "fs";
4
+ import * as os from "os";
5
+ import * as path from "path";
6
+ import {PassThrough, Readable} from "stream";
7
+ import {Access} from "../../access";
8
+ import {IronPdfServiceClient} from "../../generated_proto/ironpdfengineproto/IronPdfService";
9
+ import {BytesResultStreamP__Output} from "../../generated_proto/ironpdfengineproto/BytesResultStreamP";
10
+ import {BooleanResultP__Output} from "../../generated_proto/ironpdfengineproto/BooleanResultP";
11
+ import {
12
+ QPdfIsLinearizedRequestStreamP
13
+ } from "../../generated_proto/ironpdfengineproto/QPdfIsLinearizedRequestStreamP";
14
+ import {
15
+ QPdfLinearizeInMemoryRequestStreamP
16
+ } from "../../generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP";
17
+ import {
18
+ QPdfSaveAsLinearizedFromBytesRequestStreamP
19
+ } from "../../generated_proto/ironpdfengineproto/QPdfSaveAsLinearizedFromBytesRequestStreamP";
20
+ import {LinearizationMode} from "../../../public/render";
21
+ import {chunkBuffer, handleRemoteException} from "../util";
22
+
23
+ /**
24
+ * Check if the given PDF bytes represent a linearized ("Fast Web View") PDF.
25
+ */
26
+ export async function isLinearizedFromBytes(
27
+ pdfBytes: Buffer,
28
+ password = ""
29
+ ): Promise<boolean> {
30
+ const client: IronPdfServiceClient = await Access.ensureConnection();
31
+
32
+ return new Promise(
33
+ (resolve: (_: boolean) => void, reject: (errorMsg: string) => void) => {
34
+ const stream: grpc.ClientWritableStream<QPdfIsLinearizedRequestStreamP> =
35
+ client.QPdf_Linearization_IsLinearized(
36
+ (err: grpc.ServiceError | null, value: BooleanResultP__Output | undefined) => {
37
+ if (err) {
38
+ reject(`${err.name}/n${err.message}`);
39
+ } else if (value) {
40
+ if (value.exception) {
41
+ handleRemoteException(value.exception, reject);
42
+ return;
43
+ }
44
+ resolve(value.result ?? false);
45
+ } else {
46
+ reject("No response from IronPdfEngine for isLinearized");
47
+ }
48
+ }
49
+ );
50
+
51
+ stream.write({info: {password: password ?? ""}});
52
+ chunkBuffer(pdfBytes).forEach((chunk) => {
53
+ stream.write({pdfBytesChunk: chunk});
54
+ });
55
+ stream.end();
56
+ }
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Linearize a PDF held by the engine (by document id) and return the linearized bytes
62
+ * via the {@code QPdf_Linearization_LinearizeInMemoryFromId} unary-request/server-streaming RPC.
63
+ */
64
+ export async function linearizeInMemoryFromId(
65
+ id: string,
66
+ password = ""
67
+ ): Promise<Buffer> {
68
+ const client: IronPdfServiceClient = await Access.ensureConnection();
69
+
70
+ return new Promise(
71
+ (resolve: (_: Buffer) => void, reject: (errorMsg: string) => void) => {
72
+ const stream: grpc.ClientReadableStream<BytesResultStreamP__Output> =
73
+ client.QPdf_Linearization_LinearizeInMemoryFromId({
74
+ document: {documentId: id},
75
+ password: password ?? "",
76
+ });
77
+
78
+ const buffers: Buffer[] = [];
79
+ stream.on("data", (data: BytesResultStreamP__Output) => {
80
+ if (data.exception) {
81
+ handleRemoteException(data.exception, reject);
82
+ } else if (data.resultChunk) {
83
+ buffers.push(data.resultChunk);
84
+ }
85
+ });
86
+
87
+ stream.on("error", (err: Error) => {
88
+ reject(`${err.name}/n${err.message}`);
89
+ });
90
+
91
+ stream.on("end", () => {
92
+ resolve(Buffer.concat(buffers));
93
+ });
94
+ }
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Linearize a PDF held by the engine (by document id) and stream the linearized bytes
100
+ * as a {@link Readable}. Useful for piping to HTTP responses or file streams without
101
+ * buffering the entire PDF in memory.
102
+ */
103
+ export async function linearizeInMemoryFromIdStream(
104
+ id: string,
105
+ password = ""
106
+ ): Promise<Readable> {
107
+ const client: IronPdfServiceClient = await Access.ensureConnection();
108
+
109
+ const passThrough = new PassThrough();
110
+
111
+ const stream: grpc.ClientReadableStream<BytesResultStreamP__Output> =
112
+ client.QPdf_Linearization_LinearizeInMemoryFromId({
113
+ document: {documentId: id},
114
+ password: password ?? "",
115
+ });
116
+
117
+ stream.on("data", (data: BytesResultStreamP__Output) => {
118
+ if (data.exception) {
119
+ passThrough.destroy(
120
+ new Error(`${data.exception.message}/n${data.exception.remoteStackTrace}`)
121
+ );
122
+ } else if (data.resultChunk) {
123
+ passThrough.write(data.resultChunk);
124
+ }
125
+ });
126
+
127
+ stream.on("error", (err: Error) => {
128
+ passThrough.destroy(err);
129
+ });
130
+
131
+ stream.on("end", () => {
132
+ passThrough.end();
133
+ });
134
+
135
+ return passThrough;
136
+ }
137
+
138
+ /**
139
+ * Linearize a PDF provided as raw bytes and return the linearized bytes via the
140
+ * bidirectional streaming {@code QPdf_Linearization_LinearizeInMemory} RPC.
141
+ */
142
+ export async function linearizeInMemoryFromBytes(
143
+ pdfBytes: Buffer,
144
+ password = ""
145
+ ): Promise<Buffer> {
146
+ const client: IronPdfServiceClient = await Access.ensureConnection();
147
+
148
+ return new Promise(
149
+ (resolve: (_: Buffer) => void, reject: (errorMsg: string) => void) => {
150
+ const stream: grpc.ClientDuplexStream<
151
+ QPdfLinearizeInMemoryRequestStreamP,
152
+ BytesResultStreamP__Output
153
+ > = client.QPdf_Linearization_LinearizeInMemory();
154
+
155
+ const buffers: Buffer[] = [];
156
+ stream.on("data", (data: BytesResultStreamP__Output) => {
157
+ if (data.exception) {
158
+ handleRemoteException(data.exception, reject);
159
+ } else if (data.resultChunk) {
160
+ buffers.push(data.resultChunk);
161
+ }
162
+ });
163
+
164
+ stream.on("error", (err: Error) => {
165
+ reject(`${err.name}/n${err.message}`);
166
+ });
167
+
168
+ stream.on("end", () => {
169
+ resolve(Buffer.concat(buffers));
170
+ });
171
+
172
+ stream.write({info: {password: password ?? ""}});
173
+ chunkBuffer(pdfBytes).forEach((chunk) => {
174
+ stream.write({pdfBytesChunk: chunk});
175
+ });
176
+ stream.end();
177
+ }
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Core linearization logic shared across all linearization entry points. Implements the
183
+ * {@link LinearizationMode} strategy pattern. Mirrors {@code PdfDocument.LinearizePdfCore}
184
+ * on the C# side.
185
+ */
186
+ export async function linearizeCoreFromBytes(
187
+ pdfBytes: Buffer,
188
+ password = "",
189
+ mode: LinearizationMode = LinearizationMode.Automatic
190
+ ): Promise<Buffer> {
191
+ if (!pdfBytes || pdfBytes.length === 0) {
192
+ throw new Error("The PDF bytes cannot be null or empty.");
193
+ }
194
+
195
+ if (mode === LinearizationMode.InMemory) {
196
+ return linearizeInMemoryFromBytes(pdfBytes, password);
197
+ }
198
+
199
+ if (mode === LinearizationMode.FileBased) {
200
+ // Explicit FileBased — let any disk error bubble up.
201
+ return linearizeViaTempFile(pdfBytes, password);
202
+ }
203
+
204
+ // Automatic mode
205
+ if (canWriteToTemp()) {
206
+ try {
207
+ return await linearizeViaTempFile(pdfBytes, password);
208
+ } catch (e) {
209
+ console.warn(
210
+ `Automatic Linearization: Disk attempt failed (${(e as Error).message}). ` +
211
+ "Falling back to Memory linearization."
212
+ );
213
+ return linearizeInMemoryFromBytes(pdfBytes, password);
214
+ }
215
+ }
216
+ console.warn("Automatic Linearization: No write permission detected. Using Memory linearization.");
217
+ return linearizeInMemoryFromBytes(pdfBytes, password);
218
+ }
219
+
220
+ /**
221
+ * Variant of {@link linearizeCoreFromBytes} that starts from an open document on the engine.
222
+ * For {@link LinearizationMode.InMemory} we use the cheap document-id RPC; for the disk-based
223
+ * paths we have to fetch the bytes once and delegate to {@link linearizeCoreFromBytes}.
224
+ */
225
+ export async function linearizeCoreFromId(
226
+ id: string,
227
+ getBytes: () => Promise<Buffer>,
228
+ password = "",
229
+ mode: LinearizationMode = LinearizationMode.Automatic
230
+ ): Promise<Buffer> {
231
+ if (mode === LinearizationMode.InMemory) {
232
+ return linearizeInMemoryFromId(id, password);
233
+ }
234
+ const pdfBytes = await getBytes();
235
+ return linearizeCoreFromBytes(pdfBytes, password, mode);
236
+ }
237
+
238
+ /**
239
+ * Linearize via the engine's file-based RPC and persist the result through a client-side
240
+ * temporary file. The client-side disk write is the difference between this and
241
+ * {@link linearizeInMemoryFromBytes} — when the client filesystem is read-only,
242
+ * {@code FileBased} mode fails here so {@link LinearizationMode.Automatic} can fall back.
243
+ *
244
+ * Mirrors C# {@code PdfDocument.LinearizeViaTempFile}.
245
+ */
246
+ async function linearizeViaTempFile(pdfBytes: Buffer, password: string): Promise<Buffer> {
247
+ const linearized = await saveAsLinearizedFromBytes(pdfBytes, "", password);
248
+ const tempPath = path.join(
249
+ os.tmpdir(),
250
+ `ironpdf-linearize-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.pdf`
251
+ );
252
+ try {
253
+ fs.writeFileSync(tempPath, linearized);
254
+ return fs.readFileSync(tempPath);
255
+ } finally {
256
+ try {
257
+ if (fs.existsSync(tempPath)) {
258
+ fs.unlinkSync(tempPath);
259
+ }
260
+ } catch {
261
+ // best-effort cleanup
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Probe whether the current process can create files in the system temp directory.
268
+ */
269
+ function canWriteToTemp(): boolean {
270
+ const probePath = path.join(
271
+ os.tmpdir(),
272
+ `ironpdf-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.tmp`
273
+ );
274
+ try {
275
+ fs.writeFileSync(probePath, "");
276
+ return true;
277
+ } catch {
278
+ return false;
279
+ } finally {
280
+ try {
281
+ if (fs.existsSync(probePath)) {
282
+ fs.unlinkSync(probePath);
283
+ }
284
+ } catch {
285
+ // best-effort cleanup
286
+ }
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Linearize a PDF provided as raw bytes and save the result to disk via the file-based
292
+ * streaming {@code QPdf_Linearization_SaveAsLinearizedFromBytes} RPC.
293
+ *
294
+ * Mirrors the in-memory behavior used by {@link compressInMemory} in {@code compress.ts}:
295
+ * the engine streams the linearized bytes back, and we concatenate and persist them
296
+ * locally at {@code outputPath}.
297
+ */
298
+ export async function saveAsLinearizedFromBytes(
299
+ pdfBytes: Buffer,
300
+ outputPath: string,
301
+ password = ""
302
+ ): Promise<Buffer> {
303
+ const client: IronPdfServiceClient = await Access.ensureConnection();
304
+
305
+ return new Promise(
306
+ (resolve: (_: Buffer) => void, reject: (errorMsg: string) => void) => {
307
+ const stream: grpc.ClientDuplexStream<
308
+ QPdfSaveAsLinearizedFromBytesRequestStreamP,
309
+ BytesResultStreamP__Output
310
+ > = client.QPdf_Linearization_SaveAsLinearizedFromBytes();
311
+
312
+ const buffers: Buffer[] = [];
313
+ stream.on("data", (data: BytesResultStreamP__Output) => {
314
+ if (data.exception) {
315
+ handleRemoteException(data.exception, reject);
316
+ } else if (data.resultChunk) {
317
+ buffers.push(data.resultChunk);
318
+ }
319
+ });
320
+
321
+ stream.on("error", (err: Error) => {
322
+ reject(`${err.name}/n${err.message}`);
323
+ });
324
+
325
+ stream.on("end", () => {
326
+ resolve(Buffer.concat(buffers));
327
+ });
328
+
329
+ stream.write({
330
+ info: {outputPath: outputPath, password: password ?? ""},
331
+ });
332
+ chunkBuffer(pdfBytes).forEach((chunk) => {
333
+ stream.write({pdfBytesChunk: chunk});
334
+ });
335
+ stream.end();
336
+ }
337
+ );
338
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"renderSchema.d.ts","sourceRoot":"","sources":["renderSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAA;AACrB,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EACpB,OAAO,EACP,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EAAE,kBAAkB,EACnC,WAAW,EACX,MAAM,qBAAqB,CAAC;AAK7B,eAAO,MAAM,iBAAiB,EAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAA6B,CAAA;AAEnF,eAAO,MAAM,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAKjE,CAAA;AAEF,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAK/D,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,qBAAqB,EAAG,CAAC,CAAC,OAAO,CAAC,eAAe,CAE5D,CAAA;AAEF,eAAO,MAAM,8BAA8B,EAAG,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAM9E,CAAA;AAEF,eAAO,MAAM,aAAa,EAAG,CAAC,CAAC,OAAO,CAAC,OAAO,CAQ5C,CAAA;AAEF,eAAO,MAAM,0BAA0B,EAAG,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAKtE,CAAA;AAEF,eAAO,MAAM,4BAA4B,EAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAuB1E,CAAA"}
1
+ {"version":3,"file":"renderSchema.d.ts","sourceRoot":"","sources":["renderSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAA;AACrB,OAAO,EACN,sBAAsB,EACtB,oBAAoB,EACpB,OAAO,EACP,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EAAE,kBAAkB,EACnC,WAAW,EACX,MAAM,qBAAqB,CAAC;AAK7B,eAAO,MAAM,iBAAiB,EAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAA6B,CAAA;AAEnF,eAAO,MAAM,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAKjE,CAAA;AAEF,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAK/D,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,yBAAyB,EAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAKpE,CAAA;AAEF,eAAO,MAAM,qBAAqB,EAAG,CAAC,CAAC,OAAO,CAAC,eAAe,CAE5D,CAAA;AAEF,eAAO,MAAM,8BAA8B,EAAG,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAM9E,CAAA;AAEF,eAAO,MAAM,aAAa,EAAG,CAAC,CAAC,OAAO,CAAC,OAAO,CAQ5C,CAAA;AAEF,eAAO,MAAM,0BAA0B,EAAG,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAKtE,CAAA;AAEF,eAAO,MAAM,4BAA4B,EAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,CA4B1E,CAAA"}
@@ -84,6 +84,11 @@ exports.chromePdfRenderOptionsSchema = zod_1.z.object({
84
84
  htmlFooter: affixSchema_1.htmlAffixSchema.optional(),
85
85
  textHeader: affixSchema_1.textAffixSchema.optional(),
86
86
  textFooter: affixSchema_1.textAffixSchema.optional(),
87
- useMarginsOnHeaderAndFooter: typeSchema_1.useMarginsSchema.optional()
87
+ useMarginsOnHeaderAndFooter: typeSchema_1.useMarginsSchema.optional(),
88
+ autoBookmarksFromHeadings: zod_1.z.boolean().optional(),
89
+ autoBookmarkMinHeadingLevel: zod_1.z.number().int().min(1).max(6).optional(),
90
+ autoBookmarkMaxHeadingLevel: zod_1.z.number().int().min(1).max(6).optional(),
91
+ autoBookmarkCssSelectors: zod_1.z.array(zod_1.z.string()).optional(),
92
+ elementQuerySelectors: zod_1.z.array(zod_1.z.string()).optional()
88
93
  });
89
94
  //# sourceMappingURL=renderSchema.js.map