Enable image in HTML writer

This commit is contained in:
Ivan Lanin 2014-04-16 12:12:32 +07:00
parent 9c738f7eae
commit 2829fd8216
8 changed files with 161 additions and 99 deletions

View File

@ -32,8 +32,8 @@ This release marked heavy refactorings on internal code structure with the creat
- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198
- ODT Writer: Basic table writing support - @ivanlanin - ODT Writer: Basic table writing support - @ivanlanin
- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 - 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 - HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64) - @ivanlanin GH-203 GH-67 GH-147
- PDF Writer: Basic PDF writer initiated using DomPDF - @ivanlanin GH-68 - PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68
### Bugfixes ### Bugfixes

View File

@ -62,63 +62,63 @@ Below are the supported features for each file formats.
Writers Writers
~~~~~~~ ~~~~~~~
+-------------------------------------------------+--------+-------+-------+ +-------------------------------------------------+--------+-------+-------+-------+-------+
| Features | DOCX | ODT | RTF | | Features | DOCX | ODT | RTF | HTML | PDF |
+=========================+=======================+========+=======+=======+ +=========================+=======================+========+=======+=======+=======+=======+
| **Document Properties** | Standard | | | | | **Document Properties** | Standard | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Extended | | | | | | Extended | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | UserDefined | | | | | | UserDefined | ✓ | | | | |
+-------------------------+-----------------------+--------+-------+-------+ +-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Element Type** | Text | ✓ | ✓ | ✓ | | **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Text Run | ✓ | ✓ | ✓ | | | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Title | ✓ | | | | | Title | ✓ | | | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Link | ✓ | | | | | Link | ✓ | | | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Preserve Text | ✓ | | | | | Preserve Text | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Text Break | ✓ | ✓ | ✓ | | | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Page Break | ✓ | | | | | Page Break | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | List | ✓ | | | | | List | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Table | ✓ | | | | | Table | ✓ | ✓ | | | ✓ |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Image | ✓ | | | | | Image | ✓ | | | ✓ | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Object | ✓ | | | | | Object | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Watermark | ✓ | | | | | Watermark | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Table of Contents | ✓ | | | | | Table of Contents | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Header | ✓ | | | | | Header | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Footer | ✓ | | | | | Footer | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Footnote | ✓ | | | | | Footnote | ✓ | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Endnote | ✓ | | | | | Endnote | ✓ | | | | |
+-------------------------+-----------------------+--------+-------+-------+ +-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Graphs** | 2D basic graphs | | | | | **Graphs** | 2D basic graphs | | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | 2D advanced graphs | | | | | | 2D advanced graphs | | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | 3D graphs | | | | | | 3D graphs | | | | | |
+-------------------------+-----------------------+--------+-------+-------+ +-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Math** | OMML support | | | | | **Math** | OMML support | | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | MathML support | | | | | | MathML support | | | | | |
+-------------------------+-----------------------+--------+-------+-------+ +-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Bonus** | Encryption | | | | | **Bonus** | Encryption | | | | | |
+ +-----------------------+--------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Protection | | | | | | Protection | | | | | |
+-------------------------+-----------------------+--------+-------+-------+ +-------------------------+-----------------------+--------+-------+-------+-------+-------+
Readers Readers

View File

@ -126,6 +126,16 @@ class Image extends AbstractElement
return $this->source; return $this->source;
} }
/**
* Get image source type
*
* @return string
*/
public function getSourceType()
{
return $this->sourceType;
}
/** /**
* Get image media ID * Get image media ID
* *
@ -324,6 +334,9 @@ class Image extends AbstractElement
/** /**
* Set proportional width/height if one dimension not available * Set proportional width/height if one dimension not available
*
* @param integer $actualWidth
* @param integer $actualHeight
*/ */
private function setProportionalSize($actualWidth, $actualHeight) private function setProportionalSize($actualWidth, $actualHeight)
{ {

View File

@ -164,11 +164,7 @@ abstract class AbstractWriter implements WriterInterface
protected function getTempFile($filename) protected function getTempFile($filename)
{ {
// Temporary directory // Temporary directory
$tempDir = sys_get_temp_dir() . '/PHPWordMedia/'; $this->setTempDir();
if (!is_dir($tempDir)) {
mkdir($tempDir);
}
$this->tempDir = $tempDir;
// Temporary file // Temporary file
$this->originalFilename = $filename; $this->originalFilename = $filename;
@ -184,23 +180,30 @@ abstract class AbstractWriter implements WriterInterface
} }
/** /**
* Cleanup temporary file * Get temporary directory
*
* If a temporary file was used, copy it to the correct file stream
*/ */
protected function getTempDir() protected function getTempDir()
{ {
return $this->tempDir; return $this->tempDir;
} }
/**
* Set temporary directory
*/
protected function setTempDir()
{
$tempDir = sys_get_temp_dir() . '/PHPWordMedia/';
if (!is_dir($tempDir)) {
mkdir($tempDir);
}
$this->tempDir = $tempDir;
}
/** /**
* Cleanup temporary file * Cleanup temporary file
*
* If a temporary file was used, copy it to the correct file stream
*/ */
protected function cleanupTempFile() protected function cleanupTempFile()
{ {
// File
if ($this->originalFilename != $this->tempFilename) { if ($this->originalFilename != $this->tempFilename) {
if (copy($this->tempFilename, $this->originalFilename) === false) { if (copy($this->tempFilename, $this->originalFilename) === false) {
throw new Exception("Could not copy temporary zip file {$this->tempFilename} to {$this->originalFilename}."); throw new Exception("Could not copy temporary zip file {$this->tempFilename} to {$this->originalFilename}.");
@ -208,7 +211,14 @@ abstract class AbstractWriter implements WriterInterface
@unlink($this->tempFilename); @unlink($this->tempFilename);
} }
// Directory $this->clearTempDir();
}
/**
* Clear temporary directory
*/
protected function clearTempDir()
{
if (is_dir($this->tempDir)) { if (is_dir($this->tempDir)) {
$this->deleteDir($this->tempDir); $this->deleteDir($this->tempDir);
} }

View File

@ -36,6 +36,13 @@ use PhpOffice\PhpWord\TOC;
*/ */
class HTML extends AbstractWriter implements WriterInterface class HTML extends AbstractWriter implements WriterInterface
{ {
/**
* Is the current writer creating PDF?
*
* @var boolean
*/
protected $isPdf = false;
/** /**
* Create new instance * Create new instance
*/ */
@ -53,9 +60,11 @@ class HTML extends AbstractWriter implements WriterInterface
public function save($filename = null) public function save($filename = null)
{ {
if (!is_null($this->getPhpWord())) { if (!is_null($this->getPhpWord())) {
$this->setTempDir();
$hFile = fopen($filename, 'w') or die("can't open file"); $hFile = fopen($filename, 'w') or die("can't open file");
fwrite($hFile, $this->writeDocument()); fwrite($hFile, $this->writeDocument());
fclose($hFile); fclose($hFile);
$this->clearTempDir();
} else { } else {
throw new Exception("No PHPWord assigned."); throw new Exception("No PHPWord assigned.");
} }
@ -421,7 +430,18 @@ class HTML extends AbstractWriter implements WriterInterface
*/ */
private function writeImage($element, $withoutP = false) private function writeImage($element, $withoutP = false)
{ {
return $this->writeUnsupportedElement($element, $withoutP); $html = $this->writeUnsupportedElement($element, $withoutP);
if (!$this->isPdf) {
$imageData = $this->getBase64ImageData($element);
if (!is_null($imageData)) {
$html = '<img border="0" src="' . $imageData . '"/>';
if (!$withoutP) {
$html = '<p>' . $html . '</p>' . PHP_EOL;
}
}
}
return $html;
} }
/** /**
@ -597,4 +617,42 @@ class HTML extends AbstractWriter implements WriterInterface
return $string; return $string;
} }
/**
* Get Base64 image data
*
* @return string|null
*/
private function getBase64ImageData(Image $element)
{
$imageData = null;
$source = $element->getSource();
$imageType = $element->getImageType();
// Get actual source
if ($element->getSourceType() == 'archive') {
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$zip = new \ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename)) {
$zip->extractTo($this->getTempDir(), $imageFilename);
$actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
// Read image binary data and convert into Base64
if ($fp = fopen($actualSource, "rb", 0)) {
$image = fread($fp, filesize($actualSource));
fclose($fp);
$base64 = chunk_split(base64_encode($image));
$imageData = 'data:' . $imageType . ';base64,' . $base64;
}
return $imageData;
}
} }

View File

@ -69,7 +69,6 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
public function __construct(PhpWord $phpWord) public function __construct(PhpWord $phpWord)
{ {
parent::__construct($phpWord); parent::__construct($phpWord);
$this->setTempDir(sys_get_temp_dir());
} }
/** /**
@ -141,36 +140,11 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
return $this; 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 * Save PhpWord to PDF file, pre-save
* *
* @param string $pFilename Name of the file to save as * @param string $pFilename Name of the file to save as
* @return resource
*/ */
protected function prepareForSave($pFilename = null) protected function prepareForSave($pFilename = null)
{ {
@ -178,6 +152,8 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
if ($fileHandle === false) { if ($fileHandle === false) {
throw new Exception("Could not open file $pFilename for writing."); throw new Exception("Could not open file $pFilename for writing.");
} }
$this->isPdf = true;
return $fileHandle; return $fileHandle;
} }

View File

@ -181,6 +181,8 @@ class Word2007 extends AbstractWriter implements WriterInterface
/** /**
* Add file to package * Add file to package
* *
* Get the actual source from an archive image
*
* @param mixed $objZip * @param mixed $objZip
* @param string $source * @param string $source
* @param string $target * @param string $target

View File

@ -39,6 +39,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase
$this->assertFalse(Settings::setZipClass('foo')); $this->assertFalse(Settings::setZipClass('foo'));
} }
/**
* Test set/get PDF renderer
*/
public function testSetGetPdfRenderer() public function testSetGetPdfRenderer()
{ {
$domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');