pptx-glimpse 0.7.0 → 0.8.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.cjs +53 -24
- package/dist/index.js +53 -24
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -43,15 +43,18 @@ var DEFAULT_FONT_MAPPING = {
|
|
|
43
43
|
"Times New Roman": "Tinos",
|
|
44
44
|
"Courier New": "Cousine",
|
|
45
45
|
Cambria: "Caladea",
|
|
46
|
-
// 日本語ゴシック系 → Noto Sans
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"MS
|
|
46
|
+
// 日本語ゴシック系 → Noto Sans JP
|
|
47
|
+
// "Noto Sans CJK JP" ではなく "Noto Sans JP" を使用する。
|
|
48
|
+
// NotoSansCJK TTC は最初の1フォントのみ抽出するため JP バリアントが取れるとは限らず、
|
|
49
|
+
// Docker 環境でダウンロードする standalone NotoSansJP.ttf のフォント名に合わせている。
|
|
50
|
+
\u30E1\u30A4\u30EA\u30AA: "Noto Sans JP",
|
|
51
|
+
Meiryo: "Noto Sans JP",
|
|
52
|
+
\u6E38\u30B4\u30B7\u30C3\u30AF: "Noto Sans JP",
|
|
53
|
+
"Yu Gothic": "Noto Sans JP",
|
|
54
|
+
"MS \u30B4\u30B7\u30C3\u30AF": "Noto Sans JP",
|
|
55
|
+
"MS Gothic": "Noto Sans JP",
|
|
56
|
+
"MS P\u30B4\u30B7\u30C3\u30AF": "Noto Sans JP",
|
|
57
|
+
"MS PGothic": "Noto Sans JP",
|
|
55
58
|
// 日本語明朝系 → Noto Serif CJK JP
|
|
56
59
|
"MS \u660E\u671D": "Noto Serif CJK JP",
|
|
57
60
|
"MS Mincho": "Noto Serif CJK JP",
|
|
@@ -1055,19 +1058,22 @@ var OpentypeTextMeasurer = class {
|
|
|
1055
1058
|
this.defaultFont = defaultFont ?? null;
|
|
1056
1059
|
}
|
|
1057
1060
|
measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa) {
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1061
|
+
const latinFont = this.resolveFont(fontFamily);
|
|
1062
|
+
const eaFont = this.resolveFont(fontFamilyEa);
|
|
1063
|
+
const fallbackFont = latinFont ?? eaFont ?? this.defaultFont;
|
|
1064
|
+
if (!fallbackFont) {
|
|
1060
1065
|
return measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa);
|
|
1061
1066
|
}
|
|
1062
1067
|
const fontSizePx = fontSizePt * PX_PER_PT2;
|
|
1063
|
-
const scale = fontSizePx / font.unitsPerEm;
|
|
1064
1068
|
let totalWidth = 0;
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1069
|
+
for (const char of text) {
|
|
1070
|
+
const codePoint = char.codePointAt(0);
|
|
1071
|
+
const isEa = isCjkCodePoint(codePoint);
|
|
1072
|
+
const font = isEa ? eaFont ?? fallbackFont : latinFont ?? fallbackFont;
|
|
1073
|
+
const scale = fontSizePx / font.unitsPerEm;
|
|
1074
|
+
const glyphs = font.stringToGlyphs(char);
|
|
1075
|
+
let charWidth = (glyphs[0]?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
|
|
1076
|
+
if (bold && !isEa) {
|
|
1071
1077
|
charWidth *= BOLD_FACTOR2;
|
|
1072
1078
|
}
|
|
1073
1079
|
totalWidth += charWidth;
|
|
@@ -1086,7 +1092,14 @@ var OpentypeTextMeasurer = class {
|
|
|
1086
1092
|
}
|
|
1087
1093
|
resolveFont(name) {
|
|
1088
1094
|
if (!name) return null;
|
|
1089
|
-
|
|
1095
|
+
const direct = this.fonts.get(name);
|
|
1096
|
+
if (direct) return direct;
|
|
1097
|
+
const mapped = getCurrentMappedFont(name);
|
|
1098
|
+
if (mapped) {
|
|
1099
|
+
const mappedFont = this.fonts.get(mapped);
|
|
1100
|
+
if (mappedFont) return mappedFont;
|
|
1101
|
+
}
|
|
1102
|
+
return null;
|
|
1090
1103
|
}
|
|
1091
1104
|
};
|
|
1092
1105
|
|
|
@@ -3917,7 +3930,7 @@ function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPCh
|
|
|
3917
3930
|
const lnSpcSpcPct = lnSpc?.spcPct;
|
|
3918
3931
|
const tabStops = parseTabStops(pPr);
|
|
3919
3932
|
const properties = {
|
|
3920
|
-
alignment: pPr?.["@_algn"] ?? lstLevelProps?.alignment ??
|
|
3933
|
+
alignment: pPr?.["@_algn"] ?? lstLevelProps?.alignment ?? null,
|
|
3921
3934
|
lineSpacing: lnSpcSpcPct ? Number(lnSpcSpcPct["@_val"]) : null,
|
|
3922
3935
|
spaceBefore: parseSpacing(pPr?.spcBef),
|
|
3923
3936
|
spaceAfter: parseSpacing(pPr?.spcAft),
|
|
@@ -4601,6 +4614,19 @@ function resolveShapeTextInheritance(shape, context) {
|
|
|
4601
4614
|
const chainSources = [layoutLstStyle, masterLstStyle, txStyle, context.defaultTextStyle];
|
|
4602
4615
|
for (const paragraph of shape.textBody.paragraphs) {
|
|
4603
4616
|
const level = paragraph.properties.level;
|
|
4617
|
+
if (paragraph.properties.alignment === null) {
|
|
4618
|
+
for (const source of chainSources) {
|
|
4619
|
+
if (!source) continue;
|
|
4620
|
+
const alignment = source.levels[level]?.alignment ?? source.defaultParagraph?.alignment;
|
|
4621
|
+
if (alignment) {
|
|
4622
|
+
paragraph.properties.alignment = alignment;
|
|
4623
|
+
break;
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
if (paragraph.properties.alignment === null) {
|
|
4627
|
+
paragraph.properties.alignment = "l";
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4604
4630
|
for (const run of paragraph.runs) {
|
|
4605
4631
|
const props = run.properties;
|
|
4606
4632
|
for (const source of chainSources) {
|
|
@@ -8202,8 +8228,8 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8202
8228
|
segText,
|
|
8203
8229
|
fontSize,
|
|
8204
8230
|
props.bold,
|
|
8205
|
-
fontFamily,
|
|
8206
|
-
fontFamilyEa
|
|
8231
|
+
props.fontFamily,
|
|
8232
|
+
props.fontFamilyEa
|
|
8207
8233
|
);
|
|
8208
8234
|
if (font) {
|
|
8209
8235
|
const path = font.getPath(segText, x + totalWidth, effectiveY, fontSizePx);
|
|
@@ -8227,8 +8253,8 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8227
8253
|
char,
|
|
8228
8254
|
fontSize,
|
|
8229
8255
|
props.bold,
|
|
8230
|
-
fontFamily,
|
|
8231
|
-
fontFamilyEa
|
|
8256
|
+
props.fontFamily,
|
|
8257
|
+
props.fontFamilyEa
|
|
8232
8258
|
);
|
|
8233
8259
|
if (font) {
|
|
8234
8260
|
const charX = x + totalWidth;
|
|
@@ -8787,6 +8813,9 @@ async function convertPptxToSvg(input, options) {
|
|
|
8787
8813
|
const data = parsePptxData(input);
|
|
8788
8814
|
setScriptFonts(data.theme.fontScheme.majorFontJpan, data.theme.fontScheme.minorFontJpan);
|
|
8789
8815
|
const targetSlides = options?.slides ? data.slidePaths.filter((s) => options.slides.includes(s.slideNumber)) : data.slidePaths;
|
|
8816
|
+
if (data.slidePaths.length === 0) {
|
|
8817
|
+
warn("presentation.noSlides", "No slides found in the PPTX file");
|
|
8818
|
+
}
|
|
8790
8819
|
const results = [];
|
|
8791
8820
|
for (const { slideNumber, path } of targetSlides) {
|
|
8792
8821
|
const parsed = parseSlideWithLayout(slideNumber, path, data);
|
package/dist/index.js
CHANGED
|
@@ -7,15 +7,18 @@ var DEFAULT_FONT_MAPPING = {
|
|
|
7
7
|
"Times New Roman": "Tinos",
|
|
8
8
|
"Courier New": "Cousine",
|
|
9
9
|
Cambria: "Caladea",
|
|
10
|
-
// 日本語ゴシック系 → Noto Sans
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"MS
|
|
10
|
+
// 日本語ゴシック系 → Noto Sans JP
|
|
11
|
+
// "Noto Sans CJK JP" ではなく "Noto Sans JP" を使用する。
|
|
12
|
+
// NotoSansCJK TTC は最初の1フォントのみ抽出するため JP バリアントが取れるとは限らず、
|
|
13
|
+
// Docker 環境でダウンロードする standalone NotoSansJP.ttf のフォント名に合わせている。
|
|
14
|
+
\u30E1\u30A4\u30EA\u30AA: "Noto Sans JP",
|
|
15
|
+
Meiryo: "Noto Sans JP",
|
|
16
|
+
\u6E38\u30B4\u30B7\u30C3\u30AF: "Noto Sans JP",
|
|
17
|
+
"Yu Gothic": "Noto Sans JP",
|
|
18
|
+
"MS \u30B4\u30B7\u30C3\u30AF": "Noto Sans JP",
|
|
19
|
+
"MS Gothic": "Noto Sans JP",
|
|
20
|
+
"MS P\u30B4\u30B7\u30C3\u30AF": "Noto Sans JP",
|
|
21
|
+
"MS PGothic": "Noto Sans JP",
|
|
19
22
|
// 日本語明朝系 → Noto Serif CJK JP
|
|
20
23
|
"MS \u660E\u671D": "Noto Serif CJK JP",
|
|
21
24
|
"MS Mincho": "Noto Serif CJK JP",
|
|
@@ -1019,19 +1022,22 @@ var OpentypeTextMeasurer = class {
|
|
|
1019
1022
|
this.defaultFont = defaultFont ?? null;
|
|
1020
1023
|
}
|
|
1021
1024
|
measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa) {
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1025
|
+
const latinFont = this.resolveFont(fontFamily);
|
|
1026
|
+
const eaFont = this.resolveFont(fontFamilyEa);
|
|
1027
|
+
const fallbackFont = latinFont ?? eaFont ?? this.defaultFont;
|
|
1028
|
+
if (!fallbackFont) {
|
|
1024
1029
|
return measureTextWidth(text, fontSizePt, bold, fontFamily, fontFamilyEa);
|
|
1025
1030
|
}
|
|
1026
1031
|
const fontSizePx = fontSizePt * PX_PER_PT2;
|
|
1027
|
-
const scale = fontSizePx / font.unitsPerEm;
|
|
1028
1032
|
let totalWidth = 0;
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1033
|
+
for (const char of text) {
|
|
1034
|
+
const codePoint = char.codePointAt(0);
|
|
1035
|
+
const isEa = isCjkCodePoint(codePoint);
|
|
1036
|
+
const font = isEa ? eaFont ?? fallbackFont : latinFont ?? fallbackFont;
|
|
1037
|
+
const scale = fontSizePx / font.unitsPerEm;
|
|
1038
|
+
const glyphs = font.stringToGlyphs(char);
|
|
1039
|
+
let charWidth = (glyphs[0]?.advanceWidth ?? font.unitsPerEm * 0.6) * scale;
|
|
1040
|
+
if (bold && !isEa) {
|
|
1035
1041
|
charWidth *= BOLD_FACTOR2;
|
|
1036
1042
|
}
|
|
1037
1043
|
totalWidth += charWidth;
|
|
@@ -1050,7 +1056,14 @@ var OpentypeTextMeasurer = class {
|
|
|
1050
1056
|
}
|
|
1051
1057
|
resolveFont(name) {
|
|
1052
1058
|
if (!name) return null;
|
|
1053
|
-
|
|
1059
|
+
const direct = this.fonts.get(name);
|
|
1060
|
+
if (direct) return direct;
|
|
1061
|
+
const mapped = getCurrentMappedFont(name);
|
|
1062
|
+
if (mapped) {
|
|
1063
|
+
const mappedFont = this.fonts.get(mapped);
|
|
1064
|
+
if (mappedFont) return mappedFont;
|
|
1065
|
+
}
|
|
1066
|
+
return null;
|
|
1054
1067
|
}
|
|
1055
1068
|
};
|
|
1056
1069
|
|
|
@@ -3880,7 +3893,7 @@ function parseParagraph(p, colorResolver, rels, fontScheme, lstStyle, orderedPCh
|
|
|
3880
3893
|
const lnSpcSpcPct = lnSpc?.spcPct;
|
|
3881
3894
|
const tabStops = parseTabStops(pPr);
|
|
3882
3895
|
const properties = {
|
|
3883
|
-
alignment: pPr?.["@_algn"] ?? lstLevelProps?.alignment ??
|
|
3896
|
+
alignment: pPr?.["@_algn"] ?? lstLevelProps?.alignment ?? null,
|
|
3884
3897
|
lineSpacing: lnSpcSpcPct ? Number(lnSpcSpcPct["@_val"]) : null,
|
|
3885
3898
|
spaceBefore: parseSpacing(pPr?.spcBef),
|
|
3886
3899
|
spaceAfter: parseSpacing(pPr?.spcAft),
|
|
@@ -4564,6 +4577,19 @@ function resolveShapeTextInheritance(shape, context) {
|
|
|
4564
4577
|
const chainSources = [layoutLstStyle, masterLstStyle, txStyle, context.defaultTextStyle];
|
|
4565
4578
|
for (const paragraph of shape.textBody.paragraphs) {
|
|
4566
4579
|
const level = paragraph.properties.level;
|
|
4580
|
+
if (paragraph.properties.alignment === null) {
|
|
4581
|
+
for (const source of chainSources) {
|
|
4582
|
+
if (!source) continue;
|
|
4583
|
+
const alignment = source.levels[level]?.alignment ?? source.defaultParagraph?.alignment;
|
|
4584
|
+
if (alignment) {
|
|
4585
|
+
paragraph.properties.alignment = alignment;
|
|
4586
|
+
break;
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
if (paragraph.properties.alignment === null) {
|
|
4590
|
+
paragraph.properties.alignment = "l";
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4567
4593
|
for (const run of paragraph.runs) {
|
|
4568
4594
|
const props = run.properties;
|
|
4569
4595
|
for (const source of chainSources) {
|
|
@@ -8165,8 +8191,8 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8165
8191
|
segText,
|
|
8166
8192
|
fontSize,
|
|
8167
8193
|
props.bold,
|
|
8168
|
-
fontFamily,
|
|
8169
|
-
fontFamilyEa
|
|
8194
|
+
props.fontFamily,
|
|
8195
|
+
props.fontFamilyEa
|
|
8170
8196
|
);
|
|
8171
8197
|
if (font) {
|
|
8172
8198
|
const path = font.getPath(segText, x + totalWidth, effectiveY, fontSizePx);
|
|
@@ -8190,8 +8216,8 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
|
|
|
8190
8216
|
char,
|
|
8191
8217
|
fontSize,
|
|
8192
8218
|
props.bold,
|
|
8193
|
-
fontFamily,
|
|
8194
|
-
fontFamilyEa
|
|
8219
|
+
props.fontFamily,
|
|
8220
|
+
props.fontFamilyEa
|
|
8195
8221
|
);
|
|
8196
8222
|
if (font) {
|
|
8197
8223
|
const charX = x + totalWidth;
|
|
@@ -8750,6 +8776,9 @@ async function convertPptxToSvg(input, options) {
|
|
|
8750
8776
|
const data = parsePptxData(input);
|
|
8751
8777
|
setScriptFonts(data.theme.fontScheme.majorFontJpan, data.theme.fontScheme.minorFontJpan);
|
|
8752
8778
|
const targetSlides = options?.slides ? data.slidePaths.filter((s) => options.slides.includes(s.slideNumber)) : data.slidePaths;
|
|
8779
|
+
if (data.slidePaths.length === 0) {
|
|
8780
|
+
warn("presentation.noSlides", "No slides found in the PPTX file");
|
|
8781
|
+
}
|
|
8753
8782
|
const results = [];
|
|
8754
8783
|
for (const { slideNumber, path } of targetSlides) {
|
|
8755
8784
|
const parsed = parseSlideWithLayout(slideNumber, path, data);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pptx-glimpse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "A lightweight JavaScript library for rendering PowerPoint (.pptx) files as SVG or PNG in Node.js. No LibreOffice required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"inspect": "tsx scripts/inspect-pptx.ts",
|
|
31
31
|
"vrt:snapshot:docker-build": "docker build -t pptx-glimpse-snapshot-vrt docker/snapshot-vrt",
|
|
32
32
|
"vrt:snapshot:fixtures": "tsx vrt/snapshot/create-fixtures.ts",
|
|
33
|
-
"vrt:snapshot:update": "docker run --rm -v \"$(pwd)\":/workspace -v pptx-glimpse-snapshot-vrt-nm:/workspace/node_modules pptx-glimpse-snapshot-vrt bash /workspace/vrt/snapshot/docker-run.sh npx tsx vrt/snapshot/create-fixtures.ts &&
|
|
33
|
+
"vrt:snapshot:update": "docker run --rm -v \"$(pwd)\":/workspace -v pptx-glimpse-snapshot-vrt-nm:/workspace/node_modules pptx-glimpse-snapshot-vrt bash /workspace/vrt/snapshot/docker-run.sh bash -c \"npx tsx vrt/snapshot/create-fixtures.ts && npx tsx vrt/snapshot/update-snapshots.ts\"",
|
|
34
34
|
"vrt:lo:docker-build": "docker build -t pptx-glimpse-vrt docker/libreoffice-vrt",
|
|
35
35
|
"vrt:lo:fixtures": "docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt python3 /workspace/vrt/libreoffice/create_fixtures.py",
|
|
36
36
|
"vrt:lo:update": "npm run vrt:lo:docker-build && npm run vrt:lo:fixtures && docker run --rm -v \"$(pwd)\":/workspace pptx-glimpse-vrt bash /workspace/vrt/libreoffice/update_snapshots.sh",
|