43

I am using jspdf for creating PDF inside browser. I am having multiple charts having svg as chart Data. For adding data to pdf I am converting svg to png using canvas and then Base64 Data using canvas.toDataURL method. After all this conversions size of the file created by jspdf is huge (about 50 MB). Below is the code for div of chart data and canvas.

newdiv = document.createElement("div");
newdiv.className = "big_Con_graph big_Con_graph0";
newdiv.style.height = "0px";
newdiv.id = "big_Con_graph" + id;

below is the dimensions for SVG chart load.

document.getElementById("big_Con_graph" + id).style.display = "block";
var big_chartReference = FusionCharts("big_myChartId"+id);
if(big_chartReference != null){
    big_chartReference.dispose();
}
var big_width = "1088";
var big_height = "604";

now below is the code for conversion of above graph SVG data and adding to PDF.

var elem_graph = $($('.big_Con_graph,big_Con_graph0')[count]).clone(true);
svgString = $(elem_graph).find("span").html();
var img = document.createElement('img');
var DOMURL = self.URL || self.webkitURL || self;
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = pdfAfterImageLoad(img,pdf,imgLoadSequence,DOMURL,totalReports,reportName);
img.src = url;

this is the code for PDFAfterImageLoad function:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var png = canvas.toDataURL("image/png");
pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270);

I am using png, so imagequality parameter can not be used.

Can anyone help me decrease the file size?

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
Asha Koshti
  • 2,763
  • 4
  • 22
  • 30
  • Do you convert to base64 because jspdf requires that? – YakovL Jun 08 '16 at 09:50
  • i dont have image stored at my end by clicking of button i m getting svg data and converting it to png by canvas,so the whole process requires base64 data.even i can't store all graph data at client storage. – Asha Koshti Jun 13 '16 at 10:29
  • I see. And why are you using png instead of jpeg? Using jpeg with quality modifier would have helped (see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) – YakovL Jun 13 '16 at 12:31
  • yes but jpeg gives poor quality as used with quality parameter also.even i want to zoom in and zoom out with pdf which is not possible with jpeg. – Asha Koshti Jun 14 '16 at 05:44
  • 1
    What are the dimensions of this image? Can you show us what the image contains/does it apply to any image you add? Can you show us the code you use to add it to jspdf? (and your onload callback is used in the wrong way, should a function reference; now it's a call using the result of that for onload). –  Jun 14 '16 at 19:15
  • Thanks for the update. It still a bit unclear what the pdfAfterImageLoad is doing. And as I mentioned above it is used incorrectly. It is now called and the result of it (which may be none) is set as the handler function to onload. Also, if the image does not load in time drawImage will fail below. The drawing operations need to be inside (or invoked from) the onload handler function. –  Jun 15 '16 at 21:12
  • @K3N i have appended the code for pdfafter image load as it just add the image on pdf.nothing else – Asha Koshti Jun 16 '16 at 04:50
  • I reckon you will have to use `image/jpeg` and test possible and suitable quality parameter! – Rayon Jun 16 '16 at 07:10

6 Answers6

97

You need to compress the images in the PDF's that you are generating. Try using Deflate.js and adler32cs.js and use the compress parameter in both jsPDF and addImage functions that you are using. For eg :

var doc = new jsPDF('p', 'pt','a4',true);

make sure you set the last parameter as 'true' refer to : https://github.com/MrRio/jsPDF/blob/ddbfc0f0250ca908f8061a72fa057116b7613e78/jspdf.js#L146

Go through it and you can clearly see that the last parameter is for enabling compression.

Also use :

pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270,'','FAST');

instead of

pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270);

you can choose between NONE, FAST, MEDIUM and SLOW, whichever suits you best.

hkm93
  • 1,240
  • 9
  • 14
  • this works. Am getting one border line at the bottom - using jspdf addimag. how to remove that line – Shalini Jan 18 '17 at 10:44
  • anyway the horizontal line is not printed on the paper. – Shalini Jan 20 '17 at 08:49
  • I am creating pdf from a custom graph. I am able to generate pdf using jspdf. But color of graph and font color from the web page are replicating on the pdf. (box-shadow effect is missing from graph and graph is looking blur). How can i fix it.? – Curious Developer Jan 31 '17 at 06:23
  • @HemantKumar can you give the link with the jsfiddle.so i can guide you with the solution..actually svg that charts generates creates the problem.we need to eliminate some tag or correct it, – Asha Koshti Feb 03 '17 at 09:28
  • Ok. Sure I'll try to jsfiddle it. I'll figure out how to set it in jsfiddle. – Curious Developer Feb 03 '17 at 14:19
  • why didn't it work for chrome? although it worked before without compressing pdf as you solution said. – Hana90 Mar 12 '18 at 13:17
  • This is not working, tested in Edge and Firefox, adding compression changes nothing, Im not using node.js – Daniel Jul 16 '21 at 12:25
  • 1
    Hi @Daniel I'm sure the OP doesn't make use of node.js either. As for the solution provided, it works for the scenario mentioned in the post, i.e decreasing the size of a png using compression in the addImage(). If your problem is different and if you are using jpeg, please use the compression as suggested in a couple of other solutions. Just be mindful that using compression with jpeg will result in poor image quality but will cut down on the pdf drastically. – hkm93 Jul 28 '21 at 05:49
  • for real? 28 MB to 300Kb – amitdigga Jun 17 '23 at 09:52
23

If you add several images to one document, use

pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270, undefined,'FAST');

not

pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270,'','FAST');

otherwise the first image will substitute all others.

Andrew Hudik
  • 331
  • 2
  • 3
  • yes..it was just example given,, pdf.addImage(png, 'PNG', leftmargin, 120, 485, 270, undefined,'FAST'); in that undefined one,you have to specify different name everytime whenever you add the image.as per API it is the Alias name.which has to be unique per image. – Asha Koshti Jan 06 '17 at 07:07
  • 1
    Just jumping on to say the above example also reduced my 4Mb PDF (11 pages, with 10 charts per page) down to 977kb. Thank you so much for this tip! – JasonMHirst Nov 21 '17 at 06:42
  • I have tried doc.addImage(imgData, "JPEG", 140, 15, 300, 300, "alias1",undefined, 'SLOW'); but I am getting error Uncaught Error: getJpegSize could not find the size of the image – Naren Verma Jun 02 '23 at 11:51
4

Perfect. PDF size 90mb to 3mb with great quality.

pdf.addImage(png, 'PNG', 0, 0, 485, 270, undefined,'FAST');

1

In my case did not work with compress parameter. So, I resized the current image on my own with the following function:

function resizeBase64Img(base64, width, height) {
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var context = canvas.getContext("2d");
    var deferred = $.Deferred();
    $("<img/>").attr("src", "data:image/gif;base64," + base64).load(function() {
        context.scale(width/this.width,  height/this.height);
        context.drawImage(this, 0, 0); 
        deferred.resolve($("<img/>").attr("src", canvas.toDataURL()));               
    });
    return deferred.promise();    
}

And call it as follows:

//select my image in base64
var imageStr64 = "/9j/4RiDRXhpZgAATU0AKgA...";
//resize image, add image and create the pdf
resizeBase64Img(imageStr64, 1000, 1000).then(function(newImg){
    doc.addImage($(newImg).attr('src'), 15, 90, 180,180);
    doc.save('mypdf.pdf');
});

You can play with 'width' and 'height' parameters in resizeBase64Img function in order to generate heavy pdf with better or worst image quality.

mikemaal
  • 317
  • 3
  • 6
0

Have you tried canvg? It's not very likely that it will decrease the filesize, but at least you can try.

See a snippet in this reply.

Community
  • 1
  • 1
YakovL
  • 7,557
  • 12
  • 62
  • 102
0

I've tried the compress parameter and passing compression:'MEDIUM' toe the addImage method as suggested but nothing happened

What worked for me was converting the canvas to DataUrl base64 string and passing a compression value

pdf.addImage({ imageData: canvas.toDataURL('image/jpeg', 0.6),format: 'JPEG', x: 2, y: 100, width: newImageWidth, height: newImageHeight});

This way the image is compressed before it is added to the PDF

Daniel
  • 2,780
  • 23
  • 21