diff --git a/system/src/Grav/Common/Page/Media.php b/system/src/Grav/Common/Page/Media.php index c8385ea15..c4451e08c 100644 --- a/system/src/Grav/Common/Page/Media.php +++ b/system/src/Grav/Common/Page/Media.php @@ -74,16 +74,13 @@ class Media extends Getters } // Create the base medium - if (!empty($types['base'])) { + if (empty($types['base'])) { + $max = max(array_keys($types['alternative'])); + $medium = $types['alternative'][$max]['file']; + $medium = MediumFactory::scaledFromMedium($medium, $max, 1)['file']; + } else { $medium = MediumFactory::fromFile($types['base']['file']); $medium && $medium->set('size', $types['base']['size']); - } else if (!empty($types['alternative'])) { - $altMedium = reset($types['alternative']); - $ratio = key($types['alternative']); - - $altMedium = $altMedium['file']; - - $medium = MediumFactory::scaledFromMedium($altMedium, $ratio, 1)['file']; } if (empty($medium)) { @@ -103,10 +100,9 @@ class Media extends Getters // Build missing alternatives if (!empty($types['alternative'])) { $alternatives = $types['alternative']; - $max = max(array_keys($alternatives)); - for ($i=2; $i < $max; $i++) { + for ($i=$max; $i > 1; $i--) { if (isset($alternatives[$i])) { continue; } @@ -115,7 +111,9 @@ class Media extends Getters } foreach ($types['alternative'] as $ratio => $altMedium) { - $medium->addAlternative($ratio, $altMedium['file']); + if ($altMedium['file'] != $medium) { + $medium->addAlternative($ratio, $altMedium['file']); + } } } diff --git a/system/src/Grav/Common/Page/Medium/ImageMedium.php b/system/src/Grav/Common/Page/Medium/ImageMedium.php index e3900baef..a2bb7b169 100644 --- a/system/src/Grav/Common/Page/Medium/ImageMedium.php +++ b/system/src/Grav/Common/Page/Medium/ImageMedium.php @@ -65,11 +65,6 @@ class ImageMedium extends Medium 'zoomCrop' => [0, 1] ]; - /** - * @var array - */ - protected $derivatives = []; - /** * @var string */ @@ -197,27 +192,19 @@ class ImageMedium extends Medium */ public function srcset($reset = true) { - if (empty($this->alternatives) && empty($this->derivatives)) { + if (empty($this->alternatives)) { if ($reset) { $this->reset(); } + return ''; } - if (!empty($this->derivatives)) { - asort($this->derivatives); - - foreach ($this->derivatives as $url => $width) { - $srcset[] = $url . ' ' . $width . 'w'; - } - - $srcset[] = $this->url($reset) . ' ' . $this->get('width') . 'w'; - } else { - $srcset = [$this->url($reset) . ' ' . $this->get('width') . 'w']; - foreach ($this->alternatives as $ratio => $medium) { - $srcset[] = $medium->url($reset) . ' ' . $medium->get('width') . 'w'; - } + $srcset = []; + foreach ($this->alternatives as $ratio => $medium) { + $srcset[] = $medium->url($reset) . ' ' . $medium->get('width') . 'w'; } + $srcset[] = $this->url($reset) . ' ' . $this->get('width') . 'w'; return implode(', ', $srcset); } @@ -257,31 +244,53 @@ class ImageMedium extends Medium * @return $this */ public function derivatives($min_width, $max_width, $step = 200) { - $width = $min_width; - - // Do not upscale images. - if ($max_width > $this->get('width')) { - $max_width = $this->get('width'); - } - - while ($width <= $max_width) { - $ratio = $width / $this->get('width'); - $derivative = MediumFactory::scaledFromMedium($this, 1, $ratio); - if (is_array($derivative)) { - $this->addDerivative($derivative['file']); + if (!empty($this->alternatives)) { + $max = max(array_keys($this->alternatives)); + $base = $this->alternatives[$max]; + } else { + $base = $this; } - $width += $step; - } - return $this; - } - /** - * Add a derivative - * - * @param ImageMedium $image - */ - public function addDerivative(ImageMedium $image) { - $this->derivatives[$image->url()] = $image->get('width'); + // Do not upscale images. + $max_width = min($max_width, $base->get('width')); + + for ($width = $min_width; $width < $max_width; $width = $width + $step) { + // Only generate image alternatives that don't already exist + if (array_key_exists((int) $width, $this->alternatives)) { + continue; + } + + $derivative = MediumFactory::fromFile($base->get('filepath')); + + // It's possible that MediumFactory::fromFile returns null if the + // original image file no longer exists and this class instance was + // retrieved from the page cache + if (isset($derivative)) { + $index = 2; + $widths = array_keys($this->alternatives); + sort($widths); + + foreach ($widths as $i => $key) { + if ($width > $key) { + $index += max($i, 1); + } + } + + $basename = preg_replace('/(@\d+x){0,1}$/', "@{$width}w", $base->get('basename'), 1); + $derivative->setImagePrettyName($basename); + + $ratio = $base->get('width') / $width; + $height = $derivative->get('height') / $ratio; + + $derivative->resize($width, $height); + $derivative->set('width', $width); + $derivative->set('height', $height); + + $this->addAlternative($ratio, $derivative); + } + } + + return $this; } /** @@ -489,6 +498,10 @@ class ImageMedium extends Medium call_user_func_array([$this->image, $method], $args); foreach ($this->alternatives as $ratio => $medium) { + if (!$medium->image) { + $medium->image(); + } + $args_copy = $args; // regular image: resize 400x400 -> 200x200 diff --git a/system/src/Grav/Common/Page/Medium/Medium.php b/system/src/Grav/Common/Page/Medium/Medium.php index b13306f52..b9e338854 100644 --- a/system/src/Grav/Common/Page/Medium/Medium.php +++ b/system/src/Grav/Common/Page/Medium/Medium.php @@ -100,7 +100,9 @@ class Medium extends Data implements RenderableInterface } $alternative->set('ratio', $ratio); - $this->alternatives[(float) $ratio] = $alternative; + $width = $alternative->get('width'); + + $this->alternatives[$width] = $alternative; } /** diff --git a/system/src/Grav/Common/Page/Medium/MediumFactory.php b/system/src/Grav/Common/Page/Medium/MediumFactory.php index c75044f5c..3743a81cf 100644 --- a/system/src/Grav/Common/Page/Medium/MediumFactory.php +++ b/system/src/Grav/Common/Page/Medium/MediumFactory.php @@ -119,8 +119,8 @@ class MediumFactory } $ratio = $to / $from; - $width = (int) ($medium->get('width') * $ratio); - $height = (int) ($medium->get('height') * $ratio); + $width = $medium->get('width') * $ratio; + $height = $medium->get('height') * $ratio; $prev_basename = $medium->get('basename'); $basename = str_replace('@'.$from.'x', '@'.$to.'x', $prev_basename);