Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writer EPub3 : Added support #2724

Merged
merged 19 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ _build
/build
phpunit.xml
composer.phar
composer.lock
vendor
/report
/build
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@
"require": {
"php": "^7.1|^8.0",
"ext-dom": "*",
Sambit003 marked this conversation as resolved.
Show resolved Hide resolved
"ext-gd": "*",
Sambit003 marked this conversation as resolved.
Show resolved Hide resolved
"ext-gd": "*",
"ext-zip": "*",
"ext-json": "*",
"ext-xml": "*",
"ext-zip": "*",
"phpoffice/math": "^0.2"
},
"require-dev": {
Expand Down
2 changes: 2 additions & 0 deletions docs/changes/1.x/1.4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
- Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660)
- Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722)

- Added Support for Writer Epub3 by [@Sambit003](https://github.com/Sambit003) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724)

### Bug fixes

- Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668)
Expand Down
2 changes: 1 addition & 1 deletion samples/Sample_Header.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
}

// Set writers
$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'];
$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf', 'EPub3' => 'epub'];

// Set PDF renderer
if (null === Settings::getPdfRendererPath()) {
Expand Down
2 changes: 1 addition & 1 deletion src/PhpWord/IOFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ abstract class IOFactory
*/
public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
{
if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF'], true)) {
if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF', 'EPub3'], true)) {
throw new Exception("\"{$name}\" is not a valid writer.");
}

Expand Down
11 changes: 11 additions & 0 deletions src/PhpWord/Shared/ZipArchive.php
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,15 @@ public function pclzipLocateName($filename)

return ($listIndex > -1) ? $listIndex : false;
}

/**
* Add an empty directory to the zip archive (emulate \ZipArchive).
*
* @param string $dirname Directory name to add to the zip archive
*/
public function addEmptyDir(string $dirname): bool
{
// Create a directory entry by adding an empty file with trailing slash
return $this->addFromString(rtrim($dirname, '/') . '/', '');
}
}
91 changes: 91 additions & 0 deletions src/PhpWord/Writer/EPub3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
*
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/

namespace PhpOffice\PhpWord\Writer;

use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Writer\EPub3\Part\AbstractPart;

/**
* EPub3 writer.
*/
class EPub3 extends AbstractWriter implements WriterInterface
{
/**
* Create new EPub3 writer.
*/
public function __construct(?PhpWord $phpWord = null)
{
// Assign PhpWord
$this->setPhpWord($phpWord);

// Create parts
$this->parts = [
'Mimetype' => 'mimetype',
'Content' => 'content.opf',
'Toc' => 'toc.ncx',
'Styles' => 'styles.css',
'Manifest' => 'META-INF/container.xml',
'Nav' => 'nav.xhtml',
'ContentXhtml' => 'content.xhtml',
];
foreach (array_keys($this->parts) as $partName) {
$partClass = static::class . '\\Part\\' . $partName;
if (class_exists($partClass)) {
/** @var WriterPartInterface $part */
$part = new $partClass($partName === 'Content' || $partName === 'ContentXhtml' ? $phpWord : null);
$part->setParentWriter($this);
$this->writerParts[strtolower($partName)] = $part;
}
}

// Set package paths
$this->mediaPaths = ['image' => 'Images/', 'object' => 'Objects/'];
}

/**
* Save PhpWord to file.
*/
public function save(string $filename): void
{
$filename = $this->getTempFile($filename);
$zip = $this->getZipArchive($filename);

// Add mimetype first without compression
$zip->addFromString('mimetype', 'application/epub+zip');
$zip->addEmptyDir('META-INF');

// Add other files
foreach ($this->parts as $partName => $fileName) {
if ($fileName === '') {
continue;
}
$part = $this->getWriterPart($partName);
if (!$part instanceof AbstractPart) {
continue;
}
$zip->addFromString($fileName, $part->write());
}

// Close zip archive
$zip->close();

// Cleanup temp file
$this->cleanupTempFile();
}
}
45 changes: 45 additions & 0 deletions src/PhpWord/Writer/EPub3/Element/AbstractElement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
*
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/

namespace PhpOffice\PhpWord\Writer\EPub3\Element;

use PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement as Word2007AbstractElement;

/**
* Abstract element writer.
*
* @since 0.11.0
*/
abstract class AbstractElement extends Word2007AbstractElement
{
/**
* Get class name of writer element based on read element.
*
* @param \PhpOffice\PhpWord\Element\AbstractElement $element
*/
public static function getElementClass($element): string
{
$elementClass = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($element));
$writerClass = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\' . $elementClass;
if (!class_exists($writerClass)) {
throw new \PhpOffice\PhpWord\Exception\Exception("Writer element class {$writerClass} not found.");
}

return $writerClass;
}
}
45 changes: 45 additions & 0 deletions src/PhpWord/Writer/EPub3/Element/Image.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace PhpOffice\PhpWord\Writer\EPub3\Element;

use PhpOffice\PhpWord\Element\Image as ImageElement;

/**
* Image element writer for EPub3.
*/
class Image extends AbstractElement
{
/**
* Write element.
*/
public function write(): void
{
$xmlWriter = $this->getXmlWriter();
$xmlWriter->setIndent(false);
$element = $this->getElement();
if (!$element instanceof ImageElement) {
return;
}
$mediaIndex = $element->getMediaIndex();
$target = 'media/image' . $mediaIndex . '.' . $element->getImageExtension();
if (!$this->withoutP) {
$xmlWriter->startElement('p');
}
$xmlWriter->startElement('img');
$xmlWriter->writeAttribute('src', $target);
$style = '';
if ($element->getStyle()->getWidth() !== null) {
$style .= 'width:' . $element->getStyle()->getWidth() . 'px;';
}
if ($element->getStyle()->getHeight() !== null) {
$style .= 'height:' . $element->getStyle()->getHeight() . 'px;';
}
if ($style !== '') {
$xmlWriter->writeAttribute('style', $style);
}
$xmlWriter->endElement(); // img
if (!$this->withoutP) {
$xmlWriter->endElement(); // p
}
}
}
50 changes: 50 additions & 0 deletions src/PhpWord/Writer/EPub3/Element/Text.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace PhpOffice\PhpWord\Writer\EPub3\Element;

/**
* Text element writer for EPub3.
*/
class Text extends AbstractElement
{
/**
* Write element.
*/
public function write(): void
{
$xmlWriter = $this->getXmlWriter();
$xmlWriter->setIndent(true);
$xmlWriter->setIndentString(' ');
$element = $this->getElement();
if (!$element instanceof \PhpOffice\PhpWord\Element\Text) {
return;
}

$fontStyle = $element->getFontStyle();
$paragraphStyle = $element->getParagraphStyle();

if (!$this->withoutP) {
$xmlWriter->startElement('p');
if (is_string($paragraphStyle) && $paragraphStyle !== '') {
$xmlWriter->writeAttribute('class', $paragraphStyle);
}
}

if (!empty($fontStyle)) {
$xmlWriter->startElement('span');
if (is_string($fontStyle)) {
$xmlWriter->writeAttribute('class', $fontStyle);
}
}

$xmlWriter->text($element->getText());

if (!empty($fontStyle)) {
$xmlWriter->endElement(); // span
}

if (!$this->withoutP) {
$xmlWriter->endElement(); // p
}
}
}
45 changes: 45 additions & 0 deletions src/PhpWord/Writer/EPub3/Part.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
*
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/

namespace PhpOffice\PhpWord\Writer\EPub3;

use PhpOffice\PhpWord\Exception\Exception;

/**
* Factory class for EPub3 parts.
*/
class Part
{
/**
* Get the fully qualified class name for a specific part type.
*
* @param string $type The type of part (Content, Manifest, Meta, Mimetype)
*
* @return string The fully qualified class name
*/
public static function getPartClass(string $type): string
{
$class = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\' . $type;

if (!class_exists($class)) {
throw new Exception("Invalid part type: {$type}");
}

return $class;
}
}
Loading