我有一个非常简单的图像大小调整脚本,它循环遍历1000个文件夹,每个文件夹中有不同数量的图像。在我的测试服务器上,没有很多图像,所以运行正常...但是大约有100K图像......它会遇到内存问题。 php内存已经设置为384M,但我宁愿让脚本一次只处理10个文件夹,停一会儿,然后重新开始。我怎么能在while循环中做到这一点?使用睡眠功能可能吗?
这是......
class DevTestHelper {
//This will Go through all full size images and resize images into requested folder
function resizeGalleryImages($destFolder, $width, $height, $isCrop = false) {
$count = 1000;
$source = JPATH_SITE."/images/gallery/full";
$dest = JPATH_SITE."/images/gallery/".$destFolder;
echo 'Processing Images<br>';
//Loop through all 1000 folders 0 to 999 in the /full dir
for($i=0; $i < $count;$i++) {
$iPath = $source.'/'.$i;
if(is_dir($iPath)) {
$h = opendir($iPath);
//Loop through all the files in numbered folder
while ($entry = readdir($h)) {
//only read files
if ($entry != "." && $entry != ".." && !is_dir($entry)) {
$img = new GImage($source.'/'.$i.'/'.$entry);
$tmp = $img->resize($width, $height, true, 3);
if($isCrop) {
$tmpWidth = $tmp->getWidth();
$tmpHeight = $tmp->getHeight();
$xOffset = ($tmpWidth - $width) / 2;
$yOffset = ($tmpHeight - $height) / 2;
$tmp->crop($width, $height, $xOffset, $yOffset, false, 3);
}
$destination = $dest.'/'.$i.'/'.$entry;
if(!$tmp->toFile($destination)) {
echo 'error in creating resized image at: '.$destination.'<br>';
}
flush();
ob_flush();
sleep(10);
echo $entry ;
//echo $entry.'<br>';
}
}
echo 'Processed: '.$i.' Folder<br>';
}
}
感谢您的任何建议。
/**
* Class to manipulate an image.
*
* @package Gallery.Libraries
* @subpackage Media
* @version 1.0
*/
class GImage extends JObject
{
/**
* The image handle
*
* @access private
* @var resource
*/
var $_handle = null;
/**
* The source image path
*
* @access private
* @var string
*/
var $_path = null;
var $_support = array();
/**
* Constructor
*
* @access public
* @return void
* @since 1.0
*/
function __construct($source=null)
{
// First we test if dependencies are met.
if (!GImageHelper::test()) {
$this->setError('Unmet Dependencies');
return false;
}
// Determine which image types are supported by GD.
$info = gd_info();
if ($info['JPG Support']) {
$this->_support['JPG'] = true;
}
if ($info['GIF Create Support']) {
$this->_support['GIF'] = true;
}
if ($info['PNG Support']) {
$this->_support['PNG'] = true;
}
// If the source input is a resource, set it as the image handle.
if ((is_resource($source) && get_resource_type($source) == 'gd')) {
$this->_handle = &$source;
} elseif (!empty($source) && is_string($source)) {
// If the source input is not empty, assume it is a path and populate the image handle.
//Andy - Big freaking cockroach: if file is wrong type or doesn't even exist the error is not handled.
$this->loadFromFile($source);
}
}
function crop($width, $height, $left, $top, $createNew = true, $scaleMethod = JXIMAGE_SCALE_INSIDE)
{
// Make sure the file handle is valid.
if ((!is_resource($this->_handle) || get_resource_type($this->_handle) != 'gd')) {
$this->setError('Invalid File Handle');
return false;
}
// Sanitize width.
$width = ($width === null) ? $height : $width;
if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/', $width)) {
$width = intval(round($this->getWidth() * floatval(str_replace('%', '', $width)) / 100));
} else {
$width = intval(round(floatval($width)));
}
// Sanitize height.
$height = ($height === null) ? $width : $height;
if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/', $height)) {
$height = intval(round($this->getHeight() * floatval(str_replace('%', '', $height)) / 100));
} else {
$height = intval(round(floatval($height)));
}
// Sanitize left.
$left = intval(round(floatval($left)));
// Sanitize top.
$top = intval(round(floatval($top)));
// Create the new truecolor image handle.
$handle = imagecreatetruecolor($width, $height);
// Allow transparency for the new image handle.
imagealphablending($handle, false);
imagesavealpha($handle, true);
if ($this->isTransparent()) {
// Get the transparent color values for the current image.
$rgba = imageColorsForIndex($this->_handle, imagecolortransparent($this->_handle));
$color = imageColorAllocate($this->_handle, $rgba['red'], $rgba['green'], $rgba['blue']);
// Set the transparent color values for the new image.
imagecolortransparent($handle, $color);
imagefill($handle, 0, 0, $color);
imagecopyresized(
$handle,
$this->_handle,
0, 0,
$left,
$top,
$width,
$height,
$width,
$height
);
} else {
imagecopyresampled(
$handle,
$this->_handle,
0, 0,
$left,
$top,
$width,
$height,
$width,
$height
);
}
// If we are cropping to a new image, create a new GImage object.
if ($createNew)
{
// Create the new GImage object for the new truecolor image handle.
$new = new GImage($handle);
return $new;
} else
{
// Swap out the current handle for the new image handle.
$this->_handle = &$handle;
return true;
}
}
function filter($type)
{
// Initialize variables.
$name = preg_replace('#[^A-Z0-9_]#i', '', $type);
$className = 'GImageFilter_'.ucfirst($name);
if (!class_exists($className))
{
jimport('joomla.filesystem.path');
if ($path = JPath::find(GImageFilter::addIncludePath(), strtolower($name).'.php'))
{
require_once $path;
if (!class_exists($className)) {
$this->setError($className.' not found in file.');
return false;
}
}
else {
$this->setError($className.' not supported. File not found.');
return false;
}
}
$instance = new $className;
if (is_callable(array($instance, 'execute')))
{
// Setup the arguments to call the filter execute method.
$args = func_get_args();
array_shift($args);
array_unshift($args, $this->_handle);
// Call the filter execute method.
$return = call_user_func_array(array($instance, 'execute'), $args);
// If the filter failed, proxy the error and return false.
if (!$return) {
$this->setError($instance->getError());
return false;
}
return true;
}
else {
$this->setError($className.' not valid.');
return false;
}
}
function getHeight()
{
return imagesy($this->_handle);
}
function getWidth()
{
return imagesx($this->_handle);
}
function isTransparent()
{
// Make sure the file handle is valid.
if ((!is_resource($this->_handle) || get_resource_type($this->_handle) != 'gd')) {
$this->setError('Invalid File Handle');
return false;
}
return (imagecolortransparent($this->_handle) >= 0);
}
function loadFromFile($path)
{
// Make sure the file exists.
if (!JFile::exists($path)) {
$this->setError('File Does Not Exist');
return false;
}
// Get the image properties.
$properties = GImageHelper::getProperties($path);
if (!$properties) {
return false;
}
// Attempt to load the image based on the MIME-Type
switch ($properties->get('mime'))
{
case 'image/gif':
// Make sure the image type is supported.
if (empty($this->_support['GIF'])) {
$this->setError('File Type Not Supported');
return false;
}
// Attempt to create the image handle.
$handle = @imagecreatefromgif($path);
if (!is_resource($handle)) {
$this->setError('Unable To Process Image');
return false;
}
$this->_handle = &$handle;
break;
case 'image/jpeg':
// Make sure the image type is supported.
if (empty($this->_support['JPG'])) {
$this->setError('File Type Not Supported');
return false;
}
// Attempt to create the image handle.
$handle = @imagecreatefromjpeg($path);
if (!is_resource($handle)) {
$this->setError('Unable To Process Image');
return false;
}
$this->_handle = &$handle;
break;
case 'image/png':
// Make sure the image type is supported.
if (empty($this->_support['PNG'])) {
$this->setError('File Type Not Supported');
return false;
}
// Attempt to create the image handle.
$handle = @imagecreatefrompng($path);
if (!is_resource($handle)) {
$this->setError('Unable To Process Image');
return false;
}
$this->_handle = &$handle;
break;
default:
$this->setError('File Type Not Supported');
return false;
break;
}
// Set the filesystem path to the source image.
$this->_path = $path;
return true;
}
function resize($width, $height, $createNew = true, $scaleMethod = JXIMAGE_SCALE_INSIDE)
{
// Make sure the file handle is valid.
if ((!is_resource($this->_handle) || get_resource_type($this->_handle) != 'gd')) {
$this->setError('Invalid File Handle');
return false;
}
// Prepare the dimensions for the resize operation.
$dimensions = $this->_prepareDimensions($width, $height, $scaleMethod);
if (empty($dimensions)) {
return false;
}
//var_dump($dimensions);
// Create the new truecolor image handle.
$handle = imagecreatetruecolor($dimensions['width'], $dimensions['height']);
// Allow transparency for the new image handle.
imagealphablending($handle, false);
imagesavealpha($handle, true);
if ($this->isTransparent()) {
// Get the transparent color values for the current image.
$rgba = imageColorsForIndex($this->_handle, imagecolortransparent($this->_handle));
$color = imageColorAllocate($this->_handle, $rgba['red'], $rgba['green'], $rgba['blue']);
// Set the transparent color values for the new image.
imagecolortransparent($handle, $color);
imagefill($handle, 0, 0, $color);
imagecopyresized(
$handle,
$this->_handle,
0, 0, 0, 0,
$dimensions['width'],
$dimensions['height'],
$this->getWidth(),
$this->getHeight()
);
} else {
imagecopyresampled(
$handle,
$this->_handle,
0, 0, 0, 0,
$dimensions['width'],
$dimensions['height'],
$this->getWidth(),
$this->getHeight()
);
}
// If we are resizing to a new image, create a new GImage object.
if ($createNew)
{
// Create the new GImage object for the new truecolor image handle.
$new = new GImage($handle);
return $new;
} else
{
// Swap out the current handle for the new image handle.
$this->_handle = &$handle;
return true;
}
}
function toFile($path, $type = IMAGETYPE_JPEG, $options=array())
{
switch ($type)
{
case IMAGETYPE_GIF:
$ret = imagegif($this->_handle, $path);
break;
case IMAGETYPE_PNG:
$ret = imagepng($this->_handle, $path, (array_key_exists('quality', $options)) ? $options['quality'] : 0);
break;
case IMAGETYPE_JPEG:
default:
$ret = imagejpeg($this->_handle, $path, (array_key_exists('quality', $options)) ? $options['quality'] : 100);
break;
}
return $ret;
}
function display() {
//header('Content-type: image/jpeg');
imagejpeg($this->_handle,'',100);
}
function _prepareDimensions($width, $height, $scaleMethod)
{
// Sanitize width.
$width = ($width === null) ? $height : $width;
if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/', $width)) {
$width = intval(round($this->getWidth() * floatval(str_replace('%', '', $width)) / 100));
} else {
$width = intval(round(floatval($width)));
}
// Sanitize height.
$height = ($height === null) ? $width : $height;
if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/', $height)) {
$height = intval(round($this->getHeight() * floatval(str_replace('%', '', $height)) / 100));
} else {
$height = intval(round(floatval($height)));
}
$dimensions = array();
if ($scaleMethod == JXIMAGE_SCALE_FILL)
{
$dimensions['width'] = $width;
$dimensions['height'] = $height;
}
elseif ($scaleMethod == JXIMAGE_SCALE_INSIDE || $scaleMethod == JXIMAGE_SCALE_OUTSIDE)
{
$rx = $this->getWidth() / $width;
$ry = $this->getHeight() / $height;
if ($scaleMethod == JXIMAGE_SCALE_INSIDE)
$ratio = ($rx > $ry) ? $rx : $ry;
else
$ratio = ($rx < $ry) ? $rx : $ry;
$dimensions['width'] = round($this->getWidth() / $ratio);
$dimensions['height'] = round($this->getHeight() / $ratio);
}
else {
$this->setError('Invalid Fit Option');
return false;
}
return $dimensions;
}
}
class GImageFilter extends JObject
{
/**
* Add a directory where GImage should search for filters. You may
* either pass a string or an array of directories.
*
* @access public
* @param string A path to search.
* @return array An array with directory elements
* @since 1.5
*/
function addIncludePath($path='')
{
static $paths;
if (!isset($paths)) {
$paths = array(dirname(__FILE__).'/image');
}
// force path to array
settype($path, 'array');
// loop through the path directories
foreach ($path as $dir)
{
if (!empty($dir) && !in_array($dir, $paths)) {
array_unshift($paths, JPath::clean( $dir ));
}
}
return $paths;
}
function execute()
{
$this->setError('Method Not Implemented');
return false;
}
}
class GImageHelper
{
function getProperties($path)
{
// Initialize the path variable.
$path = (empty($path)) ? $this->_path : $path;
// Make sure the file exists.
if (!JFile::exists($path)) {
$e = new JException('File Does Not Exist');
return false;
}
// Get the image file information.
$info = @getimagesize($path);
if (!$info) {
$e = new JException('Unable To Get Image Size');
return false;
}
// Build the response object.
$result = new JObject;
$result->set('width', $info[0]);
$result->set('height', $info[1]);
$result->set('type', $info[2]);
$result->set('attributes', $info[3]);
$result->set('bits', @$info['bits']);
$result->set('channels', @$info['channels']);
$result->set('mime', $info['mime']);
return $result;
}
function test()
{
return (function_exists('gd_info') && function_exists('imagecreatetruecolor'));
}
}
答案 0 :(得分:2)
在我看来你有内存泄漏,在使用$img
创建new GImage
时,它可能会将图像读入你永远不会释放的内存中。
您可以获取已调整大小的图像的副本:
$tmp = $img->resize($width, $height, true, 3);
但是下次在循环中使用GImage
变量再次创建新的$img
。
GIMage
是否有某种close
或cleanup
功能?如果是这样,请在每次循环结束时执行此操作,然后再次调用new GImage
。
closeGImage($img);
更新:
在回答您更新的问题时,您似乎可以执行以下两项操作之一:
将$img->resize()
的第3个参数更改为false,因为这会停止在图像调整大小时创建新的GImage。
将您自己的图像销毁功能编写为GImage类的一部分。由于GImage基于GD库,因此您可以使用imagedestroy
函数see here。
更新2:
好的,所以继续你的评论......你想要做什么来创建一个破坏图像函数在GImage类中,添加以下函数:
function closeImage()
{
imagedestroy($this->_handle);
}
现在在devtest.php的for循环底部添加对此函数的调用:
...
ob_flush();
sleep(10);
echo $entry ;
$img->closeImage();
...
答案 1 :(得分:0)