I am currently creating a resume exporting tool using domPDF. I have a DB that contains all the resume data (title, description). With a loop, I am building my PDF resume which looks like this :
This is the code for the left column of my resume :
$q_cv_categories = $bdd->query('SELECT * FROM cv_category WHERE cv_column = "left"');
$q_cv_categories->execute();
while($cv_categories = $q_cv_categories->fetch()){
$html .= '<div class="special-heading-pdf">';
$html .= '<h3>'.constant($cv_categories['category_name']).'</h3>';
$html .= '</div>';
$q_cv_data = $bdd->prepare('SELECT * FROM cv_data WHERE category_id = :category ORDER BY importance DESC LIMIT 5');
$q_cv_data->bindValue('category', $cv_categories['id'], PDO::PARAM_INT);
$q_cv_data->execute();
while($cv_data = $q_cv_data->fetch()){
$html .= '<div class="resume-information"><h4 class="title-resume-data">'.constant($cv_data['title']).'</h4>';
$html .= '<p class="description-resume-data">'.constant($cv_data['description']).'</p></div>';
}
$q_cv_data->closeCursor();
}
$q_cv_categories->closeCursor();
I would like to be able to calculate the render height of each div with the resume-information class, so I can display 4 instead of 5 computer science achievements (or even 3 if needed) in order to keep the resume one page only.
Thanks
I came up with the idea of calculating the exact height of each element in the resume. For example a line of descriptive text has a height of 17px in my PDF (A4, height of 1122px).
For the right column of the resume, a line of text has a mean of 78 characters. By doing a strlen() of the description, I can approximate quite precisely the number of lines it will be taking.
Here is the example of the script I used to calculate the height of the right column :
$q_cv_categories = $bdd->query('SELECT * FROM cv_category WHERE cv_column = "right"');
$q_cv_categories->execute();
while($cv_categories = $q_cv_categories->fetch()){
$right_height += CFG_RESUME_PDF_CSS_MARGIN_TOP_HEADING; // margin-top of heading computer achievement, work exp, etc.
$right_height += CFG_RESUME_PDF_LINE_HEIGHT_PX*GetResumeLineCount(constant($cv_categories['category_name']), "right", "heading"); // heading
$right_height += CFG_RESUME_PDF_CSS_PADDING_HEADING_BLUELINE+CFG_RESUME_PDF_CSS_HEADING_GREYLINE+CFG_RESUME_PDF_CSS_HEADING_BLUELINE; // blue line of heading
$right_height += CFG_RESUME_PDF_CSS_MARGIN_BOTTOM_HEADING; // margin-bottom of heading
$q_cv_data = $bdd->prepare('SELECT * FROM cv_data WHERE category_id = :category ORDER BY importance DESC LIMIT 5');
$q_cv_data->bindValue('category', $cv_categories['id'], PDO::PARAM_INT);
$q_cv_data->execute();
while($cv_data = $q_cv_data->fetch()){
$right_height += CFG_RESUME_PDF_LINE_HEIGHT_PX*GetResumeLineCount(constant($cv_data['title']), "right", "title");
$right_height += CFG_RESUME_PDF_LINE_HEIGHT_PX*GetResumeLineCount(constant($cv_data['description']), "right", "description");
$right_height += CFG_RESUME_PDF_CSS_MARGIN_BOTTOM_RESUME_INFORMATION; // margin-bottom of resume-information
}
$q_cv_data->closeCursor();
}
$q_cv_categories->closeCursor();
The last step is to display for example 4 instead of 5 computer science achievements if the total height is more than 1100px (with a margin left of 22px), then calculate the total height once more, etc.
I have dynamic data. So my data can change
besides that I also have a data signature that cannot be separated.
This signature data must be on the same page. See the red mark in this image :
It is a unit and cannot be separated. Signature data
must be on the same page
My problem is because my data is dynamic. This makes the position of the signature data can be located in any position. See image below :
Because my data increases, the position of the headmaster in the signature data is separate
How do I make signature data (see picture 1), which red marks automatically move to the next page if the data is separate?
You can set manual page breaks with something like this:
<?php
//All lines are written from the sheet code at this moment
//The code will insert a page break and the repeated header
//Page margins
$sheet->getPageMargins()->setTop(0.5);
$sheet->getPageMargins()->setRight(0.75);
$sheet->getPageMargins()->setLeft(0.75);
$sheet->getPageMargins()->setBottom(1);
//Use fit to page for the horizontal direction
$sheet->getPageSetup()->setFitToWidth(1);
$sheet->getPageSetup()->setFitToHeight(0);
$headerItems = array(); //add your header items here as array
$headerRowsHeight = 0;// calculated height of header and images of the top
$rowCounter = 100; //get last written row
//add (other) modifier of page hight here
$pageHeight=25+50 + $headerRowsHeight; //Current used page height Header + Footer + $headerRowsHeight
$reset = $pageHeight; //If you will have the firstpage diffrent change reset value and/or pageheight
$pageMaxHeight = 980 ; //Maximale page height DIN A4 arround this
$pageClearance = 15; //Clearance of footer
//Iterate trough all written lines
for ($row = 1; $row <= $rowCounter; ++$row) {
$height=15.1; //standard row height
//get the row height
$dim = $sheet->getRowDimension($row)->getRowHeight();
//get special cell heights (non standard)
if($dim != -1){
$height=$dim;
}
//add height for line to pageheight = get current used space
$pageHeight = $pageHeight + $height;
//Check if the space is still in the range of page
$leftOverSpace = $pageMaxHeight-$pageHeight;
//Change $pageClearance to your preferd space before footer
if( $leftOverSpace < $pageClearance){
//Set pagebraek
$sheet->setBreak('A'.$row, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW);
//Reset page height
$pageHeight=$reset;
//Add page header to new page
createHeader($sheet, $row+1, $headeritems);
}
}
//Creates a header for every page
function createHeader($sheet, $row, $texts){
$count = $row;
// Iterate trough the header text array
foreach($texts as $text){
//Insert a new line with header
$sheet->insertNewRowBefore($count, 1);
//Do your header stuff here
$count++;
}
//Add two lines after the header
$sheet->insertNewRowBefore($count, 2);
//Return row number
return $count;
}
?>
Place not that the calculation is not 100% exact and that you must adapt this to your code.
I have a problem. I write codes of to display images from mysql database to FPDF but the images are displayed as overlapping (in same position)
<?php
include("connection.php");
$que1=mysql_query("select * from TableName);
ob_start();
require('fpdf/fpdf.php');
$pdf = new FPDF();
$pdf->AddPage();
while($rw=mysql_fetch_array($que1))
{
$profile=$rw['profile'];
$pdf->Image($profile,10,'',30);
}
$pdf->Output();
ob_end_flush();
?>
How can I display my images in vertical form?
Please anyone can help me.
The problem is with line
$pdf->Image($profile,10,'',30);
The first attribute is "file", Second is the axis X position, 3rd is axis Y, fourth is width.
Refference: Documentation
Please give different x,y values to prevent overlapping
From documentation I can see that Image method take [x, y] coordinates. So just for every image calculate new position:
$currentY = 0;
while ($rw = mysql_fetch_array()) {
$imageSize = $this->getSize($rw['profile']);
$pdf->Image($profile, 10, $currentY, 30);
$currentY += $imageSize['height'];
}
OR try setting y to null - Image($profile, 10, null, 30)
I need to create an excel document with only 2 col. The first one will contain multiple images 150px large and the seconde one will contain a web code. For some reason only one image is added and the file appears to be currupted. Not sure what i am doing wrong ...
<?php
include("../../init.php");
if (is_numeric($_GET[groupe])){
define( 'PCLZIP_TEMPORARY_DIR', $_CONFIG['upload']['root'].'/cache' );
// filename for download
$groupe = mysql_query("SELECT * FROM photographe_groupe WHERE id='$_GET[groupe]'");
$records = "Groupe - $groupe[nom].xlsx";
header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition:inline;filename='.$records);
$workbook = new PHPExcel;
$sheet = $workbook->getActiveSheet();
$i=0;
$select = mysql_query("SELECT * FROM photographe_images WHERE sid='$_GET[groupe]' group by `paire`");
while($photo = mysql_fetch_array($select)){
// Table header
if ($i=="1"){
$sheet->setCellValue("A1",'Photo(s)');
$sheet->setCellValue('B1','Code Web');
$i++;
}
// Set images in col 1
$select1 = mysql_query("SELECT * FROM photographe_images WHERE paire='$photo[paire]'");
while($photo1 = mysql_fetch_array($select1)){
$objDrawing = new PHPExcel_Worksheet_Drawing();
$objDrawing->setName($photo1[img]);
$objDrawing->setDescription($photo1[img]);
$objDrawing->setWorksheet($workbook->getActiveSheet());
$objDrawing->setPath($_CONFIG['upload']['root'].'/userfiles/photos/'.$photo1[img]);
$objDrawing->setWidth(150);
$objDrawing->setCoordinates('A'.$i);
}
// Set web code in col 2
$sheet->setCellValue("B$i",$photo[code_web]);
$i++;
}
}
$workbook->getActiveSheet()->getRowDimension(1)->setRowHeight(-1);
$writer = new PHPExcel_Writer_Excel2007($workbook);
PHPExcel_Settings::setZipClass(PHPExcel_Settings::PCLZIP);
$writer->save('php://output');
?>
You can download and output demo here
Just a few points to note before I try taking a look at your file:
The first point to note here is that Excel doesn't store images in cells, it "overlays" images, and doesn't particularly care where cell boundaries occur, so an image can be a fixed size irrespective of how many cells it overlays
When you specify a coordinate for a image, you're relating the top-left corner of that image to be placed at the top-left corner of that cell.... where the bottom and/or right corner of the image lies isn't determined by the cells at all. Setting the row height or column width to autosize will not be affected by the image in any way, because the image is overlaid, not a content of the cell
You can, offset the image from the top-left corner of the related cell by using the Drawing object's setOffsetX() and setOffsetY() methods.
You can link more than one image to be placed relative to the same cell's top-left corner using different offset values so they don't overlap, but you need to work out the offsets from the size of the images
I have a problem creating tables with fpdf.
Can anyone help me making this page (or at least tell me how to do it)?
invoice tables
Or can you show how to convert HTML tables to FPDF tables and put the code here?
I also have this (along with the connection to the database):
$person = mysql_fetch_array($result);
I would like this to function when added inside the tables with this = (example)
$pdf->Cell(0,260,''.$person["CA"],'C',0 ,1); --- .$person["CA"]
Can anyone help me?
Well, FPDF works kinda like a typewriter, in that it has a roving X,Y point which it writes to, which you can manually move around or let it do it for you.
I don't know if the huge whitespace at the left is required. If so, you'd have to call $this->SetX($coordinate) before each write.
You should do something like this:
class InvoicePDF extends FPDF //Create a new class to contain the header/footer/etc. which extends FPDF
{
public function Header()
{
//Header stuff goes here, like the big Invoice
$this->SetY(10); //SetY 10 units down from the top, experiment with distance to get appropriate distance
$this->SetFont('Arial','',20); //Set Font to Arial/Helvetica 20 pt font
$this->SetTextColor(0,0,0); //Set Text Color to Black;
$this->Cell(0,9,"INVOICE",0,0,'R'); //Write the word INVOICE Right aligned in a box the width of the page, will put it at the far right of the page
}
public function Footer()
{
//any footer stuff goes here
}
public function FillHeadInfo($info) //$info would be an array of the stuff to fill the small table at the top
{
$this->SetY(0); //reset the Y to the original, since we moved it down to write INVOICE
$this->SetFont('Arial','',12);
$this->SetFillColor(224,224,224); //Set background of the cell to be that grey color
$this->Cell(20,12,"Order #",1,0,'C',true); //Write a cell 20 wide, 12 high, filled and bordered, with Order # centered inside, last argument 'true' tells it to fill the cell with the color specified
$this->Cell(20,12,"Coding",1,0,'C',true);
$this->Cell(20,12,"Sales Code",1,1,'C',true); //the 1 before the 'C' instead of 0 in previous lines tells it to move down by the height of the cell after writing this
$this->Cell(20,12,$info['ordernum'],1,0,'C');
$this->Cell(20,12,$info['coding'],1,0,'C');
$this->Cell(20,12,$info['salescode'],1,1,'C');
$this->Cell(40,12,"Name & Address",1,0,'C',true);
$this->Cell(20,12,"Date",1,1,'C',true);
$y = $this->GetY(); //Need the current Y value to reset it after the next line, as multicell automatically moves down after write
$x = $this->GetX(); // Might need the X too
$this->MultiCell(40,12,$info['customername'] . "\n" . $info['address'] . "\n" . $info['city'] . ', ' . $info['state'] . ' ' . $info['zip'],1,'L',false); //I assume the customer address info is broken up into multiple different pieces
$this->SetY($y); //Reset the write point
$this->SetX($x + 40); //Move X to $x + width of last cell
$this->Cell(20,36,date("format",strtotime($info['date'])),1,1,'C'); //Might be easier to use $this->Rect() to draw rectangles for address and date and then write the address and date into them without borders using SetX and SetY, if the borders don't line up or whatever
}
public function fillItems($items)
{
//You'd build the items list much the same way as above, using a foreach loop or whatever
//Could also easily combine this function and the one above
}
}
Then, when creating the pdf you'd do something like this:
require_once('fpdf.php');
require_once('class.invoicepdf.php');
//Get whatever info you need to fill the pdf
$pdf = new InvoicePDF('P','mm','Letter');
$pdf->AddPage();
$pdf->FillHeadInfo($info); //Could also pass $_POST and rely on the keys of the $_POST array
$pdf->FillItems($items);
$pdf->Output('filename.pdf','I');
By the way, I'd suggest rather than trying to write it from $_POST, you save the order to the DB, then pass the order ID along to the script to write the pdf via a link and $_GET, and have the script retrieve the info from the DB, this way you can select only the info you need.