setCrop($options['crop']); } if (!empty($options['lazy_load'])) { $this->setLazyLoad($options['lazy_load']); } } /** * * get file name * * @return string */ public function getName() { return $this->_name; } /** * * set file name * * @param string $name * * @return $this */ public function setName($name) { $name = preg_replace("/[^a-zA-Z0-9_-]/", '', $name); $this->_name = (string)$name; return $this; } /** * * get file extension * * @return string */ public function getExtension() { return $this->_extension; } /** * * set file extension * * @param string $extension * * @return $this */ public function setExtension($extension) { if (!in_array($extension, $this->_extensions)) { $extension = self::DEFAULT_EXTENSION; } $this->_extension = (string)$extension; return $this; } /** * * get destination thumbnail width * * @return integer */ public function getWidth() { return $this->_width; } /** * * set destination thumbnail width * * @param int $width * * @return $this */ public function setWidth($width) { $width = intval($width); if ($width < self::MIN_WIDTH) { $width = self::MIN_WIDTH; } if ($width > self::MAX_WIDTH && self::MAX_WIDTH > 0) { $width = self::MAX_WIDTH; } $this->_width = $width; return $this; } /** * * get destination thumbnail height * * @return bool */ public function getHeight() { return $this->_height; } /** * * set destination thumbnail height * * @param integer|boolean $height * * @return $this */ public function setHeight($height = true) { $this->_height = $height; return $this; } /** * * set square option (legacy method) * * @param bool $square * * @return $this */ public function setSquare($square = true) { $this->setHeight((bool)$square); return $this; } /** * * get crop option * * @return boolean */ public function getCrop() { return $this->_crop; } /** * * set crop option * * @param boolean $crop * * @return $this */ public function setCrop($crop = true) { $this->_crop = (bool)$crop; return $this; } /** * * check lazy load plugin flag * * @return bool */ public function isLazyLoad() { return $this->_lazyLoad; } /** * * set lazy load plugin flag * * @param bool $lazyLoad * * @return $this */ public function setLazyLoad($lazyLoad) { $this->_lazyLoad = $lazyLoad; return $this; } /** * * get base url * * @return string */ public function getBaseUrl() { if ($this->_baseUrl === null) { $this->setBaseUrl( Front::getInstance()->getRequest()->getBaseUrl()); } return $this->_baseUrl; } /** * * set base url * * @param string $baseUrl * * @return $this */ public function setBaseUrl($baseUrl) { $this->_baseUrl = $baseUrl; return $this; } /** * * generate cached thumbnail and return image link * (has backwards compatibility for v6's uplimg folder) * * @param string $image * @param int|null $width * @param bool|int|null $height * @param array $params * * @return string */ public function generateLink($image, $width = null, $height = null, $params = array()) { $this->setWidth($width) ->setHeight($height); $type = (isset($params['type'])) ? $params['type'] : Service\ListingsMedia::TYPE_IMAGE; $crop = (isset($params['crop'])) ? $params['crop'] : null; switch ($type) { case Service\ListingsMedia::TYPE_VIDEO: $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::VIDEO_PLACEHOLDER; break; case Service\ListingsMedia::TYPE_DOWNLOAD: $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::DOWNLOAD_PLACEHOLDER; break; case Service\ListingsMedia::TYPE_CSV: $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::CSV_PLACEHOLDER; break; default: if ($image == null) { $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::IMAGE_PLACEHOLDER; } else { if (!preg_match('#^http(s)?://(.*)+$#i', $image) && !preg_match('#^uplimg/(.*)+$#i', $image)) { $image = \Ppb\Utility::getFolder('uploads') . \Ppb\Utility::URI_DELIMITER . $image; } } break; } return $this->getBaseUrl() . \Ppb\Utility::URI_DELIMITER . \Ppb\Utility::getFolder('cache') . \Ppb\Utility::URI_DELIMITER . $this->_generateThumb($image, $crop); } /** * * generates a path to a media file * if we have a remote image or a v6 image, return the path unmodified * * @param string $image * * @return string */ public function generateImagePath($image) { if (preg_match('#^uplimg/(.*)+$#i', $image)) { // we have a v6 image - add base url return $this->getBaseUrl() . '/' . $image; } else if (!preg_match('#^http(s)?://(.*)+$#i', $image)) { // we have a v7 image - add base url and uploads folder return $this->getBaseUrl() . \Ppb\Utility::URI_DELIMITER . \Ppb\Utility::getFolder('uploads') . \Ppb\Utility::URI_DELIMITER . $image; } return $image; } /** * * check whether the uploaded file is an image * * @param string $fileName * * @return bool */ public function isImage($fileName) { $fileInfo = @getimagesize($fileName); if ($fileInfo === false || $fileInfo[2] > 3) { return false; } return true; } /** * * output image using corresponding function based on mime * * @param mixed $output * @param string $fileName * @param string $mime * * @return $this */ public function imageOutputFunction($output, $fileName, $mime = null) { if ($mime === null) { $imgInfo = @getimagesize($fileName); $mime = $imgInfo['mime']; } switch ($mime) { case 'image/gif': $imageOutputFunction = 'imagegif'; break; case 'image/png': $imageOutputFunction = 'imagepng'; break; default: $imageOutputFunction = 'imagejpeg'; break; } touch($fileName); $imageOutputFunction($output, $fileName); imagedestroy($output); return $this; } /** * * image create function based on source image type * * @param string $fileName * @param string $mime * * @return mixed */ public function imageCreateFunction($fileName, $mime = null) { if ($mime === null) { $imgInfo = @getimagesize($fileName); $mime = $imgInfo['mime']; } switch ($mime) { case 'image/gif': $imageCreateFunction = 'ImageCreateFromGIF'; break; case 'image/png': $imageCreateFunction = 'ImageCreateFromPNG'; break; default: $imageCreateFunction = 'ImageCreateFromJPEG'; break; } return $imageCreateFunction($fileName); } /** * * create resized image * * @param string $srcImage * @param bool|null $crop * * @return resource */ public function createResizedImage($srcImage, $crop = null) { $fileName = null; $imgInfo = @getimagesize($srcImage); list($srcWidth, $srcHeight, $imgType) = $imgInfo; if ($imgInfo === false || $imgType > 3) { $srcImage = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::BROKEN_IMAGE; $imgInfo = @getimagesize($srcImage); list($srcWidth, $srcHeight, $imgType) = $imgInfo; } if ($crop === null) { $crop = $this->getCrop(); } $dstWidth = $tmpWidth = $this->getWidth(); $dstHeight = $this->getHeight(); $tmpHeight = round(($dstWidth * $srcHeight) / $srcWidth); if ($dstHeight === true) { $dstHeight = $dstWidth; } else if (!is_numeric($dstHeight)) { $dstHeight = $tmpHeight; } $image = $this->imageCreateFunction($srcImage, $imgInfo['mime']); if (!$image) { $output = imagecreate($dstWidth, $dstHeight); /* Create a blank image */ $white = imagecolorallocate($output, 255, 255, 255); $black = imagecolorallocate($output, 0, 0, 0); imagefilledrectangle($output, 0, 0, 150, 30, $white); imagestring($output, 1, 5, 5, 'Error loading ' . $srcImage, $black); /* Output an error message */ } else { $srcAspect = $srcWidth / $srcHeight; $dstAspect = $dstWidth / $dstHeight; /** * cropping is disabled if source image has at least one side smaller than the destination image */ if ($srcHeight < $dstHeight || $srcWidth < $dstWidth) { $crop = false; } /** * if crop, then cut to fit, otherwise add white background to fit */ if (($crop && ($srcAspect > $dstAspect)) || (!$crop && ($srcAspect < $dstAspect))) { $tmpHeight = $dstHeight; $tmpWidth = round($dstHeight * $srcAspect); } else { $tmpWidth = $dstWidth; $tmpHeight = round($dstWidth / $srcAspect); } /** * first we resize original image to desired dimensions */ $resized = imagecreatetruecolor($tmpWidth, $tmpHeight); $backgroundColor = imagecolorallocate($resized, 255, 255, 255); imagefill($resized, 0, 0, $backgroundColor); imagecopyresampled( $resized, $image, 0, 0, 0, 0, $tmpWidth, $tmpHeight, $srcWidth, $srcHeight ); $output = imagecreatetruecolor($dstWidth, $dstHeight); /** * now we either crop or add white background and output resulting image */ if ($crop) { $srcX = ($tmpWidth - $dstWidth) / 2; $srcY = ($tmpHeight - $dstHeight) / 2; imagecopy( $output, $resized, 0, 0, $srcX, $srcY, $dstWidth, $dstHeight ); } else { $backgroundColor = imagecolorallocate($output, 255, 255, 255); imagefill($output, 0, 0, $backgroundColor); $dstX = ($dstWidth - $tmpWidth) / 2; $dstY = ($dstHeight - $tmpHeight) / 2; imagecopy( $output, $resized, $dstX, $dstY, 0, 0, $tmpWidth, $tmpHeight ); } } return $output; } /** * * rotate uploaded image automatically based on exif orientation * * @param string $fileName * * @return $this */ public function imageSmartRotate($fileName) { $output = null; if (function_exists('exif_read_data')) { $exif = @exif_read_data($fileName); if (!empty($exif['Orientation'])) { $image = $this->imageCreateFunction($fileName); switch ($exif['Orientation']) { case 3: $output = imagerotate($image, 180, 255); break; case 6: $output = imagerotate($image, -90, 255); break; case 8: $output = imagerotate($image, 90, 255); break; } if ($output !== null) { $this->imageOutputFunction($output, $fileName); } } } return $this; } /** * * add watermark to the image * * @param string $fileName * @param string $watermarkText * * @return $this */ public function addWatermark($fileName, $watermarkText) { if ($this->isImage($fileName)) { $output = $this->imageCreateFunction($fileName); // Get identifier for white $white = imagecolorallocate($output, 255, 255, 255); // Add text to image imagestring($output, 20, 5, imagesy($output) - 20, $watermarkText, $white); // Save the image to file and free memory $this->imageOutputFunction($output, $fileName); } return $this; } /** * * the helper will display a thumbnail image, * or in case media is uploaded, it will add a default thumbnail * * @param string $image * @param int $width * @param string $square (Y|N|null) * @param array $params (reserved params: zoom, crop) * * @return mixed */ public function thumbnail($image = null, $width = null, $square = null, $params = array()) { $dataSrc = null; if ($image === null && $width === null && $square === null) { return $this; } $zoom = (isset($params['zoom'])) ? $params['zoom'] : false; if ($zoom === true) { $dataSrc = 'data-src="' . $this->generateImagePath($image) . '" '; // add js /** @var \Cube\View\Helper\Script $helper */ $helper = $this->getView()->getHelper('script'); $helper->addBodyCode('') ->addBodyCode(""); } $lazyLoad = (isset($params['lazyLoad']) && $this->isLazyLoad()) ? $params['lazyLoad'] : false; if (!array_key_exists('class', $params)) { $params['class'] = 'img-thumbnail img-responsive'; } $src = $this->generateLink($image, $width, $square, $params); if ($lazyLoad === true) { // add js /** @var \Cube\View\Helper\Script $helper */ $helper = $this->getView()->getHelper('script'); $helper->addBodyCode('') ->addBodyCode(''); $params['class'] .= ((!empty($params['class'])) ? ' ' : '') . 'b-lazy'; $dataSrc = 'data-src="' . $src . '" '; $src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; } foreach ($params as $key => $value) { if (!in_array($key, $this->_reservedParams)) { $dataSrc .= $key . '="' . str_replace('"', '', $value) . '" '; } } return '_endTag; } /** * * generate cache file name * * @param string $name * @param bool|null $crop * * @return string */ protected function _generateCacheName($name, $crop = null) { $extension = $this->getExtension(); $height = $this->getHeight(); $width = $this->getWidth(); if ($height === true) { $height = $width; } if ($crop === null) { $crop = $this->getCrop(); } return $name . '-' . $width . (($height !== null) ? 'x' . $height : '') . (($crop === true) ? '-' . 'crop' : '') . '.' . $extension; } /** * * generates a thumbnail of a given image, using the width and height parameters * * @param string $image * @param bool|null $crop * * @return string */ protected function _generateThumb($image, $crop = null) { $fileName = null; $pathInfo = pathinfo($image); $baseName = (isset($pathInfo['filename'])) ? $pathInfo['filename'] : null; $extension = (isset($pathInfo['extension'])) ? $pathInfo['extension'] : null; if (preg_match('#^http(s)?://(.*)+$#i', $image)) { $baseName = preg_replace('/[^\da-z]/i', '', $image); } $this->setName($baseName) ->setExtension($extension); $cacheName = $this->_generateCacheName($baseName, $crop); $cacheFilePath = \Ppb\Utility::getPath('cache') . DIRECTORY_SEPARATOR . $cacheName; if (file_exists($cacheFilePath)) { return $cacheName; } else { $output = $this->createResizedImage($image, $crop); $this->imageOutputFunction($output, $cacheFilePath); $fileName = $cacheName; return $fileName; } } }