【问题标题】:How to add/set images on PHPOffice/PHPWord Template?如何在 PHPOffice/PHPWord 模板上添加/设置图像?
【发布时间】:2014-07-23 22:57:03
【问题描述】:

我在 PHPWord 上有一个模板实例。是否可以替换或添加图像?类似 setImageValue 的东西?

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

这样的事情可能吗?

【问题讨论】:

    标签: php phpword


    【解决方案1】:

    他几乎没有经过测试。但这对我有用(尽管我的略有不同):

    将以下函数添加到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");
            }   
        }
    

    创建一个包含实际图像的文档以用作占位符(此解决方案不允许设置图像的 with & height 或多个扩展名)。 解压缩文档并检查 word/media 文件夹中的文件名。将此文件名用作 save_image 函数的 $id。

    您现在可以使用:

    $document->save_image('image1',$image_path,$document);
    

    【讨论】:

      【解决方案2】:

      以下代码是来自 TotPeRo 的更新版本(再次感谢您的代码!),最后一个 phpOffice (0.11) 已经发展了一点

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

      可以调用:

      $document->setImageValue('image1.jpg', 'my_image.jpg');
      

      【讨论】:

      • 这是一个不错的简单解决方案。谢谢。不过,特别是对于我们的 Windows 用户来说,需要注意的一点是要小心 $search 名称。它区分大小写。我使用 'image1.png' 而不是 'image1.PNG' 作为我的 $search 并最终得到一个非常混乱的存档,其中包含两个图像并且在解压缩时抛出错误。
      【解决方案3】:

      我创建了一些函数来扩展 Jerome 的解决方案。问题是为了改变图片,我们必须知道它在 docx 文件中的参考名称。对于普通用户来说,这可能很难找到(您必须“解压缩” docx,然后手动找到您的图片)。

      我的解决方案可以通过 alt 文本引用图片(它需要采用通常的格式: ${abc} ) 所以不必知道单词如何命名占位符图片,变量就足够了。 这是一个关于如何添加替代文本的链接:http://accessproject.colostate.edu/udl/modules/word/tut_alt_text.php?display=pg_2

      我只修改了TemplateProcessor.php

      首先将这个添加到类中:

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

      最后需要扩展构造函数(public function __construct($documentTemplate))。添加这个:

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

      现在您可以使用 $this->temporaryDocumentRels 从 document.xml.rels 读取内容

      保留 Jerome 的代码:

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

      此函数返回您标记的图像的 rId:

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

      如果您知道它是 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;
          }
      

      TemplateProcessor.php中的修改就完成了。

      现在你可以通过调用这个来替换图像:

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

      您还可以在 TemplateProcessor.php 中创建一个函数,调用它:

      public function setImageValueAlt($searchAlt, $replace){
              $this->setImageValue($this->getImgFileName($this->seachImagerId($searchAlt)),$replace);
          }
      

      【讨论】:

        【解决方案4】:

        我一直在寻找添加图像的解决方案。我阅读了很多文章,我只找到了适合旧版本的解决方案。更改并最终决定获取代码。

        让我们继续更改文件 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');
        

        【讨论】:

          【解决方案5】:

          *.docx的名称修改为*.zip

          打开压缩包

          查看“word/media/****”图片名称是为了替换名称

          setImageValue($search, $replace)

          $search must be equls $replace OR use $this->zipClass->renameName ($replace , $search);
          

          【讨论】:

            【解决方案6】:

            如果您想在 template.docx 中添加、删除或替换图像,您可以将其添加到您的 TemplateProcessor.php 文件中,(它适用于 PhpWord 0.14.0 版本):

            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.也添加这个功能:

            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.还有这个:

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

            5.使用方法:

            //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');
            

            【讨论】:

            • 似乎很有魅力。你应该把它推荐给phpword的核心。它应该是内置的。同时我做了一个小修改以避免php错误。
            【解决方案7】:

            请注意,对于 2020 年及以后阅读本文的任何人,PhpWord 现在具有 setImageValue() 方法,可在此处找到文档:https://phpword.readthedocs.io/en/latest/templates-processing.html#setimagevalue

            【讨论】:

              猜你喜欢
              • 2014-07-19
              • 2019-03-20
              • 1970-01-01
              • 2021-05-26
              • 1970-01-01
              • 1970-01-01
              • 2018-04-27
              • 1970-01-01
              • 2018-05-27
              相关资源
              最近更新 更多