PHPOffice\PHPPresentation添加背景格式(图案填充)功能

使用PHPPresentation时我们发现,该开源软件竟然不支持图案填充功能,于是就自己补充了下,(本想将自己代码贡献给PHPOffice官方,因下载下来的开发版本无法通过单元测试,只能暂时写到此处供参考)

以下方式可以使PHPPresentation支持背景图案填充。

1.首先创建背景填充类文件 PHPOffice/PHPPresentation/src/PhpPresentation/Slide/Background/FillType.php

代码如下

/**
* Created by chenxue4076@163.com.
* User: chenxue4076@163.com
* Date: 2019/02/27
* Time: 14:46
* File name: FillType.php
*/
namespace PhpOffice\PhpPresentation\Slide\Background;

use PhpOffice\PhpPresentation\Slide\AbstractBackground;
use PhpOffice\PhpPresentation\Style\Fill as StyleFill;

class FillType extends AbstractBackground
{
const FILL_PATTERN_BACKGROUND = array(
"cross",
"dashDnDiag", //dashed downward diagonal 下对角虚线
"dashHorz", //dashed horizontal 横虚线
"dashUpDiag", //dashed upward diagonal 上对角虚线
"dashVert", //dashed vertical 竖虚线
"diagBrick", //diagonal brick 对角砖型
"diagCross",
"divot", //divot 草皮
"dkDnDiag", //dark downward diagonal 深色下对角线
"dkHorz", //dark horizontal 深色横线
"dkUpDiag", //dark upward diagonal 深色上对角线
"dkVert", //dark vertical 深色竖线
"dnDiag",
"dotDmnd", //dotted diamond 点式菱形
"dotGrid", //dotted grid 虚线网格
"horz",
"horzBrick", //horizontal brick 横向砖型
"lgCheck", //large checker board 大棋盘
"lgConfetti", //large confetti 大纸屑
"lgGrid", //large grid 大网格
"ltDnDiag", //light downward diagonal 浅色下对角线
"ltHorz", //light horizontal 浅色横线
"ltUpDiag", //light upward diagonal 浅色上对角线
"ltVert", //light vertical 浅色竖线
"narHorz", //narrow horizontal 窄横线
"narVert", //narrow vertical 窄竖线
"openDmnd", //open diamond 轮廓式菱形?
"pct5", //5%
"pct10", //10%
"pct20", //20%
"pct25", //25%
"pct30", //30%
"pct40", //40%
"pct50", //50%
"pct60", //60%
"pct70", //70%
"pct75", //75%
"pct80", //80%
"pct90", //90%
"plaid", //plaid 苏格兰方格
"shingle", //shingle卵石 瓦形
"smCheck", //small checker board 小棋盘
"smConfetti", //small confetti 小纸屑
"smGrid", //small grid 小网格
"solidDmnd", //solid diamond 实心菱形
"sphere", //ball 球体
"trellis", //trellises 棚架
"upDiag",
"vert",
"wave", //wave 波浪
"wdDnDiag", //wide downward diagonal 宽下对角线
"wdUpDiag", //wide upward diagonal 宽上对角线
"weave", //weave 编织物
"zigZag" //zig zag 之字形
);
/**
*
@var StyleFill
*/
protected $fill;

/**
*
@param StyleFill|null $fill
*
@return $this
*/
public function setFillBackground(StyleFill $fill = null)
{
$this->fill = $fill;
return $this;
}

/**
*
@return StyleFill
*/
public function getFillBackground()
{
return $this->fill;
}
}

2.修改文件
PHPOffice/PHPPresentation/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php

找到函数 writeSlideBackground

在下面代码前

// > p:bg
$objWriter->endElement();

添加判断代码

//chenxue4076@163.com add FillType
if($oBackground instanceof Slide\Background\FillType) {
// p:bgPr
$objWriter->startElement('p:bgPr');
$this->writePatternFill($objWriter, $oBackground->getFillBackground());
// > p:bgPr
$objWriter->endElement();
}
//chenxue4076@163.com add FillType end

3.修改文件
PHPOffice/PHPPresentation/src/PhpPresentation/Writer/PowerPoint2007/AbstractDecoratorWriter.php

1)顶部添加引用

use PhpOffice\PhpPresentation\Slide\Background\FillType;

2) 找到函数 writePatternFill

在代码后面

// a:pattFill
$objWriter->startElement('a:pattFill');

添加如下代码

//chenxue4076@163.com add fill style
if( in_array($pFill->getFillType(), FillType::FILL_PATTERN_BACKGROUND)) {
$objWriter->writeAttribute('prst', $pFill->getFillType());
}
//chenxue4076@163.com add fill style end

经过以上三个文件的修改,就可以使用图案填充了,图案填充的代码调用如下

/**
*
@param PhpOffice\PhpPresentation\Slide $oSlide
*
@param string $fillType "pct5","pct10","pct20","pct25","pct30","pct40","pct50","pct60","pct70","pct75","pct80","pct90","horz","vert","ltHorz","ltVert","dkHorz","dkVert","narHorz","narVert","dashHorz","dashVert","cross","dnDiag","upDiag","ltDnDiag","ltUpDiag","dkDnDiag","dkUpDiag","wdDnDiag","wdUpDiag","dashDnDiag","dashUpDiag","diagCross","smCheck","lgCheck","smGrid","lgGrid","dotGrid","smConfetti","lgConfetti","horzBrick","diagBrick","solidDmnd","openDmnd","dotDmnd","plaid","sphere","weave","divot","shingle","wave","trellis","zigZag"
*
@param string $startColor
*
@param string $endColor
*
@return PhpOffice\PhpPresentation\Slide $oSlide
*
@throws Exception
*/
protected function shapeFillBackground($oSlide, $fillType, $startColor, $endColor)
{
$fill = new Fill();
$fill->setFillType($fillType)->setStartColor(new Color($startColor))->setEndColor(new Color($endColor));
$oBkgFill = new PhpOffice\PhpPresentation\Slide\Background\FillType();
$oBkgFill->setFillBackground($fill);
$oSlide->setBackground($oBkgFill);
return $oSlide;
}

完成。

phpExcel生成的Excel背景填充色变黑

最近有同事在处理PHPExcel生成的Excel文件时,总会生成一片黑背景。

具体样式我就不截图了, 直接说修改方式。

找到文件 PHPExcel/Writer/Excel2007/Stype.php, 找到函数方法 writePatternFill

将下面信息

$objWriter->writeAttribute('rgb', $pFill->getStartColor()->getARGB()); 

替换为

if( $pFill->getStartColor()->getARGB() == 'FF000000' && $pFill->getEndColor()->getARGB() == 'FF000000') {
$objWriter->writeAttribute('rgb', '00FFFFFF');
} else {
$objWriter->writeAttribute('rgb', $pFill->getStartColor()->getARGB());
}

原因解析:此函数中 startColor为前景色,endColor为背景色, 通过PHP生成的PHPExcel中会多出 前景色和背景色都为黑色FF000000的FILL, 这个应该是PHPExcel的BUG,这时候我们强制设置前景色(字体颜色)为透明的白色,因为都是空行,这样做并没有问题哦。

通过上面的操作我们就可以生成正常的Excel文件了。

nginx服务器upstream timed out (110: Connection timed out)以及recv() failed (104: Connection reset by peer)解决方法

  1. upstream timed out (110: Connection timed out) while reading response header from upstream
修改 nginx.conf 或者自定义的 如 vhost/blog.windigniter.com.conf
        location / {
            root   /data/www/blog.windigniter.com;
            index  index.php index.html index.htm;
            if (!-e $request_filename){
                rewrite ^(.+)$ /index.php last;
            }
            proxy_read_timeout 150;
        }
        
        location ~ \.php$ {
            root           /data/www/blog.windigniter.com;
            fastcgi_read_timeout 150;
            fastcgi_pass   windigniter;
            fastcgi_index  index.php;
            include        fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  SCRIPT_NAME  $fastcgi_script_name;
        }
fastcgi_pass windigniter; 的配置是根据自己定义的 upstream来决定的,如下面2所示 2. recv() failed (104: Connection reset by peer) while reading response header from upstream 修改 nginx.conf
    upstream windigniter {
        server 127.0.0.1:9000 weight=1 max_fails=60 fail_timeout=30;
    }
经过以上 添加 添加粗体部分的内容就可以解决,110 Connection time out 和 104 Connection reset by peer 的问题了,上次在公司处理2的时候虽然已经重启了,但还是过了几分钟才生效,未查明原因。  

PHPOffice\PHPPresentation 使用Placeholder添加sldNum页码设置字体和页码位置BUG修复以及无法显示页码问题

被PHPPresentation的页码设置折腾了好几天,一直以为是自己的代码写的有问题,先说说目前我遇到的BUG 1.在Master或Slide中设置的Placeholder页码位置和大小无效,生成的PPT Placeholder始终在左上角0,0的位置。 2.为Placeholder设置的字体属性不生效,比如大小,居中等。 3.设置垂直居中需要不可以使用fontAlgn,不生效。 以下是解决方法: 修改文件 PHPOffice/PHPPresentation/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php 找到方法名
protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeId)
1.注释代码 1)找到代码
if (!$shape->isPlaceholder()) {
    // p:sp\p:spPr\a:xfrm
将if一行注释 这里是设置RichText的相关位置的,注释掉就可以将位置信息应用给Placeholder,否则位置在0,0
//if (!$shape->isPlaceholder()) {
    // p:sp\p:spPr\a:xfrm
    ...
//}
2)找到代码
if (!$shape->isPlaceholder()) {
    $verticalAlign = $shape->getActiveParagraph()->getAlignment()->getVertical();
将if一行注释 这里设置的垂直居中,如果不注释掉垂直方向无法设置位置,文字只在顶部
//if (!$shape->isPlaceholder()) {
    $verticalAlign = $shape->getActiveParagraph()->getAlignment()->getVertical();
    ...
//}
2.添加代码 1)找到代码
if ($shape->isPlaceholder() &&
    ($shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_SLIDENUM ||
        $shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_DATETIME)
) {
    $objWriter->startElement('a:p');
在其后添加下面代码,主要是水平居中,margin值得设置等等
//TODO 此处为chenxue4076@163.com手动添加,为了是页码也能够使用到样式
    //TODO 1添加排版信息
    $paragraph =$shape->getActiveParagraph()->getAlignment();
    //a:pPr
    $objWriter->startElement('a:pPr');
        $objWriter->writeAttribute('algn', $paragraph->getHorizontal());
        $objWriter->writeAttribute('fontAlgn', $paragraph->getVertical());
        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($paragraph->getMarginLeft()));
        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($paragraph->getMarginRight()));
        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($paragraph->getIndent()));
        $objWriter->writeAttribute('lvl', $paragraph->getLevel());

        $objWriter->startElement('a:lnSpc');
            $objWriter->startElement('a:spcPct');
                $objWriter->writeAttribute('val', $shape->getActiveParagraph()->getLineSpacing() . "%");
            $objWriter->endElement();
        $objWriter->endElement();
    $objWriter->endElement();
    //TODO 1 END 添加排版信息
//TODO END 此处为chenxue4076@163.com手动添加,为了是页码也能够使用到样式
2)继续往下查找到代码
$objWriter->startElement('a:fld');
$objWriter->writeAttribute('id', $this->getGUID());
$objWriter->writeAttribute('type', (
$shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_SLIDENUM ? 'slidenum' : 'datetime'));
在其后添加下面代码,主要是字体信息,比如加粗,字体类型,大小等信息
//TODO 此处为chenxue4076@163.com手动添加,为了是页码也能够使用到样式
    //TODO 2 添加字体信息
    $font = $shape->getActiveParagraph()->getFont();
    // a:rPr
    $objWriter->startElement('a:rPr');
        $objWriter->writeAttributeIf($font->isBold(), 'b', '1');
        $objWriter->writeAttributeIf($font->isItalic(), 'i', '1');
        $objWriter->writeAttributeIf($font->isStrikethrough(), 'strike', 'sngStrike');
        // Size
        $objWriter->writeAttribute('sz', ($font->getSize() * 100));
        // Character spacing
        $objWriter->writeAttribute('spc', $font->getCharacterSpacing());
        // Underline
        $objWriter->writeAttribute('u', $font->getUnderline());
        // Color - a:solidFill
        $objWriter->startElement('a:solidFill');
            $this->writeColor($objWriter, $font->getColor());
        $objWriter->endElement();
        // Font - a:latin
        $objWriter->startElement('a:latin');
            $objWriter->writeAttribute('typeface', $font->getName());
        $objWriter->endElement();
    // a:rPr
    $objWriter->endElement();
    //TODO 2 添加字体信息
//TODO END 此处为chenxue4076@163.com手动添加,为了是页码也能够使用到样式
经过以上几步设置,现在使用Placehoder 的 sldNum 已经能正常设置文字属性和位置了 下面是生成页码的函数方法,仅供参考
/**
 * @param PhpOffice\PhpPresentation\Slide $oSlide
 * @param string|array $text
 * @param float $width
 * @param float $height
 * @param float $offsetX
 * @param float $offsetY
 * @param int $lineSpacing
 * @param boolean|array $font
 * @param boolean|array $shadow
 * @return PhpOffice\PhpPresentation\Slide $oSlide
 * @throws Exception
 */
protected function shapeSlideNum($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->getActiveParagraph()->setLineSpacing($lineSpacing);
    $oFont = new Font();
    $oFont->setSize(empty($font['size']) ? 10 : $font['size'])
        ->setBold( empty($font['bold']) ? false : true)
        ->setItalic( empty($font['italic']) ? false : true)
        ->setName(isset($font['family']) ? $font['family'] : '华文细黑')
        ->setColor(new Color(empty($font['color']) ? 'ff4d4d4d' : $font['color']));
    if( ! empty($font['h_align'])) {
        $oShape->getActiveParagraph()->getAlignment()->setHorizontal($font['h_align']);
    }
    if( ! empty($font['v_align'])) {
        $oShape->getActiveParagraph()->getAlignment()->setVertical($font['v_align']);
    }
    $oShape->getActiveParagraph()->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'));
    }
    //$oShape->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_SLIDENUM))->getPlaceholder()->setIdx($oShape->getPlaceholder()->getIdx());
    $oShape->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_SLIDENUM));
    return $oSlide;
}
经过以上设置,我们的代码添加页码就和添加其他元素一样简单了。 附件已经打包,可直接将此文件覆盖到原文件,但是不建议这样做,可能因为版本升级代码变化等原因影响到就不好了,附件地址 AbstractSlide.php.zip