@json-to-office/jto-ops 1.2.0 → 1.5.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.d.ts +87 -2
- package/dist/index.js +393 -58
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
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";
|
|
@@ -960,15 +990,31 @@ var DocxFormatAdapter = class {
|
|
|
960
990
|
const core = await import("@json-to-office/core-docx");
|
|
961
991
|
return core.docxRendererIds();
|
|
962
992
|
}
|
|
993
|
+
async rendererStatuses() {
|
|
994
|
+
const core = await import("@json-to-office/core-docx");
|
|
995
|
+
return core.docxRendererStatuses();
|
|
996
|
+
}
|
|
963
997
|
async generateBuffer(json, options) {
|
|
964
998
|
const core = await import("@json-to-office/core-docx");
|
|
965
999
|
const parsed = typeof json === "string" ? JSON.parse(json) : json;
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
parsed
|
|
969
|
-
resolved.requested,
|
|
970
|
-
resolved.customThemes
|
|
1000
|
+
const prepared = preparedFor(
|
|
1001
|
+
options.prepared?.format === "docx" ? options.prepared : void 0,
|
|
1002
|
+
parsed
|
|
971
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
|
+
}
|
|
972
1018
|
const services = buildDocxServices();
|
|
973
1019
|
const warnings = [];
|
|
974
1020
|
const buffer = await core.generateBufferFromJson(docDefinition, {
|
|
@@ -982,10 +1028,12 @@ var DocxFormatAdapter = class {
|
|
|
982
1028
|
generatedAt: options.generatedAt,
|
|
983
1029
|
baseDir: options.baseDir,
|
|
984
1030
|
renderer: options.renderer,
|
|
1031
|
+
prepared,
|
|
985
1032
|
warnings
|
|
986
1033
|
});
|
|
987
|
-
|
|
988
|
-
|
|
1034
|
+
const emitted = withoutPreparedWarnings(warnings, prepared);
|
|
1035
|
+
emitGenerationWarnings(emitted);
|
|
1036
|
+
options.warnings?.push(...toGenerationWarnings(emitted));
|
|
989
1037
|
return buffer;
|
|
990
1038
|
}
|
|
991
1039
|
async createGenerator(plugins, options) {
|
|
@@ -993,32 +1041,45 @@ var DocxFormatAdapter = class {
|
|
|
993
1041
|
const hasPlugins = plugins.length > 0;
|
|
994
1042
|
const pluginNames = plugins.map((p) => p.name);
|
|
995
1043
|
const services = buildDocxServices();
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1044
|
+
const prepared = !hasPlugins && options.prepared?.format === "docx" ? options.prepared : void 0;
|
|
1045
|
+
const resolved = prepared ? void 0 : await this.resolveThemes(options);
|
|
1046
|
+
const requestedTheme = resolved?.requested;
|
|
1047
|
+
const customThemes = resolved?.customThemes;
|
|
1048
|
+
const themeLabel = prepared ? preparedThemeLabel(prepared) : resolved?.label;
|
|
1001
1049
|
if (!hasPlugins) {
|
|
1050
|
+
let fallbackThemes;
|
|
1051
|
+
const themesFor = () => fallbackThemes ??= resolved ? Promise.resolve(resolved) : this.resolveThemes(options);
|
|
1002
1052
|
return {
|
|
1003
1053
|
generateBuffer: async (document) => {
|
|
1004
1054
|
const parsed = typeof document === "string" ? JSON.parse(document) : document;
|
|
1005
|
-
const
|
|
1055
|
+
const usable = preparedFor(prepared, parsed);
|
|
1056
|
+
const themes = usable ? void 0 : await themesFor();
|
|
1057
|
+
const normalized = usable ? { document: usable.model.authored, customThemes: void 0 } : withRequestedTheme(
|
|
1058
|
+
parsed,
|
|
1059
|
+
themes?.requested,
|
|
1060
|
+
themes?.customThemes
|
|
1061
|
+
);
|
|
1006
1062
|
const warnings = [];
|
|
1007
|
-
const buffer = await core.generateBufferFromJson(
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1063
|
+
const buffer = await core.generateBufferFromJson(
|
|
1064
|
+
normalized.document,
|
|
1065
|
+
{
|
|
1066
|
+
customThemes: normalized.customThemes,
|
|
1067
|
+
services,
|
|
1068
|
+
fonts: options.fonts,
|
|
1069
|
+
validation: {
|
|
1070
|
+
allowUnknownFields: options.validation?.allowUnknownFields
|
|
1071
|
+
},
|
|
1072
|
+
deterministic: options.deterministic,
|
|
1073
|
+
generatedAt: options.generatedAt,
|
|
1074
|
+
baseDir: options.baseDir,
|
|
1075
|
+
renderer: options.renderer,
|
|
1076
|
+
prepared: usable,
|
|
1077
|
+
warnings
|
|
1078
|
+
}
|
|
1079
|
+
);
|
|
1080
|
+
const emitted = withoutPreparedWarnings(warnings, usable);
|
|
1081
|
+
emitGenerationWarnings(emitted);
|
|
1082
|
+
options.warnings?.push(...toGenerationWarnings(emitted));
|
|
1022
1083
|
return buffer;
|
|
1023
1084
|
},
|
|
1024
1085
|
hasPlugins: false,
|
|
@@ -1100,6 +1161,64 @@ var DocxFormatAdapter = class {
|
|
|
1100
1161
|
...result.errors.length > 0 && { errors: result.errors }
|
|
1101
1162
|
};
|
|
1102
1163
|
}
|
|
1164
|
+
async analyzeQuality(doc, options = {}) {
|
|
1165
|
+
const core = await import("@json-to-office/core-docx");
|
|
1166
|
+
const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
|
|
1167
|
+
let prepared = preparedFor(
|
|
1168
|
+
options.prepared?.format === "docx" ? options.prepared : void 0,
|
|
1169
|
+
parsed
|
|
1170
|
+
);
|
|
1171
|
+
if (!prepared) {
|
|
1172
|
+
try {
|
|
1173
|
+
prepared = await this.prepareModel(parsed, options, []);
|
|
1174
|
+
} catch {
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
return core.analyzeDocxQuality(prepared?.model.authored ?? parsed, {
|
|
1178
|
+
...prepared && { prepared },
|
|
1179
|
+
renderer: options.renderer ?? documentRenderer(parsed),
|
|
1180
|
+
profile: options.quality?.profile,
|
|
1181
|
+
policy: options.quality?.policy
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
async prepareDocument(doc, options = {}) {
|
|
1185
|
+
const warnings = [];
|
|
1186
|
+
const prepared = await this.prepareModel(doc, options, warnings);
|
|
1187
|
+
emitGenerationWarnings(warnings);
|
|
1188
|
+
options.warnings?.push(...toGenerationWarnings(warnings));
|
|
1189
|
+
return prepared;
|
|
1190
|
+
}
|
|
1191
|
+
/** Prepare into a caller-owned sink; `prepareDocument` owns the reporting. */
|
|
1192
|
+
async prepareModel(doc, options, warnings) {
|
|
1193
|
+
const core = await import("@json-to-office/core-docx");
|
|
1194
|
+
const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
|
|
1195
|
+
const resolved = await this.resolveThemes(options);
|
|
1196
|
+
const normalized = withRequestedTheme(
|
|
1197
|
+
parsed,
|
|
1198
|
+
resolved.requested,
|
|
1199
|
+
resolved.customThemes
|
|
1200
|
+
);
|
|
1201
|
+
const prepared = core.prepareDocxQualityDocument(
|
|
1202
|
+
normalized.document,
|
|
1203
|
+
{
|
|
1204
|
+
customThemes: normalized.customThemes,
|
|
1205
|
+
fonts: options.fonts,
|
|
1206
|
+
renderer: options.renderer ?? documentRenderer(parsed),
|
|
1207
|
+
warnings
|
|
1208
|
+
}
|
|
1209
|
+
);
|
|
1210
|
+
return stampPrepared(
|
|
1211
|
+
{
|
|
1212
|
+
...prepared,
|
|
1213
|
+
metadata: {
|
|
1214
|
+
...prepared.metadata,
|
|
1215
|
+
...resolved.label && { themeLabel: resolved.label }
|
|
1216
|
+
}
|
|
1217
|
+
},
|
|
1218
|
+
parsed,
|
|
1219
|
+
toGenerationWarnings(warnings)
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1103
1222
|
generateSchema(_options) {
|
|
1104
1223
|
return null;
|
|
1105
1224
|
}
|
|
@@ -1111,6 +1230,10 @@ var DocxFormatAdapter = class {
|
|
|
1111
1230
|
return {};
|
|
1112
1231
|
}
|
|
1113
1232
|
}
|
|
1233
|
+
async getBuiltinThemeValues() {
|
|
1234
|
+
const core = await import("@json-to-office/core-docx");
|
|
1235
|
+
return core.themes || {};
|
|
1236
|
+
}
|
|
1114
1237
|
async resolveTheme(options) {
|
|
1115
1238
|
const core = await import("@json-to-office/core-docx");
|
|
1116
1239
|
const { requested } = await this.resolveThemes(options);
|
|
@@ -1216,15 +1339,31 @@ var PptxFormatAdapter = class {
|
|
|
1216
1339
|
const core = await import("@json-to-office/core-pptx");
|
|
1217
1340
|
return core.pptxRendererIds();
|
|
1218
1341
|
}
|
|
1342
|
+
async rendererStatuses() {
|
|
1343
|
+
const core = await import("@json-to-office/core-pptx");
|
|
1344
|
+
return core.pptxRendererStatuses();
|
|
1345
|
+
}
|
|
1219
1346
|
async generateBuffer(json, options) {
|
|
1220
1347
|
const core = await import("@json-to-office/core-pptx");
|
|
1221
1348
|
const parsed = typeof json === "string" ? JSON.parse(json) : json;
|
|
1222
|
-
const
|
|
1223
|
-
|
|
1224
|
-
parsed
|
|
1225
|
-
resolved.requested,
|
|
1226
|
-
resolved.customThemes
|
|
1349
|
+
const prepared = preparedFor(
|
|
1350
|
+
options.prepared?.format === "pptx" ? options.prepared : void 0,
|
|
1351
|
+
parsed
|
|
1227
1352
|
);
|
|
1353
|
+
let docDefinition;
|
|
1354
|
+
let customThemes;
|
|
1355
|
+
if (prepared) {
|
|
1356
|
+
docDefinition = prepared.model.authored;
|
|
1357
|
+
} else {
|
|
1358
|
+
const resolved = await this.resolveThemes(options);
|
|
1359
|
+
const normalized = withRequestedTheme(
|
|
1360
|
+
parsed,
|
|
1361
|
+
resolved.requested,
|
|
1362
|
+
resolved.customThemes
|
|
1363
|
+
);
|
|
1364
|
+
docDefinition = normalized.document;
|
|
1365
|
+
customThemes = normalized.customThemes;
|
|
1366
|
+
}
|
|
1228
1367
|
const services = buildServicesFromEnv();
|
|
1229
1368
|
const result = await core.generateBufferWithWarnings(docDefinition, {
|
|
1230
1369
|
customThemes,
|
|
@@ -1236,11 +1375,15 @@ var PptxFormatAdapter = class {
|
|
|
1236
1375
|
deterministic: options.deterministic,
|
|
1237
1376
|
generatedAt: options.generatedAt,
|
|
1238
1377
|
baseDir: options.baseDir,
|
|
1239
|
-
renderer: options.renderer
|
|
1378
|
+
renderer: options.renderer,
|
|
1379
|
+
prepared
|
|
1240
1380
|
});
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1381
|
+
const emitted = withoutPreparedWarnings(
|
|
1382
|
+
toGenerationWarnings(result.warnings),
|
|
1383
|
+
prepared
|
|
1384
|
+
);
|
|
1385
|
+
emitGenerationWarnings(emitted);
|
|
1386
|
+
options.warnings?.push(...emitted);
|
|
1244
1387
|
return result.buffer;
|
|
1245
1388
|
}
|
|
1246
1389
|
async createGenerator(plugins, options) {
|
|
@@ -1248,31 +1391,46 @@ var PptxFormatAdapter = class {
|
|
|
1248
1391
|
const hasPlugins = plugins.length > 0;
|
|
1249
1392
|
const pluginNames = plugins.map((p) => p.name);
|
|
1250
1393
|
const services = buildServicesFromEnv();
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1394
|
+
const prepared = !hasPlugins && options.prepared?.format === "pptx" ? options.prepared : void 0;
|
|
1395
|
+
const resolved = prepared ? void 0 : await this.resolveThemes(options);
|
|
1396
|
+
const requestedTheme = resolved?.requested;
|
|
1397
|
+
const customThemes = resolved?.customThemes;
|
|
1398
|
+
const themeLabel = prepared ? preparedThemeLabel(prepared) : resolved?.label;
|
|
1256
1399
|
if (!hasPlugins) {
|
|
1400
|
+
let fallbackThemes;
|
|
1401
|
+
const themesFor = () => fallbackThemes ??= resolved ? Promise.resolve(resolved) : this.resolveThemes(options);
|
|
1257
1402
|
return {
|
|
1258
1403
|
generateBuffer: async (document) => {
|
|
1259
1404
|
const parsed = typeof document === "string" ? JSON.parse(document) : document;
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1405
|
+
const usable = preparedFor(prepared, parsed);
|
|
1406
|
+
const themes = usable ? void 0 : await themesFor();
|
|
1407
|
+
const normalized = usable ? { document: usable.model.authored, customThemes: void 0 } : withRequestedTheme(
|
|
1408
|
+
parsed,
|
|
1409
|
+
themes?.requested,
|
|
1410
|
+
themes?.customThemes
|
|
1411
|
+
);
|
|
1412
|
+
const result = await core.generateBufferWithWarnings(
|
|
1413
|
+
normalized.document,
|
|
1414
|
+
{
|
|
1415
|
+
customThemes: normalized.customThemes,
|
|
1416
|
+
services,
|
|
1417
|
+
fonts: options.fonts,
|
|
1418
|
+
validation: {
|
|
1419
|
+
allowUnknownFields: options.validation?.allowUnknownFields
|
|
1420
|
+
},
|
|
1421
|
+
deterministic: options.deterministic,
|
|
1422
|
+
generatedAt: options.generatedAt,
|
|
1423
|
+
baseDir: options.baseDir,
|
|
1424
|
+
renderer: options.renderer,
|
|
1425
|
+
prepared: usable
|
|
1426
|
+
}
|
|
1427
|
+
);
|
|
1428
|
+
const warnings = withoutPreparedWarnings(
|
|
1429
|
+
toGenerationWarnings(result.warnings),
|
|
1430
|
+
usable
|
|
1431
|
+
);
|
|
1432
|
+
emitGenerationWarnings(warnings);
|
|
1433
|
+
options.warnings?.push(...warnings);
|
|
1276
1434
|
return result.buffer;
|
|
1277
1435
|
},
|
|
1278
1436
|
hasPlugins: false,
|
|
@@ -1337,6 +1495,66 @@ var PptxFormatAdapter = class {
|
|
|
1337
1495
|
...result.errors.length > 0 && { errors: result.errors }
|
|
1338
1496
|
};
|
|
1339
1497
|
}
|
|
1498
|
+
async analyzeQuality(doc, options = {}) {
|
|
1499
|
+
const core = await import("@json-to-office/core-pptx");
|
|
1500
|
+
const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
|
|
1501
|
+
let prepared = preparedFor(
|
|
1502
|
+
options.prepared?.format === "pptx" ? options.prepared : void 0,
|
|
1503
|
+
parsed
|
|
1504
|
+
);
|
|
1505
|
+
if (!prepared) {
|
|
1506
|
+
try {
|
|
1507
|
+
prepared = await this.prepareModel(parsed, options, []);
|
|
1508
|
+
} catch {
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
return core.analyzePptxQuality(prepared?.model.authored ?? parsed, {
|
|
1512
|
+
...prepared && { prepared },
|
|
1513
|
+
renderer: options.renderer ?? documentRenderer(parsed),
|
|
1514
|
+
profile: options.quality?.profile,
|
|
1515
|
+
policy: options.quality?.policy
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
async prepareDocument(doc, options = {}) {
|
|
1519
|
+
const warnings = [];
|
|
1520
|
+
const prepared = await this.prepareModel(doc, options, warnings);
|
|
1521
|
+
const normalized = toGenerationWarnings(warnings);
|
|
1522
|
+
emitGenerationWarnings(normalized);
|
|
1523
|
+
options.warnings?.push(...normalized);
|
|
1524
|
+
return prepared;
|
|
1525
|
+
}
|
|
1526
|
+
/** Prepare into a caller-owned sink; `prepareDocument` owns the reporting. */
|
|
1527
|
+
async prepareModel(doc, options, warnings) {
|
|
1528
|
+
const core = await import("@json-to-office/core-pptx");
|
|
1529
|
+
const parsed = typeof doc === "string" ? JSON.parse(doc) : doc;
|
|
1530
|
+
const resolved = await this.resolveThemes(options);
|
|
1531
|
+
const normalized = withRequestedTheme(
|
|
1532
|
+
parsed,
|
|
1533
|
+
resolved.requested,
|
|
1534
|
+
resolved.customThemes
|
|
1535
|
+
);
|
|
1536
|
+
const prepared = core.preparePptxQualityDocument(
|
|
1537
|
+
normalized.document,
|
|
1538
|
+
{
|
|
1539
|
+
customThemes: normalized.customThemes,
|
|
1540
|
+
fonts: options.fonts,
|
|
1541
|
+
services: buildServicesFromEnv(),
|
|
1542
|
+
renderer: options.renderer ?? documentRenderer(parsed),
|
|
1543
|
+
warnings
|
|
1544
|
+
}
|
|
1545
|
+
);
|
|
1546
|
+
return stampPrepared(
|
|
1547
|
+
{
|
|
1548
|
+
...prepared,
|
|
1549
|
+
metadata: {
|
|
1550
|
+
...prepared.metadata,
|
|
1551
|
+
...resolved.label && { themeLabel: resolved.label }
|
|
1552
|
+
}
|
|
1553
|
+
},
|
|
1554
|
+
parsed,
|
|
1555
|
+
toGenerationWarnings(warnings)
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1340
1558
|
generateSchema(_options) {
|
|
1341
1559
|
return null;
|
|
1342
1560
|
}
|
|
@@ -1348,6 +1566,10 @@ var PptxFormatAdapter = class {
|
|
|
1348
1566
|
return {};
|
|
1349
1567
|
}
|
|
1350
1568
|
}
|
|
1569
|
+
async getBuiltinThemeValues() {
|
|
1570
|
+
const core = await import("@json-to-office/core-pptx");
|
|
1571
|
+
return core.pptxThemes || {};
|
|
1572
|
+
}
|
|
1351
1573
|
async resolveTheme(options) {
|
|
1352
1574
|
const core = await import("@json-to-office/core-pptx");
|
|
1353
1575
|
const themes = core.pptxThemes || {};
|
|
@@ -1440,6 +1662,116 @@ function createAdapter(format) {
|
|
|
1440
1662
|
throw new Error(`Unknown format: ${format}`);
|
|
1441
1663
|
}
|
|
1442
1664
|
}
|
|
1665
|
+
|
|
1666
|
+
// src/pdf-text-geometry.ts
|
|
1667
|
+
import { execFile as execFile2 } from "child_process";
|
|
1668
|
+
import * as path6 from "path";
|
|
1669
|
+
var ENTITIES = {
|
|
1670
|
+
"&": "&",
|
|
1671
|
+
"<": "<",
|
|
1672
|
+
">": ">",
|
|
1673
|
+
""": '"',
|
|
1674
|
+
"'": "'",
|
|
1675
|
+
""": '"',
|
|
1676
|
+
"'": "'"
|
|
1677
|
+
};
|
|
1678
|
+
function decodeEntities(value) {
|
|
1679
|
+
return value.replace(
|
|
1680
|
+
/&(?:amp|lt|gt|quot|apos|#34|#39);/g,
|
|
1681
|
+
(entity) => ENTITIES[entity] ?? entity
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
var PAGE_PATTERN = /<page\s+width="([\d.]+)"\s+height="([\d.]+)">([\s\S]*?)<\/page>/g;
|
|
1685
|
+
var WORD_PATTERN = /<word\s+xMin="(-?[\d.]+)"\s+yMin="(-?[\d.]+)"\s+xMax="(-?[\d.]+)"\s+yMax="(-?[\d.]+)">([\s\S]*?)<\/word>/g;
|
|
1686
|
+
function parsePdfTextBbox(bboxXml) {
|
|
1687
|
+
const pages = [];
|
|
1688
|
+
for (const pageMatch of bboxXml.matchAll(PAGE_PATTERN)) {
|
|
1689
|
+
const words = [];
|
|
1690
|
+
for (const wordMatch of pageMatch[3].matchAll(WORD_PATTERN)) {
|
|
1691
|
+
words.push({
|
|
1692
|
+
xMin: Number(wordMatch[1]),
|
|
1693
|
+
yMin: Number(wordMatch[2]),
|
|
1694
|
+
xMax: Number(wordMatch[3]),
|
|
1695
|
+
yMax: Number(wordMatch[4]),
|
|
1696
|
+
text: decodeEntities(wordMatch[5])
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
pages.push({
|
|
1700
|
+
widthPt: Number(pageMatch[1]),
|
|
1701
|
+
heightPt: Number(pageMatch[2]),
|
|
1702
|
+
words
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
return pages;
|
|
1706
|
+
}
|
|
1707
|
+
function pdftotextCandidates() {
|
|
1708
|
+
const candidates = [];
|
|
1709
|
+
const configured = process.env.PDFTOTEXT_PATH?.trim();
|
|
1710
|
+
if (configured) candidates.push(configured);
|
|
1711
|
+
candidates.push("pdftotext");
|
|
1712
|
+
return [...new Set(candidates)];
|
|
1713
|
+
}
|
|
1714
|
+
async function run(binary, args, timeoutMs) {
|
|
1715
|
+
return new Promise((resolve2, reject) => {
|
|
1716
|
+
execFile2(
|
|
1717
|
+
binary,
|
|
1718
|
+
args,
|
|
1719
|
+
{ timeout: timeoutMs, maxBuffer: 64 * 1024 * 1024 },
|
|
1720
|
+
(error, stdout) => {
|
|
1721
|
+
if (error) reject(error);
|
|
1722
|
+
else resolve2(stdout);
|
|
1723
|
+
}
|
|
1724
|
+
);
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
var pdftotextPromise;
|
|
1728
|
+
async function resolvePdftotext() {
|
|
1729
|
+
if (!pdftotextPromise) {
|
|
1730
|
+
pdftotextPromise = (async () => {
|
|
1731
|
+
for (const candidate of pdftotextCandidates()) {
|
|
1732
|
+
if (candidate.includes(path6.sep)) {
|
|
1733
|
+
try {
|
|
1734
|
+
await run(candidate, ["-v"], 1e4);
|
|
1735
|
+
return candidate;
|
|
1736
|
+
} catch {
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
try {
|
|
1741
|
+
await run(candidate, ["-v"], 1e4);
|
|
1742
|
+
return candidate;
|
|
1743
|
+
} catch (error) {
|
|
1744
|
+
const code = error.code;
|
|
1745
|
+
if (code !== "ENOENT" && code !== "EACCES") return candidate;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
throw new Error(
|
|
1749
|
+
`Text geometry extraction needs pdftotext (poppler), which was not found. Install poppler-utils or set PDFTOTEXT_PATH (searched: ${pdftotextCandidates().join(", ")}).`
|
|
1750
|
+
);
|
|
1751
|
+
})().catch((error) => {
|
|
1752
|
+
pdftotextPromise = void 0;
|
|
1753
|
+
throw error;
|
|
1754
|
+
});
|
|
1755
|
+
}
|
|
1756
|
+
return pdftotextPromise;
|
|
1757
|
+
}
|
|
1758
|
+
async function pdftotextAvailable() {
|
|
1759
|
+
try {
|
|
1760
|
+
await resolvePdftotext();
|
|
1761
|
+
return true;
|
|
1762
|
+
} catch {
|
|
1763
|
+
return false;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
async function extractPdfTextGeometry(pdfPath, options = {}) {
|
|
1767
|
+
const binary = await resolvePdftotext();
|
|
1768
|
+
const stdout = await run(
|
|
1769
|
+
binary,
|
|
1770
|
+
["-bbox", pdfPath, "-"],
|
|
1771
|
+
options.timeoutMs ?? 6e4
|
|
1772
|
+
);
|
|
1773
|
+
return parsePdfTextBbox(stdout);
|
|
1774
|
+
}
|
|
1443
1775
|
export {
|
|
1444
1776
|
DocxFormatAdapter,
|
|
1445
1777
|
FontconfigStager,
|
|
@@ -1452,8 +1784,11 @@ export {
|
|
|
1452
1784
|
createLibreOfficePptxBatchRasterizer,
|
|
1453
1785
|
createLibreOfficePptxRasterizer,
|
|
1454
1786
|
emitDiagnostic,
|
|
1787
|
+
extractPdfTextGeometry,
|
|
1455
1788
|
getFontStager,
|
|
1456
1789
|
getRasterizerCacheStats,
|
|
1790
|
+
parsePdfTextBbox,
|
|
1791
|
+
pdftotextAvailable,
|
|
1457
1792
|
runWithDiagnosticSink,
|
|
1458
1793
|
stderrDiagnosticSink
|
|
1459
1794
|
};
|