PHP, 原创, 服务器CodeIgniter, PHP, PhpPresentation
使用PHPOffice/PHPPresentation生成超大PPT文件
- by chenxue4076
- 7 years ago
估计一般大家也用不到这个方式,必定需要生成几个G甚至几十G的PPT用途也不大,但生产环境有时候真的需要。下面就简单介绍分批生成单个超大PPT的方式。
原理:Office家族 Excel,PowerPoint都是压缩文件,将文件名后缀修改为.zip就会发现原来他们都是压缩包,针对里面的关联文件做修改便可以实现追加或者删除操作,是不是被惊到了呢?!这可是我研究了好多方式才发现的哦。
因为代码太据针对性,不是通用的,这里只列举一些通用的东西。
先说保存之前,所需数据都是差不多的, 首先需要一个封装好的类 PowerPoint.php 这里面封装通用的方法
调用时候代码说明(以CI(CodeIgniter)为例)
require_once APPPATH . 'third_party' . DIRECTORY_SEPARATOR . 'PHPOffice' . DIRECTORY_SEPARATOR . 'PowerPoint.php'; //创建类 $powerPoint = new PowerPoint(); //第一次生成的时候加上文档信息把,追加PPT的时候就不需要了 $powerPoint->getDocumentProperties()->setCreater('CX')->setCompany('Focusmedia')->setTitle('PPT属性里面的标题')->setDescription('PPT属性里面的描述')->setCategory('PPT')->setLastModifiedBy('System'); //无论首次还是追加都需要设置母版 $powerPoint->createMaster(); //第一次的时候可能需要单独的一个头部信息 $powerPoint->createHeader($dataHeader); //循环调用此方法,每调用一次增加一个PPT页面 $powerPoint->createCotent($data); //判断所有PPT页面都加完了调用此方法 $powerPoint->createFooter(); //保存或者追加用此方法,里面判断不存在文件时用自带的save方法,否则追加,追加方法看后面 $powerPoint->appendSave($file);
下面举例调用方式,比如你上万条记录需要生成PPT,我们要分批追加,这样才不会导致内存溢出而无法正常使用。
可以先将数据整理成二维数组,每组为1个页面,看实际情况
$list_page = array(); foreach ($list as $key => $item) { $list_page[$item['page_number']][] = $item; } $per_group = 100;//每生成100页PPT保存1次 $group_page = ceil( count($list_page) / $per_group);//总数据分的页数 //引入类 require_once APPPATH . 'third_party' . DIRECTORY_SEPARATOR . 'PHPOffice' . DIRECTORY_SEPARATOR . 'PowerPoint.php'; $tmp_file_path = '要保存的文件名.pptx' for( $i = 1; $i <= $group_page; $i++) { $powerPoint = new PowerPoint();//每批都需要重新创建此类 $powerPoint->createMaster();//每批都需要设置母版 //这里每批要处理的循环 for($key = ($i-1) * $per_group + 1; $key <= $i * $per_group AND $key <= count($list_page); $key++ ) { if($key == 1) { //第一条记录为头部 $powerPoint->getDocumentProperties()->setCreater('System Report monitor')->setCompany('Focusmedia') ->setTitle($report['contract_no'] . '_' . $report['city_name'].'_'.$report['publish_date']) ->setDescription($report['contract_no'] . '_' . $report['city_name'].'_'.$report['publish_date'] . '_' . ($report['export_war'] == 2 ? $report['design_no_str'] : $report['export_war'])) ->setCategory($report['contract_no'])->setLastModifiedBy('System'); //创建第一页,因为第一页可能和后面的内容不同; $powerPoint->createHeader($list_page[$key][0]); } else { $powerPoint->createContent($list_page[$key]); } if($key == count($list_page)) { //创建完所有数据是不是应该还有个结束页,谢谢大家观赏 $powerPoint->createFooter($type); } if($key == $i * $per_group || $key == count($list_page)) { //******此次循环结束或数据结束,保存PPT $powerPoint->appendSave($tmp_file_path); $powerPoint = null; } } }
//循环执行完,就得到想要的文件了,
以下重点介绍PowerPoint.php的内容,尤其是appendSave()方法,是整个操作的核心
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'PHPPresentation' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'PhpPresentation' . DIRECTORY_SEPARATOR . 'Autoloader.php'; \PhpOffice\PhpPresentation\Autoloader::register(); require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Common' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Common' . DIRECTORY_SEPARATOR . 'Autoloader.php'; \PhpOffice\Common\Autoloader::register(); use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\IOFactory; use PhpOffice\PhpPresentation\DocumentLayout; use PhpOffice\Common\Drawing; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Slide\Background\Image; use PhpOffice\PhpPresentation\Slide\Note; use PhpOffice\PhpPresentation\HashTable; use PhpOffice\PhpPresentation\Writer\AbstractWriter; use PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; use PhpOffice\PhpPresentation\Shape\Drawing\Base64; use PhpOffice\PhpPresentation\Shape\Group; class PowerPoint extends PhpOffice\PhpPresentation\Writer\PowerPoint2007\PptSlides { //概要 protected $creater = 'My name'; protected $company = 'My factory'; protected $title = 'My title'; protected $description = 'My description'; protected $category = 'My category'; protected $last_modify_by = 'modify name'; protected $created_time; protected $modified_time; protected $subject = 'My subject'; protected $keywords = 'my, key, word'; protected $objPHPPresentation; protected $properties; private $type = 'focusmedia'; private $log; private $objZip; protected $oSlideLayout = null; protected $oHashTable; public function __construct($type) { $this->type = $type; $this->log = new MY_Log(); $this->oHashTable = new HashTable(); } private function init() { if( empty($this->objPHPPresentation)) { $this->objPHPPresentation = new PhpPresentation(); $this->objPHPPresentation->removeSlideByIndex(0); } } public function getDocumentProperties() { $this->init(); $this->properties = $this->objPHPPresentation->getDocumentProperties(); return $this; } public function setCreater($creater) { $this->creater = $creater; $this->properties->setCreator($this->creater); return $this; } public function setCompany($company) { $this->company = $company; $this->properties->setCompany($this->company); return $this; } public function setTitle($title) { $this->title = $title; $this->properties->setTitle($this->title); return $this; } public function setDescription($description) { $this->description = $description; $this->properties->setDescription($this->description); return $this; } public function setCategory($category) { $this->category = $category; $this->properties->setCategory($this->category); return $this; } public function setLastModifiedBy($last_modify_by) { $this->last_modify_by = $last_modify_by; $this->properties->setLastModifiedBy($this->last_modify_by); return $this; } public function setCreated($created_time) { $this->created_time = $created_time; $this->properties->setCreated(empty($this->created_time) ? time() : $this->created_time); return $this; } public function setModified($modified_time) { $this->modified_time = $modified_time; $this->properties->setModified(empty($this->modified_time) ? time() : $this->modified_time); return $this; } public function setSubject($subject) { $this->subject = $subject; $this->properties->setSubject($this->subject); return $this; } public function setKeywords($keywords) { $this->keywords = $keywords; $this->properties->setKeywords($this->keywords); return $this; } /** * 创建幻灯片母版 */ public function createMaster() { //初始化,每次创建母版或幻灯片都新处理一下 $this->init(); //幻灯片大小,这里使用的是毫米,后面位置我使用的是厘米,这样可以更准确的创建幻灯片 $this->objPHPPresentation->getLayout()->setCX( 296.82, DocumentLayout::UNIT_MILLIMETER)->setCY( 209.86, DocumentLayout::UNIT_MILLIMETER); //var_dump($this->oMasterSlide); $oMasterSlide_array = $this->objPHPPresentation->getAllMasterSlides(); $oMasterSlide = $oMasterSlide_array[0]; //LOGO 位置信息都是里面哦 $logoWidth = 4.39; $logoHeight = 0.73; $logoOffsetX = 0.84; $logoOffsetY = 1.29; //充本地文件中添加图片,母版里面的图片一般都是固定的, 使用自定义的 shapeImgSource $this->shapeImgSource($oMasterSlide, dirname(__FILE__) . '/resource/logo.png', $logoWidth, $logoHeight, $logoOffsetX, $logoOffsetY, array('name' => $this->type . ' logo', 'description' => $this->type . ' logo')); return true; } /** * 创建幻灯片第一张 首页 * @param array $data * @return bool */ public function createHeader($data = array()) { if( empty($data)) return false; $this->init(); $headerSlide = $this->objPHPPresentation->createSlide(); $headerSlide->getSlideLayout()->layoutNr = 1; //方案标题 $titleWidth = 16.99; $titleHeight = ($this->type == 'focusmedia') ? 1.64 : 1.8; $titleOffsetX = 2.05; $titleOffsetY = ($this->type == 'focusmedia') ? 9.25 : 8.97; $titleFont = array('size' => 32, 'bold' => true, 'family' => '华文细黑', 'color' => 'ff4d4d4d'); $titleShadow = null; $this->shapeRichText($headerSlide,$data['design_name'], $titleWidth, $titleHeight, $titleOffsetX, $titleOffsetY, 100, $titleFont, $titleShadow); //创建图片框和阴影 $mediaFrameWidth = 7.4; $mediaFrameHeight = 9.39; $mediaFrameOffsetX = 20.05; $mediaFrameOffsetY = 5.7; $mediaFrameShadow = array('direction' => 45, 'distance' => 11.3, 'alpha' => 50, 'color' => 'ff808080', 'blur_radius' => 0); $this->shapeMediaFrame($headerSlide, $mediaFrameWidth, $mediaFrameHeight, $mediaFrameOffsetX, $mediaFrameOffsetY, $mediaFrameShadow, 20); //创建图片 $this->shapeImgUrl($headerSlide, $data['img_oss_path'], $data['img_path'], $mediaFrameWidth, $mediaFrameHeight, $mediaFrameOffsetX, $mediaFrameOffsetY); return true; } /** * 通用底部 */ public function createFooter() { $this->init(); //新增一个slide $footerSlide = $this->objPHPPresentation->createSlide(); $footerSlide->getSlideLayout()->layoutNr = 1; //Title $footerTitle = '如对本报告有任何问题或疑问,请于一周内向以下分众机构查询!'; $footerTitleWidth = 24;//24.54; $footerTitleHeight = 1.44; $footerTitleOffsetX = 5.5; $footerTitleOffsetY = 5.1; $footerTitleFont = array('size' => 18, 'bold' => false, 'family' => '华文细黑', 'color' => ($this->type == 'focusmedia') ? 'ff4d4d4d' : 'ff000000'); $footerTitleShadow = array('direction' => 45, 'distance' => 4, 'alpha' => 100, 'color' => 'ffc0c0c0', 'blur_radius' => 4); $this->shapeRichText($footerSlide, $footerTitle, $footerTitleWidth, $footerTitleHeight, $footerTitleOffsetX, $footerTitleOffsetY, 100, $footerTitleFont, $footerTitleShadow); return true; } //创建中间页面 public function createContent($data = array()) { $this->init(); //新增一个slide $oSlide = $this->objPHPPresentation->createSlide(); $oSlide->getSlideLayout()->layoutNr = 1; //TODO 添加正文内容 } //保存文件,这个只是作为首次生成不追加时候使用PHPPresentation的Save public function save( $fileName = '') { $oWriterPPTX = IOFactory::createWriter($this->objPHPPresentation, 'PowerPoint2007'); if(empty($fileName)) {//如果文件名为空,则随机生成文件名 $fileName = time().'.pptx'; } $fileName = trim($fileName, '/'); $oWriterPPTX->save(FCPATH . $fileName); return $fileName; } /** * 直接打开原pptx文件(不存在则调用save方法),只循环修改其中涉及到文件,其他文件不要动 (此方法较快捷,需要对PHPPresentation比较了解) * @param string $fileName */ public function appendSave($fileName = '') { $this->init(); $fileName = trim(trim($fileName, DIRECTORY_SEPARATOR), '/'); //如果指定的文件名不存在,直接调用 save 存储整个文档 if( ! file_exists( FCPATH . $fileName)) { return array('err' => 0, 'msg' => $this->save($fileName)); } //此方法内有追加 $result = $this->slideRender(FCPATH . $fileName); return empty($result) ? array('err' => 1, 'msg' => 'failed') : array('err' => 0, 'msg' => $fileName); } private function readZip( $fileName = '') { if( empty($fileName)) return false; $docString = $this->objZip->getFromName($fileName); return $docString; } private function readZipDocNoteCount( $fileName = '', $elements = '') { $count = 0; if( empty($this->objZip) OR empty($fileName)) return $count; $docString = $this->readZip($fileName); $dom = new \DOMDocument(); $dom->loadXML($docString); $xpath = new DOMXPath($dom); $elements = trim($elements, '/'); if( strpos($elements, '/') !== false) { //去掉跟节点 $arrParents = explode('/', $elements); unset($arrParents[0]); $elements = implode('/', $arrParents); } $count = $dom->getElementsByTagName($elements)->length; if($count > 0) return $count; $count = $xpath->query($elements)->length; return $count; } /** * @param $fileName * @param string $parentElement * @param string $element * @param array $attrs 二维数组 */ private function addZipXmlAttr($fileName, $parentElement = '', $element = '', $attrs = array()) { $contentString = $this->readZip($fileName); if( empty($contentString)) { $this->log->write_log_file('power_point', 'empty content string '. $fileName, ' parent '.$parentElement . ' element '. $element); } $dom = new \DOMDocument(); $dom->loadXML($contentString); $xpath = new DOMXPath($dom); foreach ($attrs as $k => $item) { $ele = $dom->createElement($element); foreach ($item as $key => $value) { $ele->setAttribute($key, $value); } $parentElement = trim($parentElement, '/'); if( strpos($parentElement, '/') !== false) { //去掉跟节点 $arrParents = explode('/', $parentElement); unset($arrParents[0]); $queryStr = implode('/', $arrParents); if( ! empty($xpath->query($queryStr)->item(0))) { $xpath->query($queryStr)->item(0)->appendChild($ele); } } else { $dom->firstChild->appendChild($ele); } } //echo $dom->saveXML(); //exit; $this->objZip->addFromString($fileName, $dom->saveXML()); } private function slideRender($file = '') { if(empty($file)) return false; //打开压缩文件 $this->objZip = new ZipArchive(); $this->objZip->open($file); //presentation.xml.rels 记录条数 $presentationCount = $this->readZipDocNoteCount( 'ppt/_rels/presentation.xml.rels', '/Relationships/Relationship'); //读取已存在的slide个数 $hasSlideCount = $this->readZipDocNoteCount('ppt/presentation.xml', '/p:presentation/p:sldIdLst/p:sldId'); //循环保存新slide文件和媒体 $newSlideCount = 0; foreach ($this->objPHPPresentation->getAllSlides() as $idx => $oSlide) { $newSlideCount++; $oSlide->getSlideLayout()->layoutNr = 1; $this->objZip->addFromString('ppt/slides/_rels/slide' . ($hasSlideCount + $idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide)); $this->objZip->addFromString('ppt/slides/slide' . ($hasSlideCount + $idx + 1) . '.xml', $this->writeSlide($oSlide)); // Add note slide if ($oSlide->getNote() instanceof Note) { if ($oSlide->getNote()->getShapeCollection()->count() > 0) { $this->objZip->addFromString('ppt/notesSlides/notesSlide' . ($hasSlideCount + $idx + 1) . '.xml', $this->writeNote($oSlide->getNote())); } } // Add background image slide $oBkgImage = $oSlide->getBackground(); if ($oBkgImage instanceof Image) { $this->objZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($hasSlideCount + $idx), file_get_contents($oBkgImage->getPath())); } $presentationAttr[$idx] = array( 'id' => 256 + $hasSlideCount + $idx, 'r:id' => 'rId'.($presentationCount + $idx + 1), ); //添加 presentation.xml[.rels], [Content_Types].xml文件关系 $presentationRelsAttr[$idx] = array( 'Id' => 'rId'.($presentationCount + $idx + 1), 'Target' => 'slides/slide'.($hasSlideCount + $idx + 1).'.xml', 'Type' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', ); $contentTypesAttr[$idx] = array( 'PartName' => '/ppt/slides/slide'.($hasSlideCount + $idx + 1).'.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml', ); } //保存媒体文件 // Create drawing dictionary $this->getDrawingHashTable()->addFromSource($this->allDrawings()); for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { $shape = $this->getDrawingHashTable()->getByIndex($i); if (!$shape instanceof AbstractDrawingAdapter) { continue; } $this->objZip->addFromString('ppt/media/' . $shape->getIndexedFilename(), $shape->getContents()); } if( ! empty($presentationAttr)) { $this->addZipXmlAttr( 'ppt/presentation.xml', 'p:presentation/p:sldIdLst', 'p:sldId', $presentationAttr); } if( ! empty($presentationRelsAttr)) { $this->addZipXmlAttr('ppt/_rels/presentation.xml.rels', 'Relationships', 'Relationship', $presentationRelsAttr); } if( ! empty($contentTypesAttr)) { $this->addZipXmlAttr('[Content_Types].xml', 'Types', 'Override', $contentTypesAttr); } //修改幻灯片个数 $contentFile = 'docProps/app.xml'; $contentString = $this->readZip($contentFile); $contentString = str_replace('<Slides>'.$hasSlideCount.'</Slides>', '<Slides>'.($hasSlideCount + $newSlideCount).'</Slides>', $contentString); $this->objZip->addFromString($contentFile, $contentString); //关闭压缩文件 $this->objZip->close(); $this->objZip = null; return true; } //获取元素属性 public function getObjPHPPresentation() { $this->init(); return $this->objPHPPresentation; } public function getPresentationProperties() { $this->init(); return $this->objPHPPresentation->getPresentationProperties(); } public function getLayout() { $this->init(); return $this->objPHPPresentation->getLayout(); } public function getAllSlides() { $this->init(); return $this->objPHPPresentation->getAllSlides(); } public function getSlide($index = 0) { $this->init(); return $this->objPHPPresentation->getSlide($index); } public function getAllMasterSlides() { $this->init(); return $this->objPHPPresentation->getAllMasterSlides(); } public function setDrawingHashTable(HashTable $hashTable) { $this->oHashTable = $hashTable; return $this; } public function getDrawingHashTable() { return $this->oHashTable; } /** * Get an array of all drawings * * @return \PhpOffice\PhpPresentation\Shape\AbstractDrawing[] All drawings in PhpPresentation * @throws \Exception */ protected function allDrawings() { // Get an array of all drawings $aDrawings = array(); // Loop through PhpPresentation foreach (array_merge($this->getObjPHPPresentation()->getAllSlides(), $this->getObjPHPPresentation()->getAllMasterSlides()) as $oSlide) { $arrayReturn = $this->iterateCollection($oSlide->getShapeCollection()->getIterator()); $aDrawings = array_merge($aDrawings, $arrayReturn); } return $aDrawings; } private function iterateCollection(\ArrayIterator $oIterator) { $arrayReturn = array(); if ($oIterator->count() <= 0) { return $arrayReturn; } while ($oIterator->valid()) { $oShape = $oIterator->current(); if ($oShape instanceof AbstractDrawingAdapter) { $arrayReturn[] = $oShape; } elseif ($oShape instanceof Chart) { $arrayReturn[] = $oShape; } elseif ($oShape instanceof Group) { $arrayGroup = $this->iterateCollection($oShape->getShapeCollection()->getIterator()); $arrayReturn = array_merge($arrayReturn, $arrayGroup); } $oIterator->next(); } return $arrayReturn; } //把我封装好的创建多媒体文字,图片画线等内容也加上吧 /** * 创建图片背景框架 * @param $oSlide 从此对象创建 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @param array $shadow 数组包含(direction(角度如:45), distance(距离:2), alpha(透明度:0-100), color(颜色:ff000000), blur_radius(模糊:0)) * @param int $border 如果数字不为0 则创建此值大小的border * @return $oSlide */ protected function shapeMediaFrame($oSlide, $width, $height, $offsetX, $offsetY, $shadow = array(), $border = 20) { $oShape = $oSlide->createRichTextShape(); $fill = new Fill(); $fill->setFillType(Fill::FILL_SOLID); $oShape->setOffsetX(Drawing::centimetersToPixels($offsetX)) ->setOffsetY(Drawing::centimetersToPixels($offsetY)) ->setWidth(Drawing::centimetersToPixels($width)) ->setHeight(Drawing::centimetersToPixels($height)) ->setFill($fill); if( ! empty($shadow)) { $oShape->getShadow()->setVisible(true)->setDirection(isset($shadow['direction']) ? $shadow['direction'] : 45) ->setDistance(isset($shadow['distance']) ? $shadow['distance'] : 2) ->setAlpha(isset($shadow['alpha']) ? $shadow['alpha'] : 100) ->setColor(new Color(isset($shadow['color']) ? $shadow['color'] : 'ff808080')) ->setBlurRadius(isset($shadow['blur_radius']) ? $shadow['blur_radius'] : 0); } if( ! empty($border)) { $oShape->getBorder()->setLineWidth($border); } return $oSlide; } /** * 从URL地址中创建图片 * @param $oSlide 从此对象创建 * @param $imgurl 图片URL地址,这里是阿里云OSS的图片地址 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @return $oSlide */ protected function shapeImgUrl($oSlide, $oss_file, $local_file, $width, $height, $offsetX, $offsetY) { if( empty($oss_file) && empty($local_file)) { return $oSlide; } if( ! empty($oss_file)) { $imgurl = get_img_url($oss_file, '', '', false, 'w_'.floor(Drawing::centimetersToPixels($width)).',h_'.floor(Drawing::centimetersToPixels($height))); $filecontent = file_get_contents($imgurl); if (!function_exists('getimagesizefromstring')) { $uri = 'data://application/octet-stream;base64,' . base64_encode($filecontent); $fileEx = getimagesize($uri); } else { $fileEx = getimagesizefromstring($filecontent); } $data_img_content = 'data:image/jpeg;base64,'.base64_encode($filecontent); } else { $file_contents = get_image_data('', $local_file, '', 'w_'.floor(Drawing::centimetersToPixels($width)).',h_'.floor(Drawing::centimetersToPixels($height))); $fileEx = getimagesize($file_contents); $data_img_content = $file_contents; } $fileWidth = $fileEx[0] > Drawing::centimetersToPixels($width) ? Drawing::centimetersToPixels($width) : $fileEx[0]; $fileHeight = $fileEx[1] > Drawing::centimetersToPixels($height) ? Drawing::centimetersToPixels($height) : $fileEx[1]; $topShape = new Base64(); //$topShape->setData($data_img_content, false)->setResizeProportional(false); //$this->log->write_log_file('img', $oss_file .$local_file .' ' . md5($data_img_content)); $topShape->setData($data_img_content)->setResizeProportional(false); if($offsetX == '50%') { $offsetX = $this->objPHPPresentation->getLayout()->getCX(DocumentLayout::UNIT_CENTIMETER); $topShape->setWidth($fileWidth)->setHeight($fileHeight) ->setOffsetX(Drawing::centimetersToPixels($offsetX) - $fileWidth/2 ) ->setOffsetY(Drawing::centimetersToPixels($offsetY)); } else { $topShape->setWidth($fileWidth)->setHeight($fileHeight) ->setOffsetX(Drawing::centimetersToPixels($offsetX + $width/2) - $fileWidth/2 ) ->setOffsetY(Drawing::centimetersToPixels($offsetY + $height/2) - $fileHeight/2 ); } $oSlide->addShape($topShape); return $oSlide; } /** * 从本地图片文件创建图片 * @param $oSlide 从此对象创建 * @param $filePath 文件的完整路径 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @param array $fileInfo 图片的标题和描述 array('name'=>'', 'description'=>'') * @return $oSlide */ protected function shapeImgSource($oSlide, $filePath, $width, $height, $offsetX, $offsetY, $fileInfo = array()) { $oShape = $oSlide->createDrawingShape(); $oShape->setName(empty($fileInfo['name']) ? 'file name' : $fileInfo['name']) ->setDescription(empty($fileInfo['description']) ? 'file description' : $fileInfo['description']) ->setPath($filePath); $oShape->setResizeProportional(false)->setHeight(Drawing::centimetersToPixels($height))->setWidth(Drawing::centimetersToPixels($width)) ->setOffsetX(Drawing::centimetersToPixels($offsetX))->setOffsetY(Drawing::centimetersToPixels($offsetY)); return $oSlide; } /** * 创建多媒体文字 * @param $oSlide 从此对象创建 * @param $text 需要创建的文字 可以是字符串或数组 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @param array $font 样式array(size:10,bold:true/false, family:华文细黑, color:ff808080) * @param array $shadow 数组包含(direction(角度如:45), distance(距离:2), alpha(透明度:0-100), color(颜色:ff000000), blur_radius(模糊:0)) */ protected function shapeRichText($oSlide, $text, $width, $height, $offsetX, $offsetY, $lineSpacing = 100, $font = array(), $shadow = array()) { if( empty($text)) return $oSlide; $oShape = $oSlide->createRichTextShape(); $oShape->setOffsetX(Drawing::centimetersToPixels($offsetX))->setOffsetY(Drawing::centimetersToPixels($offsetY))->setWidth(Drawing::centimetersToPixels($width))->setHeight(Drawing::centimetersToPixels($height)); $oShape->getParagraph(0)->setLineSpacing($lineSpacing); if( is_array($text)) { $oTextRun = $oShape->createTextRun($text[0]); } else { $oTextRun = $oShape->createTextRun($text); } $oFont = new Font(); $oFont->setSize(empty($font['size']) ? 10 : $font['size']) ->setBold(isset($font['bold']) ? true : false) ->setName(isset($font['family']) ? $font['family'] : '华文细黑') ->setColor(new Color(empty($font['color']) ? 'ff4d4d4d' : $font['color'])); if( ! empty($font['h_align'])) { $oShape->getParagraph(0)->getAlignment()->setHorizontal($font['h_align']); } if( ! empty($font['v_align'])) { $oShape->getParagraph(0)->getAlignment()->setVertical($font['h_align']); } $oTextRun->setFont($oFont); if( ! empty($shadow)) { //标题阴影 $oShape->getShadow()->setVisible(true) ->setAlpha(isset($shadow['alpha']) ? $shadow['alpha'] : 100) ->setDistance(isset($shadow['distance']) ? $shadow['distance'] : 2) ->setDirection(isset($shadow['direction']) ? $shadow['direction'] : 45) ->setBlurRadius(isset($shadow['blur_radius']) ? $shadow['blur_radius'] : 0) ->setColor(new Color(isset($shadow['color']) ? $shadow['color'] : 'ff808080')); } if( is_array($text)) { //第二行开始 foreach ($text as $key => $pContenet) { if($key == 0) { continue; } $pg = $oShape->createParagraph(); $pg->setLineSpacing($lineSpacing); $footerContentRun = $pg->createTextRun($pContenet); $footerContentRun->getFont()->setSize(empty($font['size']) ? 10 : $font['size']) ->setBold(isset($font['bold']) ? true : false) ->setName(isset($font['family']) ? $font['family'] : '华文细黑') ->setColor(new Color(empty($font['color']) ? 'ff4d4d4d' : $font['color'])); } } return $oShape; } /** * 同一行内容 字的样式不同 * @param $oSlide 从此对象创建 * @param $text 需要创建的文字 可以是字符串或数组 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @param int $lineSpacing * @param array $font 字体样式如果text为数组,则这里对应二维数组 样式array(size:10,bold:true/false, family:华文细黑, color:ff808080) * @param array $shadow 数组包含(direction(角度如:45), distance(距离:2), alpha(透明度:0-100), color(颜色:ff000000), blur_radius(模糊:0)) * @return $oSlide */ protected function shapeRichTextInline($oSlide, $text, $width, $height, $offsetX, $offsetY, $lineSpacing = 100, $font = array(), $shadow = array()) { $oShape = $oSlide->createRichTextShape(); $oShape->setOffsetX(Drawing::centimetersToPixels($offsetX)) ->setOffsetY(Drawing::centimetersToPixels($offsetY)) ->setWidth(Drawing::centimetersToPixels($width)) ->setHeight(Drawing::centimetersToPixels($height)); $oShape->getParagraph(0)->setLineSpacing($lineSpacing); if( is_array($text)) { foreach ($text as $k => $string) { $oTextRun = $oShape->createTextRun($string); if( ! empty($font[$k]) && is_array($font[$k]) ) { $oTextRun->getFont()->setName(isset($font[$k]['family']) ? $font[$k]['family'] : '华文细黑') ->setSize(empty($font[$k]['size']) ? 10 : $font[$k]['size']) ->setColor(new Color(empty($font[$k]['color']) ? 'FFCC0000' : $font[$k]['color'])); } elseif ( is_array($font)) { $oTextRun->getFont()->setName(isset($font['family']) ? $font['family'] : '华文细黑') ->setSize(empty($font['size']) ? 10 : $font['size']) ->setColor(new Color(empty($font['color']) ? 'FFCC0000' : $font['color'])); } } } else { $oTextRun = $oShape->createTextRun($text); $oTextRun->getFont()->setName(isset($font['family']) ? $font['family'] : '华文细黑') ->setSize(empty($font['size']) ? 10 : $font['size']) ->setColor(new Color(empty($font['color']) ? 'FFCC0000' : $font['color'])); } if( ! empty($shadow)) { $oShape->getShadow()->setVisible(true) ->setAlpha(isset($shadow['alpha']) ? $shadow['alpha'] : 100) ->setDistance(isset($shadow['distance']) ? $shadow['distance'] : 2) ->setDirection(isset($shadow['direction']) ? $shadow['direction'] : 45) ->setBlurRadius(isset($shadow['blur_radius']) ? $shadow['blur_radius'] : 0) ->setColor(new Color(isset($shadow['color']) ? $shadow['color'] : 'ff808080')); } return $oShape; } /** * 画线 * @param $oSlide 从此对象创建 * @param $width 创建的宽度cm * @param $height 创建的高度cm * @param $offsetX 距离左边距离单位为cm * @param $offsetY 距离左边距离单位为cm * @param array $line 样式 array(color, line_style, line_width) * @return $oSlide */ protected function shapeLine($oSlide, $width, $height, $offsetX, $offsetY, $line = array()) { $lineShape = $oSlide->createLineShape(Drawing::centimetersToPixels($offsetX), Drawing::centimetersToPixels($offsetY), Drawing::centimetersToPixels($offsetX + $width), Drawing::centimetersToPixels($offsetY + $height)); $lineShape->getBorder()->setColor(new Color(empty($line['color']) ? 'ff808080' : $line['color']))->setLineStyle(isset($line['line_stype']) ? $line['line_stype'] : Border::LINE_SINGLE)->setLineWidth(isset($line['line_width']) ? $line['line_width'] : 0.75); return $oSlide; } }
结束
重点:把PPTX文件看作一个压缩文件,读取压缩包中特定文件或添加特定文件,这样可以保证不把所有的内容全部加载到内存。 其实里面占比例最大的是图片,所以这里我们按每次100张幻灯片来处理,请根据实际情况分配批次。
难点:如何将已经存入到PhpPresentation中的内容写入到已存在的文件中,这里需要我们将PPTX文件中的子文件都了解清楚,以及研读系统中save的实现方式,将我们需要的内容单独处理掉。
(677)