static function applyUnsharpMask(&$img, $amount, $radius, $threshold)
 {
     // $img is an image that is already created within php using
     // imgcreatetruecolor. No url! $img must be a truecolor image.
     // Attempt to calibrate the parameters to Photoshop:
     $amount = min($amount, 500) * 0.016;
     $radius = abs(round(min(50, $radius) * 2));
     // Only integers make sense.
     $threshold = min(255, $threshold);
     if ($radius == 0) {
         return true;
     }
     $w = ImageSX($img);
     $h = ImageSY($img);
     $imgCanvas = ImageCreateTrueColor($w, $h);
     $imgBlur = ImageCreateTrueColor($w, $h);
     // Gaussian blur matrix:
     //
     //    1    2    1
     //    2    4    2
     //    1    2    1
     //
     //////////////////////////////////////////////////
     if (function_exists('imageconvolution')) {
         // PHP >= 5.1
         $matrix = array(array(1, 2, 1), array(2, 4, 2), array(1, 2, 1));
         ImageCopy($imgBlur, $img, 0, 0, 0, 0, $w, $h);
         ImageConvolution($imgBlur, $matrix, 16, 0);
     } else {
         // Move copies of the image around one pixel at the time and merge them with weight
         // according to the matrix. The same matrix is simply repeated for higher radii.
         for ($i = 0; $i < $radius; $i++) {
             ImageCopy($imgBlur, $img, 0, 0, 1, 0, $w - 1, $h);
             // left
             ImageCopyMerge($imgBlur, $img, 1, 0, 0, 0, $w, $h, 50);
             // right
             ImageCopyMerge($imgBlur, $img, 0, 0, 0, 0, $w, $h, 50);
             // center
             ImageCopy($imgCanvas, $imgBlur, 0, 0, 0, 0, $w, $h);
             ImageCopyMerge($imgBlur, $imgCanvas, 0, 0, 0, 1, $w, $h - 1, 33.33333);
             // up
             ImageCopyMerge($imgBlur, $imgCanvas, 0, 1, 0, 0, $w, $h, 25);
             // down
         }
     }
     if ($threshold > 0) {
         // Calculate the difference between the blurred pixels and the original
         // and set the pixels
         for ($x = 0; $x < $w - 1; $x++) {
             // each row
             for ($y = 0; $y < $h; $y++) {
                 // each pixel
                 $rgbOrig = ImageColorAt($img, $x, $y);
                 $rOrig = $rgbOrig >> 16 & 0xff;
                 $gOrig = $rgbOrig >> 8 & 0xff;
                 $bOrig = $rgbOrig & 0xff;
                 $rgbBlur = ImageColorAt($imgBlur, $x, $y);
                 $rBlur = $rgbBlur >> 16 & 0xff;
                 $gBlur = $rgbBlur >> 8 & 0xff;
                 $bBlur = $rgbBlur & 0xff;
                 // When the masked pixels differ less from the original
                 // than the threshold specifies, they are set to their original value.
                 $rNew = abs($rOrig - $rBlur) >= $threshold ? max(0, min(255, $amount * ($rOrig - $rBlur) + $rOrig)) : $rOrig;
                 $gNew = abs($gOrig - $gBlur) >= $threshold ? max(0, min(255, $amount * ($gOrig - $gBlur) + $gOrig)) : $gOrig;
                 $bNew = abs($bOrig - $bBlur) >= $threshold ? max(0, min(255, $amount * ($bOrig - $bBlur) + $bOrig)) : $bOrig;
                 if ($rOrig != $rNew || $gOrig != $gNew || $bOrig != $bNew) {
                     $pixCol = ImageColorAllocate($img, $rNew, $gNew, $bNew);
                     ImageSetPixel($img, $x, $y, $pixCol);
                 }
             }
         }
     } else {
         for ($x = 0; $x < $w; $x++) {
             // each row
             for ($y = 0; $y < $h; $y++) {
                 // each pixel
                 $rgbOrig = ImageColorAt($img, $x, $y);
                 $rOrig = $rgbOrig >> 16 & 0xff;
                 $gOrig = $rgbOrig >> 8 & 0xff;
                 $bOrig = $rgbOrig & 0xff;
                 $rgbBlur = ImageColorAt($imgBlur, $x, $y);
                 $rBlur = $rgbBlur >> 16 & 0xff;
                 $gBlur = $rgbBlur >> 8 & 0xff;
                 $bBlur = $rgbBlur & 0xff;
                 $rNew = min(255, max(0, $amount * ($rOrig - $rBlur) + $rOrig));
                 $gNew = min(255, max(0, $amount * ($gOrig - $gBlur) + $gOrig));
                 $bNew = min(255, max(0, $amount * ($bOrig - $bBlur) + $bOrig));
                 $rgbNew = ($rNew << 16) + ($gNew << 8) + $bNew;
                 ImageSetPixel($img, $x, $y, $rgbNew);
             }
         }
     }
     ImageDestroy($imgCanvas);
     ImageDestroy($imgBlur);
     return true;
 }
/**
 * Generates a resized version of an image and saves it in the image cache folder.
 * 
 * @param string $source_file The original image to be resized.
 * @param string $cache_file  The target file where the resized version will be cached.
 * @param int    $resolution  The resolution breakpoint at which the given image is to be resized.
 * @param int    $jpg_quality The JPEG quality that will be used for resizing the images.
 * @param bool   $sharpen     Whether to sharpen the resized images or not.
 * 
 * @return array Associative array( bool: success, string: message) with the result of the image cache generation.
 */
function adaptive_images_script_generate_image($source_file, $cache_file, $resolution, $jpg_quality, $sharpen)
{
    // Get original image dimensions.
    $dimensions = @GetImageSize($source_file);
    $width = $dimensions[0];
    $height = $dimensions[1];
    // Calculate resized image dimensions.
    $ratio = $height / $width;
    $new_width = $resolution;
    $new_height = ceil($new_width * $ratio);
    // Start creating the resized image with a blank true color canvas.
    $destination = @ImageCreateTrueColor($new_width, $new_height);
    $extension = adaptive_images_script_get_file_extension($source_file);
    switch ($extension) {
        case 'png':
            $source = @ImageCreateFromPng($source_file);
            break;
        case 'gif':
            $source = @ImageCreateFromGif($source_file);
            break;
        default:
            $source = @ImageCreateFromJpeg($source_file);
            break;
    }
    // PNG images generation.
    if ($extension == 'png') {
        // Create a transparent color and fill the blank canvas with it.
        $rbga_color = @ImageColorAllocateAlpha($destination, 0, 0, 0, 127);
        @ImageColorTransparent($destination, $rbga_color);
        @ImageFill($destination, 0, 0, $rbga_color);
        // Copy source image to destination image with interpolation.
        @ImageCopyResampled($destination, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
        // Convert true colour image to pallette image to achieve PNG-8 compression.
        $dither = TRUE;
        @ImageTrueColorToPalette($destination, $dither, 255);
        // Save alpha (transparency) of destination image.
        $save_alpha = TRUE;
        @ImageSaveAlpha($destination, $save_alpha);
        // Disable blending of destination image to allow for alpha (transparency) above.
        $enable_alpha_blending = FALSE;
        @ImageAlphaBlending($destination, $enable_alpha_blending);
    }
    // GIF images generation.
    if ($extension == 'gif') {
        // Create a transparent color and fill the blank canvas with it.
        $rbga_color = @ImageColorAllocateAlpha($destination, 0, 0, 0, 127);
        @ImageColorTransparent($destination, $rbga_color);
        @ImageFill($destination, 0, 0, $rbga_color);
        // Copy source image to destination image with interpolation.
        @ImageCopyResampled($destination, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
        // Convert true colour image to pallette image to achieve PNG8 compression.
        $dither = TRUE;
        @ImageTrueColorToPalette($destination, $dither, 255);
        // Enable alpha blending of destination image.
        $enable_alpha_blending = TRUE;
        @ImageAlphaBlending($destination, $enable_alpha_blending);
    }
    // JPEG images generation.
    if ($extension == 'jpg' || $extension == 'jpeg') {
        // Enable JPEG interlacing.
        ImageInterlace($destination, TRUE);
        // Interpolates source image to destination image to make it more clear for JPGs.
        @ImageCopyResampled($destination, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    }
    // Cleanup source image from memory.
    @ImageDestroy($source);
    // Do sharpening if requested.
    if ($sharpen && function_exists('imageconvolution')) {
        $sharpness_factor = adaptive_images_script_sharpness_factor($width, $new_width);
        $sharpness_transformation_matrix = array(array(-1, -2, -1), array(-2, $sharpness_factor + 12, -2), array(-1, -2, -1));
        // OR
        // $sharpenMatrix = array
        // (
        //     array(-1.2, -1, -1.2),
        //     array(-1, 20, -1),
        //     array(-1.2, -1, -1.2)
        // );
        // $divisor = array_sum(array_map('array_sum', $sharpenMatrix));
        // OR
        // $sharpen = array(
        //     array(0.0, -1.0, 0.0),
        //     array(-1.0, 5.0, -1.0),
        //     array(0.0, -1.0, 0.0)
        // );
        // $divisor = array_sum(array_map('array_sum', $sharpen));
        // OR
        // $matrix = array(
        //     array(-1, -1, -1),
        //     array(-1, 16, -1),
        //     array(-1, -1, -1),
        // );
        // $divisor = array_sum(array_map('array_sum', $matrix));
        @ImageConvolution($destination, $sharpness_transformation_matrix, $sharpness_factor, 0);
    }
    // Check and ensure that cache directory is setup OK.
    $cache_path = dirname($cache_file);
    if (!adaptive_images_script_ensure_cache_directory_ready($cache_path)) {
        return array('success' => false, 'message' => 'Cache directory for image not accessible or writeable.');
    }
    // Save resized image in cache.
    switch ($extension) {
        case 'png':
            $png_compression_level = 6;
            $image_saved = @ImagePng($destination, $cache_file, $png_compression_level, PNG_FILTER_NONE);
            break;
        case 'gif':
            $image_saved = @ImageGif($destination, $cache_file);
            break;
        default:
            $image_saved = @ImageJpeg($destination, $cache_file, $jpg_quality);
            break;
    }
    // Cleanup destination image from memory.
    @ImageDestroy($destination);
    // Check if all OK.
    if (!$image_saved && !file_exists($cache_file)) {
        return array('success' => false, 'message' => 'Resized image could not be created.');
    }
    // Return file of resized and cached image.
    return array('success' => true, 'message' => $cache_file);
}