PHP, 原创, 服务器CodeIgniter, PHP, PhpPresentation
使用PHPOffice/PHPPresentation生成超大PPT文件
- by chenxue4076
- 8 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的实现方式,将我们需要的内容单独处理掉。
(802)