@files-preview-app/preview-file 1.2.3 → 1.2.4
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/angular.cjs +338 -87
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +336 -86
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +338 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +336 -86
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +338 -87
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +336 -86
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +338 -87
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +336 -86
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -11,7 +11,7 @@ var THREE = require('three');
|
|
|
11
11
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
12
12
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
13
13
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
14
|
-
var
|
|
14
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
15
15
|
|
|
16
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
|
|
@@ -38,6 +38,7 @@ var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
|
38
38
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
39
39
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
40
40
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
41
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
41
42
|
|
|
42
43
|
// ../core/dist/index.js
|
|
43
44
|
var EventEmitter = class {
|
|
@@ -293,6 +294,39 @@ function detectOoxmlType(buffer) {
|
|
|
293
294
|
}
|
|
294
295
|
return "application/zip";
|
|
295
296
|
}
|
|
297
|
+
function detectCfbfType(buffer) {
|
|
298
|
+
const bytes = new Uint8Array(buffer);
|
|
299
|
+
const hasUtf16le = (str) => {
|
|
300
|
+
const target = new Uint8Array(str.length * 2);
|
|
301
|
+
for (let i = 0; i < str.length; i++) {
|
|
302
|
+
target[i * 2] = str.charCodeAt(i);
|
|
303
|
+
target[i * 2 + 1] = 0;
|
|
304
|
+
}
|
|
305
|
+
const targetLen = target.length;
|
|
306
|
+
const max = bytes.length - targetLen;
|
|
307
|
+
for (let i = 0; i <= max; i++) {
|
|
308
|
+
let match = true;
|
|
309
|
+
for (let j = 0; j < targetLen; j++) {
|
|
310
|
+
if (bytes[i + j] !== target[j]) {
|
|
311
|
+
match = false;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (match) return true;
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
};
|
|
319
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
320
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
321
|
+
}
|
|
322
|
+
if (hasUtf16le("WordDocument")) {
|
|
323
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
324
|
+
}
|
|
325
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
326
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
296
330
|
function extractExtension(nameOrUrl) {
|
|
297
331
|
try {
|
|
298
332
|
const url = new URL(nameOrUrl);
|
|
@@ -357,6 +391,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
357
391
|
} else {
|
|
358
392
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
359
393
|
}
|
|
394
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
395
|
+
if (metadata.extension) {
|
|
396
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
397
|
+
} else {
|
|
398
|
+
const cfbf = detectCfbfType(buffer);
|
|
399
|
+
if (cfbf) {
|
|
400
|
+
metadata.mimeType = cfbf.mime;
|
|
401
|
+
metadata.extension = cfbf.extension;
|
|
402
|
+
} else {
|
|
403
|
+
metadata.mimeType = magicMime;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
360
406
|
} else {
|
|
361
407
|
metadata.mimeType = magicMime;
|
|
362
408
|
}
|
|
@@ -1689,7 +1735,10 @@ var DocxPlugin = class {
|
|
|
1689
1735
|
supports(file) {
|
|
1690
1736
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1691
1737
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1692
|
-
|
|
1738
|
+
if (ext) {
|
|
1739
|
+
return this.extensions.includes(ext);
|
|
1740
|
+
}
|
|
1741
|
+
return this.mimeTypes.includes(mime || "");
|
|
1693
1742
|
}
|
|
1694
1743
|
getToolbarActions(instance) {
|
|
1695
1744
|
return [
|
|
@@ -2078,7 +2127,10 @@ var ExcelPlugin = class {
|
|
|
2078
2127
|
supports(file) {
|
|
2079
2128
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2080
2129
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2081
|
-
|
|
2130
|
+
if (ext) {
|
|
2131
|
+
return this.extensions.includes(ext);
|
|
2132
|
+
}
|
|
2133
|
+
return this.mimeTypes.includes(mime || "");
|
|
2082
2134
|
}
|
|
2083
2135
|
getToolbarActions(instance) {
|
|
2084
2136
|
return [
|
|
@@ -3020,7 +3072,10 @@ var PptxPlugin = class {
|
|
|
3020
3072
|
supports(file) {
|
|
3021
3073
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3022
3074
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3023
|
-
|
|
3075
|
+
if (ext) {
|
|
3076
|
+
return this.extensions.includes(ext);
|
|
3077
|
+
}
|
|
3078
|
+
return this.mimeTypes.includes(mime || "");
|
|
3024
3079
|
}
|
|
3025
3080
|
getToolbarActions(instance) {
|
|
3026
3081
|
return [
|
|
@@ -3465,7 +3520,10 @@ var RtfPlugin = class {
|
|
|
3465
3520
|
ctx.container.appendChild(wrapper);
|
|
3466
3521
|
let scale = 1;
|
|
3467
3522
|
try {
|
|
3468
|
-
|
|
3523
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3524
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3525
|
+
}
|
|
3526
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3469
3527
|
const htmlElements = await doc.render();
|
|
3470
3528
|
for (const el of htmlElements) {
|
|
3471
3529
|
wrapper.appendChild(el);
|
|
@@ -3663,7 +3721,10 @@ var OpenDocumentPlugin = class {
|
|
|
3663
3721
|
supports(file) {
|
|
3664
3722
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3665
3723
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3666
|
-
|
|
3724
|
+
if (ext) {
|
|
3725
|
+
return this.extensions.includes(ext);
|
|
3726
|
+
}
|
|
3727
|
+
return this.mimeTypes.includes(mime || "");
|
|
3667
3728
|
}
|
|
3668
3729
|
getToolbarActions(instance) {
|
|
3669
3730
|
const isPresentation = instance.isPresentation;
|
|
@@ -4078,7 +4139,10 @@ var DocPlugin = class {
|
|
|
4078
4139
|
supports(file) {
|
|
4079
4140
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4080
4141
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4081
|
-
|
|
4142
|
+
if (ext) {
|
|
4143
|
+
return this.extensions.includes(ext);
|
|
4144
|
+
}
|
|
4145
|
+
return this.mimeTypes.includes(mime || "");
|
|
4082
4146
|
}
|
|
4083
4147
|
getToolbarActions(instance) {
|
|
4084
4148
|
return [
|
|
@@ -4301,22 +4365,22 @@ var DocPlugin = class {
|
|
|
4301
4365
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4302
4366
|
*/
|
|
4303
4367
|
extractStringsFromBytes(bytes) {
|
|
4304
|
-
const
|
|
4305
|
-
const
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4368
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4369
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4370
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4371
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4372
|
+
const candidateLines = [];
|
|
4373
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4374
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4375
|
+
const trimmed = run.trim();
|
|
4376
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4377
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
4378
|
+
seen.add(trimmed);
|
|
4379
|
+
candidateLines.push(trimmed);
|
|
4380
|
+
}
|
|
4317
4381
|
}
|
|
4318
4382
|
}
|
|
4319
|
-
return
|
|
4383
|
+
return candidateLines.join("\n\n");
|
|
4320
4384
|
}
|
|
4321
4385
|
heuristicTextExtraction(buffer) {
|
|
4322
4386
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
@@ -4371,14 +4435,17 @@ function docPlugin() {
|
|
|
4371
4435
|
}
|
|
4372
4436
|
var PptPlugin = class {
|
|
4373
4437
|
id = "ppt";
|
|
4374
|
-
name = "
|
|
4438
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4375
4439
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4376
4440
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4377
|
-
weight =
|
|
4441
|
+
weight = 85;
|
|
4378
4442
|
supports(file) {
|
|
4379
4443
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4380
4444
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4381
|
-
|
|
4445
|
+
if (ext) {
|
|
4446
|
+
return this.extensions.includes(ext);
|
|
4447
|
+
}
|
|
4448
|
+
return this.mimeTypes.includes(mime || "");
|
|
4382
4449
|
}
|
|
4383
4450
|
getToolbarActions(instance) {
|
|
4384
4451
|
return [
|
|
@@ -4466,19 +4533,15 @@ var PptPlugin = class {
|
|
|
4466
4533
|
container.style.alignItems = "center";
|
|
4467
4534
|
container.style.padding = "32px 16px";
|
|
4468
4535
|
container.style.backgroundColor = "#0f172a";
|
|
4536
|
+
container.style.boxSizing = "border-box";
|
|
4469
4537
|
const slideCard = document.createElement("div");
|
|
4470
4538
|
slideCard.className = "fp-ppt-slide-card";
|
|
4471
4539
|
slideCard.style.width = "960px";
|
|
4472
|
-
slideCard.style.maxWidth = "
|
|
4540
|
+
slideCard.style.maxWidth = "92%";
|
|
4473
4541
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4474
4542
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4475
|
-
slideCard.style.boxShadow = "0
|
|
4543
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4476
4544
|
slideCard.style.borderRadius = "8px";
|
|
4477
|
-
slideCard.style.padding = "48px";
|
|
4478
|
-
slideCard.style.display = "flex";
|
|
4479
|
-
slideCard.style.flexDirection = "column";
|
|
4480
|
-
slideCard.style.justifyContent = "center";
|
|
4481
|
-
slideCard.style.alignItems = "center";
|
|
4482
4545
|
slideCard.style.boxSizing = "border-box";
|
|
4483
4546
|
slideCard.style.position = "relative";
|
|
4484
4547
|
slideCard.style.overflow = "hidden";
|
|
@@ -4489,21 +4552,25 @@ var PptPlugin = class {
|
|
|
4489
4552
|
let scale = 1;
|
|
4490
4553
|
let currentSlide = 1;
|
|
4491
4554
|
let slides = [];
|
|
4555
|
+
const createdBlobUrls = [];
|
|
4492
4556
|
try {
|
|
4493
4557
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4494
4558
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4495
4559
|
if (!pptStream || pptStream.length < 512) {
|
|
4496
4560
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4497
4561
|
}
|
|
4498
|
-
|
|
4562
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
4563
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4499
4564
|
} catch (err) {
|
|
4500
4565
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4501
4566
|
}
|
|
4502
4567
|
if (slides.length === 0) {
|
|
4503
4568
|
slides = [
|
|
4504
4569
|
{
|
|
4570
|
+
slideIndex: 1,
|
|
4505
4571
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4506
|
-
|
|
4572
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
4573
|
+
tableColumns: []
|
|
4507
4574
|
}
|
|
4508
4575
|
];
|
|
4509
4576
|
}
|
|
@@ -4512,23 +4579,73 @@ var PptPlugin = class {
|
|
|
4512
4579
|
currentSlide = idx;
|
|
4513
4580
|
const s = slides[idx - 1];
|
|
4514
4581
|
if (!s) return;
|
|
4582
|
+
let contentHtml = "";
|
|
4583
|
+
if (s.pictureUrl) {
|
|
4584
|
+
contentHtml = `
|
|
4585
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
4586
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify2__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
|
|
4587
|
+
</div>
|
|
4588
|
+
`;
|
|
4589
|
+
} else if (s.tableColumns.length > 0) {
|
|
4590
|
+
const cols = s.tableColumns;
|
|
4591
|
+
contentHtml = `
|
|
4592
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
4593
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
4594
|
+
<thead>
|
|
4595
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
4596
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
4597
|
+
</tr>
|
|
4598
|
+
</thead>
|
|
4599
|
+
<tbody>
|
|
4600
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
4601
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
4602
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
4603
|
+
</tr>
|
|
4604
|
+
`).join("")}
|
|
4605
|
+
</tbody>
|
|
4606
|
+
</table>
|
|
4607
|
+
</div>
|
|
4608
|
+
`;
|
|
4609
|
+
} else {
|
|
4610
|
+
const pTags = s.paragraphs.map((p) => {
|
|
4611
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
4612
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2__default.default.sanitize(l)}</p>`).join("");
|
|
4613
|
+
}).join("");
|
|
4614
|
+
contentHtml = `
|
|
4615
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
4616
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
4617
|
+
</div>
|
|
4618
|
+
`;
|
|
4619
|
+
}
|
|
4515
4620
|
slideCard.innerHTML = `
|
|
4516
|
-
<div style="
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4621
|
+
<div style="width: 100%; height: 100%; background: #ffffff; border: 14px solid #334155; box-sizing: border-box; display: flex; flex-direction: column; padding: 24px 32px; position: relative; font-family: Calibri, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; overflow: hidden; border-radius: 4px;">
|
|
4622
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
4623
|
+
<div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
|
|
4624
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
4625
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
4626
|
+
</h1>
|
|
4627
|
+
${s.subtitle ? `
|
|
4628
|
+
<span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
|
|
4629
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
4630
|
+
</span>
|
|
4631
|
+
` : `
|
|
4632
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
4633
|
+
Slide ${idx} / ${totalSlides}
|
|
4634
|
+
</span>
|
|
4635
|
+
`}
|
|
4525
4636
|
</div>
|
|
4637
|
+
|
|
4638
|
+
<!-- Slide Content -->
|
|
4639
|
+
${contentHtml}
|
|
4526
4640
|
</div>
|
|
4527
4641
|
`;
|
|
4528
4642
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4529
4643
|
};
|
|
4530
4644
|
renderSlide(1);
|
|
4531
4645
|
const cleanup = () => {
|
|
4646
|
+
for (const u of createdBlobUrls) {
|
|
4647
|
+
URL.revokeObjectURL(u);
|
|
4648
|
+
}
|
|
4532
4649
|
container.remove();
|
|
4533
4650
|
ctx.container.innerHTML = "";
|
|
4534
4651
|
};
|
|
@@ -4568,13 +4685,48 @@ var PptPlugin = class {
|
|
|
4568
4685
|
if (!ctx2d) return;
|
|
4569
4686
|
canvas.width = 160;
|
|
4570
4687
|
canvas.height = 90;
|
|
4571
|
-
ctx2d.fillStyle = "#
|
|
4688
|
+
ctx2d.fillStyle = "#334155";
|
|
4572
4689
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4573
|
-
ctx2d.fillStyle = "#
|
|
4574
|
-
ctx2d.
|
|
4575
|
-
ctx2d.
|
|
4576
|
-
|
|
4577
|
-
ctx2d.
|
|
4690
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4691
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
4692
|
+
ctx2d.fillStyle = "#84cc16";
|
|
4693
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
4694
|
+
ctx2d.fillStyle = "#1e293b";
|
|
4695
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
4696
|
+
ctx2d.textAlign = "left";
|
|
4697
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
4698
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
4699
|
+
if (s.subtitle) {
|
|
4700
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
4701
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
4702
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4703
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
4704
|
+
ctx2d.textAlign = "center";
|
|
4705
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
4706
|
+
}
|
|
4707
|
+
if (s.pictureUrl) {
|
|
4708
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
4709
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
4710
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4711
|
+
ctx2d.font = "8px sans-serif";
|
|
4712
|
+
ctx2d.textAlign = "center";
|
|
4713
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
4714
|
+
} else if (s.tableColumns.length > 0) {
|
|
4715
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
4716
|
+
ctx2d.lineWidth = 1;
|
|
4717
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
4718
|
+
for (let l = 1; l <= 3; l++) {
|
|
4719
|
+
ctx2d.beginPath();
|
|
4720
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
4721
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
4722
|
+
ctx2d.stroke();
|
|
4723
|
+
}
|
|
4724
|
+
} else {
|
|
4725
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
4726
|
+
for (let l = 0; l < 4; l++) {
|
|
4727
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4578
4730
|
}
|
|
4579
4731
|
}));
|
|
4580
4732
|
},
|
|
@@ -4592,66 +4744,165 @@ var PptPlugin = class {
|
|
|
4592
4744
|
}
|
|
4593
4745
|
};
|
|
4594
4746
|
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
4749
|
+
*/
|
|
4750
|
+
extractPictures(cfbf, createdUrls) {
|
|
4751
|
+
const urls = [];
|
|
4752
|
+
try {
|
|
4753
|
+
const picStream = cfbf.readStream("Pictures");
|
|
4754
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
4755
|
+
const pBuf = new Uint8Array(picStream);
|
|
4756
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
4757
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
4758
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
4759
|
+
let match = true;
|
|
4760
|
+
for (let j = 0; j < 8; j++) {
|
|
4761
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
4762
|
+
match = false;
|
|
4763
|
+
break;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
if (match) {
|
|
4767
|
+
let endIdx = -1;
|
|
4768
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
4769
|
+
let endMatch = true;
|
|
4770
|
+
for (let j = 0; j < 8; j++) {
|
|
4771
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
4772
|
+
endMatch = false;
|
|
4773
|
+
break;
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
if (endMatch) {
|
|
4777
|
+
endIdx = k + 8;
|
|
4778
|
+
break;
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
if (endIdx !== -1) {
|
|
4782
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
4783
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
4784
|
+
const url = URL.createObjectURL(blob);
|
|
4785
|
+
urls.push(url);
|
|
4786
|
+
createdUrls.push(url);
|
|
4787
|
+
i = endIdx;
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
4792
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
4793
|
+
let endIdx = -1;
|
|
4794
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
4795
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
4796
|
+
endIdx = k + 2;
|
|
4797
|
+
break;
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
if (endIdx !== -1) {
|
|
4801
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
4802
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
4803
|
+
const url = URL.createObjectURL(blob);
|
|
4804
|
+
urls.push(url);
|
|
4805
|
+
createdUrls.push(url);
|
|
4806
|
+
i = endIdx;
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
} catch (err) {
|
|
4811
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
4812
|
+
}
|
|
4813
|
+
return urls;
|
|
4814
|
+
}
|
|
4595
4815
|
/**
|
|
4596
4816
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4597
4817
|
*/
|
|
4598
|
-
extractSlides(stream) {
|
|
4818
|
+
extractSlides(stream, pictures) {
|
|
4599
4819
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4600
4820
|
const len = stream.length;
|
|
4601
4821
|
let offset = 0;
|
|
4602
4822
|
const slides = [];
|
|
4603
|
-
let
|
|
4823
|
+
let picIdx = 0;
|
|
4604
4824
|
while (offset + 8 <= len) {
|
|
4605
4825
|
const recVerInst = view.getUint16(offset, true);
|
|
4606
4826
|
const recType = view.getUint16(offset + 2, true);
|
|
4607
4827
|
const recLen = view.getUint32(offset + 4, true);
|
|
4828
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4608
4829
|
if (recType === 1006) {
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4830
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
4831
|
+
const rawTexts = [];
|
|
4832
|
+
let hasOle = false;
|
|
4833
|
+
let sOff = offset + 8;
|
|
4834
|
+
while (sOff + 8 <= slideEnd) {
|
|
4835
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
4836
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
4837
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
4838
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
4839
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4840
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4841
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
4842
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4843
|
+
rawTexts.push(txt);
|
|
4844
|
+
}
|
|
4845
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4846
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4847
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4848
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4849
|
+
rawTexts.push(txt);
|
|
4850
|
+
}
|
|
4851
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
4852
|
+
hasOle = true;
|
|
4853
|
+
}
|
|
4854
|
+
if (cIsContainer) sOff += 8;
|
|
4855
|
+
else sOff += 8 + cLen;
|
|
4614
4856
|
}
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4857
|
+
let title = "";
|
|
4858
|
+
let subtitle = "";
|
|
4859
|
+
const paragraphs = [];
|
|
4860
|
+
const tableColumns = [];
|
|
4861
|
+
for (const t of rawTexts) {
|
|
4862
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
4863
|
+
title = t;
|
|
4864
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
4865
|
+
tableColumns.push(t);
|
|
4866
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
4867
|
+
subtitle = t;
|
|
4868
|
+
} else {
|
|
4869
|
+
paragraphs.push(t);
|
|
4870
|
+
}
|
|
4623
4871
|
}
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4628
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4629
|
-
currentSlideTexts.push(text);
|
|
4872
|
+
let pictureUrl = null;
|
|
4873
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
4874
|
+
pictureUrl = pictures[picIdx++];
|
|
4630
4875
|
}
|
|
4876
|
+
slides.push({
|
|
4877
|
+
slideIndex: slides.length + 1,
|
|
4878
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
4879
|
+
subtitle,
|
|
4880
|
+
paragraphs,
|
|
4881
|
+
tableColumns,
|
|
4882
|
+
pictureUrl,
|
|
4883
|
+
hasOle
|
|
4884
|
+
});
|
|
4631
4885
|
}
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
offset += 8;
|
|
4635
|
-
} else {
|
|
4636
|
-
offset += 8 + recLen;
|
|
4637
|
-
}
|
|
4638
|
-
}
|
|
4639
|
-
if (currentSlideTexts.length > 0) {
|
|
4640
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4641
|
-
const texts = currentSlideTexts.slice(1);
|
|
4642
|
-
slides.push({ title, texts });
|
|
4886
|
+
if (isContainer) offset += 8;
|
|
4887
|
+
else offset += 8 + recLen;
|
|
4643
4888
|
}
|
|
4644
4889
|
if (slides.length === 0) {
|
|
4645
4890
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4646
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4647
|
-
const
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4891
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
4892
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
4893
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
4894
|
+
);
|
|
4895
|
+
if (clean.length > 0) {
|
|
4896
|
+
const chunkSize = 3;
|
|
4897
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
4898
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4652
4899
|
slides.push({
|
|
4900
|
+
slideIndex: slides.length + 1,
|
|
4653
4901
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4654
|
-
|
|
4902
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
4903
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
4904
|
+
tableColumns: [],
|
|
4905
|
+
pictureUrl: pictures[slides.length] || null
|
|
4655
4906
|
});
|
|
4656
4907
|
}
|
|
4657
4908
|
}
|