@json-to-office/jto-ops 1.4.0 → 1.11.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/dist/index.js CHANGED
@@ -892,6 +892,36 @@ function toGenerationWarnings(raw) {
892
892
  }
893
893
  }));
894
894
  }
895
+ function preparedThemeLabel(prepared) {
896
+ const label = prepared.metadata?.themeLabel;
897
+ return typeof label === "string" ? label : void 0;
898
+ }
899
+ var PREPARED_SOURCE = Symbol("jto.prepared.source");
900
+ var PREPARED_WARNINGS = Symbol("jto.prepared.warnings");
901
+ function stampPrepared(prepared, source, warnings) {
902
+ return Object.assign(prepared, {
903
+ [PREPARED_SOURCE]: source,
904
+ [PREPARED_WARNINGS]: warnings
905
+ });
906
+ }
907
+ function preparedFor(prepared, document) {
908
+ if (!prepared) return void 0;
909
+ const source = prepared[PREPARED_SOURCE];
910
+ return source !== void 0 && source === document ? prepared : void 0;
911
+ }
912
+ function warningKey(warning) {
913
+ return `${warning.component}|${warning.context?.code ?? ""}|${warning.message}`;
914
+ }
915
+ function withoutPreparedWarnings(warnings, prepared) {
916
+ const emitted = prepared?.[PREPARED_WARNINGS];
917
+ if (!emitted || emitted.length === 0) return warnings;
918
+ const seen = new Set(emitted.map(warningKey));
919
+ return warnings.filter((warning) => !seen.has(warningKey(warning)));
920
+ }
921
+ function documentRenderer(document) {
922
+ const renderer = document?.renderer;
923
+ return typeof renderer === "string" ? renderer : void 0;
924
+ }
895
925
  var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
896
926
  function safeThemeKey(name) {
897
927
  return name && !UNSAFE_KEYS.has(name) ? name : "custom";
@@ -967,12 +997,24 @@ var DocxFormatAdapter = class {
967
997
  async generateBuffer(json, options) {
968
998
  const core = await import("@json-to-office/core-docx");
969
999
  const parsed = typeof json === "string" ? JSON.parse(json) : json;
970
- const resolved = await this.resolveThemes(options);
971
- const { document: docDefinition, customThemes } = withRequestedTheme(
972
- parsed,
973
- resolved.requested,
974
- resolved.customThemes
1000
+ const prepared = preparedFor(
1001
+ options.prepared?.format === "docx" ? options.prepared : void 0,
1002
+ parsed
975
1003
  );
1004
+ let docDefinition;
1005
+ let customThemes;
1006
+ if (prepared) {
1007
+ docDefinition = prepared.model.authored;
1008
+ } else {
1009
+ const resolved = await this.resolveThemes(options);
1010
+ const normalized = withRequestedTheme(
1011
+ parsed,
1012
+ resolved.requested,
1013
+ resolved.customThemes
1014
+ );
1015
+ docDefinition = normalized.document;
1016
+ customThemes = normalized.customThemes;
1017
+ }
976
1018
  const services = buildDocxServices();
977
1019
  const warnings = [];
978
1020
  const buffer = await core.generateBufferFromJson(docDefinition, {
@@ -986,10 +1028,13 @@ var DocxFormatAdapter = class {
986
1028
  generatedAt: options.generatedAt,
987
1029
  baseDir: options.baseDir,
988
1030
  renderer: options.renderer,
1031
+ svgRasterFallback: options.svgRasterFallback,
1032
+ prepared,
989
1033
  warnings
990
1034
  });
991
- emitGenerationWarnings(warnings);
992
- options.warnings?.push(...toGenerationWarnings(warnings));
1035
+ const emitted = withoutPreparedWarnings(warnings, prepared);
1036
+ emitGenerationWarnings(emitted);
1037
+ options.warnings?.push(...toGenerationWarnings(emitted));
993
1038
  return buffer;
994
1039
  }
995
1040
  async createGenerator(plugins, options) {
@@ -997,32 +1042,46 @@ var DocxFormatAdapter = class {
997
1042
  const hasPlugins = plugins.length > 0;
998
1043
  const pluginNames = plugins.map((p) => p.name);
999
1044
  const services = buildDocxServices();
1000
- const {
1001
- requested: requestedTheme,
1002
- customThemes,
1003
- label: themeLabel
1004
- } = await this.resolveThemes(options);
1045
+ const prepared = !hasPlugins && options.prepared?.format === "docx" ? options.prepared : void 0;
1046
+ const resolved = prepared ? void 0 : await this.resolveThemes(options);
1047
+ const requestedTheme = resolved?.requested;
1048
+ const customThemes = resolved?.customThemes;
1049
+ const themeLabel = prepared ? preparedThemeLabel(prepared) : resolved?.label;
1005
1050
  if (!hasPlugins) {
1051
+ let fallbackThemes;
1052
+ const themesFor = () => fallbackThemes ??= resolved ? Promise.resolve(resolved) : this.resolveThemes(options);
1006
1053
  return {
1007
1054
  generateBuffer: async (document) => {
1008
1055
  const parsed = typeof document === "string" ? JSON.parse(document) : document;
1009
- const { document: docDefinition, customThemes: themes } = withRequestedTheme(parsed, requestedTheme, customThemes);
1056
+ const usable = preparedFor(prepared, parsed);
1057
+ const themes = usable ? void 0 : await themesFor();
1058
+ const normalized = usable ? { document: usable.model.authored, customThemes: void 0 } : withRequestedTheme(
1059
+ parsed,
1060
+ themes?.requested,
1061
+ themes?.customThemes
1062
+ );
1010
1063
  const warnings = [];
1011
- const buffer = await core.generateBufferFromJson(docDefinition, {
1012
- customThemes: themes,
1013
- services,
1014
- fonts: options.fonts,
1015
- validation: {
1016
- allowUnknownFields: options.validation?.allowUnknownFields
1017
- },
1018
- deterministic: options.deterministic,
1019
- generatedAt: options.generatedAt,
1020
- baseDir: options.baseDir,
1021
- renderer: options.renderer,
1022
- warnings
1023
- });
1024
- emitGenerationWarnings(warnings);
1025
- options.warnings?.push(...toGenerationWarnings(warnings));
1064
+ const buffer = await core.generateBufferFromJson(
1065
+ normalized.document,
1066
+ {
1067
+ customThemes: normalized.customThemes,
1068
+ services,
1069
+ fonts: options.fonts,
1070
+ validation: {
1071
+ allowUnknownFields: options.validation?.allowUnknownFields
1072
+ },
1073
+ deterministic: options.deterministic,
1074
+ generatedAt: options.generatedAt,
1075
+ baseDir: options.baseDir,
1076
+ renderer: options.renderer,
1077
+ svgRasterFallback: options.svgRasterFallback,
1078
+ prepared: usable,
1079
+ warnings
1080
+ }
1081
+ );
1082
+ const emitted = withoutPreparedWarnings(warnings, usable);
1083
+ emitGenerationWarnings(emitted);
1084
+ options.warnings?.push(...toGenerationWarnings(emitted));
1026
1085
  return buffer;
1027
1086
  },
1028
1087
  hasPlugins: false,
@@ -1045,7 +1104,8 @@ var DocxFormatAdapter = class {
1045
1104
  deterministic: options.deterministic,
1046
1105
  generatedAt: options.generatedAt,
1047
1106
  baseDir: options.baseDir,
1048
- renderer: options.renderer
1107
+ renderer: options.renderer,
1108
+ svgRasterFallback: options.svgRasterFallback
1049
1109
  });
1050
1110
  for (const plugin of plugins) {
1051
1111
  generator = generator.addComponent(plugin);
@@ -1065,7 +1125,8 @@ var DocxFormatAdapter = class {
1065
1125
  deterministic: options.deterministic,
1066
1126
  generatedAt: options.generatedAt,
1067
1127
  baseDir: options.baseDir,
1068
- renderer: options.renderer
1128
+ renderer: options.renderer,
1129
+ svgRasterFallback: options.svgRasterFallback
1069
1130
  });
1070
1131
  emitGenerationWarnings(result.warnings ?? []);
1071
1132
  options.warnings?.push(...toGenerationWarnings(result.warnings));
@@ -1104,6 +1165,64 @@ var DocxFormatAdapter = class {
1104
1165
  ...result.errors.length > 0 && { errors: result.errors }
1105
1166
  };
1106
1167
  }
1168
+ async analyzeQuality(doc, options = {}) {
1169
+ const core = await import("@json-to-office/core-docx");
1170
+ const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
1171
+ let prepared = preparedFor(
1172
+ options.prepared?.format === "docx" ? options.prepared : void 0,
1173
+ parsed
1174
+ );
1175
+ if (!prepared) {
1176
+ try {
1177
+ prepared = await this.prepareModel(parsed, options, []);
1178
+ } catch {
1179
+ }
1180
+ }
1181
+ return core.analyzeDocxQuality(prepared?.model.authored ?? parsed, {
1182
+ ...prepared && { prepared },
1183
+ renderer: options.renderer ?? documentRenderer(parsed),
1184
+ profile: options.quality?.profile,
1185
+ policy: options.quality?.policy
1186
+ });
1187
+ }
1188
+ async prepareDocument(doc, options = {}) {
1189
+ const warnings = [];
1190
+ const prepared = await this.prepareModel(doc, options, warnings);
1191
+ emitGenerationWarnings(warnings);
1192
+ options.warnings?.push(...toGenerationWarnings(warnings));
1193
+ return prepared;
1194
+ }
1195
+ /** Prepare into a caller-owned sink; `prepareDocument` owns the reporting. */
1196
+ async prepareModel(doc, options, warnings) {
1197
+ const core = await import("@json-to-office/core-docx");
1198
+ const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
1199
+ const resolved = await this.resolveThemes(options);
1200
+ const normalized = withRequestedTheme(
1201
+ parsed,
1202
+ resolved.requested,
1203
+ resolved.customThemes
1204
+ );
1205
+ const prepared = core.prepareDocxQualityDocument(
1206
+ normalized.document,
1207
+ {
1208
+ customThemes: normalized.customThemes,
1209
+ fonts: options.fonts,
1210
+ renderer: options.renderer ?? documentRenderer(parsed),
1211
+ warnings
1212
+ }
1213
+ );
1214
+ return stampPrepared(
1215
+ {
1216
+ ...prepared,
1217
+ metadata: {
1218
+ ...prepared.metadata,
1219
+ ...resolved.label && { themeLabel: resolved.label }
1220
+ }
1221
+ },
1222
+ parsed,
1223
+ toGenerationWarnings(warnings)
1224
+ );
1225
+ }
1107
1226
  generateSchema(_options) {
1108
1227
  return null;
1109
1228
  }
@@ -1115,6 +1234,10 @@ var DocxFormatAdapter = class {
1115
1234
  return {};
1116
1235
  }
1117
1236
  }
1237
+ async getBuiltinThemeValues() {
1238
+ const core = await import("@json-to-office/core-docx");
1239
+ return core.themes || {};
1240
+ }
1118
1241
  async resolveTheme(options) {
1119
1242
  const core = await import("@json-to-office/core-docx");
1120
1243
  const { requested } = await this.resolveThemes(options);
@@ -1227,12 +1350,24 @@ var PptxFormatAdapter = class {
1227
1350
  async generateBuffer(json, options) {
1228
1351
  const core = await import("@json-to-office/core-pptx");
1229
1352
  const parsed = typeof json === "string" ? JSON.parse(json) : json;
1230
- const resolved = await this.resolveThemes(options);
1231
- const { document: docDefinition, customThemes } = withRequestedTheme(
1232
- parsed,
1233
- resolved.requested,
1234
- resolved.customThemes
1353
+ const prepared = preparedFor(
1354
+ options.prepared?.format === "pptx" ? options.prepared : void 0,
1355
+ parsed
1235
1356
  );
1357
+ let docDefinition;
1358
+ let customThemes;
1359
+ if (prepared) {
1360
+ docDefinition = prepared.model.authored;
1361
+ } else {
1362
+ const resolved = await this.resolveThemes(options);
1363
+ const normalized = withRequestedTheme(
1364
+ parsed,
1365
+ resolved.requested,
1366
+ resolved.customThemes
1367
+ );
1368
+ docDefinition = normalized.document;
1369
+ customThemes = normalized.customThemes;
1370
+ }
1236
1371
  const services = buildServicesFromEnv();
1237
1372
  const result = await core.generateBufferWithWarnings(docDefinition, {
1238
1373
  customThemes,
@@ -1244,11 +1379,15 @@ var PptxFormatAdapter = class {
1244
1379
  deterministic: options.deterministic,
1245
1380
  generatedAt: options.generatedAt,
1246
1381
  baseDir: options.baseDir,
1247
- renderer: options.renderer
1382
+ renderer: options.renderer,
1383
+ prepared
1248
1384
  });
1249
- const normalized = toGenerationWarnings(result.warnings);
1250
- emitGenerationWarnings(normalized);
1251
- options.warnings?.push(...normalized);
1385
+ const emitted = withoutPreparedWarnings(
1386
+ toGenerationWarnings(result.warnings),
1387
+ prepared
1388
+ );
1389
+ emitGenerationWarnings(emitted);
1390
+ options.warnings?.push(...emitted);
1252
1391
  return result.buffer;
1253
1392
  }
1254
1393
  async createGenerator(plugins, options) {
@@ -1256,31 +1395,46 @@ var PptxFormatAdapter = class {
1256
1395
  const hasPlugins = plugins.length > 0;
1257
1396
  const pluginNames = plugins.map((p) => p.name);
1258
1397
  const services = buildServicesFromEnv();
1259
- const {
1260
- requested: requestedTheme,
1261
- customThemes,
1262
- label: themeLabel
1263
- } = await this.resolveThemes(options);
1398
+ const prepared = !hasPlugins && options.prepared?.format === "pptx" ? options.prepared : void 0;
1399
+ const resolved = prepared ? void 0 : await this.resolveThemes(options);
1400
+ const requestedTheme = resolved?.requested;
1401
+ const customThemes = resolved?.customThemes;
1402
+ const themeLabel = prepared ? preparedThemeLabel(prepared) : resolved?.label;
1264
1403
  if (!hasPlugins) {
1404
+ let fallbackThemes;
1405
+ const themesFor = () => fallbackThemes ??= resolved ? Promise.resolve(resolved) : this.resolveThemes(options);
1265
1406
  return {
1266
1407
  generateBuffer: async (document) => {
1267
1408
  const parsed = typeof document === "string" ? JSON.parse(document) : document;
1268
- const { document: docDefinition, customThemes: themes } = withRequestedTheme(parsed, requestedTheme, customThemes);
1269
- const result = await core.generateBufferWithWarnings(docDefinition, {
1270
- customThemes: themes,
1271
- services,
1272
- fonts: options.fonts,
1273
- validation: {
1274
- allowUnknownFields: options.validation?.allowUnknownFields
1275
- },
1276
- deterministic: options.deterministic,
1277
- generatedAt: options.generatedAt,
1278
- baseDir: options.baseDir,
1279
- renderer: options.renderer
1280
- });
1281
- const normalized = toGenerationWarnings(result.warnings);
1282
- emitGenerationWarnings(normalized);
1283
- options.warnings?.push(...normalized);
1409
+ const usable = preparedFor(prepared, parsed);
1410
+ const themes = usable ? void 0 : await themesFor();
1411
+ const normalized = usable ? { document: usable.model.authored, customThemes: void 0 } : withRequestedTheme(
1412
+ parsed,
1413
+ themes?.requested,
1414
+ themes?.customThemes
1415
+ );
1416
+ const result = await core.generateBufferWithWarnings(
1417
+ normalized.document,
1418
+ {
1419
+ customThemes: normalized.customThemes,
1420
+ services,
1421
+ fonts: options.fonts,
1422
+ validation: {
1423
+ allowUnknownFields: options.validation?.allowUnknownFields
1424
+ },
1425
+ deterministic: options.deterministic,
1426
+ generatedAt: options.generatedAt,
1427
+ baseDir: options.baseDir,
1428
+ renderer: options.renderer,
1429
+ prepared: usable
1430
+ }
1431
+ );
1432
+ const warnings = withoutPreparedWarnings(
1433
+ toGenerationWarnings(result.warnings),
1434
+ usable
1435
+ );
1436
+ emitGenerationWarnings(warnings);
1437
+ options.warnings?.push(...warnings);
1284
1438
  return result.buffer;
1285
1439
  },
1286
1440
  hasPlugins: false,
@@ -1345,6 +1499,66 @@ var PptxFormatAdapter = class {
1345
1499
  ...result.errors.length > 0 && { errors: result.errors }
1346
1500
  };
1347
1501
  }
1502
+ async analyzeQuality(doc, options = {}) {
1503
+ const core = await import("@json-to-office/core-pptx");
1504
+ const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
1505
+ let prepared = preparedFor(
1506
+ options.prepared?.format === "pptx" ? options.prepared : void 0,
1507
+ parsed
1508
+ );
1509
+ if (!prepared) {
1510
+ try {
1511
+ prepared = await this.prepareModel(parsed, options, []);
1512
+ } catch {
1513
+ }
1514
+ }
1515
+ return core.analyzePptxQuality(prepared?.model.authored ?? parsed, {
1516
+ ...prepared && { prepared },
1517
+ renderer: options.renderer ?? documentRenderer(parsed),
1518
+ profile: options.quality?.profile,
1519
+ policy: options.quality?.policy
1520
+ });
1521
+ }
1522
+ async prepareDocument(doc, options = {}) {
1523
+ const warnings = [];
1524
+ const prepared = await this.prepareModel(doc, options, warnings);
1525
+ const normalized = toGenerationWarnings(warnings);
1526
+ emitGenerationWarnings(normalized);
1527
+ options.warnings?.push(...normalized);
1528
+ return prepared;
1529
+ }
1530
+ /** Prepare into a caller-owned sink; `prepareDocument` owns the reporting. */
1531
+ async prepareModel(doc, options, warnings) {
1532
+ const core = await import("@json-to-office/core-pptx");
1533
+ const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
1534
+ const resolved = await this.resolveThemes(options);
1535
+ const normalized = withRequestedTheme(
1536
+ parsed,
1537
+ resolved.requested,
1538
+ resolved.customThemes
1539
+ );
1540
+ const prepared = core.preparePptxQualityDocument(
1541
+ normalized.document,
1542
+ {
1543
+ customThemes: normalized.customThemes,
1544
+ fonts: options.fonts,
1545
+ services: buildServicesFromEnv(),
1546
+ renderer: options.renderer ?? documentRenderer(parsed),
1547
+ warnings
1548
+ }
1549
+ );
1550
+ return stampPrepared(
1551
+ {
1552
+ ...prepared,
1553
+ metadata: {
1554
+ ...prepared.metadata,
1555
+ ...resolved.label && { themeLabel: resolved.label }
1556
+ }
1557
+ },
1558
+ parsed,
1559
+ toGenerationWarnings(warnings)
1560
+ );
1561
+ }
1348
1562
  generateSchema(_options) {
1349
1563
  return null;
1350
1564
  }
@@ -1356,6 +1570,10 @@ var PptxFormatAdapter = class {
1356
1570
  return {};
1357
1571
  }
1358
1572
  }
1573
+ async getBuiltinThemeValues() {
1574
+ const core = await import("@json-to-office/core-pptx");
1575
+ return core.pptxThemes || {};
1576
+ }
1359
1577
  async resolveTheme(options) {
1360
1578
  const core = await import("@json-to-office/core-pptx");
1361
1579
  const themes = core.pptxThemes || {};
@@ -1448,6 +1666,116 @@ function createAdapter(format) {
1448
1666
  throw new Error(`Unknown format: ${format}`);
1449
1667
  }
1450
1668
  }
1669
+
1670
+ // src/pdf-text-geometry.ts
1671
+ import { execFile as execFile2 } from "child_process";
1672
+ import * as path6 from "path";
1673
+ var ENTITIES = {
1674
+ "&": "&",
1675
+ "&lt;": "<",
1676
+ "&gt;": ">",
1677
+ "&quot;": '"',
1678
+ "&apos;": "'",
1679
+ "&#34;": '"',
1680
+ "&#39;": "'"
1681
+ };
1682
+ function decodeEntities(value) {
1683
+ return value.replace(
1684
+ /&(?:amp|lt|gt|quot|apos|#34|#39);/g,
1685
+ (entity) => ENTITIES[entity] ?? entity
1686
+ );
1687
+ }
1688
+ var PAGE_PATTERN = /<page\s+width="([\d.]+)"\s+height="([\d.]+)">([\s\S]*?)<\/page>/g;
1689
+ var WORD_PATTERN = /<word\s+xMin="(-?[\d.]+)"\s+yMin="(-?[\d.]+)"\s+xMax="(-?[\d.]+)"\s+yMax="(-?[\d.]+)">([\s\S]*?)<\/word>/g;
1690
+ function parsePdfTextBbox(bboxXml) {
1691
+ const pages = [];
1692
+ for (const pageMatch of bboxXml.matchAll(PAGE_PATTERN)) {
1693
+ const words = [];
1694
+ for (const wordMatch of pageMatch[3].matchAll(WORD_PATTERN)) {
1695
+ words.push({
1696
+ xMin: Number(wordMatch[1]),
1697
+ yMin: Number(wordMatch[2]),
1698
+ xMax: Number(wordMatch[3]),
1699
+ yMax: Number(wordMatch[4]),
1700
+ text: decodeEntities(wordMatch[5])
1701
+ });
1702
+ }
1703
+ pages.push({
1704
+ widthPt: Number(pageMatch[1]),
1705
+ heightPt: Number(pageMatch[2]),
1706
+ words
1707
+ });
1708
+ }
1709
+ return pages;
1710
+ }
1711
+ function pdftotextCandidates() {
1712
+ const candidates = [];
1713
+ const configured = process.env.PDFTOTEXT_PATH?.trim();
1714
+ if (configured) candidates.push(configured);
1715
+ candidates.push("pdftotext");
1716
+ return [...new Set(candidates)];
1717
+ }
1718
+ async function run(binary, args, timeoutMs) {
1719
+ return new Promise((resolve2, reject) => {
1720
+ execFile2(
1721
+ binary,
1722
+ args,
1723
+ { timeout: timeoutMs, maxBuffer: 64 * 1024 * 1024 },
1724
+ (error, stdout) => {
1725
+ if (error) reject(error);
1726
+ else resolve2(stdout);
1727
+ }
1728
+ );
1729
+ });
1730
+ }
1731
+ var pdftotextPromise;
1732
+ async function resolvePdftotext() {
1733
+ if (!pdftotextPromise) {
1734
+ pdftotextPromise = (async () => {
1735
+ for (const candidate of pdftotextCandidates()) {
1736
+ if (candidate.includes(path6.sep)) {
1737
+ try {
1738
+ await run(candidate, ["-v"], 1e4);
1739
+ return candidate;
1740
+ } catch {
1741
+ continue;
1742
+ }
1743
+ }
1744
+ try {
1745
+ await run(candidate, ["-v"], 1e4);
1746
+ return candidate;
1747
+ } catch (error) {
1748
+ const code = error.code;
1749
+ if (code !== "ENOENT" && code !== "EACCES") return candidate;
1750
+ }
1751
+ }
1752
+ throw new Error(
1753
+ `Text geometry extraction needs pdftotext (poppler), which was not found. Install poppler-utils or set PDFTOTEXT_PATH (searched: ${pdftotextCandidates().join(", ")}).`
1754
+ );
1755
+ })().catch((error) => {
1756
+ pdftotextPromise = void 0;
1757
+ throw error;
1758
+ });
1759
+ }
1760
+ return pdftotextPromise;
1761
+ }
1762
+ async function pdftotextAvailable() {
1763
+ try {
1764
+ await resolvePdftotext();
1765
+ return true;
1766
+ } catch {
1767
+ return false;
1768
+ }
1769
+ }
1770
+ async function extractPdfTextGeometry(pdfPath, options = {}) {
1771
+ const binary = await resolvePdftotext();
1772
+ const stdout = await run(
1773
+ binary,
1774
+ ["-bbox", pdfPath, "-"],
1775
+ options.timeoutMs ?? 6e4
1776
+ );
1777
+ return parsePdfTextBbox(stdout);
1778
+ }
1451
1779
  export {
1452
1780
  DocxFormatAdapter,
1453
1781
  FontconfigStager,
@@ -1460,8 +1788,11 @@ export {
1460
1788
  createLibreOfficePptxBatchRasterizer,
1461
1789
  createLibreOfficePptxRasterizer,
1462
1790
  emitDiagnostic,
1791
+ extractPdfTextGeometry,
1463
1792
  getFontStager,
1464
1793
  getRasterizerCacheStats,
1794
+ parsePdfTextBbox,
1795
+ pdftotextAvailable,
1465
1796
  runWithDiagnosticSink,
1466
1797
  stderrDiagnosticSink
1467
1798
  };