<?php
/**
* Project: Thumbnail simple resize: lite resize and crop image
* File: Thumbnail.php
*
* @copyright 2012 Roman Krivosheev, Personal.
* @author Roman Krivosheev <web.volga@gmail.com>
* @author Roman Krivosheev (icq: 446666000)
* @package Thumbnail
* @version 3.5.0
*
*
* include 'includes/Thumbnail.php';
* $filename = '0001.jpg';
* $options = array(
* 'type' => IMAGETYPE_JPEG,
* 'width' => 150,
* 'height' => 150,
* 'method' => THUMBNAIL_METHOD_SCALE_MAX,
* 'coord_x1' => 0,
* 'coord_y1' => 0,
* 'coord_x2' => 0,
* 'coord_y2' => 0,
* 'percent' => 0,
* 'halign' => THUMBNAIL_ALIGN_CENTER,
* 'valign' => THUMBNAIL_ALIGN_CENTER,
* 'corner' => 0,
* 'corcolor' => 'FFFFFF',
* 'cortransparent' => 0,
* 'mark' => 0,
* );
*
* Watermark position (#array option 'mark' => ):
* THUMBNAIL_MARK_TOP_LEFT = 1
* THUMBNAIL_MARK_TOP_RIGHT = 2
* THUMBNAIL_MARK_TOP_CENTER = 3
* THUMBNAIL_MARK_CENTER_CENTER = 4
* THUMBNAIL_MARK_BOTTOM_LEFT = 5
* THUMBNAIL_MARK_BOTTOM_RIGHT = 6
* THUMBNAIL_MARK_BOTTOM_CENTER = 7
* Thumbnail::output($filename, 'data.jpg', $options);
*
*
*/
/**
* This is a driver for the thumbnail creating
*
* PHP versions 4 and 5
*/
/**
* Maximal scaling
*/
define('THUMBNAIL_METHOD_SCALE_MAX', 0);
/**
* Minimal scaling
*/
define('THUMBNAIL_METHOD_SCALE_MIN', 1);
/**
* Cropping of fragment
*/
define('THUMBNAIL_METHOD_CROP', 2);
/**
* Align constants
*/
define('THUMBNAIL_ALIGN_CENTER', 0);
define('THUMBNAIL_ALIGN_LEFT', -1);
define('THUMBNAIL_ALIGN_RIGHT', +1);
define('THUMBNAIL_ALIGN_TOP', -1);
define('THUMBNAIL_ALIGN_BOTTOM', +1);
define('THUMBNAIL_MARK_TOP_LEFT', 1);
define('THUMBNAIL_MARK_TOP_RIGHT', 2);
define('THUMBNAIL_MARK_TOP_CENTER', 3);
define('THUMBNAIL_MARK_CENTER_CENTER', 4);
define('THUMBNAIL_MARK_BOTTOM_LEFT', 5);
define('THUMBNAIL_MARK_BOTTOM_RIGHT', 6);
define('THUMBNAIL_MARK_BOTTOM_CENTER', 7);
// }}}
// {{{
class Thumbnail
{
// {{{
/**
* Create a GD image resource from given input.
*
* This method tried to detect what the input, if it is a file the
* createImageFromFile will be called, otherwise createImageFromString().
*
* @param mixed $input The input for creating an image resource. The value
* may a string of filename, string of image data or
* GD image resource.
*
* @return resource An GD image resource on success or false
* @access public
* @static
* @see Thumbnail::imageCreateFromFile(), Thumbnail::imageCreateFromString()
*/
private static function imageCreate($input)
{
if ( is_file($input) ) {
return Thumbnail::imageCreateFromFile($input);
} else if ( is_string($input) ) {
return Thumbnail::imageCreateFromString($input);
} else {
return $input;
}
}
// }}}
// {{{
/**
* Create a GD image resource from file (JPEG, PNG support).
*
* @param string $filename The image filename.
*
* @return mixed GD image resource on success, FALSE on failure.
* @access public
* @static
*/
private static function imageCreateFromFile($filename)
{
if ( ! is_file($filename) || ! is_readable($filename) ) {
trigger_error('Unable to open file "' . $filename . '"', E_USER_NOTICE);
return false;
}
// determine image format
list( , , $type) = getimagesize($filename);
switch ($type) {
case IMAGETYPE_JPEG:
return imagecreatefromjpeg($filename);
break;
case IMAGETYPE_PNG:
return imagecreatefrompng($filename);
break;
case IMAGETYPE_GIF:
return imagecreatefromgif($filename);
break;
}
trigger_error('Unsupport image type', E_USER_NOTICE);
return false;
}
// }}}
// {{{
/**
* Create a GD image resource from a string data.
*
* @param string $string The string image data.
*
* @return mixed GD image resource on success, FALSE on failure.
* @access public
* @static
*/
private static function imageCreateFromString($string)
{
if ( ! is_string($string) || empty($string) ) {
trigger_error('Invalid image value in string', E_USER_NOTICE);
return false;
}
return imagecreatefromstring($string);
}
// }}}
// {{{
/**
* Display rendered image (send it to browser or to file).
* This method is a common implementation to render and output an image.
* The method calls the render() method automatically and outputs the
* image to the browser or to the file.
*
* @param mixed $input Destination image, a filename or an image string data or a GD image resource
* @param array $options Thumbnail options
* @return boolean TRUE on success or FALSE on failure.
* @access public
*/
public static function output($input, $output=null, $options=array())
{
// Load source file and render image
$renderImage = Thumbnail::render($input, $options);
if ( ! $renderImage ) {
trigger_error('Error rendering image', E_USER_NOTICE);
return false;
}
// Set output image type
// By default PNG image
$type = isset($options['type']) ? $options['type'] : IMAGETYPE_JPEG;
// Before output to browsers send appropriate headers
if ( empty($output) ) {
$content_type = image_type_to_mime_type($type);
if ( ! headers_sent() ) {
header('Content-Type: ' . $content_type);
} else {
trigger_error('Headers have already been sent. Could not display image.', E_USER_NOTICE);
return false;
}
}
// Define outputing function
switch ($type) {
case IMAGETYPE_PNG:
$result = empty($output) ? imagepng($renderImage) : imagepng($renderImage, $output);
break;
case IMAGETYPE_JPEG:
$result = empty($output) ? imagejpeg($renderImage, null, 1) : imagejpeg($renderImage, $output, 100);
break;
case IMAGETYPE_GIF:
$result = empty($output) ? imagegif($renderImage) : imagegif($renderImage, $output);
break;
default:
user_error('Image type ' . $content_type . ' not supported by PHP', E_USER_NOTICE);
return false;
}
// Output image (to browser or to file)
if ( ! $result ) {
trigger_error('Error output image', E_USER_NOTICE);
return false;
}
// Free a memory from the target image
imagedestroy($renderImage);
return true;
}
// }}}
// {{{ render()
/**
* Draw thumbnail result to resource.
*
* @param mixed $input Destination image, a filename or an image string data or a GD image resource
* @param array $options Thumbnail options
*
* @return boolean TRUE on success or FALSE on failure.
* @access public
* @see Thumbnail::output()
*/
private static function render($input, $options=array())
{
// Create the source image
$sourceImage = Thumbnail::imageCreate($input);
if ( ! is_resource($sourceImage) ) {
trigger_error('Invalid image resource', E_USER_NOTICE);
return false;
}
$sourceWidth = imagesx($sourceImage);
$sourceHeight = imagesy($sourceImage);
// Set default options
static $defOptions = array(
'width' => 150,
'height' => 150,
'method' => THUMBNAIL_METHOD_SCALE_MAX,
'halign' => THUMBNAIL_ALIGN_CENTER,
'valign' => THUMBNAIL_ALIGN_CENTER,
'coord_x1' => 0,
'coord_y1' => 0,
'coord_x2' => 150,
'coord_y2' => 150,
'corner' => 0,
'corcolor' => 'FFFFFF',
'cortransparent' => 0,
'mark' => 0,
'mark-image' => null
);
foreach ($defOptions as $k => $v) {
if ( ! isset($options[$k]) ) {
$options[$k] = $v;
}
}
// Estimate a rectangular portion of the source image and a size of the target image
if ( $options['method'] == THUMBNAIL_METHOD_CROP ) {
if ( $options['coord_x2'] AND $options['coord_y2']) {
$options['coord_x1'] = (!$options['coord_x1'] OR $options['coord_x1'] >= $options['coord_x2']) ? 0 : $options['coord_x1'];
$options['coord_y1'] = (!$options['coord_y1'] OR $options['coord_y1'] >= $options['coord_y2']) ? 0 : $options['coord_y1'];
$W = floor($options['coord_x2'] - $options['coord_x1']);
$H = floor($options['coord_y2'] - $options['coord_y1']);
}
$W = ($sourceWidth <= ($options['coord_x1']+$options['coord_x2'])) ? $sourceWidth-$options['coord_x1'] : $W;
$H = ($sourceHeight <= ($options['coord_y1']+$options['coord_y2'])) ? $sourceHeight-$options['coord_y1'] : $H;
$width = ($W >= $options['width']) ? $options['width'] : $W ;
$height = ($H >= $options['height']) ? $options['height'] : $H;
$Y = $options['coord_y1'];
$X = $options['coord_x1'];
} else {
$X = 0;
$Y = 0;
$W = $sourceWidth;
$H = $sourceHeight;
if ( $options['percent'] ) {
$width = floor($options['percent'] * $W);
$height = floor($options['percent'] * $H);
} else {
$width = $options['width'];
$height = $options['height'];
if ( $options['method'] == THUMBNAIL_METHOD_SCALE_MIN ) {
$Ww = $W / $width;
$Hh = $H / $height;
if ( $Ww > $Hh ) {
$W = floor($width * $Hh);
$X = Thumbnail::_coord($options['halign'], $sourceWidth, $W);
} else {
$H = floor($height * $Ww);
$Y = Thumbnail::_coord($options['valign'], $sourceHeight, $H);
}
} else {
if ( $H > $W ) {
$width = floor($height / $H * $W);
} else {
$height = floor($width / $W * $H);
}
}
}
}
// Create the target image
if ( function_exists('imagecreatetruecolor') ) {
$targetImage = imagecreatetruecolor($width, $height);
imageAlphaBlending($targetImage, false);
imageSaveAlpha($targetImage, true);
$transparency = imagecolorallocatealpha($targetImage, 0, 0, 0, 127);
imagefill($targetImage, 0, 0, $transparency);
} else {
$targetImage = imagecreate($width, $height);
}
if ( ! is_resource($targetImage) ) {
trigger_error('Cannot initialize new GD image stream', E_USER_NOTICE);
return false;
}
// Copy the source image to the target image
if ( $options['method'] == THUMBNAIL_METHOD_CROP ) {
$result = imagecopy($targetImage, $sourceImage, 0, 0, $X, $Y, $W, $H);
} elseif ( function_exists('imagecopyresampled') ) {
$result = imagecopyresampled($targetImage, $sourceImage, 0, 0, $X, $Y, $width, $height, $W, $H);
} else {
$result = imagecopyresized($targetImage, $sourceImage, 0, 0, $X, $Y, $width, $height, $W, $H);
}
if ( ! $result ) {
trigger_error('Cannot resize image', E_USER_NOTICE);
return false;
}
if ($options['corner'] > 0) {
/* corner background-color */
$radius = $options['corner'];
$colour = $options['corcolor'];
$source_width = $width;
$source_height = $height;
$corner_image = imagecreatetruecolor($radius,$radius);
$clear_colour = imagecolorallocate($corner_image,0,0,0);
$solid_colour = imagecolorallocate( $corner_image, hexdec( substr( $colour, 0, 2 ) ), hexdec( substr( $colour, 2, 2 ) ), hexdec( substr( $colour, 4, 2 ) ) );
imagecolortransparent($corner_image,$clear_colour);
imagefill( $corner_image, 0, 0, $solid_colour );
imagefilledellipse($corner_image, $radius, $radius, $radius * 2, $radius * 2, $clear_colour );
imagecopymerge($targetImage, $corner_image, 0, 0, 0, 0, $radius, $radius, 100 );
$corner_image = imagerotate( $corner_image, 90, 0 );
imagecopymerge($targetImage, $corner_image, 0, $source_height - $radius, 0, 0, $radius, $radius, 100 );
$corner_image = imagerotate( $corner_image, 90, 0 );
imagecopymerge($targetImage, $corner_image, $source_width - $radius, $source_height - $radius, 0, 0, $radius, $radius, 100);
$corner_image = imagerotate( $corner_image, 90, 0 );
imagecopymerge($targetImage,$corner_image,$source_width - $radius, 0, 0, 0, $radius, $radius, 100);
}
if ($options['cortransparent'] > 0) {
/* corner (transparent) */
$bwidth = $options['cortransparent'];
$width_orig = $width;
$height_orig = $height;
$img = $targetImage;
$mask = imagecreatetruecolor($width_orig, $height_orig);
$white = imagecolorallocate($mask, 255, 255, 255);
imagefill($mask, 0, 0, $white);
$cornerImg = imagecreatetruecolor($bwidth, $bwidth);
$transp = imagecolorallocate($cornerImg, 0, 0, 0);
imagefill($cornerImg, 0, 0, $transp);
$bgc = imagecolorallocate($cornerImg, 255, 255, 255);
imagefilledellipse($cornerImg, $bwidth, $bwidth, $bwidth*2, $bwidth*2, $bgc);
imagecolortransparent($cornerImg, $bgc);
imagecopymerge($mask, $cornerImg, 0, 0, 0, 0, $bwidth, $bwidth, 100);
$cornerImg = imagerotate($cornerImg, 270,0);
imagecopymerge($mask, $cornerImg, $width_orig-$bwidth, 0, 0, 0, $bwidth, $bwidth, 100);
$cornerImg = imagerotate($cornerImg, 270,0);
imagecopymerge($mask, $cornerImg, $width_orig-$bwidth, $height_orig-$bwidth, 0, 0, $bwidth, $bwidth, 100);
$cornerImg = imagerotate($cornerImg, 270,0);
imagecopymerge($mask, $cornerImg, 0, $height_orig-$bwidth, 0, 0, $bwidth, $bwidth, 100);
$newImage = imagecreatetruecolor( $width_orig, $height_orig );
imagesavealpha( $newImage, true );
$allocatedAlpha=imagecolorallocatealpha( $newImage, 0, 0, 0, 127 );
imagefill( $newImage, 0, 0, $allocatedAlpha );
for( $x = 0; $x < $width_orig; $x++ ) {
for( $y = 0; $y < $height_orig; $y++ ) {
$alpha = imagecolorsforindex( $mask, imagecolorat( $mask, $x, $y ) );
$alpha = 127 - floor( $alpha['red'] / 2 );
$colour = imagecolorsforindex( $img, imagecolorat( $img, $x, $y ) );
imagesetpixel( $newImage, $x, $y, imagecolorallocatealpha( $newImage, $colour[ 'red' ], $colour[ 'green' ], $colour[ 'blue' ], $alpha ) );
}
}
$targetImage = $newImage;
}
if ($options['mark'] > 0 AND $options['mark-image']) {
imagealphablending($targetImage, true);
if(!file_exists($options['mark-image'])) die("Cannot watermark image");
$maskwatermark = imagecreatefrompng($options['mark-image']);
$owidth = imagesx($maskwatermark);
$oheight = imagesy($maskwatermark);
$m_width = 0;
$m_height = 0;
switch ($options['mark']) {
case 1: // top left
break;
case 2: // top right
$m_width = ($width-$owidth);
break;
case 3: // top center
$m_width = ($width-$owidth)/2;
break;
case 4: // center center
$m_width = ($width-$owidth)/2;
$m_height = ($height-$oheight)/2;
break;
case 5: // bottom left
$m_height = ($height-$oheight);
break;
case 6: // bottom right
$m_width = ($width-$owidth);
$m_height = ($height-$oheight);
break;
case 7: // bottom center
$m_width = ($width-$owidth)/2;
$m_height = ($height-$oheight);
break;
default:
user_error('Image type ' . $content_type . ' not supported by PHP', E_USER_NOTICE);
return false;
}
imagecopy($targetImage, $maskwatermark, $m_width, $m_height, 0, 0, $owidth, $oheight);
}
imagedestroy($sourceImage);
return $targetImage;
}
// }}}
// {{{ _coord()
private static function _coord($align, $param, $src)
{
if ( $align < THUMBNAIL_ALIGN_CENTER ) {
$result = 0;
} elseif ( $align > THUMBNAIL_ALIGN_CENTER ) {
$result = $param - $src;
} else {
$result = ($param - $src) >> 1;
}
return $result;
}
// }}}
}
|