Merge pull request #3631 from FinnStutzenstein/pdf-images-in-vfs

Moved image sources to the virtual filesystem
This commit is contained in:
Norman Jäckel 2018-03-05 20:35:46 +01:00 committed by GitHub
commit ae3277b747
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 37 deletions

View File

@ -87,7 +87,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
return '{{ballot-placeholder-to-insert-functions-here}}'; return '{{ballot-placeholder-to-insert-functions-here}}';
}; };
// returns a promise for converting an image in data URL format // returns a promise for converting an image in data URL format with size information
PDFLayout.imageURLtoBase64 = function(url) { PDFLayout.imageURLtoBase64 = function(url) {
var promise = new Promise(function(resolve) { var promise = new Promise(function(resolve) {
var img = new Image(); var img = new Image();
@ -170,15 +170,18 @@ angular.module('OpenSlidesApp.core.pdf', [])
// Logo urls // Logo urls
var logoHeaderUrl = Config.get('logo_pdf_header').value.path, var logoHeaderUrl = Config.get('logo_pdf_header').value.path,
logoFooterUrl = Config.get('logo_pdf_footer').value.path; logoFooterUrl = Config.get('logo_pdf_footer').value.path;
var imageMap = {}; var imageMap = contentProvider.getImageMap();
// PDF header // PDF header
var getHeader = function() { var getHeader = function() {
var columns = []; var columns = [];
if (logoHeaderUrl) { if (logoHeaderUrl) {
if (logoHeaderUrl.indexOf('/') === 0) {
logoHeaderUrl = logoHeaderUrl.substr(1); // remove trailing /
}
columns.push({ columns.push({
image: imageMap[logoHeaderUrl].data, image: logoHeaderUrl,
fit: [180, 40], fit: [180, 40],
width: '20%' width: '20%'
}); });
@ -216,8 +219,11 @@ angular.module('OpenSlidesApp.core.pdf', [])
var columns = []; var columns = [];
if (logoFooterUrl) { if (logoFooterUrl) {
if (logoFooterUrl.indexOf('/') === 0) {
logoFooterUrl = logoFooterUrl.substr(1); // remove trailing /
}
columns.push({ columns.push({
image: imageMap[logoFooterUrl].data, image: logoFooterUrl,
fit: [400,50], fit: [400,50],
width: '80%' width: '80%'
}); });
@ -338,15 +344,24 @@ angular.module('OpenSlidesApp.core.pdf', [])
}; };
}; };
var getImageMap = function () {
return imageMap;
};
return $q(function (resolve) { return $q(function (resolve) {
var imageSources = [ var imageSources = [
logoHeaderUrl, logoHeaderUrl,
logoFooterUrl logoFooterUrl
]; ];
ImageConverter.toBase64(imageSources).then(function (_imageMap) { ImageConverter.toBase64(imageSources).then(function (_imageMap) {
imageMap = _imageMap; _.forEach(_imageMap, function (data, path) {
if (!imageMap[path]) {
imageMap[path] = data;
}
});
resolve({ resolve({
getDocument: getDocument getDocument: getDocument,
getImageMap: getImageMap,
}); });
}); });
}); });
@ -393,8 +408,14 @@ angular.module('OpenSlidesApp.core.pdf', [])
} }
}; };
}; };
var getImageMap = function() {
return contentProvider.getImageMap();
};
return { return {
getDocument: getDocument getDocument: getDocument,
getImageMap: getImageMap,
}; };
}; };
return { return {
@ -937,8 +958,12 @@ angular.module('OpenSlidesApp.core.pdf', [])
imageSize.width *= scaleByHeight; imageSize.width *= scaleByHeight;
imageSize.height *= scaleByHeight; imageSize.height *= scaleByHeight;
} }
var path = element.getAttribute("src");
if (path.indexOf('/') === 0) {
path = path.substr(1); // remove trailing /
}
alreadyConverted.push({ alreadyConverted.push({
image: images[element.getAttribute("src")].data, image: path,
width: imageSize.width, width: imageSize.width,
height: imageSize.height height: imageSize.height
}); });
@ -1064,8 +1089,8 @@ angular.module('OpenSlidesApp.core.pdf', [])
var imageMap = {}; var imageMap = {};
var imagePromises = _.map(imageSources, function (imageSource) { var imagePromises = _.map(imageSources, function (imageSource) {
if (imageSource) { if (imageSource) {
return PDFLayout.imageURLtoBase64(imageSource).then(function (base64Str) { return PDFLayout.imageURLtoBase64(imageSource).then(function (imgInfo) {
imageMap[imageSource] = base64Str; imageMap[imageSource] = imgInfo;
}); });
} }
}); });
@ -1127,10 +1152,17 @@ angular.module('OpenSlidesApp.core.pdf', [])
/* /*
* Create the virtual filesystem needed by PdfMake for the fonts. Gets the url * Create the virtual filesystem needed by PdfMake for the fonts. Gets the url
* mapping and loads all fonts via get requests or the urlCache. * mapping and loads all fonts via get requests or the urlCache.
* Adds all image sources to the vfs given by the imageMap.
*/ */
var getVfs = function () { var getVfs = function (imageMap) {
return $q(function (resolve, reject) {
var vfs = {}; var vfs = {};
_.forEach(imageMap || {}, function (data, path) {
if (path.indexOf('/') === 0) {
path = path.substr(1); // remove trailing /
}
vfs[path] = data.data.split(',')[1];
});
return $q(function (resolve, reject) {
var urls = getUrlMapping(); var urls = getUrlMapping();
var promises = _.chain(urls) var promises = _.chain(urls)
.map(function (filenames, url) { .map(function (filenames, url) {
@ -1209,9 +1241,9 @@ angular.module('OpenSlidesApp.core.pdf', [])
}, 1); }, 1);
}; };
return { return {
getBase64FromDocument: function (pdfDocument) { getBase64FromDocument: function (documentProvider) {
return $q(function (resolve, reject) { return $q(function (resolve, reject) {
PdfVfs.get().then(function (vfs) { PdfVfs.get(documentProvider.getImageMap()).then(function (vfs) {
var pdfWorker = new Worker('/static/js/workers/pdf-worker.js'); var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
pdfWorker.addEventListener('message', function (event) { pdfWorker.addEventListener('message', function (event) {
resolve(event.data); resolve(event.data);
@ -1220,7 +1252,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
reject(event); reject(event);
}); });
pdfWorker.postMessage(JSON.stringify({ pdfWorker.postMessage(JSON.stringify({
pdfDocument: pdfDocument, pdfDocument: documentProvider.getDocument(),
vfs: vfs, vfs: vfs,
})); }));
}); });
@ -1228,8 +1260,17 @@ angular.module('OpenSlidesApp.core.pdf', [])
}, },
// Struckture of pdfDocuments: { filname1: doc, filename2: doc, ...} // Struckture of pdfDocuments: { filname1: doc, filename2: doc, ...}
getBase64FromMultipleDocuments: function (pdfDocuments) { getBase64FromMultipleDocuments: function (pdfDocuments) {
// concat all image sources together
var imageMap = {};
_.forEach(pdfDocuments, function (doc) {
_.forEach(doc.getImageMap(), function (data, path) {
if (!imageMap[path]) {
imageMap[path] = data;
}
});
});
return $q(function (resolve, reject) { return $q(function (resolve, reject) {
PdfVfs.get().then(function (vfs) { PdfVfs.get(imageMap).then(function (vfs) {
var pdfWorker = new Worker('/static/js/workers/pdf-worker.js'); var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
var resultCount = 0; var resultCount = 0;
var base64Map = {}; // Maps filename to base64 var base64Map = {}; // Maps filename to base64
@ -1247,17 +1288,17 @@ angular.module('OpenSlidesApp.core.pdf', [])
_.forEach(pdfDocuments, function (doc, filename) { _.forEach(pdfDocuments, function (doc, filename) {
pdfWorker.postMessage(JSON.stringify({ pdfWorker.postMessage(JSON.stringify({
filename: filename, filename: filename,
pdfDocument: doc, pdfDocument: doc.getDocument(),
vfs: vfs, vfs: vfs,
})); }));
}); });
}); });
}); });
}, },
download: function (pdfDocument, filename) { download: function (documentProvider, filename) {
stateChange('info', filename); stateChange('info', filename);
this.getBase64FromDocument(pdfDocument).then(function (data) { this.getBase64FromDocument(documentProvider).then(function (data) {
var blob = b64toBlob(data); var blob = b64toBlob(data);
stateChange('success', filename); stateChange('success', filename);
FileSaver.saveAs(blob, filename); FileSaver.saveAs(blob, filename);

View File

@ -42,7 +42,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
includeComments: {}, includeComments: {},
}); });
var converter; var converter, imageMap = {};
// Query all image sources from motion text and reason // Query all image sources from motion text and reason
var getImageSources = function () { var getImageSources = function () {
@ -426,14 +426,20 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
return motion.category; return motion.category;
}; };
var getImageMap = function() {
return imageMap;
};
return $q(function (resolve) { return $q(function (resolve) {
ImageConverter.toBase64(getImageSources()).then(function (imageMap) { ImageConverter.toBase64(getImageSources()).then(function (_imageMap) {
converter = PdfMakeConverter.createInstance(imageMap); imageMap = _imageMap;
converter = PdfMakeConverter.createInstance(_imageMap);
resolve({ resolve({
getContent: getContent, getContent: getContent,
getTitle: getTitle, getTitle: getTitle,
getIdentifier: getIdentifier, getIdentifier: getIdentifier,
getCategory: getCategory getCategory: getCategory,
getImageMap: getImageMap,
}); });
}); });
}); });
@ -461,7 +467,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
* */ * */
var createInstance = function (motion, content) { var createInstance = function (motion, content) {
var converter; var converter, imageMap = {};
// Query all image sources from the content // Query all image sources from the content
var getImageSources = function () { var getImageSources = function () {
@ -593,11 +599,17 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
return pdfContent; return pdfContent;
}; };
var getImageMap = function () {
return imageMap;
};
return $q(function (resolve) { return $q(function (resolve) {
ImageConverter.toBase64(getImageSources()).then(function (imageMap) { ImageConverter.toBase64(getImageSources()).then(function (_imageMap) {
converter = PdfMakeConverter.createInstance(imageMap); imageMap = _imageMap;
converter = PdfMakeConverter.createInstance(_imageMap);
resolve({ resolve({
getContent: getContent, getContent: getContent,
getImageMap: getImageMap,
}); });
}); });
}); });
@ -643,7 +655,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
// logo // logo
if (logoBallotPaperUrl) { if (logoBallotPaperUrl) {
columns.push({ columns.push({
image: imageMap[logoBallotPaperUrl].data, image: logoBallotPaperUrl,
fit: [90,25], fit: [90,25],
alignment: 'right', alignment: 'right',
width: '40%' width: '40%'
@ -750,6 +762,10 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
return content; return content;
}; };
var getImageMap = function () {
return imageMap;
};
return $q(function (resolve) { return $q(function (resolve) {
var imageSources = [ var imageSources = [
logoBallotPaperUrl, logoBallotPaperUrl,
@ -757,7 +773,8 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
ImageConverter.toBase64(imageSources).then(function (_imageMap) { ImageConverter.toBase64(imageSources).then(function (_imageMap) {
imageMap = _imageMap; imageMap = _imageMap;
resolve({ resolve({
getContent: getContent getContent: getContent,
getImageMap: getImageMap,
}); });
}); });
}); });
@ -881,7 +898,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
// returns the pure content of the motion, parseable by pdfmake // returns the pure content of the motion, parseable by pdfmake
var getContent = function() { var getContent = function() {
var motionContent = []; var motionContent = [];
angular.forEach(allMotions, function(motion, key) { _.forEach(allMotions, function(motion, key) {
motionContent.push(motion.getContent()); motionContent.push(motion.getContent());
if (key < allMotions.length - 1) { if (key < allMotions.length - 1) {
motionContent.push(PDFLayout.addPageBreak()); motionContent.push(PDFLayout.addPageBreak());
@ -900,8 +917,22 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
content.push(motionContent); content.push(motionContent);
return content; return content;
}; };
var getImageMap = function () {
var imageMap = {};
_.forEach(allMotions, function (motion) {
_.forEach(motion.getImageMap(), function (data, path) {
if (!imageMap[path]) {
imageMap[path] = data;
}
});
});
return imageMap;
};
return { return {
getContent: getContent getContent: getContent,
getImageMap: getImageMap,
}; };
}; };
@ -992,7 +1023,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
}); });
this.getDocumentProvider(motions, params, singleMotion).then( this.getDocumentProvider(motions, params, singleMotion).then(
function (documentProvider) { function (documentProvider) {
PdfCreate.download(documentProvider.getDocument(), params.filename); PdfCreate.download(documentProvider, params.filename);
} }
); );
}, },
@ -1025,7 +1056,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
return $q(function (resolve) { 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) {
docMap[filename] = documentProvider.getDocument(); docMap[filename] = documentProvider;
resolve(); resolve();
}); });
}); });
@ -1054,7 +1085,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
var filename = gettextCatalog.getString('Motion') + '-' + id + '-' + gettextCatalog.getString('ballot-paper') + '.pdf'; var filename = gettextCatalog.getString('Motion') + '-' + id + '-' + gettextCatalog.getString('ballot-paper') + '.pdf';
PollContentProvider.createInstance(title, id).then(function (pollContentProvider) { PollContentProvider.createInstance(title, id).then(function (pollContentProvider) {
var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider); var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider);
PdfCreate.download(documentProvider.getDocument(), filename); PdfCreate.download(documentProvider, filename);
}); });
}, },
exportPersonalNote: function (motion, filename) { exportPersonalNote: function (motion, filename) {
@ -1065,7 +1096,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
}]; }];
MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) { MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) {
PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) { PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) {
PdfCreate.download(documentProvider.getDocument(), filename); PdfCreate.download(documentProvider, filename);
}); });
}); });
}, },
@ -1082,7 +1113,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
}]; }];
MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) { MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) {
PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) { PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) {
PdfCreate.download(documentProvider.getDocument(), filename); PdfCreate.download(documentProvider, filename);
}); });
}); });
} }

View File

@ -257,9 +257,9 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides
// import from textarea // import from textarea
$scope.importByLine = function () { $scope.importByLine = function () {
if ($scope.itemlist) { if ($scope.itemlist) {
$scope.titleItems = $scope.itemlist[0].split("\n"); $scope.titleItems = _.filter($scope.itemlist[0].split("\n"));
$scope.importcounter = 0; $scope.importcounter = 0;
$scope.titleItems.forEach(function(title, index) { _.forEach($scope.titleItems, function(title, index) {
var item = {title: title}; var item = {title: title};
item.agenda_type = 1; // The new topic is not hidden. item.agenda_type = 1; // The new topic is not hidden.
item.agenda_weight = 1000 + index; item.agenda_weight = 1000 + index;