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

后端 未结 7 731
猫巷女王i
猫巷女王i 2020-12-09 05:33

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\\         


        
相关标签:
7条回答
  • 2020-12-09 05:42

    modify the name of the *.docx to *.zip

    open the zip folder

    view the "word/media/****" the imgage name is to replace name

    for setImageValue($search, $replace)

    $search must be equls $replace OR use $this->zipClass->renameName ($replace , $search);
    
    0 讨论(0)
  • 2020-12-09 05:43

    Just a note for anyone reading this in 2020 and later, PhpWord now has setImageValue() method, docs can be found here: https://phpword.readthedocs.io/en/latest/templates-processing.html#setimagevalue

    0 讨论(0)
  • 2020-12-09 05:50

    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);
    
    0 讨论(0)
  • 2020-12-09 05:54

    I created some functions to extend Jerome's solution. The problem was that in order to change the picture we had to know it's reference name in the docx file. This could be difficult to find out for an average user (you have to "unZip" the docx, and find your picture manually).

    My solution makes it possible to reference pictures by alt text (it needs to be in usual format: ${abc} ) so one doesn't have to know how word names the placeholder picture, the variable is enough. Here's a link about how to add alt texts: http://accessproject.colostate.edu/udl/modules/word/tut_alt_text.php?display=pg_2

    I only modified TemplateProcessor.php

    First add this to the class:

    /**
         * Content of document rels (in XML format) of the temporary document.
         *
         * @var string
         */
        private $temporaryDocumentRels; 
    

    The constructor function (public function __construct($documentTemplate)) needs to be extended at the end. Add this:

    $this->temporaryDocumentRels = $this->zipClass->getFromName('word/_rels/document.xml.rels'); 
    

    Now you can read stuff from document.xml.rels by using $this->temporaryDocumentRels

    Keep Jerome's code:

    /**
         * 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);
        }
    

    This function returns with the rId of the image you labeled:

    /**
         * Search for the labeled image's rId
         *
         * @param string $search
         */
    
        public function seachImagerId($search){
            if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
                $search = '${' . $search . '}';
            }
            $tagPos = strpos($this->temporaryDocumentMainPart, $search);
            $rIdStart = strpos($this->temporaryDocumentMainPart, 'r:embed="',$tagPos)+9;    
            $rId=strstr(substr($this->temporaryDocumentMainPart, $rIdStart),'"', true);
            return $rId;
        }
    

    And this returns the images filename, if you know it's rId:

    /**
         * Get img filename with it's rId
         *
         * @param string $rId
         */
    
        public function getImgFileName($rId){
            $tagPos = strpos($this->temporaryDocumentRels, $rId);
            $fileNameStart = strpos($this->temporaryDocumentRels, 'Target="media/',$tagPos)+14;
            $fileName=strstr(substr($this->temporaryDocumentRels, $fileNameStart),'"', true);
            return $fileName;
        }
    

    The modifications in TemplateProcessor.php are done.

    Now you can replace the image by calling this:

    $templateProcessor->setImageValue($templateProcessor->getImgFileName($templateProcessor->seachImagerId("abc")),$replace);
    

    You can also create a functionin TemplateProcessor.php that calls it like:

    public function setImageValueAlt($searchAlt, $replace){
            $this->setImageValue($this->getImgFileName($this->seachImagerId($searchAlt)),$replace);
        }
    
    0 讨论(0)
  • 2020-12-09 05:59

    I was looking for a solution to add an image. I read a lot of articles, I only found suitable solutions for older versions. Changing and finalized the decision to get the code.

    Let us proceed to change the file TemplateProcessor.php

    public function __construct($documentTemplate)
    {
    //add to this function
    
    $this->_countRels=100; //start id for relationship between image and document.xml
    }
    
    public function save()
    {
    //add 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);
    }
    }
    
    //add function
    
    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>';
    }
    //add function
    
    function limpiarString($str) {
            return str_replace(
                    array('&', '<', '>', "\n"), 
                    array('&amp;', '&lt;', '&gt;', "\n" . '<w:br/>'), 
                    $str
            );
    }
    //HOW TO USE???
    
    $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('templ.docx');
    
    //static zone
    $templateProcessor->setValue('date', htmlspecialchars(date('d.m.Y G:i:s')));    
    //$templateProcessor->cloneRow('NAME_IN_TEMPLATE', NUMBER_OF_TABLE_RECORDS);
    $templateProcessor->cloneRow('AVTOR', 3);
    
    //variant 1
    //dynamic zone
    $templateProcessor->setValue('AVTOR#1', htmlspecialchars('Garry'));
    $templateProcessor->setValue('NAME#1', htmlspecialchars('Black Horse'));
    $templateProcessor->setValue('SIZES#1', htmlspecialchars('100x300'));
    
    /*$img = array(
            'src' => 'image.jpg',//path
        'swh'=>'350',//Image proportionally larger side
            'size'=>array(580, 280)
    );*/
    $templateProcessor->setImg('IMGD#1',array('src' => 'image.jpg','swh'=>'250'));
    
    $templateProcessor->setValue('AVTOR#2', htmlspecialchars('Barry'));
    $templateProcessor->setValue('NAME#2', htmlspecialchars('White Horse'));
    $templateProcessor->setValue('SIZES#2', htmlspecialchars('200x500'));
    $templateProcessor->setImg('IMGD#2',array('src' => 'image2.jpg','swh'=>'250'));
    
    $templateProcessor->setValue('AVTOR#3', htmlspecialchars('Backer'));
    $templateProcessor->setValue('NAME#3', htmlspecialchars('Another Side'));
    $templateProcessor->setValue('SIZES#3', htmlspecialchars('120x430'));
    $templateProcessor->setImg('IMGD#3',array('src' => 'image3.jpg','swh'=>'250'));
    //variant 2
    
    $templateProcessor->cloneRow('AVTOR', count($output['ID'])); 
            for($i=0;$i<count($output['ID']);$i++)
            {
                $templateProcessor->setValue('AVTOR'.'#'.($i+1), htmlspecialchars($output['AVTOR'][$i]));
                $templateProcessor->setValue('NAME'.'#'.($i+1), htmlspecialchars($output['PNAM'][$i]));
    //GetImg($output['ID'][$i]) my function return image path
                $templateProcessor->setImg('IMGD'.'#'.($i+1), array('src'=>GetImg($output['ID'][$i]),'swh'=>'250'));
            }
    //Save
    
    $templateProcessor->saveAs('testTemplate.docx');
    
    0 讨论(0)
  • 2020-12-09 06:02

    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');
    
    0 讨论(0)
提交回复
热议问题