Source: server/src/generatePresentation.js

/**
 * @module server/generatePresentation
 */

const getPngDimensions = require('./utils/getPngDimensions')
const elementToImageAsync = require('./utils/elementToImage')
const getThemeFunc = require('./themesManager').getThemeFunc

/**
 * generates a document presentation
 * @param documentMeta document meta object returned by {@link getDocumentAsync}
 * @returns {Promise} pptx file encoded to base64 string
 */
module.exports = function generatePresentationAsync (documentMeta) {
  return new Promise((resolve, reject) => {
    // hack to fix a bug in pptxGenJs lib that prevents multiple presentations in node
    delete require.cache[require.resolve('pptxgenjs')]

    let pptx = require('pptxgenjs')
    pptx.setLayout({name: 'NIELSEN_PAGE_SIZE', width: 10, height: 5.6})

    let allPagesPromises = documentMeta.pages.map(
      Page => handlePageAsync(pptx.addNewSlide(), documentMeta.data, Page)
    )
    Promise.all(allPagesPromises)
      .then(
        () => {
          pptx.save('http', data => {
            let pptxAsBase64 = Buffer.from(data, 'binary').toString('base64')
            resolve(pptxAsBase64)
          })
        }
      )
      .catch(err => reject(err))
  })
}

/**
 * handle specific page creation
 * @param pptx presentation instance
 * @param data data required for the document
 * @param page {Page} page class to create
 * @returns {Promise.<T>} Promise would be resolved when page creation is completed
 */
function handlePageAsync (slide, data, Page) {
  return new Promise((resolve, reject) => {
    try {
      let page = new Page(data)
      let {pageOptions} = page

      if (pageOptions.title) {
        slide.addText(pageOptions.title, {
          x: 0.7,
          y: 0.6,
          font_size: 30,
          font_face: 'Arial (Headings)',
          color: '000000',
          bold: true
        })
      }

      if (pageOptions.bodyText) {
        slide.addText(pageOptions.bodyText, {
          x: 0.7,
          y: 1.1,
          font_size: 18,
          font_face: 'Arial (Headings)',
          color: '000000'
        })
      }

      if (!pageOptions.skipPageNumber) {
        slide.slideNumber({x: '95%', y: '94%', fontFace: 'Courier', fontSize: 10, color: '000000'})
      }

      let themeFunc = getThemeFunc(pageOptions.theme)
      themeFunc(slide)

      if (page.getCustomContent) { page.getCustomContent(slide) }
      if (page.getMainContent) {
        let contentElement = page.getMainContent()
        elementToImageAsync(contentElement)
          .then(contentAsBase64Image => {
            let dimensions = getPngDimensions(contentAsBase64Image)
            slide.addImage({
              x: 2,
              y: 1.5,
              w: dimensions.width,
              h: dimensions.height,
              data: `image/png;base64,${contentAsBase64Image}`
            })
            resolve()
          })
      } else {
        resolve()
      }
    } catch (err) {
      console.error(err)
      reject(err)
    }
  })
}