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
added local transformation [#3181]
- 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: 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
@ -48,7 +49,7 @@ Core:
General:
- Switched from npm to Yarn [#3188].
- Several bugfixes and minor improvements.
- Bugfixes for PDF creation [#3227]
- Bugfixes for PDF creation [#3227, #3251]
Version 2.1.1 (2017-04-05)

View File

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

View File

@ -1008,7 +1008,34 @@ angular.module('OpenSlidesApp.core.pdf', [])
pdfWorker.addEventListener('error', function (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) {

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.
var self = this;
var pdfs = {};
var usedFilenames = [];
var pdfPromises = _.map(motions, function (motion) {
var docMap = {};
var docPromises = _.map(motions, function (motion) {
var identifier = motion.identifier ? '-' + motion.identifier : '';
var filename = gettextCatalog.getString('Motion') + identifier;
@ -742,36 +742,30 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
usedFilenames.push(filename);
filename += '.pdf';
return $q(function (resolve, reject) {
return $q(function (resolve) {
// get documentProvider for every motion.
self.getDocumentProvider(motion, params, true).then(function (documentProvider) {
var doc = documentProvider.getDocument();
PdfCreate.getBase64FromDocument(doc).then(function (data) {
pdfs[filename] = data;
resolve();
}, function (error) {
reject(error);
});
docMap[filename] = documentProvider.getDocument();
resolve();
});
});
});
// Wait for all documents to be generated. Then put them into a zip and download it.
$q.all(pdfPromises).then(function () {
var zip = new JSZip();
_.forEach(pdfs, function (data, filename) {
zip.file(filename, data, {base64: true});
$q.all(docPromises).then(function () {
PdfCreate.getBase64FromMultipleDocuments(docMap).then(function (pdfMap) {
var zip = new JSZip();
_.forEach(pdfMap, function (data, filename) {
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) {