Files
sam-hotfix/research/flow-chart/convert-to-pptx.js
김보곤 d86b5851d0 chore: 프로젝트 설정 및 문서 파일 추가
- .agent/, .claude/, .vscode/ 설정 파일
- design/ 디자인 리소스
- reports/, research/ 분석 문서
- testcase/ 테스트 케이스 문서
- db_sync_chandj.bat, sam.code-workspace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 19:51:43 +09:00

118 lines
3.8 KiB
JavaScript

/**
* SAM_ERP Storyboard HTML to PPTX Converter (Hybrid Approach)
*
* - Simple slides: Extracted as editable elements using html2pptx.js
* - Complex slides (tables, etc.): Captured as high-resolution images
*/
const PptxGenJS = require('pptxgenjs');
const html2pptx = require('./html2pptx.js');
const { chromium } = require('playwright');
const path = require('path');
const fs = require('fs');
async function convert() {
console.log('SAM_ERP Storyboard HTML to PPTX Conversion (Hybrid)');
console.log('====================================================\n');
// Create new presentation
const pres = new PptxGenJS();
// Set presentation properties (720pt x 405pt = 10" x 5.625")
pres.defineLayout({ name: 'CUSTOM', width: 10, height: 5.625 });
pres.layout = 'CUSTOM';
pres.title = 'SAM_ERP Storyboard';
pres.author = 'CODE-BRIDGE X';
pres.subject = 'SAM ERP System Storyboard';
// Get all HTML slide files
const slidesDir = path.join(__dirname, 'slides');
const imagesDir = path.join(__dirname, 'slide-images');
if (!fs.existsSync(imagesDir)) {
fs.mkdirSync(imagesDir, { recursive: true });
}
const slideFiles = fs.readdirSync(slidesDir)
.filter(f => f.endsWith('.html'))
.sort();
console.log(`Found ${slideFiles.length} slides to convert:\n`);
// Launch browser for fallback screenshots
const browser = await chromium.launch();
const context = await browser.newContext({
viewport: { width: 960, height: 540 }
});
const page = await context.newPage();
let editableCount = 0;
let imageCount = 0;
// Convert each slide
for (let i = 0; i < slideFiles.length; i++) {
const slideFile = slideFiles[i];
const slidePath = path.join(slidesDir, slideFile);
const imagePath = path.join(imagesDir, `slide-${String(i + 1).padStart(2, '0')}.png`);
console.log(` [${i + 1}/${slideFiles.length}] ${slideFile}`);
try {
// Try editable conversion first
await html2pptx(slidePath, pres);
console.log(` ✓ Editable (elements extracted)`);
editableCount++;
} catch (err) {
// Fallback to image capture
console.log(` → Falling back to image capture...`);
try {
await page.goto(`file:///${slidePath.replace(/\\/g, '/')}`);
await page.waitForLoadState('networkidle');
await page.screenshot({
path: imagePath,
fullPage: false,
clip: { x: 0, y: 0, width: 960, height: 540 }
});
const slide = pres.addSlide();
slide.addImage({
path: imagePath,
x: 0,
y: 0,
w: 10,
h: 5.625
});
console.log(` ✓ Image (screenshot captured)`);
imageCount++;
} catch (imgErr) {
console.error(` ✗ Failed: ${imgErr.message}`);
}
}
}
await browser.close();
// Save to pptx folder
const outputDir = path.join(__dirname, 'pptx');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const outputPath = path.join(outputDir, 'SAM_ERP_Storyboard_Hybrid.pptx');
console.log('\nSaving presentation...');
await pres.writeFile({ fileName: outputPath });
console.log(`\n✓ Successfully created: ${outputPath}`);
console.log(` Total slides: ${slideFiles.length}`);
console.log(` Editable slides: ${editableCount}`);
console.log(` Image slides: ${imageCount}`);
}
convert().catch(err => {
console.error('Conversion failed:', err);
process.exit(1);
});