'inner', 'g' => 'inner_gray', 'o' => 'outer', 'og' => 'outer_gray', 'cf' => 'cropFirst', // crop top or left part 'cfg' => 'cropFirst_gray', 'cc' => 'cropCenter', // crop middle or center part 'ccg' => 'cropCenter_gray', 'cl' => 'cropLast', // crop bottom or right part 'clg' => 'cropLast_gray' ); public static function setAdapter($name) { if (!in_array($name, array('im', 'gd'))) { throw new Qs_Exception('Invalid Adapter: ' . $name); } Qs_ImageFs::$_adapter = $name; } public static function get($name, $width = 0, $height = 0, $method = 'inner') { $fullName = WWW_PATH . '/' . Qs_ImageFs::WEB_PATH . '/' . $name; if (empty($name) || !file_exists($fullName)) { Qs_ImageFs::_initNotAvailable(); $name = Qs_ImageFs::NOT_AVAILABLE; } $width = intval($width); $height = intval($height); if ($width || $height){ $file = Qs_ImageFs::getIconName(Qs_ImageFs::WEB_PATH_RESIZE . '/' . $name, $width, $height, $method); $file = dirname($file) . '/' . rawurlencode(basename($file)); return $file; } $url = Qs_ImageFs::WEB_PATH . '/'; if ('.' != dirname($name)) { $url .= dirname($name) . '/'; } $url .= rawurlencode(basename($name)); return $url; } public static function getFull($name, $width = 0, $height = 0, $method = 'inner') { $attribs = Qs_ImageFs::getFullAttribs($name, $width, $height, $method); return ' ' . Qs_ImageFs::renderAttribs($attribs); } public static function renderAttribs(array $attribs) { $items = array(); foreach ($attribs as $name => $value) { if(!is_array($value)) { $value = preg_replace('!&(#?\w+);!', '%%%QS_START%%%\\1%%%QS_END%%%', $value); $value = htmlspecialchars($value); $value = str_replace(array('%%%QS_START%%%','%%%QS_END%%%'), array('&',';'), $value); } else { continue; } $items[] = $name . '="' . $value . '"'; } return implode(' ', $items); } public static function getFullAttribs($name, $width = 0, $height = 0, $method = 'inner') { $width = intval($width); $height = intval($height); $fullName = WWW_PATH . '/' . Qs_ImageFs::WEB_PATH . '/' . $name; if (empty($name) || !file_exists($fullName)) { Qs_ImageFs::_initNotAvailable(); $fullName = WWW_PATH . '/' . Qs_ImageFs::WEB_PATH . '/' . Qs_ImageFs::NOT_AVAILABLE; $name = Qs_ImageFs::NOT_AVAILABLE; } if (!$width && !$height) { $iconName = Qs_ImageFs::WEB_PATH . '/' . $name; $info = Qs_ImageFs::getInfo($iconName); $attribs = array( 'src' => Qs_ImageFs::get($name, $width, $height, $method), ); foreach (array('width', 'height') as $_name) { if (array_key_exists($_name, $info)) { $attribs[$_name] = $info[$_name]; } } return $attribs; } $iconName = Qs_ImageFs::get($name, $width, $height, $method); $size = Qs_ImageFs::getNewSize($fullName, $width, $height, $method); if (isset($size['crop'])) { return array( 'src' => $iconName, 'width' => $size['crop']['width'], 'height' => $size['crop']['height'] ); } return array( 'src' => $iconName, 'width' => $size['width'], 'height' => $size['height'] ); } protected static function _initNotAvailable() { $file = WWW_PATH . '/' . Qs_ImageFs::WEB_PATH . '/' . Qs_ImageFs::NOT_AVAILABLE; if (!file_exists($file)) { $source = WWW_PATH . '/' . Qs_ImageFs::WEB_PATH_STATIC . '/' . Qs_ImageFs::NOT_AVAILABLE; copy($source, $file); } } public static function getUrl($name, $width = 0, $height = 0, $method = 'inner') { return BASE_URL_LANGUAGE . '/' . Qs_ImageFs::get($name, $width, $height, $method); } public static function getThumbnailInfo($iconName) { $info = array( 'file' => $iconName, 'width' => 0, 'height' => 0, ); if (false !== strpos($iconName, 'x')) { $matches = array(); preg_match(Qs_ImageFs::$_thumbnailPattern, $iconName, $matches); $methodKey = !empty($matches[3]) ? $matches[3] : ''; $method = Qs_Array::get(Qs_ImageFs::$_methods, $methodKey, 'inner'); $width = intval(isset($matches[1]) ? $matches[1] : 0); $height = intval(isset($matches[2]) ? $matches[2] : 0); if ($width || $height) { $pathParts = pathinfo($iconName); if (isset($pathParts['extension'])) { $nameWww = substr($iconName, 0, - (1 + strlen($pathParts['extension']))); $nameLen = strrpos($nameWww, '_'); $name = substr($nameWww, 0, $nameLen) . '.' . $pathParts['extension']; } else { $name = substr($iconName, 0, strrpos($iconName, '_')); } $info = array( 'file' => $name, 'width' => intval($width), 'height' => intval($height), 'method' => $method, ); } } return $info; } public static function parse($options) { $matches = array(); preg_match(Qs_ImageFs::$_optionsPattern, $options, $matches); array_shift($matches); $width = array_shift($matches); $height = array_shift($matches); $methodKey = array_shift($matches); $method = Qs_ImageFs::$_methods[$methodKey]; return compact('width', 'height' ,'method'); } public static function getIconName($fileName, $width, $height, $method = 'inner') { $width = intval($width); $height = intval($height); $parts = pathinfo((string)$fileName); $methodAlias = Qs_ImageFs::getResizeMethodAlias($method); if (strpos($parts['basename'], '.') === false) { $iconName = $parts['basename'] . '_' . $width . 'x' . $height . $methodAlias; } else { $extLen = strlen($parts['extension']); $name = substr($parts['basename'], 0, - ($extLen + 1)); $iconName = $name . '_' . $width . 'x' . $height . $methodAlias . '.' . $parts['extension']; } if ($parts['dirname'] == '.') { return $iconName; } return "{$parts['dirname']}/{$iconName}"; } public static function getResizeMethodAlias($method) { return array_search($method, Qs_ImageFs::$_methods); } public static function getInfo($name) { $res = getimagesize($name); if ($res !== false) { $res['width'] = $res[0]; $res['height'] = $res[1]; $res['type'] = $res[2]; $res['attr'] = $res[3]; } else { $res = array(); } return $res; } public static function resize($source, $options) { if (!is_file($source)) { return false; } $force = false; $method = 'inner'; $width = 0; $height = 0; $quality = Qs_ImageFs::$_quality; $symlink = true; // true - create symlink; false - copy file $destination = null; if (is_string($options)) { $options = Qs_ImageFs::parse($options); } extract($options); if (null == $destination) { $destination = Qs_ImageFs::getIconName($source, $width, $height, $method); } $path = dirname($destination); if (!is_dir($path)) { umask(0); mkdir($path, 0777, true); } $width = (int) $width; $height = (int) $height; $quality = (int) $quality; $info = Qs_ImageFs::getInfo($source); if ((empty($info) || (!$height && !$width) || ($width == $info['width'] && $height == $info['height']) || ($width >= $info['width'] && $height >= $info['height'] && !Qs_ImageFs::isNewSizeDifferent($source, $width, $height, $method)) || ($width == $info['width'] && $height == 0) || ($height == $info['height'] && $width == 0)) && !(strstr($options['method'], '_gray') || $quality != Qs_ImageFs::$_quality) ) { if ($symlink) { $sourceParts = pathinfo($source); $link = WWW_PATH . '/' . $destination; $currentDir = getcwd(); if (chdir($sourceParts['dirname']) && !file_exists($link)) { if (symlink($sourceParts['basename'], $link)) { $source = $destination; } } chdir($currentDir); return $source; } else { copy($source, $destination); } return $destination; } if (!is_file($destination) || (is_file($destination) && $force)) { $function = 'resize' . ucfirst(Qs_ImageFs::$_adapter); Qs_ImageFs::$function($source, compact('width', 'height', 'force', 'method', 'destination', 'quality')); } return $destination; } public static function resizeIm($source, $options) { $width = (empty($options['width'])) ? 0 : $options['width']; $height = (empty($options['height'])) ? 0 : $options['height']; $quality = (empty($options['quality'])) ? 0 : (int) $options['quality']; $size = Qs_ImageFs::getNewSize($source, $width, $height, $options['method']); $cmd = 'convert ' . '-strip -interlace Plane ' . escapeshellarg($source) . ' ' . '-resize ' . $size['width'] . 'x' . $size['height'] . '!'; if ($quality) { $cmd .= ' -quality ' . $quality; } if ($size['gray']){ $cmd .= ' -colorspace GRAY'; } if (!empty($size['crop'])) { $crop = &$size['crop']; $cmd .= ' -crop ' . $crop['width'] . 'x' . $crop['height'] . '+' . $crop['left'] . '+' . $crop['top'] . ' ' . '+repage'; } $cmd .= ' +profile "*" ' . escapeshellarg($options['destination']); shell_exec($cmd); } public static function resizeGd($source, $options) { $width = (empty($options['width'])) ? 0 : $options['width']; $height = (empty($options['height'])) ? 0 : $options['height']; $quality = (empty($options['quality'])) ? Qs_ImageFs::$_quality : (int) $options['quality']; $size = Qs_ImageFs::getNewSize($source, $width, $height, $options['method']); $info = Qs_ImageFs::getInfo($source); if (!empty($size['crop'])) { $destImg = imagecreatetruecolor($size['crop']['width'], $size['crop']['height']); } else { $destImg = imagecreatetruecolor($size['width'], $size['height']); } switch ($info['type']) { case IMAGETYPE_GIF: $sourceImg = imagecreatefromgif($source); break; case IMAGETYPE_JPEG: $sourceImg = imagecreatefromjpeg($source); break; case IMAGETYPE_PNG: $sourceImg = imagecreatefrompng($source); break; default: break; } $sourceLeft = 0; $sourceTop = 0; $sourceWidth = $info['width']; $sourceHeight = $info['height']; $destinationWidth = $size['width']; $destinationHeight = $size['height']; if (!empty($size['crop'])) { $destinationWidth = $size['crop']['width']; $destinationHeight = $size['crop']['height']; $sourceLeft = round($size['crop']['left'] / $size['scale']); $sourceTop = round($size['crop']['top'] / $size['scale']); $sourceWidth = round($size['crop']['width'] / $size['scale']); $sourceHeight = round($size['crop']['height'] / $size['scale']); } imagecopyresampled($destImg, $sourceImg, 0, 0, $sourceLeft, $sourceTop, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight); switch ($info['type']) { case IMAGETYPE_GIF: imagegif($destImg, $options['destination']); break; case IMAGETYPE_JPEG: imagejpeg($destImg, $options['destination'], $quality); break; case IMAGETYPE_PNG: imagepng($destImg, $options['destination'], $quality); break; default: break; } } public function delete($name) { Qs_ImageFs::delIcons($name); return unlink($name); } public static function delIcons($fullName) { $parts = pathinfo($fullName); $pattern = $parts['dirname'] . '/' . $parts['filename'] . '_*.' . $parts['extension']; $files = glob($pattern); if (is_array($files) && !empty($files)) { foreach ($files as $file) { if (preg_match("/_\d+[xX]\d+\.{$parts['extension']}$/", $file)) { @unlink($file); } } } return true; } public static function isNewSizeDifferent($fullPath, $width, $height, $method = 'inner') { list($originalWidth, $originalHeight,,) = getimagesize($fullPath); $newSize = Qs_ImageFs::getNewSize($fullPath, $width, $height, $method); return ($originalWidth !== $newSize['width'] || $originalHeight !== $newSize['height']); } /** * @static * @param string $fullPath * @param int $width * @param int $height * @param string $method * @return array SizeInfo */ public static function getNewSize($fullPath, $width, $height, $method = 'inner') { if (!is_file($fullPath)) { return array(); } list($oldWidth, $oldHeight,,) = getimagesize($fullPath); $result = array(); $cropMethod = null; if ($width != 0 || $height != 0) { if ($width == 0) { $width = $oldWidth * $height / $oldHeight; } else if ($height == 0) { $height = $oldHeight * $width / $oldWidth; } $zx = $width / $oldWidth; $zy = $height / $oldHeight; $width = round($width); $height = round($height); $newx = -1; $newy = -1; $result['gray'] = false; if(strstr($method, '_gray')) { $method = str_replace('_gray', '', $method); $result['gray'] = true; } if (0 === strncmp('crop', $method, 4)) { $resizeMethod = 'outer'; $cropMethod = strtolower(substr($method, 4)); } else { $resizeMethod = $method; } switch ($resizeMethod) { case 'outer': if ($zx > $zy) { $z = $zx; $newx = $width; } else { $z = $zy; $newy = $height; } break; case 'inner': default: if ($zx < $zy) { $z = $zx; $newx = $width; } else { $z = $zy; $newy = $height; } break; } $result['width'] = ($newx == -1) ? round($oldWidth * $z) : $newx; $result['height'] = ($newy == -1) ? round($oldHeight * $z) : $newy; } else { $z = 1; $result['width'] = $oldWidth; $result['height'] = $oldHeight; } $result['scale'] = $z; switch ($cropMethod) { case 'first': $result['crop'] = array( 'width' => $width, 'height' => $height, 'left' => 0, 'top' => 0 ); break; case 'center': $result['crop'] = array( 'width' => $width, 'height' => $height, 'left' => round($result['width']/2 - $width/2), 'top' => round($result['height']/2 - $height/2), ); break; case 'last': $result['crop'] = array( 'width' => $width, 'height' => $height, 'left' => $result['width'] > $result['height'] ? $result['width'] - $width: 0, 'top' => $result['width'] > $result['height'] ? 0 : $result['height'] - $height, ); break; default: break; } return Qs_ImageFs::_getNormalizedSizeInfo($result); } /** * Returns proportional scaled SizeInfo accordingly to MAX_RESIZE_WIDTH and MAX_RESIZE_HEIGHT * @static * @param array $info SizeInfo * @return array Scaled SizeInfo */ protected static function _getNormalizedSizeInfo($info) { list($width, $height, $scale) = Qs_ImageFs::_getNormalizedSize($info['width'], $info['height']); $info['width'] = $width; $info['height'] = $height; $info['scale'] = $info['scale'] * $scale; if (!empty($info['crop'])) { $info['crop']['top'] = round($info['crop']['top'] * $scale); $info['crop']['left'] = round($info['crop']['left'] * $scale); $info['crop']['width'] = round($info['crop']['width'] * $scale); $info['crop']['height'] = round($info['crop']['height'] * $scale); } return $info; } /** * Returns proportional sizes that are not larger than MAX_RESIZE_WIDTH and MAX_RESIZE_HEIGHT * @static * @param $width * @param $height * @return array [width, height, scale] */ protected static function _getNormalizedSize($width, $height) { $scale = 1; if ($width > Qs_ImageFs::MAX_RESIZE_WIDTH && $height > Qs_ImageFs::MAX_RESIZE_HEIGHT) { $widthScale = Qs_ImageFs::MAX_RESIZE_WIDTH / $width; $heightScale = Qs_ImageFs::MAX_RESIZE_HEIGHT / $height; $scale = ($widthScale < $heightScale) ? $widthScale : $heightScale; } else if ($width > Qs_ImageFs::MAX_RESIZE_WIDTH) { $scale = Qs_ImageFs::MAX_RESIZE_WIDTH / $width; } else if ($height > Qs_ImageFs::MAX_RESIZE_HEIGHT) { $scale = Qs_ImageFs::MAX_RESIZE_HEIGHT / $height; } if ($scale != 1) { $width = round($width * $scale); $height = round($height * $scale); } return array($width, $height, $scale); } }