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

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.             // realWidth / realHeight is only relevant if using high-res option (retina, ...)
  213.             $this->width $this->realWidth $dimensions['width'] ?? null;
  214.             $this->height $this->realHeight $dimensions['height'] ?? null;
  215.             if ($config && $config->getHighResolution() > 1) {
  216.                 if ($this->width) {
  217.                     $this->width = (int)floor($this->realWidth $config->getHighResolution());
  218.                 }
  219.                 if ($this->height) {
  220.                     $this->height = (int)floor($this->realHeight $config->getHighResolution());
  221.                 }
  222.             }
  223.         }
  224.         return [
  225.             'width' => $this->width,
  226.             'height' => $this->height,
  227.         ];
  228.     }
  229.     /**
  230.      * @return Asset
  231.      */
  232.     public function getAsset()
  233.     {
  234.         return $this->asset;
  235.     }
  236.     /**
  237.      * @return Config|null
  238.      */
  239.     public function getConfig()
  240.     {
  241.         return $this->config;
  242.     }
  243.     /**
  244.      * @return string
  245.      */
  246.     public function getMimeType()
  247.     {
  248.         if (!$this->mimetype) {
  249.             $pathReference $this->getPathReference(true);
  250.             if ($pathReference['type'] === 'data-uri') {
  251.                 $this->mimetype substr($pathReference['src'], 5strpos($pathReference['src'], ';') - 5);
  252.             } else {
  253.                 $fileExt $this->getFileExtension();
  254.                 $mimeTypes MimeTypes::getDefault()->getMimeTypes($fileExt);
  255.                 if (!empty($mimeTypes)) {
  256.                     $this->mimetype $mimeTypes[0];
  257.                 } else {
  258.                     // unknown
  259.                     $this->mimetype 'application/octet-stream';
  260.                 }
  261.             }
  262.         }
  263.         return $this->mimetype;
  264.     }
  265.     /**
  266.      * @return string
  267.      */
  268.     public function getFileExtension()
  269.     {
  270.         return \Pimcore\File::getFileExtension($this->getPath());
  271.     }
  272.     /**
  273.      * TODO: Pimcore 11: remove convertArgsBcLayer method (BC layer)
  274.      *
  275.      * @param array $args
  276.      *
  277.      * @return array
  278.      */
  279.     protected function convertArgsBcLayer($args)
  280.     {
  281.         $totalArgs count($args);
  282.         if ($totalArgs 0) {
  283.             if (is_array($args[0])) {
  284.                 return $args[0];
  285.             }
  286.             trigger_deprecation('pimcore/pimcore''10.6',
  287.                 'Calling the getPath() method with arguments is deprecated since version 10.6 and will be removed in Pimcore 11.
  288.             Use an array with options (e.g. ->getPath(["deferredAllowed" => true, "cacheBuster" => false]))');
  289.             if ($totalArgs === 1) {
  290.                 return [
  291.                     'deferredAllowed' => $args[0],
  292.                 ];
  293.             }
  294.             return [
  295.                 'deferredAllowed' => $args[0],
  296.                 'cacheBuster' => $args[1],
  297.             ];
  298.         }
  299.         return [];
  300.     }
  301.     /**
  302.      * @internal
  303.      *
  304.      * @param array $pathReference
  305.      * @param bool $frontend
  306.      *
  307.      * @return string|null
  308.      */
  309.     protected function convertToWebPath(array $pathReferencebool $frontend): ?string
  310.     {
  311.         $type $pathReference['type'] ?? null;
  312.         $path $pathReference['src'] ?? null;
  313.         if ($frontend) {
  314.             if ($type === 'data-uri') {
  315.                 return $path;
  316.             } elseif ($type === 'deferred') {
  317.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail_deferred'];
  318.                 $path $prefix urlencode_ignore_slash($path);
  319.             } elseif ($type === 'thumbnail') {
  320.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail'];
  321.                 $path $prefix urlencode_ignore_slash($path);
  322.             } elseif ($type === 'asset') {
  323.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['source'];
  324.                 $path $prefix urlencode_ignore_slash($path);
  325.             } else {
  326.                 $path urlencode_ignore_slash($path);
  327.             }
  328.         }
  329.         return $path;
  330.     }
  331.     /**
  332.      * @return string
  333.      */
  334.     public function getFrontendPath(): string
  335.     {
  336.         $path $this->getPath(['deferredAllowed' => true'frontend' => true]);
  337.         if (!\preg_match('@^(https?|data):@'$path)) {
  338.             $path \Pimcore\Tool::getHostUrl() . $path;
  339.         }
  340.         return $path;
  341.     }
  342.     /**
  343.      * @internal
  344.      *
  345.      * @return string|null
  346.      *
  347.      * @throws \Exception
  348.      */
  349.     public function getLocalFile()
  350.     {
  351.         $stream $this->getStream();
  352.         if (null === $stream) {
  353.             return null;
  354.         }
  355.         return self::getLocalFileFromStream($stream);
  356.     }
  357.     /**
  358.      * @return bool
  359.      */
  360.     public function exists(): bool
  361.     {
  362.         $pathReference $this->getPathReference(true);
  363.         $type $pathReference['type'] ?? '';
  364.         if (
  365.             $type === 'asset' ||
  366.             $type === 'data-uri' ||
  367.             $type === 'thumbnail'
  368.         ) {
  369.             return true;
  370.         } elseif ($type === 'deferred') {
  371.             return false;
  372.         } elseif (isset($pathReference['storagePath'])) {
  373.             // this is probably redundant, but as it doesn't hurt we can keep it
  374.             return $this->existsOnStorage($pathReference);
  375.         }
  376.         return false;
  377.     }
  378.     /**
  379.      * @internal
  380.      *
  381.      * @param array|null $pathReference
  382.      *
  383.      * @return bool
  384.      *
  385.      * @throws \League\Flysystem\FilesystemException
  386.      */
  387.     public function existsOnStorage(?array $pathReference = []): bool
  388.     {
  389.         $pathReference ??= $this->getPathReference(true);
  390.         if (isset($pathReference['storagePath'])) {
  391.             // this is probably redundant, but as it doesn't hurt we can keep it
  392.             return Storage::get('thumbnail')->fileExists($pathReference['storagePath']);
  393.         }
  394.         return false;
  395.     }
  396.     public static function supportsFormat(string $format): bool
  397.     {
  398.         if (!isset(self::$supportedFormats[$format])) {
  399.             self::$supportedFormats[$format] = \Pimcore\Image::getInstance()->supportsFormat($format);
  400.         }
  401.         return self::$supportedFormats[$format];
  402.     }
  403.     public function getFileSize(): ?int
  404.     {
  405.         $thumbnail $this->getAsset()->getDao()->getCachedThumbnail($this->getConfig()->getName(), $this->getFilename());
  406.         if ($thumbnail && $thumbnail['filesize']) {
  407.             return $thumbnail['filesize'];
  408.         }
  409.         $pathReference $this->getPathReference(false);
  410.         if ($pathReference['type'] === 'asset') {
  411.             return $this->asset->getFileSize();
  412.         } elseif (isset($pathReference['storagePath'])) {
  413.             return Tool\Storage::get('thumbnail')->fileSize($pathReference['storagePath']);
  414.         }
  415.         return null;
  416.     }
  417.     private function getFilename(): string
  418.     {
  419.         $pathReference $this->getPathReference(true);
  420.         return basename($pathReference['src']);
  421.     }
  422.     /**
  423.      * Returns path for thumbnail image in a given file format
  424.      *
  425.      * @param string $format
  426.      *
  427.      * @return static
  428.      */
  429.     public function getAsFormat(string $format): static
  430.     {
  431.         $thumb = clone $this;
  432.         $config $thumb->getConfig() ? clone $thumb->getConfig() : new Config();
  433.         $config->setFormat($format);
  434.         $thumb->config $config;
  435.         $thumb->reset();
  436.         return $thumb;
  437.     }
  438. }