TrueColors Posted November 11, 2010 Share Posted November 11, 2010 I would like an image crop script. Basically, if I had an image 100px * 150px, it's not square. So what I would like is for both sides to end up at 100px. The extra 50px spare would be removed. Along with that, it would be cropped center. To get the width and height, we would use something like this: list($width, $height) = getimagesize($this->imageNewName); $this->imageNewName would hold a value like "PATH/TO/IMAGE/image.jpg" I would assume that is okay? I know we would also use imagecreatetruecolor() and imagecopyresampled() Although, to get it so it ends up cropping how I want is hard. In fact, I have no clue. I believe to get the $croppedSize for imagecreatetruecolor()... we would use something like this: list($width, $height) = getimagesize($this->imageNewName); if ($width > $height) { $croppedSize = $height; // We use $height as it is the smallest axis } else if ($height > $width) { $croppedSize = $width; // We use $width as it is the smallest axis } else { return($this->imageNewName); // It is already square, so no need to crop } $croppedImage = imagecreatetruecolor($croppedSize, $croppedSize); I haven't tested this, because it isn't complete. To make it center we need some X and Y variables. As to what they contain, is beyond me. Any help please? Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/ Share on other sites More sharing options...
simshaun Posted November 11, 2010 Share Posted November 11, 2010 This is an image lib I developed earlier this year to serve my basic needs. Perhaps it will help you out. <?php /** * This file contains a basic image utility that supports: * - Resizing an image to a maximum width and height. * - Cropping an image * - Rotate an image <i>(quality needs to be improved)</i> * * @package Images * @version 1.0 */ /** * This class allows you to manipulate images in a basic manner. * Currently, it runs off of the GD image library, but may be able to use * imagemagick in the future. * * Example usage on a test file: * <code> * $imageUtil = new ImageUtil('Creek test.jpg'); * $imageUtil->setNewFormat('jpg'); * //$imageUtil->thumbnail(400, 400); * //$imageUtil->crop(100, 200, 200, 100); * //$imageUtil->rotate(45); * $imageUtil->thumbnail(800, 600); * $imageUtil->save('/var/www/vhosts/domain.com/uploads/images/','large'); * $imageUtil->thumbnail(400, 400, TRUE); * $imageUtil->save('/var/www/vhosts/domain.com/uploads/images/','medium'); * $imageUtil->thumbnail(150, 150); * $imageUtil->save('/var/www/vhosts/domain.com/uploads/images/','small'); * $newPath = $imageUtil->newPath; * $imageUtil->reset(); * </code> * * Example: $key = 'photo'; if ($post[$key] != '') { $fileName = $post[$key]; $tmpName = $_FILES[$key]['tmp_name']; $imageUtil = new ImageUtil($tmpName); $imageUtil->thumbnail(700, 600, TRUE); $imageUtil->save(DIR_UPLOADS,$fileName); $fileName = $imageUtil->newFilename; $filePath = $imageUtil->newPath; $imageUtil->reset(); // Set permissions on the new image. chmod($filePath, 0777); $post[$key] = $fileName; } else { $post[$key] = $post['o_'.$key]; } * * @author Shaun * @copyright 2010 * @todo Low - Implement ability to change the library used to modify images. */ class ImageUtil { /** * This is the filename of the source image. * @var string */ var $srcImg = NULL; /** * This is the width of the source image, retrieved by getimagesize(). * @var int */ var $srcWidth = NULL; /** * This is the height of the source image, retrieved by getimagesize(). * @var int */ var $srcHeight = NULL; /** * This is the format of the source image, based on the validTypes array. * @var string */ var $srcFormat = NULL; /** * This is the source image's aspect ratio of width to height. * @var float */ var $srcAspectRatio = NULL; /** * This is the format for which to save the newly created image as. * The accepted formats are listed in the validTypes property. * @see $validTypes * @var string */ var $newFormat = NULL; /** * This is the GD resource for the new image. * @var resource */ var $newImageResource = NULL; /** * This is the filename of the newly created image. * It is generated by the class upon save(). * @var string */ var $newFilename = NULL; /** * This is the path to the newly created image. * The path is generated by the class upon save(). * @var string */ var $newPath = NULL; /** * This is set to TRUE if the source image is modified in any way. * @var boolean */ var $imageModified = FALSE; /** * This is an array of valid image formats that we are able to work with. * @var array */ var $validTypes = array( 1 => 'gif', 2 => 'jpg', 3 => 'png', /*4 => 'swf', 5 => 'psd', 6 => 'bmp', 7 => 'tiff', 8 => 'tiff', 9 => 'jpc', 10 => 'jp2', 11 => 'jpx', 12 => 'jb2', 13 => 'swc', 14 => 'iff', 15 => 'wbmp', 16 => 'xbm',*/ 99 => 'jpeg', // I will not support the types above that are commented out until I have a damn good reason to. ); /** * This is the name of the function used to sanitize the new filename before saving. * @var string */ var $filenameCleaningFunc = 'sanitizeFilename'; /** * Constructor. * * @param string */ function ImageUtil($srcImgFilename = NULL) { if ($srcImgFilename !== NULL) { $this->setSourceImage($srcImgFilename); } } /** * Set the image that will be manipulated. * * @access public * @param string */ function setSourceImage($filename) { $this->srcImg = $filename; $this->_getSourceImageInfo(); } /** * Set the format that the new image should be saved as. * * A list of acceptable formats may be found in the $validTypes property. * * @see $validTypes * @access public * @param string */ function setNewFormat($format) { $format = strtolower($format); if (array_search($format, $this->validTypes) !== FALSE) { $this->newFormat = strtolower($format); } else { trigger_error('Set new format failed. '. htmlentities($format, ENT_COMPAT, 'UTF-8') .' is not supported', E_USER_ERROR); } } /** * Resizes an image to a maximum width and/or height. * * This method automatically determines which direction is best to resize * the new image in. * * If $crop is true, the image will be resized on the smallest side and the * longest side will be trimmed. * * Otherwise, the image is resized on the smallest side, and then resized again * if the longest side still exceeds the limit. * * @access public * @param int * @param int * @param bool */ function thumbnail($maxWidth = 0, $maxHeight = 0, $crop = FALSE) { if ($this->srcImg === NULL) { trigger_error('Source image not set', E_USER_ERROR); } $maxWidth = (int) $maxWidth; $maxHeight = (int) $maxHeight; // Make sure at least one maximum dimension is specified. if ($maxWidth === 0 && $maxHeight === 0) { trigger_error('You must specify at least one maximum dimension', E_USER_ERROR); } // Format and validate the method arguments. if ($maxWidth != 0 && $maxWidth < 0) { trigger_error('$maxWidth must be a whole number greater than 0', E_USER_ERROR); } if ($maxHeight != 0 && $maxHeight < 0) { trigger_error('$maxHeight must be a whole number greater than 0', E_USER_ERROR); } // Default values $skipResize = FALSE; $trimWidth = FALSE; $trimHeight = FALSE; // Skip resizing the source image if its dimensions are already within the limits. if ($maxWidth > $this->srcWidth && $maxHeight > $this->srcHeight) { $skipResize = TRUE; } if ($skipResize === FALSE) { if ($maxWidth == 0) { $newHeight = $maxHeight; $newWidth = (int) round($newHeight / $this->srcAspectRatio); } else if ($maxHeight == 0) { $newWidth = $maxWidth; $newHeight = (int) round($newWidth / $this->srcAspectRatio); } else { /* * Use the smallest maximum dimension and calculate the other dimension's new value. */ if ($maxWidth < $maxHeight) { if ($crop) { $newHeight = $maxHeight; $newWidth = (int) round($newHeight * $this->srcAspectRatio); if ($newWidth > $maxWidth) $trimWidth = TRUE; } else { $newWidth = $maxWidth; $newHeight = (int) round($newWidth / $this->srcAspectRatio); if ($newHeight > $maxHeight) { $newHeight = $maxHeight; $newWidth = (int) round($newHeight * $this->srcAspectRatio); } } } else if ($maxHeight < $maxWidth) { if ($crop) { $newWidth = $maxWidth; $newHeight = (int) round($newWidth / $this->srcAspectRatio); if ($newHeight > $maxHeight) $trimHeight = TRUE; } else { $newHeight = $maxHeight; $newWidth = (int) round($newHeight * $this->srcAspectRatio); if ($newWidth > $maxWidth) { $newWidth = $maxWidth; $newHeight = (int) round($maxWidth / $this->srcAspectRatio); } } } // If the two dimensions are equal, then automatically determine which // dimension to use based on the source image. else { // If the image is wider than it is tall, resize based on the height. if ($this->srcWidth > $this->srcHeight) { $newHeight = (int) $maxHeight; $newWidth = (int) round($maxHeight * $this->srcAspectRatio); // If the $newWidth is greater than the $maxWidth, either trim the excess width off, // or reduce the $newWidth down to the $maxWidth and recalculate the $newHeight. if ($newWidth > $maxWidth) { if ($crop) { $trimWidth = TRUE; } else { $newWidth = $maxWidth; $newHeight = (int) round($maxWidth / $this->srcAspectRatio); } } } // If the image is taller than it is wide, or is equal in both width and height, resize based on width. else { $newWidth = (int) $maxWidth; $newHeight = (int) round($maxWidth / $this->srcAspectRatio); // If the $newHeight is greater than the $maxHeight, either trim the excess height off, // or reduce the $newHeight down to the $maxHeight and recalculate the $newWidth. if ($newHeight > $maxHeight) { if ($crop) { $trimHeight = TRUE; } else { $newHeight = $maxHeight; $newWidth = (int) round($maxHeight * $this->srcAspectRatio); } } } } } // Create the necessary image resources. $newImage = imagecreatetruecolor($trimWidth ? $maxWidth : $newWidth, $trimHeight ? $maxHeight : $newHeight); $oldImage = $this->_getSourceImageGdResource(); // Resize the old image. If "cropping", center the new image. imagecopyresampled($newImage, $oldImage, $trimWidth ? 0 - (floor(($newWidth - $maxWidth) / 2)) : 0, $trimHeight ? 0 - (floor(($newHeight - $maxHeight) / 2)) : 0, 0, 0, $newWidth, $newHeight, $this->srcWidth, $this->srcHeight); // Store the GD resource in memory. $this->newImageResource = $newImage; // Free up memory. imagedestroy($oldImage); unset($newImage); // Flag the image as modified. $this->imageModified = TRUE; } } /** * Rotates an image by the number of degrees specified. * * @access public * @param int -360 to 360 * @param hex Background color of the area generated by the rotate function */ function rotate($angle, $bgColor = 0x000000) { if ($this->srcImg === NULL) { trigger_error('Source image not set', E_USER_ERROR); } // Retrieve the current working copy of the image. $image = $this->_getWorkingCopyOfImage(); // Rotate it. $image = imagerotate($image, $angle, $bgColor); // If the new format is either a gif or a png, make the newly created background transparent. if ($this->newFormat == 'gif' || $this->newFormat == 'png') { $rgb = $this->hex2rgb($bgColor); imagecolortransparent($image, imagecolorallocate($image, $rgb['r'], $rgb['g'], $rgb['b'])); } // Store it. $this->newImageResource = $image; // Free up memory. unset($image); // Flag the image as modified. $this->imageModified = TRUE; } /** * Crops an image using the coordinates and dimensions specified. * * @access public * @param int * @param int * @param int * @param int */ function crop($x, $y, $width, $height) { if ($this->srcImg === NULL) { trigger_error('Source image not set', E_USER_ERROR); } // Retrieve the current working copy of the image. $oldImage = $this->_getWorkingCopyOfImage(); $newImage = imagecreatetruecolor($width, $height); // Crop it. imagecopy($newImage, $oldImage, 0, 0, $x, $y, $width, $height); // Store it. $this->newImageResource = $newImage; // Free up memory. imagedestroy($oldImage); unset($newImage); // Flag the image as modified. $this->imageModified = TRUE; } /** * Save the modified image. * * If $filename is left empty, a new filename will be generated based upon the * old filename and the new format. * * If you do set a new $filename, it does not need to contain an extension, although * it may. * * $filename is passed through the filename sanitization function as long as one is * set in the config. At the very least, the filename is converted to lower case and * spaces are converted to underscores. * * This method does NOT chmod the file. That must be done manually by the script that * utilizes this utility. The path to the new file may be pulled from $this->newPath. * * @access public * @param string * @param string (extension optional) * @param int 0-100. Only applies to jpegs. */ function save($path, $filename = NULL, $quality = 100) { $quality = (int) $quality; if ($quality < 0 || $quality > 100) { trigger_error('$quality must be a whole number greater than 0 and less than or equal to 100', E_USER_ERROR); } // If the path is not empty, ensure it ends with the (proper) directory separator. if ($path != '') { $path = rtrim($path, DIRECTORY_SEPARATOR); $path .= DIRECTORY_SEPARATOR; } // Ensure the path is writable. if (!is_writable($path)) { trigger_error('The destination directory '. htmlentities($path, ENT_COMPAT, 'UTF-8') .' is not writable', E_USER_ERROR); } // If the user did not specify a filename to save the new file as, use the source filename and the new format to build a new filename. if ($filename === NULL) { $srcFilename = $this->srcImg; $srcFilename = $this->removeExtension($srcFilename); $newFilename = $srcFilename .'.'. $this->newFormat; } // Otherwise, use the specified filename. If it does not contain an extension, add one. else { if (strpos($filename, '.') === FALSE) { $newFilename = $filename .'.'. $this->newFormat; } else { $newFilename = $filename; } } // If the sanitizeFilename function exists, use it on the new filename. if (function_exists($this->filenameCleaningFunc)) { $newFilename = call_user_func($this->filenameCleaningFunc, $newFilename); } // At the very least, apply a minimal sanitation to the filename. else { $newFilename = $this->sanitizeFilename($newFilename); } // If the source image has not been modified, then just copy it. if ($this->imageModified === FALSE) { if (!@copy($this->srcImg, $path.$newFilename)) { trigger_error('Source image was not modified. However, the attempt to copy the source image to the new location failed ', E_USER_ERROR); } } else { // Retrieve the image data for the new image. $image = $this->output($quality); // Save the image. $handle = @fopen($path.$newFilename, 'w'); if ($handle === FALSE) { trigger_error('Failed to create the new file for which we would write image data to', E_USER_ERROR); } flock($handle, LOCK_EX); fwrite($handle, $image); flock($handle, LOCK_UN); fclose($handle); } // Store the new filename so the calling script may store it. $this->newFilename = $newFilename; // Store the new path so the calling script may chmod the file manually. $this->newPath = $path.$newFilename; } /** * Outputs the image data. * * @access public * @param int 0-100. Only applies to jpegs. * @return string */ function output($quality = 100) { ob_start(); switch ($this->newFormat) { case 'gif': imagegif($this->newImageResource); break; case 'jpg': imagejpeg($this->newImageResource, NULL, $quality); break; case 'jpeg': imagejpeg($this->newImageResource, NULL, $quality); break; case 'png': imagepng($this->newImageResource); break; default: trigger_error('Could not create the new image because the new format type ('. htmlentities($this->newFormat, ENT_COMPAT, 'UTF-8') .') is unsupported', E_USER_ERROR); } $image = ob_get_contents(); ob_end_clean(); return $image; } /** * Sanitizes a filename. * * @access public * @param string * @return string */ function sanitizeFilename($filename) { $newFilename = strtolower($filename); // Convert multiple spaces into a single space. $newFilename = preg_replace('/\s+/', ' ', $newFilename); // Convert single spaces into underscores. $newFilename = str_replace(' ', '_', $newFilename); // Replace "different" characters with an underscore. $newFilename = preg_replace('/[^.0-9A-Z()_-]/i', '_', $newFilename); // Convert multiple underscores into a single underscore. $newFilename = preg_replace('/_+/', '_', $newFilename); return $newFilename; } /** * Removes the extension from a filename if one exists. * * @access public * @param string * @return string */ function removeExtension($filename) { $filename = explode('.', $filename); if (count($filename) == 1) { return implode('.', $filename); } else { array_pop($filename); return implode('.', $filename); } } /** * Resets the class to work with a new image. * * @access public */ function reset() { $this->srcImg = NULL; $this->srcWidth = NULL; $this->srcHeight = NULL; $this->srcFormat = NULL; $this->srcAspectRatio = NULL; $this->newFormat = NULL; $this->newPath = NULL; if (is_resource($this->newImageResource)) { imagedestroy($this->newImageResource); } else { $this->newImageResource = NULL; } } /** * Converts a hex code to RGB. * * @param hex * @return array */ function hex2rgb($hex){ $hex = dechex($hex); $rgb['r'] = hexdec(substr($hex, 0, 2)); $rgb['g'] = hexdec(substr($hex, 2, 2)); $rgb['b'] = hexdec(substr($hex, 4, 2)); return $rgb; } /** * Retrieves information about the source image and stores it in class properties. * * @access private */ function _getSourceImageInfo() { if ($this->srcImg === NULL) { trigger_error('Source image not set', E_USER_ERROR); } $srcInfo = @getimagesize($this->srcImg); if ($srcInfo === FALSE) { if (!is_readable($this->srcImg)) { trigger_error('Could not open source image for reading', E_USER_ERROR); } else { trigger_error('Could not obtain image information of '. htmlentities($this->srcImg, ENT_COMPAT, 'UTF-8'), E_USER_ERROR); } } $this->srcWidth = $srcInfo[0]; $this->srcHeight = $srcInfo[1]; $this->srcFormat = $this->_mapImageType($srcInfo[2]); $this->srcAspectRatio = round($srcInfo[0] / $srcInfo[1], ; if ($this->srcFormat === NULL) { trigger_error('Unsupported image type', E_USER_ERROR); } if ($this->newFormat === NULL) { $this->newFormat = $this->srcFormat; } } /** * Returns a GD resource for the source image. * * @access private * @return resource */ function _getSourceImageGdResource() { switch ($this->srcFormat) { case 'gif': $resource = imagecreatefromgif($this->srcImg); break; case 'jpg': $resource = imagecreatefromjpeg($this->srcImg); break; case 'png': $resource = imagecreatefrompng($this->srcImg); break; default: trigger_error('Could not create an image resource for the source image because its type is unknown or unsupported', E_USER_ERROR); } return $resource; } /** * Get the most recent version of the image used by the class. * This is the key behind allowing a user to perform more than one action * on a single image without saving and reloading and saving and reloading. * * @access private */ function _getWorkingCopyOfImage() { if ($this->newImageResource === NULL) { return $this->_getSourceImageGdResource(); } else { return $this->newImageResource; } } /** * Retrieves the type of image based on the integer returned by getimagesize(). * * @access private * @param int * @return string if type exists, NULL if it doesnt */ function _mapImageType($type) { return isset($this->validTypes[$type]) ? $this->validTypes[$type] : NULL; } } Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133134 Share on other sites More sharing options...
TrueColors Posted November 11, 2010 Author Share Posted November 11, 2010 Impressive, looks very complicated but you do have comments for it. It also has rotation of an image, which I do not need. Actually, what I'm needing the crop for is an image upload script. It's suppose to generate thumbnails. I've worked with resizing before but not cropping. I was going to crop to square, then resize to a size I would like for a thumbnail. Your script may come in handy if I can understand it Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133137 Share on other sites More sharing options...
simshaun Posted November 11, 2010 Share Posted November 11, 2010 Yea, it is probably over-commented, but I was in the mood for that when I developed it. One of these days I'll probably refactor that lib so its a bit easier to follow. Take a look at the resize() method. It supports exactly what you need. You can probably just pull the logic from it if you dont want to use the library. Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133141 Share on other sites More sharing options...
TrueColors Posted November 11, 2010 Author Share Posted November 11, 2010 I can't find the resize, but I can find the crop but because it's all split up- it's hard to read. Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133168 Share on other sites More sharing options...
simshaun Posted November 11, 2010 Share Posted November 11, 2010 Sorry, the method name is thumbnail(). Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133174 Share on other sites More sharing options...
TrueColors Posted November 11, 2010 Author Share Posted November 11, 2010 This is as far as I've got. I don't think it centers though. public function cropImage() { list($width, $height) = getimagesize($this->imageNewName); if ($width > $height) { $croppedSize = $height; } else if ($height > $width) { $croppedSize = $width; } else { return($this->imageNewName); } $crop_x = $croppedSize / 2; $crop_y = $croppedSize / 2; $croppedImage = imagecreatetruecolor($croppedSize, $croppedSize); imagecopyresampled($croppedImage, $this->image, 0, 0, $crop_x, $crop_y, $croppedSize, $croppedSize, $width, $height); // bool imagecopyresampled ( resource $dst_image , resource $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_w, int $dst_h, int $src_w, int $src_h) return($croppedImage); } Link to comment https://forums.phpfreaks.com/topic/218413-image-cropping/#findComment-1133194 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.