Merge pull request #3251 from FinnStutzenstein/PdfZipPerformance

Improve zip creation and fixing page numbers
This commit is contained in:
Emanuel Schütze 2017-05-17 08:29:00 +02:00 committed by GitHub
commit 70dd9647b4
4 changed files with 80 additions and 46 deletions

View File

@ -21,6 +21,7 @@ Motions:
- Removed server side image to base64 transformation and - Removed server side image to base64 transformation and
added local transformation [#3181] added local transformation [#3181]
- Added support for export motions in a zip archive [#3189]. - Added support for export motions in a zip archive [#3189].
- Performance improvement for zip creation [#3251]
- Bugfix: changing motion line length did not invalidate cache [#3202] - Bugfix: changing motion line length did not invalidate cache [#3202]
- Bugfix: Added more distance in motion PDF for DEL-tags in new lines [#3211]. - Bugfix: Added more distance in motion PDF for DEL-tags in new lines [#3211].
- Added warning message if an edit dialog was already opened by another - Added warning message if an edit dialog was already opened by another
@ -48,7 +49,7 @@ Core:
General: General:
- Switched from npm to Yarn [#3188]. - Switched from npm to Yarn [#3188].
- Several bugfixes and minor improvements. - Several bugfixes and minor improvements.
- Bugfixes for PDF creation [#3227] - Bugfixes for PDF creation [#3227, #3251]
Version 2.1.1 (2017-04-05) Version 2.1.1 (2017-04-05)

View File

@ -86,34 +86,46 @@ var replacePlaceholder = function (content) {
} }
}; };
// Workaround for using dynamic footer with page number.
// Create PDF on message and return the base64 decoded document // TODO: Needs improvement of pdfmake's web worker support.
self.addEventListener('message', function(e) { // see https://github.com/bpampuch/pdfmake/issues/38
var data = JSON.parse(e.data); var replaceFooter = function (doc) {
if (doc.footerTpl) {
// Workaround for using dynamic footer with page number. doc.footer = function (currentPage, pageCount) {
// TODO: Needs improvement of pdfmake's web worker support. // One way to clone arrays/objects in js, that are serilizeable.
// see https://github.com/bpampuch/pdfmake/issues/38 var columns = JSON.parse(JSON.stringify(doc.footerTpl.columns));
if (data.footerTpl) { for (var i = 0; i < columns.length; i++) {
data.footer = function (currentPage, pageCount) { if (columns[i].text) {
for(var i = 0; i < data.footerTpl.columns.length; i++) { columns[i].text = columns[i].text
if (data.footerTpl.columns[i].text) {
data.footerTpl.columns[i].text = data.footerTpl.columns[i].text
.replace('{{currentPage}}', currentPage) .replace('{{currentPage}}', currentPage)
.replace('{{pageCount}}', pageCount); .replace('{{pageCount}}', pageCount);
} }
} }
return { return {
columns: data.footerTpl.columns, columns: columns,
margin: data.footerTpl.margin, margin: doc.footerTpl.margin,
}; };
}; };
} }
};
replacePlaceholder(data.content); // Create PDF on message and return the base64 decoded document
self.addEventListener('message', function(e) {
var data = JSON.parse(e.data);
var doc = data.pdfDocument;
var pdf = pdfMake.createPdf(data); replaceFooter(doc);
replacePlaceholder(doc.content);
var pdf = pdfMake.createPdf(doc);
pdf.getBase64(function (base64) { pdf.getBase64(function (base64) {
self.postMessage(base64); if (data.filename) {
self.postMessage(JSON.stringify({
filename: data.filename,
base64: base64
}));
} else {
self.postMessage(base64);
}
}); });
}, false); }, false);

View File

@ -1008,7 +1008,34 @@ angular.module('OpenSlidesApp.core.pdf', [])
pdfWorker.addEventListener('error', function (event) { pdfWorker.addEventListener('error', function (event) {
reject(event); reject(event);
}); });
pdfWorker.postMessage(JSON.stringify(pdfDocument)); pdfWorker.postMessage(JSON.stringify({
pdfDocument: pdfDocument
}));
});
},
// Struckture of pdfDocuments: { filname1: doc, filename2: doc, ...}
getBase64FromMultipleDocuments: function (pdfDocuments) {
return $q(function (resolve, reject) {
var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
var resultCount = 0;
var base64Map = {}; // Maps filename to base64
pdfWorker.addEventListener('message', function (event) {
resultCount++;
var data = JSON.parse(event.data);
base64Map[data.filename] = data.base64;
if (resultCount === _.keys(pdfDocuments).length) {
resolve(base64Map);
}
});
pdfWorker.addEventListener('error', function (event) {
reject(event);
});
_.forEach(pdfDocuments, function (doc, filename) {
pdfWorker.postMessage(JSON.stringify({
filename: filename,
pdfDocument: doc
}));
});
}); });
}, },
download: function (pdfDocument, filename) { download: function (pdfDocument, filename) {

View File

@ -723,9 +723,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
params.filename = void 0; // clear this, so we do not override the default filenames for each pdf. params.filename = void 0; // clear this, so we do not override the default filenames for each pdf.
var self = this; var self = this;
var pdfs = {};
var usedFilenames = []; var usedFilenames = [];
var pdfPromises = _.map(motions, function (motion) { var docMap = {};
var docPromises = _.map(motions, function (motion) {
var identifier = motion.identifier ? '-' + motion.identifier : ''; var identifier = motion.identifier ? '-' + motion.identifier : '';
var filename = gettextCatalog.getString('Motion') + identifier; var filename = gettextCatalog.getString('Motion') + identifier;
@ -742,36 +742,30 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
usedFilenames.push(filename); usedFilenames.push(filename);
filename += '.pdf'; filename += '.pdf';
return $q(function (resolve, reject) { return $q(function (resolve) {
// get documentProvider for every motion. // get documentProvider for every motion.
self.getDocumentProvider(motion, params, true).then(function (documentProvider) { self.getDocumentProvider(motion, params, true).then(function (documentProvider) {
var doc = documentProvider.getDocument(); docMap[filename] = documentProvider.getDocument();
resolve();
PdfCreate.getBase64FromDocument(doc).then(function (data) {
pdfs[filename] = data;
resolve();
}, function (error) {
reject(error);
});
}); });
}); });
}); });
$q.all(docPromises).then(function () {
// Wait for all documents to be generated. Then put them into a zip and download it. PdfCreate.getBase64FromMultipleDocuments(docMap).then(function (pdfMap) {
$q.all(pdfPromises).then(function () { var zip = new JSZip();
var zip = new JSZip(); _.forEach(pdfMap, function (data, filename) {
_.forEach(pdfs, function (data, filename) { zip.file(filename, data, {base64: true});
zip.file(filename, data, {base64: true}); });
Messaging.createOrEditMessage(messageId, '<i class="fa fa-check fa-lg spacer-right"></i>' +
gettextCatalog.getString('ZIP successfully generated.'), 'success', {timeout: 3000});
zip.generateAsync({type: 'blob'}).then(function (content) {
FileSaver.saveAs(content, zipFilename);
});
}, function (error) {
Messaging.createOrEditMessage(messageId, '<i class="fa fa-exclamation-triangle fa-lg ' +
'spacer-right"></i>' + gettextCatalog.getString('Error while generating ZIP file') +
': <code>' + error + '</code>', 'error');
}); });
Messaging.createOrEditMessage(messageId, '<i class="fa fa-check fa-lg spacer-right"></i>' +
gettextCatalog.getString('ZIP successfully generated.'), 'success', {timeout: 3000});
zip.generateAsync({type: 'blob'}).then(function (content) {
FileSaver.saveAs(content, zipFilename);
});
}, function (error) {
Messaging.createOrEditMessage(messageId, '<i class="fa fa-exclamation-triangle fa-lg ' +
'spacer-right"></i>' + gettextCatalog.getString('Error while generating ZIP file') +
': <code>' + error + '</code>', 'error');
}); });
}, },
createPollPdf: function (motion, version) { createPollPdf: function (motion, version) {