หลังจากที่ได้เรียนรู้วิธีการสร้างเอกสาร MS Word จาก MS Word Template ไปแล้ว (หากยังไม่ได้อ่าน สร้างไฟล์ MS Word จาก Word Template สำหรับงานเอกสารราชการ) ในบทเรียนรู้นี้มาแทรกรูปภาพเข้าไปในเอกสาร MS Word จาก MS Word Template กันต่อ

ขั้นแรกให้ทำการสร้างตัวแปรที่จะรับค่ารูปภาพใน MS Word Template กันก่อน ในที่นี้จะใช้ ${img1} และ ${img2} ดังนี้

จากนั้นสืบทอด (Extends) Class TemplateProcessor โดยสร้างไฟล์ common\components\Processor.php แล้วเขียนโปรแกรมเพิ่ม method setImg() ดังต่อไปนี้ (ที่มาจากเว็บที่ไหนสักแห่ง)

<?php
/**
 * Created by Manop Kongoon.
 * kongoon@hotmail.com
 * Date: 22/9/2560
 * Time: 13:03
 */

namespace common\components;


use PhpOffice\PhpWord\Exception\CopyFileException;
use PhpOffice\PhpWord\Exception\CreateTemporaryFileException;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\ZipArchive;
use PhpOffice\PhpWord\TemplateProcessor;

class Processor extends TemplateProcessor
{
    public $_countRels;
    public $_rels;
    public $_types;

    public function __construct($documentTemplate)
    {
        $this->_countRels = 100; //start id for relationship between image and document.xml

        // Temporary document filename initialization
        $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord');
        if (false === $this->tempDocumentFilename) {
            throw new CreateTemporaryFileException();
        }

        // Template file cloning
        if (false === copy($documentTemplate, $this->tempDocumentFilename)) {
            throw new CopyFileException($documentTemplate, $this->tempDocumentFilename);
        }

        // Temporary document content extraction
        $this->zipClass = new ZipArchive();
        $this->zipClass->open($this->tempDocumentFilename);
        $index = 1;
        while (false !== $this->zipClass->locateName($this->getHeaderName($index))) {
            $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros(
                $this->zipClass->getFromName($this->getHeaderName($index))
            );
            $index++;
        }
        $index = 1;
        while (false !== $this->zipClass->locateName($this->getFooterName($index))) {
            $this->tempDocumentFooters[$index] = $this->fixBrokenMacros(
                $this->zipClass->getFromName($this->getFooterName($index))
            );
            $index++;
        }
        $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName($this->getMainPartName()));
    }

    /**
     * Saves the result document.
     *
     * @return string
     *
     * @throws \PhpOffice\PhpWord\Exception\Exception
     */
    public function save()
    {
        foreach ($this->tempDocumentHeaders as $index => $xml) {
            $this->zipClass->addFromString($this->getHeaderName($index), $xml);
        }

        $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart);

        if($this->_rels!="")
        {
            $this->zipClass->addFromString('word/_rels/document.xml.rels', $this->_rels);
        }
        if($this->_types!="")
        {
            $this->zipClass->addFromString('[Content_Types].xml', $this->_types);
        }

        foreach ($this->tempDocumentFooters as $index => $xml) {
            $this->zipClass->addFromString($this->getFooterName($index), $xml);
        }

        // Close zip file
        if (false === $this->zipClass->close()) {
            throw new Exception('Could not close zip file.');
        }

        return $this->tempDocumentFilename;
    }


    public function setImg( $strKey, $img){
        $strKey = '${'.$strKey.'}';
        $relationTmpl = '<Relationship Id="RID" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/IMG"/>';

        $imgTmpl = '<w:pict><v:shape type="#_x0000_t75" style="width:WIDpx;height:HEIpx"><v:imagedata r:id="RID" o:title=""/></v:shape></w:pict>';

        $toAdd = $toAddImg = $toAddType = '';
        $aSearch = array('RID', 'IMG');
        $aSearchType = array('IMG', 'EXT');
        $countrels=$this->_countRels++;
        //I'm work for jpg files, if you are working with other images types -> Write conditions here
        $imgExt = 'jpg';
        $imgName = 'img' . $countrels . '.' . $imgExt;

        $this->zipClass->deleteName('word/media/' . $imgName);
        $this->zipClass->addFile($img['src'], 'word/media/' . $imgName);

        $typeTmpl = '<Override PartName="/word/media/'.$imgName.'" ContentType="image/EXT"/>';


        $rid = 'rId' . $countrels;
        $countrels++;
        list($w,$h) = getimagesize($img['src']);

        if(isset($img['swh'])) //Image proportionally larger side
        {
            if($w<=$h)
            {
                $ht=(int)$img['swh'];
                $ot=$w/$h;
                $wh=(int)$img['swh']*$ot;
                $wh=round($wh);
            }
            if($w>=$h)
            {
                $wh=(int)$img['swh'];
                $ot=$h/$w;
                $ht=(int)$img['swh']*$ot;
                $ht=round($ht);
            }
            $w=$wh;
            $h=$ht;
        }

        if(isset($img['size']))
        {
            $w = $img['size'][0];
            $h = $img['size'][1];
        }


        $toAddImg .= str_replace(array('RID', 'WID', 'HEI'), array($rid, $w, $h), $imgTmpl) ;
        if(isset($img['dataImg']))
        {
            $toAddImg.='<w:br/><w:t>'.$this->limpiarString($img['dataImg']).'</w:t><w:br/>';
        }

        $aReplace = array($imgName, $imgExt);
        $toAddType .= str_replace($aSearchType, $aReplace, $typeTmpl) ;

        $aReplace = array($rid, $imgName);
        $toAdd .= str_replace($aSearch, $aReplace, $relationTmpl);


        $this->tempDocumentMainPart=str_replace('<w:t>' . $strKey . '</w:t>', $toAddImg, $this->tempDocumentMainPart);
        //print $this->tempDocumentMainPart;



        if($this->_rels=="")
        {
            $this->_rels=$this->zipClass->getFromName('word/_rels/document.xml.rels');
            $this->_types=$this->zipClass->getFromName('[Content_Types].xml');
        }

        $this->_types       = str_replace('</Types>', $toAddType, $this->_types) . '</Types>';
        $this->_rels        = str_replace('</Relationships>', $toAdd, $this->_rels) . '</Relationships>';
    }

    public function limpiarString($str) {
        return str_replace(
            array('&', '<', '>', "\n"),
            array('&amp;', '&lt;', '&gt;', "\n" . '<w:br/>'),
            $str
        );
    }
}

จากนั้นแก้ไขโปรแกรมที่เคยเขียนไว้ก่อนหน้าให้ use Processor แทน TemplateProcessor ดังนี้

<?php
/**
 * User: kongoon
 * Date: 19/7/2560
 * Time: 12:53
 */

namespace frontend\modules\supply\controllers;


use common\components\Processor;
use common\models\SupplyDurableItem;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\TemplateProcessor;
use Yii;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\web\Controller;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;

class TestController extends Controller
{
    public function actionWord()
    {
        $data = '';
        foreach(SupplyDurableItem::find()->limit(10)->all() as $item){
            $data .= $item->detail.' ';
        }
        Settings::setTempDir(Yii::getAlias('@webroot').'/temp/'); //กำหนด folder temp สำหรับ windows server ที่ permission denied temp (อย่ายลืมสร้างใน project ล่ะ)
        //$templateProcessor = new TemplateProcessor(Yii::getAlias('@webroot').'/msword/template_in.docx');//เลือกไฟล์ template ที่เราสร้างไว้
        $templateProcessor = new Processor(Yii::getAlias('@webroot').'/msword/template_in.docx');//เลือกไฟล์ template ที่เราสร้างไว้
        $templateProcessor->setValue('doc_department', 'สำนักเทคโนโลยีสารสนเทศ');//อัดตัวแปร รายตัว
        $templateProcessor->setValue(
            [
                'doc_no',
                'doc_date',
                'doc_title',
                'doc_to',
                'doc_detail1',
                'doc_detail2',
                'doc_detail3',
                'doc_name',
                'doc_position'
            ],
            [
                'ทน1234/2345',
                '18 กรกฏาคม 2560',
                'การสร้างระบบออกเอกสารราชการ',
                'ผู้อำนวยการสถาบันเทคโนโลยีสารสนเทศแห่งชาติ',
                'เนื่องด้วยการพัฒนาระบบ Web-based Application ในปัจจุบันประสบปัญหาในการสร้างเอกสารราชการ กระผมนายมานพ กองอุ่น มีความประสงค์จะพัฒนาระบบการออกเอกสารราชการตามแม่แบบราชการสำหรับใช้งานในระบบ Web-based Application ดังนั้น กระผมจึงพัฒนาตัวอย่างของการออกเอกสารหนังสือราชการ เพื่อเป็นแนวทางให้กับหน่วยงานต่างๆ สามารถนำไปปรับใช้ในระบบ Web-based ของตัวเองได้',
                $data,
                'จึงเรียนมาเพื่อโปรดทราบ',
                'นายมานพ กองอุ่น',
                'นักเทคโนโลยีสารสนเทศแห่งประเทศไทย'
            ]);//อัดตัวแปรแบบชุด

        $templateProcessor->setImg('img1', ['src' => Yii::getAlias('@webroot') . '/img/logo.png', 'swh' => 150]);//ที่อยู่รูป frontend/web/img/logo.png, swh ความกว้าง/สูง 150 
        $templateProcessor->setImg('img2', ['src' => Yii::getAlias('@webroot') . '/images/cell.jpg', 'swh' => 350]);//ที่อยู่รูป frontend/web/images/cell.jpg, swh ความกว้าง/สูง 350

        $templateProcessor->saveAs(Yii::getAlias('@webroot').'/msword/ms_word_result.docx');//สั่งให้บันทึกข้อมูลลงไฟล์ใหม่

        /*
        //ตัวอย่างการสร้างไฟล์ ms word แบบไม่มี template
        $PHPWord = new PHPWord();
        $PHPWord->setDefaultFontName('TH Sarabun New');
        $PHPWord->setDefaultFontSize(16);

        $section = $PHPWord->createSection();

        $section->addText('ทดสอบข้อความ');
        $section->addTextBreak(2);

        $objWriter = IOFactory::createWriter($PHPWord, 'Word2007');
        $objWriter->save(Yii::getAlias('@webroot').'/msword/ms_word_test.docx');

        $objReader = IOFactory::load(Yii::getAlias('@webroot').'/msword/ms_word_test.docx');
        */

        echo '<p>';
        echo Html::a('ดาวน์โหลดเอกสาร', Url::to(Yii::getAlias('@web').'/msword/ms_word_result.docx'), ['class' => 'btn btn-info']);//สร้าง link download
        echo '</p>';
        //ลองให้ google doc viewer แสดงข้อมูลไฟล์ให้เห็นผ่าน iframe (อาจเพี้ยนๆ บ้าง)
        echo '<iframe src="http://docs.google.com/viewer?url='.Url::to(Yii::getAlias('@web').'/msword/ms_word_result.docx', true).'&embedded=true"  style="position: absolute;width:100%; height: 100%;border: none;"></iframe>';
    }

}

 

ความคิดเห็น

หากบทเรียนรู้มีความผิดพลาดประการใด หรือมีข้อเสนอแนะกรุณาแจ้ง contact@programmerthailand.com