Created
September 13, 2011 12:51
-
-
Save anonymous/1213736 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Magento | |
* | |
* NOTICE OF LICENSE | |
* | |
* This source file is subject to the Open Software License (OSL 3.0) | |
* that is bundled with this package in the file LICENSE.txt. | |
* It is also available through the world-wide-web at this URL: | |
* http://opensource.org/licenses/osl-3.0.php | |
* If you did not receive a copy of the license and are unable to | |
* obtain it through the world-wide-web, please send an email | |
* to license@magentocommerce.com so we can send you a copy immediately. | |
* | |
* DISCLAIMER | |
* | |
* Do not edit or add to this file if you wish to upgrade Magento to newer | |
* versions in the future. If you wish to customize Magento for your | |
* needs please refer to http://www.magentocommerce.com for more information. | |
* | |
* @category Varien | |
* @package Varien_Image | |
* @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com) | |
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) | |
*/ | |
class Varien_Image_Adapter_Gd2 extends Varien_Image_Adapter_Abstract | |
{ | |
protected $_requiredExtensions = Array("gd"); | |
private static $_callbacks = array( | |
IMAGETYPE_GIF => array('output' => 'imagegif', 'create' => 'imagecreatefromgif'), | |
IMAGETYPE_JPEG => array('output' => 'imagejpeg', 'create' => 'imagecreatefromjpeg'), | |
IMAGETYPE_PNG => array('output' => 'imagepng', 'create' => 'imagecreatefrompng'), | |
IMAGETYPE_XBM => array('output' => 'imagexbm', 'create' => 'imagecreatefromxbm'), | |
IMAGETYPE_WBMP => array('output' => 'imagewbmp', 'create' => 'imagecreatefromxbm'), | |
); | |
public function open($filename) | |
{ | |
$this->_fileName = $filename; | |
$this->getMimeType(); | |
$this->_getFileAttributes(); | |
$this->_imageHandler = call_user_func($this->_getCallback('create'), $this->_fileName); | |
} | |
public function save($destination=null, $newName=null) | |
{ | |
$fileName = ( !isset($destination) ) ? $this->_fileName : $destination; | |
if( isset($destination) && isset($newName) ) { | |
$fileName = $destination . "/" . $newName; | |
} elseif( isset($destination) && !isset($newName) ) { | |
$info = pathinfo($destination); | |
$fileName = $destination; | |
$destination = $info['dirname']; | |
} elseif( !isset($destination) && isset($newName) ) { | |
$fileName = $this->_fileSrcPath . "/" . $newName; | |
} else { | |
$fileName = $this->_fileSrcPath . $this->_fileSrcName; | |
} | |
$destinationDir = ( isset($destination) ) ? $destination : $this->_fileSrcPath; | |
if( !is_writable($destinationDir) ) { | |
try { | |
$io = new Varien_Io_File(); | |
$io->mkdir($destination); | |
} catch (Exception $e) { | |
throw new Exception("Unable to write file into directory '{$destinationDir}'. Access forbidden."); | |
} | |
} | |
// keep alpha transparency | |
$isAlpha = false; | |
$this->_getTransparency($this->_imageHandler, $this->_fileType, $isAlpha); | |
if ($isAlpha) { | |
$this->_fillBackgroundColor($this->_imageHandler); | |
} | |
$functionParameters = array(); | |
$functionParameters[] = $this->_imageHandler; | |
$functionParameters[] = $fileName; | |
// set quality param for JPG file type | |
if (!is_null($this->quality()) && $this->_fileType == IMAGETYPE_JPEG) | |
{ | |
$functionParameters[] = $this->quality(); | |
} | |
// set quality param for PNG file type | |
if (!is_null($this->quality()) && $this->_fileType == IMAGETYPE_PNG) | |
{ | |
$quality = round(($this->quality() / 100) * 10); | |
if ($quality < 1) { | |
$quality = 1; | |
} elseif ($quality > 10) { | |
$quality = 10; | |
} | |
$quality = 10 - $quality; | |
$functionParameters[] = $quality; | |
} | |
call_user_func_array($this->_getCallback('output'), $functionParameters); | |
} | |
public function display() | |
{ | |
header("Content-type: ".$this->getMimeType()); | |
call_user_func($this->_getCallback('output'), $this->_imageHandler); | |
} | |
/** | |
* Obtain function name, basing on image type and callback type | |
* | |
* @param string $callbackType | |
* @param int $fileType | |
* @return string | |
* @throws Exception | |
*/ | |
private function _getCallback($callbackType, $fileType = null, $unsupportedText = 'Unsupported image format.') | |
{ | |
if (null === $fileType) { | |
$fileType = $this->_fileType; | |
} | |
if (empty(self::$_callbacks[$fileType])) { | |
throw new Exception($unsupportedText); | |
} | |
if (empty(self::$_callbacks[$fileType][$callbackType])) { | |
throw new Exception('Callback not found.'); | |
} | |
return self::$_callbacks[$fileType][$callbackType]; | |
} | |
private function _fillBackgroundColor(&$imageResourceTo, $w, $h) | |
{ | |
// try to keep transparency, if any | |
if ($this->_keepTransparency) { | |
$isAlpha = false; | |
$transparentIndex = $this->_getTransparency($this->_imageHandler, $this->_fileType, $isAlpha); | |
try { | |
// fill truecolor png with alpha transparency | |
if ($isAlpha) { | |
if (!imagealphablending($imageResourceTo, false)) { | |
throw new Exception('Failed to set alpha blending for PNG image.'); | |
} | |
$transparentAlphaColor = imagecolorallocatealpha($imageResourceTo, 0, 0, 0, 127); | |
if (false === $transparentAlphaColor) { | |
throw new Exception('Failed to allocate alpha transparency for PNG image.'); | |
} | |
if (!imagefill($imageResourceTo, 0, 0, $transparentAlphaColor)) { | |
throw new Exception('Failed to fill PNG image with alpha transparency.'); | |
} | |
if (!imagesavealpha($imageResourceTo, true)) { | |
throw new Exception('Failed to save alpha transparency into PNG image.'); | |
} | |
return $transparentAlphaColor; | |
} | |
// fill image with indexed non-alpha transparency | |
elseif (false !== $transparentIndex) { | |
list($r, $g, $b) = array_values(imagecolorsforindex($this->_imageHandler, $transparentIndex)); | |
$transparentColor = imagecolorallocate($imageResourceTo, $r, $g, $b); | |
if (false === $transparentColor) { | |
throw new Exception('Failed to allocate transparent color for image.'); | |
} | |
if (!imagefill($imageResourceTo, 0, 0, $transparentColor)) { | |
throw new Exception('Failed to fill image with transparency.'); | |
} | |
imagecolortransparent($imageResourceTo, $transparentColor); | |
return $transparentColor; | |
} | |
} | |
catch (Exception $e) { | |
// fallback to default background color | |
} | |
} | |
list($r, $g, $b) = $this->_backgroundColor; | |
$color = imagecolorallocate($imageResourceTo, $r, $g, $b); | |
if (!imagefilledrectangle($imageResourceTo, 0, 0, $w, $h, $color)) { | |
throw new Exception("Failed to fill image background with color {$r} {$g} {$b}."); | |
} | |
return $color; | |
} | |
/** | |
* Gives true for a PNG with alpha, false otherwise | |
* | |
* @param string $fileName | |
* @return boolean | |
*/ | |
public function checkAlpha($fileName) | |
{ | |
return ((ord(file_get_contents($fileName, false, null, 25, 1)) & 6) & 4) == 4; | |
} | |
private function _getTransparency($imageResource, $fileType, &$isAlpha = false, &$isTrueColor = false) | |
{ | |
$isAlpha = false; | |
$isTrueColor = false; | |
// assume that transparency is supported by gif/png only | |
if ((IMAGETYPE_GIF === $fileType) || (IMAGETYPE_PNG === $fileType)) { | |
// check for specific transparent color | |
$transparentIndex = imagecolortransparent($imageResource); | |
if ($transparentIndex >= 0) { | |
return $transparentIndex; | |
} | |
// assume that truecolor PNG has transparency | |
elseif (IMAGETYPE_PNG === $fileType) { | |
$isAlpha = $this->checkAlpha($this->_fileName); | |
$isTrueColor = true; | |
return $transparentIndex; // -1 | |
} | |
} | |
if (IMAGETYPE_JPEG === $fileType) { | |
$isTrueColor = true; | |
} | |
return false; | |
} | |
/** | |
* Change the image size | |
* | |
* @param int $frameWidth | |
* @param int $frameHeight | |
*/ | |
public function resize($frameWidth = null, $frameHeight = null) | |
{ | |
if (empty($frameWidth) && empty($frameHeight)) { | |
throw new Exception('Invalid image dimensions.'); | |
} | |
// calculate lacking dimension | |
if (!$this->_keepFrame) { | |
if (null === $frameWidth) { | |
$frameWidth = round($frameHeight * ($this->_imageSrcWidth / $this->_imageSrcHeight)); | |
} | |
elseif (null === $frameHeight) { | |
$frameHeight = round($frameWidth * ($this->_imageSrcHeight / $this->_imageSrcWidth)); | |
} | |
} | |
else { | |
if (null === $frameWidth) { | |
$frameWidth = $frameHeight; | |
} | |
elseif (null === $frameHeight) { | |
$frameHeight = $frameWidth; | |
} | |
} | |
// define coordinates of image inside new frame | |
$srcX = 0; | |
$srcY = 0; | |
$dstX = 0; | |
$dstY = 0; | |
$dstWidth = $frameWidth; | |
$dstHeight = $frameHeight; | |
if ($this->_keepAspectRatio) { | |
// do not make picture bigger, than it is, if required | |
if ($this->_constrainOnly) { | |
if (($frameWidth >= $this->_imageSrcWidth) && ($frameHeight >= $this->_imageSrcHeight)) { | |
$dstWidth = $this->_imageSrcWidth; | |
$dstHeight = $this->_imageSrcHeight; | |
} | |
} | |
// keep aspect ratio | |
if ($this->_imageSrcWidth / $this->_imageSrcHeight >= $frameWidth / $frameHeight) { | |
$dstHeight = round(($dstWidth / $this->_imageSrcWidth) * $this->_imageSrcHeight); | |
} else { | |
$dstWidth = round(($dstHeight / $this->_imageSrcHeight) * $this->_imageSrcWidth); | |
} | |
} | |
// define position in center (TODO: add positions option) | |
$dstY = round(($frameHeight - $dstHeight) / 2); | |
$dstX = round(($frameWidth - $dstWidth) / 2); | |
// get rid of frame (fallback to zero position coordinates) | |
if (!$this->_keepFrame) { | |
$frameWidth = $dstWidth; | |
$frameHeight = $dstHeight; | |
$dstY = 0; | |
$dstX = 0; | |
} | |
// create new image | |
$isAlpha = false; | |
$isTrueColor = false; | |
$this->_getTransparency($this->_imageHandler, $this->_fileType, $isAlpha, $isTrueColor); | |
if ($isTrueColor) { | |
$newImage = imagecreatetruecolor($frameWidth, $frameHeight); | |
} | |
else { | |
$newImage = imagecreate($frameWidth, $frameHeight); | |
} | |
// fill new image with required color | |
$this->_fillBackgroundColor($newImage, $frameWidth, $frameHeight); | |
// resample source image and copy it into new frame | |
imagecopyresampled($newImage, $this->_imageHandler, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $this->_imageSrcWidth, $this->_imageSrcHeight); | |
$this->_imageHandler = $newImage; | |
$this->refreshImageDimensions(); | |
} | |
public function rotate($angle) | |
{ | |
/* | |
$isAlpha = false; | |
$backgroundColor = $this->_getTransparency($this->_imageHandler, $this->_fileType, $isAlpha); | |
list($r, $g, $b) = $this->_backgroundColor; | |
if ($isAlpha) { | |
$backgroundColor = imagecolorallocatealpha($this->_imageHandler, 0, 0, 0, 127); | |
} | |
elseif (false === $backgroundColor) { | |
$backgroundColor = imagecolorallocate($this->_imageHandler, $r, $g, $b); | |
} | |
$this->_imageHandler = imagerotate($this->_imageHandler, $angle, $backgroundColor); | |
//*/ | |
$this->_imageHandler = imagerotate($this->_imageHandler, $angle, $this->imageBackgroundColor); | |
$this->refreshImageDimensions(); | |
} | |
public function watermark($watermarkImage, $positionX=0, $positionY=0, $watermarkImageOpacity=30, $repeat=false) | |
{ | |
list($watermarkSrcWidth, $watermarkSrcHeight, $watermarkFileType, ) = getimagesize($watermarkImage); | |
$this->_getFileAttributes(); | |
$watermark = call_user_func($this->_getCallback('create', $watermarkFileType, 'Unsupported watermark image format.'), $watermarkImage); | |
$merged = false; | |
if( $this->getWatermarkWidth() && $this->getWatermarkHeigth() && ($this->getWatermarkPosition() != self::POSITION_STRETCH) ) { | |
$newWatermark = imagecreatetruecolor($this->getWatermarkWidth(), $this->getWatermarkHeigth()); | |
imagealphablending($newWatermark, false); | |
$col = imagecolorallocate($newWatermark, 255, 255, 255); | |
imagecolortransparent($newWatermark, $col); | |
imagefilledrectangle($newWatermark, 0, 0, $this->getWatermarkWidth(), $this->getWatermarkHeigth(), $col); | |
imagealphablending($newWatermark, true); | |
imageSaveAlpha($newWatermark, true); | |
imagecopyresampled($newWatermark, $watermark, 0, 0, 0, 0, $this->getWatermarkWidth(), $this->getWatermarkHeigth(), imagesx($watermark), imagesy($watermark)); | |
$watermark = $newWatermark; | |
} | |
if( $this->getWatermarkPosition() == self::POSITION_TILE ) { | |
$repeat = true; | |
} elseif( $this->getWatermarkPosition() == self::POSITION_STRETCH ) { | |
$newWatermark = imagecreatetruecolor($this->_imageSrcWidth, $this->_imageSrcHeight); | |
imagealphablending($newWatermark, false); | |
$col = imagecolorallocate($newWatermark, 255, 255, 255); | |
imagecolortransparent($newWatermark, $col); | |
imagefilledrectangle($newWatermark, 0, 0, $this->_imageSrcWidth, $this->_imageSrcHeight, $col); | |
imagealphablending($newWatermark, true); | |
imageSaveAlpha($newWatermark, true); | |
imagecopyresampled($newWatermark, $watermark, 0, 0, 0, 0, $this->_imageSrcWidth, $this->_imageSrcHeight, imagesx($watermark), imagesy($watermark)); | |
$watermark = $newWatermark; | |
} elseif( $this->getWatermarkPosition() == self::POSITION_CENTER ) { | |
$positionX = ($this->_imageSrcWidth/2 - imagesx($watermark)/2); | |
$positionY = ($this->_imageSrcHeight/2 - imagesy($watermark)/2); | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} elseif( $this->getWatermarkPosition() == self::POSITION_TOP_RIGHT ) { | |
$positionX = ($this->_imageSrcWidth - imagesx($watermark)); | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} elseif( $this->getWatermarkPosition() == self::POSITION_TOP_LEFT ) { | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} elseif( $this->getWatermarkPosition() == self::POSITION_BOTTOM_RIGHT ) { | |
$positionX = ($this->_imageSrcWidth - imagesx($watermark)); | |
$positionY = ($this->_imageSrcHeight - imagesy($watermark)); | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} elseif( $this->getWatermarkPosition() == self::POSITION_BOTTOM_LEFT ) { | |
$positionY = ($this->_imageSrcHeight - imagesy($watermark)); | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} | |
if( $repeat === false && $merged === false ) { | |
imagecopymerge($this->_imageHandler, $watermark, $positionX, $positionY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
} else { | |
$offsetX = $positionX; | |
$offsetY = $positionY; | |
while( $offsetY <= ($this->_imageSrcHeight+imagesy($watermark)) ) { | |
while( $offsetX <= ($this->_imageSrcWidth+imagesx($watermark)) ) { | |
imagecopymerge($this->_imageHandler, $watermark, $offsetX, $offsetY, 0, 0, imagesx($watermark), imagesy($watermark), $this->getWatermarkImageOpacity()); | |
$offsetX += imagesx($watermark); | |
} | |
$offsetX = $positionX; | |
$offsetY += imagesy($watermark); | |
} | |
} | |
imagedestroy($watermark); | |
$this->refreshImageDimensions(); | |
} | |
public function crop($top=0, $bottom=0, $right=0, $left=0) | |
{ | |
if( $left == 0 && $top == 0 && $right == 0 && $bottom == 0 ) { | |
return; | |
} | |
$newWidth = $this->_imageSrcWidth - $left - $right; | |
$newHeight = $this->_imageSrcHeight - $top - $bottom; | |
$canvas = imagecreatetruecolor($newWidth, $newHeight); | |
if ($this->_fileType == IMAGETYPE_PNG) { | |
$this->_saveAlpha($canvas); | |
} | |
imagecopyresampled($canvas, $this->_imageHandler, $top, $bottom, $right, $left, $this->_imageSrcWidth, $this->_imageSrcHeight, $newWidth, $newHeight); | |
$this->_imageHandler = $canvas; | |
$this->refreshImageDimensions(); | |
} | |
public function checkDependencies() | |
{ | |
foreach( $this->_requiredExtensions as $value ) { | |
if( !extension_loaded($value) ) { | |
throw new Exception("Required PHP extension '{$value}' was not loaded."); | |
} | |
} | |
} | |
private function refreshImageDimensions() | |
{ | |
$this->_imageSrcWidth = imagesx($this->_imageHandler); | |
$this->_imageSrcHeight = imagesy($this->_imageHandler); | |
} | |
function __destruct() | |
{ | |
@imagedestroy($this->_imageHandler); | |
} | |
/* | |
* Fixes saving PNG alpha channel | |
*/ | |
private function _saveAlpha($imageHandler) | |
{ | |
$background = imagecolorallocate($imageHandler, 0, 0, 0); | |
ImageColorTransparent($imageHandler, $background); | |
imagealphablending($imageHandler, false); | |
imagesavealpha($imageHandler, true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 78 calls
$this->_fillBackgroundColor
, but does not pass a width or height, required by the declaration on line 135.