vendor/pimcore/pimcore/lib/Image/Adapter/GD.php line 192

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\Image\Adapter;
  15. use Pimcore\Image\Adapter;
  16. class GD extends Adapter
  17. {
  18.     /**
  19.      * @var string
  20.      */
  21.     protected $path;
  22.     /**
  23.      * @var resource|\GdImage|false
  24.      */
  25.     protected $resource;
  26.     /**
  27.      * {@inheritdoc}
  28.      */
  29.     public function load($imagePath$options = [])
  30.     {
  31.         $this->path $imagePath;
  32.         if (!$this->resource = @imagecreatefromstring(file_get_contents($this->path))) {
  33.             return false;
  34.         }
  35.         // set dimensions
  36.         list($width$height) = getimagesize($this->path);
  37.         $this->setWidth($width);
  38.         $this->setHeight($height);
  39.         if (!$this->sourceImageFormat) {
  40.             $this->sourceImageFormat \Pimcore\File::getFileExtension($imagePath);
  41.         }
  42.         if (in_array(\Pimcore\File::getFileExtension($imagePath), ['png''gif'])) {
  43.             // in GD only gif and PNG can have an alphachannel
  44.             $this->setIsAlphaPossible(true);
  45.         }
  46.         $this->setModified(false);
  47.         return $this;
  48.     }
  49.     /**
  50.      * {@inheritdoc}
  51.      */
  52.     public function getContentOptimizedFormat()
  53.     {
  54.         $format 'pjpeg';
  55.         if ($this->hasAlphaChannel()) {
  56.             $format 'png';
  57.         }
  58.         return $format;
  59.     }
  60.     /**
  61.      * {@inheritdoc}
  62.      */
  63.     public function save($path$format null$quality null)
  64.     {
  65.         if (!$format || $format == 'png32') {
  66.             $format 'png';
  67.         }
  68.         if ($format == 'original') {
  69.             $format $this->sourceImageFormat;
  70.         }
  71.         $format strtolower($format);
  72.         // progressive jpeg
  73.         if ($format == 'pjpeg') {
  74.             imageinterlace($this->resourcetrue);
  75.             $format 'jpeg';
  76.         }
  77.         if ($format == 'jpg') {
  78.             $format 'jpeg';
  79.         }
  80.         $functionName 'image' $format;
  81.         if (!function_exists($functionName)) {
  82.             $functionName 'imagepng';
  83.         }
  84.         // always create a PNG24
  85.         if ($format == 'png') {
  86.             imagesavealpha($this->resourcetrue);
  87.         }
  88.         if ($functionName === 'imagejpeg' || $functionName === 'imagewebp') {
  89.             $functionName($this->resource$path$quality);
  90.         } else {
  91.             $functionName($this->resource$path);
  92.         }
  93.         return $this;
  94.     }
  95.     /**
  96.      * @return bool
  97.      */
  98.     private function hasAlphaChannel()
  99.     {
  100.         if ($this->isAlphaPossible) {
  101.             $width imagesx($this->resource); // Get the width of the image
  102.             $height imagesy($this->resource); // Get the height of the image
  103.             // We run the image pixel by pixel and as soon as we find a transparent pixel we stop and return true.
  104.             for ($i 0$i $width$i++) {
  105.                 for ($j 0$j $height$j++) {
  106.                     $rgba imagecolorat($this->resource$i$j);
  107.                     if (($rgba 0x7F000000) >> 24) {
  108.                         return true;
  109.                     }
  110.                 }
  111.             }
  112.         }
  113.         // If we dont find any pixel the function will return false.
  114.         return false;
  115.     }
  116.     /**
  117.      * {@inheritdoc}
  118.      */
  119.     protected function destroy()
  120.     {
  121.         if ($this->resource) {
  122.             imagedestroy($this->resource);
  123.         }
  124.     }
  125.     /**
  126.      * @param int $width
  127.      * @param int $height
  128.      *
  129.      * @return \GdImage|false
  130.      */
  131.     private function createImage($width$height)
  132.     {
  133.         $newImg imagecreatetruecolor($width$height);
  134.         imagesavealpha($newImgtrue);
  135.         imagealphablending($newImgfalse);
  136.         $trans_colour imagecolorallocatealpha($newImg000127);
  137.         imagefill($newImg00$trans_colour);
  138.         return $newImg;
  139.     }
  140.     /**
  141.      * {@inheritdoc}
  142.      */
  143.     public function resize($width$height)
  144.     {
  145.         $this->preModify();
  146.         $newImg $this->createImage($width$height);
  147.         imagecopyresampled($newImg$this->resource0000$width$height$this->getWidth(), $this->getHeight());
  148.         $this->resource $newImg;
  149.         $this->setWidth($width);
  150.         $this->setHeight($height);
  151.         $this->postModify();
  152.         return $this;
  153.     }
  154.     /**
  155.      * {@inheritdoc}
  156.      */
  157.     public function crop($x$y$width$height)
  158.     {
  159.         $this->preModify();
  160.         $x min($this->getWidth(), max(0$x));
  161.         $y min($this->getHeight(), max(0$y));
  162.         $width min($width$this->getWidth() - $x);
  163.         $height min($height$this->getHeight() - $y);
  164.         $new_img $this->createImage($width$height);
  165.         imagecopy($new_img$this->resource00$x$y$width$height);
  166.         $this->resource $new_img;
  167.         $this->setWidth($width);
  168.         $this->setHeight($height);
  169.         $this->postModify();
  170.         return $this;
  171.     }
  172.     /**
  173.      * {@inheritdoc}
  174.      */
  175.     public function frame($width$height$forceResize false)
  176.     {
  177.         $this->preModify();
  178.         $this->contain($width$height$forceResize);
  179.         $x = ($width $this->getWidth()) / 2;
  180.         $y = ($height $this->getHeight()) / 2;
  181.         $newImage $this->createImage($width$height);
  182.         imagecopy($newImage$this->resource$x$y00$this->getWidth(), $this->getHeight());
  183.         $this->resource $newImage;
  184.         $this->setWidth($width);
  185.         $this->setHeight($height);
  186.         $this->postModify();
  187.         $this->setIsAlphaPossible(true);
  188.         return $this;
  189.     }
  190.     /**
  191.      * {@inheritdoc}
  192.      */
  193.     public function setBackgroundColor($color)
  194.     {
  195.         $this->preModify();
  196.         list($r$g$b) = $this->colorhex2colorarray($color);
  197.         // just imagefill() on the existing image doesn't work, so we have to create a new image, fill it and then merge
  198.         // the source image with the background-image together
  199.         $newImg imagecreatetruecolor($this->getWidth(), $this->getHeight());
  200.         $color imagecolorallocate($newImg$r$g$b);
  201.         imagefill($newImg00$color);
  202.         imagecopy($newImg$this->resource0000$this->getWidth(), $this->getHeight());
  203.         $this->resource $newImg;
  204.         $this->postModify();
  205.         $this->setIsAlphaPossible(false);
  206.         return $this;
  207.     }
  208.     /**
  209.      * {@inheritdoc}
  210.      */
  211.     public function setBackgroundImage($image$mode null)
  212.     {
  213.         $this->preModify();
  214.         $image ltrim($image'/');
  215.         $image PIMCORE_WEB_ROOT '/' $image;
  216.         if (is_file($image)) {
  217.             $backgroundImage imagecreatefromstring(file_get_contents($image));
  218.             list($backgroundImageWidth$backgroundImageHeight) = getimagesize($image);
  219.             $newImg $this->createImage($this->getWidth(), $this->getHeight());
  220.             if ($mode == 'cropTopLeft') {
  221.                 imagecopyresampled($newImg$backgroundImage0000$this->getWidth(), $this->getHeight(), $this->getWidth(), $this->getHeight());
  222.             } elseif ($mode == 'asTexture') {
  223.                 imagesettile($newImg$backgroundImage);
  224.                 imagefilledrectangle($newImg00$this->getWidth(), $this->getHeight(), IMG_COLOR_TILED);
  225.             } else {
  226.                 // default behavior (fit)
  227.                 imagecopyresampled($newImg$backgroundImage0000$this->getWidth(), $this->getHeight(), $backgroundImageWidth$backgroundImageHeight);
  228.             }
  229.             imagealphablending($newImgtrue);
  230.             imagecopyresampled($newImg$this->resource0000$this->getWidth(), $this->getHeight(), $this->getWidth(), $this->getHeight());
  231.             $this->resource $newImg;
  232.         }
  233.         $this->postModify();
  234.         return $this;
  235.     }
  236.     /**
  237.      * {@inheritdoc}
  238.      */
  239.     public function grayscale()
  240.     {
  241.         $this->preModify();
  242.         imagefilter($this->resourceIMG_FILTER_GRAYSCALE);
  243.         $this->postModify();
  244.         return $this;
  245.     }
  246.     /**
  247.      * {@inheritdoc}
  248.      */
  249.     public function sepia()
  250.     {
  251.         $this->preModify();
  252.         imagefilter($this->resourceIMG_FILTER_GRAYSCALE);
  253.         imagefilter($this->resourceIMG_FILTER_COLORIZE100500);
  254.         $this->postModify();
  255.         return $this;
  256.     }
  257.     /**
  258.      * {@inheritdoc}
  259.      */
  260.     public function addOverlay($image$x 0$y 0$alpha 100$composite 'COMPOSITE_DEFAULT'$origin 'top-left')
  261.     {
  262.         $this->preModify();
  263.         $image ltrim($image'/');
  264.         $image PIMCORE_PROJECT_ROOT '/' $image;
  265.         if (is_file($image)) {
  266.             list($oWidth$oHeight) = getimagesize($image);
  267.             if ($origin === 'top-right') {
  268.                 $x $this->getWidth() - $oWidth $x;
  269.             } elseif ($origin === 'bottom-left') {
  270.                 $y $this->getHeight() - $oHeight $y;
  271.             } elseif ($origin === 'bottom-right') {
  272.                 $x $this->getWidth() - $oWidth $x;
  273.                 $y $this->getHeight() - $oHeight $y;
  274.             } elseif ($origin === 'center') {
  275.                 $x round($this->getWidth() / 2) - round($oWidth 2) + $x;
  276.                 $y round($this->getHeight() / 2) - round($oHeight 2) + $y;
  277.             }
  278.             $overlay imagecreatefromstring(file_get_contents($image));
  279.             imagealphablending($this->resourcetrue);
  280.             imagecopyresampled($this->resource$overlay$x$y00$oWidth$oHeight$oWidth$oHeight);
  281.         }
  282.         $this->postModify();
  283.         return $this;
  284.     }
  285.     /**
  286.      * {@inheritdoc}
  287.      */
  288.     public function mirror($mode)
  289.     {
  290.         $this->preModify();
  291.         if ($mode == 'vertical') {
  292.             imageflip($this->resourceIMG_FLIP_VERTICAL);
  293.         } elseif ($mode == 'horizontal') {
  294.             imageflip($this->resourceIMG_FLIP_HORIZONTAL);
  295.         }
  296.         $this->postModify();
  297.         return $this;
  298.     }
  299.     /**
  300.      * {@inheritdoc}
  301.      */
  302.     public function rotate($angle)
  303.     {
  304.         $this->preModify();
  305.         $angle 360 $angle;
  306.         $this->resource imagerotate($this->resource$angleimagecolorallocatealpha($this->resource000127));
  307.         $this->setWidth(imagesx($this->resource));
  308.         $this->setHeight(imagesy($this->resource));
  309.         $this->postModify();
  310.         $this->setIsAlphaPossible(true);
  311.         return $this;
  312.     }
  313.     protected static $supportedFormatsCache = [];
  314.     /**
  315.      * {@inheritdoc}
  316.      */
  317.     public function supportsFormat(string $formatbool $force false)
  318.     {
  319.         if (!isset(self::$supportedFormatsCache[$format]) || $force) {
  320.             $info gd_info();
  321.             $mappings = [
  322.                 'jpg' => 'JPEG Support',
  323.                 'jpeg' => 'JPEG Support',
  324.                 'pjpeg' => 'JPEG Support',
  325.                 'webp' => 'WebP Support',
  326.                 'gif' => 'GIF Create Support',
  327.                 'png' => 'PNG Support',
  328.             ];
  329.             if (isset($mappings[$format]) && isset($info[$mappings[$format]]) && $info[$mappings[$format]]) {
  330.                 self::$supportedFormatsCache[$format] = true;
  331.             } else {
  332.                 self::$supportedFormatsCache[$format] = false;
  333.             }
  334.         }
  335.         return self::$supportedFormatsCache[$format];
  336.     }
  337. }