Skip to content

Instantly share code, notes, and snippets.

Created September 13, 2011 12:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/1213736 to your computer and use it in GitHub Desktop.
Save anonymous/1213736 to your computer and use it in GitHub Desktop.
<?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);
}
}
@philbirnie
Copy link

Line 78 calls $this->_fillBackgroundColor, but does not pass a width or height, required by the declaration on line 135.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment