diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 532905f428..451a5ae513 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -33,7 +33,8 @@ class Image extends AbstractElement const SOURCE_LOCAL = 'local'; // Local images const SOURCE_GD = 'gd'; // Generated using GD const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image - + const SOURCE_INLINE = 'inline'; // Image in inline base64 encoding + /** * Image source * @@ -341,6 +342,11 @@ public function getImageStringData($base64 = false) fclose($fileHandle); } } + + if ($this->sourceType == self::SOURCE_INLINE) { + $imageBinary = substr($source, strpos($source, 'base64,')+7); + $base64=true; + } if ($imageBinary !== null) { if ($base64) { $imageData = chunk_split(base64_encode($imageBinary)); @@ -367,10 +373,11 @@ public function getImageStringData($base64 = false) private function checkImage($source) { $this->setSourceType($source); - // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { $imageData = $this->getArchiveImageSize($source); + } elseif ($this->sourceType == self::SOURCE_INLINE) { + $imageData = $this->getInlineImageSize($source); } else { $imageData = @getimagesize($source); } @@ -407,6 +414,9 @@ private function setSourceType($source) } elseif (strpos($source, 'zip://') !== false) { $this->memoryImage = false; $this->sourceType = self::SOURCE_ARCHIVE; + } elseif (strpos($source, 'data:') !== false) { + $this->memoryImage = true; + $this->sourceType = self::SOURCE_INLINE; } else { $this->memoryImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); $this->sourceType = $this->memoryImage ? self::SOURCE_GD : self::SOURCE_LOCAL; @@ -442,6 +452,27 @@ private function getArchiveImageSize($source) return $imageData; } + /** + * Get image size from inline + * + * @param string $source + * @return array|null + */ + private function getInlineImageSize($source) + { + $imageData = null; + $imageContent = base64_decode(substr($source, strpos($source, 'base64,')+7)); + $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); + + if ($imageContent !== false) { + file_put_contents($tempFilename, $imageContent); + $imageData = @getimagesize($tempFilename); + unlink($tempFilename); + } + + return $imageData; + } + /** * Set image functions and extensions */ diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index fc23b5b0a8..70da22ddab 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -126,6 +126,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'ul' => array('List', null, null, $styles, $data, 3, null), 'ol' => array('List', null, null, $styles, $data, 7, null), 'li' => array('ListItem', $node, $element, $styles, $data, null, null), + 'img' => array('Image', $node, $element, $styles, $data, null, null), ); $newElement = null; @@ -143,6 +144,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = $arguments[$keys[$i]] = &$args[$i]; } } + $method = "parse{$method}"; $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); @@ -334,6 +336,66 @@ private static function parseListItem($node, $element, &$styles, $data) return null; } + /** + * Parse image node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + * @param array $data + * @return \PhpOffice\PhpWord\Element\Image $element + * + */ + private static function parseImage($node, $element, &$styles, $data) + { + $style=array(); + foreach ($node->attributes as $attribute) { + switch ($attribute->name) { + case 'src': + $src=$attribute->value; + break; + case 'width': + $width=$attribute->value; + $style['width']=$width; + break; + case 'height': + $height=$attribute->value; + $style['height']=$height; + break; + case 'style': + $styleattr=explode(';', $attribute->value); + foreach ($styleattr as $attr) { + if (strpos($attr, ':')) { + list($k, $v) = explode(':', $attr); + switch ($k) { + case 'float': + if (trim($v)=='right') { + $style['hPos']=\PhpOffice\PhpWord\Style\Image::POS_RIGHT; + $style['hPosRelTo']=\PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['pos']=\PhpOffice\PhpWord\Style\Image::POS_RELATIVE; + $style['wrap']=\PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; + $style['overlap']=true; + } + if (trim($v)=='left') { + $style['hPos']=\PhpOffice\PhpWord\Style\Image::POS_LEFT; + $style['hPosRelTo']=\PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['pos']=\PhpOffice\PhpWord\Style\Image::POS_RELATIVE; + $style['wrap']=\PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; + $style['overlap']=true; + } + break; + } + } + + } + break; + } + } + $newElement = $element->addImage($src, $style); + return $newElement; + } + + /** * Parse style * diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 21b2771602..ba17e9e660 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -171,6 +171,14 @@ class Frame extends AbstractStyle */ private $wrap; + /** + * Allow overlap + * + * @var bool + */ + private $overlap = false; + + /** * Create a new instance * @@ -362,7 +370,7 @@ public function getHPos() */ public function setHPos($value) { - $enum = array(self::POS_LEFT, self::POS_CENTER, self::POS_RIGHT, self::POS_INSIDE, self::POS_OUTSIDE); + $enum = array(self::POS_LEFT, self::POS_CENTER, self::POS_RIGHT, self::POS_INSIDE, self::POS_OUTSIDE, self::POS_ABSOLUTE); $this->hPos = $this->setEnumVal($value, $enum, $this->hPos); return $this; @@ -386,7 +394,7 @@ public function getVPos() */ public function setVPos($value) { - $enum = array(self::POS_TOP, self::POS_CENTER, self::POS_BOTTOM, self::POS_INSIDE, self::POS_OUTSIDE); + $enum = array(self::POS_TOP, self::POS_CENTER, self::POS_BOTTOM, self::POS_INSIDE, self::POS_OUTSIDE, self::POS_ABSOLUTE); $this->vPos = $this->setEnumVal($value, $enum, $this->vPos); return $this; @@ -472,4 +480,26 @@ public function setWrap($value) return $this; } + + /** + * Get overlap + * + * @return bool + */ + public function getOverlap() + { + return $this->overlap; + } + + /** + * Set overlap + * + * @param bool + * @return self + */ + public function setOverlap($value) + { + $this->overlap = $this->setBoolVal($value, false); + return $this; + } } diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 8e7cb71d2c..93f4c2efae 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -347,6 +347,13 @@ protected function addFilesToPackage(ZipArchive $zip, $elements) // Retrive GD image content or get local media if (isset($element['isMemImage']) && $element['isMemImage']) { $image = call_user_func($element['createFunction'], $element['source']); + + // Preserve transparancy for png files + if ($element['imageType']=='image/png') { + imageAlphaBlending($image, true); + imageSaveAlpha($image, true); + } + ob_start(); call_user_func($element['imageFunction'], $image); $imageContents = ob_get_contents(); diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 6926081f4c..3e6e388a79 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -69,6 +69,12 @@ public function write() // Style attribute $xmlWriter->writeAttribute('style', $this->assembleStyle($styles)); + + if ($style->getOverlap()) { + $xmlWriter->writeAttribute('o:allowoverlap', 't'); + } else { + $xmlWriter->writeAttribute('o:allowoverlap', 'f'); + } $this->writeWrap($xmlWriter, $style, $wrap); }