'textfield', '#title' => t('JPEG quality'), '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality, but bigger files.'), '#size' => 10, '#maxlength' => 3, '#default_value' => variable_get('imageapi_jpeg_quality', 75), '#field_suffix' => '%', ); $form['imageapi_crop_background'] = array( '#type' => 'textfield', '#title' => t('Crop background'), '#description' => t('Hex string specifying the background color to use when cropping images. If not provided, will use the default. Examples: "ABC", "ABCD", "AABBCC", "AABBCCDD".'), '#size' => 10, '#maxlength' => 8, '#default_value' => variable_get('imageapi_crop_background', ''), '#field_prefix' => '#', ); return system_settings_form($form); } /** * Open an image file. * * @param $image * An image object. The $image->resource value will populated by this call. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_open($image) { $extension = str_replace('jpg', 'jpeg', $image->info['extension']); $function = 'imagecreatefrom'. $extension; return (function_exists($function) && $image->resource = $function($image->source)); } /** * Save an image file to a destination. * * @param $image * An image object. * @param $destination * A string file path where the image should be saved. * @param $extension * A string containing one of the following extensions: gif, jpg, jpeg, png. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_close($image, $destination) { $extension = str_replace('jpg', 'jpeg', $image->info['extension']); $function = 'image'. $extension; if (!function_exists($function)) { return FALSE; } if ($extension == 'jpeg') { return $function($image->resource, $destination, variable_get('imageapi_jpeg_quality', 75)); } else { // Always save PNG images with full transparency. if ($extension == 'png') { imagealphablending($image->resource, FALSE); imagesavealpha($image->resource, TRUE); } return $function($image->resource, $destination); } } /** * Crop an image using the GD toolkit. * * @param $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param $x * The starting x offset at which to start the crop, in pixels. * @param $y * The starting y offset at which to start the crop, in pixels. * @param $width * The width of the cropped area, in pixels. * @param $height * The height of the cropped area, in pixels. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_crop(&$image, $x, $y, $width, $height) { $res = imageapi_gd_create_tmp($image, $width, $height); if (!imagecopyresampled($res, $image->resource, 0, 0, $x, $y, $width, $height, $width, $height)) { return FALSE; } // Destroy the original image and return the modified image. imagedestroy($image->resource); $image->resource = $res; $image->info['width'] = $width; $image->info['height'] = $height; return TRUE; } /** * Scale an image to the specified size using GD. * * @param $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param $width * The new width of the resized image, in pixels. * @param $height * The new height of the resized image, in pixels. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_resize(&$image, $width, $height) { $res = imageapi_gd_create_tmp($image, $width, $height); if (!imagecopyresampled($res, $image->resource, 0, 0, 0, 0, $width, $height, $image->info['width'], $image->info['height'])) { return FALSE; } imagedestroy($image->resource); // Update image object. $image->resource = $res; $image->info['width'] = $width; $image->info['height'] = $height; return TRUE; } /** * Rotate an image the given number of degrees. * * @param $image * An image object. The $image->resource, $image->info['width'], and * $image->info['height'] values will be modified by this call. * @param $degrees * The number of (clockwise) degrees to rotate the image. * @param $background * An hexadecimal integer specifying the background color to use for the * uncovered area of the image after the rotation. E.g. 0x000000 for black, * 0xff00ff for magenta, and 0xffffff for white. For images that support * transparency, this will default to transparent. Otherwise it will * be white. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_rotate(&$image, $degrees, $bgcolor) { // PHP installations using non-bundled GD do not have imagerotate. if (!function_exists('imagerotate')) { require_once drupal_get_path('module', 'imageapi_gd') .'/imagerotate.inc'; } $width = $image->info['width']; $height = $image->info['height']; // Convert the hexadecimal background value to a color index value. if (isset($background)) { $rgb = array(); for ($i = 16; $i >= 0; $i -= 8) { $rgb[] = (($background >> $i) & 0xFF); } $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0); } // Set the background color as transparent if $background is NULL. else { // Get the current transparent color. $background = imagecolortransparent($image->resource); // If no transparent colors, use white. if ($background == 0) { $background = imagecolorallocatealpha($image->resource, 255, 255, 255, 0); } } // Images are assigned a new color pallete when rotating, removing any // transparency flags. For GIF images, keep a record of the transparent color. if ($image->info['extension'] == 'gif') { $transparent_index = imagecolortransparent($image->resource); if ($transparent_index != 0) { $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index); } } $image->resource = imagerotate($image->resource, 360 - $degrees, $background); // GIFs need to reassign the transparent color after performing the rotate. if (isset($transparent_gif_color)) { $background = imagecolorexactalpha($image->resource, $transparent_gif_color['red'], $transparent_gif_color['green'], $transparent_gif_color['blue'], $transparent_gif_color['alpha']); imagecolortransparent($image->resource, $background); } $image->info['width'] = imagesx($image->resource); $image->info['height'] = imagesy($image->resource); return TRUE; } function imageapi_gd_image_sharpen(&$image, $radius, $sigma, $amount, $threshold) { $threshold = round($threshold * 255); $image->resource = imageapi_gd_unsharp_mask($image->resource, $radius, $sigma, $amount, $threshold); return TRUE; } /** * Convert an image resource to grayscale. * * Note that transparent GIFs loose transparency when desaturated. * * @param $image * An image object. The $image->resource value will be modified by this call. * @return * TRUE or FALSE, based on success. */ function imageapi_gd_image_desaturate(&$image) { // PHP installations using non-bundled GD do not have imagefilter. if (!function_exists('imagefilter')) { require_once drupal_get_path('module', 'imageapi_gd') .'/imagefilter.inc'; } return imagefilter($image->resource, IMG_FILTER_GRAYSCALE); } /** * Create a truecolor image preserving transparency from a provided image. * * @param $image * An image object. * @param $width * The new width of the new image, in pixels. * @param $height * The new height of the new image, in pixels. * @return * A GD image handle. */ function imageapi_gd_create_tmp(stdClass $image, $width, $height) { $res = imagecreatetruecolor($width, $height); if ($image->info['extension'] == 'gif') { // Grab transparent color index from image resource. $transparent = imagecolortransparent($image->resource); if ($transparent >= 0) { // The original must have a transparent color, allocate to the new image. $transparent_color = imagecolorsforindex($image->resource, $transparent); $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); // Flood with our new transparent color. imagefill($res, 0, 0, $transparent); imagecolortransparent($res, $transparent); } } elseif ($image->info['extension'] == 'png') { imagealphablending($res, FALSE); $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127); imagefill($res, 0, 0, $transparency); imagealphablending($res, TRUE); imagesavealpha($res, TRUE); } else { imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255)); } return $res; } /** * $sigma is currently unused for _gd_sharp_mask due to 3x3 convolution matrix limit. * we should explore properly implementing sigma. */ function imageapi_gd_unsharp_mask($img, $radius, $sigma, $amount, $threshold) { ////////////////////////////////////////////////////////////// //// //// Unsharp Mask for PHP - version 2.1.1 //// //// Unsharp mask algorithm by Torstein H�nsi 2003-07. //// thoensi_at_netcom_dot_no. //// Please leave this notice. //// ////////////////////////////////////////////////////////////// // http://vikjavev.no/computing/ump.php // $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: if ($amount > 500) $amount = 500; $amount = $amount * 0.016; if ($radius > 50) $radius = 50; $radius = $radius * 2; if ($threshold > 255) $threshold = 255; $radius = abs(round($radius)); // Only integers make sense. if ($radius == 0) { return $img; imagedestroy($img); break; } $w = imagesx($img); $h = imagesy($img); $img_canvas = imagecreatetruecolor($w, $h); $img_blur = imagecreatetruecolor($w, $h); // Gaussian blur matrix: // // 1 2 1 // 2 4 2 // 1 2 1 // ////////////////////////////////////////////////// $matrix = array( array( 1, 2, 1 ), array( 2, 4, 2 ), array( 1, 2, 1 ) ); imagecopy($img_blur, $img, 0, 0, 0, 0, $w, $h); imageconvolution($img_blur, $matrix, 16, 0); 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 $rgb_orig = imagecolorat($img, $x, $y); $r_orig = (($rgb_orig >> 16) & 0xFF); $g_orig = (($rgb_orig >> 8) & 0xFF); $b_orig = ($rgb_orig & 0xFF); $rgb_blur = imagecolorat($img_blur, $x, $y); $r_blur = (($rgb_blur >> 16) & 0xFF); $g_blur = (($rgb_blur >> 8) & 0xFF); $b_blur = ($rgb_blur & 0xFF); // When the masked pixels differ less from the original // than the threshold specifies, they are set to their original value. $r_new = (abs($r_orig - $r_blur) >= $threshold) ? max(0, min(255, ($amount * ($r_orig - $r_blur)) + $r_orig)) : $r_orig; $g_new = (abs($g_orig - $g_blur) >= $threshold) ? max(0, min(255, ($amount * ($g_orig - $g_blur)) + $g_orig)) : $g_orig; $b_new = (abs($b_orig - $b_blur) >= $threshold) ? max(0, min(255, ($amount * ($b_orig - $b_blur)) + $b_orig)) : $b_orig; if (($r_orig != $r_new) || ($g_orig != $g_new) || ($b_orig != $b_new)) { $pix_col = imagecolorallocate($img, $r_new, $g_new, $b_new); imagesetpixel($img, $x, $y, $pix_col); } } } } else{ for ($x = 0; $x < $w; $x++) { // each row for ($y = 0; $y < $h; $y++) { // each pixel $rgb_orig = imagecolorat($img, $x, $y); $r_orig = (($rgb_orig >> 16) & 0xFF); $g_orig = (($rgb_orig >> 8) & 0xFF); $b_orig = ($rgb_orig & 0xFF); $rgb_blur = imagecolorat($img_blur, $x, $y); $r_blur = (($rgb_blur >> 16) & 0xFF); $g_blur = (($rgb_blur >> 8) & 0xFF); $b_blur = ($rgb_blur & 0xFF); $r_new = ($amount * ($r_orig - $r_blur)) + $r_orig; if ($r_new>255) $r_new=255; elseif ($r_new<0) $r_new=0; $g_new = ($amount * ($g_orig - $g_blur)) + $g_orig; if ($g_new>255) $g_new=255; elseif ($g_new<0) $g_new=0; $b_new = ($amount * ($b_orig - $b_blur)) + $b_orig; if ($b_new>255) $b_new=255; elseif ($b_new<0) $b_new=0; $rgb_new = ($r_new << 16) + ($g_new <<8) + $b_new; imagesetpixel($img, $x, $y, $rgb_new); } } } imagedestroy($img_canvas); imagedestroy($img_blur); return $img; }