123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- <?php
- namespace Grav\Plugin;
- use Grav\Common\Plugin;
- use Grav\Common\Page\Page;
- use Grav\Common\Flex\Types\Pages\PageObject;
- use RocketTheme\Toolbox\Event\Event;
- use Grav\Common\Data;
- use Grav\Common\Grav;
- use PHPHtmlParser\Dom;
- use PHPHtmlParser\Options;
- require_once 'adapters/imagick.php';
- require_once 'adapters/gd.php';
- /**
- * Class AutomagicImagesPlugin
- * @package Grav\Plugin
- */
- class AutomagicImagesPlugin extends Plugin
- {
- /**
- * @var string
- */
- protected $adapter;
- /**
- * @var array
- */
- protected $sizes;
- /**
- * @return array
- */
- public static function getSubscribedEvents()
- {
- return [
- 'onAdminSave' => ['onAdminSave', 0],
- 'onOutputGenerated' => ['onOutputGenerated', 0]
- ];
- }
- /**
- * Determine whether a particular dependency is installed.
- * @param string $adapter Either 'gd' or 'imagick'
- * @return bool
- */
- protected function dependencyCheck($adapter = 'gd')
- {
- if ($adapter === 'gd') {
- return extension_loaded('gd');
- }
- if ($adapter === 'imagick') {
- return class_exists('\Imagick');
- }
- }
- /**
- * Determine which adapter is preferred and whether or not it's available.
- * Construct an instance of that adapter and return it.
- * @param string $source - Source image path
- * @return mixed - Either an instance of ImagickAdapter, GDAdapter or false if none of the extensions were available
- */
- protected function getImageAdapter($source)
- {
- $imagick_exists = $this->dependencyCheck('imagick');
- $gd_exists = $this->dependencyCheck('gd');
- if ($this->adapter === 'imagick') {
- if ($imagick_exists) {
- return new ImagickAdapter($source);
- } else if ($gd_exists) {
- return new GDAdapter($source);
- }
- } else if ($this->adapter === 'gd') {
- if ($gd_exists) {
- return new GDAdapter($source);
- } else if ($imagick_exists) {
- return new ImagickAdapter($source);
- }
- }
- }
- /**
- * Resizes an image using either Imagick or GD
- * @param string $source - Source image path
- * @param string $target - Target image path
- * @param float $width - Target width
- * @param float $height - Target height
- * @param int [$quality=95] - Compression quality for target image
- * @return bool - Returns true on success, otherwise false
- */
- protected function resizeImage($source, $target, $width, $height, $quality = 95)
- {
- $adapter = $this->getImageAdapter($source);
- $adapter->resize($width, $height);
- $adapter->setQuality($quality);
- return $adapter->save($target);
- }
- /**
- * Called when a page is saved from the admin plugin. Will generate
- * responsive image alternatives for images that don't have any.
- */
- public function onAdminSave($event)
- {
- $page = $event['object'];
- if (!($page instanceof Page || $page instanceof PageObject)) {
- return false;
- }
- if (!$this->dependencyCheck('imagick') && !$this->dependencyCheck('gd')) {
- $this->grav['admin']->setMessage('Neither Imagick nor GD seem to be installed. Automagic Images needs one of them to work.', 'warning');
- return;
- }
- $this->sizes = (array) $this->config->get('plugins.automagic-images.sizes');
- $this->adapter = $this->config->get('plugins.automagic-images.adapter', 'imagick');
- foreach ($page->media()->images() as $filename => $medium) {
- $srcset = $medium->srcset(false);
- if ($srcset != '') {
- continue;
- }
- // We can't rely on the path returned from the image's own path
- // method, since it points to the directory where the image is saved
- // rather than where the original is stored. This means it could
- // point to the global image cache directory.
- $page_path = $page->path();
- $source_path = "$page_path/$filename";
- $info = pathinfo($source_path);
- $count = 0;
- foreach ($this->sizes as $i => $size) {
- if ($size['width'] >= $medium->width) {
- continue;
- }
- $count++;
- $basename = str_replace(" ", "-", $info['filename']);
- $ext = strtolower($info['extension']);
- $dest_path = "{$info['dirname']}/{$basename}@{$count}x.{$ext}";
- $width = $size['width'];
- $quality = $size['quality'];
- $height = ($width / $medium->width) * $medium->height;
- $this->resizeImage($source_path, $dest_path, $width, $height, $quality, $medium->width, $medium->height);
- }
- $remove_original = $this->config->get('plugins.automagic-images.remove_original');
- if ($count > 0) {
- $original_index = $count + 1;
- if ($remove_original) {
- unlink($source_path);
- } else {
- rename($source_path, "{$info['dirname']}/{$basename}@{$original_index}x.{$ext}");
- }
- $fixed_source = str_replace($info['filename'], $basename, $source_path);
- $fixed_source = str_replace($info['extension'], $ext, $fixed_source);
- rename("{$info['dirname']}/{$basename}@1x.{$ext}", $fixed_source);
- }
- $message = "Resized $filename $count times";
- if ($remove_original) {
- $message .= ' (and removed the original image)';
- }
- $this->grav['admin']->setMessage($message, 'info');
- }
- }
- /**
- * Iterates over images in page content that was generated via twig and adds
- * sizes attribute (not cacheable)
- *
- * @return void
- */
- public function onOutputGenerated()
- {
- if ($this->isAdmin()) {
- return;
- }
- $config = (array) $this->config->get('plugins.automagic-images');
- $page = $this->grav['page'];
- // dump($this->grav->output); exit;
- $config = $this->mergeConfig($page);
- if ($config['enabled']) {
- include __DIR__ . '/vendor/autoload.php';
- $dom = new Dom;
- $dom->loadStr($this->grav->output,
- (new Options())->setCleanupInput(false)
- );
- $images = $dom->find('img');
- $arrClasses = [];
- foreach ($config['sizesattr'] as $array) {
- $arrClasses[$array['class']] = $array['directive'];
- }
- foreach ($images as $image) {
- $sizesattr = "";
- $classes = explode(" ", $image->getAttribute('class'));
- foreach ($classes as $class) {
- if (array_key_exists($class, $arrClasses)) {
- $sizesattr = $arrClasses[$class];
- }
- }
- if ($sizesattr == "") {
- if (array_key_exists('default', $arrClasses)) {
- $sizesattr = $arrClasses['default'];
- }
- }
- if ($sizesattr != "") {
- $image->setAttribute('sizes', $sizesattr);
- }
- }
- $this->grav->output = $dom->outerHtml;
- }
- }
- }
|