- .agent/, .claude/, .vscode/ 설정 파일 - design/ 디자인 리소스 - reports/, research/ 분석 문서 - testcase/ 테스트 케이스 문서 - db_sync_chandj.bat, sam.code-workspace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
118 lines
3.8 KiB
JavaScript
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);
|
|
});
|