I am creating a large HTML table and I have problem with page breaks as you can see in the following image:
Is there a method settle down the problem automatically? Or what is the way to do it?
Try adding this to your <tr> tags: nobr="true".
So a quick example would be:
<table>
<tr nobr="true">
<td>Test</td>
<td>Test 2</td>
</tr>
</table>
The nobr="true" prevents the table rows from ever breaking apart. You can also put this on <td> and <th> tags.
I know it's rather old question, but I had this same issue today, my table was splitted between pages and I investigated a little bit further on the method from FastTrack's answer and it turned out that you can also use the nobr="true" attribute also to the <table> tag. That is, for me such code solved this problem:
<table nobr="true">
<tr>
<td>Test</td>
<td>Test 2</td>
</tr>
</table>
Warning - this code makes sense only when your tables are smaller than one page.
I had the same problem with overlapping headers.
I tried yevgeny solution, but that required some more editions to my PDF generator code (I have lots of PDFs outputs written in FPDF and I wanted to minimize the process of miograting them to TCPDF), so I used this more simple solution
class MYPDF extenfs TCPDF {
//your initialization code
function header(){
//your code here
//we change only the top margin and this executes for every header in every page, even the frst one
$this->SetTopMargin($this->GetY());
}
}
roney, thank you so much, writing HTML generated overlaps with the header for pages 2,3 .. this worked for me:
class your_PDF extends TCPDF
{
var $top_margin = 20;
function Header() {
// set top margin to style pages 2, 3..
//title goes here
$this->top_margin = $this->GetY() + 5; // padding for second page
}
}
in your code
// set top margin to style pages 2, 3..
$pdf->SetMargins(15, $pdf->top_margin, 15);
For the interested, just do as follows and it will work like a charm:
$pdf->SetMargins(0, 0, 0);
$pdf->SetHeaderMargin(0);
$pdf->SetFooterMargin(0);
Strangely enough the solutions mentioned here didn't work for me. Well, it did sortof, but content inside of tags would get repeated (as desired) but would then cause layout issues for the cell above or below if it was rowspanned. As I experimented, it just got worse.
My solution, while inelegant, was to set AutoPageBreak to false, put a row incrementer counter up, incrementing for each row, then checked if it had exceeded a certain value. If so, I closed the table, used writeHTML(), called addPage() and then continued , having rebuilt it as a new table, headers and all.
Like I said, inelegant, but it worked. I hope this helps someone ... it's a fairly obvious solution but execution is not always quite so obvious. Also, there may be a better way that works for your particular situation, but if it doesn't, give mine a try. :)
Some CSS solved for me:
// Include the main TCPDF library (search for installation path).
require_once('tcpdf/tcpdf.php');
// create new PDF document
$pdf = new TCPDF('R', PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Author');
$pdf->SetTitle('TCPDF HTML Table');
$pdf->SetSubject('TCPDF Tutorial');
$pdf->SetKeywords('TCPDF, PDF, html,table, example, test, guide');
// set default header data
$pdf->SetHeaderData('', '', ' HTML table', '');
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
//$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(15, 15, 15);
$pdf->SetHeaderMargin(15);
$pdf->SetFooterMargin(15);
// set auto page breaks
$pdf->SetAutoPageBreak(TRUE, 15);
// set image scale factor
//$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
// ---------------------------------------------------------
// set font
$pdf->SetFont('times', '', 10);
// add a page
$pdf->AddPage();
$start = 1;
$end = 254;
$step = 1;
$arr = range($start, $end, $step);
$table_header .= sprintf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>", 'IP', 'Computer', 'User', 'Fone');
foreach ($arr as $ar) {
$row[] = $ar;
}
foreach ($row as $r):
if (($r % 40) === 0):
$table_header;
endif;
$table .= sprintf("<tr>\n<td>%s</td>\n<td>%s</td>\n<td>%s</td>\n<td>%s</td>\n</tr>\n", $r, $r, $r, $r);
endforeach;
$now = date("d/m/Y");
$caption = "<caption>IP addresses <em>$now</em></caption>\n";
$n = "\n";
$tbl = <<<EOD
<style>
table{
font-family: serif;
font-size: 11pt;
}
table tr {
}
table tr td {
padding:3px;
border:#000000 solid 1px;
}
em {
font-size: 4pt;
}
tr { white-space:nowrap; }
</style>
<h1>{$caption}</h1>
{$table_begin}
{$table_header}
{$table}
</table>
EOD;
$pdf->writeHTML($tbl, true, false, false, false, '');
// reset pointer to the last page
//$pdf->lastPage();
// ---------------------------------------------------------
//Close and output PDF document
$pdf->Output('html_table.pdf', 'I');
//============================================================+
// END OF FILE
//============================================================+
have you tried
<table>
<thead>
<tr>
<td>
This is my header which appears on every page
</td>
</tr>
</thead>
<tr>
<td>
My Content
</td>
</tr>
</table>
I'm using smarty, with this you have more possibilities to manually break the table (e.g. if you're using borders). If needed, i'll post this, too...
Related
I'm generating some reports on my admin and I'm exporting to PDF using the MPDF library. But when this has a very large amount of data, MPDF is resizing the table to fit on page, so that it becomes awkward.
Is there any way to prevent this from happening? The code I am using to generate is the below. I've tried to set "shrink_tables_to_fit" to 0 and 1, both unsuccessful. Also tried to set autosize=1 to every table.
$stylesheet = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/site/css/layout/pdf.css');
$bootstrap = file_get_contents('https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css');
$mpdf = new mPDF('pt', 'a4');
$mpdf->shrink_tables_to_fit = 1;
$mpdf->setAutoTopMargin = 'stretch';
$mpdf->setAutoBottomMargin = 'stretch';
$mpdf->SetHTMLHeader('<img src="'.$_SERVER['DOCUMENT_ROOT'].'/site/img/content/pdf/header.jpg">');
$mpdf->SetFooter('{DATE j/m/Y H:i}|{PAGENO}/{nb}');
$mpdf->WriteHTML($bootstrap, 1);
$mpdf->WriteHTML($stylesheet, 1);
$mpdf->WriteHTML($html);
$mpdf->Output($_SERVER['DOCUMENT_ROOT'].'/upload/consultas-pre/'.$nomeArquivo.'.pdf', 'F');
You can split the entire table into different tables and at end of the each table add :
<div style="page-break-after: always;"> </div>
Which will create a page break.
Example :
<?php $rows=1; foreach($allData as $data){ ?>
<table>
<tr>
<td>Your table data</td>
</tr>
</table>
<?php if($row == 10) { ?>
<div style="page-break-after: always;"> </div>
<?php } ?>
<?php } ?>
You can read more about mpdf page break here
I found it.
I can not have a table with other tables inside. When this happens, MPDF gets lost in resize.
I had the same issue. Tried everything I found on stackoverflow in different combinations: shrink_tables_to_fit, autosize="0", page-break-inside:..., overflow:..., etc...
In my case my table was inside the div that had position:absolute in its inline style. After I changed it to relative or removed position completely, the table is divided properly between pages.
Try this in the table opening tag:
<table autosize="1">
I am creating PDF file with custom structure/layout using TCPDF library. Data is coming from server side and data is being displayed data in tabular form in PDF file.
PDF structure should be look like this
Required PDF structure
Based on my code. PDF structure/PDF structure based on my code
Actually, I this this layout in PDF file
Sheet Size : 210x297 mm (A4)
Format 6 (Row) x 3 (Col)
Label Size : 63.5 x 46.6
Margins : Left 7 mm, Right 8 mm, Gutter 2 mm
Top 10.4 mm Bottom 7 mm
I am using sheet size like this
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, array('210', '297'), true, 'UTF-8', false);
I am using Label (First column) size like this. I don't know it's correct or not but it looks like correct.
$subhtml .= '<td border="0" width="63.5mm" height="46.6mm style="float:left;text-align:left;">
I am using Margins (Left, Right,Top) like this and I don't know how to give gutter (space between two columns)
$pdf->SetMargins(7, 10.4, 8);
Bottom 7 MM like this
$pdf->SetFooterMargin(7);
PROBLEMS
Left side space is not same as in required PDF structure file.
How to give gutter/space between two columns.
All above code are correct or not?
Complete Code
$sql = "SELECT * FROM Members where MemberId in (select MemberId from Normalized_Category where Category IN (".addQuotes($categories)."))";
$result = mysqli_query($conn, $sql);
while($rows = mysqli_fetch_assoc($result)){
$members[] = $rows;
}
$subhtml ='';
$i = 1;
$j = 3;
$html ='';
foreach($members as $value){
$subhtml .= '<td border="0" width="63.5mm" height="46.6mm" style="float:left;text-align:left;">
<span>'.$value['MemberId'].'</span>
<span style="float:right; text-align:right;">'.$value['Expiry_Date'].'</span>
<br/><b>
<span>'.$value['Salute'].' '.$value['Name'].'</span>
</b><br/>
<span>'.$value['Address1'].','.$value['Address2'].','.$value['Address3'].' </span>
<br/><span>'.$value['City'].' '.$value['PinCode'].' - '.$value['State'].'</span><br/>
<span>'.$value['Contact'].'</span><br/></td>';
if ($i % $j == 0) {
$subhtml .= '</tr><tr>';
}
$i++;
}
$tbl = <<<EOD
<table border="0" cellpadding="2" align="justify">
<tr nobr="true">
<th colspan="3"></th>
</tr>
<tr nobr="true">
$subhtml
</tr>
</table>
EOD;
require('tcpdf/tcpdf.php');
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, array('210', '297'), true, 'UTF-8', false);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetMargins(7, 10.4, 8); // left = 2.5 cm, top =
$pdf->SetFooterMargin(7);
if (#file_exists(dirname(__FILE__).'/lang/eng.php')) {
require_once(dirname(__FILE__).'/lang/eng.php');
$pdf->setLanguageArray($l);
}
$pdf->SetFont('helvetica', '', 9);
$pdf->AddPage();
$pdf->writeHTML($tbl, true, false, false, false, '');
$pdf->Output('Members.PDF', 'D');
I am using a custom Footer and have set its position with setY();. However, the content goes on behind my Footer, which means I needed to make my pagebreak higher. This resulted in messing up the size of my footer when I have more than one page.
My footer consists of tables with images inside. The thing that goes wrong, is that the images are getting weird sizes by some kind of scaling! The larger I make my setAutoPageBreak(), the more messed up my footer will become.
I've been at it for quite some hours. I hope someone can help me on this one.
My footer:
public function Footer() {
$footer = '<table>
<tr>
<td width="30" height="50"></td>
<td style="width: 570px; height: 55px;">
<img src="some_image" width="30" height="50" />
</td>
</tr>
</table>
';
$this->SetY(-60);
$this->writeHTML($footer, true, true, true, false, '');
}
TCPDF handling:
$pdf = new MyPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
set margins
$PDF_MARGIN_LEFT = 20;
$PDF_MARGIN_TOP = 40;
$PDF_MARGIN_RIGHT = 20;
$pdf->SetMargins($PDF_MARGIN_LEFT, $PDF_MARGIN_TOP, $PDF_MARGIN_RIGHT);
//LTRB
$PDF_MARGIN_HEADER = 5;
$PDF_MARGIN_FOOTER = 60;
$pdf->SetHeaderMargin($PDF_MARGIN_HEADER);
$pdf->SetFooterMargin($PDF_MARGIN_FOOTER);
// set auto page breaks, it also specifies margin-bottom. This scales the footer somehow...
$PDF_MARGIN_BOTTOM = 20;
$pdf->SetAutoPageBreak(true, $PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->AddPage();
// output the HTML content
$pdf->writeHTML($my_printed_html, true, false, true, false, '');
$pdf->Output('Test.pdf', 'I');
Editted:
I noticed the problem only occurs if my footer is below the pagebreak margin. If the footer is above it, the images are normal but the content passes the footer from behind.
Is there a way to bypass this?
The problem was solved quite easily, with a lot of regret of losing too much valuable time on this.
When you are using images in TCPDF, always match the size of the image with the desired size you want them to be in your pdf. The setImageScale() does not reach every image if it is outside the page range. That includes the footer, if its position is outside of the page margin_bottom.
I hope you guys won't hurt your heads too much about it and that this will save you all.
This might have been already answered, yes, I used Google, and the search here stackoverflow, but the problem remains...
I'm using TCPDF library to generate PDF file, it works just fine, but I have the following situation, in order for my to generate a PDF ot just the HTML I need to put a few foreach and while's and IF's inside the HTML so that I can get the layout that the user is requesting...
so...
if(isset($_POST['submit'])) {
$ids = htmlentities($_POST['id'], ENT_NOQUOTE;
$con = conectionDB();
$query 'SELECT * FROM books WHERE id = "$ids"';
$doit = $con->query($query);
// at this point everything is file
// a few if's and we are done with the fetching "books" data
// a few other tuff that is required from the library nothing fancy...
// now here is the hard part
// next line will build my layout to display my PDF
$build_HTML = <<<EOD
<style>
.clasess {...}
.nother {...}
</style>
<table width="100%" border="1" cellpadding="0" bordercolor="#333333" >
<tr>
<td>Author</td>
<td>Books</td>
</tr>
<tr>
<td> Jong </td>
<td>
<table>
<tr>
<td>Title</td><td>Year</td>
</tr>
// Here is the problem I need to put a query to fetch the related data from
// another table
$books = conectionDB();
$bookQ = "SELECT * FROM titles WHERE name = '$author_name'";
$doitTitles = $books->query($bookQ);
if ($doitTitles->num_row > 1) {
while($dos = $doitTitles->fetch_assoc()){
// my td's, but this doest work...
}
}
</table>
</td>
</tr>
</table>
EOD;
$pdf->writeHTML($build_HTML, true, false, false, false, '');
} else {
// Go back...
}
As you can see I need that query right there, you may have notice that I have $doitTitles->num_row > 1 why? because if there is more than 1 tittle the layout would different if there is only 1 record...
We know that, that wont work, so the question is, is there another way to do that?
now, before the user go to the PDF, I display the information in plain html, which mean that the HTML that I use before the user go in to the PDF will be the same... so I was wondering, there another library that I can use to render the HTML in to PDF instead of building the PDF from inside the file... the user is able to see the result so those result just put 'em in a PDF...
Thank you!
I have the solution, so the thing is that I'm trying to output an html that is been build with dynamic content, if that was to be show as any other page, my_page.html there is no problem, but in PDF using <<
$raw_html = 'Tables';
// a few while and foreach's and queries
$raw_html .='Closed tables';
// Ready the HTML
$html = <<<EOD
$raw_html
EOD;
$pdf->writeHTML($html, true, false, false, false, '');
$pdf->Output('pdf_file_with_dynamic_html.pdf', 'I');
// the end.
by preparing the html before the output it gives me the data I need the way i need it...
that solved my problem.
I am a beginner to php,I am using tcpdf class for generating PDF docs (contains html tables) for the SQL data.It converts the data as pdf for limited rows(200 rows but it takes 120sec ),but it can not able to do that for above 200 rows(shows maximum execution timed out).
I am using writehtml() function for writing html tables.
Is there any way to process larger records?
require_once('tcpdf/tcpdf.php');
$pdf = new TCPDF('P', PDF_UNIT,'A4', true, 'UTF-8', false);
$pdf->setFontSubsetting(false);
$pdf->SetHeaderData('logo.jpg',40,'companyhead',"addressline1,asdasd,\nxxxfgh-1234");
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, 30, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
//selecting from the database and fetching each records
$query = "SELECT * FROM test3 WHERE month='$month[0]' AND year='$year[0]'";
$result = mysql_query($query);
while($rows = mysql_fetch_assoc($result))
{
//here goes some calculations with retrieved records
//add a page
$pdf->AddPage();
$pdf->SetFont('Times', 'B', 15);
$pdf->Write(0,'Pay slip for'.$month.','.$year.'', '', 0, 'C', true, 0, false, false, 0);
$pdf->Ln();
$pdf->SetFont('Times', '', 10);
//html table with the processed records goes here
$table ='<table width="555" style="border:1px solid black;" align="center">
//table contents
</table>';
$pdf->writeHTML($table, true, false, false, false, '');
$pdf->Ln();
$pdf->Ln();
//------------------------------------------------------------------------------------
//html table
$table ='<table width="540" align="center" style="border:1px solid black;">
//table contents
</table>';
$pdf->writeHTML($table, true, false, false, false, '');
//------------------------------------------------------------------------------------
$pdf->Ln();
$pdf->Ln();
//adding some text content to the pdf
$pdf->Write(0, 'Note:The information provided to you is confidential do not share it with others', '', 0, 'L', true, 0, false, false, 0);
$pdf->lastPage();
}
$pdf->Output('unnamed.pdf', 'I');
You can try to process only some row at time and then force output with ob_flush function (http://it1.php.net/ob_flush)
eg:
$chunk =0 ;
for($rows as $k => $v) {
$data_to_write = process_elem($k,$v);
write_to_pdf($data_to_write);
if($chunk++ == 50) {
ob_flush;
$chunk=0;
}
}
If you post your code I can help you in a better way.
Use a work queue such as Beanstalk. Instead of trying to work through all of the records at once, get the basic record id's from the main page. In the worker process, which will process one record at a time in in the background to actually assemble the PDF. Your initial script finishes quicker and you can monitor the queue in realtime. Your system will get through the records no matter how many you throw at it.
Beanstalk: http://kr.github.io/beanstalkd/
You will need the PHP library to use it: https://github.com/pda/pheanstalk
Once you get it, you can offload many background tasks with it such as logging, sending messages or image resize tasks to name a few of the workers I have setup.
Good Luck!