Skip to content

Instantly share code, notes, and snippets.

@keego
Forked from poissoj/splitImage.js
Last active June 9, 2021 19:40
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keego/983f14b0b79f45e4cc71d6928a25a40c to your computer and use it in GitHub Desktop.
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)
// 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);
@umerfarooqQC
Copy link

umerfarooqQC commented Oct 30, 2019

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.

@edwindelbosque
Copy link

edwindelbosque commented Jun 9, 2021

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