@ohos-ports/slides-grab 1.5.0-beta.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/LICENSE +21 -0
- package/README-ko.md +292 -0
- package/README.md +301 -0
- package/bin/ohos-postinstall.cjs +118 -0
- package/bin/ppt-agent.js +620 -0
- package/convert.cjs +20 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/glib-2.0/include/glibconfig.h +220 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/index.js +1 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libexpat.so +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libffi.so +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libjpeg.so +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libpcre2-8.so.0 +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libvips-cpp.so.42.20.3 +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/lib/libvips.so.42.20.3 +0 -0
- package/native/@img/sharp-libvips-openharmony-arm64/package.json +13 -0
- package/native/@img/sharp-openharmony-arm64/lib/sharp-openharmony-arm64.node +0 -0
- package/native/@img/sharp-openharmony-arm64/package.json +16 -0
- package/package.json +95 -0
- package/runtimes/claude-code/agents/design-critic-agent.md +23 -0
- package/runtimes/codex/agents/slides-grab-design-critic.md +22 -0
- package/scripts/build-viewer.js +444 -0
- package/scripts/design-gate.js +258 -0
- package/scripts/download-video.js +213 -0
- package/scripts/editor-server.js +1167 -0
- package/scripts/figma-export.js +169 -0
- package/scripts/generate-image.js +116 -0
- package/scripts/generate-images.js +164 -0
- package/scripts/html2pdf.js +822 -0
- package/scripts/html2png.js +246 -0
- package/scripts/html2pptx.js +162 -0
- package/scripts/import-template.js +86 -0
- package/scripts/install-runtime.js +216 -0
- package/scripts/render-tldraw.js +44 -0
- package/scripts/validate-slides.js +221 -0
- package/skills/slides-grab/SKILL.md +65 -0
- package/skills/slides-grab/references/presentation-workflow-reference.md +61 -0
- package/skills/slides-grab-card-news/SKILL.md +35 -0
- package/skills/slides-grab-design/SKILL.md +88 -0
- package/skills/slides-grab-design/references/beautiful-slide-defaults.md +88 -0
- package/skills/slides-grab-design/references/design-gate.md +349 -0
- package/skills/slides-grab-design/references/design-rules.md +76 -0
- package/skills/slides-grab-design/references/design-system-full.md +568 -0
- package/skills/slides-grab-design/references/detailed-design-rules.md +70 -0
- package/skills/slides-grab-export/SKILL.md +55 -0
- package/skills/slides-grab-export/references/export-rules.md +27 -0
- package/skills/slides-grab-export/references/html2pptx.md +627 -0
- package/skills/slides-grab-export/references/ooxml.md +427 -0
- package/skills/slides-grab-export/references/pptx-skill-reference.md +189 -0
- package/skills/slides-grab-html/SKILL.md +67 -0
- package/skills/slides-grab-image/SKILL.md +82 -0
- package/skills/slides-grab-plan/SKILL.md +68 -0
- package/skills/slides-grab-plan/references/design-md-to-slides-conversion.md +135 -0
- package/skills/slides-grab-plan/references/outline-format.md +47 -0
- package/skills/slides-grab-plan/references/plan-workflow-reference.md +140 -0
- package/src/codex-imagen.js +182 -0
- package/src/design-diversity-data.js +6932 -0
- package/src/design-gate-report.js +244 -0
- package/src/design-gate-state.js +329 -0
- package/src/design-import.js +164 -0
- package/src/design-md-parser.js +415 -0
- package/src/design-styles-data.js +1928 -0
- package/src/design-styles.js +209 -0
- package/src/editor/codex-edit.js +584 -0
- package/src/editor/edit-subprocess.js +170 -0
- package/src/editor/editor-codex-prompt.md +50 -0
- package/src/editor/editor.html +1785 -0
- package/src/editor/js/editor-bbox.js +332 -0
- package/src/editor/js/editor-chat.js +56 -0
- package/src/editor/js/editor-direct-edit.js +238 -0
- package/src/editor/js/editor-dom.js +59 -0
- package/src/editor/js/editor-init.js +405 -0
- package/src/editor/js/editor-navigation.js +54 -0
- package/src/editor/js/editor-select.js +558 -0
- package/src/editor/js/editor-send.js +175 -0
- package/src/editor/js/editor-sse.js +163 -0
- package/src/editor/js/editor-state.js +41 -0
- package/src/editor/js/editor-type.js +71 -0
- package/src/editor/js/editor-utils.js +167 -0
- package/src/editor/js/model-registry.js +37 -0
- package/src/editor/screenshot.js +82 -0
- package/src/export-resolution.cjs +68 -0
- package/src/figma.js +71 -0
- package/src/html2pptx-scale.cjs +120 -0
- package/src/html2pptx.cjs +1262 -0
- package/src/image-contract.js +329 -0
- package/src/image-native.js +468 -0
- package/src/nano-banana.js +841 -0
- package/src/ohos-browser-bridge.cjs +272 -0
- package/src/pptx-raster-export.cjs +299 -0
- package/src/resolve.js +110 -0
- package/src/slide-mode.cjs +72 -0
- package/src/template-fidelity.js +267 -0
- package/src/template-import.js +505 -0
- package/src/template-layout.js +261 -0
- package/src/template-pack.js +255 -0
- package/src/tldraw/render.js +473 -0
- package/src/validation/cli.js +120 -0
- package/src/validation/core.js +1023 -0
- package/templates/chart.html +121 -0
- package/templates/closing.html +54 -0
- package/templates/content.html +50 -0
- package/templates/contents.html +60 -0
- package/templates/cover.html +64 -0
- package/templates/custom/.gitkeep +0 -0
- package/templates/custom/README.md +7 -0
- package/templates/design-styles/README.md +20 -0
- package/templates/design-styles/preview.html +4438 -0
- package/templates/diagram-tldraw.html +56 -0
- package/templates/diagram.html +98 -0
- package/templates/quote.html +31 -0
- package/templates/section-divider.html +43 -0
- package/templates/split-layout.html +43 -0
- package/templates/statistics.html +55 -0
- package/templates/team.html +49 -0
- package/templates/timeline.html +59 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
// OHOS: Use system Haitai browser via CDP bridge instead of standalone Chromium
|
|
6
|
+
const { launchBrowserViaCdp, loadPageUrl } = require('../ohos-browser-bridge.cjs');
|
|
7
|
+
|
|
8
|
+
export const SCREENSHOT_SIZE = { width: 1600, height: 900 };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Launch a reusable headless Chromium browser.
|
|
12
|
+
* Caller is responsible for closing the browser when done.
|
|
13
|
+
*/
|
|
14
|
+
export async function createScreenshotBrowser() {
|
|
15
|
+
if (process.platform === 'openharmony') {
|
|
16
|
+
const browser = await launchBrowserViaCdp();
|
|
17
|
+
return { browser };
|
|
18
|
+
}
|
|
19
|
+
const { chromium } = require('playwright');
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
return { browser };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a fresh screenshot page/context from an existing browser.
|
|
26
|
+
* Caller must close the returned context.
|
|
27
|
+
*/
|
|
28
|
+
export async function createScreenshotPage(browser, screenshotSize = SCREENSHOT_SIZE) {
|
|
29
|
+
const context = await browser.newContext({ viewport: screenshotSize });
|
|
30
|
+
const page = await context.newPage();
|
|
31
|
+
return { context, page };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Capture a screenshot of a single slide HTML file.
|
|
36
|
+
*
|
|
37
|
+
* @param {import('playwright').Page} page – reusable Playwright page
|
|
38
|
+
* @param {string} slideFile – filename, e.g. "slide-04.html"
|
|
39
|
+
* @param {string} screenshotPath – output PNG path
|
|
40
|
+
* @param {string} slidesDir – directory containing the slide files
|
|
41
|
+
* @param {object} [options]
|
|
42
|
+
* @param {boolean} [options.useHttp] – if true, slidesDir is treated as a base URL
|
|
43
|
+
*/
|
|
44
|
+
export async function captureSlideScreenshot(page, slideFile, screenshotPath, slidesDir, options = {}) {
|
|
45
|
+
const screenshotSize = options.screenshotSize || SCREENSHOT_SIZE;
|
|
46
|
+
const slideUrl = options.useHttp
|
|
47
|
+
? `${slidesDir}/${slideFile}`
|
|
48
|
+
: pathToFileURL(join(slidesDir, slideFile)).href;
|
|
49
|
+
|
|
50
|
+
await loadPageUrl(page, slideUrl, { waitUntil: 'load' });
|
|
51
|
+
await page.evaluate(async () => {
|
|
52
|
+
if (document.fonts?.ready) {
|
|
53
|
+
await document.fonts.ready;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await page.evaluate(({ width, height }) => {
|
|
58
|
+
const htmlStyle = document.documentElement.style;
|
|
59
|
+
const bodyStyle = document.body.style;
|
|
60
|
+
|
|
61
|
+
htmlStyle.margin = '0';
|
|
62
|
+
htmlStyle.padding = '0';
|
|
63
|
+
htmlStyle.overflow = 'hidden';
|
|
64
|
+
htmlStyle.background = '#ffffff';
|
|
65
|
+
|
|
66
|
+
bodyStyle.margin = '0';
|
|
67
|
+
bodyStyle.padding = '0';
|
|
68
|
+
bodyStyle.transformOrigin = 'top left';
|
|
69
|
+
|
|
70
|
+
const rect = document.body.getBoundingClientRect();
|
|
71
|
+
const sourceWidth = rect.width > 0 ? rect.width : width;
|
|
72
|
+
const sourceHeight = rect.height > 0 ? rect.height : height;
|
|
73
|
+
const scale = Math.min(width / sourceWidth, height / sourceHeight);
|
|
74
|
+
|
|
75
|
+
bodyStyle.transform = `scale(${scale})`;
|
|
76
|
+
}, screenshotSize);
|
|
77
|
+
|
|
78
|
+
await page.screenshot({
|
|
79
|
+
path: screenshotPath,
|
|
80
|
+
fullPage: false,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const {
|
|
2
|
+
DEFAULT_SLIDE_MODE,
|
|
3
|
+
getSlideModeConfig,
|
|
4
|
+
} = require('./slide-mode.cjs');
|
|
5
|
+
|
|
6
|
+
const RESOLUTION_HEIGHTS = Object.freeze({
|
|
7
|
+
'720p': 720,
|
|
8
|
+
'1080p': 1080,
|
|
9
|
+
'1440p': 1440,
|
|
10
|
+
'2160p': 2160,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const RESOLUTION_ALIASES = Object.freeze({
|
|
14
|
+
'4k': '2160p',
|
|
15
|
+
uhd: '2160p',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function getResolutionChoices() {
|
|
19
|
+
return Object.keys(RESOLUTION_HEIGHTS);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function normalizeResolutionPreset(value, options = {}) {
|
|
23
|
+
const { allowEmpty = true } = options;
|
|
24
|
+
|
|
25
|
+
if (typeof value !== 'string') {
|
|
26
|
+
if (allowEmpty) {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`--resolution must be one of: ${getResolutionChoices().join(', ')}, 4k`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const trimmed = value.trim().toLowerCase();
|
|
33
|
+
if (trimmed === '') {
|
|
34
|
+
if (allowEmpty) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`--resolution must be one of: ${getResolutionChoices().join(', ')}, 4k`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const normalized = RESOLUTION_ALIASES[trimmed] || trimmed;
|
|
41
|
+
if (!RESOLUTION_HEIGHTS[normalized]) {
|
|
42
|
+
throw new Error(`Unknown resolution "${value}". Expected one of: ${getResolutionChoices().join(', ')}, 4k`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return normalized;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getResolutionSize(value, slideMode = DEFAULT_SLIDE_MODE) {
|
|
49
|
+
const normalized = normalizeResolutionPreset(value);
|
|
50
|
+
if (!normalized) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const height = RESOLUTION_HEIGHTS[normalized];
|
|
55
|
+
const { framePx } = getSlideModeConfig(slideMode);
|
|
56
|
+
const aspectRatio = framePx.width / framePx.height;
|
|
57
|
+
return {
|
|
58
|
+
width: Math.round(height * aspectRatio),
|
|
59
|
+
height,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
RESOLUTION_PRESETS: RESOLUTION_HEIGHTS,
|
|
65
|
+
getResolutionChoices,
|
|
66
|
+
getResolutionSize,
|
|
67
|
+
normalizeResolutionPreset,
|
|
68
|
+
};
|
package/src/figma.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
import { basename, dirname, extname, join, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const {
|
|
7
|
+
DEFAULT_SLIDE_MODE,
|
|
8
|
+
getSlideModeConfig,
|
|
9
|
+
} = require('./slide-mode.cjs');
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_FIGMA_SUFFIX = '-figma.pptx';
|
|
12
|
+
export const SLIDE_FILE_PATTERN = /^slide-.*\.html$/i;
|
|
13
|
+
export const FIGMA_EXPORT_LAYOUT_NAME = 'SLIDES_GRAB_STANDARD';
|
|
14
|
+
export const SLIDE_WIDTH_INCHES = 10;
|
|
15
|
+
export const SLIDE_HEIGHT_INCHES = 5.625;
|
|
16
|
+
|
|
17
|
+
export function buildDefaultFigmaOutput(slidesDir) {
|
|
18
|
+
const absoluteSlidesDir = resolve(slidesDir);
|
|
19
|
+
const deckName = basename(absoluteSlidesDir);
|
|
20
|
+
const parentDir = dirname(absoluteSlidesDir);
|
|
21
|
+
return join(parentDir, `${deckName}${DEFAULT_FIGMA_SUFFIX}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function normalizeFigmaOutput(slidesDir, output) {
|
|
25
|
+
if (typeof output === 'string' && output.trim() !== '') {
|
|
26
|
+
const trimmed = output.trim();
|
|
27
|
+
return extname(trimmed).toLowerCase() === '.pptx' ? trimmed : `${trimmed}.pptx`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return buildDefaultFigmaOutput(slidesDir);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getFigmaImportCaveats() {
|
|
34
|
+
return [
|
|
35
|
+
'Figma export is experimental / unstable. Figma imports PPTX best-effort, and complex layouts, shadows, and grouped elements can shift or flatten.',
|
|
36
|
+
'Fonts are resolved inside Figma. If Pretendard is unavailable there, expect substitution and reflow.',
|
|
37
|
+
'Import is one-way. Re-importing creates a new Figma Slides file instead of updating the existing one.',
|
|
38
|
+
'Review every imported slide, especially chart-heavy slides and text near slide edges.',
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getFigmaManualImportInstructions() {
|
|
43
|
+
return 'Figma Slides -> Import -> select the generated .pptx file.';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function configureFigmaExportPresentation(pres, slideMode = DEFAULT_SLIDE_MODE) {
|
|
47
|
+
const { figmaSizeIn } = getSlideModeConfig(slideMode);
|
|
48
|
+
pres.defineLayout({
|
|
49
|
+
name: FIGMA_EXPORT_LAYOUT_NAME,
|
|
50
|
+
width: figmaSizeIn.width,
|
|
51
|
+
height: figmaSizeIn.height,
|
|
52
|
+
});
|
|
53
|
+
pres.layout = FIGMA_EXPORT_LAYOUT_NAME;
|
|
54
|
+
return pres;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function ensureOutputDirectory(outputFile) {
|
|
58
|
+
await mkdir(dirname(resolve(outputFile)), { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function toSlideOrder(fileName) {
|
|
62
|
+
const match = fileName.match(/\d+/);
|
|
63
|
+
return match ? Number.parseInt(match[0], 10) : Number.POSITIVE_INFINITY;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function sortFigmaSlideFiles(a, b) {
|
|
67
|
+
const orderA = toSlideOrder(a);
|
|
68
|
+
const orderB = toSlideOrder(b);
|
|
69
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
70
|
+
return a.localeCompare(b);
|
|
71
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const PX_PER_IN = 96;
|
|
2
|
+
const EMU_PER_IN = 914400;
|
|
3
|
+
|
|
4
|
+
function validateDimensions(bodyDimensions, pres, options = {}) {
|
|
5
|
+
const errors = [];
|
|
6
|
+
const widthInches = bodyDimensions.width / PX_PER_IN;
|
|
7
|
+
const heightInches = bodyDimensions.height / PX_PER_IN;
|
|
8
|
+
const { fitToLayout = false } = options;
|
|
9
|
+
|
|
10
|
+
if (!pres.presLayout) return errors;
|
|
11
|
+
|
|
12
|
+
const layoutWidth = pres.presLayout.width / EMU_PER_IN;
|
|
13
|
+
const layoutHeight = pres.presLayout.height / EMU_PER_IN;
|
|
14
|
+
|
|
15
|
+
if (fitToLayout) {
|
|
16
|
+
const sourceAspectRatio = widthInches / heightInches;
|
|
17
|
+
const layoutAspectRatio = layoutWidth / layoutHeight;
|
|
18
|
+
if (Math.abs(sourceAspectRatio - layoutAspectRatio) > 0.01) {
|
|
19
|
+
errors.push(
|
|
20
|
+
`HTML aspect ratio (${widthInches.toFixed(1)}" × ${heightInches.toFixed(1)}") ` +
|
|
21
|
+
`doesn't match presentation layout (${layoutWidth.toFixed(1)}" × ${layoutHeight.toFixed(1)}")`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return errors;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (Math.abs(layoutWidth - widthInches) > 0.1 || Math.abs(layoutHeight - heightInches) > 0.1) {
|
|
28
|
+
errors.push(
|
|
29
|
+
`HTML dimensions (${widthInches.toFixed(1)}" × ${heightInches.toFixed(1)}") ` +
|
|
30
|
+
`don't match presentation layout (${layoutWidth.toFixed(1)}" × ${layoutHeight.toFixed(1)}")`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return errors;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getLayoutScale(bodyDimensions, pres) {
|
|
37
|
+
if (!pres.presLayout) {
|
|
38
|
+
return { x: 1, y: 1, point: 1 };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const layoutWidth = pres.presLayout.width / EMU_PER_IN;
|
|
42
|
+
const layoutHeight = pres.presLayout.height / EMU_PER_IN;
|
|
43
|
+
const sourceWidth = bodyDimensions.width / PX_PER_IN;
|
|
44
|
+
const sourceHeight = bodyDimensions.height / PX_PER_IN;
|
|
45
|
+
const x = layoutWidth / sourceWidth;
|
|
46
|
+
const y = layoutHeight / sourceHeight;
|
|
47
|
+
|
|
48
|
+
return { x, y, point: (x + y) / 2 };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scaleTextRun(run, pointScale) {
|
|
52
|
+
if (!run || !run.options) return;
|
|
53
|
+
if (Number.isFinite(run.options.fontSize)) run.options.fontSize *= pointScale;
|
|
54
|
+
if (run.options.bullet && Number.isFinite(run.options.bullet.indent)) {
|
|
55
|
+
run.options.bullet.indent *= pointScale;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function scaleSlideData(slideData, scale) {
|
|
60
|
+
if (!slideData || (Math.abs(scale.x - 1) < 0.001 && Math.abs(scale.y - 1) < 0.001)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const placeholder of slideData.placeholders || []) {
|
|
65
|
+
placeholder.x *= scale.x;
|
|
66
|
+
placeholder.y *= scale.y;
|
|
67
|
+
placeholder.w *= scale.x;
|
|
68
|
+
placeholder.h *= scale.y;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const element of slideData.elements || []) {
|
|
72
|
+
if (element.position) {
|
|
73
|
+
element.position.x *= scale.x;
|
|
74
|
+
element.position.y *= scale.y;
|
|
75
|
+
element.position.w *= scale.x;
|
|
76
|
+
element.position.h *= scale.y;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (element.type === 'line') {
|
|
80
|
+
element.x1 *= scale.x;
|
|
81
|
+
element.x2 *= scale.x;
|
|
82
|
+
element.y1 *= scale.y;
|
|
83
|
+
element.y2 *= scale.y;
|
|
84
|
+
element.width *= scale.point;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (element.style) {
|
|
88
|
+
for (const key of ['fontSize', 'lineSpacing', 'paraSpaceBefore', 'paraSpaceAfter']) {
|
|
89
|
+
if (Number.isFinite(element.style[key])) element.style[key] *= scale.point;
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(element.style.margin)) {
|
|
92
|
+
element.style.margin = element.style.margin.map((value) => value * scale.point);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (element.shape) {
|
|
97
|
+
if (Number.isFinite(element.shape.rectRadius)) element.shape.rectRadius *= scale.point;
|
|
98
|
+
if (element.shape.line && Number.isFinite(element.shape.line.width)) {
|
|
99
|
+
element.shape.line.width *= scale.point;
|
|
100
|
+
}
|
|
101
|
+
if (element.shape.shadow) {
|
|
102
|
+
if (Number.isFinite(element.shape.shadow.blur)) element.shape.shadow.blur *= scale.point;
|
|
103
|
+
if (Number.isFinite(element.shape.shadow.offset)) element.shape.shadow.offset *= scale.point;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Array.isArray(element.text)) {
|
|
108
|
+
for (const run of element.text) scaleTextRun(run, scale.point);
|
|
109
|
+
}
|
|
110
|
+
if (Array.isArray(element.items)) {
|
|
111
|
+
for (const run of element.items) scaleTextRun(run, scale.point);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
getLayoutScale,
|
|
118
|
+
scaleSlideData,
|
|
119
|
+
validateDimensions,
|
|
120
|
+
};
|