แทรกรูปภาพในเอกสาร MS Word จาก MS Word Template

แทรกรูปภาพในเอกสาร MS Word จาก MS Word Template

มานพ กองอุ่น phpword yii framework2 267

หลังจากที่ได้เรียนรู้วิธีการสร้างเอกสาร 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
มานพ กองอุ่น

มานพ กองอุ่น
admin

  • 2 เพื่อน
  • 16 ผู้ติดตาม
  • 773 โพสต์