Basic PDF Writer #68

This commit is contained in:
Ivan Lanin 2014-04-13 23:17:39 +07:00
parent d54d47d4d7
commit 580a61a832
9 changed files with 473 additions and 28 deletions

View File

@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
## 0.10.0 - Not yet released
This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML support is enabled.
This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled.
### Features
@ -33,6 +33,7 @@ This release marked heavy refactorings on internal code structure with the creat
- ODT Writer: Basic table writing support - @ivanlanin
- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194
- HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147
- PDF Writer: Basic PDF writer initiated using DomPDF - @ivanlanin GH-68
### Bugfixes

View File

@ -11,6 +11,16 @@ define('IS_INDEX', SCRIPT_FILENAME == 'index');
require_once '../src/PhpWord/Autoloader.php';
\PhpOffice\PhpWord\Autoloader::register();
// Set writers
$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf');
// Set PDF renderer
$rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF;
$rendererLibraryPath = ""; // Put dompdf library path
if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) {
$writers['PDF'] = null;
}
// Return to the caller script when runs by CLI
if (CLI) {
return;
@ -22,9 +32,6 @@ $pageTitle = IS_INDEX ? 'Welcome to ' : "{$pageHeading} - ";
$pageTitle .= 'PHPWord';
$pageHeading = IS_INDEX ? '' : "<h1>{$pageHeading}</h1>";
// Set writers
$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html');
// Populate samples
$files = '';
if ($handle = opendir('.')) {
@ -51,10 +58,15 @@ function write($phpWord, $filename, $writers)
// Write
foreach ($writers as $writer => $extension) {
$result .= date('H:i:s') . " Write to {$writer} format" . EOL;
$result .= date('H:i:s') . " Write to {$writer} format";
if (!is_null($extension)) {
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer);
$xmlWriter->save("{$filename}.{$extension}");
rename("{$filename}.{$extension}", "results/{$filename}.{$extension}");
} else {
$result .= ' ... NOT DONE!';
}
$result .= EOL;
}
// Do not show execution time for index

View File

@ -28,7 +28,7 @@ abstract class IOFactory
*/
public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
{
if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) {
if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML', 'PDF'))) {
throw new Exception("\"{$name}\" is not a valid writer.");
}

View File

@ -18,6 +18,9 @@ class Settings
const PCLZIP = 'PhpOffice\\PhpWord\\Shared\\ZipArchive';
const ZIPARCHIVE = 'ZipArchive';
/** Optional PDF Rendering libraries */
const PDF_RENDERER_DOMPDF = 'DomPDF';
/**
* Compatibility option for XMLWriter
*
@ -27,13 +30,32 @@ class Settings
/**
* Name of the class used for Zip file management
* e.g.
* ZipArchive
*
* @var string
*/
private static $zipClass = self::ZIPARCHIVE;
/**
* Name of the classes used for PDF renderer
*
* @var array
*/
private static $pdfRenderers = array(self::PDF_RENDERER_DOMPDF);
/**
* Name of the external Library used for rendering PDF files
*
* @var string
*/
private static $pdfRendererName = null;
/**
* Directory Path to the external Library used for rendering PDF files
*
* @var string
*/
private static $pdfRendererPath = null;
/**
* Set the compatibility option used by the XMLWriter
*
@ -74,7 +96,7 @@ class Settings
return true;
}
return false;
} // function setZipClass()
}
/**
* Return the name of the Zip handler Class that PHPWord is configured to use (PCLZip or ZipArchive)
@ -87,5 +109,71 @@ class Settings
public static function getZipClass()
{
return self::$zipClass;
} // function getZipClass()
}
/**
* Set details of the external library for rendering PDF files
*
* @param string $libraryName
* @param string $libraryBaseDir
* @return boolean Success or failure
*/
public static function setPdfRenderer($libraryName, $libraryBaseDir)
{
if (!self::setPdfRendererName($libraryName)) {
return false;
}
return self::setPdfRendererPath($libraryBaseDir);
}
/**
* Return the PDF Rendering Library
*/
public static function getPdfRendererName()
{
return self::$pdfRendererName;
}
/**
* Identify the external library to use for rendering PDF files
*
* @param string $libraryName
* @return boolean Success or failure
*/
public static function setPdfRendererName($libraryName)
{
if (!in_array($libraryName, self::$pdfRenderers)) {
return false;
}
self::$pdfRendererName = $libraryName;
return true;
}
/**
* Return the directory path to the PDF Rendering Library
*/
public static function getPdfRendererPath()
{
return self::$pdfRendererPath;
}
/**
* Location of external library to use for rendering PDF files
*
* @param string $libraryBaseDir Directory path to the library's base folder
* @return boolean Success or failure
*/
public static function setPdfRendererPath($libraryBaseDir)
{
if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) {
return false;
}
self::$pdfRendererPath = $libraryBaseDir;
return true;
}
}

View File

@ -16,6 +16,7 @@ use PhpOffice\PhpWord\Element\Link;
use PhpOffice\PhpWord\Element\ListItem;
use PhpOffice\PhpWord\Element\Object;
use PhpOffice\PhpWord\Element\PageBreak;
use PhpOffice\PhpWord\Element\PreserveText;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextBreak;
@ -65,7 +66,7 @@ class HTML extends AbstractWriter implements WriterInterface
*
* @return string
*/
private function writeDocument()
public function writeDocument()
{
$html = '';
$html .= '<!DOCTYPE html>' . PHP_EOL;
@ -87,7 +88,7 @@ class HTML extends AbstractWriter implements WriterInterface
*
* @return string
*/
public function writeHTMLHead()
private function writeHTMLHead()
{
$properties = $this->getPhpWord()->getDocumentProperties();
$propertiesMapping = array(
@ -124,7 +125,7 @@ class HTML extends AbstractWriter implements WriterInterface
*
* @return string
*/
public function writeHTMLBody()
private function writeHTMLBody()
{
$phpWord = $this->getPhpWord();
$html = '';
@ -136,8 +137,8 @@ class HTML extends AbstractWriter implements WriterInterface
if ($countSections > 0) {
foreach ($sections as $section) {
$pSection++;
$cellContents = $section->getElements();
foreach ($cellContents as $element) {
$contents = $section->getElements();
foreach ($contents as $element) {
if ($element instanceof Text) {
$html .= $this->writeText($element);
} elseif ($element instanceof TextRun) {
@ -161,9 +162,9 @@ class HTML extends AbstractWriter implements WriterInterface
} elseif ($element instanceof Object) {
$html .= $this->writeObject($element);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element, true);
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element, true);
$html .= $this->writeEndnote($element);
}
}
}
@ -248,9 +249,9 @@ class HTML extends AbstractWriter implements WriterInterface
} elseif ($element instanceof Image) {
$html .= $this->writeImage($element, true);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element, true);
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element, true);
$html .= $this->writeEndnote($element);
}
}
$html .= '</p>' . PHP_EOL;
@ -263,6 +264,7 @@ class HTML extends AbstractWriter implements WriterInterface
* Write link
*
* @param Link $element
* @param boolean $withoutP
* @return string
*/
private function writeLink($element, $withoutP = false)
@ -300,6 +302,7 @@ class HTML extends AbstractWriter implements WriterInterface
* Write preserve text
*
* @param PreserveText $element
* @param boolean $withoutP
* @return string
*/
private function writePreserveText($element, $withoutP = false)
@ -350,7 +353,7 @@ class HTML extends AbstractWriter implements WriterInterface
/**
* Write table
*
* @param Title $element
* @param Table $element
* @return string
*/
private function writeTable($element)
@ -361,7 +364,7 @@ class HTML extends AbstractWriter implements WriterInterface
if ($cRows > 0) {
$html .= "<table>" . PHP_EOL;
foreach ($rows as $row) {
$height = $row->getHeight();
// $height = $row->getHeight();
$rowStyle = $row->getStyle();
$tblHeader = $rowStyle->getTblHeader();
$html .= "<tr>" . PHP_EOL;
@ -388,13 +391,13 @@ class HTML extends AbstractWriter implements WriterInterface
} elseif ($content instanceof Object) {
$html .= $this->writeObject($content);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element, true);
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element, true);
$html .= $this->writeEndnote($element);
}
}
} else {
$this->writeTextBreak($content);
$html .= $this->writeTextBreak(new TextBreak());
}
$html .= "</td>" . PHP_EOL;
}
@ -410,6 +413,7 @@ class HTML extends AbstractWriter implements WriterInterface
* Write image
*
* @param Image $element
* @param boolean $withoutP
* @return string
*/
private function writeImage($element, $withoutP = false)
@ -421,6 +425,7 @@ class HTML extends AbstractWriter implements WriterInterface
* Write object
*
* @param Object $element
* @param boolean $withoutP
* @return string
*/
private function writeObject($element, $withoutP = false)
@ -478,11 +483,14 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeStyles()
{
$bodyCss = array();
$css = '<style>' . PHP_EOL;
// Default styles
$bodyCss['font-family'] = "'" . $this->getPhpWord()->getDefaultFontName() . "'";
$bodyCss['font-size'] = $this->getPhpWord()->getDefaultFontSize() . 'pt';
$css .= '* ' . $this->assembleCss($bodyCss, true) . PHP_EOL;
// Custom styles
$styles = Style::getStyles();
if (is_array($styles)) {

View File

@ -0,0 +1,66 @@
<?php
/**
* PHPWord
*
* @link https://github.com/PHPOffice/PhpWord
* @copyright 2014 PHPWord
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Writer;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
/**
* PDF Writer
*/
class PDF
{
/**
* The wrapper for the requested PDF rendering engine
*
* @var \PhpOffice\PhpWord\Writer\PDF\Core
*/
private $renderer = null;
/**
* Instantiate a new renderer of the configured type within this container class
*
* @param \PhpOffice\PhpWord\PhpWord $phpWord
*/
public function __construct(PhpWord $phpWord)
{
$pdfLibraryName = Settings::getPdfRendererName();
$pdfLibraryPath = Settings::getPdfRendererPath();
if (is_null($pdfLibraryName) || is_null($pdfLibraryPath)) {
throw new Exception("PDF rendering library or library path has not been defined.");
}
$includePath = str_replace('\\', '/', get_include_path());
$rendererPath = str_replace('\\', '/', $pdfLibraryPath);
if (strpos($rendererPath, $includePath) === false) {
set_include_path(get_include_path() . PATH_SEPARATOR . $pdfLibraryPath);
}
$rendererName = 'PhpOffice\\PhpWord\\Writer\\PDF\\' . $pdfLibraryName;
$this->renderer = new $rendererName($phpWord);
}
/**
* Magic method to handle direct calls to the configured PDF renderer wrapper class.
*
* @param string $name Renderer library method name
* @param mixed[] $arguments Array of arguments to pass to the renderer method
* @return mixed Returned data from the PDF renderer wrapper method
*/
public function __call($name, $arguments)
{
if ($this->renderer === null) {
throw new Exception("PDF Rendering library has not been defined.");
}
return call_user_func_array(array($this->renderer, $name), $arguments);
}
}

View File

@ -0,0 +1,194 @@
<?php
/**
* PHPWord
*
* @link https://github.com/PHPOffice/PhpWord
* @copyright 2014 PHPWord
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Writer\PDF;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\PhpWord\Exception\Exception;
/**
* Core PDF Writer
*/
abstract class Core extends \PhpOffice\PhpWord\Writer\HTML
{
/**
* Temporary storage directory
*
* @var string
*/
protected $tempDir = '';
/**
* Font
*
* @var string
*/
protected $font;
/**
* Paper size
*
* @var int
*/
protected $paperSize = null;
/**
* Orientation
*
* @var string
*/
protected $orientation = null;
/**
* Temporary storage for Save Array Return type
*
* @var string
*/
private $saveArrayReturnType;
/**
* Paper Sizes xRef List
*
* @var array
*/
protected static $paperSizes = array(
9 => 'A4', // (210 mm by 297 mm)
);
/**
* Create new instance
*
* @param PhpWord $phpWord PhpWord object
*/
public function __construct(PhpWord $phpWord)
{
parent::__construct($phpWord);
$this->tempDir = sys_get_temp_dir();
}
/**
* Get Font
*
* @return string
*/
public function getFont()
{
return $this->font;
}
/**
* Set font. Examples:
* 'arialunicid0-chinese-simplified'
* 'arialunicid0-chinese-traditional'
* 'arialunicid0-korean'
* 'arialunicid0-japanese'
*
* @param string $fontName
*/
public function setFont($fontName)
{
$this->font = $fontName;
return $this;
}
/**
* Get Paper Size
*
* @return int
*/
public function getPaperSize()
{
return $this->paperSize;
}
/**
* Set Paper Size
*
* @param string $pValue Paper size = PAPERSIZE_A4
* @return self
*/
public function setPaperSize($pValue = 9)
{
$this->paperSize = $pValue;
return $this;
}
/**
* Get Orientation
*
* @return string
*/
public function getOrientation()
{
return $this->orientation;
}
/**
* Set Orientation
*
* @param string $pValue Page orientation ORIENTATION_DEFAULT
* @return self
*/
public function setOrientation($pValue = 'default')
{
$this->orientation = $pValue;
return $this;
}
/**
* Get temporary storage directory
*
* @return string
*/
public function getTempDir()
{
return $this->tempDir;
}
/**
* Set temporary storage directory
*
* @param string $pValue Temporary storage directory
* @return self
*/
public function setTempDir($pValue = '')
{
if (is_dir($pValue)) {
$this->tempDir = $pValue;
} else {
throw new Exception("Directory does not exist: $pValue");
}
return $this;
}
/**
* Save PhpWord to PDF file, pre-save
*
* @param string $pFilename Name of the file to save as
*/
protected function prepareForSave($pFilename = null)
{
$fileHandle = fopen($pFilename, 'w');
if ($fileHandle === false) {
throw new Exception("Could not open file $pFilename for writing.");
}
return $fileHandle;
}
/**
* Save PhpWord to PDF file, post-save
*
* @param resource $fileHandle
* @throws Exception
*/
protected function restoreStateAfterSave($fileHandle)
{
fclose($fileHandle);
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* PHPWord
*
* @link https://github.com/PHPOffice/PhpWord
* @copyright 2014 PHPWord
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Writer\PDF;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\PhpWord\Exception\Exception;
/** Require DomPDF library */
$pdfRendererClassFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php';
if (file_exists($pdfRendererClassFile)) {
require_once $pdfRendererClassFile;
} else {
throw new Exception('Unable to load PDF Rendering library');
}
/**
* DomPDF writer
*/
class DomPDF extends Core implements \PhpOffice\PhpWord\Writer\WriterInterface
{
/**
* Create new instance
*
* @param PhpWord $phpWord PhpWord object
*/
public function __construct(PhpWord $phpWord)
{
parent::__construct($phpWord);
}
/**
* Save PhpWord to file
*
* @param string $pFilename Name of the file to save as
* @throws Exception
*/
public function save($pFilename = null)
{
$fileHandle = parent::prepareForSave($pFilename);
// Default PDF paper size
$paperSize = 'A4';
$orientation = 'P';
$printPaperSize = 9;
if (isset(self::$paperSizes[$printPaperSize])) {
$paperSize = self::$paperSizes[$printPaperSize];
}
$orientation = ($orientation == 'L') ? 'landscape' : 'portrait';
// Create PDF
$pdf = new \DOMPDF();
$pdf->set_paper(strtolower($paperSize), $orientation);
$pdf->load_html($this->writeDocument());
$pdf->render();
// Write to file
fwrite($fileHandle, $pdf->output());
parent::restoreStateAfterSave($fileHandle);
}
}

View File

@ -55,6 +55,10 @@ class AbstractStyleTest extends \PHPUnit_Framework_TestCase
/**
* Helper function to call protected method
*
* @param mixed $object
* @param string $method
* @param array $args
*/
public static function callProtectedMethod($object, $method, array $args = array())
{