-
-
Save keego/983f14b0b79f45e4cc71d6928a25a40c to your computer and use it in GitHub Desktop.
Uses `html2canvas` to take screenshots each element in an html NodeList, then uses `pdfMake` to concatenate them into a pdf and download it. (ES5 for AngularJS)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Private fields | |
var PAGE_HEIGHT = 700; | |
var PAGE_WIDTH = 500; | |
// Private methods | |
function createNewReport (fileName) { | |
var content = []; | |
function addImage(image) { | |
return new Promise(function (resolve, reject) { | |
var dims = getPngDimensions(image); | |
var printHeight = dims.height * PAGE_WIDTH / dims.width; | |
if (printHeight > PAGE_HEIGHT) { | |
var img = new Image(); | |
img.onload = splitImage(img, content, resolve); | |
img.src = image; | |
return; | |
} | |
content.push({ | |
image: image, | |
margin: [0, 5], | |
width: PAGE_WIDTH, | |
}); | |
resolve(); | |
}); | |
} | |
function download() { | |
var docDefinition = { | |
content: content, | |
}; | |
pdfMake.createPdf(docDefinition).download(fileName); | |
} | |
/** | |
* Note: seems to have some quality degradation issues. | |
*/ | |
function splitImage(img, content, callback) { | |
return function () { | |
var canvas = document.createElement('canvas'); | |
var ctx = canvas.getContext('2d'); | |
var printHeight = img.height * PAGE_WIDTH / img.width; | |
canvas.width = PAGE_WIDTH; | |
for (var pages = 0; printHeight > pages * PAGE_HEIGHT; pages++) { | |
/* Don't use full height for the last image */ | |
canvas.height = Math.min(PAGE_HEIGHT, printHeight - pages * PAGE_HEIGHT); | |
ctx.drawImage(img, 0, -pages * PAGE_HEIGHT, canvas.width, printHeight); | |
content.push({ | |
image: canvas.toDataURL(), | |
margin: [0, 5], | |
width: PAGE_WIDTH, | |
}); | |
} | |
callback(); | |
} | |
} | |
return { | |
addImage: addImage, | |
download: download, | |
splitImage: splitImage, | |
}; | |
} | |
function getPngDimensions (base64) { | |
var header = atob(base64.slice(22, 70)).slice(16, 24); | |
var uint8 = Uint8Array.from(header, function (c) { | |
return c.charCodeAt(0); | |
}); | |
var dataView = new DataView(uint8.buffer); | |
return { | |
width: dataView.getInt32(0), | |
height: dataView.getInt32(4), | |
}; | |
} | |
// Public interface | |
var screenshotService = { | |
/** | |
* Screenshots each element, concatenates them into a file, and downloads it | |
* @param {NodeList} nodeList | |
* @param {string} name what to name the file | |
*/ | |
download: function (nodeList, name) { | |
var report = createNewReport(name); | |
// convert to Array so we can use Array methods | |
var elements = Array.prototype.slice.call(nodeList); | |
var canvasPromises = elements.map(function (element) { | |
return html2canvas(element); | |
}); | |
Promise.all(canvasPromises) | |
.then(function (canvases) { | |
var images = canvases.map(function (canvas) { | |
return canvas.toDataURL(); | |
}); | |
var imagePromises = images.map(function (image) { | |
return report.addImage(image); | |
}); | |
return imagePromises; | |
}) | |
.then(function () { | |
report.download(); | |
}) | |
.catch(function (error) { | |
console.error('[screenshotService]', 'Failed to screenshot and download provided elements', { | |
elements: elements, | |
error: error, | |
}); | |
}); | |
}, | |
}; | |
// Example usage | |
var elementsToScreenshot = document.querySelectorAll('.screenshot-content'); | |
var fileName = 'Page Data.pdf'; | |
screenshotService.download(elementsToScreenshot, fileName); |
On Safari, trying to download multiple times brings an errorType error regarding Uint8Array.from().
I changed getPngDimensions() to this and fixed it:
const getPngDimensions = (base64: string) => {
const img = new Image()
img.src = base64
return {
width: img.width,
height: img.height,
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
if (printHeight > PAGE_HEIGHT) {
var img = new Image();
img.onload = splitImage(img, content, resolve);
img.src = image;
return; // remove
}
remove return statement from add image function .
OtherWise Pdf is empty due to no content is pushed on content array.