@pollium/vyva-convert 0.4.0 → 0.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/README.md +3 -1
- package/dist/import/pdf.js +35 -1
- package/dist/import/pptx-theme.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,7 +81,9 @@ const { title, content } = await importFile(upload.bytes, upload.filename, {
|
|
|
81
81
|
keeps its theme colors and the font most of its text uses. What its slide master draws comes in
|
|
82
82
|
locked, behind the slide's own elements, and freeform shapes come in as polygons.
|
|
83
83
|
- A PDF becomes a deck of its own pages: one slide for each page, at the size of the first page,
|
|
84
|
-
with that page behind it. Nothing is converted, so it looks exactly like the original.
|
|
84
|
+
with that page behind it. Nothing is converted, so it looks exactly like the original. The deck
|
|
85
|
+
takes the font most of the text of its first five pages uses, so text written over a page
|
|
86
|
+
matches it.
|
|
85
87
|
`saveImage` stores the PDF once, as `application/pdf`; return `null` and the import is refused as
|
|
86
88
|
`empty`. A PDF Vyva cannot open is refused as `unsupported`, and one of more than 1000 pages as
|
|
87
89
|
`too-large`.
|
package/dist/import/pdf.js
CHANGED
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
import { ConvertError } from "../errors.js";
|
|
2
2
|
import { titleOf } from "./titles.js";
|
|
3
3
|
import { PLAIN_THEME } from "./plain-theme.js";
|
|
4
|
+
import { familyOf } from "./pptx-theme.js";
|
|
4
5
|
import { MAX_EXTENT, MAX_SLIDES } from "@pollium/vyva-core/content";
|
|
5
6
|
import { newId } from "@pollium/vyva-core/ids";
|
|
6
7
|
import { getDocumentProxy } from "unpdf";
|
|
7
8
|
//#region src/import/pdf.ts
|
|
8
9
|
const PX_PER_POINT = 2;
|
|
9
10
|
const PDF_TYPE = "application/pdf";
|
|
11
|
+
const FONT_PAGES = 5;
|
|
12
|
+
const SUBSET = /^[A-Z]{6}\+/;
|
|
13
|
+
const STYLE = /[,-].*$/;
|
|
14
|
+
const MAKER = /(PSMT|PS|MT)$/;
|
|
15
|
+
const WORDS = /([a-z])([A-Z])/g;
|
|
16
|
+
const LATEX_SERIF = /^(CM(R|BX|TI|SL)\d|SF(RM|BX|TI)\d|NimbusRom|LMRoman)/;
|
|
17
|
+
const GENERIC = {
|
|
18
|
+
serif: "Lora",
|
|
19
|
+
monospace: "JetBrains Mono"
|
|
20
|
+
};
|
|
21
|
+
const familyOfPdf = (name, generic) => {
|
|
22
|
+
const base = name.replace(SUBSET, "").replace(STYLE, "");
|
|
23
|
+
if (LATEX_SERIF.test(base)) return "Lora";
|
|
24
|
+
return familyOf(base.replace(MAKER, "").replace(WORDS, "$1 $2")) ?? GENERIC[generic] ?? PLAIN_THEME.font;
|
|
25
|
+
};
|
|
26
|
+
const dominantFont = async (pdf) => {
|
|
27
|
+
const counts = /* @__PURE__ */ new Map();
|
|
28
|
+
for (let number = 1; number <= Math.min(pdf.numPages, FONT_PAGES); number++) {
|
|
29
|
+
const page = await pdf.getPage(number);
|
|
30
|
+
await page.getOperatorList();
|
|
31
|
+
const content = await page.getTextContent();
|
|
32
|
+
for (const item of content.items) {
|
|
33
|
+
if (!("str" in item)) continue;
|
|
34
|
+
const font = page.commonObjs.has(item.fontName) ? page.commonObjs.get(item.fontName) : {};
|
|
35
|
+
const family = familyOfPdf(typeof font.name === "string" ? font.name : "", content.styles[item.fontName]?.fontFamily ?? "");
|
|
36
|
+
counts.set(family, (counts.get(family) ?? 0) + item.str.length);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return [...counts].sort((a, b) => b[1] - a[1])[0]?.[0] ?? PLAIN_THEME.font;
|
|
40
|
+
};
|
|
10
41
|
const slideSizeOf = (width, height) => {
|
|
11
42
|
const scale = Math.min(PX_PER_POINT, MAX_EXTENT / Math.max(width, height));
|
|
12
43
|
return {
|
|
@@ -32,7 +63,10 @@ const importPdf = async (buffer, filename, saveImage) => {
|
|
|
32
63
|
content: {
|
|
33
64
|
kind: "deck",
|
|
34
65
|
format: slideSizeOf(width, height),
|
|
35
|
-
theme:
|
|
66
|
+
theme: {
|
|
67
|
+
...PLAIN_THEME,
|
|
68
|
+
font: await dominantFont(pdf)
|
|
69
|
+
},
|
|
36
70
|
slides: Array.from({ length: pdf.numPages }, (_, index) => ({
|
|
37
71
|
id: newId(),
|
|
38
72
|
background: {
|
|
@@ -37,8 +37,10 @@ const FONT_SUBSTITUTES = {
|
|
|
37
37
|
"gill sans mt": "Montserrat",
|
|
38
38
|
georgia: "Merriweather",
|
|
39
39
|
cambria: "Lora",
|
|
40
|
+
times: "Lora",
|
|
40
41
|
"times new roman": "Lora",
|
|
41
42
|
garamond: "Lora",
|
|
43
|
+
courier: "JetBrains Mono",
|
|
42
44
|
"courier new": "JetBrains Mono",
|
|
43
45
|
consolas: "JetBrains Mono"
|
|
44
46
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pollium/vyva-convert",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Server-side tools for Vyva content: clean what clients send, import Word, PowerPoint, PDF, OpenDocument, Markdown and image files, and export to PDF, Word, PowerPoint and HTML.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|