Reputation: 1115
I'm convert html to pdf using jspdf. I'm using addHTML method to convert html page in to pdf
var htmlSource = $('#body')[0];
function crate (){
var pdf = new jsPDF('p','px');
pdf.addHTML(
htmlSource,10, 10, {pagesplit: true, margin: {top: 10, right: 10,bottom: 10, left: 10, useFor: 'page'}},
function(dispose){
pdf.save('datapdf.pdf');
}
);
}
and I want add header and footer on all pages either leave blank space for header and footer. but using option I can only leave header space on first page of pdf.
Upvotes: 9
Views: 25421
Reputation: 351
In React you can do following:
Check this official repo to change jspdf-autotable generator class.
More over you can use header image but you need to convert it to base64 format. Convert image to base64 online service.
Also you can use my pdf class to generate a proper pdf report with js-pdf and autotable plugins in typescript:
import jspdf from "jspdf";
import autoTable from "jspdf-autotable";
// Main assets of our custom jspdf.
// It's very important to import this font assets.
import CustomPDFFont from "../assets/make_pdf_assets/Font";
import CustomHeadingImg from "../assets/make_pdf_assets/HeadingImage";
import colors from "../config/colors";
export default class ExportPdf {
document: any;
isValueAdded: boolean;
pageSize: any;
pageHeight: any;
pageWidth: any;
createdAt: string;
constructor() {
this.isValueAdded = false;
this.document = new jspdf("p", "px");
this.document.addFileToVFS("font_name.ttf", CustomPDFFont);
this.document.addFont(
"font_name.ttf",
"font_face_name",
"normal"
);
this.document.setFont("font_face_name");
// jsPDF 1.4+ uses getWidth, <1.4 uses .width
this.pageSize = this.document.internal.pageSize;
this.pageHeight = this.pageSize.height
? this.pageSize.height
: this.pageSize.getHeight();
this.pageWidth = this.pageSize.width
? this.pageSize.width
: this.pageSize.getHeight();
this.createdAt = "Mamad Steve";
}
/** Set header Logo */
private _setHeaderLogo = (data: any) => {
this.document.addImage(
CustomHeadingImg, // Use base64 format
"png",
data.settings.margin.left,
20, // Y distance
70, // Width size
20 // Height size
);
};
/** Set date and time of exported report */
private _setDateTime = () => {
const date: Date = new Date();
// Set date time at header
let reportDate: string = [
date.getFullYear(),
date.getMonth(),
date.getDay(),
].toString();
let reportTime: string = [
date.getHours(),
date.getMinutes(),
date.getSeconds(),
].toString();
// Makes DateTime more readable: Date: 11/6/2023 Time: 11:25
reportDate = reportDate.replaceAll(",", "/");
reportTime = reportTime.replaceAll(",", ":");
this.document.setFontSize(10);
this.document.text(
`Date: ${reportDate} Time: ${reportTime}`,
this.pageWidth - 140,
50,
);
};
/** Set page number at footer */
private _setPageNum = (data: any) => {
// Set number in Footer of every page
const content = "Page " + this.document.internal.getNumberOfPages();
this.document.setFontSize(10);
this.document.text(
`${content}, By ${this.createdAt}`,
data.settings.margin.left,
this.pageHeight - 10
);
};
/**
* # Make custom `.pdf`
*
* Make custom `pdf` with **Grid** style, custom header with logo image,
* custom footer with page number.
*
* @param any[] data
* @param any[] columns
*
* @example
*
* const data = [["data0", "data1", "data2", ...], [...], ...]
* const column = ["field0", "field1", "field2", ...];
*
* this.addNewTableInPdf(data: data, columns: columns);
* */
public addNewTableInPdf = (data: any[], columns: any[]): void => {
autoTable(this.document, {
head: columns,
body: data,
theme: "grid",
styles: { font: "font_face_name", halign: "center" },
didDrawPage: (data) => {
/** At Header */
this._setHeaderLogo(data);
this._setDateTime();
/** At Footer */
this._setPageNum(data);
},
headStyles: { fillColor: colors.primary, textColor: "#fff" },
margin: { top: 50 },
});
};
}
This class is my own, it works well but maybe it is not clean to another developers. But result is:
Upvotes: 1
Reputation: 1
pdf()
{
var margin= [9,9,9,9];
var ptbdel=11;
var rem=0;
var invoiceNumber= this.orderDetail.invoiceNumber;
var count =this.orderDetail.orderItems.length;
debugger
if(count>3)
{
margin=[10, 10, 10, 10]
ptbdel=12;
}
var doc = new jsPDF('l','mm',"a4",);
doc.html(document.getElementById('contentpopup')!, {
autoPaging:"text",
callback: function (doc) {
let i=doc.internal.pages.length-1
rem=i-ptbdel;
while(i>=(rem))
{
doc.deletePage(i)
i--;
}
for(let i = 1 ; i<=doc.internal.pages.length;i++)
{
doc.setPage(i)
doc.setFontSize(8)
doc.text("Page "+doc.getCurrentPageInfo().pageNumber+" of "+(rem-1),270,5)
}
doc.save(invoiceNumber+'.pdf');
},
margin: margin,
html2canvas: {
scale: .25, //you have to adjust to your size
},
});
}
Adjust Scale That Best Fits in Your Scenario.
Upvotes: 0
Reputation: 55
let doc = new JsPDF('p', 'pt', 'a4')
doc.html(componentRef.current, {
callback: function (pdf) {
//pdf.setFontSize(10)
let totalPages = pdf.internal.pages.length-1
for (let i = 1; i <= totalPages; i++) {
pdf.setPage(i);
// pdf.setFontSize(10);
// pdf.setTextColor(150);
pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100, pdf.internal.pageSize.getHeight() - 30);
}
pdf.save(
`delivery-${deliveryDate}.pdf`
)
},
margin: [10, 0, 55, 0],
autoPaging: "text",
})
Upvotes: 3
Reputation: 2337
If someone still looking for the short solution, you can try this,
For the footer as number of page,
html2pdf().from(element).set(opt).toPdf().get('pdf').then(function (pdf) {
var totalPages = pdf.internal.getNumberOfPages();
for (i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(150);
pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100, pdf.internal.pageSize.getHeight() - 30);
}
}).save();
For the header, you can write
pdfObject.text("my header text", 10, 10)
this will create the header text as my header text
in each page position x=10, y=10.
Upvotes: 4
Reputation: 96
One approach could be to refill the html page rendering in the client browser so as to display it exactly as you want it to be printed in the pdf (then simply use the function you just created above), therefore in a format composed by a series of vertical elements like h, p1, f, h, p2, f, h, p3, f, etc (where h=header, p1 ... pn are the pages and f=footer) instead of a series containing just h, p1, p2, p3, ... , pn, f (as is now).
This means that you might have access to the source code of the html page (so it's not just a page taken from the internet), because if it's an external resource maybe the dimensions of the header and footer are programatically constructed as to also fill spaces in relation with other elements of the page (and I think here of flex / applied vertically / or grid technologies in rendering the webpage).
Another aspect, if going to do this method, is that maybe the split in content is not always possible (and I'm not thinking here about destroying tables or other multi-page elements visible only when using the scrolling), but also the rendering might take into consideration the vertical display of the page (opposite to landscape mode as in desktop) in order to redraw the elements from the page. That sometimes could make the footer and header maybe larger, so I'm not sure why you would want to spend parts of valuable estate of the final printed page by doing that. (The solution would be possibly to open a new window, thus re-rendering the page in the new format, maybe even behind the existing page, then launch the print confirmation / or download the file / before closing that respective page.)
The other way would be to change the function so to work with a virtual rendering of the page (no displayed page) - by making the changes into your function and not in the rendering itself.
However, that second approach present also a few challenges, too. Initially, at declaring the variable 'var pdf' this is created as a unique data storage container, then you assign to it the constructor ( var pdf = new jsPDF('p','px'); ). However on the next step you add to it a HTML content (pdf.addHTML) which is a single element, not a multiple entity. You should change the function in order to make it print an array where you first calculate the elements based on the dimensions of pages rendered.
Maybe the code would become something as :
var fullpage, onepage, headd, foott, edges, contentt, he, fo, c, pages;
fullpage = document.body.scrollHeight; // height of all html page (not just the visible content)
onepage = 1200; // height of each single page printed in pdf - in pixels
headd = document.getElementById("header");
he = headd.offsetHeight;
foott = document.getElementById("footer");
fo = foott.offsetHeight;
edges = he + fo;
contentt = onepage - edges; // height of content of each page printed
pages = [0]; // start to work with first page which obviously is there
fullpage -= onepage; // remove height of first printed page (containg both header and footer)
pdf.addHTML( // create first page of pdf file
htmlSource, 10, 10, {pagesplit: true, margin: {top: 10, right:
10, bottom: 10, left: 10, useFor: 'page'}},
function(dispose){
pdf.save('datapdf.pdf');
}); // this is your code
var i = 0; // start the counter
while(fullpage > 0) { // start adding header + footer to remaining pages
fullpage += edges; // if there is still a page 2...n we add edges, etc.
i++;
pages[i] = content(onepage) { // here you must insert the code for harvesting the n-st page content from your source code
return htmlSource;
}
function addPages(i) {
var eachpdf = "datapdf" + i + ".pdf";
// <= here goes again your code, with a small change
// pagesplit: false - instead of true, in order to speed the process, and also
// pdf.save(eachpdf); - instead of pdf.save('datapdf.pdf');
}
}
What you try to achieve is to create a series he, p1, fo, he, p2, fo, he, p3, fo, etc (where he=header, p1 ... pn are the pages / named datapdfi above / and fo=footer) instead of a series containing just h, p1, p2, p3, ... , pn, f.
This means you must construct an array containing separate pdf pages as explained in code above.
I didn't yet create for you the code for separating the content of each page (which might return the htmlSource) however this is in strict dependence with the way in which your pages are rendered.
Upvotes: 6
Reputation: 222522
There is a suggested method use HTML's elements <header>
and <footer>
for that purpose, for example:
<footer>
<div style='text-align:center;'>Page <span class="pageCounter"></span>/<span class="totalPages"></span></div>
</footer>
See https://github.com/MrRio/jsPDF/pull/260
Upvotes: 3