@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/vue.cjs
CHANGED
|
@@ -14,7 +14,7 @@ var THREE = require('three');
|
|
|
14
14
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
15
15
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
16
16
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
17
|
-
var
|
|
17
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
18
18
|
|
|
19
19
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
20
|
|
|
@@ -41,6 +41,7 @@ var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
|
41
41
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
42
42
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
43
43
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
44
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
44
45
|
|
|
45
46
|
// src/vue.ts
|
|
46
47
|
var EventEmitter = class {
|
|
@@ -296,6 +297,39 @@ function detectOoxmlType(buffer) {
|
|
|
296
297
|
}
|
|
297
298
|
return "application/zip";
|
|
298
299
|
}
|
|
300
|
+
function detectCfbfType(buffer) {
|
|
301
|
+
const bytes = new Uint8Array(buffer);
|
|
302
|
+
const hasUtf16le = (str) => {
|
|
303
|
+
const target = new Uint8Array(str.length * 2);
|
|
304
|
+
for (let i = 0; i < str.length; i++) {
|
|
305
|
+
target[i * 2] = str.charCodeAt(i);
|
|
306
|
+
target[i * 2 + 1] = 0;
|
|
307
|
+
}
|
|
308
|
+
const targetLen = target.length;
|
|
309
|
+
const max = bytes.length - targetLen;
|
|
310
|
+
for (let i = 0; i <= max; i++) {
|
|
311
|
+
let match = true;
|
|
312
|
+
for (let j = 0; j < targetLen; j++) {
|
|
313
|
+
if (bytes[i + j] !== target[j]) {
|
|
314
|
+
match = false;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (match) return true;
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
};
|
|
322
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
323
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
324
|
+
}
|
|
325
|
+
if (hasUtf16le("WordDocument")) {
|
|
326
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
327
|
+
}
|
|
328
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
329
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
299
333
|
function extractExtension(nameOrUrl) {
|
|
300
334
|
try {
|
|
301
335
|
const url = new URL(nameOrUrl);
|
|
@@ -360,6 +394,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
360
394
|
} else {
|
|
361
395
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
362
396
|
}
|
|
397
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
398
|
+
if (metadata.extension) {
|
|
399
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
400
|
+
} else {
|
|
401
|
+
const cfbf = detectCfbfType(buffer);
|
|
402
|
+
if (cfbf) {
|
|
403
|
+
metadata.mimeType = cfbf.mime;
|
|
404
|
+
metadata.extension = cfbf.extension;
|
|
405
|
+
} else {
|
|
406
|
+
metadata.mimeType = magicMime;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
363
409
|
} else {
|
|
364
410
|
metadata.mimeType = magicMime;
|
|
365
411
|
}
|
|
@@ -1648,7 +1694,10 @@ var DocxPlugin = class {
|
|
|
1648
1694
|
supports(file) {
|
|
1649
1695
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1650
1696
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1651
|
-
|
|
1697
|
+
if (ext) {
|
|
1698
|
+
return this.extensions.includes(ext);
|
|
1699
|
+
}
|
|
1700
|
+
return this.mimeTypes.includes(mime || "");
|
|
1652
1701
|
}
|
|
1653
1702
|
getToolbarActions(instance) {
|
|
1654
1703
|
return [
|
|
@@ -2037,7 +2086,10 @@ var ExcelPlugin = class {
|
|
|
2037
2086
|
supports(file) {
|
|
2038
2087
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2039
2088
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2040
|
-
|
|
2089
|
+
if (ext) {
|
|
2090
|
+
return this.extensions.includes(ext);
|
|
2091
|
+
}
|
|
2092
|
+
return this.mimeTypes.includes(mime || "");
|
|
2041
2093
|
}
|
|
2042
2094
|
getToolbarActions(instance) {
|
|
2043
2095
|
return [
|
|
@@ -2979,7 +3031,10 @@ var PptxPlugin = class {
|
|
|
2979
3031
|
supports(file) {
|
|
2980
3032
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2981
3033
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2982
|
-
|
|
3034
|
+
if (ext) {
|
|
3035
|
+
return this.extensions.includes(ext);
|
|
3036
|
+
}
|
|
3037
|
+
return this.mimeTypes.includes(mime || "");
|
|
2983
3038
|
}
|
|
2984
3039
|
getToolbarActions(instance) {
|
|
2985
3040
|
return [
|
|
@@ -3424,7 +3479,10 @@ var RtfPlugin = class {
|
|
|
3424
3479
|
ctx.container.appendChild(wrapper);
|
|
3425
3480
|
let scale = 1;
|
|
3426
3481
|
try {
|
|
3427
|
-
|
|
3482
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3483
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3484
|
+
}
|
|
3485
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3428
3486
|
const htmlElements = await doc.render();
|
|
3429
3487
|
for (const el of htmlElements) {
|
|
3430
3488
|
wrapper.appendChild(el);
|
|
@@ -3622,7 +3680,10 @@ var OpenDocumentPlugin = class {
|
|
|
3622
3680
|
supports(file) {
|
|
3623
3681
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3624
3682
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3625
|
-
|
|
3683
|
+
if (ext) {
|
|
3684
|
+
return this.extensions.includes(ext);
|
|
3685
|
+
}
|
|
3686
|
+
return this.mimeTypes.includes(mime || "");
|
|
3626
3687
|
}
|
|
3627
3688
|
getToolbarActions(instance) {
|
|
3628
3689
|
const isPresentation = instance.isPresentation;
|
|
@@ -4037,7 +4098,10 @@ var DocPlugin = class {
|
|
|
4037
4098
|
supports(file) {
|
|
4038
4099
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4039
4100
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4040
|
-
|
|
4101
|
+
if (ext) {
|
|
4102
|
+
return this.extensions.includes(ext);
|
|
4103
|
+
}
|
|
4104
|
+
return this.mimeTypes.includes(mime || "");
|
|
4041
4105
|
}
|
|
4042
4106
|
getToolbarActions(instance) {
|
|
4043
4107
|
return [
|
|
@@ -4260,22 +4324,22 @@ var DocPlugin = class {
|
|
|
4260
4324
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4261
4325
|
*/
|
|
4262
4326
|
extractStringsFromBytes(bytes) {
|
|
4263
|
-
const
|
|
4264
|
-
const
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4327
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4328
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4329
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4330
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4331
|
+
const candidateLines = [];
|
|
4332
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4333
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4334
|
+
const trimmed = run.trim();
|
|
4335
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4336
|
+
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)) {
|
|
4337
|
+
seen.add(trimmed);
|
|
4338
|
+
candidateLines.push(trimmed);
|
|
4339
|
+
}
|
|
4276
4340
|
}
|
|
4277
4341
|
}
|
|
4278
|
-
return
|
|
4342
|
+
return candidateLines.join("\n\n");
|
|
4279
4343
|
}
|
|
4280
4344
|
heuristicTextExtraction(buffer) {
|
|
4281
4345
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
@@ -4330,14 +4394,17 @@ function docPlugin() {
|
|
|
4330
4394
|
}
|
|
4331
4395
|
var PptPlugin = class {
|
|
4332
4396
|
id = "ppt";
|
|
4333
|
-
name = "
|
|
4397
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4334
4398
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4335
4399
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4336
|
-
weight =
|
|
4400
|
+
weight = 85;
|
|
4337
4401
|
supports(file) {
|
|
4338
4402
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4339
4403
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4340
|
-
|
|
4404
|
+
if (ext) {
|
|
4405
|
+
return this.extensions.includes(ext);
|
|
4406
|
+
}
|
|
4407
|
+
return this.mimeTypes.includes(mime || "");
|
|
4341
4408
|
}
|
|
4342
4409
|
getToolbarActions(instance) {
|
|
4343
4410
|
return [
|
|
@@ -4425,19 +4492,15 @@ var PptPlugin = class {
|
|
|
4425
4492
|
container.style.alignItems = "center";
|
|
4426
4493
|
container.style.padding = "32px 16px";
|
|
4427
4494
|
container.style.backgroundColor = "#0f172a";
|
|
4495
|
+
container.style.boxSizing = "border-box";
|
|
4428
4496
|
const slideCard = document.createElement("div");
|
|
4429
4497
|
slideCard.className = "fp-ppt-slide-card";
|
|
4430
4498
|
slideCard.style.width = "960px";
|
|
4431
|
-
slideCard.style.maxWidth = "
|
|
4499
|
+
slideCard.style.maxWidth = "92%";
|
|
4432
4500
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4433
4501
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4434
|
-
slideCard.style.boxShadow = "0
|
|
4502
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4435
4503
|
slideCard.style.borderRadius = "8px";
|
|
4436
|
-
slideCard.style.padding = "48px";
|
|
4437
|
-
slideCard.style.display = "flex";
|
|
4438
|
-
slideCard.style.flexDirection = "column";
|
|
4439
|
-
slideCard.style.justifyContent = "center";
|
|
4440
|
-
slideCard.style.alignItems = "center";
|
|
4441
4504
|
slideCard.style.boxSizing = "border-box";
|
|
4442
4505
|
slideCard.style.position = "relative";
|
|
4443
4506
|
slideCard.style.overflow = "hidden";
|
|
@@ -4448,21 +4511,25 @@ var PptPlugin = class {
|
|
|
4448
4511
|
let scale = 1;
|
|
4449
4512
|
let currentSlide = 1;
|
|
4450
4513
|
let slides = [];
|
|
4514
|
+
const createdBlobUrls = [];
|
|
4451
4515
|
try {
|
|
4452
4516
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4453
4517
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4454
4518
|
if (!pptStream || pptStream.length < 512) {
|
|
4455
4519
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4456
4520
|
}
|
|
4457
|
-
|
|
4521
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
4522
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4458
4523
|
} catch (err) {
|
|
4459
4524
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4460
4525
|
}
|
|
4461
4526
|
if (slides.length === 0) {
|
|
4462
4527
|
slides = [
|
|
4463
4528
|
{
|
|
4529
|
+
slideIndex: 1,
|
|
4464
4530
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4465
|
-
|
|
4531
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
4532
|
+
tableColumns: []
|
|
4466
4533
|
}
|
|
4467
4534
|
];
|
|
4468
4535
|
}
|
|
@@ -4471,23 +4538,73 @@ var PptPlugin = class {
|
|
|
4471
4538
|
currentSlide = idx;
|
|
4472
4539
|
const s = slides[idx - 1];
|
|
4473
4540
|
if (!s) return;
|
|
4541
|
+
let contentHtml = "";
|
|
4542
|
+
if (s.pictureUrl) {
|
|
4543
|
+
contentHtml = `
|
|
4544
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
4545
|
+
<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;" />
|
|
4546
|
+
</div>
|
|
4547
|
+
`;
|
|
4548
|
+
} else if (s.tableColumns.length > 0) {
|
|
4549
|
+
const cols = s.tableColumns;
|
|
4550
|
+
contentHtml = `
|
|
4551
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
4552
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
4553
|
+
<thead>
|
|
4554
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
4555
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
4556
|
+
</tr>
|
|
4557
|
+
</thead>
|
|
4558
|
+
<tbody>
|
|
4559
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
4560
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
4561
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
4562
|
+
</tr>
|
|
4563
|
+
`).join("")}
|
|
4564
|
+
</tbody>
|
|
4565
|
+
</table>
|
|
4566
|
+
</div>
|
|
4567
|
+
`;
|
|
4568
|
+
} else {
|
|
4569
|
+
const pTags = s.paragraphs.map((p) => {
|
|
4570
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
4571
|
+
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("");
|
|
4572
|
+
}).join("");
|
|
4573
|
+
contentHtml = `
|
|
4574
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
4575
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
4576
|
+
</div>
|
|
4577
|
+
`;
|
|
4578
|
+
}
|
|
4474
4579
|
slideCard.innerHTML = `
|
|
4475
|
-
<div style="
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4580
|
+
<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;">
|
|
4581
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
4582
|
+
<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;">
|
|
4583
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
4584
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
4585
|
+
</h1>
|
|
4586
|
+
${s.subtitle ? `
|
|
4587
|
+
<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);">
|
|
4588
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
4589
|
+
</span>
|
|
4590
|
+
` : `
|
|
4591
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
4592
|
+
Slide ${idx} / ${totalSlides}
|
|
4593
|
+
</span>
|
|
4594
|
+
`}
|
|
4484
4595
|
</div>
|
|
4596
|
+
|
|
4597
|
+
<!-- Slide Content -->
|
|
4598
|
+
${contentHtml}
|
|
4485
4599
|
</div>
|
|
4486
4600
|
`;
|
|
4487
4601
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4488
4602
|
};
|
|
4489
4603
|
renderSlide(1);
|
|
4490
4604
|
const cleanup = () => {
|
|
4605
|
+
for (const u of createdBlobUrls) {
|
|
4606
|
+
URL.revokeObjectURL(u);
|
|
4607
|
+
}
|
|
4491
4608
|
container.remove();
|
|
4492
4609
|
ctx.container.innerHTML = "";
|
|
4493
4610
|
};
|
|
@@ -4527,13 +4644,48 @@ var PptPlugin = class {
|
|
|
4527
4644
|
if (!ctx2d) return;
|
|
4528
4645
|
canvas.width = 160;
|
|
4529
4646
|
canvas.height = 90;
|
|
4530
|
-
ctx2d.fillStyle = "#
|
|
4647
|
+
ctx2d.fillStyle = "#334155";
|
|
4531
4648
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4532
|
-
ctx2d.fillStyle = "#
|
|
4533
|
-
ctx2d.
|
|
4534
|
-
ctx2d.
|
|
4535
|
-
|
|
4536
|
-
ctx2d.
|
|
4649
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4650
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
4651
|
+
ctx2d.fillStyle = "#84cc16";
|
|
4652
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
4653
|
+
ctx2d.fillStyle = "#1e293b";
|
|
4654
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
4655
|
+
ctx2d.textAlign = "left";
|
|
4656
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
4657
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
4658
|
+
if (s.subtitle) {
|
|
4659
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
4660
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
4661
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4662
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
4663
|
+
ctx2d.textAlign = "center";
|
|
4664
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
4665
|
+
}
|
|
4666
|
+
if (s.pictureUrl) {
|
|
4667
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
4668
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
4669
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4670
|
+
ctx2d.font = "8px sans-serif";
|
|
4671
|
+
ctx2d.textAlign = "center";
|
|
4672
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
4673
|
+
} else if (s.tableColumns.length > 0) {
|
|
4674
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
4675
|
+
ctx2d.lineWidth = 1;
|
|
4676
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
4677
|
+
for (let l = 1; l <= 3; l++) {
|
|
4678
|
+
ctx2d.beginPath();
|
|
4679
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
4680
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
4681
|
+
ctx2d.stroke();
|
|
4682
|
+
}
|
|
4683
|
+
} else {
|
|
4684
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
4685
|
+
for (let l = 0; l < 4; l++) {
|
|
4686
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4537
4689
|
}
|
|
4538
4690
|
}));
|
|
4539
4691
|
},
|
|
@@ -4551,66 +4703,165 @@ var PptPlugin = class {
|
|
|
4551
4703
|
}
|
|
4552
4704
|
};
|
|
4553
4705
|
}
|
|
4706
|
+
/**
|
|
4707
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
4708
|
+
*/
|
|
4709
|
+
extractPictures(cfbf, createdUrls) {
|
|
4710
|
+
const urls = [];
|
|
4711
|
+
try {
|
|
4712
|
+
const picStream = cfbf.readStream("Pictures");
|
|
4713
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
4714
|
+
const pBuf = new Uint8Array(picStream);
|
|
4715
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
4716
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
4717
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
4718
|
+
let match = true;
|
|
4719
|
+
for (let j = 0; j < 8; j++) {
|
|
4720
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
4721
|
+
match = false;
|
|
4722
|
+
break;
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
if (match) {
|
|
4726
|
+
let endIdx = -1;
|
|
4727
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
4728
|
+
let endMatch = true;
|
|
4729
|
+
for (let j = 0; j < 8; j++) {
|
|
4730
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
4731
|
+
endMatch = false;
|
|
4732
|
+
break;
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
if (endMatch) {
|
|
4736
|
+
endIdx = k + 8;
|
|
4737
|
+
break;
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4740
|
+
if (endIdx !== -1) {
|
|
4741
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
4742
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
4743
|
+
const url = URL.createObjectURL(blob);
|
|
4744
|
+
urls.push(url);
|
|
4745
|
+
createdUrls.push(url);
|
|
4746
|
+
i = endIdx;
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
4751
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
4752
|
+
let endIdx = -1;
|
|
4753
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
4754
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
4755
|
+
endIdx = k + 2;
|
|
4756
|
+
break;
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4759
|
+
if (endIdx !== -1) {
|
|
4760
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
4761
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
4762
|
+
const url = URL.createObjectURL(blob);
|
|
4763
|
+
urls.push(url);
|
|
4764
|
+
createdUrls.push(url);
|
|
4765
|
+
i = endIdx;
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
} catch (err) {
|
|
4770
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
4771
|
+
}
|
|
4772
|
+
return urls;
|
|
4773
|
+
}
|
|
4554
4774
|
/**
|
|
4555
4775
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4556
4776
|
*/
|
|
4557
|
-
extractSlides(stream) {
|
|
4777
|
+
extractSlides(stream, pictures) {
|
|
4558
4778
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4559
4779
|
const len = stream.length;
|
|
4560
4780
|
let offset = 0;
|
|
4561
4781
|
const slides = [];
|
|
4562
|
-
let
|
|
4782
|
+
let picIdx = 0;
|
|
4563
4783
|
while (offset + 8 <= len) {
|
|
4564
4784
|
const recVerInst = view.getUint16(offset, true);
|
|
4565
4785
|
const recType = view.getUint16(offset + 2, true);
|
|
4566
4786
|
const recLen = view.getUint32(offset + 4, true);
|
|
4787
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4567
4788
|
if (recType === 1006) {
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4789
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
4790
|
+
const rawTexts = [];
|
|
4791
|
+
let hasOle = false;
|
|
4792
|
+
let sOff = offset + 8;
|
|
4793
|
+
while (sOff + 8 <= slideEnd) {
|
|
4794
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
4795
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
4796
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
4797
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
4798
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4799
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4800
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
4801
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4802
|
+
rawTexts.push(txt);
|
|
4803
|
+
}
|
|
4804
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4805
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4806
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4807
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4808
|
+
rawTexts.push(txt);
|
|
4809
|
+
}
|
|
4810
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
4811
|
+
hasOle = true;
|
|
4812
|
+
}
|
|
4813
|
+
if (cIsContainer) sOff += 8;
|
|
4814
|
+
else sOff += 8 + cLen;
|
|
4573
4815
|
}
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4816
|
+
let title = "";
|
|
4817
|
+
let subtitle = "";
|
|
4818
|
+
const paragraphs = [];
|
|
4819
|
+
const tableColumns = [];
|
|
4820
|
+
for (const t of rawTexts) {
|
|
4821
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
4822
|
+
title = t;
|
|
4823
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
4824
|
+
tableColumns.push(t);
|
|
4825
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
4826
|
+
subtitle = t;
|
|
4827
|
+
} else {
|
|
4828
|
+
paragraphs.push(t);
|
|
4829
|
+
}
|
|
4582
4830
|
}
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4587
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4588
|
-
currentSlideTexts.push(text);
|
|
4831
|
+
let pictureUrl = null;
|
|
4832
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
4833
|
+
pictureUrl = pictures[picIdx++];
|
|
4589
4834
|
}
|
|
4835
|
+
slides.push({
|
|
4836
|
+
slideIndex: slides.length + 1,
|
|
4837
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
4838
|
+
subtitle,
|
|
4839
|
+
paragraphs,
|
|
4840
|
+
tableColumns,
|
|
4841
|
+
pictureUrl,
|
|
4842
|
+
hasOle
|
|
4843
|
+
});
|
|
4590
4844
|
}
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
offset += 8;
|
|
4594
|
-
} else {
|
|
4595
|
-
offset += 8 + recLen;
|
|
4596
|
-
}
|
|
4597
|
-
}
|
|
4598
|
-
if (currentSlideTexts.length > 0) {
|
|
4599
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4600
|
-
const texts = currentSlideTexts.slice(1);
|
|
4601
|
-
slides.push({ title, texts });
|
|
4845
|
+
if (isContainer) offset += 8;
|
|
4846
|
+
else offset += 8 + recLen;
|
|
4602
4847
|
}
|
|
4603
4848
|
if (slides.length === 0) {
|
|
4604
4849
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4605
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4606
|
-
const
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4850
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
4851
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
4852
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
4853
|
+
);
|
|
4854
|
+
if (clean.length > 0) {
|
|
4855
|
+
const chunkSize = 3;
|
|
4856
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
4857
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4611
4858
|
slides.push({
|
|
4859
|
+
slideIndex: slides.length + 1,
|
|
4612
4860
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4613
|
-
|
|
4861
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
4862
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
4863
|
+
tableColumns: [],
|
|
4864
|
+
pictureUrl: pictures[slides.length] || null
|
|
4614
4865
|
});
|
|
4615
4866
|
}
|
|
4616
4867
|
}
|