diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6df064a06..36c27c26e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
### Features
-None yet.
+- Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin GH-123
### Bugfixes
diff --git a/docs/elements.rst b/docs/elements.rst
index 7d07674206..a3a8171721 100644
--- a/docs/elements.rst
+++ b/docs/elements.rst
@@ -47,6 +47,8 @@ column shows the containers while the rows lists the elements.
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
| 19 | Line | v | v | v | v | v | v |
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
+| 20 | Shapes | v | v | v | v | v | v |
++-------+-----------------+-----------+----------+----------+---------+------------+------------+
Legend:
@@ -490,7 +492,12 @@ Fields
To be completed
-Line
+Lines
+-----
+
+To be completed
+
+Shapes
------
To be completed
diff --git a/docs/intro.rst b/docs/intro.rst
index aca5b24153..5045d4dc1d 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -99,11 +99,11 @@ Writers
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | Endnote | ✓ | | | ✓ | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
-| **Graphs** | 2D basic graphs | | | | | |
+| **Graphs** | 2D basic graphs | ✓ | | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | 2D advanced graphs | | | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
-| | 3D graphs | | | | | |
+| | 3D graphs | ✓ | | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| **Math** | OMML support | | | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
diff --git a/docs/src/documentation.md b/docs/src/documentation.md
index 84522c1b5f..e971640144 100644
--- a/docs/src/documentation.md
+++ b/docs/src/documentation.md
@@ -36,6 +36,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst
- [Textboxes](#textboxes)
- [Fields](#fields)
- [Lines](#lines)
+ - [Shapes](#shapes)
- [Templates](#templates)
- [Writers & readers](#writers-readers)
- [OOXML](#ooxml)
@@ -101,9 +102,9 @@ Below are the supported features for each file formats.
| | Footer | ✓ | | | | |
| | Footnote | ✓ | | | ✓ | |
| | Endnote | ✓ | | | ✓ | |
-| **Graphs** | 2D basic graphs | | | | | |
+| **Graphs** | 2D basic graphs | ✓ | | | | |
| | 2D advanced graphs | | | | | |
-| | 3D graphs | | | | | |
+| | 3D graphs | ✓ | | | | |
| **Math** | OMML support | | | | | |
| | MathML support | | | | | |
| **Bonus** | Encryption | | | | | |
@@ -465,6 +466,7 @@ Below are the matrix of element availability in each container. The column shows
| 17 | TextBox | v | v | v | v | - | - |
| 18 | Field | v | v | v | v | v | v |
| 19 | Line | v | v | v | v | v | v |
+| 20 | Shape | v | v | v | v | v | v |
Legend:
@@ -850,6 +852,10 @@ To be completed.
To be completed.
+## Shapes
+
+To be completed.
+
# Templates
You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file.
diff --git a/phpmd.xml.dist b/phpmd.xml.dist
index f0b62b2d6e..5eb348ecfe 100644
--- a/phpmd.xml.dist
+++ b/phpmd.xml.dist
@@ -18,7 +18,7 @@
-
+
diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php
new file mode 100644
index 0000000000..02399992e7
--- /dev/null
+++ b/samples/Sample_31_Shape.php
@@ -0,0 +1,82 @@
+addTitleStyle(1, array('size' => 14, 'bold' => true));
+
+$section = $phpWord->addSection();
+
+// Arc
+$section->addTitle('Arc', 1);
+$section->addShape(
+ 'arc',
+ array(
+ 'points' => '-90 20',
+ 'frame' => array('width' => 120, 'height' => 120),
+ 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'),
+ )
+);
+
+// Curve
+$section->addTitle('Curve', 1);
+$section->addShape(
+ 'curve',
+ array(
+ 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow',
+ 'outline' => array('color' => '#66cc00', 'weight' => 2, 'dash' => 'dash', 'startArrow' => 'diamond', 'endArrow' => 'block'),
+ )
+);
+
+// Line
+$section->addTitle('Line', 1);
+$section->addShape(
+ 'line',
+ array(
+ 'points' => '1,1 150,30',
+ 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3, 'startArrow' => 'oval', 'endArrow' => 'classic'),
+ )
+);
+
+// Polyline
+$section->addTitle('Polyline', 1);
+$section->addShape(
+ 'polyline',
+ array(
+ 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50',
+ 'outline' => array('color' => '#cc6666', 'weight' => 2, 'startArrow' => 'none', 'endArrow' => 'classic'),
+ )
+);
+
+// Rectangle
+$section->addTitle('Rectangle', 1);
+$section->addShape(
+ 'rect',
+ array(
+ 'roundness' => 0.2,
+ 'frame' => array('width' => 100, 'height' => 100, 'left' => 1, 'top' => 1),
+ 'fill' => array('color' => '#FFCC33'),
+ 'outline' => array('color' => '#990000', 'weight' => 1),
+ 'shadow' => array(),
+ )
+);
+
+// Oval
+$section->addTitle('Oval', 1);
+$section->addShape(
+ 'oval',
+ array(
+ 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1),
+ 'fill' => array('color' => '#33CC99'),
+ 'outline' => array('color' => '#333333', 'weight' => 2),
+ 'extrusion' => array(),
+ )
+);
+
+// Save file
+echo write($phpWord, basename(__FILE__, '.php'), $writers);
+if (!CLI) {
+ include_once 'Sample_Footer.php';
+}
diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php
index 4bbe5ddff5..ae750de995 100644
--- a/src/PhpWord/Element/AbstractContainer.php
+++ b/src/PhpWord/Element/AbstractContainer.php
@@ -39,6 +39,7 @@
* @method TextBox addTextBox($style = null)
* @method Field addField($type = null, $properties = array(), $options = array())
* @method Line addLine($lineStyle = null)
+ * @method Shape addObject($type, $style = null)
*
* @since 0.10.0
*/
@@ -74,7 +75,7 @@ public function __call($function, $args)
{
$elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak',
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote',
- 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line');
+ 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape');
$functions = array();
for ($i = 0; $i < count($elements); $i++) {
$functions[$i] = 'add' . $elements[$i];
@@ -242,6 +243,7 @@ private function checkValidity($method)
'Object' => $allContainers,
'Field' => $allContainers,
'Line' => $allContainers,
+ 'Shape' => $allContainers,
'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php
index ca45ef23f9..c8e574b7e5 100644
--- a/src/PhpWord/Element/AbstractElement.php
+++ b/src/PhpWord/Element/AbstractElement.php
@@ -262,4 +262,25 @@ protected function setStyle($styleObject, $styleValue = null, $returnObject = fa
return $style;
}
+
+ /**
+ * Set enum value
+ *
+ * @param mixed $value
+ * @param array $enum
+ * @param mixed $default
+ * @return mixed
+ * @throws \InvalidArgumentException
+ * @todo Merge with the same method in AbstractStyle
+ */
+ protected function setEnumVal($value = null, $enum = array(), $default = null)
+ {
+ if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
+ throw new \InvalidArgumentException("Invalid style value: {$value}");
+ } elseif ($value === null || trim($value) == '') {
+ $value = $default;
+ }
+
+ return $value;
+ }
}
diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php
new file mode 100644
index 0000000000..9b3aae4ffe
--- /dev/null
+++ b/src/PhpWord/Element/Shape.php
@@ -0,0 +1,88 @@
+setType($type);
+ $this->style = $this->setStyle(new ShapeStyle(), $style);
+ }
+
+ /**
+ * Get type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set pattern
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setType($value = null)
+ {
+ $enum = array('arc', 'curve', 'line', 'polyline', 'rect', 'oval');
+ $this->type = $this->setEnumVal($value, $enum, null);
+
+ return $this;
+ }
+
+ /**
+ * Get shape style
+ *
+ * @return \PhpOffice\PhpWord\Style\Shape
+ */
+ public function getStyle()
+ {
+ return $this->style;
+ }
+}
diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php
index 13ef8f9b26..4d3758889d 100644
--- a/src/PhpWord/Style/AbstractStyle.php
+++ b/src/PhpWord/Style/AbstractStyle.php
@@ -264,7 +264,7 @@ protected function setFloatVal($value, $default = null)
protected function setEnumVal($value = null, $enum = array(), $default = null)
{
if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
- throw new \InvalidArgumentException('Invalid style value.');
+ throw new \InvalidArgumentException("Invalid style value: {$value}");
} elseif ($value === null || trim($value) == '') {
$value = $default;
}
diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php
new file mode 100644
index 0000000000..ccbb26505b
--- /dev/null
+++ b/src/PhpWord/Style/Extrusion.php
@@ -0,0 +1,106 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set pattern
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setType($value = null)
+ {
+ $enum = array(self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE);
+ $this->type = $this->setEnumVal($value, $enum, null);
+
+ return $this;
+ }
+
+ /**
+ * Get color
+ *
+ * @return string
+ */
+ public function getColor()
+ {
+ return $this->color;
+ }
+
+ /**
+ * Set color
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setColor($value = null)
+ {
+ $this->color = $value;
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php
new file mode 100644
index 0000000000..08c7a85739
--- /dev/null
+++ b/src/PhpWord/Style/Fill.php
@@ -0,0 +1,69 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get color
+ *
+ * @return string
+ */
+ public function getColor()
+ {
+ return $this->color;
+ }
+
+ /**
+ * Set color
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setColor($value = null)
+ {
+ $this->color = $value;
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php
new file mode 100644
index 0000000000..fce3f4a997
--- /dev/null
+++ b/src/PhpWord/Style/Frame.php
@@ -0,0 +1,159 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get width
+ *
+ * @return int|float
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * Set width
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setWidth($value = null)
+ {
+ $this->width = $this->setNumericVal($value, null);
+
+ return $this;
+ }
+
+ /**
+ * Get height
+ *
+ * @return int|float
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * Set height
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setHeight($value = null)
+ {
+ $this->height = $this->setNumericVal($value, null);
+
+ return $this;
+ }
+
+ /**
+ * Get left
+ *
+ * @return int|float
+ */
+ public function getLeft()
+ {
+ return $this->left;
+ }
+
+ /**
+ * Set left
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setLeft($value = 0)
+ {
+ $this->left = $this->setNumericVal($value, 0);
+
+ return $this;
+ }
+
+ /**
+ * Get topmost position
+ *
+ * @return int|float
+ */
+ public function getTop()
+ {
+ return $this->top;
+ }
+
+ /**
+ * Set topmost position
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setTop($value = 0)
+ {
+ $this->top = $this->setNumericVal($value, 0);
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php
new file mode 100644
index 0000000000..7e6b19cf90
--- /dev/null
+++ b/src/PhpWord/Style/Outline.php
@@ -0,0 +1,248 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get weight
+ *
+ * @return int|float
+ */
+ public function getWeight()
+ {
+ return $this->weight;
+ }
+
+ /**
+ * Set weight
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setWeight($value = null)
+ {
+ $this->weight = $this->setNumericVal($value, null);
+
+ return $this;
+ }
+
+ /**
+ * Get color
+ *
+ * @return string
+ */
+ public function getColor()
+ {
+ return $this->color;
+ }
+
+ /**
+ * Set color
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setColor($value = null)
+ {
+ $this->color = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get dash type
+ *
+ * @return string
+ */
+ public function getDash()
+ {
+ return $this->dash;
+ }
+
+ /**
+ * Set dash type
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setDash($value = null)
+ {
+ $this->dash = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get line style
+ *
+ * @return string
+ */
+ public function getLine()
+ {
+ return $this->line;
+ }
+
+ /**
+ * Set line style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setLine($value = null)
+ {
+ $enum = array(self::LINE_SINGLE, self::LINE_THIN_THIN, self::LINE_THIN_THICK,
+ self::LINE_THICK_THIN, self::LINE_THICK_BETWEEN_THIN);
+ $this->line = $this->setEnumVal($value, $enum, null);
+
+ return $this;
+ }
+
+ /**
+ * Get startArrow
+ *
+ * @return string
+ */
+ public function getStartArrow()
+ {
+ return $this->startArrow;
+ }
+
+ /**
+ * Set pattern
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setStartArrow($value = null)
+ {
+ $enum = array(self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC,
+ self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN);
+ $this->startArrow = $this->setEnumVal($value, $enum, null);
+
+ return $this;
+ }
+
+ /**
+ * Get endArrow
+ *
+ * @return string
+ */
+ public function getEndArrow()
+ {
+ return $this->endArrow;
+ }
+
+ /**
+ * Set pattern
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setEndArrow($value = null)
+ {
+ $enum = array(self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC,
+ self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN);
+ $this->endArrow = $this->setEnumVal($value, $enum, null);
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php
new file mode 100644
index 0000000000..deafbff0f8
--- /dev/null
+++ b/src/PhpWord/Style/Shadow.php
@@ -0,0 +1,97 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get color
+ *
+ * @return string
+ */
+ public function getColor()
+ {
+ return $this->color;
+ }
+
+ /**
+ * Set color
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setColor($value = null)
+ {
+ $this->color = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get offset
+ *
+ * @return string
+ */
+ public function getOffset()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * Set offset
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setOffset($value = null)
+ {
+ $this->offset = $value;
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php
new file mode 100644
index 0000000000..c9809920bb
--- /dev/null
+++ b/src/PhpWord/Style/Shape.php
@@ -0,0 +1,255 @@
+setStyleByArray($style);
+ }
+
+ /**
+ * Get points
+ *
+ * @return string
+ */
+ public function getPoints()
+ {
+ return $this->points;
+ }
+
+ /**
+ * Set points
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setPoints($value = null)
+ {
+ $this->points = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get roundness
+ *
+ * @return int|float
+ */
+ public function getRoundness()
+ {
+ return $this->roundness;
+ }
+
+ /**
+ * Set roundness
+ *
+ * @param int|float $value
+ * @return self
+ */
+ public function setRoundness($value = null)
+ {
+ $this->roundness = $this->setNumericVal($value, null);
+
+ return $this;
+ }
+
+ /**
+ * Get frame
+ *
+ * @return \PhpOffice\PhpWord\Style\Frame
+ */
+ public function getFrame()
+ {
+ return $this->frame;
+ }
+
+ /**
+ * Set frame
+ *
+ * @param mixed $value
+ * @return self
+ */
+ public function setFrame($value = null)
+ {
+ $this->setObjectVal($value, 'Frame', $this->frame);
+
+ return $this;
+ }
+
+ /**
+ * Get fill
+ *
+ * @return \PhpOffice\PhpWord\Style\Fill
+ */
+ public function getFill()
+ {
+ return $this->fill;
+ }
+
+ /**
+ * Set fill
+ *
+ * @param mixed $value
+ * @return self
+ */
+ public function setFill($value = null)
+ {
+ $this->setObjectVal($value, 'Fill', $this->fill);
+
+ return $this;
+ }
+
+ /**
+ * Get outline
+ *
+ * @return \PhpOffice\PhpWord\Style\Outline
+ */
+ public function getOutline()
+ {
+ return $this->outline;
+ }
+
+ /**
+ * Set outline
+ *
+ * @param mixed $value
+ * @return self
+ */
+ public function setOutline($value = null)
+ {
+ $this->setObjectVal($value, 'Outline', $this->outline);
+
+ return $this;
+ }
+
+ /**
+ * Get shadow
+ *
+ * @return \PhpOffice\PhpWord\Style\Shadow
+ */
+ public function getShadow()
+ {
+ return $this->shadow;
+ }
+
+ /**
+ * Set shadow
+ *
+ * @param mixed $value
+ * @return self
+ */
+ public function setShadow($value = null)
+ {
+ $this->setObjectVal($value, 'Shadow', $this->shadow);
+
+ return $this;
+ }
+
+ /**
+ * Get 3D extrusion
+ *
+ * @return \PhpOffice\PhpWord\Style\Extrusion
+ */
+ public function getExtrusion()
+ {
+ return $this->extrusion;
+ }
+
+ /**
+ * Set 3D extrusion
+ *
+ * @param mixed $value
+ * @return self
+ */
+ public function setExtrusion($value = null)
+ {
+ $this->setObjectVal($value, 'Extrusion', $this->extrusion);
+
+ return $this;
+ }
+}
diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php
index 18f2828751..8645a1f402 100644
--- a/src/PhpWord/Writer/HTML/Style/Font.php
+++ b/src/PhpWord/Writer/HTML/Style/Font.php
@@ -17,7 +17,6 @@
namespace PhpOffice\PhpWord\Writer\HTML\Style;
-use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Style\Font as FontStyle;
/**
diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php
new file mode 100644
index 0000000000..5590861c8a
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Element/Shape.php
@@ -0,0 +1,169 @@
+getXmlWriter();
+ $element = $this->getElement();
+ if (!$element instanceof ShapeElement) {
+ return;
+ }
+
+ $style = $element->getStyle();
+ $type = $element->getType();
+ if ($type == 'rect' && $style->getRoundness() !== null) {
+ $type = 'roundrect';
+ }
+ $method = "write{$type}";
+
+ if (!$this->withoutP) {
+ $xmlWriter->startElement('w:p');
+ }
+
+ $xmlWriter->startElement('w:r');
+ $xmlWriter->startElement('w:pict');
+ $xmlWriter->startElement("v:{$type}");
+
+ // Element style
+ if (method_exists($this, $method)) {
+ $this->$method($xmlWriter, $style);
+ }
+
+ // Child style
+ $styleWriter = new ShapeStyleWriter($xmlWriter, $style);
+ $styleWriter->write();
+
+ $xmlWriter->endElement(); // v:$type
+ $xmlWriter->endElement(); // w:pict
+ $xmlWriter->endElement(); // w:r
+
+ if (!$this->withoutP) {
+ $xmlWriter->endElement(); // w:p
+ }
+ }
+
+ /**
+ * Write arc
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param \PhpOffice\PhpWord\Style\Shape $style
+ */
+ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style)
+ {
+ $points = $this->getPoints('arc', $style->getPoints());
+
+ $xmlWriter->writeAttributeIf($points['start'] !== null, 'startAngle', $points['start']);
+ $xmlWriter->writeAttributeIf($points['end'] !== null, 'endAngle', $points['end']);
+ }
+
+ /**
+ * Write curve
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param \PhpOffice\PhpWord\Style\Shape $style
+ */
+ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style)
+ {
+ $points = $this->getPoints('curve', $style->getPoints());
+
+ $this->writeLine($xmlWriter, $style);
+ $xmlWriter->writeAttributeIf($points['point1'] !== null, 'control1', $points['point1']);
+ $xmlWriter->writeAttributeIf($points['point2'] !== null, 'control2', $points['point2']);
+ }
+
+ /**
+ * Write line
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param \PhpOffice\PhpWord\Style\Shape $style
+ */
+ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style)
+ {
+ $points = $this->getPoints('line', $style->getPoints());
+
+ $xmlWriter->writeAttributeIf($points['start'] !== null, 'from', $points['start']);
+ $xmlWriter->writeAttributeIf($points['end'] !== null, 'to', $points['end']);
+ }
+
+ /**
+ * Write polyline
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param \PhpOffice\PhpWord\Style\Shape $style
+ */
+ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style)
+ {
+ $xmlWriter->writeAttributeIf($style->getPoints() !== null, 'points', $style->getPoints());
+ }
+
+ /**
+ * Write rectangle
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param \PhpOffice\PhpWord\Style\Shape $style
+ */
+ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style)
+ {
+ $xmlWriter->writeAttribute('arcsize', $style->getRoundness());
+ }
+
+ /**
+ * Set points
+ *
+ * @param string $type
+ * @param string $value
+ * @return array
+ */
+ private function getPoints($type, $value)
+ {
+ $points = array();
+
+ switch ($type) {
+ case 'arc':
+ case 'line':
+ $points = explode(' ', $value);
+ @list($start, $end) = $points;
+ $points = array('start' => $start, 'end' => $end);
+ break;
+ case 'curve':
+ $points = explode(' ', $value);
+ @list($start, $end, $point1, $point2) = $points;
+ $points = array('start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2);
+ break;
+ }
+
+ return $points;
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
index 61c8bae808..d91e37b8d2 100644
--- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
+++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
@@ -102,4 +102,40 @@ protected function convertTwip($value, $default = 0)
return $value * $factor;
}
+
+ /**
+ * Write child style
+ *
+ * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
+ * @param string $name
+ * @param mixed $value
+ */
+ protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value)
+ {
+ if ($value !== null) {
+ $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name;
+
+ /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */
+ $writer = new $class($xmlWriter, $value);
+ $writer->write();
+ }
+ }
+
+ /**
+ * Assemble style array into style string
+ *
+ * @param array $styles
+ * @return string
+ */
+ protected function assembleStyle($styles = array())
+ {
+ $style = '';
+ foreach ($styles as $key => $value) {
+ if (!is_null($value) && $value != '') {
+ $style .= "{$key}:{$value}; ";
+ }
+ }
+
+ return trim($style);
+ }
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php
new file mode 100644
index 0000000000..aa8ba1eadf
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php
@@ -0,0 +1,44 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Extrusion) {
+ return;
+ }
+ $xmlWriter = $this->getXmlWriter();
+
+ $xmlWriter->startElement("o:extrusion");
+ $xmlWriter->writeAttribute('on', 't');
+ $xmlWriter->writeAttributeIf($style->getType() !== null, 'type', $style->getType());
+ $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());
+ $xmlWriter->endElement();
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php
new file mode 100644
index 0000000000..0695f8eff0
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Fill.php
@@ -0,0 +1,41 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Fill) {
+ return;
+ }
+ $xmlWriter = $this->getXmlWriter();
+
+ $xmlWriter->writeAttribute('on', 't');
+ $xmlWriter->writeAttributeIf($style->getColor() !== null, 'fillcolor', $style->getColor());
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php
new file mode 100644
index 0000000000..dd2337eec8
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Frame.php
@@ -0,0 +1,56 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Frame) {
+ return;
+ }
+ $xmlWriter = $this->getXmlWriter();
+
+ $styles = array();
+ $properties = array(
+ 'left' => 'margin-left',
+ 'top' => 'margin-top',
+ 'width' => 'width',
+ 'height' => 'height',
+ );
+
+ foreach ($properties as $key => $property) {
+ $method = "get{$key}";
+ $value = $style->$method();
+ if ($value !== null) {
+ $styles[$property] = $style->$method() . 'pt';
+ }
+ }
+
+ $xmlWriter->writeAttribute('style', $this->assembleStyle($styles));
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php
index 280b569a4a..aebc93c114 100644
--- a/src/PhpWord/Writer/Word2007/Style/Image.php
+++ b/src/PhpWord/Writer/Word2007/Style/Image.php
@@ -152,22 +152,4 @@ protected function getElementStyle(ImageStyle $style)
return $styles;
}
-
- /**
- * Assemble style array into style string
- *
- * @param array $styles
- * @return string
- */
- protected function assembleStyle($styles = array())
- {
- $style = '';
- foreach ($styles as $key => $value) {
- if (!is_null($value) && $value != '') {
- $style .= "{$key}:{$value}; ";
- }
- }
-
- return trim($style);
- }
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php
new file mode 100644
index 0000000000..5003d9fca6
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Outline.php
@@ -0,0 +1,48 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Outline) {
+ return;
+ }
+ $xmlWriter = $this->getXmlWriter();
+
+ $xmlWriter->startElement("v:stroke");
+ $xmlWriter->writeAttribute('on', 't');
+ $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());
+ $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . 'pt');
+ $xmlWriter->writeAttributeIf($style->getDash() !== null, 'dashstyle', $style->getDash());
+ $xmlWriter->writeAttributeIf($style->getLine() !== null, 'linestyle', $style->getLine());
+ $xmlWriter->writeAttributeIf($style->getStartArrow() !== null, 'startarrow', $style->getStartArrow());
+ $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow());
+ $xmlWriter->endElement();
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php
index f328770083..0e97a7d7dc 100644
--- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php
+++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php
@@ -110,24 +110,6 @@ private function writeStyle()
}
}
- /**
- * Write child style
- *
- * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
- * @param string $name
- * @param mixed $value
- */
- private function writeChildStyle(XMLWriter $xmlWriter, $name, $value)
- {
- if ($value !== null) {
- $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name;
-
- /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */
- $writer = new $class($xmlWriter, $value);
- $writer->write();
- }
- }
-
/**
* Write tabs
*
diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php
new file mode 100644
index 0000000000..dd7c769aca
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php
@@ -0,0 +1,44 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Shadow) {
+ return;
+ }
+ $xmlWriter = $this->getXmlWriter();
+
+ $xmlWriter->startElement("v:shadow");
+ $xmlWriter->writeAttribute('on', 't');
+ $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());
+ $xmlWriter->writeAttributeIf($style->getOffset() !== null, 'offset', $style->getOffset());
+ $xmlWriter->endElement();
+ }
+}
diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php
new file mode 100644
index 0000000000..7eafb18e1a
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Style/Shape.php
@@ -0,0 +1,45 @@
+getStyle();
+ if (!$style instanceof \PhpOffice\PhpWord\Style\Shape) {
+ return;
+ }
+
+ $xmlWriter = $this->getXmlWriter();
+
+ $childStyles = array('Frame', 'Fill', 'Outline', 'Shadow', 'Extrusion');
+ foreach ($childStyles as $childStyle) {
+ $method = "get{$childStyle}";
+ $this->writeChildStyle($xmlWriter, $childStyle, $style->$method());
+ }
+ }
+}
diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php
index da7504b5c1..6ba3477be0 100644
--- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php
+++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php
@@ -41,7 +41,7 @@ public function testUnmatchedElements()
$elements = array(
'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun',
'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC',
- 'Field', 'Line'
+ 'Field', 'Line', 'Shape'
);
foreach ($elements as $element) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element;
@@ -61,10 +61,91 @@ public function testLineElement()
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
+
$section->addLine(array('width' => 1000, 'height' => 1000, 'positioning' => 'absolute', 'flip' => true));
$doc = TestHelperDOCX::getDocument($phpWord);
$element = "/w:document/w:body/w:p/w:r/w:pict/v:shapetype";
$this->assertTrue($doc->elementExists($element));
}
+
+ /**
+ * Test shape elements
+ */
+ public function testShapeElements()
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // Arc
+ $section->addShape(
+ 'arc',
+ array(
+ 'points' => '-90 20',
+ 'frame' => array('width' => 120, 'height' => 120),
+ 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'),
+ )
+ );
+
+ // Curve
+ $section->addShape(
+ 'curve',
+ array(
+ 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow',
+ 'outline' => array('color' => '#66cc00', 'weight' => 2, 'dash' => 'dash',
+ 'startArrow' => 'diamond', 'endArrow' => 'block'),
+ )
+ );
+
+ // Line
+ $section->addShape(
+ 'line',
+ array(
+ 'points' => '1,1 150,30',
+ 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3,
+ 'startArrow' => 'oval', 'endArrow' => 'classic'),
+ )
+ );
+
+ // Polyline
+ $section->addShape(
+ 'polyline',
+ array(
+ 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50',
+ 'outline' => array('color' => '#cc6666', 'weight' => 2,
+ 'startArrow' => 'none', 'endArrow' => 'classic'),
+ )
+ );
+
+ // Rectangle
+ $section->addShape(
+ 'rect',
+ array(
+ 'roundness' => 0.2,
+ 'frame' => array('width' => 100, 'height' => 100, 'left' => 1, 'top' => 1),
+ 'fill' => array('color' => '#FFCC33'),
+ 'outline' => array('color' => '#990000', 'weight' => 1),
+ 'shadow' => array('color' => '#EEEEEE', 'offset' => '3pt,3pt'),
+ )
+ );
+
+ // Oval
+ $section->addShape(
+ 'oval',
+ array(
+ 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1),
+ 'fill' => array('color' => '#33CC99'),
+ 'outline' => array('color' => '#333333', 'weight' => 2),
+ 'extrusion' => array('type' => 'perspective', 'color' => '#EEEEEE'),
+ )
+ );
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $elements = array('arc', 'curve', 'line', 'polyline', 'roundrect', 'oval');
+ foreach ($elements as $element) {
+ $path = "/w:document/w:body/w:p/w:r/w:pict/v:{$element}";
+ $this->assertTrue($doc->elementExists($path));
+ }
+ }
}
diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php
index 71cbc30068..c840d2074f 100644
--- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php
+++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php
@@ -31,7 +31,7 @@ public function testEmptyStyles()
$styles = array(
'Alignment', 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering',
'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table',
- 'TextBox', 'Line'
+ 'TextBox', 'Line', 'Shape', 'Frame', 'Outline', 'Fill', 'Shadow', 'Extrusion',
);
foreach ($styles as $style) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style;