Instantly share code, notes, and snippets.

Embed
What would you like to do?
Split image for pdfMake
const PAGE_HEIGHT = 700;
const PAGE_WIDTH = 500;
const content = [];
function getPngDimensions (base64) {
const header = atob(base64.slice(22, 70)).slice(16, 24);
const uint8 = Uint8Array.from(header, c => c.charCodeAt(0));
const dataView = new DataView(uint8.buffer);
return {
width: dataView.getInt32(0),
height: dataView.getInt32(4)
};
}
const splitImage = (img, content, callback) => () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const printHeight = img.height * PAGE_WIDTH / img.width;
canvas.width = PAGE_WIDTH;
for (let 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();
};
function next () {
/* add other content here, can call addImage() again for example */
pdfMake.createPdf({ content }).download();
}
function addImage () {
/* Load big image */
const image = 'data:image/png;base64,iVBORw0Kgo…';
const { width, height } = getPngDimensions(image);
const printHeight = height * PAGE_WIDTH / width;
if (printHeight > PAGE_HEIGHT) {
const img = new Image();
img.onload = splitImage(img, content, next);
img.src = image;
return;
}
content.push({ image, margin: [0, 5], width: PAGE_WIDTH });
next();
}
addImage();
@HarshSaudagar

This comment has been minimized.

Copy link

HarshSaudagar commented Jan 3, 2018

function getPngDimensions (base64) {
    const header = atob(base64.slice(22, 70)).slice(16, 24);
    const uint8 = Uint8Array.from(header, c => c.charCodeAt(0));
    const dataView = new DataView(uint8.buffer);

    return {
        width: dataView.getInt32(0),
        height: dataView.getInt32(4)
    };
}

New to Javascript and web deveIopment. I didn't understand what this function does exactly? Could please explain ?
Especially const header = atob(base64.slice(22, 70)).slice(16, 24);.

Thanks in advance

@xreign

This comment has been minimized.

Copy link

xreign commented Apr 24, 2018

Any angularjs version of this?

@kriscoleman

This comment has been minimized.

Copy link

kriscoleman commented May 2, 2018

AngularJS should just work with this... it just runs JS and that's all this is.

@keego

This comment has been minimized.

Copy link

keego commented Jan 13, 2019

Thanks for the code and insight @Balkoth. The split image definitely splits the image well and puts the different parts on different pages, but I noticed the image quality noticeably degraded. When using images small enough where splitImage was not needed, quality seemed great. My project doesn't support ES6 so I had to convert this code to ES5, and I also decided to promisify things a bit, namely addImage but those were all the changes I made.

@keego

This comment has been minimized.

Copy link

keego commented Jan 15, 2019

Managed to work around the quality degradation issue by using html2canvas to snapshot many smaller nodes as opposed to the whole page at once. Then instead of having to split one big image, a bunch of the smaller images can be concatenated and naturally overflow to the next page. This gives the consumer better control of how a site can be split up into multiple pdf pages. I posted a forked gist for reference (note its ES5).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment