src/Services/ImageService.php line 64

Open in your IDE?
  1. <?php
  2. namespace Slivki\Services;
  3. use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
  4. use Doctrine\ORM\EntityManagerInterface;
  5. use Imagine\Exception\InvalidArgumentException;
  6. use Imagine\Gd\Font;
  7. use Imagine\Gd\Imagine;
  8. use Imagine\Image\Box;
  9. use Imagine\Image\Palette\RGB;
  10. use Imagine\Image\Point;
  11. use Slivki\Entity\Media;
  12. use Slivki\Entity\Media\AbstractMediaBase;
  13. use Slivki\Entity\Media\OfferAppTeaserMedia;
  14. use Slivki\Entity\Media\OfferMobileTeaserMedia;
  15. use Slivki\Entity\Media\OfferTeaserMedia;
  16. use Slivki\Entity\MediaSize;
  17. use Slivki\Entity\MediaType;
  18. use Slivki\Entity\Offer;
  19. use Slivki\Entity\SaleProduct;
  20. use Slivki\Util\SoftCache;
  21. use Symfony\Component\Filesystem\Filesystem;
  22. use Symfony\Component\HttpKernel\KernelInterface;
  23. class ImageService
  24. {
  25.     const CACHE_NAME "media-1-0-";
  26.     const MEDIA_ROOT "/znijki-media/";
  27.     const INITIAL_PATH "initial";
  28.     const BACKGROUNDS_PATH "backgrounds/";
  29.     const BACKGROUNDS_CERTIFICATES_PATH "backgrounds/certificates/";
  30.     const FALLBACK_IMAGE "/common-img/d.gif";
  31.     const DEFAULT_AVATAR "/images/default_avatar.png?v=2";
  32.     const IMAGE_URL_CACHE_EXPIRE 1800;
  33.     const CACHE_KEY "-url-1-0-";
  34.     private $mediaRepository;
  35.     private $entityManager;
  36.     private $webRoot;
  37.     private $baseUrl;
  38.     public function __construct(
  39.         EntityManagerInterface $entityManager,
  40.         KernelInterface $kernel,
  41.         string $baseUrl
  42.     ) {
  43.         $this->mediaRepository $entityManager->getRepository(Media::class);
  44.         $this->entityManager $entityManager;
  45.         $this->webRoot $kernel->getProjectDir() . "/public";
  46.         $this->baseUrl $baseUrl;
  47.     }
  48.     public function getImageURLCached (AbstractMediaBase $media null$width$height) {
  49.         if (!$media) {
  50.             return self::FALLBACK_IMAGE;
  51.         }
  52.         $softCache = new SoftCache(self::CACHE_NAME);
  53.         $cacheKey $media->getID() . self::CACHE_KEY $width "x" $height;
  54.         $imageURLCached $softCache->get($cacheKey);
  55.         if ($imageURLCached) {
  56.             return $imageURLCached;
  57.         }
  58.         $imageURL $this->getImageURL($media$width$height);
  59.         if (!$imageURL) {
  60.             return self::FALLBACK_IMAGE;
  61.         }
  62.         $softCache->set($cacheKey$imageURLself::IMAGE_URL_CACHE_EXPIRE);
  63.         return $imageURL;
  64.     }
  65.     public function mediaCacheReload(AbstractMediaBase $media): void
  66.     {
  67.         $softCache = new SoftCache(self::CACHE_NAME);
  68.         $softCache->delete(sprintf('%s%s%s'$media->getID(), self::CACHE_KEY'0x0'));
  69.         foreach ($media->getSizes() as $mediaSize) {
  70.             $this->resizeImage($media$mediaSize->getWidth(), $mediaSize->getHeight());
  71.         }
  72.     }
  73.     public function getImageURLCachedWithDomain(?AbstractMediaBase $mediaint $widthint $height): string
  74.     {
  75.         return $this->baseUrl $this->getImageURLCached($media$width$height);
  76.     }
  77.     public function getFallbackImageURLWithDomain(): string
  78.     {
  79.         return $this->baseUrl self::FALLBACK_IMAGE;
  80.     }
  81.     public function getFullAvatarUrlByPath(string $path): string
  82.     {
  83.         return \sprintf('%s%s%s%s'$this->baseUrlself::MEDIA_ROOTself::INITIAL_PATH$path);
  84.     }
  85.     public function getImageURL(AbstractMediaBase $media$width$height) {
  86.         $media $this->entityManager->merge($media);
  87.         if ($width == && $height == 0) {
  88.             return self::MEDIA_ROOT self::INITIAL_PATH $media->getPath() . $media->getName();
  89.         }
  90.         $mediaSizes $media->getSizes();
  91.         $mediaSize null;
  92.         foreach ($mediaSizes->toArray() as $size) {
  93.             if ($size->getWidth() == $width && $size->getHeight() == $height) {
  94.                 $mediaSize $size;
  95.                 break;
  96.             }
  97.         }
  98.         if (!$mediaSize) {
  99.             $imageCreated false;
  100.             $mediaSize = new MediaSize();
  101.             $mediaSize->setWidth($width);
  102.             $mediaSize->setHeight($height);
  103.             $mediaSize->setMedia($media);
  104.             try {
  105.                 $this->entityManager->persist($mediaSize);
  106.                 $this->entityManager->flush($mediaSize);
  107.             } catch (UniqueConstraintViolationException $exception) {
  108.                 $imageCreated false;
  109.             }
  110.             if (!$imageCreated) {
  111.                 if (!$this->resizeImage($media$width$height)) {
  112.                     //return false;
  113.                     //$softCache = new SoftCache(self::CACHE_NAME);
  114.                     //$cacheKey = $media->getID() . "-url-" . $width . "x" . $height;
  115.                     //$softCache->set($cacheKey, self::FALLBACK_IMAGE, self::IMAGE_URL_CACHE_EXPIRE);
  116.                     //return self::FALLBACK_IMAGE;
  117.                 }
  118.             }
  119.         }
  120.         return $this->getMediaURL($media$width$height);
  121.     }
  122.     public function clearMediaUrlCache(AbstractMediaBase $media): void
  123.     {
  124.         $softCache = new SoftCache(self::CACHE_NAME);
  125.         $softCache->delete(sprintf('%d%s%dx%d'$media->getID(), self::CACHE_KEY00));
  126.         foreach ($media->getSizes() as $mediaSize) {
  127.             $softCache->delete(
  128.                 sprintf(
  129.                     '%d%s%dx%d',
  130.                     $media->getID(),
  131.                     self::CACHE_KEY,
  132.                     $mediaSize->getWidth(),
  133.                     $mediaSize->getHeight(),
  134.                 )
  135.             );
  136.         }
  137.     }
  138.     public function resizeImage(AbstractMediaBase $media$width$height) {
  139.         $mediaPathNew $this->getMediaPath($media$width$height);
  140.         $this->makeMediaPath($mediaPathNew);
  141.         $originalMediaPath $this->webRoot self::MEDIA_ROOT self::INITIAL_PATH $media->getPath() . $media->getName();
  142.         if ($width == && $height == 0) {
  143.             $fileSystem = new Filesystem();
  144.             if (!$fileSystem->exists($originalMediaPath)) {
  145.                 return false;
  146.             }
  147.             $fileSystem->copy($originalMediaPath$this->getFullMediaPath($media$width$height));
  148.             return true;
  149.         }
  150.         try {
  151.             $imagine = new Imagine();
  152.             $image $imagine->open($originalMediaPath);
  153.             $errorReporting error_reporting(E_ERROR);
  154.             $exifData exif_read_data($originalMediaPath);
  155.             $rotateValue 0;
  156.             if ($exifData !== false && isset($exifData['Orientation'])) {
  157.                 switch ($exifData['Orientation']) {
  158.                     case 8:
  159.                         $rotateValue = -90;
  160.                         break;
  161.                     case 3:
  162.                         $rotateValue 180;
  163.                         break;
  164.                     case 6:
  165.                         $rotateValue 90;
  166.                         break;
  167.                 }
  168.                 if ($rotateValue != 0) {
  169.                     $image->rotate($rotateValue);
  170.                 }
  171.             }
  172.             error_reporting($errorReporting);
  173.             if ($width == 0) {
  174.                 $sourceImageSize $image->getSize();
  175.                 $newImageSize $sourceImageSize->heighten($height);
  176.             } else if ($height == 0) {
  177.                 $sourceImageSize $image->getSize();
  178.                 $newImageSize $sourceImageSize->widen($width);
  179.             } else {
  180.                 $newImageSize = new Box($width$height);
  181.             }
  182.             $image->resize($newImageSize);
  183.             $fileName $this->getFullMediaPath($media$width$height);
  184.             $image->save($fileName);
  185.             if ($media instanceof OfferTeaserMedia || $media instanceof OfferMobileTeaserMedia || $media instanceof OfferAppTeaserMedia) {
  186.                 $tinifyResult $this->tinify($fileName);
  187.                 if (isset($tinifyResult['output']['url'])) {
  188.                     copy($tinifyResult['output']['url'], $fileName);
  189.                 }
  190.             }
  191.         } catch (InvalidArgumentException $exception) {
  192.             return false;
  193.         }
  194.         $softCache = new SoftCache(self::CACHE_NAME);
  195.         $cacheKey $media->getID() . self::CACHE_KEY $width "x" $height;
  196.         $softCache->delete($cacheKey);
  197.         return true;
  198.     }
  199.     private function getMediaPath(AbstractMediaBase $media$width$height) {
  200.         return "w" $width "_" $height $media->getPath();
  201.     }
  202.     public function getFullMediaPath(AbstractMediaBase $media$width$height) {
  203.         return $this->webRoot self::MEDIA_ROOT $this->getMediaPath($media$width$height) . $media->getName();
  204.     }
  205.     public function saveMailingTeaserImage(Offer $offer) {
  206.         $width 500;
  207.         $height 324;
  208.         $captionHeight 60;
  209.         $teaserMedia $offer->getTeaserMedia();
  210.         if (!$teaserMedia) {
  211.             return false;
  212.         }
  213.         $initialMediaPath $this->webRoot self::MEDIA_ROOT self::INITIAL_PATH $teaserMedia->getPath();
  214.         $teaserMediaName $teaserMedia->getName();
  215.         if (!file_exists($initialMediaPath $teaserMediaName)) {
  216.             return false;
  217.         }
  218.         $imagine = new Imagine();
  219.         $image $imagine->open($initialMediaPath $teaserMediaName);
  220.         $newImageSize = new Box($width$height);
  221.         $image->resize($newImageSize);
  222.         if ($offer->getMailingTeaserMedia()) {
  223.             $newFileName $offer->getMailingTeaserMedia()->getName();
  224.         } else {
  225.             $newFileName 'm_' $teaserMediaName;
  226.             $fs = new Filesystem();
  227.             while ($fs->exists($initialMediaPath$newFileName)) {
  228.                 $newFileName time() . '_' $newFileName;
  229.             }
  230.         }
  231.         $caption $offer->getCaptionName();
  232.         if ($caption) {
  233.             $palette = new RGB();
  234.             $captionFont = new Font('/home/virtwww/slivki/public/fonts/roboto/Roboto-Bold.ttf' 28,  $palette->color('#ffffff'));
  235.             $caption mb_strtoupper($caption);
  236.             $captionBox $captionFont->box($caption);
  237.             while ($captionBox->getWidth() > $width 20) {
  238.                 $caption str_replace('...'''$caption);
  239.                 $caption mb_substr($caption0, -1) . '...';
  240.                 $captionBox $captionFont->box($caption);
  241.             }
  242.             $captionCoordinates = [
  243.                 new Point(0$height $captionHeight),
  244.                 new Point($width$height $captionHeight),
  245.                 new Point($width,  $height),
  246.                 new Point(0$height),
  247.             ];
  248.             $image->draw()->polygon($captionCoordinates$palette->color($offer->getCaptionColor()), true);
  249.             $image->draw()->text($caption$captionFont, new Point((int)($width/$captionBox->getWidth()/2), $height 46));
  250.         }
  251.         $image->save($initialMediaPath $newFileName, ['jpeg_quality' => 100]);
  252.         return $newFileName;
  253.     }
  254.     public function tinify($fileName) {
  255.         $apiKey 'J7BW6n1n3gN3VmQ5rC8mqcnKdf4lsrJq';
  256.         $url 'https://api.tinify.com/shrink';
  257.         $curl curl_init();
  258.         curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);
  259.         curl_setopt($curlCURLOPT_USERPWD'api:' $apiKey);
  260.         curl_setopt($curlCURLOPT_POSTFIELDSfile_get_contents($fileName));
  261.         curl_setopt($curlCURLOPT_URL$url);
  262.         $result curl_exec($curl);
  263.         curl_close($curl);
  264.         if (!$result) {
  265.             return false;
  266.         }
  267.         $result json_decode($resulttrue);
  268.         return $result;
  269.     }
  270.     public function saveSaleProductMailingTeaserImage(SaleProduct $saleProduct) {
  271.         $width 524;
  272.         $height 340;
  273.         $padding 20;
  274.         $suplpierLogoHeight 60;
  275.         $teaserMedia $saleProduct->getTeaserMedia();
  276.         if (!$teaserMedia) {
  277.             return false;
  278.         }
  279.         $initialMediaPath $this->webRoot self::MEDIA_ROOT self::INITIAL_PATH $teaserMedia->getPath();
  280.         $teaserMediaName $teaserMedia->getName();
  281.         if (!file_exists($initialMediaPath $teaserMediaName)) {
  282.             return false;
  283.         }
  284.         $imagine = new Imagine();
  285.         $image $imagine->open($initialMediaPath $teaserMediaName);
  286.         $newImageSize = new Box($width$height);
  287.         $image->resize($newImageSize);
  288.         if ($saleProduct->getMailingTeaserMedia()) {
  289.             $newFileName $saleProduct->getMailingTeaserMedia()->getName();
  290.         } else {
  291.             $newFileName 'm_' $teaserMediaName;
  292.             $fs = new Filesystem();
  293.             while ($fs->exists($initialMediaPath$newFileName)) {
  294.                 $newFileName time() . '_' $newFileName;
  295.             }
  296.         }
  297.         if ($saleProduct->getRegularPrice() > 0) {
  298.             $palette = new RGB();
  299.             $discountLabelFont = new Font('/home/virtwww/slivki/public/fonts/roboto/Roboto-Bold.ttf' 28,  $palette->color('#333333'));
  300.             $discountLabelBgColor $palette->color('#00e196');
  301.             $discountLabelText '-' round($saleProduct->getDiscountPercent(), 0) . '%';
  302.             $discountLabelBox $discountLabelFont->box($discountLabelText);
  303.             $discountLabelCoordinates = [
  304.                 new Point($width $discountLabelBox->getWidth() - $padding0),
  305.                 new Point($width0),
  306.                 new Point($width,  $discountLabelBox->getHeight() + $padding),
  307.                 new Point($width $discountLabelBox->getWidth() - $padding$discountLabelBox->getHeight() + $padding),
  308.             ];
  309.             $image->draw()->polygon($discountLabelCoordinates$discountLabelBgColortrue);
  310.             $discountLabelPosition = new Point($width $discountLabelBox->getWidth() - $padding$padding);
  311.             $image->draw()->text($discountLabelText$discountLabelFont$discountLabelPosition);
  312.         }
  313.         $supplierLogo $this->entityManager->getRepository(Media::class)
  314.             ->getMedia($saleProduct->getSaleVersion()->getSale()->getID(), MediaType::TYPE_SALE_FLIER_LOGO_ID);
  315.         if ($supplierLogo) {
  316.             $supplierLogo $supplierLogo[0];
  317.             $supplierLogoImageFile $this->webRoot self::MEDIA_ROOT self::INITIAL_PATH $supplierLogo->getPath() . $supplierLogo->getName();
  318.             if (file_exists($supplierLogoImageFile)) {
  319.                 $supplierLogoImage $imagine->open($supplierLogoImageFile);
  320.                 $imageSize $supplierLogoImage->getSize();
  321.                 $newSize $imageSize->heighten($suplpierLogoHeight);
  322.                 $supplierLogoImage->resize($newSize);
  323.                 $image->paste($supplierLogoImage, new Point(1010));
  324.             }
  325.         }
  326.         $image->save($initialMediaPath $newFileName, ['jpeg_quality' => 100]);
  327.         return $newFileName;
  328.     }
  329.     private function getMediaURL(AbstractMediaBase $media$width$height) {
  330.         return self::MEDIA_ROOT $this->getMediaPath($media$width$height) . $media->getName();
  331.     }
  332.     private function makeMediaPath($mediaPath) {
  333.         $fileSystem = new Filesystem();
  334.         if ($fileSystem->exists($this->webRoot self::MEDIA_ROOT $mediaPath)) {
  335.             return;
  336.         }
  337.         $folders explode("/"$mediaPath);
  338.         $mediaPath $this->webRoot self::MEDIA_ROOT;
  339.         foreach ($folders as $folder) {
  340.             if ($folder == "") {
  341.                 continue;
  342.             }
  343.             $mediaPath .= $folder;
  344.             if (!$fileSystem->exists($mediaPath)) {
  345.                 $fileSystem->mkdir($mediaPath);
  346.             }
  347.             $mediaPath .= "/";
  348.         }
  349.     }
  350. }