| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- <?php
- namespace yiins\web;
- use CHtml;
- use yiins\components\ImageGD;
- use yiins\Yii;
- class Image
- {
- protected $image;
- protected $imageCroppedPath;
- protected $imagePath;
- protected $width;
- protected $height;
- protected $cropRatio;
- protected $nestedDir;
- protected $showWatermark;
- protected $params = [];
- private final function __construct(array $options)
- {
- $this->params = Yii::app()->params['imagephp'] ?? [];
- $this->image = $options['image'] ?? '';
- $this->imagePath = realpath(Yii::web()->uploadSaver->uploadsPath . '/..' . $this->image);
- $this->width = $options['width'] ?? false;
- $this->height = $options['height'] ?? false;
- $this->cropRatio = $options['cropRatio'] ?? false;
- $this->showWatermark = $options['showWatermark'] ?? false;
- $this->croppedImage();
- if ($this->showWatermark && isset($this->params['watermarkPath'])) {
- $this->watermarkedImage($this->imageCroppedPath);
- }
- }
- protected function croppedImage()
- {
- $filename = sha1(basename($this->imagePath) . $this->width . $this->height . $this->cropRatio);
- $path = $this->getNestedDir($filename);
- $this->imageCroppedPath = Yii::web()->uploadSaver->uploadsPath . '/' . $path . '/' . $filename . '.' . $this->getExt();
- if (!file_exists($this->imageCroppedPath)) {
- $this->cropImage();
- }
- }
- protected function getNestedDir($fileName, $depth = 4)
- {
- if (!$this->nestedDir) {
- $len = strlen($fileName);
- $res = [];
- for ($i = 0; $i < $len && $i < $depth * 2; $i += 2) {
- $res[] = substr($fileName, $i, 2);
- @mkdir(Yii::web()->uploadSaver->uploadsPath . '/' . implode('/', $res), 0777);
- }
- $this->nestedDir = implode('/', $res);
- }
- return $this->nestedDir;
- }
- public function getExt()
- {
- $fileNameArr = explode('.', $this->imagePath);
- return array_pop($fileNameArr);
- }
- protected function cropImage()
- {
- // Get the size and MIME type of the requested image
- $size = getImageSize($this->imagePath);
- $width = $size[0];
- $height = $size[1];
- list($maxWidth, $maxHeight) = $this->calculateMaxes($width, $height);
- $offsetX = 0;
- $offsetY = 0;
- list($width, $height, $offsetX, $offsetY) = $this->calculateCrop($width, $height, $offsetX, $offsetY);
- // Setting up the ratios needed for resizing. We will compare these below to determine how to
- // resize the image (based on height or based on width)
- $xRatio = $maxWidth / $width;
- $yRatio = $maxHeight / $height;
- // If either a max width or max height are not specified, we default to something
- // large so the unspecified dimension isn't a constraint on our resized image.
- // If neither are specified but the color is, we aren't going to be resizing at
- // all, just coloring.
- if ($xRatio * $height < $maxHeight) { // Resize the image based on width
- $tnHeight = ceil($xRatio * $height);
- $tnWidth = $maxWidth;
- } else {
- // Resize the image based on height
- $tnWidth = ceil($yRatio * $width);
- $tnHeight = $maxHeight;
- }
- if ((int)ini_get('memory_limit') < 100) {
- ini_set('memory_limit', '100M');
- }
- ImageGD::resize($this->imagePath, $tnWidth, $tnHeight, $offsetX, $offsetY, $width, $height)
- ->quality(100)
- ->output($this->imageCroppedPath);
- }
- protected function calculateMaxes($width, $height)
- {
- $maxWidth = ($this->width !== false) ? (int)$this->width : 0;
- $maxHeight = ($this->height !== false) ? (int)$this->height : 0;
- if (!$maxWidth && $maxHeight) {
- $maxWidth = 99999999999999;
- } elseif ($maxWidth && !$maxHeight) {
- $maxHeight = 99999999999999;
- } elseif (!$maxWidth && !$maxHeight) {
- $maxWidth = $width;
- $maxHeight = $height;
- }
- return [$maxWidth, $maxHeight];
- }
- protected function calculateCrop($width, $height, $offsetX, $offsetY)
- {
- if ($this->cropRatio !== false) {
- $cropRatio = explode(':', (string)$this->cropRatio);
- if (count($cropRatio) == 2) {
- $ratioComputed = $width / $height;
- $cropRatioComputed = (float)$cropRatio[0] / (float)$cropRatio[1];
- if ($ratioComputed < $cropRatioComputed) { // Image is too tall so we will crop the top and bottom
- $origHeight = $height;
- $height = $width / $cropRatioComputed;
- $offsetY = ($origHeight - $height) / 2;
- } else {
- if ($ratioComputed > $cropRatioComputed) { // Image is too wide so we will crop off the left and right sides
- $origWidth = $width;
- $width = $height * $cropRatioComputed;
- $offsetX = ($origWidth - $width) / 2;
- }
- }
- }
- }
- return [$width, $height, $offsetX, $offsetY];
- }
- protected function watermarkedImage($from)
- {
- $filename = sha1(basename($this->imagePath) . $this->width . $this->height . $this->cropRatio . $this->showWatermark);
- $path = $this->getNestedDir($filename);
- $this->imageCroppedPath = Yii::web()->uploadSaver->uploadsPath . '/' . $path . '/' . $filename . '.' . $this->getExt();
- if (!file_exists($this->imageCroppedPath)) {
- $this->watermarkImage($from);
- }
- }
- public function watermarkImage($from)
- {
- if ((int)ini_get('memory_limit') < 100) {
- ini_set('memory_limit', '100M');
- }
- $wmPath = is_callable($this->params['watermarkPath']) ? $this->params['watermarkPath']() : $this->params['watermarkPath'];
- ImageGD::watermark($from, $wmPath,
- $this->params['watermarkPosition'] ?? false)->output($this->imageCroppedPath);
- }
- /**
- * @param string $image
- * @param int|boolean $width
- * @param int|boolean $height
- * @param string|boolean $cropRatio
- * @param array $options
- * @return string
- */
- public static function render($image, $width = false, $height = false, $cropRatio = false, $options = [])
- {
- if (strpos($image, '//') === 0 || preg_match('/https?:/', $image)) {
- return CHtml::image($image, $options['alt'] ?? '', $options);
- }
- if (empty($image) || !file_exists(Yii::web()->uploadSaver->uploadsPath . '/..' . $image)) {
- return '';
- }
- $options = \CMap::mergeArray([
- 'image' => $image,
- 'width' => $width,
- 'height' => $height,
- 'cropRatio' => $cropRatio,
- ], $options);
- return (new static($options))->printHtml($options);
- }
- protected function printHtml($options)
- {
- $alt = '';
- if (isset($options['alt'])) {
- $alt = $options['alt'];
- unset($options['alt']);
- }
- $htmlOptions = [];
- if (isset($options['class'])) {
- $htmlOptions['class'] = $options['class'];
- }
- if (isset($options['style'])) {
- $htmlOptions['style'] = $options['style'];
- }
- return CHtml::image(Yii::web()->baseUrl . '/'
- . ltrim(Yii::web()->uploadSaver->uploadsUrl, '/') . '/'
- . $this->getNestedDir(basename($this->imageCroppedPath)) . '/'
- . basename($this->imageCroppedPath), $alt, $htmlOptions);
- }
- public static function getImageUrl($image, $width = false, $height = false, $cropRatio = false, $options = [])
- {
- if (empty($image) || !file_exists(Yii::web()->uploadSaver->uploadsPath . '/..' . $image)) {
- return '';
- }
- $options = \CMap::mergeArray([
- 'image' => $image,
- 'width' => $width,
- 'height' => $height,
- 'cropRatio' => $cropRatio,
- ], $options);
- return (new static($options))->getUrl();
- }
- protected function getUrl()
- {
- return Yii::web()->baseUrl . '/'
- . ltrim(Yii::web()->uploadSaver->uploadsUrl, '/') . '/'
- . $this->getNestedDir(basename($this->imageCroppedPath)) . '/'
- . basename($this->imageCroppedPath);
- }
- }
|