diff --git a/system/src/Grav/Common/Media/Interfaces/MediaCollectionInterface.php b/system/src/Grav/Common/Media/Interfaces/MediaCollectionInterface.php index a971e0fae..6162746f5 100644 --- a/system/src/Grav/Common/Media/Interfaces/MediaCollectionInterface.php +++ b/system/src/Grav/Common/Media/Interfaces/MediaCollectionInterface.php @@ -109,12 +109,6 @@ interface MediaCollectionInterface extends \Grav\Framework\Media\Interfaces\Medi */ public function createFromArray(array $items = [], Blueprint $blueprint = null): ?MediaObjectInterface; - /** - * @param MediaObjectInterface $mediaObject - * @return ImageFile - */ - public function getImageFileObject(MediaObjectInterface $mediaObject): ImageFile; - /** * @param string $filepath * @return string diff --git a/system/src/Grav/Common/Media/Interfaces/MediaFileInterface.php b/system/src/Grav/Common/Media/Interfaces/MediaFileInterface.php index c20e4de99..53fbe3b11 100644 --- a/system/src/Grav/Common/Media/Interfaces/MediaFileInterface.php +++ b/system/src/Grav/Common/Media/Interfaces/MediaFileInterface.php @@ -50,4 +50,16 @@ interface MediaFileInterface extends MediaObjectInterface * @return mixed */ public function relativePath($reset = true); + + /** + * @return string + * @throws \RuntimeException + */ + public function readFile(): string; + + /** + * @return resource + * @throws \RuntimeException + */ + public function readStream(); } diff --git a/system/src/Grav/Common/Media/Traits/ImageMediaTrait.php b/system/src/Grav/Common/Media/Traits/ImageMediaTrait.php index 3959fb05f..50e23db3e 100644 --- a/system/src/Grav/Common/Media/Traits/ImageMediaTrait.php +++ b/system/src/Grav/Common/Media/Traits/ImageMediaTrait.php @@ -12,7 +12,6 @@ namespace Grav\Common\Media\Traits; use Grav\Common\Config\Config; use Grav\Common\Grav; use Grav\Common\Media\Interfaces\ImageMediaInterface; -use Grav\Common\Media\Interfaces\MediaCollectionInterface; use Grav\Common\Page\Medium\ImageFile; use Grav\Common\Page\Medium\ImageMedium; use Grav\Common\Page\Medium\MediumFactory; @@ -351,14 +350,7 @@ trait ImageMediaTrait // Make sure we free previous image. unset($this->image); - /** @var MediaCollectionInterface $media */ - $media = $this->get('media'); - if ($media && method_exists($media, 'getImageFileObject')) { - $this->image = $media->getImageFileObject($this); - } else { - $this->image = ImageFile::open($this->get('filepath')); - } - + $this->image = ImageFile::fromData($this->readFile()); $this->image ->setCacheDir($cacheDir) ->setActualCacheDir($cacheDir) diff --git a/system/src/Grav/Common/Page/Medium/AbstractMedia.php b/system/src/Grav/Common/Page/Medium/AbstractMedia.php index 9b25ce978..51a707c23 100644 --- a/system/src/Grav/Common/Page/Medium/AbstractMedia.php +++ b/system/src/Grav/Common/Page/Medium/AbstractMedia.php @@ -56,8 +56,8 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac protected $path; /** @var string|null */ protected $url; - /** @var array */ - protected $index = []; + /** @var array|null */ + protected $index; /** @var MediaObjectInterface[] */ protected $items = []; /** @var array|null */ @@ -242,6 +242,16 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac */ abstract public function createFromFile($filename, array $params = []): ?MediaObjectInterface; + /** + * Create a new ImageMedium by scaling another ImageMedium object. + * + * @param MediaObjectInterface $medium + * @param int $from + * @param int $to + * @return MediaObjectInterface + */ + abstract public function scaledFromMedium(MediaObjectInterface $medium, int $from, int $to = 1): MediaObjectInterface; + /** * Create Medium from array of parameters * @@ -251,12 +261,6 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac */ abstract public function createFromArray(array $items = [], Blueprint $blueprint = null): ?MediaObjectInterface; - /** - * @param MediaObjectInterface $mediaObject - * @return ImageFile - */ - abstract public function getImageFileObject(MediaObjectInterface $mediaObject): ImageFile; - /** * @return array */ @@ -264,8 +268,7 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac { return [ 'version' => static::VERSION, - 'index' => $this->index, - 'items' => $this->items, + 'index' => $this->index ?? [], 'path' => $this->path, 'url' => $this->url, 'media_order' => $this->media_order, @@ -291,10 +294,8 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac $this->media_order = $data['media_order']; $this->standard_exif = $data['standard_exif']; $this->indexTimeout = $data['indexTimeout']; - $items = $data['items']; - foreach ($items as $name => $item) { - $this->add($name, $item); - } + + $this->init(); } /** @@ -509,18 +510,20 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac $config = $this->getConfig(); // Get file media listing. Use cached version if possible to avoid I/O. - $now = time(); - [$files, $timestamp] = $this->loadIndex(); - $timeout = $this->indexTimeout; - if (!$timestamp || ($timeout && $timestamp < $now - $timeout)) { - $media_types = $config->get('media.types'); - $files = $this->prepareFileInfo($this->loadFileInfo(), $media_types, $files); + if (null === $this->index) { + $now = time(); + [$files, $timestamp] = $this->loadIndex(); + $timeout = $this->indexTimeout; + if (!$timestamp || ($timeout && $timestamp < $now - $timeout)) { + $media_types = $config->get('media.types'); + $files = $this->prepareFileInfo($this->loadFileInfo(), $media_types, $files); - $this->saveIndex($files, $now); + $this->saveIndex($files, $now); + } + + $this->index = $files; } - $this->index = $files; - // Group images by base name. $media = []; foreach ($files as $filename => $info) { @@ -542,8 +545,8 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac } } - // Prepare the alternatives in case there is no base medium. foreach ($media as $name => $types) { + // Prepare the alternatives in case there is no base medium. if (!empty($types['alternative'])) { /** * @var string|int $ratio @@ -568,7 +571,7 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac $max = max(array_keys($types['alternative'])); $medium = $types['alternative'][$max]['file']; $file_path = $medium->path(); - $medium = MediumFactory::scaledFromMedium($medium, $max, 1)['file']; + $medium = $this->scaledFromMedium($medium, $max); } else { $medium = $this->createFromFile($types['base']['file']); if ($medium) { @@ -577,10 +580,6 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac } } - if (empty($medium)) { - continue; - } - if ($file_path) { $meta_path = $file_path . '.meta.yaml'; if (file_exists($meta_path)) { @@ -620,11 +619,9 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac $max = max(array_keys($alternatives)); for ($i=$max; $i > 1; $i--) { - if (isset($alternatives[$i])) { - continue; + if (!isset($alternatives[$i])) { + $types['alternative'][$i] = $this->scaledFromMedium($alternatives[$max]['file'], $max, $i); } - - $types['alternative'][$i] = MediumFactory::scaledFromMedium($alternatives[$max]['file'], $max, $i); } foreach ($types['alternative'] as $altMedium) { diff --git a/system/src/Grav/Common/Page/Medium/ImageFile.php b/system/src/Grav/Common/Page/Medium/ImageFile.php index 1aae7eeb6..aa5e09a8d 100644 --- a/system/src/Grav/Common/Page/Medium/ImageFile.php +++ b/system/src/Grav/Common/Page/Medium/ImageFile.php @@ -175,11 +175,16 @@ class ImageFile extends Image */ public function fixOrientation() { + $info = $this->source->getInfos(); + if (!\is_string($info) || !file_exists($info)) { + return $this; + } + if (!extension_loaded('exif')) { throw new RuntimeException('You need to EXIF PHP Extension to use this function'); } - if (!in_array(exif_imagetype($this->source->getInfos()), [IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM], true)) { + if (!in_array(exif_imagetype($info), [IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM], true)) { return $this; } @@ -188,7 +193,7 @@ class ImageFile extends Image $locator = Grav::instance()['locator']; $filepath = $this->source->getInfos(); if ($locator->isStream($filepath)) { - $filepath = $locator->findResource($this->source->getInfos(), true, true); + $filepath = $locator->findResource($info, true, true); } // Make sure file exists diff --git a/system/src/Grav/Common/Page/Medium/ImageMedium.php b/system/src/Grav/Common/Page/Medium/ImageMedium.php index 8d84f9551..7061b6aec 100644 --- a/system/src/Grav/Common/Page/Medium/ImageMedium.php +++ b/system/src/Grav/Common/Page/Medium/ImageMedium.php @@ -17,7 +17,6 @@ use Grav\Common\Media\Interfaces\MediaLinkInterface; use Grav\Common\Media\Traits\ImageLoadingTrait; use Grav\Common\Media\Traits\ImageMediaTrait; use Grav\Common\Utils; -use Gregwar\Image\Image; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use function array_key_exists; use function func_get_args; @@ -54,13 +53,10 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate $this->def('debug', $config->get('system.images.debug')); $path = $this->get('filepath'); - if (!$path || !file_exists($path) || !filesize($path)) { - return; - } - $this->set('thumbnails.media', $path); - if (!($this->offsetExists('width') && $this->offsetExists('height') && $this->offsetExists('mime'))) { + $exists = $path && file_exists($path) && filesize($path); + if ($exists && !($this->offsetExists('width') && $this->offsetExists('height') && $this->offsetExists('mime'))) { $image_info = getimagesize($path); if ($image_info) { $this->def('width', $image_info[0]); @@ -223,7 +219,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate } $srcset = []; - foreach ($this->alternatives as $ratio => $medium) { + foreach ($this->alternatives as $medium) { $srcset[] = $medium->url($reset) . ' ' . $medium->get('width') . 'w'; } $srcset[] = str_replace(' ', '%20', $this->url($reset)) . ' ' . $this->get('width') . 'w'; @@ -315,7 +311,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate */ public function autoSizes($enabled = 'true') { - $this->auto_sizes = $enabled === 'true' ?: false; + $this->auto_sizes = $enabled === 'true'; return $this; } @@ -326,7 +322,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate */ public function aspectRatio($enabled = 'true') { - $this->aspect_ratio = $enabled === 'true' ?: false; + $this->aspect_ratio = $enabled === 'true'; return $this; } @@ -429,7 +425,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate public function addFrame(int $border = 10, string $color = '0x000000') { if($border > 0 && preg_match('/^0x[a-f0-9]{6}$/i', $color)) { // $border must be an integer and bigger than 0; $color must be formatted as an HEX value (0x??????). - $image = ImageFile::open($this->path()); + $image = ImageFile::fromData($this->readFile()); } else { return $this; diff --git a/system/src/Grav/Common/Page/Medium/Link.php b/system/src/Grav/Common/Page/Medium/Link.php index c76d8c191..fce2d2e7d 100644 --- a/system/src/Grav/Common/Page/Medium/Link.php +++ b/system/src/Grav/Common/Page/Medium/Link.php @@ -40,7 +40,7 @@ class Link implements RenderableInterface, MediaLinkInterface { $this->attributes = $attributes; - $source = $medium->reset()->thumbnail('auto')->display('thumbnail'); + $source = $medium->reset()->thumbnail()->display('thumbnail'); if (!$source instanceof MediaObjectInterface) { throw new RuntimeException('Media has no thumbnail set'); } diff --git a/system/src/Grav/Common/Page/Medium/LocalMedia.php b/system/src/Grav/Common/Page/Medium/LocalMedia.php index d7056bbad..bf1b99236 100644 --- a/system/src/Grav/Common/Page/Medium/LocalMedia.php +++ b/system/src/Grav/Common/Page/Medium/LocalMedia.php @@ -109,14 +109,18 @@ abstract class LocalMedia extends AbstractMedia } /** - * @param MediaObjectInterface $mediaObject - * @return ImageFile + * Create a new ImageMedium by scaling another ImageMedium object. + * + * @param MediaObjectInterface $medium + * @param int $from + * @param int $to + * @return MediaObjectInterface */ - public function getImageFileObject(MediaObjectInterface $mediaObject): ImageFile + public function scaledFromMedium(MediaObjectInterface $medium, int $from, int $to = 1): MediaObjectInterface { - $filepath = $mediaObject->get('filepath'); + $result = MediumFactory::scaledFromMedium($medium, $from, $to); - return ImageFile::open($filepath); + return is_array($result) ? $result['file'] : $result; } /** diff --git a/system/src/Grav/Common/Page/Medium/Medium.php b/system/src/Grav/Common/Page/Medium/Medium.php index f39611dee..9ccc881e0 100644 --- a/system/src/Grav/Common/Page/Medium/Medium.php +++ b/system/src/Grav/Common/Page/Medium/Medium.php @@ -13,10 +13,13 @@ use Grav\Common\File\CompiledYamlFile; use Grav\Common\Grav; use Grav\Common\Data\Data; use Grav\Common\Data\Blueprint; +use Grav\Common\Media\Interfaces\MediaCollectionInterface; use Grav\Common\Media\Interfaces\MediaFileInterface; use Grav\Common\Media\Interfaces\MediaLinkInterface; +use Grav\Common\Media\Interfaces\MediaObjectInterface; use Grav\Common\Media\Traits\MediaFileTrait; use Grav\Common\Media\Traits\MediaObjectTrait; +use RuntimeException; /** * Class Medium @@ -45,29 +48,23 @@ class Medium extends Data implements RenderableInterface, MediaFileInterface */ public function __construct($items = [], Blueprint $blueprint = null) { + $items += ['mime' => 'application/octet-stream']; + $size = $items['size'] ?? null; + $modified = $items['modified'] ?? null; + if (null === $size || null === $modified) { + $path = $items['filepath']; + if ($path && file_exists($path)) { + $items['size'] = $size ?? filesize($path); + $items['modified'] = $modified ?? filemtime($path); + } + } + parent::__construct($items, $blueprint); if (Grav::instance()['config']->get('system.media.enable_media_timestamp', true)) { $this->timestamp = Grav::instance()['cache']->getKey(); } - $this->def('mime', 'application/octet-stream'); - - $sizeMissing = !$this->offsetExists('size'); - $modifiedMissing = !$this->offsetExists('modified'); - if ($sizeMissing || $modifiedMissing) { - $path = $this->get('filepath'); - if ($path && file_exists($path)) { - if ($sizeMissing) { - $this->set('size', filesize($path)); - } - if ($modifiedMissing) { - $this->set('modified', filemtime($path)); - } - } - - } - $this->reset(); } @@ -80,6 +77,24 @@ class Medium extends Data implements RenderableInterface, MediaFileInterface // Allows future compatibility as parent::__clone() works. } + /** + * @return string + * @throws RuntimeException + */ + public function readFile(): string + { + return $this->getMedia()->readFile($this->filepath); + } + + /** + * @return resource + * @throws RuntimeException + */ + public function readStream() + { + return $this->getMedia()->readStream($this->filepath); + } + /** * Add meta file for the medium. * @@ -116,11 +131,11 @@ class Medium extends Data implements RenderableInterface, MediaFileInterface /** * @param string $thumb - * @return Medium|null + * @return MediaObjectInterface|null */ protected function createThumbnail($thumb) { - return MediumFactory::fromFile($thumb, ['type' => 'thumbnail']); + return $this->getMedia()->createFromFile($thumb, ['type' => 'thumbnail']); } /** @@ -132,6 +147,14 @@ class Medium extends Data implements RenderableInterface, MediaFileInterface return new Link($attributes, $this); } + /** + * @return MediaCollectionInterface + */ + protected function getMedia(): MediaCollectionInterface + { + return $this->get('media', GlobalMedia::getInstance()); + } + /** * @return Grav */