From 63dfc9ef2f7eed2ca1e171df34056993a6bec4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Wed, 19 Sep 2018 10:58:58 -0400 Subject: [PATCH] feat(print): Add test layers for CORS in print (#183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add printing output format (pdf, Image) combobox Change print format to print paper format * (change) to (selectionChange) after angular update * Temporary remove Resolution parameter for printing Fix image size to fit pdf page * Fix Internet Explorer issue with window.open and getComputedStyle to generate the legend (use local div instead) Add WorldFile for tiff Remove resolution for future TODO amelioration * Update fr.geo.json * Update print.service.ts * Add jsZip to be able to download one file in print module Add checkbox for zip Add loading Fix pdf with legend in IE * Add layer "embâcle" in the demo Ajust css display change element display instead of disabling * Add more layers to the print demo Fix Print error message * run test.libs fix * Add test layers for CORS in print --- demo/src/app/geo/print/print.component.ts | 32 ++++ .../geo/src/lib/print/shared/print.service.ts | 157 +++++++++++------- projects/geo/src/locale/en.geo.json | 2 + projects/geo/src/locale/fr.geo.json | 2 + 4 files changed, 129 insertions(+), 64 deletions(-) diff --git a/demo/src/app/geo/print/print.component.ts b/demo/src/app/geo/print/print.component.ts index 04e36fc54d..9758b2a83b 100644 --- a/demo/src/app/geo/print/print.component.ts +++ b/demo/src/app/geo/print/print.component.ts @@ -66,5 +66,37 @@ export class AppPrintComponent { } }) .subscribe(l => this.map.addLayer(l)); + + this.layerService + .createAsyncLayer({ + title: 'Geomet', + sourceOptions: { + type: 'wms', + url: 'http://geo.weather.gc.ca/geomet/?lang=fr', + params: { + layers: 'RADAR_1KM_RDBR', + version: '1.3.0', + }, + crossOrigin: 'anonymous' + } + }) + .subscribe(l => this.map.addLayer(l)); + + /* + //CORS error if activate (for test) + this.layerService + .createAsyncLayer({ + title: 'Geomet', + sourceOptions: { + type: 'wms', + url: 'https://ws.mapserver.transports.gouv.qc.ca/swtq?service=wms', + params: { + layers: 'swtq', + version: '1.3.0', + } + } + }) + .subscribe(l => this.map.addLayer(l)); + */ } } diff --git a/projects/geo/src/lib/print/shared/print.service.ts b/projects/geo/src/lib/print/shared/print.service.ts index fc653c45a3..ac9b0b005f 100644 --- a/projects/geo/src/lib/print/shared/print.service.ts +++ b/projects/geo/src/lib/print/shared/print.service.ts @@ -124,6 +124,7 @@ export class PrintService { @return The image of the legend */ getLayersLegendImage(map, format = 'png', doZipFile) { + const status$ = new Subject(); // Get html code for the legend const width = 200; // milimeters unit, originally define for document pdf let html = this.getLayersLegendHtml(map, width); @@ -143,16 +144,22 @@ export class PrintService { div.innerHTML = html; // Define event to execute after all images are loaded to create the canvas setTimeout(function() { - html2canvas(div, { useCORS: true }).then(canvas => { + html2canvas(div, { useCORS: true}).then(canvas => { - if (!doZipFile) { - // Save the canvas as file - that.saveCanvasImageAsFile(canvas, 'legendImage', format); - } else { - // Add the canvas to zip - that.generateCanvaFileToZip(canvas, 'legendImage' + '.' + format); - } - div.parentNode.removeChild(div); // remove temp div (IE) + let status = SubjectStatus.Done; + try { + if (!doZipFile) { + // Save the canvas as file + that.saveCanvasImageAsFile(canvas, 'legendImage', format); + } else { + // Add the canvas to zip + that.generateCanvaFileToZip(canvas, 'legendImage' + '.' + format); + } + div.parentNode.removeChild(div); // remove temp div (IE) + } catch (err) { + status = SubjectStatus.Error; + } + status$.next(status); }); }, 500); } @@ -243,26 +250,17 @@ export class PrintService { // Create div to contain html code for legend const div = window.document.createElement('div'); - html2canvas(div, { useCORS: true }).then(canvas => { + html2canvas(div, { useCORS: true}).then(canvas => { let imgData; const position = 10; - try { - imgData = canvas.toDataURL('image/png'); - doc.addPage(); - const imageSize = this.getImageSizeToFitPdf(doc, canvas); - doc.addImage(imgData, 'PNG', 10, position, imageSize[0], imageSize[1]); - that.saveDoc(doc); - div.parentNode.removeChild(div); // remove temp div (IE) - } catch (err) { - div.parentNode.removeChild(div); // remove temp div (IE) - this.messageService.error( - 'Security error: The legend cannot be printed.', - 'Print', - 'print' - ); - throw new Error(err); - } + imgData = canvas.toDataURL('image/png'); + doc.addPage(); + const imageSize = this.getImageSizeToFitPdf(doc, canvas); + doc.addImage(imgData, 'PNG', 10, position, imageSize[0], imageSize[1]); + that.saveDoc(doc); + div.parentNode.removeChild(div); // remove temp div (IE style) + }); // Add html code to convert in the new window @@ -277,17 +275,9 @@ export class PrintService { margins: Array ) { let image; - try { - image = canvas.toDataURL('image/jpeg'); - } catch (err) { - this.messageService.error( - 'Security error: This map cannot be printed.', - 'Print', - 'print' - ); - throw new Error(err); - } + image = canvas.toDataURL('image/jpeg'); + if (image !== undefined) { const imageSize = this.getImageSizeToFitPdf(doc, canvas); @@ -330,6 +320,11 @@ export class PrintService { this.addCanvas(doc, canvas, size, margins); } catch (err) { status = SubjectStatus.Error; + this.messageService.error( + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageBody'), + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageHeader'), + 'print' + ); } this.renderMap(map, mapSize, extent); @@ -346,6 +341,11 @@ export class PrintService { this.addCanvas(doc, canvas, size, margins); } catch (err) { status = SubjectStatus.Error; + this.messageService.error( + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageBody'), + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageHeader'), + 'print' + ); } this.renderMap(map, mapSize, extent); @@ -384,6 +384,7 @@ export class PrintService { comment = '', doZipFile = true ) { + const status$ = new Subject(); const resolution = map.ol.getView().getResolution(); this.activityId = this.activityService.register(); const translate = this.languageService.translate; @@ -498,20 +499,27 @@ export class PrintService { // Add map to new canvas newContext.drawImage(context.canvas, 0, positionHCanvas); - // Save the canvas as file - if (!doZipFile) { - this.saveCanvasImageAsFile(newCanvas, 'map', format); - } else if (format.toLowerCase() === 'tiff') { - // Add the canvas to zip - this.generateCanvaFileToZip( - newCanvas, - 'map' + map.projection.replace(':', '_') + '.' + format - ); - } else { - // Add the canvas to zip - this.generateCanvaFileToZip(newCanvas, 'map' + '.' + format); + let status = SubjectStatus.Done; + try { + // Save the canvas as file + if (!doZipFile) { + this.saveCanvasImageAsFile(newCanvas, 'map', format); + } else if (format.toLowerCase() === 'tiff') { + // Add the canvas to zip + this.generateCanvaFileToZip( + newCanvas, + 'map' + map.projection.replace(':', '_') + '.' + format + ); + } else { + // Add the canvas to zip + this.generateCanvaFileToZip(newCanvas, 'map' + '.' + format); + } + } catch (err) { + status = SubjectStatus.Error; } + status$.next(status); + if (format.toLowerCase() === 'tiff') { const tiwContent = this.getWorldFileInformation(map); const blob = new Blob([tiwContent], {type: 'text/plain;charset=utf-8'}); @@ -592,16 +600,26 @@ export class PrintService { private saveCanvasImageAsFile(canvas, name, format) { const blobFormat = 'image/' + format; const that = this; - // If navigator is Internet Explorer - if (navigator.msSaveBlob) { - navigator.msSaveBlob(canvas.msToBlob(), name + '.' + format); - this.saveFileProcessing(); - } else { - canvas.toBlob(function(blob) { - // download image - saveAs(blob, name + '.' + format); - that.saveFileProcessing(); - }, blobFormat); + + try { + canvas.toDataURL(); // Just to make the catch trigger wihtout toBlob Error throw not catched + // If navigator is Internet Explorer + if (navigator.msSaveBlob) { + navigator.msSaveBlob(canvas.msToBlob(), name + '.' + format); + this.saveFileProcessing(); + } else { + canvas.toBlob(function(blob) { + // download image + saveAs(blob, name + '.' + format); + that.saveFileProcessing(); + }, blobFormat); + } + } catch (err) { + this.messageService.error( + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageBody'), + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageHeader'), + 'print' + ); } } @@ -616,13 +634,24 @@ export class PrintService { if (!this.hasOwnProperty('zipFile') || typeof this.zipFile === 'undefined') { this.zipFile = new JSZip(); } - if (navigator.msSaveBlob) { - this.addFileToZip(name, canvas.msToBlob()); - } else { - canvas.toBlob(function(blob) { - that.addFileToZip(name, blob); - }, blobFormat); + + try { + canvas.toDataURL(); // Just to make the catch trigger wihtout toBlob Error throw not catched + if (navigator.msSaveBlob) { + this.addFileToZip(name, canvas.msToBlob()); + } else { + canvas.toBlob(function(blob) { + that.addFileToZip(name, blob); + }, blobFormat); + } + } catch (err) { + this.messageService.error( + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageBody'), + this.languageService.translate.instant('igo.geo.printForm.corsErrorMessageHeader'), + 'print' + ); } + } /** diff --git a/projects/geo/src/locale/en.geo.json b/projects/geo/src/locale/en.geo.json index fabada0ff1..2e83837c35 100644 --- a/projects/geo/src/locale/en.geo.json +++ b/projects/geo/src/locale/en.geo.json @@ -124,6 +124,8 @@ "write": "Read and Write" }, "printForm": { + "corsErrorMessageBody": "Unable to print due to non-owned access rights", + "corsErrorMessageHeader": "Print", "comment": "Comment", "doZipFile": "Zip files", "outputFormat": "Output format", diff --git a/projects/geo/src/locale/fr.geo.json b/projects/geo/src/locale/fr.geo.json index 98263c29fb..c1d4c30534 100644 --- a/projects/geo/src/locale/fr.geo.json +++ b/projects/geo/src/locale/fr.geo.json @@ -126,6 +126,8 @@ "write": "Lecture et écriture" }, "printForm": { + "corsErrorMessageBody": "Impossible d'imprimer dû à des droits d'accès non détenus", + "corsErrorMessageHeader": "Impression", "comment": "Commentaire", "doZipFile": "Compresser les fichiers", "outputFormat": "Format de sortie",