Index: trunk/lib/ImageThumb.inc.php
===================================================================
--- trunk/lib/ImageThumb.inc.php	(revision 815)
+++ trunk/lib/ImageThumb.inc.php	(revision 1)
@@ -1,33 +1,16 @@
 <?php
 /**
- * The Strangecode Codebase - a general application development framework for PHP
- * For details visit the project site: <http://trac.strangecode.com/codebase/>
- * Copyright 2001-2012 Strangecode, LLC
- *
- * This file is part of The Strangecode Codebase.
- *
- * The Strangecode Codebase is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * The Strangecode Codebase is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
+ * ImageThumb.inc.php 
+ * Code by Strangecode :: www.strangecode.com :: This document contains copyrighted information
  */
 
 /**
- * ImageThumb.inc.php
+ * The ImageThumb class resizes images.
  *
  * @author   Quinn Comendant <quinn@strangecode.com>
- * @requires Netpbm <http://sourceforge.net/projects/netpbm/> and libjpeg or GD.
- * @version  2.0
+ * @requires Netpbm binaries from http://sourceforge.net/projects/netpbm/
+ * @version  1.1
  */
 
-// Image proportion options.
 define('IMAGETHUMB_FIT_WIDTH', 1);
 define('IMAGETHUMB_FIT_HEIGHT', 2);
@@ -36,138 +19,74 @@
 define('IMAGETHUMB_NO_SCALE', 5);
 
-// Image resize options.
-define('IMAGETHUMB_METHOD_NETPBM', 6);
-define('IMAGETHUMB_METHOD_GD', 7);
-
-class ImageThumb
-{
-
-    // General object parameters.
-    protected $_params = array(
-        // The location for images to create thumbnails from.
-        'source_dir' => null,
-
-        // Existing files will be overwritten when there is a name conflict?
-        'allow_overwriting' => false,
-
-        // The file permissions of the uploaded files. Remember, files will be owned by the web server user.
-        'dest_file_perms' => 0600,
-
-        // Permissions of auto-created directories. Must be at least 0700 with owner=apache.
-        'dest_dir_perms' => 0700,
-
-        // Require file to have one of the following file name extensions.
-        'valid_file_extensions' => array('jpg', 'jpeg', 'gif', 'png'),
-
-        // Method to use for resizing. (IMAGETHUMB_METHOD_NETPBM or IMAGETHUMB_METHOD_GD)
-        'resize_method' => IMAGETHUMB_METHOD_NETPBM,
-
-        // Netpbm and libjpeg binary locations.
-        'anytopnm_binary' => '/usr/bin/anytopnm',
-        'pnmscale_binary' => '/usr/bin/pnmscale',
-        'cjpeg_binary' => '/usr/bin/cjpeg',
-
-        // Which messages do we pass to raiseMsg? Use one of the MSG_* constants or false to disable.
-        'display_messages' => MSG_ALL,
-    );
-
-    // Default image size specs.
-    protected $_default_image_specs = array(
-        // The destination for an image thumbnail size.
-        // Use initial / to specify absolute paths, leave off to specify a path relative to source_dir (eg: ../thumbs).
-        'dest_dir' => null,
-
-        // Destination file types. (IMG_JPG, IMG_PNG, IMG_GIF, IMG_WBMP)
-        'dest_file_type' => IMG_JPG,
-
-        // Destination file types. ('jpg', 'png', 'gif', 'wbmp')
-        'dest_file_extension' => 'jpg',
-
-        // Type of scaling to perform, and sizes used to calculate max dimensions.
-        'scaling_type' => IMAGETHUMB_FIT_LARGER,
-        'width' => null,
-        'height' => null,
-
-        // Percentage quality of image compression output 0-100.
-        'quality' => 65,
-
-        // Create progressive jpegs?
-        'progressive' => false,
-
-        // If using GD method, apply sharpen filter. Requires PHP > 5.1.
-        'sharpen' => true,
-
-        // Integers between 1-100, useful values are 65-85.
-        'sharpen_value' => 75,
-
-        // If source image is smaller than thumbnail, allow upscaling?
-        'allow_upscaling' => false,
-
-        // If thumb exists and filesize is smaller than this, do not overwrite the thumb.
-        'keep_filesize' => null,
-    );
-
-    // Final specifications for image sizes, set with setSpec().
-    protected $_image_specs = array();
-
-    /**
-     * Set (or overwrite existing) parameters by passing an array of new parameters.
-     *
-     * @access public
-     * @param  array    $params     Array of parameters (key => val pairs).
-     */
-    public function setParam($params)
-    {
-        $app =& App::getInstance();
-
-        if (isset($params) && is_array($params)) {
-
-            // Enforce valid source_dir parameter.
-            if (isset($params['source_dir'])) {
-                // Source must be directory.
-                if (!is_dir($params['source_dir'])) {
-                    $app->logMsg(sprintf('Attempting to auto-create source directory: %s', $params['source_dir']), LOG_NOTICE, __FILE__, __LINE__);
-                    if (version_compare(PHP_VERSION, '5.0.0', '>=')) {
-                        // Recursive.
-                        mkdir($params['source_dir'], isset($params['dest_dir_perms']) ? $params['dest_dir_perms'] : $this->getParam('dest_dir_perms'), true);
-                    } else {
-                        mkdir($params['source_dir'], isset($params['dest_dir_perms']) ? $params['dest_dir_perms'] : $this->getParam('dest_dir_perms'));
-                    }
-                    if (!is_dir($params['source_dir'])) {
-                        $app->logMsg(sprintf('Source directory invalid: %s', $params['source_dir']), LOG_ERR, __FILE__, __LINE__);
-                        trigger_error(sprintf('Source directory invalid: %s', $params['source_dir']), E_USER_ERROR);
-                    }
-                }
-                // Source must be readable.
-                if (!is_readable($params['source_dir'])) {
-                    $app->logMsg(sprintf('Source directory not readable: %s', $params['source_dir']), LOG_ERR, __FILE__, __LINE__);
-                    trigger_error(sprintf('Source directory not readable: %s', $params['source_dir']), E_USER_ERROR);
-                }
-            }
-
-            // Merge new parameters with old overriding only those passed.
-            $this->_params = array_merge($this->_params, $params);
-        } else {
-            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
-        }
-    }
-
-    /**
-     * Return the value of a parameter, if it exists.
-     *
-     * @access public
-     * @param string $param        Which parameter to return.
-     * @return mixed               Configured parameter value.
-     */
-    public function getParam($param)
-    {
-        $app =& App::getInstance();
-
-        if (array_key_exists($param, $this->_params)) {
-            return $this->_params[$param];
-        } else {
-            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
-            return null;
-        }
+class ImageThumb {
+    
+    // The location for images to create thumbnails from.
+    var $source_dir = null;
+    
+    // Specifications for thumbnail images.
+    var $spec; 
+    
+    // Array of acceptable file extensions (lowercase).
+    var $valid_file_extensions = array('jpg', 'jpeg', 'gif', 'png');
+    
+    // The uploaded files will be owned by user 'apache'. Set world-read/write 
+    // if the website admin needs to read/delete these files. Must be at least 0400 with owner=apache.
+    var $dest_file_perms = 0644;
+    
+    // Must be at least 0700 with owner=apache.
+    var $dest_dir_perms = 0777;
+
+    // Executable binary locations.
+    var $anytopnm_binary = '/usr/bin/anytopnm';
+    var $pnmscale_binary = '/usr/bin/pnmscale';
+    var $cjpeg_binary = '/usr/bin/cjpeg';
+    var $_valid_binaries = true;
+    
+    // Display messages raised in this object?
+    var $display_messages = true;
+
+    /**
+     * Constructor.
+     *
+     * @access  public
+     */
+    function ImageThumb()
+    {
+        if (!file_exists($this->anytopnm_binary)) {
+            App::logMsg(sprintf('ImageThumb error: anytopnm binary %s not found.', $this->anytopnm_binary), LOG_ERR, __FILE__, __LINE__);
+            $this->_valid_binaries = false;
+        }
+        if (!file_exists($this->pnmscale_binary)) {
+            App::logMsg(sprintf('ImageThumb error: pnmscale binary %s not found.', $this->pnmscale_binary), LOG_ERR, __FILE__, __LINE__);
+            $this->_valid_binaries = false;
+        }
+        if (!file_exists($this->cjpeg_binary)) {
+            App::logMsg(sprintf('ImageThumb error: cjpeg binary %s not found.', $this->cjpeg_binary), LOG_ERR, __FILE__, __LINE__);
+            $this->_valid_binaries = false;
+        }
+    }
+
+    /**
+     * Set the directory of the source images.
+     *
+     * @access  public
+     * @param   string $source_dir The full directory path of the source images.
+     * @return  bool true on success, false on failure.
+     */
+    function setSourceDirectory($source_dir)
+    {
+        
+        // Set the source directory path, stripping any extra slashes if needed.
+        $this->source_dir = preg_replace('!/+$!', '', $source_dir);
+        
+        if (!is_dir($this->source_dir)) {
+            App::logMsg(sprintf('ImageThumb error: source directory not found: %s', $this->source_dir), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        if (!is_readable($this->source_dir)) {
+            App::logMsg(sprintf('ImageThumb error: source directory not readable: %s', $this->source_dir), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        return true;
     }
 
@@ -176,296 +95,47 @@
      *
      * @access  public
-     * @param   array   $spec   The specifications for a size of output image.
-     * @param   int     $index  The position of the specification in the spec array
-     *                          Use to overwrite existing spec array values.
-     */
-    public function setSpec($spec, $index=null)
-    {
-        $app =& App::getInstance();
-
-        // A little sanity checking.
-        if (!isset($spec['dest_dir']) || '' == trim($spec['dest_dir'])) {
-            $app->logMsg('setSpec error: dest_dir not specified.', LOG_ERR, __FILE__, __LINE__);
-        } else {
-            $spec['dest_dir'] = trim($spec['dest_dir']);
-        }
-        if (isset($spec['dest_file_type'])) {
-            switch ($spec['dest_file_type']) {
-            case IMG_JPG :
-                if (imagetypes() & IMG_JPG == 0) {
-                    $app->logMsg(sprintf('IMG_JPG is not supported by this version of PHP GD.', null), LOG_ERR, __FILE__, __LINE__);
-                }
-                $spec['dest_file_extension'] = 'jpg';
-                break;
-            case IMG_PNG :
-                if (imagetypes() & IMG_PNG == 0) {
-                    $app->logMsg(sprintf('IMG_PNG is not supported by this version of PHP GD.', null), LOG_ERR, __FILE__, __LINE__);
-                }
-                $spec['dest_file_extension'] = 'png';
-                break;
-            case IMG_GIF :
-                if (imagetypes() & IMG_GIF == 0) {
-                    $app->logMsg(sprintf('IMG_GIF is not supported by this version of PHP GD.', null), LOG_ERR, __FILE__, __LINE__);
-                }
-                $spec['dest_file_extension'] = 'gif';
-                break;
-            case IMG_WBMP :
-                if (imagetypes() & IMG_WBMP == 0) {
-                    $app->logMsg(sprintf('IMG_WBMP is not supported by this version of PHP GD.', null), LOG_ERR, __FILE__, __LINE__);
-                }
-                $spec['dest_file_extension'] = 'wbmp';
-                break;
-            default :
-                $app->logMsg(sprintf('Invalid dest_file_type: %s', $spec['dest_file_type']), LOG_ERR, __FILE__, __LINE__);
-                break;
-            }
-        }
-        if (IMAGETHUMB_FIT_HEIGHT != $spec['scaling_type'] && (!isset($spec['width']) || !is_numeric($spec['width']))) {
-            $app->logMsg(sprintf('setSpec error: invalid width: %s', $spec['width']), LOG_ERR, __FILE__, __LINE__);
-        }
-        if (IMAGETHUMB_FIT_WIDTH != $spec['scaling_type'] && (!isset($spec['height']) || !is_numeric($spec['height']))) {
-            $app->logMsg(sprintf('setSpec error: invalid height: %s', $spec['height']), LOG_ERR, __FILE__, __LINE__);
-        }
-        if (isset($spec['quality']) && IMG_JPG != $spec['dest_file_type']) {
-            $app->logMsg('The "quality" specification is not used unless IMG_JPG is the dest_file_type.', LOG_NOTICE, __FILE__, __LINE__);
-        }
-        if (isset($spec['progressive']) && IMG_JPG != $spec['dest_file_type']) {
-            $app->logMsg('The "progressive" specification is not used unless IMG_JPG is the dest_file_type.', LOG_NOTICE, __FILE__, __LINE__);
-        }
-
-        // Add to _image_specs array.
-        if (isset($index) && isset($this->_image_specs[$index])) {
-            // Merge with existing spec if index is provided.
-            $final_spec = array_merge($this->_image_specs[$index], $spec);
-            $this->_image_specs[$index] = $final_spec;
-        } else {
-            // Merge with spec defaults.
-            $final_spec = array_merge($this->_default_image_specs, $spec);
-            $this->_image_specs[] = $final_spec;
-        }
-
-        return $final_spec;
-    }
-
-    /*
-    * Retrieve a value of a thumb specification.
-    *
-    * @access   public
-    * @param    string  $key    Key to return. See _default_image_specs above for a list.
-    * @param    int     $index  The index in the spec array of the value to retrieve. The first if not specified.
-    * @return   mixed           Value of requested index.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    08 May 2007 15:26:39
-    */
-    public function getSpec($key, $index=null)
-    {
-        $index = isset($index) ? $index : 0;
-        return $this->_image_specs[$index][$key];
-    }
-
-    /**
-     * Process an entire directory of images.
-     *
-     * @access  public
-     * @return  bool true on success, false on failure.
-     */
-    public function processAll($runtime_specs=null)
-    {
-        $app =& App::getInstance();
-
-        // Ensure we have a source.
-        if ('' == $this->getParam('source_dir')) {
-            $app->logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Get all files in source directory.
-        $dir_handle = opendir($this->getParam('source_dir'));
-        while ($dir_handle && ($file = readdir($dir_handle)) !== false) {
-            // If the file name does not start with a dot (. or .. or .htaccess).
-            if (!preg_match('/^\./', $file) && in_array(mb_strtolower(mb_substr($file, mb_strrpos($file, '.') + 1)), $this->getParam('valid_file_extensions'))) {
-                $files[] = $file;
-            }
-        }
-
-        // Process each found file.
-        if (is_array($files) && !empty($files)) {
-            $return_val = 0;
-            foreach ($files as $file_name) {
-                $return_val += (false === $this->processFile($file_name, $runtime_specs) ? 1 : 0);
-            }
-            $this->_raiseMsg(sprintf(_("Resized %s images."), sizeof($files)), MSG_SUCCESS, __FILE__, __LINE__);
-            return 0 === $return_val;
-        } else {
-            $app->logMsg(sprintf('No source images found in directory: %s', $this->getParam('source_dir')), LOG_NOTICE, __FILE__, __LINE__);
-            return false;
-        }
-    }
-
-    /**
-     * Generate thumbnails for the specified file.
-     *
-     * @access  public
-     * @param   string $file_name Name of file with extension.
-     * @param   array $runtime_specs Array of specifications that will override all configured specifications.
-     * @return  bool true on success, false on failure.
-     */
-    public function processFile($file_name, $runtime_specs=null)
-    {
-        $app =& App::getInstance();
-
-        // Source file determined by provided file_name.
-        $source_file = realpath(sprintf('%s/%s', $this->getParam('source_dir'), $file_name));
-
-        // Ensure we have a source.
-        if (sizeof($this->_image_specs) < 1) {
-            if (is_array($runtime_specs)) {
-                $this->setSpec($runtime_specs, 0);
-            } else {
-                $app->logMsg(sprintf('Image specifications not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+     * @param   array $spec The specifications for each size of output image.
+     * @return  bool true on success, false on failure.
+     */
+    function setSpec($spec = array())
+    {
+        $dest_dir        = preg_replace('!/+$!', '', $spec['dest_dir']);
+        $width           = $spec['width'];
+        $height          = $spec['height'];
+        $scaling_type    = $spec['scaling_type'];
+        $quality         = isset($spec['quality']) ? $spec['quality'] : 75;
+        $progressive     = isset($spec['progressive']) ? $spec['progressive'] : false;
+        $allow_upscaling = isset($spec['allow_upscaling']) ? $spec['allow_upscaling'] : false;
+        $keep_filesize   = isset($spec['keep_filesize']) ? $spec['keep_filesize'] : null;
+    
+        // Define pnmscale arguments.
+        switch ($scaling_type) {
+        case IMAGETHUMB_FIT_WIDTH :
+            if (empty($width)) {
+                App::logMsg('ImageThumb error: width not specified for IMAGETHUMB_FIT_WIDTH.', LOG_ERR, __FILE__, __LINE__);
                 return false;
             }
-        }
-
-        // Ensure we have a source.
-        if ('' == $this->getParam('source_dir')) {
-            $app->logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Confirm source image exists.
-        if (!file_exists($source_file)) {
-            $this->_raiseMsg(sprintf(_("Image resizing failed: source image <em>%s</em> was not found."), $file_name), MSG_ERR, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Source image not found: %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Confirm source image is readable.
-        if (!is_readable($source_file)) {
-            $this->_raiseMsg(sprintf(_("Image resizing failed: source image <em>%s</em> is not readable."), $file_name), MSG_ERR, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Source image not readable: %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Confirm source image contains data.
-        if (filesize($source_file) <= 0) {
-            $this->_raiseMsg(sprintf(_("Image resizing failed: source image <em>%s</em> is zero bytes."), $file_name), MSG_ERR, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Source image is zero bytes: %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Confirm source image has a valid file extension.
-        if (!$this->_validFileExtension($file_name)) {
-            $this->_raiseMsg(sprintf(_("Image resizing failed: source image <em>%s</em> not a valid type. It must have one of the following file name extensions: %s"), $file_name, join(', ', $this->getParam('valid_file_extensions'))), MSG_ERR, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Image resizing failed: source image not of valid type: %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Ensure destination directories are created. This will only be called once per page load.
-        if (!$this->_createDestDirs()) {
-            $app->logMsg('Image resizing failed: unable to create dest dirs.', LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        // To keep this script running even if user tries to stop browser.
-        ignore_user_abort(true);
-        ini_set('max_execution_time', 300);
-        ini_set('max_input_time', 300);
-
-        // This remains zero until something goes wrong.
-        $return_val = 0;
-
-        foreach ($this->_image_specs as $index => $spec) {
-
-            if (is_array($runtime_specs)) {
-                // Override with runtime specs.
-                $spec = $this->setSpec($runtime_specs, $index);
-            }
-
-            // Destination filename uses the extension defined by dest_file_extension.
-            if ('/' == $spec['dest_dir'][0]) {
-                // Absolute path.
-                $dest_file = sprintf('%s/%s.%s', $spec['dest_dir'], mb_substr($file_name, 0, mb_strrpos($file_name, '.')), $spec['dest_file_extension']);
-            } else {
-                // Relative path.
-                $dest_file = sprintf('%s/%s/%s.%s', $this->getParam('source_dir'), $spec['dest_dir'], mb_substr($file_name, 0, mb_strrpos($file_name, '.')), $spec['dest_file_extension']);
-            }
-
-            // Ensure destination directory exists and is writable.
-            if (!is_dir(dirname($dest_file)) || !is_writable(dirname($dest_file))) {
-                $this->_createDestDirs($dest_file);
-                if (!is_dir(dirname($dest_file)) || !is_writable(dirname($dest_file))) {
-                    $app->logMsg(sprintf('Image resizing failed, dest_dir invalid: %s', dirname($dest_file)), LOG_ERR, __FILE__, __LINE__);
-                    $return_val++;
-                    continue;
-                }
-            }
-
-            // Skip existing thumbnails with file size below $spec['keep_filesize'].
-            if (isset($spec['keep_filesize']) && file_exists($dest_file)) {
-                $file_size = filesize($dest_file);
-                if (false !== $file_size && $file_size < $spec['keep_filesize']) {
-                    $app->logMsg(sprintf('Skipping thumbnail %s. File already exists and file size is less than %s bytes.', $spec['dest_dir'] . '/' . $file_name, $spec['keep_filesize']), LOG_INFO, __FILE__, __LINE__);
-                    continue;
-                }
-            }
-
-            // Determine if original file size is smaller than specified thumbnail size. Do not scale-up if $spec['allow_upscaling'] config is set to false.
-            $image_size = getimagesize($source_file);
-            if ($image_size['0'] <= $spec['width'] && $image_size['1'] <= $spec['height'] && !$spec['allow_upscaling']) {
-                $spec['scaling_type'] = IMAGETHUMB_NO_SCALE;
-                $app->logMsg(sprintf('Image %s smaller than specified %s thumbnail size. Keeping original size.', $file_name, basename($spec['dest_dir'])), LOG_INFO, __FILE__, __LINE__);
-            }
-
-            // DO IT! Based on available method.
-            if (IMAGETHUMB_METHOD_NETPBM === $this->getParam('resize_method') && file_exists($this->getParam('anytopnm_binary')) && file_exists($this->getParam('pnmscale_binary')) && file_exists($this->getParam('cjpeg_binary'))) {
-                // Resize using Netpbm binaries.
-                $app->logMsg(sprintf('Resizing with Netpbm: %s', $source_file), LOG_DEBUG, __FILE__, __LINE__);
-                $return_val += $this->_resizeWithNetpbm($source_file, $dest_file, $spec);
-            } else if (IMAGETHUMB_METHOD_GD === $this->getParam('resize_method') && extension_loaded('gd')) {
-                // Resize with GD.
-                $app->logMsg(sprintf('Resizing with GD: %s', $source_file), LOG_DEBUG, __FILE__, __LINE__);
-                $return_val += $this->_resizeWithGD($source_file, $dest_file, $spec);
-            } else {
-                $app->logMsg(sprintf('Image thumbnailing canceled. Neither Netpbm or GD is available.', null), LOG_ERR, __FILE__, __LINE__);
-                return false;
-            }
-        }
-
-        // If > 0, there was a problem thumb-nailing.
-        return 0 === $return_val;
-    }
-
-    /*
-    * Use the Netpbm and libjpg cjpeg tools to generate a rescaled compressed image.
-    * This is the preferred method over GD which has (supposedly) less quality.
-    *
-    * @access   private
-    * @param    string  $source_file    Full path to source image file.
-    * @param    string  $dest_file      Full path to destination image file.
-    * @param    array   $spec           Array of image size specifications.
-    * @return   int                     0 if no error, n > 0 if errors.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    19 May 2006 13:55:46
-    */
-    protected function _resizeWithNetpbm($source_file, $dest_file, $spec)
-    {
-        $app =& App::getInstance();
-
-        // Define pnmscale arguments.
-        switch ($spec['scaling_type']) {
-        case IMAGETHUMB_FIT_WIDTH :
-            $pnmscale_args = sprintf(' -width %s ', escapeshellarg($spec['width']));
+            $pnmscale_args = sprintf(' -width %s ', escapeshellcmd($width));
             break;
         case IMAGETHUMB_FIT_HEIGHT :
-            $pnmscale_args = sprintf(' -height %s ', escapeshellarg($spec['height']));
+            if (empty($height)) {
+                App::logMsg('ImageThumb error: height not specified for IMAGETHUMB_FIT_HEIGHT.', LOG_ERR, __FILE__, __LINE__);
+                return false;
+            }
+            $pnmscale_args = sprintf(' -height %s ', escapeshellcmd($height));
             break;
         case IMAGETHUMB_FIT_LARGER :
-            $pnmscale_args = sprintf(' -xysize %s %s ', escapeshellarg($spec['width']), escapeshellarg($spec['height']));
+            if (empty($width) || empty($height)) {
+                App::logMsg('ImageThumb error: width or height not specified for IMAGETHUMB_FIT_LARGER.', LOG_ERR, __FILE__, __LINE__);
+                return false;
+            }
+            $pnmscale_args = sprintf(' -xysize %s %s ', escapeshellcmd($width), escapeshellcmd($height));
             break;
         case IMAGETHUMB_STRETCH :
-            $pnmscale_args = sprintf(' -width %s -height %s ', escapeshellarg($spec['width']), escapeshellarg($spec['height']));
+            if (empty($width) || empty($height)) {
+                App::logMsg('ImageThumb error: width or height not specified for IMAGETHUMB_STRETCH.', LOG_ERR, __FILE__, __LINE__);
+                return false;
+            }
+            $pnmscale_args = sprintf(' -width %s -height %s ', escapeshellcmd($width), escapeshellcmd($height));
             break;
         case IMAGETHUMB_NO_SCALE :
@@ -474,180 +144,193 @@
             break;
         }
-
+        
         // Define cjpeg arguments.
-        $cjpeg_args = sprintf(' -optimize -quality %s ', escapeshellarg($spec['quality']));
-        $cjpeg_args .= (true === $spec['progressive']) ? ' -progressive ' : '';
-
-        // Format the command that creates the thumbnail.
-        $command = sprintf('%s %s | %s %s | %s %s > %s',
-            escapeshellcmd($this->getParam('anytopnm_binary')),
-            escapeshellcmd($source_file),
-            escapeshellcmd($this->getParam('pnmscale_binary')),
-            escapeshellcmd($pnmscale_args),
-            escapeshellcmd($this->getParam('cjpeg_binary')),
-            escapeshellcmd($cjpeg_args),
-            escapeshellcmd($dest_file)
+        $cjpeg_args = sprintf(' -optimize -quality %s ', escapeshellcmd($quality));
+        $cjpeg_args .= (true === $progressive) ? ' -progressive ' : '';
+        
+        $this->spec[] = array(
+            'dest_dir' => $dest_dir,
+            'width' => $width,
+            'height' => $height,
+            'scaling_type' => $scaling_type,
+            'quality' => $quality,
+            'progressive' => $progressive,
+            'pnmscale_args' => $pnmscale_args,
+            'cjpeg_args' => $cjpeg_args,
+            'allow_upscaling' => $allow_upscaling,
+            'keep_filesize' => $keep_filesize,
         );
-        $app->logMsg(sprintf('ImageThumb Netpbm command: %s', $command), LOG_DEBUG, __FILE__, __LINE__);
-
-        // Execute!
-        exec($command, $output, $return_val);
-
-        if (0 === $return_val) {
-            // Success!
-            // Make the thumbnail writable so the user can delete it over ftp without being 'apache'.
-            chmod($dest_file, $this->getParam('dest_file_perms'));
-            $app->logMsg(sprintf('Successfully resized image %s', $spec['dest_dir'] . '/' . basename($dest_file), $return_val), LOG_DEBUG, __FILE__, __LINE__);
+    }
+
+    /**
+     * Make directory for each specified thumbnail size, if it doesn't exist.
+     *
+     * @access  public
+     * @return  bool true on success, false on failure.
+     */
+    function createDestDirs()
+    {
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before creating destination directories.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        $return_val = 0;
+        foreach ($this->spec as $s) {
+            if (!is_dir($this->source_dir . '/' . $s['dest_dir'])) {
+                if (!mkdir($this->source_dir . '/' . $s['dest_dir'], $this->dest_dir_perms)) {
+                    $return_val += 1;
+                    App::logMsg(sprintf('mkdir failure: %s', $this->source_dir . '/' . $s['dest_dir']), LOG_ERR, __FILE__, __LINE__);
+                }
+            }
+        }
+                
+        // If > 0, there was a problem creating dest dirs.
+        return (0 == $return_val);
+    }
+
+    /**
+     * Generate thumbnails for the specified file.
+     *
+     * @access  public
+     * @param   string $file_name Name of file with extention.
+     * @return  bool true on success, false on failure.
+     */
+    function processFile($file_name)
+    {
+        // Ensure we have valid binaries.
+        if (!$this->_valid_binaries) {
+            return false;
+        }
+        
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // To keep this script running even if user tries to stop browser.
+        ignore_user_abort(true); 
+        if (!ini_get('safe_mode')) { 
+            set_time_limit(300); 
+        }
+        
+        // Confirm source image exists.
+        if (!file_exists($this->source_dir . '/' . $file_name)) {
+            $this->raiseMsg(sprintf(_("Image resizing failed: source image not found: <strong>%s</strong>"), $file_name), MSG_ERR, __FILE__, __LINE__);
+            App::logMsg(sprintf('Source image not found: %s', $file_name), LOG_ALERT, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Confirm source image is readable.
+        if (!is_readable($this->source_dir . '/' . $file_name)) {
+            $this->raiseMsg(sprintf(_("Image resizing failed: source image not readable: <strong>%s</strong>"), $file_name), MSG_ERR, __FILE__, __LINE__);
+            App::logMsg(sprintf('Source image not readable: %s', $file_name), LOG_ALERT, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Confirm source image contains data.
+        if (filesize($this->source_dir . '/' . $file_name) < 1) {
+            $this->raiseMsg(sprintf(_("Image resizing failed: source image corrupt: <strong>%s</strong>"), $file_name), MSG_ERR, __FILE__, __LINE__);
+            App::logMsg(sprintf('Source image is zero bytes: %s', $file_name), LOG_ALERT, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Confirm source image has a valid file extension.
+        if (!$this->validFileExtension($file_name)) {
+            $this->raiseMsg(sprintf(_("Image resizing failed: source image not of valid type: <strong>%s</strong>"), $file_name), MSG_ERR, __FILE__, __LINE__);
+            App::logMsg(sprintf('Image resizing failed: source image not of valid type: %s', $file_name), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Output file will be a jpg. Set file extension.
+        $file_name = substr($file_name, 0, strrpos($file_name, '.')) . '.jpg';
+
+        // This remains zero until something goes wrong.
+        $final_return_val = 0;
+        
+        foreach ($this->spec as $s) {
+        
+            // Skip existing thumbnails with file size below $s['keep_filesize'].
+            if (file_exists(realpath($this->source_dir . '/' . $s['dest_dir'] . '/' . $file_name)) && isset($s['keep_filesize'])) {
+                $file_size = filesize(realpath($this->source_dir . '/' . $s['dest_dir'] . '/' . $file_name));
+                if ($file_size && $file_size < $s['keep_filesize']) {
+                    App::logMsg(sprintf('Skipping thumbnail %s. File already exists and file size is less than %s bytes.', $s['dest_dir'] . '/' . $file_name, $s['keep_filesize']), LOG_DEBUG, __FILE__, __LINE__);
+                    continue;
+                }
+            }
+            
+            // Determine if original file size is smaller than specified thumbnail size. Do not scale-up if allow_upscaling config is set to false.
+            $image_size = getimagesize(realpath($this->source_dir . '/' . $file_name));
+            if ($image_size['0'] <= $s['width'] && $image_size['1'] <= $s['height'] && !$s['allow_upscaling']) {
+                $pnmscale_args = ' 1 ';
+                App::logMsg(sprintf('Image %s smaller than specified %s thumbnail size. Keeping original size.', $file_name, $s['dest_dir']), LOG_DEBUG, __FILE__, __LINE__);
+            } else {
+                $pnmscale_args = $s['pnmscale_args'];
+            }
+            
+            // Execute the command that creates the thumbnail.
+            $command = sprintf('%s %s/%s | %s %s | %s %s > %s/%s',
+                escapeshellcmd($this->anytopnm_binary),
+                escapeshellcmd($this->source_dir),
+                escapeshellcmd($file_name),
+                escapeshellcmd($this->pnmscale_binary),
+                escapeshellcmd($pnmscale_args),
+                escapeshellcmd($this->cjpeg_binary),
+                escapeshellcmd($s['cjpeg_args']), 
+                escapeshellcmd(realpath($this->source_dir . '/' . $s['dest_dir'])),
+                escapeshellcmd($file_name)
+            );
+            App::logMsg(sprintf('ImageThumb command: %s', $command), LOG_DEBUG, __FILE__, __LINE__);
+            exec($command, $output, $return_val);
+
+            if (0 == $return_val) {
+                // Make the thumbnail writable so the user can delete it over ftp without being 'apache'.
+                chmod(realpath($this->source_dir . '/' . $s['dest_dir'] . '/' . $file_name), $this->dest_file_perms);
+                App::logMsg(sprintf('Successfully resized image %s', $s['dest_dir'] . '/' . $file_name, $return_val), LOG_DEBUG, __FILE__, __LINE__);
+            } else {
+                App::logMsg(sprintf('Image %s failed resizing with return value: %s%s', $s['dest_dir'] . '/' . $file_name, $return_val, empty($output) ? '' : ' (' . getDump($output) . ')'), LOG_ERR, __FILE__, __LINE__);
+            }
+            
+            // Return from the command will be > 0 if there was an error.
+            $final_return_val += $return_val;
+        }
+        
+        // If > 0, there was a problem thumbnailing.
+        return (0 == $final_return_val);
+    }
+
+    /**
+     * Process an entire directory of images.
+     *
+     * @access  public
+     * @return  bool true on success, false on failure.
+     */
+    function processAll()
+    {
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Get all files in source directory.
+        $dir_handle = opendir($this->source_dir);
+        while ($dir_handle && ($file = readdir($dir_handle)) !== false) {
+            // If the file name does not start with a dot (. or .. or .htaccess).
+            if (!preg_match('/^\./', $file) && in_array(strtolower(substr($file, strrpos($file, '.') + 1)), $this->valid_file_extensions)) {
+                $files[] = $file;
+            }
+        }
+        
+        // Process each found file.
+        if (is_array($files) && !empty($files)) {
+            foreach ($files as $file_name) {
+                $this->processFile($file_name);
+            }
+            return sizeof($files);
         } else {
-            // An error occurred.
-            $app->logMsg(sprintf('Image %s failed resizing with return value: %s%s', $spec['dest_dir'] . '/' . basename($dest_file), $return_val, empty($output) ? '' : ' (' . truncate(getDump($output, true), 128, 'end') . ')'), LOG_ERR, __FILE__, __LINE__);
-        }
-
-        // Return from the command will be > 0 if there was an error.
-        return $return_val;
-    }
-
-    /*
-    * Use PHP's built-in GD tools to generate a rescaled compressed image.
-    *
-    * @access   private
-    * @param    string  $source_file    Full path to source image file.
-    * @param    string  $dest_file      Full path to destination image file.
-    * @param    array   $spec           Array of image size specifications.
-    * @return   int                     0 if no error, n > 0 if errors.
-    * @author   Quinn Comendant <quinn@strangecode.com>
-    * @version  1.0
-    * @since    19 May 2006 15:46:02
-    */
-    protected function _resizeWithGD($source_file, $dest_file, $spec)
-    {
-        $app =& App::getInstance();
-
-        // Get original file dimensions and type.
-        list($source_image_width, $source_image_height, $source_image_type) = getimagesize($source_file);
-
-        // Define destination image dimensions.
-        switch ($spec['scaling_type']) {
-        case IMAGETHUMB_FIT_WIDTH :
-            $dest_image_width = $spec['width'];
-            $dest_image_height = $source_image_height * ($spec['width'] / $source_image_width);
-            break;
-        case IMAGETHUMB_FIT_HEIGHT :
-            $dest_image_height = $spec['height'];
-            $dest_image_width = $source_image_width * ($spec['height'] / $source_image_height);
-            break;
-        case IMAGETHUMB_FIT_LARGER :
-            if (($source_image_width * ($spec['height'] / $source_image_height)) <= $spec['width']) {
-                // Height is larger.
-                $dest_image_height = $spec['height'];
-                $dest_image_width = $source_image_width * ($spec['height'] / $source_image_height);
-            } else {
-                // Width is larger.
-                $dest_image_width = $spec['width'];
-                $dest_image_height = $source_image_height * ($spec['width'] / $source_image_width);
-            }
-            break;
-        case IMAGETHUMB_STRETCH :
-            $dest_image_width = $spec['width'];
-            $dest_image_height = $spec['height'];
-            break;
-        case IMAGETHUMB_NO_SCALE :
-        default :
-            $dest_image_width = $source_image_width;
-            $dest_image_height = $source_image_height;
-            break;
-        }
-
-        // Create source image data in memory.
-        switch ($source_image_type) {
-        case IMAGETYPE_JPEG : // = 2
-            $source_image_resource = imagecreatefromjpeg($source_file);
-            break;
-        case IMAGETYPE_PNG : // = 3
-            $source_image_resource = imagecreatefrompng($source_file);
-            break;
-        case IMAGETYPE_GIF : // = 1
-            $source_image_resource = imagecreatefromgif($source_file);
-            break;
-        case IMAGETYPE_WBMP : // = 15
-            $source_image_resource = imagecreatefromwbmp($source_file);
-        case IMAGETYPE_SWF : // = 4
-        case IMAGETYPE_PSD : // = 5
-        case IMAGETYPE_BMP : // = 6
-        case IMAGETYPE_TIFF_II : // = 7
-        case IMAGETYPE_TIFF_MM : // = 8
-        case IMAGETYPE_JPC : // = 9
-        case IMAGETYPE_JP2 : // = 10
-        case IMAGETYPE_JPX : // = 11
-        case IMAGETYPE_JB2 : // = 12
-        case IMAGETYPE_SWC : // = 13
-        case IMAGETYPE_IFF : // = 14
-        case IMAGETYPE_XBM : // = 16
-        default :
-            $app->logMsg(sprintf('Source image type %s not supported.', $source_image_type), LOG_WARNING, __FILE__, __LINE__);
-            return 1;
-        }
-        if (!$source_image_resource) {
-            $app->logMsg(sprintf('Error creating %s image in memory from %s', $source_image_type, $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return 1;
-        }
-
-        // Create destination image data in memory.
-        $dest_image_resource = imagecreatetruecolor($dest_image_width, $dest_image_height);
-
-        // Resample!
-        if (!imagecopyresampled($dest_image_resource, $source_image_resource, 0, 0, 0, 0, $dest_image_width, $dest_image_height, $source_image_width, $source_image_height)) {
-            // Always cleanup images from memory.
-            imagedestroy($source_image_resource);
-            imagedestroy($dest_image_resource);
-            $app->logMsg(sprintf('Error resampling image %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return 1;
-        }
-
-        // Sharpen image using a custom filter matrix.
-        if (version_compare(PHP_VERSION, '5.1.0', '>=') && true === $spec['sharpen'] && $spec['sharpen_value'] > 0) {
-            $sharpen_value = round((((48 - 10) / (100 - 1)) * (100 - $spec['sharpen_value'])) + 10); // TODO: WTF is this math?
-            imageconvolution($dest_image_resource, array(array(-1, -1, -1), array(-1, $sharpen_value, -1),array(-1, -1, -1)), ($sharpen_value - 8), 0);
-        }
-
-        // Save image.
-        $return_val = true;
-        switch ($spec['dest_file_type']) {
-        case IMG_JPG :
-            imageinterlace($dest_image_resource, (true == $spec['progressive'] ? 1 : 0));
-            $return_val = imagejpeg($dest_image_resource, $dest_file, $spec['quality']);
-            break;
-        case IMG_PNG :
-            $return_val = imagepng($dest_image_resource, $dest_file);
-            break;
-        case IMG_GIF :
-            $return_val = imagegif($dest_image_resource, $dest_file);
-            break;
-        case IMG_WBMP :
-            $return_val = imagewbmp($dest_image_resource, $dest_file);
-            break;
-        default :
-            $app->logMsg(sprintf('Destination image type %s not supported for image %s.', $spec['dest_file_type'], $dest_file), LOG_WARNING, __FILE__, __LINE__);
-            // Always cleanup images from memory.
-            imagedestroy($source_image_resource);
-            imagedestroy($dest_image_resource);
-            return 1;
-            break;
-        }
-
-        // Always cleanup images from memory.
-        imagedestroy($source_image_resource);
-        imagedestroy($dest_image_resource);
-
-        if ($return_val) {
-            // Success!
-            // Make the thumbnail writable so the user can delete it over ftp without being 'apache'.
-            chmod($dest_file, $this->getParam('dest_file_perms'));
-            $app->logMsg(sprintf('Successfully resized image: %s', $dest_file), LOG_DEBUG, __FILE__, __LINE__);
+            App::logMsg(sprintf('No images found to thumbnail in directory %s.', $this->source_dir), LOG_NOTICE, __FILE__, __LINE__);
             return 0;
-        } else {
-            // An error occurred.
-            $app->logMsg(sprintf('Failed resizing image: %s', $dest_file), LOG_ERR, __FILE__, __LINE__);
-            return 1;
         }
     }
@@ -657,37 +340,27 @@
      *
      * @access  public
-     * @param   string  $file_name  The file name to delete, with extension.
-     * @param   bool    $use_glob   Set true to use glob to find the filename (using $file_name as a pattern)
-     * @return  bool true on success, false on failure.
-     */
-    public function deleteThumbs($file_name, $use_glob=false)
-    {
-        $app =& App::getInstance();
-
-        // Ensure we have a source.
-        if ('' == $this->getParam('source_dir')) {
-            $app->logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
-            return false;
-        }
-
-        $return_val = 0;
-        foreach ($this->_image_specs as $spec) {
-            // Get base directory depending on if the spec's dest_dir is an absolute path or not.
-            $dest_dir = '/' == $spec['dest_dir'][0] ? $spec['dest_dir'] : sprintf('%s/%s', $this->getParam('source_dir'), $spec['dest_dir']);
-            if ($use_glob) {
-                $dest_file = realpath(sprintf('%s/%s', $dest_dir, $this->_glob($file_name, $dest_dir)));
-            } else {
-                $dest_file = realpath(sprintf('%s/%s.%s', $dest_dir, mb_substr($file_name, 0, mb_strrpos($file_name, '.')), $spec['dest_file_extension']));
-            }
-
-            if (file_exists($dest_file)) {
-                if (!unlink($dest_file)) {
-                    $return_val++;
-                    $app->logMsg(sprintf('Delete thumbs failed: %s', $dest_file), LOG_WARNING, __FILE__, __LINE__);
+     * @param   string $file_name The file name to delete, with extention.
+     * @return  bool true on success, false on failure.
+     */
+    function deleteThumbs($file_name)
+    {
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        $ret = 0;
+        foreach ($this->spec as $s) {
+            $file_path_name = realpath($this->source_dir . '/' . $s['dest_dir'] . '/' . $file_name);
+            if (file_exists($file_path_name)) {
+                if (!unlink($file_path_name)) {
+                    $ret++;
+                    App::logMsg(sprintf(_("Delete thumbs failed: %s"), $file_path_name), LOG_WARNING, __FILE__, __LINE__);
                 }
             }
         }
-        $app->logMsg(sprintf('Thumbnails deleted for file: %s', $dest_file), LOG_DEBUG, __FILE__, __LINE__);
-        return 0 === $return_val;
+        $this->raiseMsg(sprintf(_("The thumbnails for file <strong>%s</strong> have been deleted."), $file_name), MSG_SUCCESS, __FILE__, __LINE__);
+        return (0 == $ret);
     }
 
@@ -696,56 +369,44 @@
      *
      * @access  public
-     * @param   string $file_name The file name to delete, with extension.
-     * @return  bool true on success, false on failure.
-     */
-    public function deleteOriginal($file_name)
-    {
-        $app =& App::getInstance();
-
-        // Ensure we have a source.
-        if ('' == $this->getParam('source_dir')) {
-            $app->logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
-            return false;
-        }
-
-        // Ensure we have a source.
-        if ('' == $file_name) {
-            $app->logMsg(sprintf('Cannot delete, filename empty.'), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-
-        $source_file = realpath(sprintf('%s/%s', $this->getParam('source_dir'), $file_name));
-        if (is_file($source_file) && unlink($source_file)) {
-            $app->logMsg(sprintf('Original file successfully deleted: %s', $file_name), LOG_INFO, __FILE__, __LINE__);
-            return true;
-        } else {
-            $app->logMsg(sprintf('Delete original failed: %s', $source_file), LOG_WARNING, __FILE__, __LINE__);
-            return false;
-        }
-    }
-
+     * @param   string $file_name The file name to delete, with extention.
+     * @return  bool true on success, false on failure.
+     */
+    function deleteOriginal($file_name)
+    {
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        $file_path_name = $this->source_dir . '/' . $file_name;
+        if (!unlink($file_path_name)) {
+            App::logMsg(sprintf(_("Delete original failed: %s"), $file_path_name), LOG_WARNING, __FILE__, __LINE__);
+            return false;
+        }
+        $this->raiseMsg(sprintf(_("The original file <strong>%s</strong> has been deleted."), $file_name), MSG_SUCCESS, __FILE__, __LINE__);
+        return true;
+    }
+    
     /**
      * Returns true if file exists.
      *
      * @access  public
-     * @param   string $file_name The file name to test, with extension.
-     * @return  bool true on success, false on failure.
-     */
-    public function exists($file_name)
-    {
-        $app =& App::getInstance();
-
-        // Ensure we have a source.
-        if ('' == $this->getParam('source_dir')) {
-            $app->logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
-            return false;
-        }
-
-        $source_file = realpath(sprintf('%s/%s', $this->getParam('source_dir'), $file_name));
-        return file_exists($source_file);
-    }
-
-    /**
-     * Tests if extension of $file_name is in the array valid_file_extensions.
+     * @param   string $file_name The file name to test, with extention.
+     * @return  bool true on success, false on failure.
+     */
+    function exists($file_name)
+    {
+        // Ensure we have a source.
+        if (!isset($this->source_dir)) {
+            App::logMsg(sprintf('Source directory not set before processing.'), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+        
+        return file_exists($this->source_dir . '/' . $file_name);
+    }
+    
+    /**
+     * Tests if extention of $file_name is in the array valid_file_extensions.
      *
      * @access  public
@@ -753,65 +414,12 @@
      * @return  bool    True on success, false on failure.
      */
-    protected function _validFileExtension($file_name)
+    function validFileExtension($file_name)
     {
         preg_match('/.*?\.(\w+)$/i', $file_name, $ext);
-        return !empty($ext) && in_array(mb_strtolower($ext[1]), $this->getParam('valid_file_extensions'));
-    }
-
-    /**
-     * Make directory for each specified thumbnail size, if it doesn't exist.
-     *
-     * @access  public
-     * @return  bool true on success, false on failure.
-     */
-    protected function _createDestDirs($filename=null)
-    {
-        $app =& App::getInstance();
-
-        // Keep track of directories we've already created.
-        $dd_hash = md5(isset($filename) ? dirname($filename) : 'none');
-        static $already_checked = array();
-
-        $return_val = 0;
-
-        if (!isset($already_checked[$dd_hash])) {
-            // Ensure we have a source.
-            if ('' == $this->getParam('source_dir')) {
-                $app->logMsg(sprintf('Source directory not set before creating destination directories.'), LOG_ERR, __FILE__, __LINE__);
-                return false;
-            }
-
-            // Loop through specs and ensure all dirs are created.
-            foreach ($this->_image_specs as $spec) {
-                if (isset($filename)) {
-                    $dest_dir = dirname($filename);
-                } else {
-                    // Get base directory depending on if the spec's dest_dir is an absolute path or not.
-                    $dest_dir = '/' == $spec['dest_dir'][0] ? $spec['dest_dir'] : sprintf('%s/%s', $this->getParam('source_dir'), $spec['dest_dir']);
-                }
-                if (!file_exists($dest_dir)) {
-                    // Recursively create destination directory.
-                    $app->logMsg(sprintf('Creating dest dir: %s', $dest_dir), LOG_DEBUG, __FILE__, __LINE__);
-                    if (!file_exists($dest_dir) && !($ret = mkdir($dest_dir, $this->getParam('dest_dir_perms'), true))) {
-                        $return_val++;
-                        $app->logMsg(sprintf('mkdir failure: %s', $dest_dir), LOG_ERR, __FILE__, __LINE__);
-                    }
-                    if ($ret) {
-                        $app->logMsg(sprintf('mkdir success: %s', $dest_dir), LOG_DEBUG, __FILE__, __LINE__);
-                    }
-                } else {
-                    $app->logMsg(sprintf('Dest dir exists: %s', $dest_dir), LOG_DEBUG, __FILE__, __LINE__);
-                }
-            }
-        }
-
-        $already_checked[$dd_hash] = true;
-
-        // If > 0, there was a problem creating dest dirs.
-        return 0 === $return_val;
-    }
-
-    /**
-     * An alias for $app->raiseMsg that only sends messages configured by display_messages.
+        return in_array(strtolower($ext[1]), $this->valid_file_extensions);
+    }
+    
+    /**
+     * An alias for App::raiseMsg that only sends messages if display_messages is true.
      *
      * @access public
@@ -823,33 +431,11 @@
      * @param string $line    __LINE__.
      */
-    protected function _raiseMsg($message, $type, $file, $line)
-    {
-        $app =& App::getInstance();
-
-        if ($this->getParam('display_messages') === true || (is_int($this->getParam('display_messages')) && $this->getParam('display_messages') & $type > 0)) {
-            $app->raiseMsg($message, $type, $file, $line);
-        }
-    }
-
-    /**
-     * Get filename by glob pattern. Searches a directory for an image that matches the
-     * specified glob pattern and returns the filename of the first file found.
-     *
-     * @access  public
-     * @param   string  $pattern    Pattern to match filename.
-     * @param   string  $directory  Pattern to match containing directory.
-     * @return  string filename on success, empty string on failure.
-     * @author  Quinn Comendant <quinn@strangecode.com>
-     * @since   15 Nov 2005 20:55:22
-     */
-    protected function _glob($pattern, $directory)
-    {
-        $file_list = glob(sprintf('%s/%s', $directory, $pattern));
-        if (isset($file_list[0])) {
-            return basename($file_list[0]);
-        } else {
-            return '';
+    function raiseMsg($message, $type, $file, $line)
+    {
+        if ($this->display_messages) {
+            App::raiseMsg($message, $type, $file, $line);
         }
     }
 
 } // End of class.
+?>
