The best HTML to PDF library for PHP?
Posted: Sun Jul 19, 2009 8:05 pm
Does anyone have a HTML to PDF solution that they are happy with? It could be a PHP library or a command line program.
A community of PHP developers offering assistance, advice, discussion, and friendship.
http://forums.devnetwork.net/
I tried it, but they only seem to give example HTML files and not much example PHP code. I used the example on some simple files but it does not produce a valid PDF file. Hmmmm....Darhazer wrote:We are using HTML2PDF, however we have problems with page breaks (sometimes last line of the page appears only the half of it)
Does this work? If it does it would probably be the easiest way. How do you find the markers/tags in the PDF file?Darhazer wrote:Another approach we are currently researching (but this if you have a template with fixed amount of data, i.e. you have no multiple rows with varying count to insert, but only single variables) is making a PDF with markers in it, and than with PHP just enter the data in those markers.
Code: Select all
// Util
require_once(dirname(__FILE__) . '/../../html2pdf-2.1.5/config.inc.php');
require_once(HTML2PS_DIR . 'pipeline.factory.class.php');
require_once(HTML2PS_DIR . 'fetcher.url.class.php');
class fclHtml2Pdf {
protected $_html;
function fclHtml2Pdf()
{
$this->_init();
parse_config_file(HTML2PS_DIR . 'html2ps.config');
}
function _init()
{
global $g_config;
$g_config = array(
'cssmedia' => 'screen',
'convert' => 1,
'media' => 'A4',
'scalepoints' => 1,
'renderimages' => 1,
'renderlinks' => 1,
'pagewidth' => 800,
'landscape' => 0,
'method' => 'fpdf',
'margins' => array( 'left' => 30, 'right' => 30, 'top' => 15, 'bottom' => 15),
'encoding' => 'utf-8',
'compress' => 1,
'output' => 1,
'pdfversion' => '1.5',
'transparency_workaround' => 0,
'imagequality_workaround' => 0,
'draw_page_border' => 0,
'debugbox' => 0,
'html2xhtml' => 1,
'debugnoclip' => false,
);
}
function setHtml($html)
{
$this->_html = $html;
}
function setFilename($filename)
{
global $g_baseurl;
$g_baseurl = $filename;
}
function setTitle($title)
{
$this->_title = $title;
}
function generate()
{
global $g_config,
$g_border,
$g_font_size,
$g_table_border,
$g_baseurl,
$g_css_index,
$g_font_weight,
$g_font_style,
$g_font_family,
$g_image_encoder,
$g_stylesheet_title,
$g_media,
$g_framepos,
$g_px_scale,
$g_pt_scale;
// begin processing
$g_media = Media::predefined($g_config['media']);
$g_media->set_landscape($g_config['landscape']);
$g_media->set_margins($g_config['margins']);
$g_media->set_pixels($g_config['pagewidth']);
// Initialize the coversion pipeline
$pipeline = new Pipeline();
// Configure the fetchers
$pipeline->fetchers[] = new miFetcher($this->_html);
//$pipeline->fetchers[] = new FetcherURL();
// Configure the data filters
$pipeline->data_filters[] = new DataFilterDoctype();
$pipeline->data_filters[] = new DataFilterUTF8($g_config['encoding']);
if ($g_config['html2xhtml']) {
$pipeline->data_filters[] = new DataFilterHTML2XHTML();
} else {
$pipeline->data_filters[] = new DataFilterXHTML2XHTML();
};
$pipeline->parser = new ParserXHTML();
// "PRE" tree filters
$pipeline->pre_tree_filters = array();
$header_html = '';
$footer_html = '';
$pipeline->pre_tree_filters[] = new PreTreeFilterHeaderFooter($header_html, $footer_html);
if (isset($g_config['renderfields'])) {
$pipeline->pre_tree_filters[] = new PreTreeFilterHTML2PSFields();
};
//
if ($g_config['method'] === 'ps') {
$pipeline->layout_engine = new LayoutEnginePS();
} else {
$pipeline->layout_engine = new LayoutEngineDefault();
};
$pipeline->post_tree_filters = array();
// Configure the output format
if (@$g_config['pslevel'] == 3) {
$image_encoder = new PSL3ImageEncoderStream();
} else {
$image_encoder = new PSL2ImageEncoderStream();
};
switch ($g_config['method']) {
case 'fastps':
if ($g_config['pslevel'] == 3) {
$pipeline->output_driver = new OutputDriverFastPS($image_encoder);
} else {
$pipeline->output_driver = new OutputDriverFastPSLevel2($image_encoder);
};
break;
case 'pdflib':
$pipeline->output_driver = new OutputDriverPDFLIB16($g_config['pdfversion']);
break;
case 'fpdf':
$pipeline->output_driver = new OutputDriverFPDF();
break;
case 'png':
$pipeline->output_driver = new OutputDriverPNG();
break;
case 'pcl':
$pipeline->output_driver = new OutputDriverPCL();
break;
default:
die("Unknown output method");
};
$pipeline->output_driver->setTitle($this->_title);
$pipeline->output_driver->setAuthor('Mirchev Ideas Ltd.');
// Setup watermark
$watermark_text = '';
$pipeline->output_driver->set_watermark($watermark_text);
if ($g_config['debugbox']) {
$pipeline->output_driver->set_debug_boxes(true);
}
if ($g_config['draw_page_border']) {
$pipeline->output_driver->set_show_page_border(true);
}
if (@$g_config['ps2pdf']) {
$pipeline->output_filters[] = new OutputFilterPS2PDF($g_config['pdfversion']);
}
if ($g_config['compress'] && $g_config['method'] == 'fastps') {
$pipeline->output_filters[] = new OutputFilterGZip();
}
$filename = $g_baseurl;
switch ($g_config['output']) {
case 0:
$pipeline->destination = new DestinationBrowser($filename);
break;
case 1:
$pipeline->destination = new DestinationDownload($filename);
break;
case 2:
$pipeline->destination = new DestinationFile($filename);
break;
};
// Start the conversion
$status = $pipeline->process($g_baseurl, $g_media);
if ($status == null) {
print($pipeline->error_message());
error_log("Error in conversion pipeline");
die();
}
}
}
class miFetcher extends FetcherUrl {
public function __construct($html)
{
$this->_html = $html;
parent::__construct();
}
public function get_data($data_id)
{
// If it is NOT a URL use the FetchedDataURL - this is the html of the report
if ((strlen($data_id) < 7) or substr_compare($data_id, 'http://', 0, 7))
return new FetchedDataURL($this->_html, array(), "");
$data = parent::get_data($data_id);
return $data;
}
public function get_base_url()
{
return 'http://' . $_SERVER['HTTP_HOST'] . '/';
}
}
Code: Select all
// actual code
class fclPdfExportAction extends miActionWithWebForm {
protected $_title = '';
protected $_filename = '';
/**
* Generates the HTML from the template
* Subclasses can override to provide custom logic for parsing the template
*/
protected function generateHtml($template)
{
// enter some html, framewok-secific code removed
return $html;
}
public function doAction()
{
$html = $this->generateHtml($this->_view->getTemplateFileName($this->template));
$pdf = &new fclHtml2Pdf();
$pdf->setHtml($html);
$pdf->setFilename($this->_filename);
$pdf->setTitle($this->_title);
$pdf->generate();
exit;
}
}ohh threes that as well, i have teared this framework upside down and it still needs a lot of work as its lacking some important features. see the problem is all PHP-PDF frameworks available right now only make PDF from scratch which hardly comes in handy. most of developers want to convert from existing .doc, .docx, .rtf and .wp files.pytrin wrote:Did you try Zend_Pdf?
I've got some experience working with PDF's.arborint wrote:Does this work? If it does it would probably be the easiest way. How do you find the markers/tags in the PDF file?Darhazer wrote:Another approach we are currently researching (but this if you have a template with fixed amount of data, i.e. you have no multiple rows with varying count to insert, but only single variables) is making a PDF with markers in it, and than with PHP just enter the data in those markers.
Thanks for the links and code. I will need to dig through your classes to see what you are doing ... and get rid of the pipline stuff which I don't need. I just need to convert one at a time -- on demand.
I think Zend_Pdf like many others only generates PDFs programmatically. I am looking for HTML to PDF conversion. I may end up having to do the PDFs in code.pytrin wrote:Did you try Zend_Pdf?
Thanks for the tips, and any code you can post would be welcome. I have what is essentially a receipt that is currently HTML. I need to make it also available as PDF. If I can convert the existing one on-the-fly that would be easiest, and I would not have to support two versions of each receipt type (there are 20-30) because changes to a HTML one would automatically be reflected in the PDFs.flying_circus wrote:I've got some experience working with PDF's.
I'm not sure I understand exactly what you are trying to accomplish, but we use it to populate PDF order form. I've built a flash interface for the user to select their options, and then a print button which creates a POST to the generate PDF page. That generate PDF page parses the POST information and inserts the data into the PDF form. It's called FDF data fields. I use acrobat pro to make forms fields in the PDF.
The other program I use is PDFlib. PDFlib can import an existing .pdf file and basically rasterize it as a background. Then you can super-impose your data over top of the background drawing by x and y coords.
I can probably send a few snippets of code if you are interested in either method.
Code: Select all
<?php
/*
* createXFDF
*
* @param string $file The pdf file - url or file path accepted
* @param array $info data to use in key/value pairs no more than 2 dimensions
* @param string $enc default UTF-8, match server output: default_charset in php.ini
* @return string The XFDF data for acrobat reader to use in the pdf form file
*/
function createXFDF($file,$info,$enc='UTF-8')
{
$data = '<?xml version="1.0" encoding="' . $enc . '"?>' . "\n" . '<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' . "\n";
$data .= '<fields>' . "\n";
foreach($info as $field => $val)
{
$data .= '<field name="' . $field . '">' . "\n";
$data .= '<value>'.$val.'</value>'."\n";
$data .= '</field>'."\n";
}
$data .='</fields>' . "\n";
$data .= '<ids original="' . md5($file) . '" modified="' . time() . '" />' . "\n" . '<f href="' . $file . '" />' . "\n" . '</xfdf>'."\n";
return $data;
}
# Test Code
$file = 'http://server/test/xfdf/order.pdf';
$info = array('contpanel1' => 'Black',
'contpanel2' => 'Red',
'contpanel3' => 'Blue',
'contpanel4' => 'Green',
'contpanel5' => 'Yeller');
$xfdf = createXFDF($file, $info);
$file_name = "order.xfdf";
header('Content-type: application/vnd.adobe.xfdf');
header('Content-Disposition: inline; filename="' . $file_name . '"');
print $xfdf;
?>Code: Select all
<?php
////////////////////////////////
// Get Post Data
////////////////////////////////
//Materials
$matCp_1 = strtoupper($_POST['cp1']);
$matCp_2 = strtoupper($_POST['cp2']);
$matCp_3 = strtoupper($_POST['cp3']);
$matCp_4 = strtoupper($_POST['cp4']);
$matCp_5 = strtoupper($_POST['cp5']);
////////////////////////////////
// Create new PDF Document
// Set background as order form
////////////////////////////////
define('FPDF_FONTPATH','font/');
require_once('includes/modules/fpdf.php');
require_once('includes/modules/fpdi.php');
class PDF extends FPDI {
//Page footer
function Footer() {
//Position at 1.5 cm from bottom
$this->SetY(-15);
//Arial italic 8
$this->SetFont('Arial','I',10);
//Page number
$this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
}
}
$pdf = new PDF();
$pdf->AliasNbPages();
$pdf->SetCreator('Fabrikam');
$pdf->SetAuthor('Fabrikam');
$pdf->SetTitle('Fabrikam Order Form');
$pdf->SetDisplayMode('real');
$pagecount = $pdf->setSourceFile("order_form.pdf");
$tplidx = $pdf->ImportPage(1);
$pdf->addPage();
$pdf->useTemplate($tplidx,0,10,210);
////////////////////////////////
// Populate order form fields
////////////////////////////////
$pdf->SetFont('Arial','',9);
// Materials
// Container Panel 1
$pdf->SetXY(26,82.1);
$pdf->Cell(0,0,$matCp_1);
// Container Panel 2
$pdf->SetXY(26,85.75);
$pdf->Cell(0,0,$matCp_2);
// Container Panel 3
$pdf->SetXY(26,89.50);
$pdf->Cell(0,0,$matCp_3);
// Container Panel 4
$pdf->SetXY(26,93.1);
$pdf->Cell(0,0,$matCp_4);
// Container Panel 5
$pdf->SetXY(26,96.75);
$pdf->Cell(0,0,$matCp_5);
////////////////////////////////
// Return to Top of Document
// Output PDF Document
////////////////////////////////
$pdf->SetXY(0,0);
$pdf->Output("infinity.pdf","I");
$pdf->closeParsers();
?>Code: Select all
<?php
# Load Site Config File
require_once('includes/configuration.php');
# Begin Output Buffering
if(GZIP_COMPRESSION == "true" && extension_loaded('zlib')) {
ini_set('zlib.output_compression_level', GZIP_COMPRESSION_LEVEL);
ob_start();
}
# Includes
require_once('includes/classes/class.db.php');
# Create Database Object
$db = new db();
# Declare Variables
$rigId = (isset($_POST['rigId']) ? $_POST['rigId'] : '');
$rig = array();
$timestamp = strtotime("now");
$infile = "order.pdf";
$searchpath = PDF_FILE_PATH;
$license = "";
$width = 612.0;
$height = 792.0;
try {
$p = new PDFlib();
$p->set_parameter("license", $license);
/* open new PDF file; insert a file name to create the PDF on disk */
if ($p->begin_document("","") == 0) {
die("Error: " . $p->get_errmsg());
}
$p->set_parameter("SearchPath", $searchpath);
/* This line is required to avoid problems on Japanese systems */
$p->set_parameter("hypertextencoding", "winansi");
/* Set PDF Info */
$p->set_info("Creator", "order.php");
$p->set_info("Author", "Fabrikam");
$p->set_info("Title", "Fabrikam Order Form");
/* $pdi = PDF Import from an existing PDF file */
$pdi = $p->open_pdi($infile, "", 0);
if (!$pdi) {
die("Error: " . $p->get_errmsg());
}
$p->set_parameter("topdown", "true");
$p->begin_page_ext($width, $height, "");
/* open_pdi_page($pdi,$pageNumber,"") */
$page = $p->open_pdi_page($pdi, 1, "");
if (!$page) {
die("Error: " . $p->get_errmsg());
}
$p->fit_pdi_page($page, 0, $height, "");
// experimental
/* Populate Form */
// Set Font and Font Size
$font = $p->load_font("Arial", "winansi", "");
$fontBold = $p->load_font("Arial Bold", "winansi", "");
$fontBlack = $p->load_font("Arial Black", "winansi", "fontstyle bold");
$p->setfont($font, 9);
// Timestamp
$p->set_text_pos(250, 790);
$p->show("Printed On: " . date("m/d/Y - h:i:s A",$timestamp));
// Materials
// Cordura/Para-pak
$p->setfont($fontBlack, 9);
if($rig['cnt_material'] == 'CORDURA') {
$p->set_text_pos(116, 144);
$p->show("X");
} else if($rig['cnt_material'] == 'PARAPAK') {
$p->set_text_pos(194, 144);
$p->show("X");
} else if($rig['cnt_material'] == 'MESH') {
$p->set_text_pos(272, 144);
$p->show("X");
}
$p->setfont($font, 9);
// Container Color
// Panel 1
$p->set_text_pos(80, 212);
$p->show($rig['cnt_panel1']);
// Panel 2
$p->set_text_pos(80, 223);
$p->show($rig['cnt_panel2']);
// Panel 3
$p->set_text_pos(80, 234);
$p->show($rig['cnt_panel3']);
// Panel 4
$p->set_text_pos(80, 245);
$p->show($rig['cnt_panel4']);
// Panel 5
$p->set_text_pos(80, 256);
$p->show($rig['cnt_panel5']);
// Backpad
$p->set_text_pos(80, 277);
if($rig['cnt_material'] == 'MESH') {
$p->show('MESH');
} else {
$p->show($rig['cnt_backpad']);
}
// Vertical text on Left Edge
// Name
$p->fit_textline($rig['cus_firstname'] . ' ' . $rig['cus_lastname'],25,725,"orientate west");
// Serial Number
$p->fit_textline($rig['cnt_serialNumber'],25,450,"orientate west");
//
/* finish the first page */
$p->close_pdi_page($page);
$p->end_page_ext("");
$p->end_document("");
$p->close_pdi($pdi);
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=foo.pdf");
print $buf;
}
catch (PDFlibException $e) {
die("PDFlib exception occurred in quickreference sample:\n" .
"[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " .
$e->get_errmsg() . "\n");
}
catch (Exception $e) {
die($e);
}
?>