1<?php
2
3namespace dokuwiki\plugin\wordimport\docx;
4
5/**
6 * An image
7 *
8 * This is a paragraph with a drawing element containing an image
9 */
10class Image extends Paragraph
11{
12    /** @var string The reference ID for this image */
13    protected $rId = '';
14    /** @var string The description text for this image */
15    protected $alt = '';
16
17    /** @inheritdoc  */
18    public function parse()
19    {
20        parent::parse();
21
22        $blip = $this->p->xpath('w:r/w:drawing/wp:inline//a:blip')[0];
23        $this->rId = (string) $blip->attributes('r', true)->embed;
24
25        $alt = $this->p->xpath('w:r/w:drawing/wp:inline/wp:docPr')[0];
26        $this->alt = $this->clean((string)$alt['descr']);
27    }
28
29    /**
30     * The relationship ID points to an image in the relationships file. If we are in an import process,
31     * eg. $docx->getPageId() is set, we copy the image to the media folder here before referencing it in
32     * the DokuWiki syntax. Images are named after their relationship ID.
33     *
34     * @inheritdoc
35     */
36    public function __toString(): string
37    {
38        try {
39            $src = $this->docx->getRelationships()->getTarget('image', $this->rId);
40            $src = $this->docx->getFilePath($src);
41        } catch (\Exception $e) {
42            return ''; // we don't have an image for this. Ignore
43        }
44
45        [$ext, $mime] = mimetype($src);
46        if (!$mime) return ''; // not a supported image
47        if (!str_starts_with($mime, 'image/')) return ''; // not an image
48
49        $pageid = $this->docx->getPageId();
50        if ($pageid) {
51            $target = $pageid . ':' . $this->rId . '.' . $ext;
52            $this->copyImage($src, $target);
53        } else {
54            $target = $this->rId . '.' . $ext;
55        }
56        $target = cleanID($target);
57
58        $target = $this->alignmentPadding($target);
59        return '{{' . $target . '|' . $this->alt . '}}';
60    }
61
62    /**
63     * Copy an image to the media folder
64     *
65     * Will do nothing if the image already exists and is the same
66     *
67     * @param string $src The full path to the source image
68     * @param string $target The target media id
69     * @throws \Exception when the media could not be saved
70     */
71    protected function copyImage($src, $target)
72    {
73        if (file_exists(mediaFN($target)) && md5_file($src) === md5_file(mediaFN($target))) {
74            // image exists and is the same
75            return;
76        }
77
78        $auth = auth_quickaclcheck(getNS($target) . ':*');
79        $res = media_save(['name' => $src], $target, true, $auth, 'copy');
80        if (is_array($res)) {
81            throw new \Exception('Failed to save media: ' . $res[0]);
82        }
83
84        // clear the message generated by media_save
85        global $MSG;
86        $MSG = [];
87    }
88
89    /**
90     * Remove any character we can't allow inside an image tag
91     * @param string $string
92     * @return string
93     */
94    protected function clean($string): string
95    {
96        return str_replace(["\n", '{', '}', '|'], ' ', $string);
97    }
98}
99