Reputation: 979
Is there any way to solve this? I tried to set width and height in mm. How can I set it to full-width?
Upvotes: 74
Views: 274769
Reputation: 21
I encountered the same issue when working with dom-to-image with jsPDF. I had an image from my html perfectly sized to match my A4 PDF, but upon downloading the PDF, the image is slightly blurry. To address this, I doubled the scale of the image, then fit it to my PDF size before generating.
const generatePDFfromHTML = async (htmlContentId: string, outputPath: string) => {
const input = document.getElementById(htmlContentId)
const scale = 2
if (!input) {
console.error(`HTML element with ID ${htmlContentId} not found.`)
return
}
const scaledWidth = input.offsetWidth * scale
const scaledHeight = input.offsetHeight * scale
try {
const dataUrl = await domtoimage.toPng(input, {
width: scaledWidth,
height: scaledHeight,
style: {
transform: "scale(" + scale + ")",
transformOrigin: "top left",
},
})
const pdf = new jsPDF()
const img = new Image()
img.src = dataUrl
img.onload = () => {
const pdfWidth = pdf.internal.pageSize.getWidth()
const pdfHeight = (img.height * pdfWidth) / img.width
pdf.addImage(dataUrl, "PNG", 0, 0, pdfWidth, pdfHeight)
pdf.save(outputPath)
}
} catch (error) {
console.error("Error generating PDF:", error)
}
}
Upvotes: 0
Reputation: 3665
The trick is to make the canvas close to the desired size.
const handleDownloadCertificate = async () => {
const domElement = document.getElementById('certificate');
if (domElement) {
try {
const canvas = await html2canvas(domElement, { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const componentWidth = domElement.clientWidth;
const componentHeight = domElement.clientHeight;
const ratio = componentHeight / componentWidth;
const width = 210; // in mm A4
let height = 297; // in mm A4
height = ratio * width;
const pdf = new JSPDF('p', 'mm', [width, height]);
pdf.addImage(imgData, 'JPEG', 0, 0, width, height);
const fileName = getCertificateName({ course, name });
pdf.save(`${fileName}.pdf`);
} catch (error) {
console.error('Error building PDF', error);
}
}
};
Upvotes: 1
Reputation: 348
Change the PDF page width to size of the image as follows
const exportOrgChartPdfFormat = async (response) => {
try {
const blob = new Blob([response.data], { // response.data contains blob
type: "image/png",
});
const reader = new FileReader();
reader.onloadend = () => {
const base64data = reader.result;
const img = new Image();
img.onload = function () {
const imgWidth = this.width;
const imgHeight = this.height;
const pdf = new jsPDF(
imgWidth > imgHeight ? "l" : "p",
"pt",
[imgWidth, imgHeight]
);
**pdf.internal.pageSize.width = imgWidth;**
**pdf.internal.pageSize.height = imgHeight;**
pdf.addImage(
base64data,
"PNG",
0,
0,
imgWidth,
imgHeight
);
pdf.save("export.pdf");
};
img.src = base64data;
};
reader.readAsDataURL(blob);
} catch (e) {
return e;
}
};
Upvotes: 0
Reputation: 45
Some answers above didn't cover responsive pages for html2canvas. If you need to resize your image based on changing element dimensions use this code:
html2canvas(input, { scrollY: -window.scrollY }).then((canvas) => {
const imgData = canvas.toDataURL('image/jpeg');
const pdf = new jsPDF('p', 'mm', 'a4');
const imgProps = pdf.getImageProperties(imgData);
// doc and image dimensions
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgWidth = imgProps.width;
const imgHeight = imgProps.height;
// claculating right scale to fit the page
const scale = Math.max(pdfHeight / imgHeight, pdfWidth / imgWidth);
const finalWidth = imgWidth * scale;
const finalHeight = imgHeight * scale;
const leftMargin = (pdfWidth - finalWidth) / 2;
// add image with alias and compression of your choice
pdf.addImage( imgData, 'PNG', leftMargin, 0, finalWidth, finalHeight, 'alias', 'FAST');
pdf.save( 'report-name.pdf' );
});
Upvotes: 3
Reputation: 890
If you need to get width 100% of PDF file and auto height you can use getImageProperties
property of html2canvas library
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
orientation: 'landscape',
});
const imgProps= pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('download.pdf');
});
Upvotes: 89
Reputation: 1
convertPhotoImageToPdf(imgPath){
var doc = new jsPDF(undefined, null, null, true);
var imgData = 'data:image/jpeg;base64,'+ imgPath;
doc.addImage(imgData, 'JPEG',10,10,0,0,null,'FAST',0);
//if want add one page
//doc.addPage()
doc.save('testPdf.pdf')
}
Upvotes: -1
Reputation: 1
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
Upvotes: -2
Reputation: 81
There where a lot of solutions with .addImage, I tried many of them, but nothing worked out. So I found the .html() function and after some tries the html2canvas-scale-option. This solution is no general solution, you have to adjust the scale so it will fit your pdf, but this is the only solution, which works for me.
var doc = new jspdf.jsPDF({
orientation: 'p',
unit: 'pt',
format: 'a4'
});
doc.html(document.querySelector('#styledTable'), {
callback: function (doc) {
doc.save('file.pdf');
},
margin: [60, 60, 60, 60],
x: 32,
y: 32,
html2canvas: {
scale: 0.3, //this was my solution, you have to adjust to your size
width: 1000 //for some reason width does nothing
},
});
Upvotes: 5
Reputation: 1139
my solution is to check what ratio (height or width) need to apply depending of the pdf orientation and image size. note: set margin to 0 if no margin is required.
const imgData = canvas.toDataURL("image/jpeg");
const pdf = new jsPDF({
orientation: "portrait", // landscape or portrait
unit: "mm",
format: "a4",
});
const imgProps = pdf.getImageProperties(imgData);
const margin = 0.1;
const pdfWidth = pdf.internal.pageSize.width * (1 - margin);
const pdfHeight = pdf.internal.pageSize.height * (1 - margin);
const x = pdf.internal.pageSize.width * (margin / 2);
const y = pdf.internal.pageSize.height * (margin / 2);
const widthRatio = pdfWidth / imgProps.width;
const heightRatio = pdfHeight / imgProps.height;
const ratio = Math.min(widthRatio, heightRatio);
const w = imgProps.width * ratio;
const h = imgProps.height * ratio;
pdf.addImage(imgData, "JPEG", x, y, w, h);
Upvotes: 3
Reputation: 111
Solution for all screen sizes and dynamic orientation:
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
export default async function downloadComponentInPDF(Component: HTMLElement) {
await html2canvas(Component).then((canvas) => {
const componentWidth = Component.offsetWidth
const componentHeight = Component.offsetHeight
const orientation = componentWidth >= componentHeight ? 'l' : 'p'
const imgData = canvas.toDataURL('image/png')
const pdf = new jsPDF({
orientation,
unit: 'px'
})
pdf.internal.pageSize.width = componentWidth
pdf.internal.pageSize.height = componentHeight
pdf.addImage(imgData, 'PNG', 0, 0, componentWidth, componentHeight)
pdf.save('download.pdf')
})
}
Upvotes: 11
Reputation: 5535
This is how I've achieved in Reactjs.
Main problem were ratio and scale If you do a quick window.devicePixelRatio, it's default value is 2 which was causing the half image issue.
const printDocument = () => {
const input = document.getElementById('divToPrint');
const divHeight = input.clientHeight
const divWidth = input.clientWidth
const ratio = divHeight / divWidth;
html2canvas(input, { scale: '1' }).then((canvas) => {
const imgData = canvas.toDataURL('image/jpeg');
const pdfDOC = new JSPDF("l", "mm", "a0"); // use a4 for smaller page
const width = pdfDOC.internal.pageSize.getWidth();
let height = pdfDOC.internal.pageSize.getHeight();
height = ratio * width;
pdfDOC.addImage(imgData, 'JPEG', 0, 0, width - 20, height - 10);
pdfDOC.save('summary.pdf'); //Download the rendered PDF.
})
}
Upvotes: 3
Reputation: 2610
If you want a dynamic sized image to automatically fill the page as much as possible and still keep the image width/height-ratio, you could do as follows:
let width = doc.internal.pageSize.getWidth()
let height = doc.internal.pageSize.getHeight()
let widthRatio = width / canvas.width
let heightRatio = height / canvas.height
let ratio = widthRatio > heightRatio ? heightRatio : widthRatio
doc.addImage(
canvas.toDataURL('image/jpeg', 1.0),
'JPEG',
0,
0,
canvas.width * ratio,
canvas.height * ratio,
)
Upvotes: 9
Reputation: 1191
A better solution is to set the doc width/height using the aspect ratio of your image.
var ExportModule = {
// Member method to convert pixels to mm.
pxTomm: function(px) {
return Math.floor(px / $('#my_mm').height());
},
ExportToPDF: function() {
var myCanvas = document.getElementById("exportToPDF");
html2canvas(myCanvas, {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/jpeg', 1.0);
//Get the original size of canvas/image
var img_w = canvas.width;
var img_h = canvas.height;
//Convert to mm
var doc_w = ExportModule.pxTomm(img_w);
var doc_h = ExportModule.pxTomm(img_h);
//Set doc size
var doc = new jsPDF('l', 'mm', [doc_w, doc_h]);
//set image height similar to doc size
doc.addImage(imgData, 'JPG', 0, 0, doc_w, doc_h);
var currentTime = new Date();
doc.save('Dashboard_' + currentTime + '.pdf');
}
});
},
}
<script src="Scripts/html2canvas.js"></script>
<script src="Scripts/jsPDF/jsPDF.js"></script>
<script src="Scripts/jsPDF/plugins/canvas.js"></script>
<script src="Scripts/jsPDF/plugins/addimage.js"></script>
<script src="Scripts/jsPDF/plugins/fileSaver.js"></script>
<div id="my_mm" style="height: 1mm; display: none"></div>
<div id="exportToPDF">
Your html here.
</div>
<button id="export_btn" onclick="ExportModule.ExportToPDF();">Export</button>
Upvotes: 1
Reputation: 3997
It's easy to fit the page if you only have one image. The more challenge task is to fit images with various sizes to a pdf file. The key to archive that is to calculate the aspect ratio of the image and relative width/height ratio of the page. The following code is what I used to convert multiple images online to a PDF file. It will rotate the image(s) based on the orientation of the images/page and set proper margin. My project use images with online src. You should be able to modify to suit your needs.
As for image rotation, if you see a blank page after rotation, it could simply be that the image is out of bounds. See this answer for details.
function exportPdf(urls) {
let pdf = new jsPDF('l', 'mm', 'a4');
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const pageRatio = pageWidth / pageHeight;
for (let i = 0; i < urls.length; i++) {
let img = new Image();
img.src = urls[i];
img.onload = function () {
const imgWidth = this.width;
const imgHeight = this.height;
const imgRatio = imgWidth / imgHeight;
if (i > 0) { pdf.addPage(); }
pdf.setPage(i + 1);
if (imgRatio >= 1) {
const wc = imgWidth / pageWidth;
if (imgRatio >= pageRatio) {
pdf.addImage(img, 'JPEG', 0, (pageHeight - imgHeight / wc) / 2, pageWidth, imgHeight / wc, null, 'NONE');
}
else {
const pi = pageRatio / imgRatio;
pdf.addImage(img, 'JPEG', (pageWidth - pageWidth / pi) / 2, 0, pageWidth / pi, (imgHeight / pi) / wc, null, 'NONE');
}
}
else {
const wc = imgWidth / pageHeight;
if (1 / imgRatio > pageRatio) {
const ip = (1 / imgRatio) / pageRatio;
const margin = (pageHeight - ((imgHeight / ip) / wc)) / 4;
pdf.addImage(img, 'JPEG', (pageWidth - (imgHeight / ip) / wc) / 2, -(((imgHeight / ip) / wc) + margin), pageHeight / ip, (imgHeight / ip) / wc, null, 'NONE', -90);
}
else {
pdf.addImage(img, 'JPEG', (pageWidth - imgHeight / wc) / 2, -(imgHeight / wc), pageHeight, imgHeight / wc, null, 'NONE', -90);
}
}
if (i == urls.length - 1) {
pdf.save('Photo.pdf');
}
}
}
}
If this is a bit hard to follow, you can also use
.addPage([imgWidth, imgHeight])
, which is more straightforward. The downside of this method is that the first page is fixed bynew jsPDF()
. See this answer for details.
Upvotes: 6
Reputation: 2793
You can get the width and height of PDF document like below,
var doc = new jsPDF("p", "mm", "a4");
var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight();
Then you can use this width and height for your image to fit the entire PDF document.
var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJ......';
doc.addImage(imgData, 'JPEG', 0, 0, width, height);
Make sure that your image has the same size (resolution) of the PDF document. Otherwise it will look distorted (stretched).
If you want convert px
to mm
use this link http://www.endmemo.com/sconvert/millimeterpixel.php
Upvotes: 140
Reputation: 429
My answer deals with a more specific case of what you are asking but I think one could draw some ideas from this to apply more generally. Also, I would post this as a comment to Purushoth's answer (on which mine is based), if only I could.
Ok, so my problem was how to fit a web page into the pdf document, without losing the aspect ratio. I used jsPDF in conjuction with html2canvas and I calculated the ratio from my div
's width and height. I applied that same ratio to the pdf document and the page fit perfectly onto the page without any distortion.
var divHeight = $('#div_id').height();
var divWidth = $('#div_id').width();
var ratio = divHeight / divWidth;
html2canvas(document.getElementById("div_id"), {
height: divHeight,
width: divWidth,
onrendered: function(canvas) {
var image = canvas.toDataURL("image/jpeg");
var doc = new jsPDF(); // using defaults: orientation=portrait, unit=mm, size=A4
var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight();
height = ratio * width;
doc.addImage(image, 'JPEG', 0, 0, width-20, height-10);
doc.save('myPage.pdf'); //Download the rendered PDF.
}
});
Upvotes: 27
Reputation: 71
i faced same problem but i solve using this code
html2canvas(body,{
onrendered:function(canvas){
var pdf=new jsPDF("p", "mm", "a4");
var width = pdf.internal.pageSize.getWidth();
var height = pdf.internal.pageSize.getHeight();
pdf.addImage(canvas, 'JPEG', 0, 0,width,height);
pdf.save('test11.pdf');
}
})
Upvotes: 1
Reputation: 999
The API changed since this commit, using version 1.4.1 it's now
var width = pdf.internal.pageSize.getWidth();
var height = pdf.internal.pageSize.getHeight();
Upvotes: 11
Reputation: 310
I discovered this while experimenting with html2canvas this morning. While this doesn't include provisions for printing multiple pages it does scale the image to page width and reframes the height in ratio to the adjusted width:
html2canvas(document.getElementById('testdiv')).then(function(canvas){
var wid: number
var hgt: number
var img = canvas.toDataURL("image/png", wid = canvas.width, hgt = canvas.height);
var hratio = hgt/wid
var doc = new jsPDF('p','pt','a4');
var width = doc.internal.pageSize.width;
var height = width * hratio
doc.addImage(img,'JPEG',20,20, width, height);
doc.save('Test.pdf');
});
Upvotes: 18