omniscript-converters
Version:
Format converters for OmniScript Format (OSF) - Convert to/from DOCX, PPTX, XLSX, PDF
362 lines • 13.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PPTXConverter = void 0;
const pptxgenjs_1 = __importDefault(require("pptxgenjs"));
class PPTXConverter {
getSupportedFormats() {
return ['pptx'];
}
async convert(document, options = {}) {
const pptx = new pptxgenjs_1.default();
// Set presentation metadata
this.setPresentationMetadata(pptx, document, options);
// Configure theme and layout
this.configureTheme(pptx, options.theme || 'default');
// Process document blocks
await this.generateSlides(pptx, document, options);
const blob = await pptx.write();
const arrayBuffer = await blob.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
return {
buffer,
mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
extension: 'pptx'
};
}
setPresentationMetadata(pptx, document, options) {
const meta = this.getMetadata(document);
pptx.author = String(meta.author) || 'OmniScript OSF';
pptx.company = 'Generated by OmniScript';
pptx.title = String(meta.title) || 'OSF Presentation';
pptx.subject = 'Generated from OSF document';
}
configureTheme(pptx, theme) {
const themeConfig = this.getThemeConfiguration(theme);
pptx.defineLayout({
name: 'OSF_LAYOUT',
width: 10,
height: 7.5
});
// Note: Master slides removed for compatibility with pptxgenjs v4
}
async generateSlides(pptx, document, options) {
let hasCreatedTitleSlide = false;
for (const block of document.blocks) {
switch (block.type) {
case 'meta':
if (!hasCreatedTitleSlide && options.includeMetadata !== false) {
this.createTitleSlide(pptx, block, options);
hasCreatedTitleSlide = true;
}
break;
case 'doc':
this.createDocSlides(pptx, block, options);
break;
case 'slide':
this.createSlideFromBlock(pptx, block, options);
break;
case 'sheet':
this.createSheetSlide(pptx, block, options);
break;
}
}
}
createTitleSlide(pptx, meta, options) {
const slide = pptx.addSlide();
const theme = this.getThemeConfiguration(options.theme || 'default');
if (meta.props.title) {
slide.addText(String(meta.props.title), {
x: 1, y: 2, w: 8, h: 1.5,
align: 'center',
fontSize: 44,
bold: true,
color: theme.primary,
fontFace: theme.titleFont
});
}
const subtitle = [];
if (meta.props.author)
subtitle.push(`By: ${String(meta.props.author)}`);
if (meta.props.date)
subtitle.push(String(meta.props.date));
if (subtitle.length > 0) {
slide.addText(subtitle.join(' | '), {
x: 1, y: 4, w: 8, h: 0.8,
align: 'center',
fontSize: 20,
color: theme.secondary,
fontFace: theme.bodyFont
});
}
}
createDocSlides(pptx, doc, options) {
const content = doc.content || '';
const theme = this.getThemeConfiguration(options.theme || 'default');
// Split content into logical slides based on headings
const sections = this.splitContentIntoSections(content);
for (const section of sections) {
const slide = pptx.addSlide();
if (section.title) {
slide.addText(section.title, {
x: 0.5, y: 0.5, w: 9, h: 1,
fontSize: 32,
bold: true,
color: theme.primary,
fontFace: theme.titleFont
});
}
if (section.content.length > 0) {
const contentText = this.formatContentForSlide(section.content);
slide.addText(contentText, {
x: 0.5, y: section.title ? 1.8 : 0.5,
w: 9, h: section.title ? 4.7 : 6.2,
fontSize: 18,
color: theme.text,
fontFace: theme.bodyFont,
valign: 'top'
});
}
}
}
createSlideFromBlock(pptx, slideBlock, options) {
const slide = pptx.addSlide();
const theme = this.getThemeConfiguration(options.theme || 'default');
// Add slide title
if (slideBlock.title) {
slide.addText(slideBlock.title, {
x: 0.5, y: 0.5, w: 9, h: 1,
fontSize: 32,
bold: true,
color: theme.primary,
fontFace: theme.titleFont
});
}
// Add slide content
if (slideBlock.content) {
let yPosition = slideBlock.title ? 1.8 : 0.5;
for (const contentBlock of slideBlock.content) {
if (contentBlock.type === 'unordered_list') {
const bullets = contentBlock.items.map(item => {
const itemText = item.content.map(this.extractText).join('');
return { text: itemText, options: { bullet: true } };
});
slide.addText(bullets, {
x: 0.5, y: yPosition, w: 9, h: 4.5,
fontSize: 20,
color: theme.text,
fontFace: theme.bodyFont,
valign: 'top'
});
yPosition += 4.5;
}
else if (contentBlock.type === 'paragraph') {
const paragraphText = contentBlock.content.map(this.extractText).join('');
slide.addText(paragraphText, {
x: 0.5, y: yPosition, w: 9, h: 1.5,
fontSize: 18,
color: theme.text,
fontFace: theme.bodyFont,
valign: 'top'
});
yPosition += 1.8;
}
}
}
}
createSheetSlide(pptx, sheet, options) {
const slide = pptx.addSlide();
const theme = this.getThemeConfiguration(options.theme || 'default');
// Add sheet title
if (sheet.name) {
slide.addText(sheet.name, {
x: 0.5, y: 0.5, w: 9, h: 1,
fontSize: 28,
bold: true,
color: theme.primary,
fontFace: theme.titleFont
});
}
if (sheet.data) {
// Prepare table data
const tableData = this.prepareTableData(sheet);
if (tableData.length > 0) {
slide.addTable(tableData, {
x: 0.5,
y: sheet.name ? 1.8 : 0.5,
w: 9,
h: sheet.name ? 4.7 : 6.2,
fontSize: 14,
color: theme.text,
fontFace: theme.bodyFont,
border: { pt: 1, color: theme.border },
fill: { color: theme.tableBackground }
});
}
}
}
prepareTableData(sheet) {
const tableData = [];
// Add header row if columns are defined
if (sheet.cols) {
const cols = Array.isArray(sheet.cols)
? sheet.cols
: String(sheet.cols).replace(/[[\]]/g, '').split(',').map(s => s.trim());
const headerRow = cols.map(col => ({
text: col,
options: { bold: true, fill: { color: 'E8E8E8' } }
}));
tableData.push(headerRow);
}
if (sheet.data) {
// Calculate table dimensions
const coords = Object.keys(sheet.data).map(k => k.split(',').map(Number));
const maxRow = Math.max(...coords.map(c => c[0]));
const maxCol = Math.max(...coords.map(c => c[1]));
// Add data rows
for (let r = 1; r <= maxRow; r++) {
const row = [];
for (let c = 1; c <= maxCol; c++) {
const key = `${r},${c}`;
const value = sheet.data[key] || '';
row.push({ text: String(value) });
}
tableData.push(row);
}
}
return tableData;
}
splitContentIntoSections(content) {
const lines = content.split('\n');
const sections = [];
let currentSection = { content: [] };
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith('# ')) {
// New section with heading
if (currentSection.title || currentSection.content.length > 0) {
sections.push(currentSection);
}
currentSection = {
title: trimmed.substring(2),
content: []
};
}
else if (trimmed.startsWith('## ')) {
// Subsection - also creates new slide
if (currentSection.title || currentSection.content.length > 0) {
sections.push(currentSection);
}
currentSection = {
title: trimmed.substring(3),
content: []
};
}
else if (trimmed !== '') {
currentSection.content.push(trimmed);
}
}
// Add the last section
if (currentSection.title || currentSection.content.length > 0) {
sections.push(currentSection);
}
return sections.length > 0 ? sections : [{ content: [content] }];
}
formatContentForSlide(contentLines) {
const formattedContent = [];
for (const line of contentLines) {
if (line.startsWith('- ') || line.startsWith('* ')) {
// Bullet point
formattedContent.push({
text: line.substring(2),
options: { bullet: true }
});
}
else {
// Regular paragraph
formattedContent.push({
text: line,
options: { paragraph: true }
});
}
}
return formattedContent;
}
extractText(run) {
if (typeof run === 'string')
return run;
if (run.type === 'link')
return run.text;
if (run.type === 'image')
return run.alt || '';
if (run.text)
return run.text;
return '';
}
getMetadata(document) {
for (const block of document.blocks) {
if (block.type === 'meta') {
const meta = block;
return {
title: meta.props.title ? String(meta.props.title) : undefined,
author: meta.props.author ? String(meta.props.author) : undefined,
date: meta.props.date ? String(meta.props.date) : undefined
};
}
}
return {};
}
getThemeConfiguration(theme) {
const themes = {
default: {
primary: '2C3E50',
secondary: '7F8C8D',
accent: '3498DB',
text: '2C3E50',
background: 'FFFFFF',
border: 'DDDDDD',
tableBackground: 'F8F9FA',
titleFont: 'Calibri',
bodyFont: 'Calibri'
},
corporate: {
primary: '1A365D',
secondary: '4A5568',
accent: '2B6CB0',
text: '2D3748',
background: 'FFFFFF',
border: '2B6CB0',
tableBackground: 'EBF4FF',
titleFont: 'Arial',
bodyFont: 'Arial'
},
academic: {
primary: '2D3748',
secondary: '4A5568',
accent: '4A5568',
text: '1A202C',
background: 'FFFFFF',
border: '4A5568',
tableBackground: 'F7FAFC',
titleFont: 'Times New Roman',
bodyFont: 'Times New Roman'
},
modern: {
primary: '6366F1',
secondary: '8B5CF6',
accent: '06B6D4',
text: '1F2937',
background: 'FFFFFF',
border: 'E5E7EB',
tableBackground: 'F9FAFB',
titleFont: 'Segoe UI',
bodyFont: 'Segoe UI'
}
};
return themes[theme] || themes.default;
}
}
exports.PPTXConverter = PPTXConverter;
//# sourceMappingURL=pptx.js.map