Last active
March 23, 2017 10:11
-
-
Save noisymask/fd9ca933a89275b1f8d2eb81cb3a5f44 to your computer and use it in GitHub Desktop.
Craft CMS image resizing helper (Twig)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Shortcut wrapper for image resizing on the fly | |
* | |
* Usage: | |
* | |
* {{ image|resize(width, height, mode, position, quality) }} | |
* | |
* e.g. | |
* | |
* {{ image|resize(800, 600) }} | |
* {{ image|resize(320, null, {mode: 'crop'}) }} | |
* {{ image|resize(null, 1080, {mode: 'crop', position: 'top-left', quality: 80}) }} | |
* | |
* {{ image|media() }} | |
* <img src="http://domain.com/img/image.jpg" width="[original width]" height="[original height]" alt="image alt tag"> | |
* | |
* {{ image|media(1440, 700, { attr: { class: 'img-responsive mb3', 'data-name': 'value' } }) }} | |
* <img src="http://domain.com/img/_1440x700_crop_center-center_80/image.jpg" width="1440" height="700" alt="image alt tag" class="img-responsive mb3", data-name="value"> | |
*/ | |
namespace Craft; | |
use Twig_Extension; | |
use Twig_Filter_Method; | |
class ImageHelperExtension extends Twig_Extension | |
{ | |
// resizing modes | |
const MODE_CROP = 'crop'; | |
const MODE_FIT = 'fit'; | |
const MODE_STRETCH = 'stretch'; | |
// cropping positions | |
const POSITION_TOP_LEFT = 'top-left'; | |
const POSITION_TOP_CENTER = 'top-center'; | |
const POSITION_TOP_RIGHT = 'top-right'; | |
const POSITION_CENTER_LEFT = 'center-left'; | |
const POSITION_CENTER_CENTER = 'center-center'; | |
const POSITION_CENTER_RIGHT = 'center-right'; | |
const POSITION_BOTTOM_LEFT = 'bottom-left'; | |
const POSITION_BOTTOM_CENTER = 'bottom-center'; | |
const POSITION_BOTTOM_RIGHT = 'bottom-right'; | |
/** | |
* @return string | |
*/ | |
public function getName() | |
{ | |
return 'ImageHelper'; | |
} | |
/** | |
* @return array | |
*/ | |
public function getFilters() | |
{ | |
return [ | |
'resize' => new Twig_Filter_Method($this, 'resize', [ | |
'is_safe' => ['html'] | |
]), | |
'media' => new Twig_Filter_Method($this, 'media', [ | |
'is_safe' => ['html'] | |
]) | |
]; | |
} | |
/** | |
* Return the url of the (resized) asset | |
* | |
* @param AssetFileModel $file | |
* @param int|null $width | |
* @param int|null $height | |
* @param array $options | |
* @return string | |
*/ | |
public function resize(AssetFileModel $file = null, $width = null, $height = null, $options = []) | |
{ | |
if (!$file instanceof AssetFileModel) { | |
return ''; | |
} | |
$transform = $this->transform($file, $width, $height, $options); | |
return $file->getUrl($transform); | |
} | |
/** | |
* Create a complete <img> element from the (resized) asset | |
* | |
* @param AssetFileModel $file | |
* @param null $width | |
* @param null $height | |
* @param array $options | |
* @return mixed todo - add srcset attributes for hi-res displays | |
* | |
* todo - add srcset attributes for hi-res displays | |
* @internal param int|null $width | |
* @internal param int|null $height | |
*/ | |
public function media(AssetFileModel $file = null, $width = null, $height = null, $options = []) | |
{ | |
if (!$file instanceof AssetFileModel) { | |
return ''; | |
} | |
$attributes = ''; | |
if (isset($options['attr'])) { | |
$attributes = implode(' ', array_map( | |
function ($v, $k) { return sprintf('%s="%s"', $k, $v); }, | |
$options['attr'], | |
array_keys($options['attr']) | |
)); | |
} | |
// no resize, return original | |
if (is_int($width) || is_int($height)) { | |
$transform = $this->transform($file, $width, $height, $options); | |
$file->setTransform($transform); | |
} | |
$img = '<img src="' . $file->getUrl() . '" width="' . $file->getWidth() . '" height="' . $file->getHeight() . '" alt="' . HtmlHelper::encode($file->title) . '" ' . $attributes . ' />'; | |
return TemplateHelper::getRaw($img); | |
} | |
/** | |
* @param AssetFileModel $file | |
* @param $width | |
* @param $height | |
* @param $options | |
* @return array|null|\Twig_Markup | |
*/ | |
private function transform(AssetFileModel $file, $width, $height, $options) | |
{ | |
$mode = isset($options['mode']) ? $options['mode'] : self::MODE_CROP; | |
$position = isset($options['position']) ? $options['position'] : self::POSITION_CENTER_CENTER; | |
$quality = isset($options['quality']) ? $options['quality'] : 90; | |
list($width, $height) = ImageHelper::calculateMissingDimension($width, $height, $file->getWidth(), $file->getHeight()); | |
$transform = [ | |
'mode' => $this->mode($mode), | |
'width' => $width, | |
'height' => $height, | |
'quality' => (int)$quality | |
]; | |
if ($mode == self::MODE_CROP) { | |
$transform['position'] = $this->position($position); | |
} | |
return $transform; | |
} | |
/** | |
* Validate resize mode | |
* | |
* @param $mode | |
* @return mixed | |
* @throws \InvalidArgumentException | |
*/ | |
private function mode($mode) | |
{ | |
if (!in_array($mode, [ | |
self::MODE_CROP, | |
self::MODE_FIT, | |
self::MODE_STRETCH | |
])) { | |
throw new \InvalidArgumentException('Invalid resize mode: '.(string)$mode); | |
} | |
return $mode; | |
} | |
/** | |
* Validate crop position | |
* | |
* @param $position | |
* @return mixed | |
* @throws \InvalidArgumentException | |
*/ | |
private function position($position) | |
{ | |
if (!in_array($position, [ | |
self::POSITION_TOP_LEFT, | |
self::POSITION_TOP_CENTER, | |
self::POSITION_TOP_RIGHT, | |
self::POSITION_CENTER_LEFT, | |
self::POSITION_CENTER_CENTER, | |
self::POSITION_CENTER_RIGHT, | |
self::POSITION_BOTTOM_LEFT, | |
self::POSITION_BOTTOM_CENTER, | |
self::POSITION_BOTTOM_RIGHT | |
])) { | |
throw new \InvalidArgumentException('Invalid crop position: '.(string)$position); | |
} | |
return $position; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment