/**
  * @param string $imagePath - either a local absolute/relative path, or a remote URL (e.g. http://...flickr.com/.../ ). See SECURITY note above.
  * @param array $opts (
  *  curl(boolean) = false,
  *  maxCurlSize(int in Mbytes),
  *  w(pixels),
  *  h(pixels),
  *  crop(boolean) = false,
  *  scale(boolean) = true,
  *  thumbnail(boolean) = false,
  *  maxOnly(boolean) = true, # Resize only when file is larger.
  *  canvasColor(string) = '#FFFFFF',
  *  resultDir = null,
  *  remoteDir = null,
  *  outputFilename(string) = false,
  *  cacheHttpMinutes(int) = 20,
  *  overwrite(boolean) - false,
  *  onlyCreateWhenNew(boolean) - true)
  * @throws \Exception
  * @return bool|mixed|string string new URL for resized image.
  */
 public static function resize($imagePath, $opts = null)
 {
     $imagePath = urldecode($imagePath);
     # start configuration
     $resultDir = null;
     if (!empty($opts['resultDir'])) {
         $resultDir = $opts['resultDir'];
         # path to your result Dir, must be writeable by web server
         $resultDir = str_replace('/', DIRECTORY_SEPARATOR, $resultDir);
     }
     $remoteDir = null;
     if (!empty($opts['remoteDir'])) {
         $remoteDir = $opts['remoteDir'];
     }
     if (empty($remoteDir)) {
         $remoteDir = $resultDir . 'remote/';
         # path to the Dir you wish to download remote images into
     }
     $overwrite = false;
     if (isset($opts['overwrite'])) {
         $overwrite = $opts['overwrite'];
     }
     $onlyCreateWhenNew = true;
     if (isset($opts['onlyCreateWhenNew'])) {
         $onlyCreateWhenNew = $opts['onlyCreateWhenNew'];
     }
     $defaults = array('curl' => false, 'crop' => false, 'scale' => true, 'thumbnail' => false, 'maxOnly' => true, 'canvasColor' => '#FFFFFF', 'outputFilename' => false, 'resultDir' => $resultDir, 'remoteDir' => $remoteDir, 'quality' => 90, 'cacheHttpMinutes' => 20);
     $opts = array_merge($defaults, $opts);
     $path_to_convert = 'convert';
     # this could be something like /usr/bin/convert or /opt/local/share/bin/convert
     ## you shouldn't need to configure anything else beyond this point
     $purl = parse_url($imagePath);
     $finfo = pathinfo($imagePath);
     $ext_r = explode('.', $imagePath);
     $ext = $ext_r[count($ext_r) - 1];
     //if not using imagic, run the following code and return the new path immediately
     if (!empty($opts['noImagick']) && $opts['noImagick']) {
         if (file_exists($imagePath) == false) {
             $imagePath = $_SERVER['DOCUMENT_ROOT'] . $imagePath;
             if (file_exists($imagePath) == false) {
                 throw new \Exception("Image not found. (" . $imagePath . ")");
             }
         }
         $filename = md5_file($imagePath);
         if (false !== $opts['outputFilename']) {
             $opts['outputFilename'] = str_replace('/', DIRECTORY_SEPARATOR, $opts['outputFilename']);
             $newPath = $resultDir . $opts['outputFilename'];
         } else {
             $newPath = $resultDir . $filename . $ext;
         }
         if (move_uploaded_file($imagePath, $newPath)) {
             return $newPath;
         } else {
             $e = new \Exception("Unable to move the uploaded file. Please check your Dir permission.");
             throw $e;
         }
     }
     # check for remote image..
     if (isset($purl['scheme']) && ($purl['scheme'] == 'http' || $purl['scheme'] == 'https')) {
         # grab the image, and cache it so we have something to work with..
         list($filename) = explode('?', $finfo['basename']);
         $local_filepath = $remoteDir . $filename;
         $download_image = true;
         if (file_exists($local_filepath)) {
             if (filemtime($local_filepath) < strtotime('+' . $opts['cacheHttpMinutes'] . ' minutes')) {
                 $download_image = false;
             }
         }
         if ($download_image == true) {
             try {
                 if ($opts['curl'] == true) {
                     if (!empty($opts['maxCurlSize'])) {
                         if (ImageProcessor::grabSize($imagePath) <= $opts['maxCurlSize'] * 1024 * 1024) {
                             ImageProcessor::grabImage($imagePath, $local_filepath);
                         } else {
                             throw new \Exception("image too large");
                         }
                     } else {
                         ImageProcessor::grabImage($imagePath, $local_filepath);
                     }
                 }
                 $img = @file_get_contents($imagePath);
                 if (empty($img)) {
                     return "invalid image pathname";
                 } else {
                     file_put_contents($local_filepath, $img);
                 }
             } catch (\Exception $e) {
                 throw new \Exception("ERROR: While doing image resize, got this error: " . $e->getMessage());
             }
         }
         $imagePath = $local_filepath;
     }
     if (file_exists($imagePath) == false) {
         $imagePath = $_SERVER['DOCUMENT_ROOT'] . $imagePath;
         if (file_exists($imagePath) == false) {
             throw new \Exception('image not found. (' . $imagePath . ')');
         }
     }
     $w = 0;
     if (isset($opts['w'])) {
         $w = $opts['w'];
     }
     if (isset($opts['h'])) {
         $h = $opts['h'];
     }
     $filename = md5_file($imagePath);
     // If the user has requested an explicit outputFilename, do not use the cache directory.
     if (false !== $opts['outputFilename']) {
         $newPath = $resultDir . $opts['outputFilename'];
     } else {
         if (!empty($w) and !empty($h)) {
             $newPath = $resultDir . $filename . '_w' . $w . '_h' . $h . (isset($opts['crop']) && $opts['crop'] == true ? "_cp" : "") . (isset($opts['scale']) && $opts['scale'] == true ? "_sc" : "") . '.' . $ext;
         } elseif (!empty($w)) {
             $newPath = $resultDir . $filename . '_w' . $w . '.' . $ext;
         } elseif (!empty($h)) {
             $newPath = $resultDir . $filename . '_h' . $h . '.' . $ext;
         } else {
             return false;
         }
     }
     $create = true;
     if ($onlyCreateWhenNew) {
         if (file_exists($newPath) == true) {
             $create = false;
             $origFileTime = date("YmdHis", filemtime($imagePath));
             $newFileTime = date("YmdHis", filemtime($newPath));
             if ($newFileTime < $origFileTime) {
                 # Not using $opts['expire-time'] ??
                 $create = true;
             }
         }
     } else {
         if (!$overwrite) {
             if (file_exists($newPath) == true) {
                 $newExt = substr(strrchr($newPath, '.'), 1);
                 $pos = strrpos($newPath, '.' . $newExt);
                 if ($pos !== false) {
                     $noExt = substr_replace($newPath, '', $pos, strlen('.' . $newExt));
                     $count = 1;
                     while (file_exists($noExt . '-' . $count . '.' . $newExt)) {
                         $count += 1;
                     }
                     $newPath = $noExt . '-' . $count . '.' . $newExt;
                 } else {
                     $noExt = $newPath;
                     $count = 1;
                     while (file_exists($noExt . '-' . $count)) {
                         $count += 1;
                     }
                     $newPath = $noExt . '-' . $count;
                 }
             }
         }
     }
     if ($create == true) {
         if (!empty($w) and !empty($h)) {
             list($width, $height) = getimagesize($imagePath);
             if ($width > $height) {
                 $resize = $w;
                 if (true === $opts['crop']) {
                     $resize = "x" . $h;
                 }
             } else {
                 $resize = "x" . $h;
                 if (true === $opts['crop']) {
                     $resize = $w;
                 }
             }
             if (!empty($opts['imagickProgressive']) && $opts['imagickProgressive']) {
                 $progressiveCommand = "-strip -interlace Plane";
             } else {
                 $progressiveCommand = "";
             }
             if (true === $opts['scale']) {
                 $resize = $w . "x" . $h;
                 $cmd = $path_to_convert . " {$progressiveCommand} " . escapeshellarg($imagePath) . " -resize " . escapeshellarg($resize) . (true === $opts['crop'] ? "^ -background transparent -gravity center -extent " . escapeshellarg($resize) : "") . " -quality " . escapeshellarg($opts['quality']) . " " . escapeshellarg($newPath);
             } else {
                 $cmd = $path_to_convert . " {$progressiveCommand} " . escapeshellarg($imagePath) . " -resize " . escapeshellarg($resize) . " -size " . escapeshellarg($w . "x" . $h) . " xc:" . escapeshellarg($opts['canvasColor']) . " +swap -gravity center -composite -quality " . escapeshellarg($opts['quality']) . " " . escapeshellarg($newPath);
             }
         } else {
             if (self::isWindows()) {
                 $maxSign = "^>";
             } else {
                 $maxSign = "\\>";
             }
             $cmd = $path_to_convert . " " . escapeshellarg($imagePath) . " -thumbnail " . (!empty($h) ? 'x' : '') . $w . "" . (isset($opts['maxOnly']) && $opts['maxOnly'] == true ? $maxSign : "") . " -quality " . escapeshellarg($opts['quality']) . " " . escapeshellarg($newPath);
         }
         exec($cmd, $output, $return_code);
         if ($return_code == 127) {
             $path_to_convert = '/usr/local/bin/convert';
             # this could be something like /usr/bin/convert or /opt/local/share/bin/convert
             $cmd = preg_replace('/convert/', $path_to_convert, $cmd, 1);
             exec($cmd, $output, $return_code);
         }
         if ($return_code != 0) {
             throw new \Exception("Tried to execute : {$cmd}, return code: {$return_code}, output: " . print_r($output, true));
         }
     }
     # return cache file path
     return $newPath;
 }