first commit

This commit is contained in:
2025-03-12 17:06:23 +01:00
commit 2241f7131f
13185 changed files with 1692479 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
<?php
/**
* Get the path of a generated thumbnail for any given image
*
* @param string $source
* @param int $width
* @param int $height
* @param boolean $absolute
* @return string
*/
function thumbnail_path($source, $width, $height, $absolute = false)
{
$thumbnails_dir = sfConfig::get('app_sfThumbnail_thumbnails_dir', 'uploads/thumbnails');
$width = intval($width);
$height = intval($height);
if (substr($source, 0, 1) == '/') {
$realpath = sfConfig::get('sf_web_dir') . $source;
} else {
$realpath = sfConfig::get('sf_web_dir') . '/images/' . $source;
}
$real_dir = dirname($realpath);
$thumb_dir = '/' . $thumbnails_dir . substr($real_dir, strlen(sfConfig::get('sf_web_dir')));
$thumb_name = preg_replace('/^(.*?)(\..+)?$/', '$1_' . $width . 'x' . $height . '$2', basename($source));
$img_from = $realpath;
$thumb = $thumb_dir . '/' . $thumb_name;
$img_to = sfConfig::get('sf_web_dir') . $thumb;
if (!is_dir(dirname($img_to))) {
if (!mkdir(dirname($img_to), 0777, true)) {
throw new Exception('Cannot create directory for thumbnail : ' . $img_to);
}
}
if (!is_file($img_to) || filemtime($img_from) > filemtime($img_to)) {
$thumbnail = new sfThumbnail($width, $height);
$thumbnail->loadFile($img_from);
$thumbnail->save($img_to);
}
return image_path($thumb, $absolute);
}
/**
* Get the <img> tag to include a thumbnail into your web page
*
* @param string $source
* @param int $width
* @param int $height
* @param mixed $options
* @return string
*/
function thumbnail_tag($source, $width, $height, $options = array())
{
$img_src = thumbnail_path($source, $width, $height, false);
return image_tag($img_src, $options);
}

View File

@@ -0,0 +1,396 @@
<?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.
*/
/**
* sfGDAdapter provides a mechanism for creating thumbnail images.
* @see http://www.php.net/gd
*
* @package sfThumbnailPlugin
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Benjamin Meynell <bmeynell@colorado.edu>
*/
class sfGDAdapter
{
protected
$sourceWidth,
$sourceHeight,
$sourceMime,
$maxWidth,
$maxHeight,
$scale,
$inflate,
$quality,
$source,
$transparent,
$options,
$thumb;
/**
* List of accepted image types based on MIME
* descriptions that this adapter supports
*/
protected $imgTypes = array(
'image/jpeg',
'image/pjpeg',
'image/png',
'image/gif',
'image/webp',
);
/**
* Stores function names for each image type
*/
protected $imgLoaders = array(
'image/jpeg' => 'imagecreatefromjpeg',
'image/pjpeg' => 'imagecreatefromjpeg',
'image/png' => 'imagecreatefrompng',
'image/gif' => 'imagecreatefromgif',
'image/webp' => 'imagecreatefromwebp',
);
/**
* Stores function names for each image type
*/
protected $imgCreators = array(
'image/jpeg' => 'imagejpeg',
'image/pjpeg' => 'imagejpeg',
'image/png' => 'imagepng',
'image/gif' => 'imagegif',
'image/webp' => 'imagewebp',
);
protected static $imageTypeSupported = [];
public static function hasImageTypeSupport($imageType)
{
if (!isset(self::$imageTypeSupported[$imageType]))
{
if (!extension_loaded('gd'))
{
self::$imageTypeSupported[$imageType] = false;
return false;
}
$info = gd_info();
if ('WEBP' == $imageType)
{
$imageType = 'WebP';
}
self::$imageTypeSupported[$imageType] = isset($info[$imageType . ' Support']) && $info[$imageType . ' Support'] ||
isset($info[$imageType . ' Read Support']) && $info[$imageType . ' Read Support'] &&
isset($info[$imageType . ' Create Support']) && $info[$imageType . ' Create Support'];
}
return self::$imageTypeSupported[$imageType];
}
public function __construct($maxWidth, $maxHeight, $scale, $inflate, $quality, $options)
{
if (!extension_loaded('gd'))
{
throw new Exception('GD not enabled. Check your php.ini file.');
}
$this->maxWidth = $maxWidth;
$this->maxHeight = $maxHeight;
$this->scale = $scale;
$this->inflate = $inflate;
$this->quality = $quality;
$this->options = $options;
}
public function loadFile($thumbnail, $image, $auto_crop = false)
{
$this->transparent = false;
$imgData = @GetImageSize($image);
if (!$imgData)
{
throw new Exception(sprintf('Could not load image %s', $image));
}
if (in_array($imgData['mime'], $this->imgTypes))
{
$loader = $this->imgLoaders[$imgData['mime']];
if (!function_exists($loader))
{
throw new Exception(sprintf('Function %s not available. Please enable the GD extension.', $loader));
}
$this->source = $loader($image);
$this->sourceWidth = $imgData[0];
$this->sourceHeight = $imgData[1];
$this->sourceMime = $imgData['mime'];
$thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate, $auto_crop);
$this->thumb = imagecreatetruecolor($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight());
if ($imgData[0] == $this->maxWidth && $imgData[1] == $this->maxHeight)
{
$this->thumb = $this->source;
}
else
{
$mime_type = $this->getSourceMime();
if ($mime_type == 'image/png' || $mime_type == 'image/gif')
{
$this->preserveTransparency($this->thumb, $this->source);
}
if ($mime_type == 'image/png')
{
$this->preserveAlpha($this->thumb);
}
if ($auto_crop && is_array($auto_crop))
{
$w = $auto_crop[2] - $auto_crop[0];
$h = $auto_crop[3] - $auto_crop[1];
imagecopyresampled($this->thumb, $this->source, 0, 0, $auto_crop[0], $auto_crop[1], $thumbnail->getThumbWidth(), $thumbnail->getThumbHeight(), $w, $h);
$this->sharpenImage($this->thumb);
}
else
{
imagecopyresampled($this->thumb, $this->source, 0, 0, 0, 0, $thumbnail->getThumbWidth(), $thumbnail->getThumbHeight(), $imgData[0], $imgData[1]);
if ($auto_crop)
{
$this->freeSource();
$this->thumb = $this->cropImage($this->thumb);
$thumbnail->setThumbWidth(imagesx($this->thumb));
$thumbnail->setThumbHeight(imagesy($this->thumb));
}
$this->sharpenImage($this->thumb);
}
}
return true;
}
else
{
throw new Exception(sprintf('Image MIME type %s not supported', $imgData['mime']));
}
}
protected function sharpenImage($image, $strength = 0.2)
{
$mime_type = $this->getSourceMime();
if (function_exists('imageconvolution') && $mime_type != 'image/png' && $mime_type != 'image/gif') {
// black pixel bug fix
$pixel_fix = imagecolorat($image, 0, 0);
$matrix = array(
array(0, -$strength, 0),
array(-$strength, 8*$strength+1, -$strength),
array(0, -$strength, 0),
);
$divisor = array_sum(array_map('array_sum', $matrix));
imageconvolution($image, $matrix, $divisor, 0);
// black pixel bug fix
imagesetpixel($image, 0, 0, $pixel_fix);
}
}
protected function cropImage($source)
{
$sw = imagesx($source);
$sh = imagesy($source);
$sx = 0;
$sy = 0;
$dw = $sw;
$dh = $sh;
if ($sw > $this->maxWidth)
{
$sx = round(($sw - $this->maxWidth) / 2);
$dw = $sw - $sx * 2;
}
elseif ($sh > $this->maxHeight)
{
$sy = round(($sh - $this->maxHeight) / 2);
$dh = $sh - $sy * 2;
}
$croped = imagecreatetruecolor($dw, $dh);
$mime_type = $this->getSourceMime();
if ($mime_type == 'image/png' || $mime_type == 'image/gif')
{
$this->preserveTransparency($croped, $source);
}
if ($mime_type == 'image/png')
{
$this->preserveAlpha($croped);
}
imagecopyresampled($croped, $source, 0, 0, $sx, $sy, $dw, $dh, $dw, $dh);
imagedestroy($source);
return $croped;
}
public function loadData($thumbnail, $image, $mime)
{
if (in_array($mime, $this->imgTypes))
{
$this->source = imagecreatefromstring($image);
$this->sourceWidth = imagesx($this->source);
$this->sourceHeight = imagesy($this->source);
$this->sourceMime = $mime;
$thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate);
$this->thumb = imagecreatetruecolor($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight());
if ($this->sourceWidth == $this->maxWidth && $this->sourceHeight == $this->maxHeight)
{
$this->thumb = $this->source;
}
else
{
imagecopyresampled($this->thumb, $this->source, 0, 0, 0, 0, $thumbnail->getThumbWidth(), $thumbnail->getThumbHeight(), $this->sourceWidth, $this->sourceHeight);
}
return true;
}
else
{
throw new Exception(sprintf('Image MIME type %s not supported', $mime));
}
}
protected function preserveTransparency($thumb, $source)
{
$trans_index = imagecolortransparent($source);
if ($trans_index >= 0 && $trans_index < imagecolorstotal($source))
{
$this->transparent = true;
$trans_color = imagecolorsforindex($source, $trans_index);
$trans_index = imagecolorallocate($thumb, $trans_color['red'], $trans_color['green'], $trans_color['blue']);
imagefill($thumb, 0, 0, $trans_index);
imagecolortransparent($thumb, $trans_index);
}
else
{
$this->transparent = false;
}
}
protected function preserveAlpha($source)
{
imagealphablending($source, false);
imagesavealpha($source, true);
}
protected function disableAlpha($source)
{
imagealphablending($source, true);
imagesavealpha($source, false);
}
public function save($thumbnail, $thumbDest, $targetMime = null)
{
imageinterlace($this->thumb, true);
if ($targetMime !== null)
{
$creator = $this->imgCreators[$targetMime];
}
else
{
$creator = $this->imgCreators[$thumbnail->getMime()];
}
if (self::hasImageTypeSupport('webp') && isset($this->options['enable_webp_format']) && $this->options['enable_webp_format'])
{
$creator = 'imagewebp';
}
if ($creator == 'imagejpeg')
{
imagejpeg($this->thumb, $thumbDest, $this->quality);
}
else
{
$creator($this->thumb, $thumbDest);
}
}
public function toString($thumbnail, $targetMime = null)
{
if ($targetMime !== null)
{
$creator = $this->imgCreators[$targetMime];
}
else
{
$creator = $this->imgCreators[$thumbnail->getMime()];
}
ob_start();
if ($creator != 'imagegif' && $creator != 'imagepng')
{
$creator($this->thumb, null, $this->quality);
}
else
{
$creator($this->thumb);
}
return ob_get_clean();
}
public function freeSource()
{
if (is_resource($this->source))
{
imagedestroy($this->source);
}
}
public function freeThumb()
{
if (is_resource($this->thumb))
{
imagedestroy($this->thumb);
}
}
public function getSourceMime()
{
return $this->sourceMime;
}
}

View File

@@ -0,0 +1,340 @@
<?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.
*/
/**
* sfImageMagickAdapter provides a mechanism for creating thumbnail images.
* @see http://www.imagemagick.org
*
* @package sfThumbnailPlugin
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Benjamin Meynell <bmeynell@colorado.edu>
*/
class sfImagickAdapter
{
protected
$sourceWidth,
$sourceHeight,
$sourceMime,
$maxWidth,
$maxHeight,
$scale,
$inflate,
$quality,
$options,
$watermark;
/**
* Imagick Instance
*
* @var Imagick
*/
protected $imagick;
protected static $textPosition = array(
'top' => Imagick::GRAVITY_NORTH,
'left' => Imagick::GRAVITY_WEST,
'middle' => Imagick::GRAVITY_CENTER,
'right' => Imagick::GRAVITY_EAST,
'bottom' => Imagick::GRAVITY_SOUTH,
'diagonal_up' => Imagick::GRAVITY_CENTER,
'diagonal_down' => Imagick::GRAVITY_CENTER,
);
protected static $textAlpha = array(
32 => 0.75,
64 => 0.5,
96 => 0.25,
);
protected static $imageTypeSupported = [];
public static function hasImageTypeSupport($imageType)
{
if (!isset(self::$imageTypeSupported[$imageType]))
{
self::$imageTypeSupported[$imageType] = class_exists('Imagick', false) && !empty(Imagick::queryFormats($imageType));
}
return self::$imageTypeSupported[$imageType];
}
public function __construct($maxWidth, $maxHeight, $scale, $inflate, $quality, $options)
{
$this->maxWidth = $maxWidth;
$this->maxHeight = $maxHeight;
$this->scale = $scale;
$this->inflate = $inflate;
$this->quality = $quality;
$this->options = $options;
}
public function toString($thumbnail, $targetMime = null)
{
return $this->imagick->getImageBlob();
}
public function setWatermarkText($text, $size = null, $position = 'down', $color = '#000', $alpha = 0, $font = null)
{
$this->watermark = array(
'text' => trim($text),
'color' => $color,
'alpha' => $alpha,
'position' => $position,
'size' => !$size ? 72 : $size,
'font' => sfConfig::get('sf_data_dir').'/fonts/'.$font,
);
}
public function loadFile($thumbnail, $image, $auto_crop = false)
{
$this->imagick = new Imagick($image);
// if (is_callable(array($this->imagick, 'adaptiveSharpenImage')))
{
// $this->imagick->adaptiveSharpenImage(2,1);
}
$this->fixOrientation();
if (defined('Imagick::RESOURCETYPE_THREAD'))
{
$this->imagick->setResourceLimit(Imagick::RESOURCETYPE_THREAD, 1);
}
$this->sourceWidth = $this->imagick->getImageWidth();
$this->sourceHeight = $this->imagick->getImageHeight();
$this->sourceMime = $this->imagick->getImageMimeType();
$thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate, $auto_crop);
if ($this->sourceWidth > $this->maxWidth || $this->sourceHeight > $this->maxHeight)
{
if ($auto_crop && is_array($auto_crop))
{
$w = $auto_crop[2] - $auto_crop[0];
$h = $auto_crop[3] - $auto_crop[1];
$this->imagick->cropImage($w, $h, $auto_crop[0], $auto_crop[1]);
$this->resizeImage($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight());
$thumbnail->setThumbWidth($this->imagick->getImageWidth());
$thumbnail->setThumbHeight($this->imagick->getImageHeight());
}
else
{
$this->resizeImage($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight());
if ($auto_crop)
{
$this->imagick->cropImage($this->maxWidth, $this->maxHeight, ($thumbnail->getThumbWidth() - $this->maxWidth) / 2, ($thumbnail->getThumbHeight() - $this->maxHeight) / 2);
}
$thumbnail->setThumbWidth($this->imagick->getImageWidth());
$thumbnail->setThumbHeight($this->imagick->getImageHeight());
}
$this->imagick->setImagePage($this->imagick->getImageWidth(), $this->imagick->getImageHeight(), 0, 0);
}
if ($this->watermark && !empty($this->watermark['text']))
{
$fontSize = $this->watermark['size'];
$color = $this->watermark['color'];
if (is_array($this->watermark['color']))
{
$color = new ImagickPixel(sprintf('rgb(%s, %s, %s)', $this->watermark['color'][0], $this->watermark['color'][1], $this->watermark['color'][2]));
}
else
{
$color = new ImagickPixel('#'.$this->watermark['color']);
}
$draw = new ImagickDraw();
$draw->setFont($this->watermark['font']);
$draw->setFontSize($fontSize);
$draw->setGravity(self::$textPosition[$this->watermark['position']]);
$draw->setTextEncoding('UTF-8');
$draw->setFillColor($color);
if ($this->watermark['alpha'])
{
$draw->setFillOpacity(self::$textAlpha[$this->watermark['alpha']]);
}
$angle = 0;
$x = 0;
$y = 0;
$padding = 2;
$paddingX = $thumbnail->getThumbWidth() * ($padding / 100);
$paddingY = $thumbnail->getThumbHeight() * ($padding / 100);
$maxTextWidth = $thumbnail->getThumbWidth() - $paddingX;
$maxTextHeight = $thumbnail->getThumbHeight() - $paddingY;
switch ($this->watermark['position'])
{
case 'diagonal_up':
$angle = -45;
break;
case 'diagonal_down':
$angle = 45;
break;
case 'right':
$angle = 90;
$maxTextWidth = $thumbnail->getThumbHeight() - $paddingY;
$maxTextHeight = $thumbnail->getThumbWidth() - $paddingX;
break;
case 'left':
$angle = -90;
$maxTextWidth = $thumbnail->getThumbHeight() - $paddingY;
$maxTextHeight = $thumbnail->getThumbWidth() - $paddingX;
break;
case 'top':
case 'bottom':
$maxTextWidth = $thumbnail->getThumbWidth() - $paddingX * 2;
$y = $paddingY;
break;
}
do
{
$fontSize -= 4;
$draw->setFontSize($fontSize);
$metrics = $this->imagick->queryFontMetrics($draw, $this->watermark['text']);
} while (!$metrics || $metrics['textWidth'] > $maxTextWidth || $metrics['textHeight'] > $maxTextHeight);
if ($angle == -90)
{
$y = ($metrics['textHeight'] + $paddingY) / 2;
$x = -$metrics['textWidth'] / 2;
}
elseif ($angle == 90)
{
$y = -($metrics['textHeight'] + $paddingY) / 2;
$x = $metrics['textWidth'] / 2;
}
$draw->rotate($angle);
$draw->annotation($x, $y, $this->watermark['text']);
$this->imagick->drawImage($draw);
}
}
public function loadData($thumbnail, $image, $mime)
{
throw new Exception('This function is not yet implemented. Try a different adapter.');
}
public function save($thumbnail, $thumbDest, $targetMime = null)
{
if (sfThumbnail::hasImageTypeSupport('webp') && isset($this->options['enable_webp_format']) && $this->options['enable_webp_format'])
{
$this->imagick->setFormat('webp');
$this->imagick->setImageCompressionQuality($this->quality);
}
elseif ($this->sourceMime != 'image/png')
{
$this->imagick->setImageCompressionQuality($this->quality);
}
else
{
$this->imagick->setFormat('PNG');
$this->imagick->setImageCompression(Imagick::COMPRESSION_NO);
$this->imagick->setImageCompressionQuality(100);
}
$this->imagick->writeImage($thumbDest);
}
public function freeSource()
{
if ($this->imagick)
{
$this->imagick->clear();
}
}
public function freeThumb()
{
return true;
}
public function getSourceMime()
{
return $this->sourceMime;
}
protected function resizeImage($width, $height)
{
if (isset($this->options['high_quality_images']) && $this->options['high_quality_images'])
{
$this->imagick->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 0.9);
}
else
{
$this->imagick->scaleImage($width, $height);
}
}
protected function fixOrientation()
{
if (isset($this->options['respect_exif_orientation']) && $this->options['respect_exif_orientation'])
{
switch ($this->imagick->getImageOrientation())
{
case \Imagick::ORIENTATION_UNDEFINED:
case \Imagick::ORIENTATION_TOPLEFT:
// We assume normal orientation
break;
case \Imagick::ORIENTATION_TOPRIGHT:
$this->imagick->flopImage();
break;
case \Imagick::ORIENTATION_BOTTOMRIGHT:
$this->imagick->rotateImage('#000', 180);
break;
case \Imagick::ORIENTATION_BOTTOMLEFT:
$this->imagick->rotateImage('#000', 180);
$this->imagick->flopImage();
break;
case \Imagick::ORIENTATION_LEFTTOP:
$this->imagick->rotateImage('#000', 90);
$this->imagick->flopImage();
break;
case \Imagick::ORIENTATION_RIGHTTOP:
$this->imagick->rotateImage('#000', 90);
break;
case \Imagick::ORIENTATION_RIGHTBOTTOM:
$this->imagick->rotateImage('#000', -90);
$this->imagick->flopImage();
break;
case \Imagick::ORIENTATION_LEFTBOTTOM:
$this->imagick->rotateImage('#000', -90);
break;
}
}
$this->imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT);
$this->imagick->setImagePage($this->imagick->getImageWidth(), $this->imagick->getImageHeight(), 0, 0);
}
}

View File

@@ -0,0 +1,426 @@
<?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
{
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* @package sfThumbnailPlugin
*/
/**
* Rozszerzenie pluginu stThumbnailPlugin
*
* @package sfThumbnailPlugin
* @author Marcin Butlak <marcin.butlak@sote.pl>
* @copyright SOTE
* @license SOTE
* @version $Id: stGDAdapter.class.php 3382 2008-12-16 10:03:52Z marcin $
*/
class stGDAdapter extends sfGDAdapter
{
protected $watermarkText = false, $watermarkColor, $watermarkAlpha, $watermarkPosition, $watermarkSize, $watermarkFont = 'arial.ttf';
/**
* @todo dodac opis phpdoc
*/
public function setWatermarkText($text, $size = null, $position = 'down', $color = '#000', $alpha = 0, $font = null)
{
$this->watermarkText = $text;
$this->watermarkColor = $color;
$this->watermarkAlpha = $alpha;
$this->watermarkPosition = $position;
$this->watermarkSize = !$size ? 72 : $size;
if ($font)
{
$this->watermarkFont = $font;
}
}
/**
* @todo dodać opis phpdoc
*/
public function loadFile($thumbnail, $image, $auto_crop = null)
{
if (parent::loadFile($thumbnail, $image, $auto_crop))
{
if ($this->watermarkText)
{
$this->disableAlpha($this->thumb);
$font_file = sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.$this->watermarkFont;
$rgb = $this->watermarkColor;
$color = imagecolorallocatealpha($this->thumb, $rgb[0], $rgb[1], $rgb[2], $this->watermarkAlpha);
$metrics = $this->acquireTextMetrics($thumbnail, $font_file);
imagettftext($this->thumb, $metrics['size'], $metrics['angle'], $metrics['x_offset'], $metrics['y_offset'], $color, $font_file, $this->watermarkText);
$this->preserveAlpha($this->thumb);
}
}
}
protected function acquireTextMetrics($thumbnail, $font_file)
{
$thumb_width = $thumbnail->getThumbWidth();
$thumb_height = $thumbnail->getThumbHeight();
$position = sfThumbnail::getWatermarkPosition($this->watermarkPosition);
$angle = 0;
switch ($this->watermarkPosition)
{
case 'top':
list($tb, $watermark_width, $watermark_height, $watermark_size) = $this->calculateTextMetrics(0, $this->watermarkSize, $thumb_width, $thumb_height, $font_file);
$x_offset = abs($watermark_width - $thumb_width) / 2;
$y_offset = abs($tb[7]) + $thumb_height * 0.01;
break;
case 'bottom':
list($tb, $watermark_width, $watermark_height, $watermark_size) = $this->calculateTextMetrics(0, $this->watermarkSize, $thumb_width, $thumb_height, $font_file);
$x_offset = abs($watermark_width - $thumb_width) / 2;
$y_offset = $thumb_height - $tb[1] - $thumb_height * 0.01;
break;
case 'left':
$angle = -90;
list($tb, $watermark_height, $watermark_width, $watermark_size) = $this->calculateTextMetrics(0, $this->watermarkSize, $thumb_height, $thumb_width, $font_file);
$x_offset = abs($tb[1]) + $thumb_width * 0.01;
$y_offset = abs($watermark_height - $thumb_height) / 2;
break;
case 'right':
$angle = 90;
list($tb, $watermark_height, $watermark_width, $watermark_size) = $this->calculateTextMetrics(0, $this->watermarkSize, $thumb_height, $thumb_width, $font_file);
$x_offset = $thumb_width - abs($tb[1]) - $thumb_width * 0.01;
$y_offset = abs($watermark_height + $thumb_height) / 2;
break;
case 'middle':
list($tb, $watermark_width, $watermark_height, $watermark_size) = $this->calculateTextMetrics(0, $this->watermarkSize, $thumb_width, $thumb_height, $font_file);
$x_offset = abs($watermark_width - $thumb_width) / 2;
$y_offset = abs($watermark_height + $thumb_height) / 2 - $tb[1];
break;
case 'diagonal_up':
$angle = 45;
list($tb, $watermark_width, $watermark_height, $watermark_size) = $this->calculateTextMetrics($angle, $this->watermarkSize, $thumb_width, $thumb_height, $font_file);
$x_offset = abs($watermark_width - $thumb_width) / 2;
$y_offset = abs($watermark_height + $thumb_height) / 2;
break;
case 'diagonal_down':
$angle = -45;
list($tb, $watermark_width, $watermark_height, $watermark_size) = $this->calculateTextMetrics(45, $this->watermarkSize, $thumb_width, $thumb_height, $font_file);
$x_offset = abs($watermark_height - $thumb_width) / 2 + $tb[0];
$y_offset = abs($watermark_width - $thumb_height) / 2;
break;
}
return array('size' => $watermark_size, 'x_offset' => $x_offset, 'y_offset' => $y_offset, 'angle' => $angle, 'width' => $watermark_width, 'height' => $watermark_height);
}
protected function calculateTextMetrics($angle, $size, $thumb_width, $thumb_height, $font_file)
{
do
{
$tb = imagettfbbox($size, $angle, $font_file, $this->watermarkText);
$watermark_width = abs($tb[4]) + abs($tb[0]);
$watermark_height = abs($tb[3]) + abs($tb[7]);
$size -= 2;
}
while (($watermark_height * 1.2 > $thumb_height || $watermark_width * 1.2 > $thumb_width) && $size >= 2);
return array($tb, $watermark_width, $watermark_height, $size + 2);
}
}