427 lines
11 KiB
PHP
427 lines
11 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the symfony package.
|
|
* (c) 2004-2007 Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
/**
|
|
* sfThumbnail provides a mechanism for creating thumbnail images.
|
|
*
|
|
* This is taken from Harry Fueck's Thumbnail class and
|
|
* converted for PHP5 strict compliance for use with symfony.
|
|
*
|
|
* @package sfThumbnailPlugin
|
|
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
* @author Benjamin Meynell <bmeynell@colorado.edu>
|
|
*/
|
|
class sfThumbnail
|
|
{
|
|
const QUALITY_OPTIMIZED = 80;
|
|
/**
|
|
* Width of thumbnail in pixels
|
|
*/
|
|
protected $thumbWidth;
|
|
/**
|
|
* Height of thumbnail in pixels
|
|
*/
|
|
protected $thumbHeight;
|
|
/**
|
|
* Temporary file if the source is not local
|
|
*/
|
|
protected $tempFile = null;
|
|
|
|
protected static $imageTypeSupported = [];
|
|
|
|
public static function hasImageTypeSupport($imageType, $adapter = null)
|
|
{
|
|
if (null === $adapter)
|
|
{
|
|
$generalAssetConfig = stConfig::getInstance('stAsset')->get('general', []);
|
|
$adapter = isset($generalAssetConfig['adapter']) ? $generalAssetConfig['adapter'] : stGDAdapter::class;
|
|
}
|
|
|
|
$imageType = strtoupper($imageType);
|
|
|
|
$id = $adapter.'_'.$imageType;
|
|
|
|
if (!isset(self::$imageTypeSupported[$id]))
|
|
{
|
|
self::$imageTypeSupported[$id] = call_user_func([$adapter, 'hasimageTypeSupport'], $imageType);
|
|
}
|
|
|
|
return self::$imageTypeSupported[$id];
|
|
}
|
|
|
|
public static function getWatermarkFonts()
|
|
{
|
|
static $arr = array();
|
|
|
|
if (!$arr)
|
|
{
|
|
$fonts = sfConfig::get('app_stThumbnailPlugin_watermark_fonts');
|
|
|
|
$i18n = sfContext::getInstance()->getI18N();
|
|
|
|
foreach ($fonts as $k => $v)
|
|
{
|
|
$arr[$k] = $i18n->__($v, array(), 'stThumbnail');
|
|
}
|
|
|
|
asort($arr);
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
public static function getWatermarkPosition($position = null)
|
|
{
|
|
static $arr = array();
|
|
|
|
$positions = sfConfig::get('app_stThumbnailPlugin_watermark_positions');
|
|
|
|
if ($position)
|
|
{
|
|
return isset($positions[$position]) ? $positions[$position] : null;
|
|
}
|
|
elseif (!$arr)
|
|
{
|
|
$i18n = sfContext::getInstance()->getI18N();
|
|
|
|
foreach ($positions as $k => $v)
|
|
{
|
|
$arr[$k] = $i18n->__($v['name'], array(), 'stThumbnail');
|
|
}
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
public static function create($image_from, $image_to = null, $params = array())
|
|
{
|
|
if (stConfig::getInstance('stOptimizationBackend')->get('optimize_img'))
|
|
{
|
|
$params['quality'] = self::QUALITY_OPTIMIZED;
|
|
}
|
|
|
|
$thumbnail = new sfThumbnail($params['width'], $params['height'], true, true, $params['quality']);
|
|
|
|
if (isset($params['watermark']))
|
|
{
|
|
$thumbnail->setWatermarkText($params['watermark']['text'], isset($params['watermark']['size']) ? $params['watermark']['size'] : null, $params['watermark']['position'], $params['watermark']['color'], $params['watermark']['alpha'], $params['watermark']['font']);
|
|
}
|
|
|
|
$thumbnail->loadFile($image_from, isset($params['auto_crop']) ? $params['auto_crop'] : null);
|
|
|
|
if ($image_to)
|
|
{
|
|
$thumbnail->save($image_to);
|
|
}
|
|
|
|
return $thumbnail;
|
|
}
|
|
|
|
public static function getDefaultAdapter()
|
|
{
|
|
$adapters = self::getSupportedAdapters();
|
|
|
|
return isset($adapters['sfImagickAdapter']) ? 'sfImagickAdapter' : 'stGDAdapter';
|
|
}
|
|
|
|
public static function getSupportedAdapters()
|
|
{
|
|
$adapters = array('stGDAdapter' => 'GD');
|
|
|
|
if (class_exists('Imagick'))
|
|
{
|
|
$adapters['sfImagickAdapter'] = 'ImageMagick';
|
|
}
|
|
|
|
return $adapters;
|
|
}
|
|
|
|
/**
|
|
* Thumbnail constructor
|
|
*
|
|
* @param int (optional) max width of thumbnail
|
|
* @param int (optional) max height of thumbnail
|
|
* @param boolean (optional) if true image scales
|
|
* @param boolean (optional) if true inflate small images
|
|
* @param string (optional) adapter class name
|
|
* @param array (optional) adapter options
|
|
*/
|
|
public function __construct($maxWidth = null, $maxHeight = null, $scale = true, $inflate = true, $quality = 75, $adapterClass = null, $adapterOptions = array())
|
|
{
|
|
if (!$adapterClass)
|
|
{
|
|
$general = stConfig::getInstance('stAsset')->get('general', array());
|
|
$adapters = self::getSupportedAdapters();
|
|
$adapterClass = isset($general['adapter']) && isset($adapters[$general['adapter']]) ? $general['adapter'] : self::getDefaultAdapter();
|
|
|
|
$adapterOptions = array_merge($adapterOptions, $general);
|
|
}
|
|
|
|
$this->adapter = new $adapterClass($maxWidth, $maxHeight, $scale, $inflate, $quality, $adapterOptions);
|
|
}
|
|
|
|
/**
|
|
* Loads an image from a file and creates an internal thumbnail out of it
|
|
*
|
|
* @param string filename (with absolute path) of the image to load
|
|
*
|
|
* @return boolean True if the image was properly loaded
|
|
* @throws Exception If the image cannot be loaded, or if its mime type is not supported
|
|
*/
|
|
public function loadFile($image, $auto_crop = null)
|
|
{
|
|
$this->adapter->loadFile($this, $image, $auto_crop);
|
|
}
|
|
|
|
/**
|
|
* Loads an image from a string (e.g. database) and creates an internal thumbnail out of it
|
|
*
|
|
* @param string the image string (must be a format accepted by imagecreatefromstring())
|
|
* @param string mime type of the image
|
|
*
|
|
* @return boolean True if the image was properly loaded
|
|
* @access public
|
|
* @throws Exception If image mime type is not supported
|
|
*/
|
|
public function loadData($image, $mime)
|
|
{
|
|
$this->adapter->loadData($this, $image, $mime);
|
|
}
|
|
|
|
/**
|
|
* Saves the thumbnail to the filesystem
|
|
* If no target mime type is specified, the thumbnail is created with the same mime type as the source file.
|
|
*
|
|
* @param string the image thumbnail file destination (with absolute path)
|
|
* @param string The mime-type of the thumbnail (possible values are 'image/jpeg', 'image/png', and 'image/gif')
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function save($thumbDest, $targetMime = null)
|
|
{
|
|
$dir = dirname($thumbDest);
|
|
|
|
if (!is_dir($dir))
|
|
{
|
|
mkdir($dir, 0755, true);
|
|
}
|
|
|
|
$this->adapter->save($this, $thumbDest, $targetMime);
|
|
}
|
|
|
|
public function __toString()
|
|
{
|
|
return $this->toString();
|
|
}
|
|
|
|
/**
|
|
* Returns the thumbnail as a string
|
|
* If no target mime type is specified, the thumbnail is created with the same mime type as the source file.
|
|
*
|
|
*
|
|
* @param string The mime-type of the thumbnail (possible values are adapter dependent)
|
|
*
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public function toString($targetMime = null)
|
|
{
|
|
return $this->adapter->toString($this, $targetMime);
|
|
}
|
|
|
|
public function freeSource()
|
|
{
|
|
if (!is_null($this->tempFile))
|
|
{
|
|
unlink($this->tempFile);
|
|
}
|
|
$this->adapter->freeSource();
|
|
}
|
|
|
|
public function freeThumb()
|
|
{
|
|
$this->adapter->freeThumb();
|
|
}
|
|
|
|
public function freeAll()
|
|
{
|
|
$this->adapter->freeSource();
|
|
$this->adapter->freeThumb();
|
|
}
|
|
|
|
/**
|
|
* Returns the width of the thumbnail
|
|
*/
|
|
public function getThumbWidth()
|
|
{
|
|
return $this->thumbWidth;
|
|
}
|
|
|
|
/**
|
|
* Returns the height of the thumbnail
|
|
*/
|
|
public function getThumbHeight()
|
|
{
|
|
return $this->thumbHeight;
|
|
}
|
|
|
|
public function setThumbWidth($v)
|
|
{
|
|
$this->thumbWidth = $v;
|
|
}
|
|
|
|
public function setThumbHeight($v)
|
|
{
|
|
$this->thumbHeight = $v;
|
|
}
|
|
|
|
/**
|
|
* Returns the mime type of the source image
|
|
*/
|
|
public function getMime()
|
|
{
|
|
return $this->adapter->getSourceMime();
|
|
}
|
|
|
|
/**
|
|
* Computes the thumbnail width and height
|
|
* Used by adapter
|
|
*/
|
|
public function initThumb($sourceWidth, $sourceHeight, $maxWidth, $maxHeight, $scale, $inflate, $crop = null)
|
|
{
|
|
if ($crop && is_array($crop))
|
|
{
|
|
$this->thumbWidth = $sourceWidth > $maxWidth ? $maxWidth : $sourceWidth;
|
|
$this->thumbHeight = $sourceHeight > $maxHeight ? $maxHeight : $sourceHeight;
|
|
}
|
|
else
|
|
{
|
|
list($this->thumbWidth, $this->thumbHeight) = $this->getImageSize($sourceWidth, $sourceHeight, $maxWidth, $maxHeight, $scale, $inflate, $crop);
|
|
}
|
|
}
|
|
|
|
public function getCroppedImageSize($maxWidth, $maxHeight)
|
|
{
|
|
$sw = $this->thumbWidth;
|
|
|
|
$sh = $this->thumbHeight;
|
|
|
|
$sx = 0;
|
|
|
|
$sy = 0;
|
|
|
|
$dw = $sw;
|
|
|
|
$dh = $sh;
|
|
|
|
if ($sw > $maxWidth)
|
|
{
|
|
$sx = round(($sw - $maxWidth) / 2);
|
|
|
|
$dw = $sw - $sx * 2;
|
|
}
|
|
elseif ($sh > $maxHeight)
|
|
{
|
|
$sy = round(($sh - $maxHeight) / 2);
|
|
|
|
$dh = $sh - $sy * 2;
|
|
}
|
|
|
|
return array($dw, $dh);
|
|
}
|
|
|
|
public function getImageSize($sourceWidth, $sourceHeight, $maxWidth, $maxHeight, $scale, $inflate, $crop = null)
|
|
{
|
|
$size = array();
|
|
|
|
if ($maxWidth > 0)
|
|
{
|
|
$ratioWidth = $maxWidth / $sourceWidth;
|
|
}
|
|
if ($maxHeight > 0)
|
|
{
|
|
$ratioHeight = $maxHeight / $sourceHeight;
|
|
}
|
|
|
|
if ($scale)
|
|
{
|
|
if ($maxWidth && $maxHeight)
|
|
{
|
|
$ratio = !$crop && ($ratioWidth < $ratioHeight) || $crop && ($ratioWidth > $ratioHeight) ? $ratioWidth : $ratioHeight;
|
|
}
|
|
if ($maxWidth xor $maxHeight)
|
|
{
|
|
$ratio = (isset($ratioWidth)) ? $ratioWidth : $ratioHeight;
|
|
}
|
|
if ((!$maxWidth && !$maxHeight) || (!$inflate && $ratio > 1))
|
|
{
|
|
$ratio = 1;
|
|
}
|
|
|
|
$ratio = min($ratio, 1);
|
|
|
|
$size = array(floor($ratio * $sourceWidth), floor($ratio * $sourceHeight));
|
|
}
|
|
else
|
|
{
|
|
if (!isset($ratioWidth) || (!$inflate && $ratioWidth > 1))
|
|
{
|
|
$ratioWidth = 1;
|
|
}
|
|
if (!isset($ratioHeight) || (!$inflate && $ratioHeight > 1))
|
|
{
|
|
$ratioHeight = 1;
|
|
}
|
|
$size = array(floor($ratioWidth * $sourceWidth), floor($ratioHeight * $sourceHeight));
|
|
}
|
|
|
|
return $size;
|
|
}
|
|
|
|
public function __destruct()
|
|
{
|
|
$this->freeAll();
|
|
}
|
|
|
|
protected function html2rgb($color)
|
|
{
|
|
if ($color[0] == '#')
|
|
$color = substr($color, 1);
|
|
|
|
if (strlen($color) == 6)
|
|
list($r, $g, $b) = array($color[0].$color[1], $color[2].$color[3], $color[4].$color[5]); elseif (strlen($color) == 3)
|
|
list($r, $g, $b) = array($color[0].$color[0], $color[1].$color[1], $color[2].$color[2]); else
|
|
return false;
|
|
|
|
$r = hexdec($r);
|
|
$g = hexdec($g);
|
|
$b = hexdec($b);
|
|
|
|
return array($r, $g, $b);
|
|
}
|
|
|
|
public function setWatermarkText($text, $size = 12, $position = 'diagonal_down', $color = '#000', $alpha = 0, $font = null)
|
|
{
|
|
if (is_string($color))
|
|
{
|
|
$color = $this->html2rgb($color);
|
|
}
|
|
|
|
$this->adapter->setWatermarkText($text, $size, $position, $color, $alpha, $font);
|
|
}
|
|
|
|
}
|
|
|
|
class stThumbnail extends sfThumbnail
|
|
{
|
|
|
|
}
|