12

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

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

这样的事情可能吗?

4

7 回答 7

13

以下代码是来自 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');
于 2014-06-09T09:59:56.380 回答
7

如果您想在 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
    );
}

五、使用方法:

//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');
于 2018-02-01T14:52:26.843 回答
4

我创建了一些函数来扩展 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);
    }
于 2015-08-27T12:45:59.903 回答
3

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

将以下函数添加到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);
于 2014-06-05T19:09:46.527 回答
1

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

让我们继续更改文件 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');
于 2016-01-20T08:57:51.350 回答
0

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

打开 zip 文件夹

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

为了setImageValue($search, $replace)

$search must be equls $replace OR use $this->zipClass->renameName ($replace , $search);
于 2016-08-03T03:40:15.227 回答
0

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

于 2020-08-12T13:59:01.173 回答