Skip to content

Commit fe3421e

Browse files
committed
test(generate): text, charts, images with pptxgenjs #60
1 parent 1baa407 commit fe3421e

File tree

13 files changed

+388
-79
lines changed

13 files changed

+388
-79
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# pptx-automizer: A Powerful .pptx Modifier for Node.js
22

3-
`pptx-automizer` is a Node.js-based PowerPoint (.pptx) generator that automates the manipulation of existing .pptx files. With `pptx-automizer`, you can import your library of .pptx templates, merge templates, and customize slide content. `pptx-automizer` will not write files from scratch, but edit and merge existing pptx files. You can style template slides within PowerPoint, and these templates will be seamlessly integrated into the output presentation. Most of the content can be modified by using callbacks with [xmldom](https://github.com/xmldom/xmldom).
4-
`pptx-automizer` is a Node.js-based PowerPoint (.pptx) generator that automates the manipulation of existing .pptx files. With `pptx-automizer`, you can import your library of .pptx templates, merge templates, and customize slide content. `pptx-automizer` will not write files from scratch, but edit and merge existing pptx files. You can style template slides within PowerPoint, and these templates will be seamlessly integrated into the output presentation. Most of the content can be modified by using callbacks with [xmldom](https://github.com/xmldom/xmldom).
3+
`pptx-automizer` is a Node.js-based PowerPoint (.pptx) generator that automates the manipulation of existing .pptx files. With `pptx-automizer`, you can import your library of .pptx templates, merge templates, and customize slide content. You can style template slides within PowerPoint, and these templates will be seamlessly integrated into the output presentation. Most of the content can be modified by using callbacks with [xmldom](https://github.com/xmldom/xmldom).
4+
5+
If you require to create elements from scratch, `pptx-automizer` wraps around [PptxGenJS](https://github.com/gitbrent/PptxGenJS). Use the powerful syntax of `PptxGenJS` to add dynamic content to your existing .pptx template files.
56

67
`pptx-automizer` is particularly well-suited for users who aim to manage their own library of .pptx template files, making it an ideal choice for those who work with intricate, well-designed customized layouts. With this tool, any existing slide or even a single element can serve as a data-driven template for generating output .pptx files.
78

@@ -478,7 +479,6 @@ Find more examples on image manipulation:
478479

479480
- [Add external image](https://github.com/singerla/pptx-automizer/blob/main/__tests__/add-external-image.test.ts)
480481
- [Modify duotone color overlay for images](https://github.com/singerla/pptx-automizer/blob/main/__tests__/modify-image-duotone.test.ts)
481-
- [Swap image source on a slide master](https://github.com/singerla/pptx-automizer/blob/main/__tests__/modify-master-external-image.test.ts)
482482

483483
## Modify Tables
484484

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import Automizer from '../src/automizer';
2+
import { ChartData, modify } from '../src';
3+
4+
const dataChartAreaLine = [
5+
{
6+
name: 'Actual Sales',
7+
labels: ['Jan', 'Feb', 'Mar'],
8+
values: [1500, 4600, 5156],
9+
},
10+
{
11+
name: 'Projected Sales',
12+
labels: ['Jan', 'Feb', 'Mar'],
13+
values: [1000, 2600, 3456],
14+
},
15+
];
16+
17+
test('generate a chart with pptxgenjs and add it to a template slide', async () => {
18+
const automizer = new Automizer({
19+
templateDir: `${__dirname}/pptx-templates`,
20+
outputDir: `${__dirname}/pptx-output`,
21+
});
22+
23+
const pres = automizer
24+
.loadRoot(`RootTemplate.pptx`)
25+
.load(`EmptySlide.pptx`, 'empty')
26+
.load(`SlideWithCharts.pptx`, 'charts');
27+
28+
pres.addSlide('empty', 1, (slide) => {
29+
// Use pptxgenjs to add generated contents from scratch:
30+
slide.generate((pSlide, objectName, pptxGenJs) => {
31+
pSlide.addChart(pptxGenJs.ChartType.line, dataChartAreaLine, {
32+
x: 1,
33+
y: 1,
34+
w: 8,
35+
h: 4,
36+
objectName,
37+
});
38+
});
39+
});
40+
41+
// Mix the created chart with modified existing chart
42+
pres.addSlide('charts', 2, (slide) => {
43+
slide.modifyElement('ColumnChart', [
44+
modify.setChartData(<ChartData>{
45+
series: [{ label: 'series 1' }, { label: 'series 3' }],
46+
categories: [
47+
{ label: 'cat 2-1', values: [50, 50] },
48+
{ label: 'cat 2-2', values: [14, 50] },
49+
],
50+
}),
51+
]);
52+
});
53+
54+
const result = await pres.write(`generate-pptxgenjs-charts.test.pptx`);
55+
56+
expect(result.charts).toBe(4);
57+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Automizer from '../src/automizer';
2+
import { ChartData, modify } from '../src';
3+
4+
test('insert an image with pptxgenjs on a template slide', async () => {
5+
const automizer = new Automizer({
6+
templateDir: `${__dirname}/pptx-templates`,
7+
outputDir: `${__dirname}/pptx-output`,
8+
});
9+
10+
const pres = automizer
11+
.loadRoot(`RootTemplate.pptx`)
12+
.load(`EmptySlide.pptx`, 'empty');
13+
14+
pres.addSlide('empty', 1, (slide) => {
15+
// Use pptxgenjs to add image from file:
16+
slide.generate((pptxGenJSSlide, objectName) => {
17+
pptxGenJSSlide.addImage({
18+
path: `${__dirname}/images/test.png`,
19+
x: 1,
20+
y: 2,
21+
objectName,
22+
});
23+
});
24+
});
25+
26+
const result = await pres.write(`generate-pptxgenjs-image.test.pptx`);
27+
28+
expect(result.images).toBe(1);
29+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Automizer from '../src/automizer';
2+
import { ChartData, modify } from '../src';
3+
4+
test('insert a textbox with pptxgenjs on a template slide', async () => {
5+
const automizer = new Automizer({
6+
templateDir: `${__dirname}/pptx-templates`,
7+
outputDir: `${__dirname}/pptx-output`,
8+
});
9+
10+
const pres = automizer
11+
.loadRoot(`RootTemplate.pptx`)
12+
.load(`EmptySlide.pptx`, 'empty');
13+
14+
pres.addSlide('empty', 1, (slide) => {
15+
// Use pptxgenjs to add text from scratch:
16+
slide.generate((pptxGenJSSlide, objectName) => {
17+
pptxGenJSSlide.addText('Test', {
18+
x: 1,
19+
y: 1,
20+
color: '363636',
21+
objectName,
22+
});
23+
}, 'custom object name');
24+
});
25+
26+
const result = await pres.write(`generate-pptxgenjs-text.test.pptx`);
27+
28+
expect(result.slides).toBe(2);
29+
});

src/automizer.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,16 +437,12 @@ export default class Automizer implements IPresentationProps {
437437
}
438438

439439
async finalizePresentation() {
440-
await this.rootTemplate.injectPptxGenJS();
441-
442440
await this.writeMasterSlides();
443441
await this.writeSlides();
444442
await this.writeMediaFiles();
445443
await this.normalizePresentation();
446444
await this.applyModifyPresentationCallbacks();
447445

448-
// await this.rootTemplate.cleanupPptxGenJS();
449-
450446
// TODO: refactor content tracker, move this to root template
451447
Tracker.reset();
452448
}
@@ -467,9 +463,11 @@ export default class Automizer implements IPresentationProps {
467463
await this.rootTemplate.countExistingSlides();
468464
this.status.max = this.rootTemplate.slides.length;
469465

466+
await this.rootTemplate.runExternalGenerators();
470467
for (const slide of this.rootTemplate.slides) {
471468
await this.rootTemplate.appendSlide(slide);
472469
}
470+
await this.rootTemplate.cleanupExternalGenerators();
473471

474472
if (this.params.removeExistingSlides) {
475473
await this.rootTemplate.truncate();

src/classes/has-shapes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,6 @@ export default class HasShapes {
750750
*/
751751
async copyRelatedContent(): Promise<void> {
752752
const charts = await Chart.getAllOnSlide(this.sourceArchive, this.relsPath);
753-
vd(charts.length);
754753
for (const chart of charts) {
755754
await new Chart(
756755
{

src/classes/template.ts

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import { ArchiveParams, MediaFile } from '../types/types';
1414
import Automizer from '../automizer';
1515
import { IMaster } from '../interfaces/imaster';
1616
import { ILayout } from '../interfaces/ilayout';
17-
import PptxGenJS from 'pptxgenjs';
18-
import { randomUUID } from 'crypto';
19-
import fs from 'fs';
17+
import { IGenerator } from '../interfaces/igenerator';
18+
import GeneratePptxGenJs from '../helper/generate/generate-pptxgenjs';
2019

2120
export class Template implements ITemplate {
2221
/**
@@ -69,8 +68,7 @@ export class Template implements ITemplate {
6968
mediaFiles: MediaFile[] = [];
7069

7170
automizer: Automizer;
72-
pptxGenJS: PptxGenJS;
73-
pptxGenJSTmpFile: string;
71+
generators: IGenerator[] = [];
7472

7573
constructor(location: string, params: ArchiveParams) {
7674
this.location = location;
@@ -196,54 +194,6 @@ export class Template implements ITemplate {
196194
});
197195
}
198196

199-
async injectPptxGenJS(): Promise<void> {
200-
this.createPptxGenJSInstance();
201-
this.pptxGenJSTmpFile = randomUUID() + '.pptx';
202-
203-
let generatedSlidesCount = 0;
204-
for (const slide of this.slides) {
205-
const generate = slide.getGeneratedElements();
206-
if (generate.length) {
207-
generatedSlidesCount++;
208-
const pgenSlide = this.appendPptxGenSlide();
209-
210-
generate.forEach((generateElement) => {
211-
generateElement.objectName =
212-
generateElement.objectName || randomUUID();
213-
generateElement.tmpSlideNumber = generatedSlidesCount;
214-
generateElement.callback(
215-
pgenSlide,
216-
generateElement.objectName,
217-
this.pptxGenJS,
218-
);
219-
220-
slide.addElement(
221-
this.pptxGenJSTmpFile,
222-
generatedSlidesCount,
223-
generateElement.objectName,
224-
);
225-
});
226-
}
227-
}
228-
229-
if (generatedSlidesCount > 0) {
230-
await this.pptxGenJS.writeFile({
231-
fileName: this.automizer.templateDir + '/' + this.pptxGenJSTmpFile,
232-
});
233-
this.automizer.load(this.pptxGenJSTmpFile);
234-
}
235-
}
236-
237-
createPptxGenJSInstance(): void {
238-
this.pptxGenJS = new PptxGenJS();
239-
}
240-
appendPptxGenSlide(): PptxGenJS.Slide {
241-
return this.pptxGenJS.addSlide();
242-
}
243-
async cleanupPptxGenJS() {
244-
fs.unlinkSync(this.automizer.templateDir + '/' + this.pptxGenJSTmpFile);
245-
}
246-
247197
async countExistingSlides(): Promise<void> {
248198
const xml = await this.getSlideIdList();
249199
const sldIdLst = xml.getElementsByTagName('p:sldIdLst');
@@ -288,4 +238,20 @@ export class Template implements ITemplate {
288238
count(name: string): number {
289239
return CountHelper.count(name, this.counter);
290240
}
241+
242+
async runExternalGenerators() {
243+
this.generators.push(
244+
new GeneratePptxGenJs(this.automizer, this.slides).create(),
245+
);
246+
247+
for (const generator of this.generators) {
248+
await generator.generateSlides();
249+
}
250+
}
251+
252+
async cleanupExternalGenerators() {
253+
for (const generator of this.generators) {
254+
await generator.cleanup();
255+
}
256+
}
291257
}

0 commit comments

Comments
 (0)