X-Git-Url: https://git.rapsys.eu/packbundle/blobdiff_plain/df7b4f1cde5b1f7c3534df258047d1581f066134..5b4dd4270841cc519adb7c20688d8ebd3c467102:/Util/FacebookUtil.php diff --git a/Util/FacebookUtil.php b/Util/FacebookUtil.php index ea3393d..633702b 100644 --- a/Util/FacebookUtil.php +++ b/Util/FacebookUtil.php @@ -11,378 +11,38 @@ namespace Rapsys\PackBundle\Util; -use Symfony\Component\Asset\PackageInterface; +use Psr\Container\ContainerInterface; + +use Rapsys\PackBundle\RapsysPackBundle; + use Symfony\Component\Filesystem\Exception\IOExceptionInterface; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Routing\RouterInterface; /** * Helps manage facebook images */ class FacebookUtil { /** - * The cache directory - * - * @var string + * Alias string */ - protected $cache; + protected string $alias; /** - * The fonts array - * - * @var array + * Config array */ - protected $fonts; + protected array $config; /** - * The public path + * Creates a new facebook util * - * @var string + * @param ContainerInterface $container The container instance + * @param RouterInterface $router The RouterInterface instance + * @param SluggerUtil $slugger The SluggerUtil instance */ - protected $path; - - /** - * The public url - * - * @var string - */ - protected $url; - - /** - * The package instance - * - * @var PackageInterface - */ - protected $package; - - /** - * The prefix - * - * @var string - */ - protected $prefix; - - /** - * The source - * - * @var string - */ - protected $source; - - /** - * Creates a new osm util - * - * @param PackageInterface $package The package instance - * @param string $cache The cache directory - * @param string $path The public path - * @param string $url The public url - * @param string $prefix The prefix - */ - function __construct(PackageInterface $package, string $cache, string $path, string $url, string $prefix = 'facebook', string $source = 'png/facebook.png', array $fonts = [ 'default' => 'ttf/default.ttf' ]) { - //Set cache - $this->cache = $cache.'/'.$prefix; - - //Set fonts - $this->fonts = $fonts; - - //Set path - $this->path = $path.'/'.$prefix; - - //Set url - $this->url = $url.'/'.$prefix; - - //Set package instance - $this->package = $package; - - //Set prefix key - $this->prefix = $prefix; - - //Set source - $this->source = $source; - } - - /** - * Return the facebook image - * - * Generate simple image in jpeg format or load it from cache - * - * @param string $pathInfo The request path info - * @param array $texts The image texts - * @param int $updated The updated timestamp - * @param ?string $source The image source - * @param int $width The width - * @param int $height The height - * @return array The image array - */ - public function getImage(string $pathInfo, array $texts, int $updated, ?string $source = null, int $width = 1200, int $height = 630): array { - //Set path file - $path = $this->path.$pathInfo.'.jpeg'; - - //Without existing path - if (!is_dir($dir = dirname($path))) { - //Create filesystem object - $filesystem = new Filesystem(); - - try { - //Create path - //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) - $filesystem->mkdir($dir, 0775); - } catch (IOExceptionInterface $e) { - //Throw error - throw new \Exception(sprintf('Output path "%s" do not exists and unable to create it', $dir), 0, $e); - } - } - - //With path file - if (is_file($path) && ($mtime = stat($path)['mtime']) && $mtime >= $updated) { - #XXX: we used to drop texts with $data['canonical'] === true !!! - - //Return image data - return [ - #'og:image' => $this->package->getAbsoluteUrl('@RapsysAir/facebook/'.$mtime.$pathInfo.'.jpeg'), - 'og:image' => $this->package->getAbsoluteUrl($this->url.'/'.$mtime.$pathInfo.'.jpeg'), - 'og:image:alt' => str_replace("\n", ' ', implode(' - ', array_keys($texts))), - 'og:image:height' => $height, - 'og:image:width' => $width - ]; - } - - //Set cache path - $cache = $this->cache.$pathInfo.'.png'; - - //Without cache path - if (!is_dir($dir = dirname($cache))) { - //Create filesystem object - $filesystem = new Filesystem(); - - try { - //Create path - //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) - $filesystem->mkdir($dir, 0775); - } catch (IOExceptionInterface $e) { - //Throw error - throw new \Exception(sprintf('Output directory "%s" do not exists and unable to create it', $dir), 0, $e); - } - } - - //Without source - if ($source === null) { - //Set source - $source = realpath($this->source); - } - - //Create image object - $image = new \Imagick(); - - //Without cache image - if (!is_file($cache) || stat($cache)['mtime'] < stat($source)['mtime']) { - //Check target directory - if (!is_dir($dir = dirname($cache))) { - //Create filesystem object - $filesystem = new Filesystem(); - - try { - //Create dir - //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) - $filesystem->mkdir($dir, 0775); - } catch (IOExceptionInterface $e) { - //Throw error - throw new \Exception(sprintf('Output directory "%s" do not exists and unable to create it', $dir), 0, $e); - } - } - - //Read image - $image->readImage($source); - - //Crop using aspect ratio - //XXX: for better result upload image directly in aspect ratio :) - $image->cropThumbnailImage($width, $height); - - //Strip image exif data and properties - $image->stripImage(); - - //Save cache image - if (!$image->writeImage($cache)) { - //Throw error - throw new \Exception(sprintf('Unable to write image "%s"', $cache)); - } - //With cache - } else { - //Read image - $image->readImage($cache); - } - - //Create draw - $draw = new \ImagickDraw(); - - //Set stroke antialias - $draw->setStrokeAntialias(true); - - //Set text antialias - $draw->setTextAntialias(true); - - //Set align aliases - $aligns = [ - 'left' => \Imagick::ALIGN_LEFT, - 'center' => \Imagick::ALIGN_CENTER, - 'right' => \Imagick::ALIGN_RIGHT - ]; - - //Set default font - $defaultFont = 'dejavusans'; - - //Set default align - $defaultAlign = 'center'; - - //Set default size - $defaultSize = 60; - - //Set default stroke - $defaultStroke = '#00c3f9'; - - //Set default width - $defaultWidth = 15; - - //Set default fill - $defaultFill = 'white'; - - //Init counter - $i = 1; - - //Set text count - $count = count($texts); - - //Draw each text stroke - foreach($texts as $text => $data) { - //Set font - $draw->setFont($this->fonts[$data['font']??$defaultFont]); - - //Set font size - $draw->setFontSize($data['size']??$defaultSize); - - //Set stroke width - $draw->setStrokeWidth($data['width']??$defaultWidth); - - //Set text alignment - $draw->setTextAlignment($align = ($aligns[$data['align']??$defaultAlign])); - - //Get font metrics - $metrics = $image->queryFontMetrics($draw, $text); - - //Without y - if (empty($data['y'])) { - //Position verticaly each text evenly - $texts[$text]['y'] = $data['y'] = (($height + 100) / (count($texts) + 1) * $i) - 50; - } - - //Without x - if (empty($data['x'])) { - if ($align == \Imagick::ALIGN_CENTER) { - $texts[$text]['x'] = $data['x'] = $width/2; - } elseif ($align == \Imagick::ALIGN_LEFT) { - $texts[$text]['x'] = $data['x'] = 50; - } elseif ($align == \Imagick::ALIGN_RIGHT) { - $texts[$text]['x'] = $data['x'] = $width - 50; - } - } - - //Center verticaly - //XXX: add ascender part then center it back by half of textHeight - //TODO: maybe add a boundingbox ??? - $texts[$text]['y'] = $data['y'] += $metrics['ascender'] - $metrics['textHeight']/2; - - //Set stroke color - $draw->setStrokeColor(new \ImagickPixel($data['stroke']??$defaultStroke)); - - //Set fill color - $draw->setFillColor(new \ImagickPixel($data['stroke']??$defaultStroke)); - - //Add annotation - $draw->annotation($data['x'], $data['y'], $text); - - //Increase counter - $i++; - } - - //Create stroke object - $stroke = new \Imagick(); - - //Add new image - $stroke->newImage($width, $height, new \ImagickPixel('transparent')); - - //Draw on image - $stroke->drawImage($draw); - - //Blur image - //XXX: blur the stroke canvas only - $stroke->blurImage(5,3); - - //Set opacity to 0.5 - //XXX: see https://www.php.net/manual/en/image.evaluateimage.php - $stroke->evaluateImage(\Imagick::EVALUATE_DIVIDE, 1.5, \Imagick::CHANNEL_ALPHA); - - //Compose image - $image->compositeImage($stroke, \Imagick::COMPOSITE_OVER, 0, 0); - - //Clear stroke - $stroke->clear(); - - //Destroy stroke - unset($stroke); - - //Clear draw - $draw->clear(); - - //Set text antialias - $draw->setTextAntialias(true); - - //Draw each text - foreach($texts as $text => $data) { - //Set font - $draw->setFont($this->fonts[$data['font']??$defaultFont]); - - //Set font size - $draw->setFontSize($data['size']??$defaultSize); - - //Set text alignment - $draw->setTextAlignment($aligns[$data['align']??$defaultAlign]); - - //Set fill color - $draw->setFillColor(new \ImagickPixel($data['fill']??$defaultFill)); - - //Add annotation - $draw->annotation($data['x'], $data['y'], $text); - - //With canonical text - if (!empty($data['canonical'])) { - //Prevent canonical to finish in alt - unset($texts[$text]); - } - } - - //Draw on image - $image->drawImage($draw); - - //Strip image exif data and properties - $image->stripImage(); - - //Set image format - $image->setImageFormat('jpeg'); - - //Set progressive jpeg - $image->setInterlaceScheme(\Imagick::INTERLACE_PLANE); - - //Save image - if (!$image->writeImage($path)) { - //Throw error - throw new \Exception(sprintf('Unable to write image "%s"', $path)); - } - - //Return image data - return [ - 'og:image' => $this->package->getAbsoluteUrl($this->url.'/'.stat($path)['mtime'].$pathInfo.'.jpeg'), - 'og:image:alt' => str_replace("\n", ' ', implode(' - ', array_keys($texts))), - 'og:image:height' => $height, - 'og:image:width' => $width - ]; + public function __construct(protected ContainerInterface $container, protected RouterInterface $router, protected SluggerUtil $slugger) { + //Retrieve config + $this->config = $container->getParameter($this->alias = RapsysPackBundle::getAlias()); } }