1<?php
2
3
4namespace ComboStrap;
5
6
7class ImageRaster extends Image
8{
9
10    const CANONICAL = "raster";
11
12
13    public function __construct($path, $attributes = null)
14    {
15        parent::__construct($path, $attributes);
16        $this->getAttributes()->setLogicalTag(self::CANONICAL);
17    }
18
19    private $imageWidth = null;
20    /**
21     * @var int
22     */
23    private $imageWeight = null;
24    /**
25     * See {@link image_type_to_mime_type}
26     * @var int
27     */
28    private $imageType;
29    private $wasAnalyzed = false;
30
31
32    /**
33     * @var mixed - the mime from the {@link RasterImageLink::analyzeImageIfNeeded()}
34     */
35    private $mime;
36
37    /**
38     * @return int - the width of the image from the file
39     * @throws ExceptionCombo
40     */
41    public function getIntrinsicWidth(): int
42    {
43        $this->analyzeImageIfNeeded();
44        return $this->imageWidth;
45    }
46
47    /**
48     * @return int - the height of the image from the file
49     * @throws ExceptionCombo
50     */
51    public function getIntrinsicHeight(): int
52    {
53        $this->analyzeImageIfNeeded();
54        return $this->imageWeight;
55    }
56
57    /**
58     * @throws ExceptionCombo
59     */
60    private
61    function analyzeImageIfNeeded()
62    {
63
64        if (!$this->wasAnalyzed) {
65
66            if ($this->exists()) {
67
68                /**
69                 * Based on {@link media_image_preview_size()}
70                 * $dimensions = media_image_preview_size($this->id, '', false);
71                 */
72                $imageInfo = array();
73                $path = $this->getPath();
74                if ($path instanceof DokuPath) {
75                    $path = $path->toLocalPath();
76                }
77                $imageSize = getimagesize($path->toAbsolutePath()->toString(), $imageInfo);
78                if ($imageSize === false) {
79                    throw new ExceptionCombo("We couldn't retrieve the type and dimensions of the image ($this). The image format seems to be not supported.", self::CANONICAL);
80                }
81                $this->imageWidth = (int)$imageSize[0];
82                if (empty($this->imageWidth)) {
83                    throw new ExceptionCombo("We couldn't retrieve the width of the image ($this)", self::CANONICAL);
84                }
85                $this->imageWeight = (int)$imageSize[1];
86                if (empty($this->imageWeight)) {
87                    throw new ExceptionCombo("We couldn't retrieve the height of the image ($this)", self::CANONICAL);
88                }
89                $this->imageType = (int)$imageSize[2];
90                $this->mime = $imageSize[3];
91
92            }
93        }
94        $this->wasAnalyzed = true;
95    }
96
97
98    /**
99     * @throws ExceptionCombo
100     */
101    public function getUrl()
102    {
103        return $this->getUrlAtBreakpoint();
104    }
105
106
107    /**
108     * @param int|null $breakpointWidth - the breakpoint width - use for responsive image
109     * @return string|null
110     * @throws ExceptionCombo
111     */
112    public function getUrlAtBreakpoint(int $breakpointWidth = null)
113    {
114
115        /**
116         * Default
117         */
118        if ($breakpointWidth == null) {
119            $breakpointWidth = $this->getTargetWidth();
120        }
121
122        if (!$this->exists()) {
123            LogUtility::msg("The image ($this) does not exist, you can't ask the URL", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
124            return false;
125        }
126
127        /**
128         * Link attribute
129         */
130        $att = array();
131
132        /**
133         * The image ratio is fixed
134         * Width is driving the computation
135         */
136        // Height for the given width
137        $breakpointHeight = $this->getBreakpointHeight($breakpointWidth);
138
139        /**
140         * If the request is not the original image
141         * and not cropped, add the width and height
142         */
143        if ($breakpointWidth != null &&
144            (
145                $breakpointWidth < $this->getIntrinsicWidth()
146                ||
147                $breakpointHeight < $this->getIntrinsicHeight()
148            )) {
149
150            $att['w'] = $breakpointWidth;
151
152            if (!empty($breakpointHeight)) {
153                $att['h'] = $breakpointHeight;
154                $this->checkLogicalRatioAgainstTargetRatio($breakpointWidth, $breakpointHeight);
155            }
156
157        }
158
159        if (!empty($this->getCache())) {
160            $att[CacheMedia::CACHE_KEY] = $this->getCache();
161        }
162
163        /**
164         * Smart Cache
165         */
166        $this->addCacheBusterToQueryParameters($att);
167
168        $direct = true;
169
170        if ($this->getPath() === null) {
171            LogUtility::msg("The Url of a image not in the media library is not yet supported", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
172            return "";
173        }
174        return ml($this->getPath()->getDokuwikiId(), $att, $direct, DokuwikiUrl::AMPERSAND_CHARACTER, true);
175
176
177    }
178
179    /**
180     * @throws ExceptionCombo
181     */
182    public
183    function getAbsoluteUrl()
184    {
185
186        return $this->getUrl();
187
188    }
189
190    /**
191     * We overwrite the {@link Image::getTargetWidth()}
192     * because we don't scale up for raster image
193     * to not lose quality.
194     *
195     * @return int
196     * @throws ExceptionCombo
197     */
198    public
199    function getTargetWidth(): int
200    {
201
202        $requestedWidth = $this->getRequestedWidth();
203
204        /**
205         * May be 0 (ie empty)
206         */
207        if (!empty($requestedWidth)) {
208            // it should not be bigger than the media Height
209            $mediaWidth = $this->getIntrinsicWidth();
210            if (!empty($mediaWidth)) {
211                if ($requestedWidth > $mediaWidth) {
212                    global $ID;
213                    if ($ID != "wiki:syntax") {
214                        // There is a bug in the wiki syntax page
215                        // {{wiki:dokuwiki-128.png?200x50}}
216                        // https://forum.dokuwiki.org/d/19313-bugtypo-how-to-make-a-request-to-change-the-syntax-page-on-dokuwikii
217                        LogUtility::msg("For the image ($this), the requested width of ($requestedWidth) can not be bigger than the intrinsic width of ($mediaWidth). The width was then set to its natural width ($mediaWidth)", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
218                    }
219                    $requestedWidth = $mediaWidth;
220                }
221            }
222            return $requestedWidth;
223        }
224
225        return parent::getTargetWidth();
226    }
227
228    /**
229     * @throws ExceptionCombo
230     */
231    public function getTargetHeight(): int
232    {
233
234        $requestedHeight = $this->getRequestedHeight();
235        if (!empty($requestedHeight)) {
236            // it should not be bigger than the media Height
237            $mediaHeight = $this->getIntrinsicHeight();
238            if (!empty($mediaHeight)) {
239                if ($requestedHeight > $mediaHeight) {
240                    LogUtility::msg("For the image ($this), the requested height of ($requestedHeight) can not be bigger than the intrinsic height of ($mediaHeight). The height was then set to its natural height ($mediaHeight)", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
241                    return $mediaHeight;
242                }
243            }
244        }
245
246        return parent::getTargetHeight();
247    }
248
249
250}
251