vendor/pimcore/pimcore/models/Asset/Thumbnail/ImageThumbnailTrait.php line 102

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\Asset\Thumbnail;
  15. use Pimcore\Helper\TemporaryFileHelperTrait;
  16. use Pimcore\Model\Asset;
  17. use Pimcore\Model\Asset\Image;
  18. use Pimcore\Model\Asset\Image\Thumbnail\Config;
  19. use Pimcore\Tool;
  20. use Pimcore\Tool\Storage;
  21. use Symfony\Component\Mime\MimeTypes;
  22. trait ImageThumbnailTrait
  23. {
  24.     use TemporaryFileHelperTrait;
  25.     /**
  26.      * @internal
  27.      *
  28.      * @var Asset|null
  29.      */
  30.     protected $asset;
  31.     /**
  32.      * @internal
  33.      *
  34.      * @var Config|null
  35.      */
  36.     protected $config;
  37.     /**
  38.      * @internal
  39.      *
  40.      * @var array
  41.      */
  42.     protected array $pathReference = [];
  43.     /**
  44.      * @internal
  45.      *
  46.      * @var int|null
  47.      */
  48.     protected $width;
  49.     /**
  50.      * @internal
  51.      *
  52.      * @var int|null
  53.      */
  54.     protected $height;
  55.     /**
  56.      * @internal
  57.      *
  58.      * @var int|null
  59.      */
  60.     protected $realWidth;
  61.     /**
  62.      * @internal
  63.      *
  64.      * @var int|null
  65.      */
  66.     protected $realHeight;
  67.     /**
  68.      * @internal
  69.      *
  70.      * @var string
  71.      */
  72.     protected $mimetype;
  73.     /**
  74.      * @internal
  75.      *
  76.      * @var bool
  77.      */
  78.     protected $deferred true;
  79.     private static array $supportedFormats = [];
  80.     /**
  81.      * @return null|resource
  82.      */
  83.     public function getStream()
  84.     {
  85.         $pathReference $this->getPathReference(false);
  86.         if ($pathReference['type'] === 'asset') {
  87.             return $this->asset->getStream();
  88.         } elseif (isset($pathReference['storagePath'])) {
  89.             return Tool\Storage::get('thumbnail')->readStream($pathReference['storagePath']);
  90.         }
  91.         return null;
  92.     }
  93.     public function getPathReference(bool $deferredAllowed false): array
  94.     {
  95.         if (!$deferredAllowed && (($this->pathReference['type'] ?? '') === 'deferred')) {
  96.             $this->pathReference = [];
  97.         }
  98.         if (empty($this->pathReference)) {
  99.             $this->generate($deferredAllowed);
  100.         }
  101.         return $this->pathReference;
  102.     }
  103.     /**
  104.      * @internal
  105.      */
  106.     public function reset()
  107.     {
  108.         $this->pathReference = [];
  109.         $this->width null;
  110.         $this->height null;
  111.         $this->realHeight null;
  112.         $this->realWidth null;
  113.     }
  114.     /**
  115.      * @return int
  116.      */
  117.     public function getWidth()
  118.     {
  119.         if (!$this->width) {
  120.             $this->getDimensions();
  121.         }
  122.         return $this->width;
  123.     }
  124.     /**
  125.      * @return int
  126.      */
  127.     public function getHeight()
  128.     {
  129.         if (!$this->height) {
  130.             $this->getDimensions();
  131.         }
  132.         return $this->height;
  133.     }
  134.     /**
  135.      * @return int
  136.      */
  137.     public function getRealWidth()
  138.     {
  139.         if (!$this->realWidth) {
  140.             $this->getDimensions();
  141.         }
  142.         return $this->realWidth;
  143.     }
  144.     /**
  145.      * @return int
  146.      */
  147.     public function getRealHeight()
  148.     {
  149.         if (!$this->realHeight) {
  150.             $this->getDimensions();
  151.         }
  152.         return $this->realHeight;
  153.     }
  154.     private function readDimensionsFromFile(): array
  155.     {
  156.         $dimensions = [];
  157.         $pathReference $this->getPathReference();
  158.         if (in_array($pathReference['type'], ['thumbnail''asset'])) {
  159.             try {
  160.                 $localFile $this->getLocalFile();
  161.                 if (null !== $localFile) {
  162.                     if ($imageInfo = @getimagesize($localFile)) {
  163.                         $dimensions = [
  164.                             'width' => $imageInfo[0],
  165.                             'height' => $imageInfo[1],
  166.                         ];
  167.                         if ($config $this->getConfig()) {
  168.                             $this->getAsset()->getDao()->addToThumbnailCache(
  169.                                 $config->getName(),
  170.                                 basename($pathReference['storagePath']),
  171.                                 filesize($localFile),
  172.                                 $dimensions['width'],
  173.                                 $dimensions['height']
  174.                             );
  175.                         }
  176.                     }
  177.                 }
  178.             } catch (\Exception $e) {
  179.                 // noting to do
  180.             }
  181.         }
  182.         return $dimensions;
  183.     }
  184.     /**
  185.      * @return array
  186.      */
  187.     public function getDimensions()
  188.     {
  189.         if (!$this->width || !$this->height) {
  190.             $config $this->getConfig();
  191.             $asset $this->getAsset();
  192.             $dimensions = [];
  193.             if ($config) {
  194.                 $thumbnail $asset->getDao()->getCachedThumbnail($config->getName(), $this->getFilename());
  195.                 if (isset($thumbnail['width'], $thumbnail['height'])) {
  196.                     $dimensions['width'] = $thumbnail['width'];
  197.                     $dimensions['height'] = $thumbnail['height'];
  198.                 }
  199.             }
  200.             if (empty($dimensions) && $this->exists()) {
  201.                 $dimensions $this->readDimensionsFromFile();
  202.             }
  203.             // try to calculate the final dimensions based on the thumbnail configuration
  204.             if (empty($dimensions) && $config && $asset instanceof Image) {
  205.                 $dimensions $config->getEstimatedDimensions($asset);
  206.             }
  207.             if (empty($dimensions)) {
  208.                 // unable to calculate dimensions -> use fallback
  209.                 // generate the thumbnail and get dimensions from the thumbnail file
  210.                 $dimensions $this->readDimensionsFromFile();
  211.             }
  212.             $this->width $dimensions['width'] ?? null;
  213.             $this->height $dimensions['height'] ?? null;
  214.             // the following is only relevant if using high-res option (retina, ...)
  215.             $this->realHeight $this->height;
  216.             $this->realWidth $this->width;
  217.             if ($config && $config->getHighResolution() && $config->getHighResolution() > 1) {
  218.                 $this->realWidth = (int)floor($this->width $config->getHighResolution());
  219.                 $this->realHeight = (int)floor($this->height $config->getHighResolution());
  220.             }
  221.         }
  222.         return [
  223.             'width' => $this->width,
  224.             'height' => $this->height,
  225.         ];
  226.     }
  227.     /**
  228.      * @return Asset
  229.      */
  230.     public function getAsset()
  231.     {
  232.         return $this->asset;
  233.     }
  234.     /**
  235.      * @return Config|null
  236.      */
  237.     public function getConfig()
  238.     {
  239.         return $this->config;
  240.     }
  241.     /**
  242.      * @return string
  243.      */
  244.     public function getMimeType()
  245.     {
  246.         if (!$this->mimetype) {
  247.             $pathReference $this->getPathReference(true);
  248.             if ($pathReference['type'] === 'data-uri') {
  249.                 $this->mimetype substr($pathReference['src'], 5strpos($pathReference['src'], ';') - 5);
  250.             } else {
  251.                 $fileExt $this->getFileExtension();
  252.                 $mimeTypes MimeTypes::getDefault()->getMimeTypes($fileExt);
  253.                 if (!empty($mimeTypes)) {
  254.                     $this->mimetype $mimeTypes[0];
  255.                 } else {
  256.                     // unknown
  257.                     $this->mimetype 'application/octet-stream';
  258.                 }
  259.             }
  260.         }
  261.         return $this->mimetype;
  262.     }
  263.     /**
  264.      * @return string
  265.      */
  266.     public function getFileExtension()
  267.     {
  268.         return \Pimcore\File::getFileExtension($this->getPath(true));
  269.     }
  270.     /**
  271.      * @internal
  272.      *
  273.      * @param array $pathReference
  274.      *
  275.      * @return string|null
  276.      */
  277.     protected function convertToWebPath(array $pathReference): ?string
  278.     {
  279.         $type $pathReference['type'] ?? null;
  280.         $path $pathReference['src'] ?? null;
  281.         if (Tool::isFrontend()) {
  282.             if ($type === 'data-uri') {
  283.                 return $path;
  284.             } elseif ($type === 'deferred') {
  285.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail_deferred'];
  286.                 $path $prefix urlencode_ignore_slash($path);
  287.             } elseif ($type === 'thumbnail') {
  288.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail'];
  289.                 $path $prefix urlencode_ignore_slash($path);
  290.             } elseif ($type === 'asset') {
  291.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['source'];
  292.                 $path $prefix urlencode_ignore_slash($path);
  293.             } else {
  294.                 $path urlencode_ignore_slash($path);
  295.             }
  296.         }
  297.         return $path;
  298.     }
  299.     /**
  300.      * @return string
  301.      */
  302.     public function getFrontendPath(): string
  303.     {
  304.         $path $this->getPath();
  305.         if (!\preg_match('@^(https?|data):@'$path)) {
  306.             $path \Pimcore\Tool::getHostUrl() . $path;
  307.         }
  308.         return $path;
  309.     }
  310.     /**
  311.      * @internal
  312.      *
  313.      * @return string|null
  314.      *
  315.      * @throws \Exception
  316.      */
  317.     public function getLocalFile()
  318.     {
  319.         $stream $this->getStream();
  320.         if (null === $stream) {
  321.             return null;
  322.         }
  323.         return self::getLocalFileFromStream($stream);
  324.     }
  325.     /**
  326.      * @return bool
  327.      */
  328.     public function exists(): bool
  329.     {
  330.         $pathReference $this->getPathReference(true);
  331.         $type $pathReference['type'] ?? '';
  332.         if (
  333.             $type === 'asset' ||
  334.             $type === 'data-uri' ||
  335.             $type === 'thumbnail'
  336.         ) {
  337.             return true;
  338.         } elseif ($type === 'deferred') {
  339.             return false;
  340.         } elseif (isset($pathReference['storagePath'])) {
  341.             // this is probably redundant, but as it doesn't hurt we can keep it
  342.             return $this->existsOnStorage($pathReference);
  343.         }
  344.         return false;
  345.     }
  346.     /**
  347.      * @internal
  348.      *
  349.      * @param array|null $pathReference
  350.      *
  351.      * @return bool
  352.      *
  353.      * @throws \League\Flysystem\FilesystemException
  354.      */
  355.     public function existsOnStorage(?array $pathReference = []): bool
  356.     {
  357.         $pathReference ??= $this->getPathReference(true);
  358.         if (isset($pathReference['storagePath'])) {
  359.             // this is probably redundant, but as it doesn't hurt we can keep it
  360.             return Storage::get('thumbnail')->fileExists($pathReference['storagePath']);
  361.         }
  362.         return false;
  363.     }
  364.     public static function supportsFormat(string $format): bool
  365.     {
  366.         if (!isset(self::$supportedFormats[$format])) {
  367.             self::$supportedFormats[$format] = \Pimcore\Image::getInstance()->supportsFormat($format);
  368.         }
  369.         return self::$supportedFormats[$format];
  370.     }
  371.     public function getFileSize(): ?int
  372.     {
  373.         $thumbnail $this->getAsset()->getDao()->getCachedThumbnail($this->getConfig()->getName(), $this->getFilename());
  374.         if ($thumbnail && $thumbnail['filesize']) {
  375.             return $thumbnail['filesize'];
  376.         }
  377.         $pathReference $this->getPathReference(false);
  378.         if ($pathReference['type'] === 'asset') {
  379.             return $this->asset->getFileSize();
  380.         } elseif (isset($pathReference['storagePath'])) {
  381.             return Tool\Storage::get('thumbnail')->fileSize($pathReference['storagePath']);
  382.         }
  383.         return null;
  384.     }
  385.     private function getFilename(): string
  386.     {
  387.         $pathReference $this->getPathReference(true);
  388.         return basename($pathReference['src']);
  389.     }
  390.     /**
  391.      * Returns path for thumbnail image in a given file format
  392.      *
  393.      * @param string $format
  394.      *
  395.      * @return static
  396.      */
  397.     public function getAsFormat(string $format): static
  398.     {
  399.         $thumb = clone $this;
  400.         $config $thumb->getConfig() ? clone $thumb->getConfig() : new Config();
  401.         $config->setFormat($format);
  402.         $thumb->config $config;
  403.         $thumb->reset();
  404.         return $thumb;
  405.     }
  406. }