หลังจากที่ได้เรียนรู้วิธีการสร้างเอกสาร 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('&', '<', '>', "\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>';
}
}
ความคิดเห็น