Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New function in TemplateProcessor to add images to documents #1084

Closed
wants to merge 2 commits into from

Conversation

ejn
Copy link

@ejn ejn commented Jun 23, 2017

Image placeholders have the form ${img:<name>}.

The width and height of the image to insert may be specified as
additional arguments to the placeholder: ${img:<name>:width:height}

For the width and height, CSS units cm, mm, px, pt and pc may be used,
e.g. ${img:beispiel:15cm:360pt}

ejn added 2 commits June 27, 2017 11:28
- utility functions to parse lengths given in absolute CSS units (in. px,
mm, cm, pc)
Image placeholders have the form ${img:name}.

The width and height of the image to insert may be specified as
additional arguments to the placeholder: ${img:name:width:height}

For the width and height, CSS units cm, mm, px, pt and pc may be used,
e.g. ${img:beispiel:15cm:360pt}
@ejn
Copy link
Author

ejn commented Jun 27, 2017

(updated the PR to split into two PRs due to code overlap with #1086)

@SadPencil
Copy link

that's helpful.
I wonder if it's possible to give a base-64 image string instead of a file path to add image in template?

@ejn
Copy link
Author

ejn commented Sep 6, 2017

@SadPencil tbh I'm not sure what would be possible internally in the DOCX, but it should be straightforward to allow the image to be passed as a string (no need for base64-encoding!) instead of a file path and then write the string to an internal file in the DOCX. It would require a little refactoring of addImageToArchive() and insertImage() (probably to API methods insertImageFromString() and insertImageFromFile() with a common helper method), but the changes to this PR should be pretty straightforward. Why not give it a go?

@SalvatorePollaci
Copy link

When will this pull request be merged?

@FBnil
Copy link

FBnil commented Oct 2, 2017

@ejn:

I like your work a lot. And I've got a working copy of something similar to insertImageFromString() but broader.
I've exposed zipAddFromString(), basically:

    /**
     * Updates a file inside the document, from a string (with binary data)
     *
     * @param string $localname
     * @param string $contents
     *
     * @return bool
     */
    public function zipAddFromString($localname, $contents)
    {
        return $this->zipClass->AddFromString($localname, $contents);
    }

That already allows to retain the dimensions/position/properties of the image and only change the image. Tested to work with Office 365 and LibreOffice. Even if the new jpg has a bigger size.

A working example is in my pull request: #1147

@SadPencil You can do exactly what you describe in the current PHPWord version 0.13; first define this class (You can do it inline, just above your code):

class OpenTemplateProcessor extends \PhpOffice\PhpWord\TemplateProcessor
{
    protected $_instance;

    public function __construct($instance) {
		return parent::__construct($instance);
    }

    public function __get($key) {
        return $this->$key;
    }

    public function __set($key, $val) {
        return $this->$key = $val;
    }
}

now instead of new TemplateProcessor(), do a new OpenTemplateProcessor()
This object behaves the same, but has access to the zipClass, like so:

$replace = "word/media/image2.jpeg";
$met = file_get_contents(storage_path('anyNewImage.jpg'));
$templateProcessor = new OpenTemplateProcessor($file_dir);
$templateProcessor->zipClass->AddFromString($replace,$met);
// now use save() or saveas()

and you have injected a new image.

@FBnil FBnil mentioned this pull request Oct 6, 2017
@FBnil
Copy link

FBnil commented Oct 7, 2017

@ejn Still working on a united script, can you make your script that it also allows a insertImageFromString() and a insertImageFromFile() where the latter just uses the first to do all the job?

Still waiting for your Feedback about if it is better to have uniform names, setValue(), setImage(), etc.
At least for the public functions, the protected functions can stay named the way they are.

@rkorebrits
Copy link

Hi @ejn , I'm trying to implement your changes, but the output file is borked. I've checked out your branch and using the code 100% as you pushed it.

I've set up an empty file with just the variable to test, this is the result:

Template: empty.docx
Output: CV_680989964_Test_Name_20180507-140848.docx

When I open the output file, I get this message:
image

After clicking "ok" here, I get the option to "recover the contents", which works, but it's not a viable solution. Am I missing something here? Or what could cause this issue?

@ejn
Copy link
Author

ejn commented May 7, 2018

@rkorebrits: Looking at the result file and the file after Word has repaired it, the [Content_Types].xml is borked - I'm guessing by a . in the filename of the image you're adding which is being interpreted as the file extension (Extension="76766837.jpeg").

The workaround is probably to make sure that there is no . in the filename apart from before the real extension, a real fix would be to replace strpos with strrpos in line 820/821 (or do getting the extension in some other better way).

If/when I get around to reworking this to take care of the points raised by @FBnil (using the existing methods to generate the XML rather than just slapping in pre-prepared chunks) then I'll be sure to take care of that too.

@rkorebrits
Copy link

Thanks @ejn! That did the trick :-)

@rkorebrits
Copy link

rkorebrits commented May 9, 2018

@ejn I have updated the code to check if there is an image passed, and if the image actually exists. If the image doesn't exist it threw a PHP error before on getimagesize. When there is no image, the tag should be removed imho.

public function insertImage($name, $srcFilename, $width = null, $height = null, $mimeType = null, $filename = null)
{

    if ( ! $srcFilename || ! file_exists($srcFilename)) {
        $removeImageRegex = '/\${img:' . $name . '.*?}/i';

        foreach ($this->tempDocumentHeaders as $index => $header) {
            $this->tempDocumentHeaders[$index] = preg_replace(
                $removeImageRegex, '', $this->tempDocumentHeaders[$index]
            );
        }

        $this->tempDocumentMainPart = preg_replace(
            $removeImageRegex, '', $this->tempDocumentMainPart
        );

        foreach ($this->tempDocumentFooters as $index => $footer) {
            $this->tempDocumentFooters[$index] = preg_replace(
                $removeImageRegex, '', $this->tempDocumentFooters[$index]
            );
        }

        return $this;
    }

@troosan troosan added this to the v0.16.0 milestone Jul 15, 2018
@troosan
Copy link
Contributor

troosan commented Dec 26, 2018

I merged #1170 which is doing the same. Feel free to open a new PR if features are missing

@troosan troosan closed this Dec 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

6 participants