setLazy(true); } if ($imagePath == $imageUrl) { // The image is not local if (!$resizeRemote) { return $originalImageUrl; } $pathInfo = pathinfo(parse_url($imageUrl, PHP_URL_PATH)); $extension = false; if (isset($pathInfo['extension'])) { $extension = self::validateGDExtension($pathInfo['extension']); } $extension = self::checkMetaExtension($originalImageUrl, $extension); if (!$extension) { return $originalImageUrl; } if (strtolower($extension) === 'webp' && !function_exists('imagecreatefromwebp')) { return $originalImageUrl; } $resizedPath = $cache->makeCache($extension, array( self::class, '_resizeRemoteImage' ), array( $extension, $imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y )); if (substr($resizedPath, 0, 5) == 'http:' || substr($resizedPath, 0, 6) == 'https:') { return $resizedPath; } if ($resizedPath === $originalImageUrl) { return $originalImageUrl; } return Filesystem::pathToAbsoluteURL($resizedPath); } else { $extension = false; $imageType = @self::exif_imagetype($imagePath); switch ($imageType) { case IMAGETYPE_JPEG: $extension = 'jpg'; break; case IMAGETYPE_PNG: if (self::isPNG8($imagePath)) { // GD cannot resize palette PNG so we return the original image return $originalImageUrl; } $extension = 'png'; break; case IMAGETYPE_WEBP: if (!function_exists('imagecreatefromwebp')) { return $originalImageUrl; } $extension = 'webp'; break; } if (!$extension) { return $originalImageUrl; } return Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array( self::class, '_resizeImage' ), array( $extension, $imagePath, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y ))); } } public static function _resizeRemoteImage($targetFile, $extension, $imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y) { return self::_resizeImage($targetFile, $extension, $imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y); } public static function _resizeImage($targetFile, $extension, $imagePath, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality = 100, $optimize = false, $x = 50, $y = 50) { $targetDir = dirname($targetFile); $rotated = false; if ($extension == 'png') { $image = @imagecreatefrompng($imagePath); } else if ($extension == 'jpg') { $image = @imagecreatefromjpeg($imagePath); if (function_exists("exif_read_data")) { $exif = @exif_read_data($imagePath); $rotated = self::getOrientation($exif, $image); if ($rotated) { imagedestroy($image); $image = $rotated; } } } else if ($extension == 'webp') { //@TODO: should we need to care about rotation? $image = @imagecreatefromwebp($imagePath); } if (isset($image) && $image) { $originalWidth = imagesx($image); $originalHeight = imagesy($image); if ($optimize) { if ($originalWidth <= $targetWidth || $originalHeight <= $targetHeight) { if (!Filesystem::existsFolder($targetDir)) { Filesystem::createFolder($targetDir); } if ($extension == 'png') { imagesavealpha($image, true); imagealphablending($image, false); imagepng($image, $targetFile); } else if ($extension == 'jpg') { imagejpeg($image, $targetFile, $quality); } else if ($extension == 'webp') { imagesavealpha($image, true); imagealphablending($image, false); imagewebp($image, $targetFile, $quality); } imagedestroy($image); return true; } if ($originalWidth / $targetWidth > $originalHeight / $targetHeight) { $targetWidth = round($originalWidth / ($originalHeight / $targetHeight)); } else { $targetHeight = round($originalHeight / ($originalWidth / $targetWidth)); } } if ($rotated || $originalWidth != $targetWidth || $originalHeight != $targetHeight) { $newImage = imagecreatetruecolor($targetWidth, $targetHeight); if ($extension == 'png' || $extension == 'webp') { imagesavealpha($newImage, true); imagealphablending($newImage, false); $transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127); imagefilledrectangle($image, 0, 0, $targetWidth, $targetHeight, $transparent); } else if ($extension == 'jpg' && $backgroundColor) { $rgb = Color::hex2rgb($backgroundColor); $background = imagecolorallocate($newImage, $rgb[0], $rgb[1], $rgb[2]); imagefilledrectangle($newImage, 0, 0, $targetWidth, $targetHeight, $background); } list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = self::imageMode($targetWidth, $targetHeight, $originalWidth, $originalHeight, $mode, $x, $y); imagecopyresampled($newImage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); imagedestroy($image); } else { $newImage = $image; } if (!Filesystem::existsFolder($targetDir)) { Filesystem::createFolder($targetDir); } if ($extension == 'png') { imagepng($newImage, $targetFile); } else if ($extension == 'jpg') { imagejpeg($newImage, $targetFile, $quality); } else if ($extension == 'webp') { imagewebp($newImage, $targetFile, $quality); } imagedestroy($newImage); return true; } throw new Exception('Unable to resize image: ' . $imagePath); } public static function scaleImage($group, $imageUrlOrPath, $scale = 1, $resizeRemote = false, $quality = 100) { if (strpos($imageUrlOrPath, Filesystem::getBasePath()) === 0) { $imageUrl = Url::pathToUri($imageUrlOrPath); } else { $imageUrl = ResourceTranslator::toUrl($imageUrlOrPath); } if (!extension_loaded('gd') || $scale <= 0) { return $imageUrl; } $quality = max(0, min(100, $quality)); $originalImageUrl = $imageUrl; if (substr($imageUrl, 0, 2) == '//') { $imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) . ':' . $imageUrl; } $imageUrl = Url::relativetoabsolute($imageUrl); $imagePath = Filesystem::absoluteURLToPath($imageUrl); $cache = new CacheImage($group); if ($imagePath == $imageUrl) { // The image is not local if (!$resizeRemote) { return $originalImageUrl; } $pathInfo = pathinfo(parse_url($imageUrl, PHP_URL_PATH)); $extension = false; if (isset($pathInfo['extension'])) { $extension = self::validateGDExtension($pathInfo['extension']); } $extension = self::checkMetaExtension($imageUrl, $extension); if (!$extension) { return $originalImageUrl; } if (strtolower($extension) === 'webp' && !function_exists('imagecreatefromwebp')) { return $originalImageUrl; } return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array( self::class, '_scaleRemoteImage' ), array( $extension, $imageUrl, $scale, $quality )))); } else { $extension = false; $imageType = @self::exif_imagetype($imagePath); switch ($imageType) { case IMAGETYPE_JPEG: $extension = 'jpg'; break; case IMAGETYPE_PNG: if (self::isPNG8($imagePath)) { // GD cannot resize palette PNG so we return the original image return $originalImageUrl; } $extension = 'png'; break; case IMAGETYPE_WEBP: if (!function_exists('imagecreatefromwebp')) { return $originalImageUrl; } $extension = 'webp'; break; } if (!$extension) { return $originalImageUrl; } return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array( self::class, '_scaleImage' ), array( $extension, $imagePath, $scale, $quality )))); } } public static function _scaleRemoteImage($targetFile, $extension, $imageUrl, $scale, $quality) { return self::_scaleImage($targetFile, $extension, $imageUrl, $scale, $quality); } public static function _scaleImage($targetFile, $extension, $imagePath, $scale, $quality = 100) { $targetDir = dirname($targetFile); $image = false; if ($extension == 'png') { $image = @imagecreatefrompng($imagePath); } else if ($extension == 'jpg') { $image = @imagecreatefromjpeg($imagePath); if (function_exists("exif_read_data")) { $exif = @exif_read_data($imagePath); $rotated = self::getOrientation($exif, $image); if ($rotated) { imagedestroy($image); $image = $rotated; } } } else if ($extension == 'webp') { //@TODO: should we need to care about rotation? $image = @imagecreatefromwebp($imagePath); } if ($image) { $originalWidth = imagesx($image); $originalHeight = imagesy($image); $targetWidth = $originalWidth * $scale; $targetHeight = $originalHeight * $scale; if ((isset($rotated) && $rotated) || $originalWidth != $targetWidth || $originalHeight != $targetHeight) { $newImage = imagecreatetruecolor($targetWidth, $targetHeight); if ($extension == 'png' || $extension == 'webp') { imagesavealpha($newImage, true); imagealphablending($newImage, false); $transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127); imagefilledrectangle($image, 0, 0, $targetWidth, $targetHeight, $transparent); } list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = self::imageMode($targetWidth, $targetHeight, $originalWidth, $originalHeight); imagecopyresampled($newImage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); imagedestroy($image); } else { $newImage = $image; } if (!Filesystem::existsFolder($targetDir)) { Filesystem::createFolder($targetDir); } if ($extension == 'png') { imagepng($newImage, $targetFile); } else if ($extension == 'jpg') { imagejpeg($newImage, $targetFile, $quality); } else if ($extension == 'webp') { imagewebp($newImage, $targetFile, $quality); } imagedestroy($newImage); return true; } throw new Exception('Unable to scale image: ' . $imagePath); } private static function getOrientation($exif, $image) { if ($exif && !empty($exif['Orientation'])) { $rotated = false; switch ($exif['Orientation']) { case 3: $rotated = imagerotate($image, 180, 0); break; case 6: $rotated = imagerotate($image, -90, 0); break; case 8: $rotated = imagerotate($image, 90, 0); break; } return $rotated; } return false; } private static function imageMode($width, $height, $originalWidth, $OriginalHeight, $mode = 'cover', $x = 50, $y = 50) { $dst_x = 0; $dst_y = 0; $src_x = 0; $src_y = 0; $dst_w = $width; $dst_h = $height; $src_w = $originalWidth; $src_h = $OriginalHeight; $horizontalRatio = $width / $originalWidth; $verticalRatio = $height / $OriginalHeight; if ($horizontalRatio > $verticalRatio) { $new_h = round($horizontalRatio * $OriginalHeight); $dst_y = round(($height - $new_h) / 2 * $y / 50); $dst_h = $new_h; } else { $new_w = round($verticalRatio * $originalWidth); $dst_x = round(($width - $new_w) / 2 * $x / 50); $dst_w = $new_w; } return array( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); } private static function validateGDExtension($extension) { static $validExtensions = array( 'png' => 'png', 'jpg' => 'jpg', 'jpeg' => 'jpg', 'gif' => 'gif', 'webp' => 'webp', 'svg' => 'svg' ); $extension = strtolower($extension); if (isset($validExtensions[$extension])) { return $validExtensions[$extension]; } return false; } private static function validateExtension($extension) { static $validExtensions = array( 'png' => 'png', 'jpg' => 'jpg', 'jpeg' => 'jpg', 'gif' => 'gif', 'webp' => 'webp', 'svg' => 'svg' ); $extension = strtolower($extension); if (isset($validExtensions[$extension])) { return $validExtensions[$extension]; } return false; } public static function base64Transparent() { return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; } public static function base64($imagePath, $image) { $pathInfo = pathinfo(parse_url($imagePath, PHP_URL_PATH)); $extension = self::validateExtension($pathInfo['extension']); if ($extension) { return 'data:image/' . $extension . ';base64,' . Base64::encode(Filesystem::readFile($imagePath)); } return ResourceTranslator::toUrl($image); } public static function exif_imagetype($filename) { if (!function_exists('exif_imagetype')) { if ((list($width, $height, $type, $attr) = getimagesize($filename)) !== false) { return $type; } return false; } return exif_imagetype($filename); } public static function isPNG8($path) { $fp = fopen($path, 'r'); fseek($fp, 25); $data = fgets($fp, 2); fclose($fp); if (ord($data) == 3) { return true; } return false; } public static function scaleImageWebp($group, $imageUrlOrPath, $options) { $options = array_merge(array( 'mode' => 'scale', 'scale' => 1, 'quality' => 100, 'remote' => false ), $options); if (strpos($imageUrlOrPath, Filesystem::getBasePath()) === 0) { $imageUrl = Url::pathToUri($imageUrlOrPath); } else { $imageUrl = ResourceTranslator::toUrl($imageUrlOrPath); } if (!extension_loaded('gd') || $options['mode'] === 'scale' && $options['scale'] <= 0) { return Filesystem::pathToAbsoluteURL($imageUrl); } $options['quality'] = max(0, min(100, $options['quality'])); $originalImageUrl = $imageUrl; if (substr($imageUrl, 0, 2) == '//') { $imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) . ':' . $imageUrl; } $imageUrl = Url::relativetoabsolute($imageUrl); $imagePath = Filesystem::absoluteURLToPath($imageUrl); $cache = new CacheImage($group); if ($imagePath == $imageUrl) { // The image is not local if (!$options['remote']) { return $originalImageUrl; } $pathInfo = pathinfo(parse_url($imageUrl, PHP_URL_PATH)); $extension = false; if (isset($pathInfo['extension'])) { $extension = self::validateGDExtension($pathInfo['extension']); } $extension = self::checkMetaExtension($imageUrl, $extension); if (!$extension || (strtolower($extension) === 'webp' && !function_exists('imagecreatefromwebp')) || !ini_get('allow_url_fopen')) { return $originalImageUrl; } return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache('webp', array( self::class, '_scaleRemoteImageWebp' ), array( $extension, $imageUrl, $options )))); } else { $extension = false; $imageType = @self::exif_imagetype($imagePath); switch ($imageType) { case IMAGETYPE_JPEG: $extension = 'jpg'; break; case IMAGETYPE_PNG: $extension = 'png'; break; case IMAGETYPE_WEBP: if (!function_exists('imagecreatefromwebp')) { return $originalImageUrl; } $extension = 'webp'; break; } if (!$extension) { return $originalImageUrl; } return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache('webp', array( self::class, '_scaleImageWebp' ), array( $extension, $imagePath, $options )))); } } public static function _scaleRemoteImageWebp($targetFile, $extension, $imageUrl, $options) { return self::_scaleImageWebp($targetFile, $extension, $imageUrl, $options); } public static function _scaleImageWebp($targetFile, $extension, $imagePath, $options) { $options = array_merge(array( 'focusX' => 50, 'focusY' => 50, ), $options); $targetDir = dirname($targetFile); $image = false; if ($extension == 'png') { $image = @imagecreatefrompng($imagePath); if (!imageistruecolor($image)) { imagepalettetotruecolor($image); imagealphablending($image, true); imagesavealpha($image, true); } } else if ($extension == 'jpg') { $image = @imagecreatefromjpeg($imagePath); if (function_exists("exif_read_data")) { $exif = @exif_read_data($imagePath); $rotated = self::getOrientation($exif, $image); if ($rotated) { imagedestroy($image); $image = $rotated; } } } else if ($extension == 'webp') { //@TODO: should we need to care about rotation? $image = @imagecreatefromwebp($imagePath); if (!imageistruecolor($image)) { imagepalettetotruecolor($image); imagealphablending($image, true); imagesavealpha($image, true); } } if ($image) { $originalWidth = imagesx($image); $originalHeight = imagesy($image); switch ($options['mode']) { case 'scale': $targetWidth = round($originalWidth * $options['scale']); $targetHeight = round($originalHeight * $options['scale']); break; case 'resize': $targetWidth = $options['width']; $targetHeight = $options['height']; break; } if ((isset($rotated) && $rotated) || $originalWidth != $targetWidth || $originalHeight != $targetHeight) { $newImage = imagecreatetruecolor($targetWidth, $targetHeight); if ($extension == 'png') { imagesavealpha($newImage, true); imagealphablending($newImage, false); $transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127); imagefilledrectangle($image, 0, 0, $targetWidth, $targetHeight, $transparent); } list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = self::imageMode($targetWidth, $targetHeight, $originalWidth, $originalHeight, 'cover', $options['focusX'], $options['focusY']); imagecopyresampled($newImage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); imagedestroy($image); } else { $newImage = $image; } if (!Filesystem::existsFolder($targetDir)) { Filesystem::createFolder($targetDir); } imagewebp($newImage, $targetFile, $options['quality']); imagedestroy($newImage); return true; } throw new Exception('Unable to scale image: ' . $imagePath); } public static function checkMetaExtension($imageUrl, $originalExtension) { if (strpos($imageUrl, 'dst-jpg') !== false) { return 'jpg'; } else if (strpos($imageUrl, 'dst-png') !== false) { return 'png'; } else if (strpos($imageUrl, 'dst-webp') !== false) { return 'webp'; } else { // not Instagram or Facebook url return $originalExtension; } } }