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.
Related
I'm using the TCPDF library to create a .pdf file. I have to add an image in the footer which should cover 100% of the width, but it's coming in the center with equal margin from left and right. I want to remove those margins and set full width to the footer image. The code I'm using to set the footer is below. You can also see in the attach image how my image appears in the footer:-
$footer_image_file = './images/logo/footer.png';
$footer_logo_html = '<div style="width:100opx !important;height:100px;"><img width:"1000px;" src="' . $footer_image_file . '" /></div>';
$pdf->writeHTML($footer_logo_html, true, 0, true, 0);
Try use writeHTMLCell() for this. Set 1st parameter 21 - A4 width (I set cm as unit of measure), and 4 as A4 height - image height:
$pdf->writeHTMLCell(21, '', 0, 29.7 - 4, $footer_logo_html, 0, 1, false, true, 'L', false);
Result:
I use Your .png, so it have white space on the edges =)
I have been trying to create a PDF containing a SVG image with the TCPDF Library. I wanted to have the SVG centered on a page with some text above and below it.
I have managed to get this working to a point however part of the SVG image is being cut off, it seems to have something to do with the X/Y position but I am not sure how to correct this problem.
What is causing the TCPDF Library error that cuts off my SVG image?
Code:
<?php
require_once('../../TCPDF/tcpdf.php');
// Remove the default header and footer
class PDF extends TCPDF {
public function Header() {}
public function Footer() {}
}
$pdf = new PDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', 'B', 160);
$pdf->SetTextColor(0,0,0);
$pdf->Cell(0, 0, 'Higher', 1, 1, 'C', false, '', 1);
$pdf->Ln(4);
$pdf->ImageSVG($file='Image.svg', $x=0, $y=80, $w=100, $h=100, $link='', $align='N', $palign='C', $border=1, $fitonpage=false);
$pdf->Ln(4);
$pdf->Cell(0, 0, 'Lower', 1, 1, 'C', 0, '', 1);
$file = 'Result' . '.pdf'; // Set the name of the PDF file
$pdf->Output($file, 'F'); // Save PDF to file
$pdf->Output($file, 'I'); // Display the PDF
?>
This seems to a bug with the current version of the TCPDF Library that I was using.
The problem is when you use the align features:
$align='N', $palign='C'
etc, and if anyone else has a similar problem and needs a workaround for it I fixed it by manually centering the SVG using the x/y positions.
Another problem to note is when I tried using some SVG images that were in large size I noticed it would create visual glitches so the SVG handling definitely seems to have a few bug. For that problem the workaround I found was to lower the size of the SVG and then scale them using the width/height values instead which seemed to correct the problem.
Open your svg image in an editor
In the svg tag "
Find the property for width and height
Modify it depending on your preferences
<svg xmlns="http://www.w3.org/2000/svg"
width="150" height="100" viewBox="0 0 3 2">
<rect width="1" height="2" x="0" fill="#008d46" />
<rect width="1" height="2" x="1" fill="#ffffff" />
<rect width="1" height="2" x="2" fill="#d2232c" />
</svg>
if modifying width and heigth does not work, there is probably a rectangle tag or a line tag inside the <svg> ... </svg> that execeds the already defined width and height.
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
When using TCPDF together with FPDI templates, some CSS support is lost in the process. The problem are things like borders or background-colors, that end up in layers below the PDF template. TCPDF uses SetLineStyle() to convert CSS borders/backgrounds to PDF and this seems to be the problem.
For example:
$this->setSourceFile($filename); // /path/to/my/background.pdf
$imported_page = $this->ImportPage(1);
$this->useTemplate($imported_page);
...
$html = '<table style="border: 1px solid #000;"><tr><td style="background-color: #ff0000;">...</td></tr></table>';
$this->writeHTMLCell(45, 25, 160, 29, $html);
doesn't render the CSS borders. As soon as useTemplate() is removed the borders are there. Analyzing the resulting PDFs with Illustrator shows some interesting things:
PDF layers with useTemplate() - top to bottom:
Table/Content layers
PDF Template layers (group)
Border and background layers (paths)
PDF layers without useTemplate() - top to bottom:
Table/Content layers
Border and background layers (paths)
When disabling the layer group containing the PDF template in Illustrator, the borders and backgrounds become visible.
Unfortunately we didn't find a way to put the PDF template layer group at the bottom of the stack so everything else renders above it. The only workaround we could come up with, was wrapping the writeHTMLCell() call in startTemplate() / endTemplate() and finishing up with printTemplate():
$this->setSourceFile($filename); // /path/to/my/background.pdf
$imported_page = $this->ImportPage(1);
$this->useTemplate($imported_page);
...
$html = '<table style="border: 1px solid #000;"><tr><td style="background-color: #ff0000;">...</td></tr></table>';
$workaround_template = $this->startTemplate($w, $h);
$this->writeHTMLCell(45, 25, 160, 29, $html);
$this->endTemplate();
$this->printTemplate($workaround_template, $x, $y, $w, $h, 'T', 'L');
So out of curiosity: is this the only way to do it, or is there a way to put the PDF template at the bottom of all things to come?
Thanks in advance!
The solution is to use setPageMark() indeed.
Here is what worked very well for me:
public function AddPage($orientation = '', $format = '') {
global $pdf_data_path;
parent::AddPage($orientation, $format);
if ($this->use_headed) {
$this->setSourceFile($pdf_data_path."/headed.pdf");
$tplidx = $this->importPage(1, '/MediaBox');
$this->useTemplate($tplidx, 0, 0, 0, 0, true);
$this->setPageMark();
}
}
The key is to place setPageMark() after you used the template. The borders will then be stacked on top of the template in resulting PDF.
Did you try using the setPageMark()-method?
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...
How can I set my Iframe height to be dynamic to its content.
The content is only PHP code, nothing else.
I use the php to query database, and then show some ads. The more ads, the higher the iframe should be.
I thought height='100%' should do it, but no...
I have read other Q but their solutions doesn't work for me.
Suggestions ?
Thanks
You have to set height of iframe in javascript. JavaScript should be in page inside the iframe (must be if page with iframe and page in iframe are from different domains).
a.html:
<iframe src="b.html" id="myiframe"></iframe>
b.html:
<div style="height: 500px; background:magenta;"></div>
<script>
parent.document.getElementById('myiframe').style.height = document.body.offsetHeight+'px';
</script>
If the ads are just text, you can use line height * number of lines as the height. I assume you know the font size, and number of lines can be found by counting <br />'s:
<?php
// $content is your ads
// assuming ads.php returns an ad with an id, this example uses ad #10
// We are reading it with a full url because we don't want to read it as just
// a text file (we want it to be interpreted by php before we load it)
$content = file_get_contents('http://www.example.com/ads.php?id=10');
$line_height = 12; // line-height: 12px; is set in CSS
$number_of_lines = substr_count($content,'<br />'); // you can search for <br>
// and <br/> as well if you
// need to
$height = $line_height * $number_of_lines; // You may also want to have padding
?>
<iframe src="ads.php?id=10" height="<?php echo $height; ?>" />
EDIT: changed $font_size to $line_height