Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An error occurred while processing /ppt/slides/slide4.xml #130

Open
igor-sobolev opened this issue Nov 15, 2024 · 9 comments
Open

An error occurred while processing /ppt/slides/slide4.xml #130

igor-sobolev opened this issue Nov 15, 2024 · 9 comments

Comments

@igor-sobolev
Copy link

Background: need to append PptxGenJS buffer presentation into the main one, for some reasons just appending slides cut off last 2 slides, so was trying to combine .loadRoot and .load for getting root template but getting empty array for pres.getTemplate('myTemplate.pptx').getAllSlideNumbers(). There's an unknown issue with reading slides when reading presentation info (one example below):

An error occurred while processing /ppt/slides/slide4.xml: [Error: ENOENT: no such file or directory, open '/home/USER/workspace/PROJECT/utils/csvs/tmp/templates/presentation.pptx/ppt//ppt/slides/slide4.xml'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/home/USER/workspace/PROJECT/utils/csvs/tmp/templates/presentation.pptx/ppt//ppt/slides/slide4.xml'
}

I can see it's extracted into temp folder I use, but I don't see anywhere ppt// mentioned.
Seems like I have troubles with a prefix of ppt// when accessing presentation with await pres.getInfo(). The error persists both for jszip and fs modes. I could skip that and get at least some info with

if (file.includes('ppt//')) { file = file.replace(/ppt\/\//g, '')}
if (file.includes('ppt/media//')) { file = file.replace(/ppt\/media\/\//g, '')}

in helper/archive/archive-fs.js read() function, but it failed in relations later.

Any ideas/suggestions what could be wrong?

OS: Linux Ubuntu
Node: 20.12.2

@singerla
Copy link
Owner

Could you provide some code for me to reproduce this issue? Or will this occur on all PptxGenJS buffers? I've never tried this 😄

@igor-sobolev
Copy link
Author

igor-sobolev commented Nov 18, 2024

const automizer = new Automizer({
  // this is where your template pptx files are coming from:
  templateDir,

  // specify the directory to write your final pptx output files:
  outputDir,

  // turn this to true if you want to generally use
  // Powerpoint's creationIds instead of slide numbers
  // or shape names:
  useCreationIds: false,

  // Always use the original slideMaster and slideLayout of any
  // imported slide:
  autoImportSlideMasters: true,

  // truncate root presentation and start with zero slides
  removeExistingSlides: true,

  // activate `cleanup` to eventually remove unused files:
  cleanup: false,

  // Set a value from 0-9 to specify the zip-compression level.
  // The lower the number, the faster your output file will be ready.
  // Higher compression levels produce smaller files.
  compression: 0,

  // You can enable 'archiveType' and set mode: 'fs'.
  // This will extract all templates and output to disk.
  // It will not improve performance, but it can help debugging:
  // You don't have to manually extract pptx contents, which can
  // be annoying if you need to look inside your files.
  archiveType: {
    mode: 'fs',
    baseDir: `${__dirname}/csvs/tmp`,
    cleanupWorkDir: true,
  },

  // use a callback function to track pptx generation process.
  statusTracker: (status) => {
    console.log(status.info + ' (' + status.share + '%)');
  },
});

const presentationFileName = process.argv[2] || 'Presentation.pptx';
const suggestionsFileName = `${templateDir}/sugesstions.json`;

const categories = [
  'Category 1',
];

const updatePresentation = async (data) => {
  console.log(`Loading file: ${presentationFileName}`);

  // 'binary',
  // const rootTemplate = fs.readFileSync(
  //   path.resolve(`${templateDir}/${presentationFileName}`)
  // );

  let pres = automizer
    .loadRoot(presentationFileName)
    .load(presentationFileName, 'root');

  const presInfo = await pres.getInfo();
  const rootSlides = presInfo.slidesByTemplate('root');
  console.log('@@@@@@@@@@@@@@@', rootSlides) // [ ]

  rootSlides.forEach((_, index) => {
    // add each slide from root template
    pres.addSlide('root', index + 1); // tried to add by index, but no luck here as well
  });

  console.log('Getting suggestions slides...');

  const suggestionPresentations = await Promise.all(categories.map((category) => {
    const suggestionsData = data
      .filter((s) => {
        return s.category === category && !!s.suggestions
      });

    return generateCategorySuggestions(category, suggestionsData);
  }));

  // preload bufferized category slides as templates
  // suggestionPresentations.forEach(({ category, buffer }) => {
  //   pres.load(buffer, category);
  // });

  // suggestionPresentations.forEach(async ({ category }) => {
  //   const slideNumbers = await pres.getTemplate(category).getAllSlideNumbers();
  //   for (let slideNumber of slideNumbers) {
  //     // add each slide from category template
  //     pres.addSlide(category, slideNumber);
  //   }
  // });

  // const finalJSZip = await pres.getJSZip();
  // const buffer = await finalJSZip.generateAsync({ type: 'nodebuffer' });
  // fs.writeFileSync(`${outputDir}/${presentationFileName}`, buffer);

  // @TODO: original save
  await pres.write(presentationFileName).then((summary) => {
    console.log(summary);
  });
  console.log(`Saved file: ${presentationFileName} to ${outputDir}`);
  console.log(`Done.`);
  console.log(`==================================================`);
}

@igor-sobolev
Copy link
Author

@singerla hi, was the code sample helpful?

@singerla
Copy link
Owner

Hi @igor-sobolev, I was playing around with loading pptxGenJs generated files, but could not reproduce the error message. It's clear to me that /ppt//ppt/ is wrong, but I can't imagine where this is coming from.

My current approach:

  • Create a presentation with 10+ slides in pptxGenJs
  • Load this presentation as root and as template
  • Load info about the pptxGenJs-generated pptx
  • Add all slides
  • Add some more fancy stuff

But (un?)fortunately everything works as expected.

import Automizer from './index';
import pptxgen from 'pptxgenjs';

const run = async () => {
  const outputDir = `${__dirname}/../__tests__/pptx-output`;
  const templateDir = `${__dirname}/../__tests__/pptx-templates`;

  let presPptxGen = new pptxgen();

  let slide = presPptxGen.addSlide();
  let textboxText = 'Hello World from PptxGenJS!';
  let textboxOpts: pptxgen.TextPropsOptions = {
    x: 1,
    y: 1,
    color: '363636',
    objectName: 'Text 1',
  };
  slide.addText(textboxText, textboxOpts);

  for (let i = 2; i <= 10; i++) {
    presPptxGen.addSlide().addImage({
      path: 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg',
      objectName: 'Image ' + i,
      x: 1,
      y: 2,
    });
  }

  await presPptxGen.writeFile({
    fileName: templateDir + '/presPptxGenTmp.pptx',
  });

  const automizer = new Automizer({
    templateDir,
    outputDir,
    removeExistingSlides: true,
    archiveType: {
      mode: 'fs',
      baseDir: `${__dirname}/tmp`,
      cleanupWorkDir: true,
    },
  });

  let pres = automizer
    .loadRoot(`presPptxGenTmp.pptx`)
    .load(`presPptxGenTmp.pptx`, 'root')
    .load(`SlideWithShapes.pptx`, 'shapes')
    .load(`EmptySlide.pptx`, 'emptySlide');

  const presInfo = await pres.getInfo();
  const rootSlides = presInfo.slidesByTemplate('root');
  console.log('@@@@@@@@@@@@@@@', rootSlides); // [ ]

  rootSlides.forEach((_, index) => {
    // add each slide from root template
    pres.addSlide('root', _.number); // tried to add by index, but no luck here as well
  });

  pres.addSlide('shapes', 1, (slide) => {
    slide.addElement('root', 1, 'Text 1');
    slide.addElement('root', 1, 'Image 1');

    pres.write(`myOutputPresentation.pptx`).then((summary) => {
      console.log(summary);
    });
  });
};

run().catch((error) => {
  console.error(error);
});

Where is this double ppt/ coming from in your case?

Have a great week anyway! 😄

@igor-sobolev
Copy link
Author

Hey, thanks for a reply, double ppt/ coming from at the point it's extracted either by JSZip or by fs mode, but there's no such folder in presentation archive

@singerla
Copy link
Owner

It's hard to reproduce without the underlying pptx files generated by pptxGenJs. Every combination that I am testing with v0.6 works without double ppt/. Is it possible to provide some mock templates? Do they contain something special?

I was trying this code to produce my own files:

import Automizer, { CmToDxa, modify } from './index';
import pptxgen from 'pptxgenjs';

const run = async () => {
  const outputDir = `${__dirname}/../__tests__/pptx-output`;
  const templateDir = `${__dirname}/../__tests__/pptx-templates`;

  let presPptxGen = new pptxgen();
  for (let i = 2; i <= 10; i++) {
    presPptxGen.addSlide().addImage({
      path: 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg',
      objectName: 'Image ' + i,
      x: 1,
      y: 2,
    });
  }

  await presPptxGen.writeFile({
    fileName: templateDir + '/presPptxGenTmp.pptx',
  });
  await presPptxGen.writeFile({
    fileName: templateDir + '/presPptxGenTmp2.pptx',
  });

  const automizer = new Automizer({
    templateDir,
    outputDir,
    removeExistingSlides: true,
    autoImportSlideMasters: true,
    // archiveType: {
    //   mode: 'fs',
    //   baseDir: `${__dirname}/tmp`,
    //   cleanupWorkDir: false,
    // },
  });

  let pres = automizer
    .loadRoot(`presPptxGenTmp.pptx`)
    .load(`presPptxGenTmp.pptx`, 'root');

  const presInfo = await pres.getInfo();
  const rootSlides = presInfo.slidesByTemplate('root');
  console.log('@@@@@@@@@@@@@@@', rootSlides); // [ ]

  rootSlides.forEach((_, index) => {
    // add each slide from root template
    pres.addSlide('root', _.number); // tried to add by index, but no luck here as well
  });

  const suggestionPresentations = [{ category: `presPptxGenTmp2.pptx` }];

  for (const { category } of suggestionPresentations) {
    pres.load(category);
    const slideNumbers = await pres.getTemplate(category).getAllSlideNumbers();

    for (let slideNumber of slideNumbers) {
      // add each slide from category template
      pres.addSlide(category, slideNumber);
    }
  }

  pres.load(`presPptxGenTmp2.pptx`, 'presPptxGenTmp2');

  pres.addSlide('presPptxGenTmp2', 3, (slide) => {
    slide.modifyElement('Image 4', modify.updatePosition({ x: CmToDxa(5) }));
  });

  pres.write(`myOutputPresentation.pptx`).then((summary) => {
    console.log(summary);
  });
};

run().catch((error) => {
  console.error(error);
});

@igor-sobolev
Copy link
Author

Seems the previous issue was coming from @xmldom/xmldom on [email protected], so it seems that something's changed from the time and version now is changed, but I get a different error now 🥴

ParseError: processing instruction at position 1 is an xml declaration which is only at the start of the document
    at DOMHandler.fatalError (/home/[email protected]/workspace/health-check-survey/node_modules/@xmldom/xmldom/lib/dom-parser.js:483:9)

Will try to investigate whether there's something with my presentations

@singerla
Copy link
Owner

This error seems to point to a problem with the prepended XML-Tag <?xml version="1.0" .... In pptx-automizer library we only have two XML files as a fallback to assert datalabels or borders (see src/helper/xml). It is very likely this is caused by one of your templates.

@singerla
Copy link
Owner

@igor-sobolev could you find a solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants