@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/angular.cjs
CHANGED
|
@@ -15,7 +15,7 @@ var THREE = require('three');
|
|
|
15
15
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
16
16
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
17
17
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
18
|
-
var
|
|
18
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
19
19
|
|
|
20
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
21
|
|
|
@@ -42,6 +42,7 @@ var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
|
42
42
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
43
43
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
44
44
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
45
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
45
46
|
|
|
46
47
|
var __create = Object.create;
|
|
47
48
|
var __defProp = Object.defineProperty;
|
|
@@ -344,6 +345,39 @@ function detectOoxmlType(buffer) {
|
|
|
344
345
|
}
|
|
345
346
|
return "application/zip";
|
|
346
347
|
}
|
|
348
|
+
function detectCfbfType(buffer) {
|
|
349
|
+
const bytes = new Uint8Array(buffer);
|
|
350
|
+
const hasUtf16le = (str) => {
|
|
351
|
+
const target = new Uint8Array(str.length * 2);
|
|
352
|
+
for (let i = 0; i < str.length; i++) {
|
|
353
|
+
target[i * 2] = str.charCodeAt(i);
|
|
354
|
+
target[i * 2 + 1] = 0;
|
|
355
|
+
}
|
|
356
|
+
const targetLen = target.length;
|
|
357
|
+
const max = bytes.length - targetLen;
|
|
358
|
+
for (let i = 0; i <= max; i++) {
|
|
359
|
+
let match = true;
|
|
360
|
+
for (let j = 0; j < targetLen; j++) {
|
|
361
|
+
if (bytes[i + j] !== target[j]) {
|
|
362
|
+
match = false;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (match) return true;
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
};
|
|
370
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
371
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
372
|
+
}
|
|
373
|
+
if (hasUtf16le("WordDocument")) {
|
|
374
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
375
|
+
}
|
|
376
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
377
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
347
381
|
function extractExtension(nameOrUrl) {
|
|
348
382
|
try {
|
|
349
383
|
const url = new URL(nameOrUrl);
|
|
@@ -408,6 +442,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
408
442
|
} else {
|
|
409
443
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
410
444
|
}
|
|
445
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
446
|
+
if (metadata.extension) {
|
|
447
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
448
|
+
} else {
|
|
449
|
+
const cfbf = detectCfbfType(buffer);
|
|
450
|
+
if (cfbf) {
|
|
451
|
+
metadata.mimeType = cfbf.mime;
|
|
452
|
+
metadata.extension = cfbf.extension;
|
|
453
|
+
} else {
|
|
454
|
+
metadata.mimeType = magicMime;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
411
457
|
} else {
|
|
412
458
|
metadata.mimeType = magicMime;
|
|
413
459
|
}
|
|
@@ -1696,7 +1742,10 @@ var DocxPlugin = class {
|
|
|
1696
1742
|
supports(file) {
|
|
1697
1743
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1698
1744
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1699
|
-
|
|
1745
|
+
if (ext) {
|
|
1746
|
+
return this.extensions.includes(ext);
|
|
1747
|
+
}
|
|
1748
|
+
return this.mimeTypes.includes(mime || "");
|
|
1700
1749
|
}
|
|
1701
1750
|
getToolbarActions(instance) {
|
|
1702
1751
|
return [
|
|
@@ -2085,7 +2134,10 @@ var ExcelPlugin = class {
|
|
|
2085
2134
|
supports(file) {
|
|
2086
2135
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2087
2136
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2088
|
-
|
|
2137
|
+
if (ext) {
|
|
2138
|
+
return this.extensions.includes(ext);
|
|
2139
|
+
}
|
|
2140
|
+
return this.mimeTypes.includes(mime || "");
|
|
2089
2141
|
}
|
|
2090
2142
|
getToolbarActions(instance) {
|
|
2091
2143
|
return [
|
|
@@ -3027,7 +3079,10 @@ var PptxPlugin = class {
|
|
|
3027
3079
|
supports(file) {
|
|
3028
3080
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3029
3081
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3030
|
-
|
|
3082
|
+
if (ext) {
|
|
3083
|
+
return this.extensions.includes(ext);
|
|
3084
|
+
}
|
|
3085
|
+
return this.mimeTypes.includes(mime || "");
|
|
3031
3086
|
}
|
|
3032
3087
|
getToolbarActions(instance) {
|
|
3033
3088
|
return [
|
|
@@ -3472,7 +3527,10 @@ var RtfPlugin = class {
|
|
|
3472
3527
|
ctx.container.appendChild(wrapper);
|
|
3473
3528
|
let scale = 1;
|
|
3474
3529
|
try {
|
|
3475
|
-
|
|
3530
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3531
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3532
|
+
}
|
|
3533
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3476
3534
|
const htmlElements = await doc.render();
|
|
3477
3535
|
for (const el of htmlElements) {
|
|
3478
3536
|
wrapper.appendChild(el);
|
|
@@ -3670,7 +3728,10 @@ var OpenDocumentPlugin = class {
|
|
|
3670
3728
|
supports(file) {
|
|
3671
3729
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3672
3730
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3673
|
-
|
|
3731
|
+
if (ext) {
|
|
3732
|
+
return this.extensions.includes(ext);
|
|
3733
|
+
}
|
|
3734
|
+
return this.mimeTypes.includes(mime || "");
|
|
3674
3735
|
}
|
|
3675
3736
|
getToolbarActions(instance) {
|
|
3676
3737
|
const isPresentation = instance.isPresentation;
|
|
@@ -4085,7 +4146,10 @@ var DocPlugin = class {
|
|
|
4085
4146
|
supports(file) {
|
|
4086
4147
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4087
4148
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4088
|
-
|
|
4149
|
+
if (ext) {
|
|
4150
|
+
return this.extensions.includes(ext);
|
|
4151
|
+
}
|
|
4152
|
+
return this.mimeTypes.includes(mime || "");
|
|
4089
4153
|
}
|
|
4090
4154
|
getToolbarActions(instance) {
|
|
4091
4155
|
return [
|
|
@@ -4308,22 +4372,22 @@ var DocPlugin = class {
|
|
|
4308
4372
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4309
4373
|
*/
|
|
4310
4374
|
extractStringsFromBytes(bytes) {
|
|
4311
|
-
const
|
|
4312
|
-
const
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4375
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4376
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4377
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4378
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4379
|
+
const candidateLines = [];
|
|
4380
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4381
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4382
|
+
const trimmed = run.trim();
|
|
4383
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4384
|
+
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)) {
|
|
4385
|
+
seen.add(trimmed);
|
|
4386
|
+
candidateLines.push(trimmed);
|
|
4387
|
+
}
|
|
4324
4388
|
}
|
|
4325
4389
|
}
|
|
4326
|
-
return
|
|
4390
|
+
return candidateLines.join("\n\n");
|
|
4327
4391
|
}
|
|
4328
4392
|
heuristicTextExtraction(buffer) {
|
|
4329
4393
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
@@ -4378,14 +4442,17 @@ function docPlugin() {
|
|
|
4378
4442
|
}
|
|
4379
4443
|
var PptPlugin = class {
|
|
4380
4444
|
id = "ppt";
|
|
4381
|
-
name = "
|
|
4445
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4382
4446
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4383
4447
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4384
|
-
weight =
|
|
4448
|
+
weight = 85;
|
|
4385
4449
|
supports(file) {
|
|
4386
4450
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4387
4451
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4388
|
-
|
|
4452
|
+
if (ext) {
|
|
4453
|
+
return this.extensions.includes(ext);
|
|
4454
|
+
}
|
|
4455
|
+
return this.mimeTypes.includes(mime || "");
|
|
4389
4456
|
}
|
|
4390
4457
|
getToolbarActions(instance) {
|
|
4391
4458
|
return [
|
|
@@ -4473,19 +4540,15 @@ var PptPlugin = class {
|
|
|
4473
4540
|
container.style.alignItems = "center";
|
|
4474
4541
|
container.style.padding = "32px 16px";
|
|
4475
4542
|
container.style.backgroundColor = "#0f172a";
|
|
4543
|
+
container.style.boxSizing = "border-box";
|
|
4476
4544
|
const slideCard = document.createElement("div");
|
|
4477
4545
|
slideCard.className = "fp-ppt-slide-card";
|
|
4478
4546
|
slideCard.style.width = "960px";
|
|
4479
|
-
slideCard.style.maxWidth = "
|
|
4547
|
+
slideCard.style.maxWidth = "92%";
|
|
4480
4548
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4481
4549
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4482
|
-
slideCard.style.boxShadow = "0
|
|
4550
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4483
4551
|
slideCard.style.borderRadius = "8px";
|
|
4484
|
-
slideCard.style.padding = "48px";
|
|
4485
|
-
slideCard.style.display = "flex";
|
|
4486
|
-
slideCard.style.flexDirection = "column";
|
|
4487
|
-
slideCard.style.justifyContent = "center";
|
|
4488
|
-
slideCard.style.alignItems = "center";
|
|
4489
4552
|
slideCard.style.boxSizing = "border-box";
|
|
4490
4553
|
slideCard.style.position = "relative";
|
|
4491
4554
|
slideCard.style.overflow = "hidden";
|
|
@@ -4496,21 +4559,25 @@ var PptPlugin = class {
|
|
|
4496
4559
|
let scale = 1;
|
|
4497
4560
|
let currentSlide = 1;
|
|
4498
4561
|
let slides = [];
|
|
4562
|
+
const createdBlobUrls = [];
|
|
4499
4563
|
try {
|
|
4500
4564
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4501
4565
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4502
4566
|
if (!pptStream || pptStream.length < 512) {
|
|
4503
4567
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4504
4568
|
}
|
|
4505
|
-
|
|
4569
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
4570
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4506
4571
|
} catch (err) {
|
|
4507
4572
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4508
4573
|
}
|
|
4509
4574
|
if (slides.length === 0) {
|
|
4510
4575
|
slides = [
|
|
4511
4576
|
{
|
|
4577
|
+
slideIndex: 1,
|
|
4512
4578
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4513
|
-
|
|
4579
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
4580
|
+
tableColumns: []
|
|
4514
4581
|
}
|
|
4515
4582
|
];
|
|
4516
4583
|
}
|
|
@@ -4519,23 +4586,73 @@ var PptPlugin = class {
|
|
|
4519
4586
|
currentSlide = idx;
|
|
4520
4587
|
const s = slides[idx - 1];
|
|
4521
4588
|
if (!s) return;
|
|
4589
|
+
let contentHtml = "";
|
|
4590
|
+
if (s.pictureUrl) {
|
|
4591
|
+
contentHtml = `
|
|
4592
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
4593
|
+
<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;" />
|
|
4594
|
+
</div>
|
|
4595
|
+
`;
|
|
4596
|
+
} else if (s.tableColumns.length > 0) {
|
|
4597
|
+
const cols = s.tableColumns;
|
|
4598
|
+
contentHtml = `
|
|
4599
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
4600
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
4601
|
+
<thead>
|
|
4602
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
4603
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
4604
|
+
</tr>
|
|
4605
|
+
</thead>
|
|
4606
|
+
<tbody>
|
|
4607
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
4608
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
4609
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
4610
|
+
</tr>
|
|
4611
|
+
`).join("")}
|
|
4612
|
+
</tbody>
|
|
4613
|
+
</table>
|
|
4614
|
+
</div>
|
|
4615
|
+
`;
|
|
4616
|
+
} else {
|
|
4617
|
+
const pTags = s.paragraphs.map((p) => {
|
|
4618
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
4619
|
+
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("");
|
|
4620
|
+
}).join("");
|
|
4621
|
+
contentHtml = `
|
|
4622
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
4623
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
4624
|
+
</div>
|
|
4625
|
+
`;
|
|
4626
|
+
}
|
|
4522
4627
|
slideCard.innerHTML = `
|
|
4523
|
-
<div style="
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4628
|
+
<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;">
|
|
4629
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
4630
|
+
<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;">
|
|
4631
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
4632
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
4633
|
+
</h1>
|
|
4634
|
+
${s.subtitle ? `
|
|
4635
|
+
<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);">
|
|
4636
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
4637
|
+
</span>
|
|
4638
|
+
` : `
|
|
4639
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
4640
|
+
Slide ${idx} / ${totalSlides}
|
|
4641
|
+
</span>
|
|
4642
|
+
`}
|
|
4532
4643
|
</div>
|
|
4644
|
+
|
|
4645
|
+
<!-- Slide Content -->
|
|
4646
|
+
${contentHtml}
|
|
4533
4647
|
</div>
|
|
4534
4648
|
`;
|
|
4535
4649
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4536
4650
|
};
|
|
4537
4651
|
renderSlide(1);
|
|
4538
4652
|
const cleanup = () => {
|
|
4653
|
+
for (const u of createdBlobUrls) {
|
|
4654
|
+
URL.revokeObjectURL(u);
|
|
4655
|
+
}
|
|
4539
4656
|
container.remove();
|
|
4540
4657
|
ctx.container.innerHTML = "";
|
|
4541
4658
|
};
|
|
@@ -4575,13 +4692,48 @@ var PptPlugin = class {
|
|
|
4575
4692
|
if (!ctx2d) return;
|
|
4576
4693
|
canvas.width = 160;
|
|
4577
4694
|
canvas.height = 90;
|
|
4578
|
-
ctx2d.fillStyle = "#
|
|
4695
|
+
ctx2d.fillStyle = "#334155";
|
|
4579
4696
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4580
|
-
ctx2d.fillStyle = "#
|
|
4581
|
-
ctx2d.
|
|
4582
|
-
ctx2d.
|
|
4583
|
-
|
|
4584
|
-
ctx2d.
|
|
4697
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4698
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
4699
|
+
ctx2d.fillStyle = "#84cc16";
|
|
4700
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
4701
|
+
ctx2d.fillStyle = "#1e293b";
|
|
4702
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
4703
|
+
ctx2d.textAlign = "left";
|
|
4704
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
4705
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
4706
|
+
if (s.subtitle) {
|
|
4707
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
4708
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
4709
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4710
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
4711
|
+
ctx2d.textAlign = "center";
|
|
4712
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
4713
|
+
}
|
|
4714
|
+
if (s.pictureUrl) {
|
|
4715
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
4716
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
4717
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4718
|
+
ctx2d.font = "8px sans-serif";
|
|
4719
|
+
ctx2d.textAlign = "center";
|
|
4720
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
4721
|
+
} else if (s.tableColumns.length > 0) {
|
|
4722
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
4723
|
+
ctx2d.lineWidth = 1;
|
|
4724
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
4725
|
+
for (let l = 1; l <= 3; l++) {
|
|
4726
|
+
ctx2d.beginPath();
|
|
4727
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
4728
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
4729
|
+
ctx2d.stroke();
|
|
4730
|
+
}
|
|
4731
|
+
} else {
|
|
4732
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
4733
|
+
for (let l = 0; l < 4; l++) {
|
|
4734
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4585
4737
|
}
|
|
4586
4738
|
}));
|
|
4587
4739
|
},
|
|
@@ -4599,66 +4751,165 @@ var PptPlugin = class {
|
|
|
4599
4751
|
}
|
|
4600
4752
|
};
|
|
4601
4753
|
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
4756
|
+
*/
|
|
4757
|
+
extractPictures(cfbf, createdUrls) {
|
|
4758
|
+
const urls = [];
|
|
4759
|
+
try {
|
|
4760
|
+
const picStream = cfbf.readStream("Pictures");
|
|
4761
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
4762
|
+
const pBuf = new Uint8Array(picStream);
|
|
4763
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
4764
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
4765
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
4766
|
+
let match = true;
|
|
4767
|
+
for (let j = 0; j < 8; j++) {
|
|
4768
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
4769
|
+
match = false;
|
|
4770
|
+
break;
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
if (match) {
|
|
4774
|
+
let endIdx = -1;
|
|
4775
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
4776
|
+
let endMatch = true;
|
|
4777
|
+
for (let j = 0; j < 8; j++) {
|
|
4778
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
4779
|
+
endMatch = false;
|
|
4780
|
+
break;
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
if (endMatch) {
|
|
4784
|
+
endIdx = k + 8;
|
|
4785
|
+
break;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
if (endIdx !== -1) {
|
|
4789
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
4790
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
4791
|
+
const url = URL.createObjectURL(blob);
|
|
4792
|
+
urls.push(url);
|
|
4793
|
+
createdUrls.push(url);
|
|
4794
|
+
i = endIdx;
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
4799
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
4800
|
+
let endIdx = -1;
|
|
4801
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
4802
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
4803
|
+
endIdx = k + 2;
|
|
4804
|
+
break;
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
if (endIdx !== -1) {
|
|
4808
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
4809
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
4810
|
+
const url = URL.createObjectURL(blob);
|
|
4811
|
+
urls.push(url);
|
|
4812
|
+
createdUrls.push(url);
|
|
4813
|
+
i = endIdx;
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
} catch (err) {
|
|
4818
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
4819
|
+
}
|
|
4820
|
+
return urls;
|
|
4821
|
+
}
|
|
4602
4822
|
/**
|
|
4603
4823
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4604
4824
|
*/
|
|
4605
|
-
extractSlides(stream) {
|
|
4825
|
+
extractSlides(stream, pictures) {
|
|
4606
4826
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4607
4827
|
const len = stream.length;
|
|
4608
4828
|
let offset = 0;
|
|
4609
4829
|
const slides = [];
|
|
4610
|
-
let
|
|
4830
|
+
let picIdx = 0;
|
|
4611
4831
|
while (offset + 8 <= len) {
|
|
4612
4832
|
const recVerInst = view.getUint16(offset, true);
|
|
4613
4833
|
const recType = view.getUint16(offset + 2, true);
|
|
4614
4834
|
const recLen = view.getUint32(offset + 4, true);
|
|
4835
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4615
4836
|
if (recType === 1006) {
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4837
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
4838
|
+
const rawTexts = [];
|
|
4839
|
+
let hasOle = false;
|
|
4840
|
+
let sOff = offset + 8;
|
|
4841
|
+
while (sOff + 8 <= slideEnd) {
|
|
4842
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
4843
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
4844
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
4845
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
4846
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4847
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4848
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
4849
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4850
|
+
rawTexts.push(txt);
|
|
4851
|
+
}
|
|
4852
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4853
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4854
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4855
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4856
|
+
rawTexts.push(txt);
|
|
4857
|
+
}
|
|
4858
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
4859
|
+
hasOle = true;
|
|
4860
|
+
}
|
|
4861
|
+
if (cIsContainer) sOff += 8;
|
|
4862
|
+
else sOff += 8 + cLen;
|
|
4621
4863
|
}
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4864
|
+
let title = "";
|
|
4865
|
+
let subtitle = "";
|
|
4866
|
+
const paragraphs = [];
|
|
4867
|
+
const tableColumns = [];
|
|
4868
|
+
for (const t of rawTexts) {
|
|
4869
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
4870
|
+
title = t;
|
|
4871
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
4872
|
+
tableColumns.push(t);
|
|
4873
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
4874
|
+
subtitle = t;
|
|
4875
|
+
} else {
|
|
4876
|
+
paragraphs.push(t);
|
|
4877
|
+
}
|
|
4630
4878
|
}
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4635
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4636
|
-
currentSlideTexts.push(text);
|
|
4879
|
+
let pictureUrl = null;
|
|
4880
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
4881
|
+
pictureUrl = pictures[picIdx++];
|
|
4637
4882
|
}
|
|
4883
|
+
slides.push({
|
|
4884
|
+
slideIndex: slides.length + 1,
|
|
4885
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
4886
|
+
subtitle,
|
|
4887
|
+
paragraphs,
|
|
4888
|
+
tableColumns,
|
|
4889
|
+
pictureUrl,
|
|
4890
|
+
hasOle
|
|
4891
|
+
});
|
|
4638
4892
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
offset += 8;
|
|
4642
|
-
} else {
|
|
4643
|
-
offset += 8 + recLen;
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
if (currentSlideTexts.length > 0) {
|
|
4647
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4648
|
-
const texts = currentSlideTexts.slice(1);
|
|
4649
|
-
slides.push({ title, texts });
|
|
4893
|
+
if (isContainer) offset += 8;
|
|
4894
|
+
else offset += 8 + recLen;
|
|
4650
4895
|
}
|
|
4651
4896
|
if (slides.length === 0) {
|
|
4652
4897
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4653
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4654
|
-
const
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4898
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
4899
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
4900
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
4901
|
+
);
|
|
4902
|
+
if (clean.length > 0) {
|
|
4903
|
+
const chunkSize = 3;
|
|
4904
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
4905
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4659
4906
|
slides.push({
|
|
4907
|
+
slideIndex: slides.length + 1,
|
|
4660
4908
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4661
|
-
|
|
4909
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
4910
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
4911
|
+
tableColumns: [],
|
|
4912
|
+
pictureUrl: pictures[slides.length] || null
|
|
4662
4913
|
});
|
|
4663
4914
|
}
|
|
4664
4915
|
}
|