xref: /plugin/combo/ComboStrap/RasterImageLink.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau/**
3*37748cd8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
4*37748cd8SNickeau *
5*37748cd8SNickeau * This source code is licensed under the GPL license found in the
6*37748cd8SNickeau * COPYING  file in the root directory of this source tree.
7*37748cd8SNickeau *
8*37748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
9*37748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
10*37748cd8SNickeau *
11*37748cd8SNickeau */
12*37748cd8SNickeau
13*37748cd8SNickeaunamespace ComboStrap;
14*37748cd8SNickeau
15*37748cd8SNickeaurequire_once(__DIR__ . '/MediaLink.php');
16*37748cd8SNickeaurequire_once(__DIR__ . '/LazyLoad.php');
17*37748cd8SNickeaurequire_once(__DIR__ . '/PluginUtility.php');
18*37748cd8SNickeau
19*37748cd8SNickeau/**
20*37748cd8SNickeau * Image
21*37748cd8SNickeau * This is the class that handles the
22*37748cd8SNickeau * raster image type of the dokuwiki {@link MediaLink}
23*37748cd8SNickeau *
24*37748cd8SNickeau * The real documentation can be found on the image page
25*37748cd8SNickeau * @link https://www.dokuwiki.org/images
26*37748cd8SNickeau *
27*37748cd8SNickeau * Doc:
28*37748cd8SNickeau * https://web.dev/optimize-cls/#images-without-dimensions
29*37748cd8SNickeau * https://web.dev/cls/
30*37748cd8SNickeau */
31*37748cd8SNickeauclass RasterImageLink extends MediaLink
32*37748cd8SNickeau{
33*37748cd8SNickeau
34*37748cd8SNickeau    const CANONICAL = "raster";
35*37748cd8SNickeau    const CONF_LAZY_LOADING_ENABLE = "rasterImageLazyLoadingEnable";
36*37748cd8SNickeau
37*37748cd8SNickeau    const RESPONSIVE_CLASS = "img-fluid";
38*37748cd8SNickeau
39*37748cd8SNickeau    const CONF_RESPONSIVE_IMAGE_MARGIN = "responsiveImageMargin";
40*37748cd8SNickeau    const CONF_RETINA_SUPPORT_ENABLED = "retinaRasterImageEnable";
41*37748cd8SNickeau    const LAZY_CLASS = "lazy-raster-combo";
42*37748cd8SNickeau
43*37748cd8SNickeau    const BREAKPOINTS =
44*37748cd8SNickeau        array(
45*37748cd8SNickeau            "xs" => 375,
46*37748cd8SNickeau            "sm" => 576,
47*37748cd8SNickeau            "md" => 768,
48*37748cd8SNickeau            "lg" => 992
49*37748cd8SNickeau        );
50*37748cd8SNickeau
51*37748cd8SNickeau
52*37748cd8SNickeau    private $imageWidth = null;
53*37748cd8SNickeau    /**
54*37748cd8SNickeau     * @var int
55*37748cd8SNickeau     */
56*37748cd8SNickeau    private $imageWeight = null;
57*37748cd8SNickeau    /**
58*37748cd8SNickeau     * See {@link image_type_to_mime_type}
59*37748cd8SNickeau     * @var int
60*37748cd8SNickeau     */
61*37748cd8SNickeau    private $imageType;
62*37748cd8SNickeau    private $wasAnalyzed = false;
63*37748cd8SNickeau
64*37748cd8SNickeau    /**
65*37748cd8SNickeau     * @var bool
66*37748cd8SNickeau     */
67*37748cd8SNickeau    private $analyzable = false;
68*37748cd8SNickeau
69*37748cd8SNickeau    /**
70*37748cd8SNickeau     * @var mixed - the mime from the {@link RasterImageLink::analyzeImageIfNeeded()}
71*37748cd8SNickeau     */
72*37748cd8SNickeau    private $mime;
73*37748cd8SNickeau
74*37748cd8SNickeau    /**
75*37748cd8SNickeau     * RasterImageLink constructor.
76*37748cd8SNickeau     * @param $ref
77*37748cd8SNickeau     * @param TagAttributes $tagAttributes
78*37748cd8SNickeau     */
79*37748cd8SNickeau    public function __construct($ref, $tagAttributes = null)
80*37748cd8SNickeau    {
81*37748cd8SNickeau        parent::__construct($ref, $tagAttributes);
82*37748cd8SNickeau        $this->getTagAttributes()->setLogicalTag(self::CANONICAL);
83*37748cd8SNickeau
84*37748cd8SNickeau    }
85*37748cd8SNickeau
86*37748cd8SNickeau
87*37748cd8SNickeau    /**
88*37748cd8SNickeau     * @param string $ampersand
89*37748cd8SNickeau     * @param null $localWidth - the asked width - use for responsive image
90*37748cd8SNickeau     * @return string|null
91*37748cd8SNickeau     */
92*37748cd8SNickeau    public function getUrl($ampersand = DokuwikiUrl::URL_ENCODED_AND, $localWidth = null)
93*37748cd8SNickeau    {
94*37748cd8SNickeau
95*37748cd8SNickeau        if ($this->exists()) {
96*37748cd8SNickeau
97*37748cd8SNickeau            /**
98*37748cd8SNickeau             * Link attribute
99*37748cd8SNickeau             */
100*37748cd8SNickeau            $att = array();
101*37748cd8SNickeau
102*37748cd8SNickeau            // Width is driving the computation
103*37748cd8SNickeau            if ($localWidth != null && $localWidth != $this->getMediaWidth()) {
104*37748cd8SNickeau
105*37748cd8SNickeau                $att['w'] = $localWidth;
106*37748cd8SNickeau
107*37748cd8SNickeau                // Height
108*37748cd8SNickeau                $height = $this->getImgTagHeightValue($localWidth);
109*37748cd8SNickeau                if (!empty($height)) {
110*37748cd8SNickeau                    $att['h'] = $height;
111*37748cd8SNickeau                    $this->checkWidthAndHeightRatioAndReturnTheGoodValue($localWidth, $height);
112*37748cd8SNickeau                }
113*37748cd8SNickeau
114*37748cd8SNickeau
115*37748cd8SNickeau            }
116*37748cd8SNickeau
117*37748cd8SNickeau            if ($this->getCache()) {
118*37748cd8SNickeau                $att[CacheMedia::CACHE_KEY] = $this->getCache();
119*37748cd8SNickeau            }
120*37748cd8SNickeau            $direct = true;
121*37748cd8SNickeau
122*37748cd8SNickeau            return ml($this->getId(), $att, $direct, $ampersand, true);
123*37748cd8SNickeau
124*37748cd8SNickeau        } else {
125*37748cd8SNickeau
126*37748cd8SNickeau            return false;
127*37748cd8SNickeau
128*37748cd8SNickeau        }
129*37748cd8SNickeau    }
130*37748cd8SNickeau
131*37748cd8SNickeau    public function getAbsoluteUrl()
132*37748cd8SNickeau    {
133*37748cd8SNickeau
134*37748cd8SNickeau        return $this->getUrl();
135*37748cd8SNickeau
136*37748cd8SNickeau    }
137*37748cd8SNickeau
138*37748cd8SNickeau
139*37748cd8SNickeau    /**
140*37748cd8SNickeau     * Render a link
141*37748cd8SNickeau     * Snippet derived from {@link \Doku_Renderer_xhtml::internalmedia()}
142*37748cd8SNickeau     * A media can be a video also (Use
143*37748cd8SNickeau     * @return string
144*37748cd8SNickeau     */
145*37748cd8SNickeau    public function renderMediaTag()
146*37748cd8SNickeau    {
147*37748cd8SNickeau
148*37748cd8SNickeau
149*37748cd8SNickeau        if ($this->exists()) {
150*37748cd8SNickeau
151*37748cd8SNickeau
152*37748cd8SNickeau            /**
153*37748cd8SNickeau             * No dokuwiki type attribute
154*37748cd8SNickeau             */
155*37748cd8SNickeau            $this->tagAttributes->removeComponentAttributeIfPresent(MediaLink::MEDIA_DOKUWIKI_TYPE);
156*37748cd8SNickeau            $this->tagAttributes->removeComponentAttributeIfPresent(MediaLink::DOKUWIKI_SRC);
157*37748cd8SNickeau
158*37748cd8SNickeau            /**
159*37748cd8SNickeau             * Responsive image
160*37748cd8SNickeau             * https://getbootstrap.com/docs/5.0/content/images/
161*37748cd8SNickeau             * to apply max-width: 100%; and height: auto;
162*37748cd8SNickeau             *
163*37748cd8SNickeau             * Even if the resizing is requested by height,
164*37748cd8SNickeau             * the height: auto on styling is needed to conserve the ratio
165*37748cd8SNickeau             * while scaling down the screen
166*37748cd8SNickeau             */
167*37748cd8SNickeau            $this->tagAttributes->addClassName(self::RESPONSIVE_CLASS);
168*37748cd8SNickeau
169*37748cd8SNickeau
170*37748cd8SNickeau            /**
171*37748cd8SNickeau             * width and height to give the dimension ratio
172*37748cd8SNickeau             * They have an effect on the space reservation
173*37748cd8SNickeau             * but not on responsive image at all
174*37748cd8SNickeau             * To allow responsive height, the height style property is set at auto
175*37748cd8SNickeau             * (ie img-fluid in bootstrap)
176*37748cd8SNickeau             */
177*37748cd8SNickeau            // The unit is not mandatory in HTML, this is expected to be CSS pixel
178*37748cd8SNickeau            // https://html.spec.whatwg.org/multipage/embedded-content-other.html#attr-dim-height
179*37748cd8SNickeau            // The HTML validator does not expect an unit otherwise it send an error
180*37748cd8SNickeau            // https://validator.w3.org/
181*37748cd8SNickeau            $htmlLengthUnit = "";
182*37748cd8SNickeau
183*37748cd8SNickeau            /**
184*37748cd8SNickeau             * Height
185*37748cd8SNickeau             * The logical height that the image should take on the page
186*37748cd8SNickeau             *
187*37748cd8SNickeau             * Note: The style is also set in {@link Dimension::processWidthAndHeight()}
188*37748cd8SNickeau             *
189*37748cd8SNickeau             * The doc is {@link https://www.dokuwiki.org/images#resizing}
190*37748cd8SNickeau             * See the ''0x20''
191*37748cd8SNickeau             */
192*37748cd8SNickeau            $imgTagHeight = $this->getImgTagHeightValue();
193*37748cd8SNickeau            if (!empty($imgTagHeight)) {
194*37748cd8SNickeau                $this->tagAttributes->addHtmlAttributeValue("height", $imgTagHeight . $htmlLengthUnit);
195*37748cd8SNickeau            }
196*37748cd8SNickeau
197*37748cd8SNickeau
198*37748cd8SNickeau            /**
199*37748cd8SNickeau             * Width
200*37748cd8SNickeau             *
201*37748cd8SNickeau             * We create a series of URL
202*37748cd8SNickeau             * for different width and let the browser
203*37748cd8SNickeau             * download the best one for:
204*37748cd8SNickeau             *   * the actual container width
205*37748cd8SNickeau             *   * the actual of screen resolution
206*37748cd8SNickeau             *   * and the connection speed.
207*37748cd8SNickeau             *
208*37748cd8SNickeau             * The max-width value is set
209*37748cd8SNickeau             */
210*37748cd8SNickeau            $mediaWidthValue = $this->getMediaWidth();
211*37748cd8SNickeau            $srcValue = $this->getUrl();
212*37748cd8SNickeau
213*37748cd8SNickeau            /**
214*37748cd8SNickeau             * Responsive image src set building
215*37748cd8SNickeau             * We have chosen
216*37748cd8SNickeau             *   * 375: Iphone6
217*37748cd8SNickeau             *   * 768: Ipad
218*37748cd8SNickeau             *   * 1024: Ipad Pro
219*37748cd8SNickeau             *
220*37748cd8SNickeau             */
221*37748cd8SNickeau            // The image margin applied
222*37748cd8SNickeau            $imageMargin = PluginUtility::getConfValue(self::CONF_RESPONSIVE_IMAGE_MARGIN, "20px");
223*37748cd8SNickeau
224*37748cd8SNickeau
225*37748cd8SNickeau            /**
226*37748cd8SNickeau             * Srcset and sizes for responsive image
227*37748cd8SNickeau             * Width is mandatory for responsive image
228*37748cd8SNickeau             * Ref https://developers.google.com/search/docs/advanced/guidelines/google-images#responsive-images
229*37748cd8SNickeau             */
230*37748cd8SNickeau            if (!empty($mediaWidthValue)) {
231*37748cd8SNickeau
232*37748cd8SNickeau                /**
233*37748cd8SNickeau                 * The internal intrinsic value of the image
234*37748cd8SNickeau                 */
235*37748cd8SNickeau                $imgTagWidth = $this->getImgTagWidthValue();
236*37748cd8SNickeau                if (!empty($imgTagWidth)) {
237*37748cd8SNickeau
238*37748cd8SNickeau                    if (!empty($imgTagHeight)) {
239*37748cd8SNickeau                        $imgTagWidth = $this->checkWidthAndHeightRatioAndReturnTheGoodValue($imgTagWidth, $imgTagHeight);
240*37748cd8SNickeau                    }
241*37748cd8SNickeau                    $this->tagAttributes->addHtmlAttributeValue("width", $imgTagWidth . $htmlLengthUnit);
242*37748cd8SNickeau                }
243*37748cd8SNickeau
244*37748cd8SNickeau                /**
245*37748cd8SNickeau                 * Continue
246*37748cd8SNickeau                 */
247*37748cd8SNickeau                $srcSet = "";
248*37748cd8SNickeau                $sizes = "";
249*37748cd8SNickeau
250*37748cd8SNickeau                /**
251*37748cd8SNickeau                 * Add smaller sizes
252*37748cd8SNickeau                 */
253*37748cd8SNickeau                foreach (self::BREAKPOINTS as $breakpointWidth) {
254*37748cd8SNickeau
255*37748cd8SNickeau                    if ($imgTagWidth > $breakpointWidth) {
256*37748cd8SNickeau
257*37748cd8SNickeau                        if (!empty($srcSet)) {
258*37748cd8SNickeau                            $srcSet .= ", ";
259*37748cd8SNickeau                            $sizes .= ", ";
260*37748cd8SNickeau                        }
261*37748cd8SNickeau                        $breakpointWidthMinusMargin = $breakpointWidth - $imageMargin;
262*37748cd8SNickeau                        $xsmUrl = $this->getUrl(DokuwikiUrl::URL_ENCODED_AND, $breakpointWidthMinusMargin);
263*37748cd8SNickeau                        $srcSet .= "$xsmUrl {$breakpointWidthMinusMargin}w";
264*37748cd8SNickeau                        $sizes .= $this->getSizes($breakpointWidth, $breakpointWidthMinusMargin);
265*37748cd8SNickeau
266*37748cd8SNickeau                    }
267*37748cd8SNickeau
268*37748cd8SNickeau                }
269*37748cd8SNickeau
270*37748cd8SNickeau                /**
271*37748cd8SNickeau                 * Add the last size
272*37748cd8SNickeau                 * If the image is really small, srcset and sizes are empty
273*37748cd8SNickeau                 */
274*37748cd8SNickeau                if (!empty($srcSet)) {
275*37748cd8SNickeau                    $srcSet .= ", ";
276*37748cd8SNickeau                    $sizes .= ", ";
277*37748cd8SNickeau                    $srcUrl = $this->getUrl(DokuwikiUrl::URL_ENCODED_AND, $imgTagWidth);
278*37748cd8SNickeau                    $srcSet .= "$srcUrl {$imgTagWidth}w";
279*37748cd8SNickeau                    $sizes .= "{$imgTagWidth}px";
280*37748cd8SNickeau                }
281*37748cd8SNickeau
282*37748cd8SNickeau                /**
283*37748cd8SNickeau                 * Lazy load
284*37748cd8SNickeau                 */
285*37748cd8SNickeau                $lazyLoad = $this->getLazyLoad();
286*37748cd8SNickeau                if ($lazyLoad) {
287*37748cd8SNickeau
288*37748cd8SNickeau                    /**
289*37748cd8SNickeau                     * Snippet Lazy loading
290*37748cd8SNickeau                     */
291*37748cd8SNickeau                    LazyLoad::addLozadSnippet();
292*37748cd8SNickeau                    PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("lozad-raster");
293*37748cd8SNickeau                    $this->tagAttributes->addClassName(self::LAZY_CLASS);
294*37748cd8SNickeau                    $this->tagAttributes->addClassName(LazyLoad::LAZY_CLASS);
295*37748cd8SNickeau
296*37748cd8SNickeau                    /**
297*37748cd8SNickeau                     * A small image has no srcset
298*37748cd8SNickeau                     *
299*37748cd8SNickeau                     */
300*37748cd8SNickeau                    if (!empty($srcSet)) {
301*37748cd8SNickeau
302*37748cd8SNickeau                        /**
303*37748cd8SNickeau                         * !!!!! DON'T FOLLOW THIS ADVICE !!!!!!!!!
304*37748cd8SNickeau                         * https://github.com/aFarkas/lazysizes/#modern-transparent-srcset-pattern
305*37748cd8SNickeau                         * The transparent image has a fix dimension aspect ratio of 1x1 making
306*37748cd8SNickeau                         * a bad reserved space for the image
307*37748cd8SNickeau                         * We use a svg instead
308*37748cd8SNickeau                         */
309*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("src", $srcValue);
310*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("srcset", LazyLoad::getPlaceholder($imgTagWidth,$imgTagHeight));
311*37748cd8SNickeau                        /**
312*37748cd8SNickeau                         * We use `data-sizes` and not `sizes`
313*37748cd8SNickeau                         * because `sizes` without `srcset`
314*37748cd8SNickeau                         * shows the broken image symbol
315*37748cd8SNickeau                         * Javascript changes them at the same time
316*37748cd8SNickeau                         */
317*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("data-sizes", $sizes);
318*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("data-srcset", $srcSet);
319*37748cd8SNickeau
320*37748cd8SNickeau                    } else {
321*37748cd8SNickeau
322*37748cd8SNickeau                        /**
323*37748cd8SNickeau                         * Small image but there is no little improvement
324*37748cd8SNickeau                         */
325*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("data-src", $srcValue);
326*37748cd8SNickeau
327*37748cd8SNickeau                    }
328*37748cd8SNickeau
329*37748cd8SNickeau                    LazyLoad::addPlaceholderBackground($this->tagAttributes);
330*37748cd8SNickeau
331*37748cd8SNickeau
332*37748cd8SNickeau                } else {
333*37748cd8SNickeau
334*37748cd8SNickeau                    if (!empty($srcSet)) {
335*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("srcset", $srcSet);
336*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("sizes", $sizes);
337*37748cd8SNickeau                    } else {
338*37748cd8SNickeau                        $this->tagAttributes->addHtmlAttributeValue("src", $srcValue);
339*37748cd8SNickeau                    }
340*37748cd8SNickeau
341*37748cd8SNickeau                }
342*37748cd8SNickeau
343*37748cd8SNickeau            } else {
344*37748cd8SNickeau
345*37748cd8SNickeau                // No width, no responsive possibility
346*37748cd8SNickeau                $lazyLoad = $this->getLazyLoad();
347*37748cd8SNickeau                if ($lazyLoad) {
348*37748cd8SNickeau
349*37748cd8SNickeau                    LazyLoad::addPlaceholderBackground($this->tagAttributes);
350*37748cd8SNickeau                    $this->tagAttributes->addHtmlAttributeValue("src", LazyLoad::getPlaceholder());
351*37748cd8SNickeau                    $this->tagAttributes->addHtmlAttributeValue("data-src", $srcValue);
352*37748cd8SNickeau
353*37748cd8SNickeau                }
354*37748cd8SNickeau
355*37748cd8SNickeau            }
356*37748cd8SNickeau
357*37748cd8SNickeau
358*37748cd8SNickeau            /**
359*37748cd8SNickeau             * Title (ie alt)
360*37748cd8SNickeau             */
361*37748cd8SNickeau            if ($this->tagAttributes->hasComponentAttribute(TagAttributes::TITLE_KEY)) {
362*37748cd8SNickeau                $title = $this->tagAttributes->getValueAndRemove(TagAttributes::TITLE_KEY);
363*37748cd8SNickeau                $this->tagAttributes->addHtmlAttributeValueIfNotEmpty("alt", $title);
364*37748cd8SNickeau            }
365*37748cd8SNickeau
366*37748cd8SNickeau            /**
367*37748cd8SNickeau             * Create the img element
368*37748cd8SNickeau             */
369*37748cd8SNickeau            $htmlAttributes = $this->tagAttributes->toHTMLAttributeString();
370*37748cd8SNickeau            $imgHTML = '<img ' . $htmlAttributes . '/>';
371*37748cd8SNickeau
372*37748cd8SNickeau        } else {
373*37748cd8SNickeau
374*37748cd8SNickeau            $imgHTML = "<span class=\"text-danger\">The image ($this) does not exist</span>";
375*37748cd8SNickeau
376*37748cd8SNickeau        }
377*37748cd8SNickeau
378*37748cd8SNickeau        return $imgHTML;
379*37748cd8SNickeau    }
380*37748cd8SNickeau
381*37748cd8SNickeau    /**
382*37748cd8SNickeau     * @return int - the width of the image from the file
383*37748cd8SNickeau     */
384*37748cd8SNickeau    public
385*37748cd8SNickeau    function getMediaWidth()
386*37748cd8SNickeau    {
387*37748cd8SNickeau        $this->analyzeImageIfNeeded();
388*37748cd8SNickeau        return $this->imageWidth;
389*37748cd8SNickeau    }
390*37748cd8SNickeau
391*37748cd8SNickeau    /**
392*37748cd8SNickeau     * @return int - the height of the image from the file
393*37748cd8SNickeau     */
394*37748cd8SNickeau    public
395*37748cd8SNickeau    function getMediaHeight()
396*37748cd8SNickeau    {
397*37748cd8SNickeau        $this->analyzeImageIfNeeded();
398*37748cd8SNickeau        return $this->imageWeight;
399*37748cd8SNickeau    }
400*37748cd8SNickeau
401*37748cd8SNickeau    private
402*37748cd8SNickeau    function analyzeImageIfNeeded()
403*37748cd8SNickeau    {
404*37748cd8SNickeau
405*37748cd8SNickeau        if (!$this->wasAnalyzed) {
406*37748cd8SNickeau
407*37748cd8SNickeau            if ($this->exists()) {
408*37748cd8SNickeau
409*37748cd8SNickeau                /**
410*37748cd8SNickeau                 * Based on {@link media_image_preview_size()}
411*37748cd8SNickeau                 * $dimensions = media_image_preview_size($this->id, '', false);
412*37748cd8SNickeau                 */
413*37748cd8SNickeau                $imageInfo = array();
414*37748cd8SNickeau                $imageSize = getimagesize($this->getFileSystemPath(), $imageInfo);
415*37748cd8SNickeau                if ($imageSize === false) {
416*37748cd8SNickeau                    $this->analyzable = false;
417*37748cd8SNickeau                    LogUtility::msg("We couldn't retrieve the type and dimensions of the image ($this). The image format seems to be not supported.", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
418*37748cd8SNickeau                } else {
419*37748cd8SNickeau                    $this->analyzable = true;
420*37748cd8SNickeau                    $this->imageWidth = (int)$imageSize[0];
421*37748cd8SNickeau                    if (empty($this->imageWidth)) {
422*37748cd8SNickeau                        $this->analyzable = false;
423*37748cd8SNickeau                    }
424*37748cd8SNickeau                    $this->imageWeight = (int)$imageSize[1];
425*37748cd8SNickeau                    if (empty($this->imageWeight)) {
426*37748cd8SNickeau                        $this->analyzable = false;
427*37748cd8SNickeau                    }
428*37748cd8SNickeau                    $this->imageType = (int)$imageSize[2];
429*37748cd8SNickeau                    $this->mime = $imageSize[3];
430*37748cd8SNickeau                }
431*37748cd8SNickeau            }
432*37748cd8SNickeau        }
433*37748cd8SNickeau        $this->wasAnalyzed = true;
434*37748cd8SNickeau    }
435*37748cd8SNickeau
436*37748cd8SNickeau
437*37748cd8SNickeau    /**
438*37748cd8SNickeau     *
439*37748cd8SNickeau     * @return bool true if we could extract the dimensions
440*37748cd8SNickeau     */
441*37748cd8SNickeau    public
442*37748cd8SNickeau    function isAnalyzable()
443*37748cd8SNickeau    {
444*37748cd8SNickeau        $this->analyzeImageIfNeeded();
445*37748cd8SNickeau        return $this->analyzable;
446*37748cd8SNickeau
447*37748cd8SNickeau    }
448*37748cd8SNickeau
449*37748cd8SNickeau
450*37748cd8SNickeau    public function getRequestedHeight()
451*37748cd8SNickeau    {
452*37748cd8SNickeau        $requestedHeight = parent::getRequestedHeight();
453*37748cd8SNickeau        if (!empty($requestedHeight)) {
454*37748cd8SNickeau            // it should not be bigger than the media Height
455*37748cd8SNickeau            $mediaHeight = $this->getMediaHeight();
456*37748cd8SNickeau            if (!empty($mediaHeight)) {
457*37748cd8SNickeau                if ($requestedHeight > $mediaHeight) {
458*37748cd8SNickeau                    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);
459*37748cd8SNickeau                    $requestedHeight = $mediaHeight;
460*37748cd8SNickeau                }
461*37748cd8SNickeau            }
462*37748cd8SNickeau        }
463*37748cd8SNickeau        return $requestedHeight;
464*37748cd8SNickeau    }
465*37748cd8SNickeau
466*37748cd8SNickeau    public function getRequestedWidth()
467*37748cd8SNickeau    {
468*37748cd8SNickeau        $requestedWidth = parent::getRequestedWidth();
469*37748cd8SNickeau        if (!empty($requestedWidth)) {
470*37748cd8SNickeau            // it should not be bigger than the media Height
471*37748cd8SNickeau            $mediaWidth = $this->getMediaWidth();
472*37748cd8SNickeau            if (!empty($mediaWidth)) {
473*37748cd8SNickeau                if ($requestedWidth > $mediaWidth) {
474*37748cd8SNickeau                    global $ID;
475*37748cd8SNickeau                    if ($ID != "wiki:syntax") {
476*37748cd8SNickeau                        // There is a bug in the wiki syntax page
477*37748cd8SNickeau                        // {{wiki:dokuwiki-128.png?200x50}}
478*37748cd8SNickeau                        // https://forum.dokuwiki.org/d/19313-bugtypo-how-to-make-a-request-to-change-the-syntax-page-on-dokuwikii
479*37748cd8SNickeau                        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);
480*37748cd8SNickeau                    }
481*37748cd8SNickeau                    $requestedWidth = $mediaWidth;
482*37748cd8SNickeau                }
483*37748cd8SNickeau            }
484*37748cd8SNickeau        }
485*37748cd8SNickeau        return $requestedWidth;
486*37748cd8SNickeau    }
487*37748cd8SNickeau
488*37748cd8SNickeau
489*37748cd8SNickeau    public
490*37748cd8SNickeau    function getLazyLoad()
491*37748cd8SNickeau    {
492*37748cd8SNickeau        $lazyLoad = parent::getLazyLoad();
493*37748cd8SNickeau        if ($lazyLoad !== null) {
494*37748cd8SNickeau            return $lazyLoad;
495*37748cd8SNickeau        } else {
496*37748cd8SNickeau            return PluginUtility::getConfValue(RasterImageLink::CONF_LAZY_LOADING_ENABLE);
497*37748cd8SNickeau        }
498*37748cd8SNickeau    }
499*37748cd8SNickeau
500*37748cd8SNickeau    /**
501*37748cd8SNickeau     * @param $screenWidth
502*37748cd8SNickeau     * @param $imageWidth
503*37748cd8SNickeau     * @return string sizes with a dpi correction if
504*37748cd8SNickeau     */
505*37748cd8SNickeau    private
506*37748cd8SNickeau    function getSizes($screenWidth, $imageWidth)
507*37748cd8SNickeau    {
508*37748cd8SNickeau
509*37748cd8SNickeau        if ($this->getWithDpiCorrection()) {
510*37748cd8SNickeau            $dpiBase = 96;
511*37748cd8SNickeau            $sizes = "(max-width: {$screenWidth}px) and (min-resolution:" . (3 * $dpiBase) . "dpi) " . intval($imageWidth / 3) . "px";
512*37748cd8SNickeau            $sizes .= ", (max-width: {$screenWidth}px) and (min-resolution:" . (2 * $dpiBase) . "dpi) " . intval($imageWidth / 2) . "px";
513*37748cd8SNickeau            $sizes .= ", (max-width: {$screenWidth}px) and (min-resolution:" . (1 * $dpiBase) . "dpi) {$imageWidth}px";
514*37748cd8SNickeau        } else {
515*37748cd8SNickeau            $sizes = "(max-width: {$screenWidth}px) {$imageWidth}px";
516*37748cd8SNickeau        }
517*37748cd8SNickeau        return $sizes;
518*37748cd8SNickeau    }
519*37748cd8SNickeau
520*37748cd8SNickeau    /**
521*37748cd8SNickeau     * Return if the DPI correction is enabled or not for responsive image
522*37748cd8SNickeau     *
523*37748cd8SNickeau     * Mobile have a higher DPI and can then fit a bigger image on a smaller size.
524*37748cd8SNickeau     *
525*37748cd8SNickeau     * This can be disturbing when debugging responsive sizing image
526*37748cd8SNickeau     * If you want also to use less bandwidth, this is also useful.
527*37748cd8SNickeau     *
528*37748cd8SNickeau     * @return bool
529*37748cd8SNickeau     */
530*37748cd8SNickeau    private
531*37748cd8SNickeau    function getWithDpiCorrection()
532*37748cd8SNickeau    {
533*37748cd8SNickeau        /**
534*37748cd8SNickeau         * Support for retina means no DPI correction
535*37748cd8SNickeau         */
536*37748cd8SNickeau        $retinaEnabled = PluginUtility::getConfValue(self::CONF_RETINA_SUPPORT_ENABLED, 0);
537*37748cd8SNickeau        return !$retinaEnabled;
538*37748cd8SNickeau    }
539*37748cd8SNickeau
540*37748cd8SNickeau
541*37748cd8SNickeau}
542