Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add/set images on PHPOffice/PHPWord Template?

Tags:

php

phpword

I have an instance of a template on PHPWord. Is it possible to replace or add an image? Something like a setImageValue?

$phpWord = new \PhpOffice\PhpWord\Template('a.docx');
$phpWord->setImageValue('IMAGE_PLACEHOLDER', 'a.jpg');
$phpWord->saveAs('b.docx');

Is something like this possible?

like image 370
Diogo Melo Avatar asked Jun 03 '14 14:06

Diogo Melo


3 Answers

If you want to add, remove or replace image in template.docx you can add this to your TemplateProcessor.php file, (it works for me with PhpWord 0.14.0 version):

1.

// add this in the class
protected $_rels;
protected $_types;

public function __construct($documentTemplate){
    // add this line to this function
    $this->_countRels=100; 
}

2.

public function save()
{
    //add this snippet to this function after $this->zipClass->addFromString('word/document.xml', $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);
    }
}

3. Add this function too:

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>';
}

4. And this:

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

5. How to use:

//open your template  
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('files/template.docx');
//add image to selector
$templateProcessor->setImg('selector',array('src' => 'image.jpg','swh'=>'200', 'size'=>array(0=>$width, 1=>$height));
// You can also clone row if you need
//$templateProcessor->cloneRow('NAME_IN_TEMPLATE', NUMBER_OF_TABLE_RECORDS);
$templateProcessor->cloneRow('SELECTOR', 4);
//save
header("Content-Disposition: attachment; filename='helloWord.docx'");
$templateProcessor->saveAs('php://output');
like image 200
karolkarp Avatar answered Nov 08 '22 12:11

karolkarp


Following code is the updated version of the one from TotPeRo (thanks again for your code!), for last phpOffice (0.11) that has evolved a little

/**
 * Set a new image
 *
 * @param string $search
 * @param string $replace
 */
public function setImageValue($search, $replace)
{
    // Sanity check
    if (!file_exists($replace))
    {
        return;
    }

    // Delete current image
    $this->zipClass->deleteName('word/media/' . $search);

    // Add a new one
    $this->zipClass->addFile($replace, 'word/media/' . $search);
}

Can be called with:

$document->setImageValue('image1.jpg', 'my_image.jpg');
like image 42
Jerome Avatar answered Nov 08 '22 13:11

Jerome


his is pretty much untested. but this is working for me (although mine is slightly different):

add the following function to PHPWord/Template.php :

 public function save_image($id,$filepath,&$document=null) { 
        if(file_exists($filepath))
        {
            $this->_objZip->deleteName('word/media/'.$id);          
            $this->_objZip->addFile ($filepath,'word/media/'.$id);
            //$document->setValue($id.'::width', "300px");
            //$document->setValue($id.'::height', "300px");
        }   
    }

create a document with an actual image to be used as a place holder (this solution don't allow setting the with & height of the image or multiple extensions). unzip the the documnt and check for the file name in word/media folder. use this file name as the $id for the save_image function.

you can now use:

$document->save_image('image1',$image_path,$document);
like image 3
TotPeRo Avatar answered Nov 08 '22 13:11

TotPeRo