<?php
/*======================================================================*\
|| #################################################################### ||
|| # vBulletin 4.0.5
|| # ---------------------------------------------------------------- # ||
|| # Copyright ©2000-2010 vBulletin Solutions Inc. All Rights Reserved. ||
|| # This file may not be redistributed in whole or significant part. # ||
|| # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
|| #################################################################### ||
\*======================================================================*/
if (!isset($GLOBALS['vbulletin']->db))
{
exit;
}
/**#@+
* Global image type defines used by serveral functions
*/
define('GIF', 1);
define('JPG', 2);
define('PNG', 3);
/**#@-*/
/**#@+
* These make up the bit field to enable specific parts of image verification
*/
define('ALLOW_RANDOM_FONT', 1);
define('ALLOW_RANDOM_SIZE', 2);
define('ALLOW_RANDOM_SLANT', 4);
define('ALLOW_RANDOM_COLOR', 8);
define('ALLOW_RANDOM_SHAPE', 16);
/**#@-*/
if (function_exists('imagegif'))
{
define('IMAGEGIF', true);
}
else
{
define('IMAGEGIF', false);
}
if (function_exists('imagejpeg'))
{
define('IMAGEJPEG', true);
}
else
{
define('IMAGEJPEG', false);
}
if (function_exists('imagepng'))
{
define('IMAGEPNG', true);
}
else
{
define('IMAGEPNG', false);
}
if (($current_memory_limit = ini_size_to_bytes(@ini_get('memory_limit'))) < 128 * 1024 * 1024 AND $current_memory_limit > 0)
{
@ini_set('memory_limit', 128 * 1024 * 1024);
}
/**
* Abstracted image class
*
* @package vBulletin
* @version $Revision: 37230 $
* @date $Date: 2010-05-28 11:50:59 -0700 (Fri, 28 May 2010) $
*
*/
class vB_Image
{
/**
* Constructor
* Does nothing :p
*
* @return void
*/
function vB_Image() {}
/**
* Select image library
*
* @return object
*/
function &fetch_library(&$registry, $type = 'image')
{
// Library used for thumbnails, image functions
if ($type == 'image')
{
$selectclass = 'vB_Image_' . ($registry->options['imagetype'] ? $registry->options['imagetype'] : 'GD');
}
// Library used for Verification Image
else
{
switch($registry->options['regimagetype'])
{
case 'Magick':
$selectclass = 'vB_Image_Magick';
break;
default:
$selectclass = 'vB_Image_GD';
}
}
$object = new $selectclass($registry);
return $object; // function defined as returning & must return a defined variable
}
}
/**
* Abstracted image class
*
* @package vBulletin
* @version $Revision: 37230 $
* @date $Date: 2010-05-28 11:50:59 -0700 (Fri, 28 May 2010) $
*
*/
class vB_Image_Abstract
{
/**
* Main data registry
*
* @var vB_Registry
*/
var $registry = null;
/**
* @var array
*/
var $thumb_extensions = array();
/**
* @var array
*/
var $info_extensions = array();
/**
* @var array
*/
var $must_convert_types = array();
/**
* @var array
*/
var $resize_types = array();
/**
* @var mixed
*/
var $imageinfo = null;
/**
* @var array $extension_map
*/
var $extension_map = array(
'gif' => 'GIF',
'jpg' => 'JPEG',
'jpeg' => 'JPEG',
'jpe' => 'JPEG',
'png' => 'PNG',
'bmp' => 'BMP',
'tif' => 'TIFF',
'tiff' => 'TIFF',
'psd' => 'PSD',
'pdf' => 'PDF',
);
/**
* @var array $regimageoption
*/
var $regimageoption = array(
'randomfont' => false,
'randomsize' => false,
'randomslant' => false,
'randomcolor' => false,
'randomshape' => false,
);
/**
* Constructor
* Don't allow direct construction of this abstract class
* Sets registry
*
* @return void
*/
function vB_Image_Abstract(&$registry)
{
if (!is_subclass_of($this, 'vB_Image_Abstract'))
{
trigger_error('Direct Instantiation of vB_Image_Abstract prohibited.', E_USER_ERROR);
return NULL;
}
$this->registry = &$registry;
$this->regimageoption['randomfont'] = $this->registry->options['regimageoption'] & ALLOW_RANDOM_FONT;
$this->regimageoption['randomsize'] = $this->registry->options['regimageoption'] & ALLOW_RANDOM_SIZE;
$this->regimageoption['randomslant'] = $this->registry->options['regimageoption'] & ALLOW_RANDOM_SLANT;
$this->regimageoption['randomcolor'] = $this->registry->options['regimageoption'] & ALLOW_RANDOM_COLOR;
$this->regimageoption['randomshape'] = $this->registry->options['regimageoption'] & ALLOW_RANDOM_SHAPE;
}
/**
* Private
* Fetches image files from the backgrounds directory
*
* @return array
*
*/
function &fetch_regimage_backgrounds()
{
// Get backgrounds
$backgrounds = array();
if ($handle = @opendir(DIR . '/images/regimage/backgrounds/'))
{
while ($filename = @readdir($handle))
{
if (preg_match('#\.(gif|jpg|jpeg|jpe|png)$#i', $filename))
{
$backgrounds[] = DIR . "/images/regimage/backgrounds/$filename";
}
}
@closedir($handle);
}
return $backgrounds;
}
/**
* Private
* Fetches True Type fonts from the fonts directory
*
* @return array
*
*/
function &fetch_regimage_fonts()
{
// Get fonts
$fonts = array();
if ($handle = @opendir(DIR . '/images/regimage/fonts/'))
{
while ($filename =@ readdir($handle))
{
if (preg_match('#\.ttf$#i', $filename))
{
$fonts[] = DIR . "/images/regimage/fonts/$filename";
}
}
@closedir($handle);
}
return $fonts;
}
/**
*Public
*
*
* @param string $type Type of image from $info_extensions
*
* @return bool
*/
function fetch_must_convert($type)
{
return !empty($this->must_convert_types["$type"]);
}
/**
* Public
* Checks if supplied extension can be used by fetch_image_info
*
* @param string $extension Extension of file
*
* @return bool
*/
function is_valid_info_extension($extension)
{
return !empty($this->info_extensions[strtolower($extension)]);
}
/**
* Public
* Checks if supplied extension can be resized into a smaller permanent image, not to be used for PSD, PDF, etc as it will lose the original format
*
* @param string $type Type of image from $info_extensions
*
* @return bool
*/
function is_valid_resize_type($type)
{
return !empty($this->resize_types["$type"]);
}
/**
* Public
* Checks if supplied extension can be used by fetch_thumbnail
*
* @param string $extension Extension of file
*
* @return bool
*/
function is_valid_thumbnail_extension($extension)
{
return !empty($this->thumb_extensions[strtolower($extension)]);
}
/**
* Public
* Checks if supplied extension can be used by fetch_thumbnail
*
* @param string $extension Extension of file
*
* @return bool
*/
function fetch_imagetype_from_extension($extension)
{
return $this->extension_map[strtolower($extension)];
}
/**
* Private
* Checks for HTML tags that can be exploited via IE
*
* @param string filename
*
* @return bool
*/
function verify_image_file($filename)
{
// Verify that file is playing nice
$fp = fopen($filename, 'rb');
if ($fp)
{
$header = fread($fp, 256);
fclose($fp);
if (preg_match('#<html|<head|<body|<script|<pre|<plaintext|<table|<a href|<img|<title#si', $header))
{
return false;
}
}
else
{
return false;
}
return true;
}
/**
* Public
* Retrieve info about image
*
* @param string filename Location of file
* @param string extension Extension of file name
*
* @return array [0] int width
* [1] int height
* [2] string type ('GIF', 'JPEG', 'PNG', 'PSD', 'BMP', 'TIFF',) (and so on)
* [scenes] int scenes
* [channels] int Number of channels (GREYSCALE = 1, RGB = 3, CMYK = 4)
* [bits] int Number of bits per pixel
* [library] string Library Identifier
*/
function fetch_image_info() {}
/**
* Public
* Output an image based on a string
*
* @param string string String to output
* @param bool moveabout move text about
*
* @return void
*/
function print_image_from_string() {}
/**
* Public
* Returns an array containing a thumbnail, creation time, thumbnail size and any errors
*
* @param string filename filename of the source file
* @param string location location of the source file
* @param int newsize new size of image (longest side of image)
* @param int quality Jpeg Quality
* @param bool labelimage Include image dimensions and filesize on thumbnail
* @param bool drawborder Draw border around thumbnail
*
* @return array
*/
function fetch_thumbnail() {}
/**
* Public
* Return Error from graphics library
*
* @return mixed
*/
function fetch_error() {}
}
/**
* Image class for ImageMagick
*
* @package vBulletin
* @version $Revision: 37230 $
* @date $Date: 2010-05-28 11:50:59 -0700 (Fri, 28 May 2010) $
*
*/
class vB_Image_Magick extends vB_Image_Abstract
{
/**
* @var string
*/
var $convertpath = '/usr/local/bin/convert';
/**
* @var string
*/
var $identifypath = '/usr/local/bin/identify';
/**
* @var integer
*/
var $returnvalue = 0;
/**
* @var string
*/
var $identifyformat = '';
/**
* @var string
*/
var $convertoptions = array(
'width' => '100',
'height' => '100',
'quality' => '75',
);
/**
* @var string
*
*/
var $error = '';
/**
* @var string
*
*/
var $thumbcolor = 'black';
/**
* Constructor
* Sets ImageMagick paths to convert and identify
*
* @return void
*/
function vB_Image_Magick(&$registry)
{
parent::vB_Image_Abstract($registry);
$path = preg_replace('#[/\\\]+$#', '', $this->registry->options['magickpath']);
if (preg_match('#^WIN#i', PHP_OS))
{
$this->identifypath = '"' . $path . '\identify.exe"';
$this->convertpath = '"' . $path . '\convert.exe"';
}
else
{
$this->identifypath = "'" . $path . "/identify'";
$this->convertpath = "'" . $path . "/convert'";
}
$this->must_convert_types = array(
'PSD' => true,
'BMP' => true,
'TIFF' => true,
'PDF' => true,
);
$this->resize_types = array(
'GIF' => true,
'JPEG' => true,
'PNG' => true,
'BMP' => true,
'TIFF' => true
);
$this->thumb_extensions = array(
'gif' => true,
'jpg' => true,
'jpe' => true,
'jpeg' => true,
'png' => true,
'psd' => true,
'pdf' => true,
'bmp' => true,
'tiff' => true,
'tif' => true,
);
$this->info_extensions =& $this->thumb_extensions;
if (preg_match('~^#([0-9A-F]{6})$~i', $this->registry->options['thumbcolor'], $match))
{
$this->thumbcolor = $match[0];
}
$this->version = $this->fetch_version();
}
/**
* Private
* Return Error from fetch_im_exec()
*
* @return string
*/
function fetch_error()
{
if (!empty($this->error))
{
return implode("\n", $this->error);
}
else
{
return false;
}
}
/**
* Private
* Generic call to imagemagick binaries
*
* @param string command ImageMagick binary to execute
* @param string args Arguments to the ImageMagick binary
*
* @return mixed
*/
function fetch_im_exec($command, $args, $needoutput = false, $dieongs = true)
{
if (!function_exists('exec'))
{
$this->error = array(fetch_error('php_error_exec_disabled'));
return false;
}
$imcommands = array(
'identify' => $this->identifypath,
'convert' => $this->convertpath,
);
$input = $imcommands["$command"] . ' ' . $args . ' 2>&1';
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' AND PHP_VERSION < '5.3.0')
{
$input = '"' . $input . '"';
}
$exec = @exec($input, $output, $this->returnvalue);
if ($this->returnvalue OR $exec === null)
{ // error was encountered
if (!empty($output))
{ // command issued by @exec failed
if (strpos(strtolower(implode(' ', $output)), 'postscript delegate failed') !== false)
{
$output[] = fetch_error('install_ghostscript_to_resize_pdf');
}
$this->error = $output;
}
else if (!empty($php_errormsg))
{ // @exec failed so display error and remove path reveal
$this->error = array(fetch_error('php_error_x', str_replace($this->registry->options['magickpath'] . '\\', '', $php_errormsg)));
}
else if ($this->returnvalue == -1)
{ // @exec failed but we don't have $php_errormsg to tell us why
$this->error = array(fetch_error('php_error_unspecified_exec'));
}
return false;
}
else
{
$this->error = '';
if (!empty($output))
{ // $output is an array of returned text
// This is for IM which doesn't return false for failed font
if (strpos(strtolower(implode(' ', $output)), 'unable to read font') !== false)
{
$this->error = $output;
return false;
}
if (strpos(strtolower(implode(' ', $output)), 'postscript delegate failed') !== false)
{ // this is for IM 6.2.4+ which doesn't return false for exec(convert.exe) on .pdf when GS isn't installed
$this->error = array(fetch_error('install_ghostscript_to_resize_pdf'));
}
return $output;
}
else if (empty($output) AND $needoutput)
{ // $output is empty and we expected something back
return false;
}
else
{ // $output is empty and we didn't expect anything back
return true;
}
}
}
/**
* Private
* Fetch Imagemagick Version
*
* @return mixed
*/
function fetch_version()
{
if ($result = $this->fetch_im_exec('convert', '-version', true) AND preg_match('#ImageMagick (\d+\.\d+\.\d+)#', $result[0], $matches))
{
return $matches[1];
}
return false;
}
/**
* Private
* Identify an image
*
* @param string $filename File to obtain image information from
*
* @return mixed
*/
function fetch_identify_info($filename)
{
$fp = @fopen($filename, 'rb');
if (($header = @fread($fp, 4)) == '%PDF')
{ // this is a PDF so only look at frame 0 to save mucho processing time
$frame0 = '[0]';
}
@fclose($fp);
$execute = (!empty($this->identifyformat) ? "-format {$this->identifyformat} \"$filename\"" : "\"$filename\"") . $frame0;
if ($result = $this->fetch_im_exec('identify', $execute, true))
{
if (empty($result) OR !is_array($result))
{
return false;
}
do
{
$last = array_pop($result);
}
while (!empty($result) AND $last == '');
$temp = explode('###', $last);
if (count($temp) < 6)
{
return false;
}
preg_match('#^(\d+)x(\d+)#', $temp[0], $matches);
$imageinfo = array(
2 => $temp[3],
'bits' => $temp[6],
'scenes' => $temp[4],
'animated' => ($temp[4] > 1),
'library' => 'IM',
);
if (version_compare($this->version, '6.2.6', '>='))
{
$imageinfo[0] = $matches[1];
$imageinfo[1] = $matches[2];
}
else //IM v6.2.5 and lower don't support -laters optimize
{
$imageinfo[0] = $temp[1];
$imageinfo[1] = $temp[2];
}
switch($temp[5])
{
case 'PseudoClassGray':
case 'PseudoClassGrayMatte':
case 'PseudoClassRGB':
case 'PseudoClassRGBMatte':
$imageinfo['channels'] = 1;
break;
case 'DirectClassRGB':
$imageinfo['channels'] = 3;
break;
case 'DirectClassCMYK':
$imageinfo['channels'] = 4;
break;
default:
$imageinfo['channels'] = 1;
}
return $imageinfo;
}
else
{
return false;
}
}
/**
* Private
* Set image size for convert
*
* @param width Width of new image
* @param height Height of new image
* @param quality Quality of Jpeg images
* @param bool Include image dimensions and filesize on thumbnail
* @param bool Draw border around thumbnail
*
* @return void
*/
function set_convert_options($width = 100, $height = 100, $quality = 75, $labelimage = false, $drawborder = false, $jpegconvert = false, $owidth = null, $oheight = null, $ofilesize = null)
{
$this->convertoptions['width'] = $width;
$this->convertoptions['height'] = $height;
$this->convertoptions['quality'] = $quality;
$this->convertoptions['labelimage'] = $labelimage;
$this->convertoptions['drawborder'] = $drawborder;
$this->convertoptions['owidth'] = $owidth;
$this->convertoptions['oheight'] = $oheight;
$this->convertoptions['ofilesize'] = $ofilesize;
$this->convertoptions['jpegconvert'] = $jpegconvert;
}
/**
* Private
* Convert an image
*
* @param string filename Image file to convert
* @param string output Image file to write converted image to
* @param string extension Filetype
* @param boolean thumbnail Generate a thumbnail for display in a browser
* @param boolean sharpen Sharpen the output
*
* @return mixed
*/
function fetch_converted_image($filename, $output, $imageinfo, $thumbnail = true, $sharpen = true)
{
$execute = '';
if ($thumbnail)
{
// Only specify scene 1 if this is a PSD or a PDF -- allows animated gifs to be resized..
$execute .= (in_array($imageinfo[2], array('PDF', 'PSD'))) ? " \"{$filename}\"[0] " : " \"$filename\"";
}
else
{
$execute .= " \"$filename\"";
}
if ($imageinfo['scenes'] > 1 AND version_compare($this->version, '6.2.6', '>='))
{
$execute .= ' -coalesce ';
}
if ($this->convertoptions['width'] > 0 OR $this->convertoptions['height'] > 0)
{
if ($this->convertoptions['width'])
{
$size = $this->convertoptions['width'];
if ($this->convertoptions['height'])
{
$size .= 'x' . $this->convertoptions['height'];
}
}
else if ($this->convertoptions['height'])
{
$size .= 'x' . $this->convertoptions['height'];
}
$execute .= " -size $size ";
}
if ($thumbnail)
{
if ($size)
{ // have to use -thumbnail here .. -sample looks BAD for animated gifs
$execute .= " -thumbnail \"$size>\" ";
}
}
$execute .= ($sharpen AND $imageinfo[2] == 'JPEG') ? " -sharpen 0x1 " : '';
if ($imageinfo['scenes'] > 1 AND version_compare($this->version, '6.2.6', '>='))
{
$execute .= ' -layers optimize ';
}
// ### Convert a CMYK jpg to RGB since IE/Firefox will not display CMYK inline .. conversion is ugly since we don't specify profiles
if ($this->imageinfo['channels'] == 4 AND $thumbnail)
{
$execute .= ' -colorspace RGB ';
}
if ($thumbnail)
{
$xratio = ($this->convertoptions['width'] == 0 OR $imageinfo[0] <= $this->convertoptions['width']) ? 1 : $imageinfo[0] / $this->convertoptions['width'];
$yratio = ($this->convertoptions['height'] == 0 OR $imageinfo[1] <= $this->convertoptions['height']) ? 1 : $imageinfo[1] / $this->convertoptions['height'];
if ($xratio > $yratio)
{
$new_width = round($imageinfo[0] / $xratio) - 1;
$new_height = round($imageinfo[1] / $xratio) - 1;
}
else
{
$new_width = round($imageinfo[0] / $yratio) - 1;
$new_height = round($imageinfo[1] / $yratio) - 1;
}
# if ($imageinfo[0] <= $this->convertoptions['width'] AND $imageinfo[1] <= $this->convertoptions['height'])
# {
# $this->convertoptions['labelimage'] = false;
# $this->convertoptions['drawborder'] = false;
# }
if ($this->convertoptions['labelimage'])
{
if ($this->convertoptions['owidth'])
{
$dimensions = "{$this->convertoptions['owidth']}x{$this->convertoptions['oheight']}";
}
else
{
$dimensions = "$imageinfo[0]x$imageinfo[1]";
}
if ($this->convertoptions['ofilesize'])
{
$filesize = $this->convertoptions['ofilesize'];
}
else
{
$filesize = @filesize($filename);
}
if ($filesize / 1024 < 1)
{
$filesize = 1024;
}
$sizestring = (!empty($filesize)) ? number_format($filesize / 1024, 0, '', '') . 'kb' : '';
if (!$this->convertoptions['jpegconvert'] OR $imageinfo[2] == 'PSD' OR $imageinfo[2] == 'PDF')
{
$type = $imageinfo[2];
}
else
{
$type = 'JPEG';
}
if (($new_width / strlen("$dimensions $sizestring $type")) >= 6)
{
$finalstring = "$dimensions $sizestring $type";
}
else if (($new_width / strlen("$dimensions $sizestring")) >= 6)
{
$finalstring = "$dimensions $sizestring";
}
else if (($new_width / strlen($dimensions)) >= 6)
{
$finalstring = $dimensions;
}
else if (($new_width / strlen($sizestring)) >= 6)
{
$finalstring = $sizestring;
}
if ($finalstring)
{ // confusing -flip statements added to workaround an issue with very wide yet short images. See http://www.imagemagick.org/discourse-server/viewtopic.php?t=10367
$execute .= " -flip -background \"{$this->thumbcolor}\" -splice 0x15 -flip -gravity South -fill white -pointsize 11 -annotate 0 \"$finalstring\" ";
}
}
if ($this->convertoptions['drawborder'])
{
$execute .= " -bordercolor \"{$this->thumbcolor}\" -compose Copy -border 1 ";
}
if (($imageinfo[2] == 'PNG' OR $imageinfo[2] == 'PSD') AND !$this->convertoptions['jpegconvert'])
{
$execute .= " -depth 8 -quality {$this->convertoptions['quality']} PNG:";
}
else if ($this->fetch_must_convert($imageinfo[2]) OR $imageinfo[2] == 'JPEG' OR $this->convertoptions['jpegconvert'])
{
$execute .= " -quality {$this->convertoptions['quality']} JPEG:";
}
else if ($imageinfo[2] == 'GIF')
{
$execute .= " -depth $imageinfo[bits] ";
}
}
$execute .= "\"$output\"";
if ($zak = $this->fetch_im_exec('convert', $execute))
{
return $zak;
}
else if ($sharpen AND !empty($this->error[0]) AND strpos($this->error[0], 'image smaller than radius') !== false)
{ // try to resize again, but without sharpen
$this->error = '';
return $this->fetch_converted_image($filename, $output, $imageinfo, $thumbnail, false);
}
else
{
return false;
}
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function fetch_image_info($filename)
{
if (!$this->verify_image_file($filename))
{
return false;
}
$this->identifyformat = '%g###%w###%h###%m###%n###%r###%z###';
$this->imageinfo = $this->fetch_identify_info($filename);
return $this->imageinfo;
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function fetch_thumbnail($filename, $location, $maxwidth = 100, $maxheight = 100, $quality = 75, $labelimage = false, $drawborder = false, $jpegconvert = false, $sharpen = true, $owidth = null, $oheight = null, $ofilesize = null)
{
$thumbnail = array(
'filedata' => '',
'filesize' => 0,
'dateline' => 0,
'imageerror' => '',
);
if ($this->is_valid_thumbnail_extension(file_extension($filename)))
{
if ($imageinfo = $this->fetch_image_info($location))
{
$thumbnail['source_width'] = $imageinfo[0];
$thumbnail['source_height'] = $imageinfo[1];
if ($this->fetch_imagetype_from_extension(file_extension($filename)) != $imageinfo[2])
{
$thumbnail['imageerror'] = 'thumbnail_notcorrectimage';
}
else if ($imageinfo[0] > $maxwidth OR $imageinfo[1] > $maxheight OR $this->fetch_must_convert($imageinfo[2]))
{
if ($this->registry->options['safeupload'])
{
$tmpname = $this->registry->options['tmppath'] . '/' . md5(uniqid(microtime()) . $this->registry->userinfo['userid']);
}
else
{
if (!($tmpname = @tempnam(ini_get('upload_tmp_dir'), 'vbthumb')))
{
$thumbnail['imageerror'] = 'thumbnail_nogetimagesize';
return $thumbnail;
}
}
$this->set_convert_options($maxwidth, $maxheight, $quality, $labelimage, $drawborder, $jpegconvert, $owidth, $oheight, $ofilesize);
if ($result = $this->fetch_converted_image($location, $tmpname, $imageinfo, true, $sharpen))
{
if ($imageinfo = $this->fetch_image_info($tmpname))
{
$thumbnail['width'] = $imageinfo[0];
$thumbnail['height'] = $imageinfo[1];
}
$extension = strtolower(file_extension($filename));
if ($jpegconvert)
{
$thumbnail['filename'] = preg_replace('#' . preg_quote(file_extension($filename), '#') . '$#', 'jpg', $filename);
}
$thumbnail['filesize'] = filesize($tmpname);
$thumbnail['dateline'] = TIMENOW;
$thumbnail['filedata'] = file_get_contents($tmpname);
}
else
{
$thumbnail['imageerror'] = 'thumbnail_nogetimagesize';
}
@unlink($tmpname);
}
else
{
if ($imageinfo[0] > 0 AND $imageinfo[1] > 0)
{
$thumbnail['filedata'] = @file_get_contents($location);
$thumbnail['width'] = $imageinfo[0];
$thumbnail['height'] = $imageinfo[1];
$thumbnail['imageerror'] = 'thumbnailalready';
}
else
{
$thumbnail['filedata'] = '';
$thumbnail['imageerror'] = 'thumbnail_nogetimagesize';
}
}
}
else
{
$thumbnail['filedata'] = '';
$thumbnail['imageerror'] = 'thumbnail_nogetimagesize';
}
}
if (!empty($thumbnail['filedata']))
{
$thumbnail['filesize'] = strlen($thumbnail['filedata']);
$thumbnail['dateline'] = TIMENOW;
}
return $thumbnail;
}
/**
* See function definition in vB_Image_Abstract
*/
function print_image_from_string($string, $moveabout = true)
{
if ($this->registry->options['safeupload'])
{
$tmpname = $this->registry->options['tmppath'] . '/' . md5(uniqid(microtime()) . $this->registry->userinfo['userid']);
}
else
{
if (!($tmpname = @tempnam(ini_get('upload_tmp_dir'), 'vb')))
{
echo 'Could not create temporary file.';
return false;
}
}
// Command start for no background image
$execute = ' -size 201x61 xc:white ';
$fonts =& $this->fetch_regimage_fonts();
if ($moveabout)
{
$backgrounds =& $this->fetch_regimage_backgrounds();
if (!empty($backgrounds))
{
$index = mt_rand(0, count($backgrounds) - 1);
$background = $backgrounds["$index"];
// replace Command start with background image
$execute = " \"$background\" -resize 201x61! -swirl " . mt_rand(10, 100);
// randomly rotate the background image 180 degrees
$execute .= (TIMENOW & 2) ? ' -rotate 180 ' : '';
}
// Randomly move the letters up and down
for ($x = 0; $x < strlen($string); $x++)
{
if (!empty($fonts))
{
$index = mt_rand(0, count($fonts) - 1);
if ($this->regimageoption['randomfont'])
{
$font = $fonts["$index"];
}
else
{
if (!$font)
{
$font = $fonts["$index"];
}
}
}
else
{
$font = 'Helvetica';
}
if ($this->regimageoption['randomshape'])
{
// Stroke Width, 1 or 2
$strokewidth = mt_rand(1, 2);
// Pick a random color
$r = mt_rand(50, 200);
$b = mt_rand(50, 200);
$g = mt_rand(50, 200);
// Pick a Shape
$x1 = mt_rand(0, 200);
$y1 = mt_rand(0, 60);
$x2 = mt_rand(0, 200);
$y2 = mt_rand(0, 60);
$start = mt_rand(0, 360);
$end = mt_rand(0, 360);
switch(mt_rand(1, 5))
{
case 1:
$shape = "\"roundrectangle $x1,$y1 $x2,$y2 $start,end\"";
break;
case 2:
$shape = "\"arc $x1,$y1 $x2,$y2 20,15\"";
break;
case 3:
$shape = "\"ellipse $x1,$y1 $x2,$y2 $start,$end\"";
break;
case 4:
$shape = "\"line $x1,$y1 $x2,$y2\"";
break;
case 5:
$x3 = mt_rand(0, 200);
$y3 = mt_rand(0, 60);
$x4 = mt_rand(0, 200);
$y4 = mt_rand(0, 60);
$shape = "\"polygon $x1,$y1 $x2,$y2 $x3,$y3 $x4,$y4\"";
break;
}
// before or after
$place = mt_rand(1, 2);
$finalshape = " -flatten -stroke \"rgb($r,$b,$g)\" -strokewidth $strokewidth -fill none -draw $shape -stroke none ";
if ($place == 1)
{
$execute .= $finalshape;
}
}
$slant = (($x <= 1 OR $x == 5) AND $this->regimageoption['randomslant']) ? true : false;
$execute .= $this->annotate($string["$x"], $font, $slant, true);
if ($this->regimageoption['randomshape'] AND $place == 2)
{
$execute .= $finalshape;
}
}
}
else
{
if (!empty($fonts))
{
$font = $fonts[0];
}
else
{
$font = 'Helvetica';
}
$execute .= $this->annotate("\"$string\"", $font, false, false);
}
// Swirl text, stroke inner border of 1 pixel and output as GIF
$execute .= ' -flatten ';
$execute .= ($moveabout AND $this->regimageoption['randomslant']) ? ' -swirl 20 ' : '';
$execute .= " -stroke black -strokewidth 1 -fill none -draw \"rectangle 0,60 200,0\" -depth 8 PNG:\"$tmpname\"";
if ($result = $this->fetch_im_exec('convert', $execute))
{
header('Content-disposition: inline; filename=image.png');
header('Content-transfer-encoding: binary');
header('Content-Type: image/png');
if ($filesize = @filesize($tmpname))
{ // this is here because of a stupid Win32 CGI thingymajig. filesize fails but readfile works, go figure
header("Content-Length: $filesize");
}
readfile($tmpname);
@unlink($tmpname);
}
else
{
echo htmlspecialchars_uni($this->fetch_error());
@unlink($tmpname);
return false;
}
}
/**
* Private
* Return a letter position command
*
* @param string letter Character to position
*
* @return string
*/
function annotate($letter, $font, $slant = false, $random = true)
{
// Start position
static $r, $g, $b, $position = 10;
// Character Slant
static $slants = array(
'0x0', # Normal
'0x30', # Slant Right
'20x20', # Slant Down
'315x315', # Slant Up
'45x45',
'0x330',
);
// Can't use slants AND swirl at the same time, it just looks bad ;)
if ($slant)
{
$coord = mt_rand(1, count($slants) - 1);
$coord = $slants["$coord"];
}
else
{
$coord = $slants[0];
}
if ($random)
{
// Y Axis position, random from 32 to 48
$y = mt_rand(32, 48);
if ($this->regimageoption['randomcolor'] OR empty($r))
{
// Generate a random color..
$r = mt_rand(50, 200);
$b = mt_rand(50, 200);
$g = mt_rand(50, 200);
}
$pointsize = $this->regimageoption['randomsize'] ? mt_rand(28, 36) : 32;
}
else
{
$y = 40;
$pointsize = 32;
$r = $b = $g = 0;
}
$output = " -font \"$font\" -pointsize $pointsize -fill \"rgb($r,$b,$g)\" -annotate $coord+$position+$y $letter ";
$position += rand(25, 35);
return $output;
}
}
/**
* Image class for GD Image Library
*
* @package vBulletin
* @version $Revision: 37230 $
* @date $Date: 2010-05-28 11:50:59 -0700 (Fri, 28 May 2010) $
*
*/
class vB_Image_GD extends vB_Image_Abstract
{
/**
* @var string
*
*/
var $thumbcolor = array(
'r' => 0,
'b' => 0,
'g' => 0
);
/**
* Constructor. Sets up resizable types, extensions, etc.
*
* @return void
*/
function vB_Image_GD(&$registry)
{
parent::vB_Image_Abstract($registry);
$this->info_extensions = array(
'gif' => true,
'jpg' => true,
'jpe' => true,
'jpeg' => true,
'png' => true,
'psd' => true,
'bmp' => true,
'tiff' => true,
'tif' => true,
);
$this->thumb_extensions = array(
'gif' => true,
'jpg' => true,
'jpe' => true,
'jpeg' => true,
'png' => true,
);
$this->resize_types = array(
'JPEG' => true,
'PNG' => true,
'GIF' => true,
);
if (preg_match('~#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})~i', $this->registry->options['thumbcolor'], $match))
{
$this->thumbcolor = array(
'r' => hexdec($match[1]),
'g' => hexdec($match[2]),
'b' => hexdec($match[3])
);
}
}
/**
* Private
* Output an image
*
* @param object filename Image file to convert
* @param int output Image file to write converted image to
* @param bool headers Generate image header
* @param int quality Jpeg Quality
*
* @return void
*/
// ###################### Start print_image #######################
function print_image(&$image, $type = 'JPEG', $headers = true, $quality = 75)
{
// Determine what image type to output
switch($type)
{
case 'GIF':
if (!IMAGEGIF)
{
if (IMAGEJPEG)
{
$type = 'JPEG';
}
else if (IMAGEPNG)
{
$type = 'PNG';
}
else // nothing!
{
imagedestroy($image);
return false;
}
}
break;
case 'PNG':
if (!IMAGEPNG)
{
if (IMAGEJPEG)
{
$type = 'JPEG';
}
else if (IMAGEGIF)
{
$type = 'GIF';
}
else // nothing!
{
imagedestroy($image);
return false;
}
}
break;
default: // JPEG
if (!IMAGEJPEG)
{
if (IMAGEGIF)
{
$type = 'GIF';
}
else if (IMAGEPNG)
{
$type = 'PNG';
}
else // nothing!
{
imagedestroy($image);
return false;
}
}
else
{
$type = 'JPEG';
}
break;
}
/* If you are calling print_image inside ob_start in order to capture the image
remember any headers still get sent to the browser. Mozilla is not happy with this */
switch ($type)
{
case 'GIF':
if ($headers)
{
header('Content-transfer-encoding: binary');
header('Content-disposition: inline; filename=image.gif');
header('Content-type: image/gif');
}
imagegif($image);
imagedestroy($image);
return 'gif';
case 'PNG':
if ($headers)
{
header('Content-transfer-encoding: binary');
header('Content-disposition: inline; filename=image.png');
header('Content-type: image/png');
}
imagepng($image);
imagedestroy($image);
return 'png';
case 'JPEG':
if ($headers)
{
header('Content-transfer-encoding: binary');
header('Content-disposition: inline; filename=image.jpg');
header('Content-type: image/jpeg');
}
imagejpeg($image, '', $quality);
imagedestroy($image);
return 'jpg';
default:
imagedestroy($image);
return false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
////
//// p h p U n s h a r p M a s k
////
//// Original Unsharp mask algorithm by Torstein Hшnsi 2003.
//// thoensi@netcom.no
//// Formatted for vBulletin usage by Freddie Bingham
////
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Private
* Sharpen an image
*
* @param object finalimage
* @param int float
* @param radius float
* @param threshold float
*
* @return void
*/
function unsharpmask(&$finalimage, $amount = 50, $radius = 1, $threshold = 0)
{
// $finalimg 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 true;
}
$w = imagesx($finalimage);
$h = imagesy($finalimage);
$imgCanvas = imagecreatetruecolor($w, $h);
$imgBlur = imagecreatetruecolor($w, $h);
// Gaussian blur matrix:
//
// 1 2 1
// 2 4 2
// 1 2 1
//
//////////////////////////////////////////////////
$gdinfo = gd_info();
if (function_exists('imageconvolution') && strstr($gdinfo['GD Version'], 'bundled'))
{
$matrix = array(
array( 1, 2, 1 ),
array( 2, 4, 2 ),
array( 1, 2, 1 )
);
imagecopy ($imgBlur, $finalimage, 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, $finalimage, 0, 0, 1, 0, $w - 1, $h); // left
imagecopymerge ($imgBlur, $finalimage, 1, 0, 0, 0, $w, $h, 50); // right
imagecopymerge ($imgBlur, $finalimage, 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($finalimage, $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) OR ($gOrig != $gNew) OR ($bOrig != $bNew))
{
$pixCol = ImageColorAllocate($finalimage, $rNew, $gNew, $bNew);
ImageSetPixel($finalimage, $x, $y, $pixCol);
}
}
}
}
else
{
for ($x = 0; $x < $w; $x++) // each row
{
for ($y = 0; $y < $h; $y++) // each pixel
{
$rgbOrig = ImageColorAt($finalimage, $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 = ($amount * ($rOrig - $rBlur)) + $rOrig;
if ($rNew > 255)
{
$rNew = 255;
}
elseif ($rNew < 0)
{
$rNew = 0;
}
$gNew = ($amount * ($gOrig - $gBlur)) + $gOrig;
if ($gNew > 255)
{
$gNew = 255;
}
elseif ($gNew < 0)
{
$gNew = 0;
}
$bNew = ($amount * ($bOrig - $bBlur)) + $bOrig;
if ($bNew > 255)
{
$bNew = 255;
}
elseif ($bNew < 0)
{
$bNew = 0;
}
$rgbNew = ($rNew << 16) + ($gNew << 8) + $bNew;
ImageSetPixel($finalimage, $x, $y, $rgbNew);
}
}
}
imagedestroy($imgCanvas);
imagedestroy($imgBlur);
return true;
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function print_image_from_string($string, $moveabout = true)
{
$image_width = 201;
$image_height = 61;
$backgrounds = $this->fetch_regimage_backgrounds();
if ($moveabout)
{
$notdone = true;
while ($notdone AND !empty($backgrounds))
{
$index = mt_rand(0, count($backgrounds) - 1);
$background = $backgrounds["$index"];
switch(strtolower(file_extension($background)))
{
case 'jpg':
case 'jpe':
case 'jpeg':
if (!function_exists('imagecreatefromjpeg') OR !$image = @imagecreatefromjpeg($background))
{
unset($backgrounds["$index"]);
}
else
{
$notdone = false;
}
break;
case 'gif':
if (!function_exists('imagecreatefromgif') OR !$image = @imagecreatefromgif($background))
{
unset($backgrounds["$index"]);
}
else
{
$notdone = false;
}
break;
case 'png':
if (!function_exists('imagecreatefrompng') OR !$image = @imagecreatefrompng($background))
{
unset($backgrounds["$index"]);
}
else
{
$notdone = false;
}
break;
}
sort($backgrounds);
}
}
if ($image)
{
// randomly flip
if (TIMENOW & 2)
{
$image =& $this->flipimage($image);
}
$gotbackground = true;
}
else
{
$image =& $this->fetch_image_resource($image_width, $image_height);
}
if (function_exists('imagettftext') AND $fonts = $this->fetch_regimage_fonts())
{
if ($moveabout)
{
// Randomly move the letters up and down
for ($x = 0; $x < strlen($string); $x++)
{
$index = mt_rand(0, count($fonts) - 1);
if ($this->regimageoption['randomfont'])
{
$font = $fonts["$index"];
}
else
{
if (empty($font))
{
$font = $fonts["$index"];
}
}
$image = $this->annotatettf($image, $string["$x"], $font);
}
}
else
{
$image = $this->annotatettf($image, $string, $fonts[0], false);
}
}
if ($moveabout)
{
$blur = .9;
/*if (function_exists('imagefilter'))
{
#if (!@imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR))
{
# $image =& $this->blur($image, $blur);
}
}
else
{
# $image =& $this->blur($image, $blur);
}*/
}
$text_color = imagecolorallocate($image, 0, 0, 0);
// draw a border
imageline($image, 0, 0, $image_width, 0, $text_color);
imageline($image, 0, 0, 0, $image_height, $text_color);
imageline($image, $image_width - 1, 0, $image_width - 1, $image_height, $text_color);
imageline($image, 0, $image_height - 1, $image_width, $image_height - 1, $text_color);
$this->print_image($image, 'JPEG', true, 100);
}
/**
* Private
* Create blank image
*
* @param int width Width of image
* @param int height Height of image
*
* @return resource
*/
function &fetch_image_resource($width, $height)
{
$image = imagecreatetruecolor($width, $height);
$background_color = imagecolorallocate($image, 255, 255, 255); //white background
imagefill($image, 0, 0, $background_color); // For GD2+
return $image;
}
/**
* Private
* Return a letter position command
*
* @param resource image Image to annotate
* @param string letter Character to position
* @param boolean random Apply effects
*
* @return string
*/
function &annotategd($image, $letter, $random = true)
{
// Start position
static $r, $g, $b, $xposition = 10;
if ($random)
{
if ($this->regimageoption['randomcolor'] OR empty($r))
{
// Generate a random color..
$r = mt_rand(50, 200);
$b = mt_rand(50, 200);
$g = mt_rand(50, 200);
}
$yposition = mt_rand(0, 5);
$text_color = imagecolorallocate($image, $r, $g, $b);
imagechar($image, 5, $xposition, $yposition, $letter, $text_color);
$xposition += mt_rand(10, 25);
}
else
{
$text_color = imagecolorallocate($image, 0, 0, 0);
$yposition = 2;
imagechar($image, 5, $xposition, $yposition, $letter, $text_color);
$xposition += 10;
}
return $image;
}
/**
* Private
* Return a letter position command
*
* @param resource image Image to annotate
* @param string letter Character to position
* @param string font Font to annotate (path)
* @param boolean slant Slant fonts left or right
* @param boolean random Apply effects
*
* @return string
*/
function annotatettf($image, $letter, $font, $random = true)
{
if ($random)
{
// Start position
static $r, $g, $b, $position = 15;
// Y Axis position, random from 35 to 48
$y = mt_rand(35, 48);
if ($this->regimageoption['randomcolor'] OR empty($r))
{
// Generate a random color..
$r = mt_rand(50, 200);
$b = mt_rand(50, 200);
$g = mt_rand(50, 200);
}
if ($this->regimageoption['randomshape'])
{
if (function_exists('imageantialias'))
{ // See http://bugs.php.net/bug.php?id=28147
imageantialias($image, true);
}
// Stroke Width, 2 or 3
imagesetthickness($image, mt_rand(2, 3));
// Pick a random color
$shapecolor = imagecolorallocate($image, mt_rand(50, 200), mt_rand(50, 200), mt_rand(50, 200));
// Pick a Shape
$x1 = mt_rand(0, 200);
$y1 = mt_rand(0, 60);
$x2 = mt_rand(0, 200);
$y2 = mt_rand(0, 60);
$start = mt_rand(0, 360);
$end = mt_rand(0, 360);
switch(mt_rand(1, 4))
{
case 1:
imagearc($image, $x1, $y1, $x2, $y2, $start, $end, $shapecolor);
break;
case 2:
imageellipse($image, $x1, $y1, $x2, $y2, $shapecolor);
break;
case 3:
imageline($image, $x1, $y1, $x2, $y2, $shapecolor);
break;
case 4:
imagepolygon($image, array(
$x1, $y1,
$x2, $y2,
mt_rand(0, 200), mt_rand(0, 60),
mt_rand(0, 200), mt_rand(0, 60),
),
4, $shapecolor
);
break;
}
}
// Angle
$slant = $this->regimageoption['randomslant'] ? mt_rand(-20, 60) : 0;
$pointsize = $this->regimageoption['randomsize'] ? mt_rand(20, 32) : 24;
$text_color = imagecolorallocate($image, $r, $g, $b);
}
else
{
$position = 10;
$y = 40;
$slant = 0;
$pointsize = 24;
$text_color = imagecolorallocate($image, 0, 0, 0);
}
if (!$result = @imagettftext($image, $pointsize, $slant, $position, $y, $text_color, $font, $letter))
{
return false;
}
else
{
$position += rand(25, 35);
return $image;
}
}
/**
* Private
* mirror an image horizontally. Can be extended to other flips but this is all we need for now
*
* @param image image Image file to convert
*
* @return object image
*/
function &flipimage(&$image)
{
$width = imagesx($image);
$height = imagesy($image);
$output = imagecreatetruecolor($width, $height);
for($x = 0; $x < $height; $x++)
{
imagecopy($output, $image, 0, $height - $x - 1, 0, $x, $width, 1);
}
return $output;
}
/**
* Private
* Apply a swirl/twirl filter to an image
*
* @param image image Image file to convert
* @param float output Degree of twirl
* @param bool randirection Randomize direction of swirl (clockwise/counterclockwise)
*
* @return object image
*/
function &swirl(&$image, $degree = .005, $randirection = true)
{
$image_width = imagesx($image);
$image_height = imagesy($image);
$temp = imagecreatetruecolor($image_width, $image_height);
if ($randirection)
{
$degree = (mt_rand(0, 1) == 1) ? $degree : $degree * -1;
}
$middlex = floor($image_width / 2);
$middley = floor($image_height / 2);
for ($x = 0; $x < $image_width; $x++)
{
for ($y = 0; $y < $image_height; $y++)
{
$xx = $x - $middlex;
$yy = $y - $middley;
$theta = atan2($yy, $xx);
$radius = sqrt($xx * $xx + $yy * $yy);
$radius -= 5;
$newx = $middlex + ($radius * cos($theta + $degree * $radius));
$newy = $middley + ($radius * sin($theta + $degree * $radius));
if (($newx > 0 AND $newx < $image_width) AND ($newy > 0 AND $newy < $image_height))
{
$index = imagecolorat($image, $newx, $newy);
$colors = imagecolorsforindex($image, $index);
$color = imagecolorresolve($temp, $colors['red'], $colors['green'], $colors['blue']);
}
else
{
$color = imagecolorresolve($temp, 255, 255, 255);
}
imagesetpixel($temp, $x, $y, $color);
}
}
return $temp;
}
/**
* Private
* Apply a wave filter to an image
*
* @param image image Image to convert
* @param int wave Amount of wave to apply
* @param bool randirection Randomize direction of wave
*
* @return image
*/
function &wave(&$image, $wave = 10, $randirection = true)
{
$image_width = imagesx($image);
$image_height = imagesy($image);
$temp = imagecreatetruecolor($image_width, $image_height);
if ($randirection)
{
$direction = (TIMENOW & 2) ? true : false;
}
$middlex = floor($image_width / 2);
$middley = floor($image_height / 2);
for ($x = 0; $x < $image_width; $x++)
{
for ($y = 0; $y < $image_height; $y++)
{
$xo = $wave * sin(2 * 3.1415 * $y / 128);
$yo = $wave * cos(2 * 3.1415 * $x / 128);
if ($direction)
{
$newx = $x - $xo;
$newy = $y - $yo;
}
else
{
$newx = $x + $xo;
$newy = $y + $yo;
}
if (($newx > 0 AND $newx < $image_width) AND ($newy > 0 AND $newy < $image_height))
{
$index = imagecolorat($image, $newx, $newy);
$colors = imagecolorsforindex($image, $index);
$color = imagecolorresolve($temp, $colors['red'], $colors['green'], $colors['blue']);
}
else
{
$color = imagecolorresolve($temp, 255, 255, 255);
}
imagesetpixel($temp, $x, $y, $color);
}
}
return $temp;
}
/**
* Private
* Apply a blur filter to an image
*
* @param image image Image to convert
* @param int radius Radius of blur
*
* @return image
*/
function &blur(&$image, $radius = .5)
{
$radius = ($radius > 50) ? 100 : abs(round($radius * 2));
if ($radius == 0)
{
return $image;
}
$w = imagesx($image);
$h = imagesy($image);
$imgCanvas = imagecreatetruecolor($w, $h);
$imgBlur = imagecreatetruecolor($w, $h);
imagecopy ($imgCanvas, $image, 0, 0, 0, 0, $w, $h);
// Gaussian blur matrix:
//
// 1 2 1
// 2 4 2
// 1 2 1
//
//////////////////////////////////////////////////
// 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, $imgCanvas, 0, 0, 1, 1, $w - 1, $h - 1); // up left
imagecopymerge($imgBlur, $imgCanvas, 1, 1, 0, 0, $w, $h, 50); // down right
imagecopymerge($imgBlur, $imgCanvas, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left
imagecopymerge($imgBlur, $imgCanvas, 1, 0, 0, 1, $w, $h - 1, 25); // up right
imagecopymerge($imgBlur, $imgCanvas, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left
imagecopymerge($imgBlur, $imgCanvas, 1, 0, 0, 0, $w, $h, 25); // right
imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 1, $w, $h - 1, 20 ); // up
imagecopymerge($imgBlur, $imgCanvas, 0, 1, 0, 0, $w, $h, 16.666667); // down
imagecopymerge($imgBlur, $imgCanvas, 0, 0, 0, 0, $w, $h, 50); // center
imagecopy($imgCanvas, $imgBlur, 0, 0, 0, 0, $w, $h);
}
imagedestroy($imgBlur);
return $imgCanvas;
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function fetch_image_info($filename)
{
static $types = array(
1 => 'GIF',
2 => 'JPEG',
3 => 'PNG',
4 => 'SWF',
5 => 'PSD',
6 => 'BMP',
7 => 'TIFF',
8 => 'TIFF',
9 => 'JPC',
10=> 'JP2',
11=> 'JPX',
12=> 'JB2',
13=> 'SWC',
14=> 'IFF',
15=> 'WBMP',
16=> 'XBM',
);
if (!$this->verify_image_file($filename))
{
return false;
}
// use PHP's getimagesize if it works
if ($imageinfo = getimagesize($filename))
{
$this->imageinfo = array(
0 => $imageinfo[0],
1 => $imageinfo[1],
2 => $types["$imageinfo[2]"],
'channels' => $imageinfo['channels'],
'bits' => $imageinfo['bits'],
'scenes' => 1,
'library' => 'GD',
'animated' => false,
);
if ($this->imageinfo[2] == 'GIF')
{ // get scenes
$data = file_get_contents($filename);
// Look for a Global Color table char and the Image seperator character
// The scene count could be broken, see #26591
$this->imageinfo['scenes'] = count(preg_split('#\x00[\x00-\xFF]\x00\x2C#', $data)) - 1;
$this->imageinfo['animated'] = (strpos($data, 'NETSCAPE2.0') !== false);
unset($data);
}
return $this->imageinfo;
}
// getimagesize barfs on some jpegs but we can try to create an image to find the dimensions
else if (function_exists('imagecreatefromjpeg') AND $img = @imagecreatefromjpeg($filename))
{
$this->imageinfo = array(
0 => imagesx($img),
1 => imagesy($img),
2 => 'JPEG',
'channels' => 3,
'bits' => 8,
'library' => 'GD',
);
imagedestroy($img);
return $this->imageinfo;
}
else
{
return false;
}
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function fetch_thumbnail($filename, $location, $maxwidth = 100, $maxheight = 100, $quality = 75, $labelimage = false, $drawborder = false, $jpegconvert = false, $sharpen = true, $owidth = null, $oheight = null, $ofilesize = null)
{
$thumbnail = array(
'filedata' => '',
'filesize' => 0,
'dateline' => 0,
'imageerror' => '',
);
if ($validfile = $this->is_valid_thumbnail_extension(file_extension($filename)) AND $imageinfo = $this->fetch_image_info($location))
{
$thumbnail['source_width'] = $new_width = $width = $imageinfo[0];
$thumbnail['source_height'] = $new_height = $height = $imageinfo[1];
if ($this->fetch_imagetype_from_extension(file_extension($filename)) != $imageinfo[2])
{
$thumbnail['imageerror'] = 'thumbnail_notcorrectimage';
}
else if ($width > $maxwidth OR $height > $maxheight)
{
$memoryok = true;
if (function_exists('memory_get_usage') AND $memory_limit = @ini_get('memory_limit') AND $memory_limit != -1)
{
$memorylimit = vb_number_format($memory_limit, 0, false, null, '');
$memoryusage = memory_get_usage();
$freemem = $memorylimit - $memoryusage;
$checkmem = true;
$tmemory = $width * $height * ($imageinfo[2] == 'JPEG' ? 5 : 2) + 7372.8 + sqrt(sqrt($width * $height));
$tmemory += 166000; // fudge factor, object overhead, etc
if ($freemem > 0 AND $tmemory > $freemem AND $tmemory <= ($memorylimit * 3))
{ // attempt to increase memory within reason, no more than triple
if (($current_memory_limit = ini_size_to_bytes(@ini_get('memory_limit'))) < $memorylimit + $tmemory AND $current_memory_limit > 0)
{
@ini_set('memory_limit', $memorylimit + $tmemory);
}
$memory_limit = @ini_get('memory_limit');
$memorylimit = vb_number_format($memory_limit, 0, false, null, '');
$memoryusage = memory_get_usage();
$freemem = $memorylimit - $memoryusage;
}
}
switch($imageinfo[2])
{
case 'GIF':
if (function_exists('imagecreatefromgif'))
{
if ($checkmem)
{
if ($freemem > 0 AND $tmemory > $freemem)
{
$thumbnail['imageerror'] = 'thumbnail_notenoughmemory';
$memoryok = false;
}
}
if ($memoryok AND !$image = @imagecreatefromgif($location))
{
$thumbnail['imageerror'] = 'thumbnail_nocreateimage';
}
}
else
{
$thumbnail['imageerror'] = 'thumbnail_nosupport';
}
break;
case 'JPEG':
if (function_exists('imagecreatefromjpeg'))
{
if ($checkmem)
{
if ($freemem > 0 AND $tmemory > $freemem)
{
$thumbnail['imageerror'] = 'thumbnail_notenoughmemory';
$memoryok = false;
}
}
if ($memoryok AND !$image = @imagecreatefromjpeg($location))
{
$thumbnail['imageerror'] = 'thumbnail_nocreateimage';
}
}
else
{
$thumbnail['imageerror'] = 'thumbnail_nosupport';
}
break;
case 'PNG':
if (function_exists('imagecreatefrompng'))
{
if ($checkmem)
{
if ($freemem > 0 AND $tmemory > $freemem)
{
$thumbnail['imageerror'] = 'thumbnail_notenoughmemory';
$memoryok = false;
}
}
if ($memoryok AND !$image = @imagecreatefrompng($location))
{
$thumbnail['imagerror'] = 'thumbnail_nocreateimage';
}
}
else
{
$thumbnail['imageerror'] = 'thumbnail_nosupport';
}
break;
}
if ($image)
{
$xratio = ($maxwidth == 0) ? 1 : $width / $maxwidth;
$yratio = ($maxheight == 0) ? 1 : $height / $maxheight;
if ($xratio > $yratio)
{
$new_width = round($width / $xratio);
$new_height = round($height / $xratio);
}
else
{
$new_width = round($width / $yratio);
$new_height = round($height / $yratio);
}
if ($drawborder)
{
$create_width = $new_width + 2;
$create_height = $new_height + 2;
$dest_x_start = 1;
$dest_y_start = 1;
}
else
{
$create_width = $new_width;
$create_height = $new_height;
$dest_x_start = 0;
$dest_y_start = 0;
}
if ($labelimage)
{
$font = 2;
$labelboxheight = ($drawborder) ? 13 : 14;
if ($ofilesize)
{
$filesize = $ofilesize;
}
else
{
$filesize = @filesize($location);
}
if ($filesize / 1024 < 1)
{
$filesize = 1024;
}
if ($owidth)
{
$dimensions = $owidth . 'x' . $oheight;
}
else
{
$dimensions = (!empty($width) AND !empty($height)) ? "{$width}x{$height}" : '';
}
$sizestring = (!empty($filesize)) ? number_format($filesize / 1024, 0, '', '') . 'kb' : '';
if (($string_length = (strlen($string = "$dimensions $sizestring $imageinfo[2]") * imagefontwidth($font))) < $new_width)
{
$finalstring = $string;
$finalwidth = $string_length;
}
else if (($string_length = (strlen($string = "$dimensions $sizestring") * imagefontwidth($font))) < $new_width)
{
$finalstring = $string;
$finalwidth = $string_length;
}
else if (($string_length = (strlen($string = $dimensions) * imagefontwidth($font))) < $new_width)
{
$finalstring = $string;
$finalwidth = $string_length;
}
else if (($string_length = (strlen($string = $sizestring) * imagefontwidth($font))) < $new_width)
{
$finalstring = $string;
$finalwidth = $string_length;
}
if (!empty($finalstring))
{
$create_height += $labelboxheight;
if ($drawborder)
{
$label_x_start = ($new_width - ($finalwidth)) / 2 + 2;
$label_y_start = ($labelboxheight - imagefontheight($font)) / 2 + $new_height + 1;
}
else
{
$label_x_start = ($new_width - ($finalwidth)) / 2 + 1;
$label_y_start = ($labelboxheight - imagefontheight($font)) / 2 + $new_height;
}
}
}
if (!($finalimage = @imagecreatetruecolor($create_width, $create_height)))
{
$thumbnail['imageerror'] = 'thumbnail_nocreateimage';
imagedestroy($image);
return $thumbnail;
}
$bgcolor = imagecolorallocate($finalimage, 255, 255, 255);
imagefill($finalimage, 0, 0, $bgcolor);
@imagecopyresampled($finalimage, $image, $dest_x_start, $dest_y_start, 0, 0, $new_width, $new_height, $width, $height);
imagedestroy($image);
if ($sharpen AND $this->imageinfo[2] != 'GIF')
{
$this->unsharpmask($finalimage);
}
if ($labelimage AND !empty($finalstring))
{
$bgcolor = imagecolorallocate($finalimage, $this->thumbcolor['r'], $this->thumbcolor['g'], $this->thumbcolor['b']);
$recstart = ($drawborder) ? $create_height - $labelboxheight - 1 : $create_height - $labelboxheight;
imagefilledrectangle($finalimage, 0, $recstart, $create_width, $create_height, $bgcolor);
$textcolor = imagecolorallocate($finalimage, 255, 255, 255);
imagestring($finalimage, $font, $label_x_start, $label_y_start, $finalstring, $textcolor);
}
if ($drawborder)
{
$bordercolor = imagecolorallocate($finalimage, $this->thumbcolor['r'], $this->thumbcolor['g'], $this->thumbcolor['b']);
imageline($finalimage, 0, 0, $create_width, 0, $bordercolor);
imageline($finalimage, 0, 0, 0, $create_height, $bordercolor);
imageline($finalimage, $create_width - 1, 0, $create_width - 1, $create_height, $bordercolor);
imageline($finalimage, 0, $create_height - 1, $create_width, $create_height - 1, $bordercolor);
}
ob_start();
$new_extension = $this->print_image($finalimage, $jpegconvert ? 'JPEG' : $imageinfo[2], false, $quality);
$thumbnail['filedata'] = ob_get_contents();
ob_end_clean();
$thumbnail['width'] = $create_width;
$thumbnail['height'] = $create_height;
$extension = file_extension($filename);
if ($new_extension != $extension)
{
$thumbnail['filename'] = preg_replace('#' . preg_quote($extension, '#') . '$#', $new_extension, $filename);
}
}
}
else
{
if ($imageinfo[0] == 0 AND $imageinfo[1] == 0) // getimagesize() failed
{
$thumbnail['filedata'] = '';
$thumbnail['imageerror'] = 'thumbnail_nogetimagesize';
}
else
{
$thumbnail['filedata'] = @file_get_contents($location);
$thumbnail['width'] = $imageinfo[0];
$thumbnail['height'] = $imageinfo[1];
$thumbnail['imageerror'] = 'thumbnailalready';
}
}
}
else if (!$validfile)
{
$thumbnail['filedata'] = '';
$thumbnail['imageerror'] = 'thumbnail_nosupport';
}
if (!empty($thumbnail['filedata']))
{
$thumbnail['filesize'] = strlen($thumbnail['filedata']);
$thumbnail['dateline'] = TIMENOW;
}
return $thumbnail;
}
/**
*
* See function definition in vB_Image_Abstract
*
*/
function fetch_error()
{
return false;
}
}
/*======================================================================*\
|| ####################################################################
|| # CVS: $RCSfile$ - $Revision: 37230 $
|| ####################################################################
\*======================================================================*/
?>