Skip to content

Commit e6e332e

Browse files
authored
Merge pull request #50 from singerla/feature-output-stream
Feature output stream
2 parents 0944a39 + 03a6411 commit e6e332e

File tree

6 files changed

+111
-19
lines changed

6 files changed

+111
-19
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@ pres.addSlide('graph', 1)
106106
pres.write(`myPresentation.pptx`).then(summary => {
107107
console.log(summary)
108108
})
109+
110+
// It is also possible to get a ReadableStream.
111+
// stream() accepts JSZip.JSZipGeneratorOptions for 'nodebuffer' type.
112+
const stream = await pres.stream({
113+
compressionOptions: {
114+
level: 9,
115+
},
116+
})
117+
// You can e.g. output the pptx archive to stdout instead of writing a file:
118+
stream.pipe(process.stdout)
119+
120+
// If you need any other output format, you can eventually access
121+
// the underlying JSZip instance:
122+
const finalJSZip = await pres.getJSZip()
123+
// Convert the output to whatever needed:
124+
const base64 = await finalJSZip.generateAsync({ type: 'base64' })
125+
109126
```
110127

111128

src/automizer.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as fs from 'fs';
1818
import { XmlHelper } from './helper/xml-helper';
1919
import ModifyPresentationHelper from './helper/modify-presentation-helper';
2020
import { ContentTracker } from './helper/content-tracker';
21+
import JSZip, { OutputType } from 'jszip';
2122

2223
/**
2324
* Automizer
@@ -295,9 +296,7 @@ export default class Automizer implements IPresentationProps {
295296
* @returns summary object.
296297
*/
297298
public async write(location: string): Promise<AutomizerSummary> {
298-
await this.writeSlides();
299-
await this.normalizePresentation();
300-
await this.applyModifyPresentationCallbacks();
299+
await this.finalizePresentation();
301300

302301
await this.rootTemplate.archive.output(
303302
this.getLocation(location, 'output'),
@@ -318,6 +317,43 @@ export default class Automizer implements IPresentationProps {
318317
};
319318
}
320319

320+
/**
321+
* Create a ReadableStream from output pptx file.
322+
* @param generatorOptions - JSZipGeneratorOptions for nodebuffer Output type
323+
* @returns Promise<NodeJS.ReadableStream>
324+
*/
325+
public async stream(
326+
generatorOptions?: JSZip.JSZipGeneratorOptions<'nodebuffer'>,
327+
): Promise<NodeJS.ReadableStream> {
328+
await this.finalizePresentation();
329+
330+
if (!this.rootTemplate.archive.stream) {
331+
throw 'Streaming is not implemented for current archive type';
332+
}
333+
334+
return this.rootTemplate.archive.stream(this.params, generatorOptions);
335+
}
336+
337+
/**
338+
* Pass final JSZip instance.
339+
* @returns Promise<NodeJS.ReadableStream>
340+
*/
341+
public async getJSZip(): Promise<JSZip> {
342+
await this.finalizePresentation();
343+
344+
if (!this.rootTemplate.archive.getFinalArchive) {
345+
throw 'GetFinalArchive is not implemented for current archive type';
346+
}
347+
348+
return this.rootTemplate.archive.getFinalArchive();
349+
}
350+
351+
async finalizePresentation() {
352+
await this.writeSlides();
353+
await this.normalizePresentation();
354+
await this.applyModifyPresentationCallbacks();
355+
}
356+
321357
/**
322358
* Write all slides to archive.
323359
*/

src/dev.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ const outputName = 'create-presentation-file-proxy.test.pptx';
55
const automizer = new Automizer({
66
templateDir: `${__dirname}/../__tests__/pptx-templates`,
77
outputDir: `${__dirname}/../__tests__/pptx-output`,
8-
archiveType: {
9-
mode: 'fs',
10-
baseDir: `${__dirname}/../__tests__/pptx-cache`,
11-
workDir: outputName,
12-
cleanupWorkDir: true,
13-
},
8+
// Streaming is only implemented for jszip
9+
// archiveType: {
10+
// mode: 'fs',
11+
// baseDir: `${__dirname}/../__tests__/pptx-cache`,
12+
// workDir: outputName,
13+
// cleanupWorkDir: true,
14+
// },
1415
rootTemplate: 'RootTemplateWithImages.pptx',
1516
presTemplates: [
1617
`RootTemplate.pptx`,
@@ -19,7 +20,7 @@ const automizer = new Automizer({
1920
],
2021
removeExistingSlides: true,
2122
cleanup: true,
22-
compression: 0,
23+
compression: 1,
2324
});
2425

2526
const run = async () => {
@@ -37,7 +38,7 @@ const run = async () => {
3738
],
3839
};
3940

40-
const result = await automizer
41+
const pres = await automizer
4142
.addSlide('ChartBarsStacked.pptx', 1, (slide) => {
4243
slide.modifyElement('BarsStacked', [modify.setChartData(dataSmaller)]);
4344
slide.addElement('ChartBarsStacked.pptx', 1, 'BarsStacked', [
@@ -57,10 +58,20 @@ const run = async () => {
5758
.addSlide('ChartBarsStacked.pptx', 1, (slide) => {
5859
slide.addElement('SlideWithImages.pptx', 2, 'imageJPG');
5960
slide.modifyElement('BarsStacked', [modify.setChartData(dataSmaller)]);
60-
})
61-
.write(outputName);
61+
});
62+
63+
const stream = await pres.stream({
64+
compressionOptions: {
65+
level: 9,
66+
},
67+
});
68+
69+
const jszip = await pres.getJSZip();
70+
const base64 = await jszip.generateAsync({ type: 'base64' });
71+
vd(stream);
72+
73+
// stream.pipe(process.stdout);
6274

63-
vd(result.duration);
6475
// vd(pres.rootTemplate.content);
6576
};
6677

src/helper/archive/archive-jszip.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AutomizerParams } from '../../types/types';
55
import IArchive, { ArchivedFile } from '../../interfaces/iarchive';
66
import { XmlDocument } from '../../types/xml-types';
77
import path from 'path';
8+
import { vd } from '../general-helper';
89

910
export default class ArchiveJszip extends Archive implements IArchive {
1011
archive: JSZip;
@@ -87,6 +88,27 @@ export default class ArchiveJszip extends Archive implements IArchive {
8788
});
8889
}
8990

91+
async stream(
92+
params: AutomizerParams,
93+
options?: JSZip.JSZipGeneratorOptions<'nodebuffer'>,
94+
): Promise<NodeJS.ReadableStream> {
95+
this.setOptions(params);
96+
97+
await this.writeBuffer(this);
98+
99+
const mergedOptions = {
100+
...this.options,
101+
...options,
102+
};
103+
104+
return this.archive.generateNodeStream(mergedOptions);
105+
}
106+
107+
async getFinalArchive(): Promise<JSZip> {
108+
await this.writeBuffer(this);
109+
return this.archive;
110+
}
111+
90112
async getContent(params: AutomizerParams): Promise<Buffer> {
91113
this.setOptions(params);
92114

src/helper/archive/archive.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ export default class Archive {
4444
}
4545
}
4646

47-
fromBuffer(relativePath) {
48-
return this.buffer.find((file) => file.relativePath === relativePath);
49-
}
50-
5147
setOptions(params: AutomizerParams): void {
5248
if (params.compression > 0) {
5349
this.options.compression = 'DEFLATE';
@@ -56,4 +52,8 @@ export default class Archive {
5652
};
5753
}
5854
}
55+
56+
fromBuffer(relativePath) {
57+
return this.buffer.find((file) => file.relativePath === relativePath);
58+
}
5959
}

src/interfaces/iarchive.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import ArchiveJszip from '../helper/archive/archive-jszip';
22
import { AutomizerParams } from '../types/types';
3-
import { InputType } from 'jszip';
3+
import JSZip, { InputType } from 'jszip';
44
import { XmlDocument } from '../types/xml-types';
55
import ArchiveFs from '../helper/archive/archive-fs';
66

@@ -26,4 +26,10 @@ export default interface IArchive {
2626
remove: (file: string) => Promise<void>;
2727
output: (location: string, params: AutomizerParams) => Promise<void>;
2828
getContent?: (params: AutomizerParams) => Promise<Buffer>;
29+
getArchive?: (params: AutomizerParams) => Promise<Buffer>;
30+
stream?: (
31+
params: AutomizerParams,
32+
options: JSZip.JSZipGeneratorOptions<'nodebuffer'>,
33+
) => Promise<NodeJS.ReadableStream>;
34+
getFinalArchive?: () => Promise<JSZip>;
2935
}

0 commit comments

Comments
 (0)