Current File : /mnt/web608/e1/80/59722480/htdocs/.cm4all/include/ImageProcessorImpl.php |
<?php
require_once(dirname(__FILE__).DIRECTORY_SEPARATOR."ImageProcessorHelper.php");
require_once(dirname(__FILE__).DIRECTORY_SEPARATOR."config.php");
class MemChecker {
function __construct() {
if(function_exists('ini_get_all')){
$iniData = ini_get_all();
$this->memoryLimitBytes = min(
$this->_getBytes($iniData["memory_limit"]["local_value"]),
$this->_getBytes($iniData["memory_limit"]["global_value"])
);
}else{
$this->memoryLimitBytes = $this->_getBytes(ini_get("memory_limit"));
}
}
function MemChecker() {
self::__construct();
}
function _getBytes($mValue) {
if (!$mValue) {
$mValue = "666M";
}
$mValue = trim($mValue);
if (is_numeric($mValue)) {
$iValue = $mValue;
} else {
$sUnit = strtolower(substr($mValue, -1));
$iValue = (int) substr($mValue, 0, -1);
switch ($sUnit) {
case 'k':
$iValue *= 1024;
case 'm':
$iValue *= 1024;
case 'g':
$iValue *= 1024;
}
}
return $iValue;
}
function _getImageMemUsage($width, $heigth) {
return $width * $heigth * 4 + 1024; # 3 colors * 8 bit + 1 alpha * 8 bit = 32 bit = 4 byte, 1024 byte as security barrier
}
function check($fn, $width, $height, $noAutoError=FALSE) {
$expectedMemUsage = memory_get_usage(TRUE) + $this->_getImageMemUsage($width, $height);
if ($expectedMemUsage > $this->memoryLimitBytes) {
if ($noAutoError) {
return FALSE;
} else {
error_log("Out of memory\n($fn)\nDimensions: $width x $height\nMemory Usage: ". $expectedMemUsage . " > Available Memory: " . $this->memoryLimitBytes);
err("Out of memory\n($fn)\n$width x $height\n" . $expectedMemUsage . " > " . $this->memoryLimitBytes, "413 Request Entity Too Large");
}
}
}
}
class InputImage {
function __construct($imagepath, $filename, $rawtrans) {
$this->imagepath = $imagepath;
$this->_imagepath = md5($this->imagepath);
$this->filename = $filename;
$this->imginfo = @getimagesize($this->imagepath);
$this->transpath = preg_replace("/_|;/", "/", $rawtrans);
$this->suffix = strtolower(substr($this->filename, strrpos($this->filename, ".")));
if (!$this->suffix) {
$this->suffix = ".png";
}
$this->cachedir = ".cache/" . $this->transpath . "/";
$this->im = false;
$this->memChecker = new MemChecker();
$this->transparentColor = FALSE;
$this->transparentIndex = FALSE;
$this->loaded = false;
// preprocess animated gif stuff
$this->_isAnimatedGif = false;
if ($this->imginfo[2] == IMAGETYPE_GIF) {
$this->_isAnimatedGif = __isAnimatedGif($this->imagepath);
if ($this->_isAnimatedGif) {
$this->suffix = ".gif";
}
}
}
function InputImage() {
self::__construct();
}
function createTargetImage($width, $height) {
$this->memChecker->check("createTargetImage", $width, $height);
if (!$this->loaded) {
trigger_error('InputImage->get must be called first!', E_USER_ERROR);
}
$im = @imagecreatetruecolor($width, $height);
if ($this->suffix != ".jpg"
&& $this->suffix != ".jpeg"
&& $this->suffix != ".gif")
{
// Turn off alpha blending and set alpha flag
@imagealphablending($im, false);
@imagesavealpha($im, true);
// Internally another image is created by libgd
$this->memChecker->check("allocateAlpha", $width, $height);
@imagefill($im, 0, 0, @imagecolorallocatealpha($im, 0,0,0,127));
}
if($this->transparentColor) {
imagealphablending($im, false);
$this->transparentIndex = @imagecolorallocatealpha($im, $this->transparentColor['red'], $this->transparentColor['green'], $this->transparentColor['blue'], 127);
$this->memChecker->check("allocateTransparentColor", $width, $height);
@imagefill($im, 0,0, $this->transparentIndex);
}
return $im;
}
function get() {
$this->memChecker->check("get", $this->imginfo[0], $this->imginfo[1]);
if (!$this->im) {
if ($this->imginfo[2] == IMAGETYPE_GIF) {
$this->im = @imagecreatefromgif($this->imagepath) or trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
// store transparent color
$transparent_index = @imagecolortransparent($this->im);
if ($transparent_index != -1) {
$this->transparentColor = @imagecolorsforindex($this->im, $transparent_index);
}
} else if ($this->imginfo[2] == IMAGETYPE_JPEG) {
$this->im = @imagecreatefromjpeg($this->imagepath) or trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
} else if ($this->imginfo[2] == IMAGETYPE_PNG) {
$this->im = @imagecreatefrompng($this->imagepath) or trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
} else if ($this->imginfo[2] == IMAGETYPE_BMP) {
$this->im = @imagecreatefrombmp($this->imagepath) or trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
} else if ($this->imginfo[2] == IMAGETYPE_WBMP) {
$this->im = @imagecreatefromwbmp($this->imagepath) or trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
} else {
trigger_error('Cannot load image: ' . $this->imagepath, E_USER_ERROR);
}
}
$this->loaded = true;
return $this->im;
}
function set($im) {
$this->destroy();
$this->im = $im;
$this->imginfo[0] = imagesx($this->im);
$this->imginfo[1] = imagesy($this->im);
}
function destroy() {
@imagedestroy($this->im);
$this->im = false;
}
function width() {
return $this->imginfo[0];
}
function height() {
return $this->imginfo[1];
}
function writeResult($transformedImage=false) {
if (!$transformedImage) {
$transformedImage = $this->im;
}
$this->prepareCacheFile();
if ($this->suffix == ".jpg" || $this->suffix == ".jpeg") {
@imagejpeg($transformedImage, $this->_cachefile(), 90);
} else if ($this->suffix == ".gif") {
if ($this->transparentIndex) {
// restore transparency
@imagecolortransparent($transformedImage, $this->transparentIndex);
$iwidth = @imagesx($transformedImage);
$iheight = @imagesy($transformedImage);
for ($y = 0 ; $y < $iheight ; $y++) {
for ($x = 0 ; $x < $iwidth ; $x++) {
if (((@imagecolorat($transformedImage, $x, $y) >> 24) & 0x7F) >= 100) {
@imagesetpixel($transformedImage, $x, $y, $this->transparentIndex);
}
}
}
}
@imagetruecolortopalette($transformedImage, true, 255);
@imagesavealpha($transformedImage, false);
@imagegif($transformedImage, $this->_cachefile());
} else {
@imagepng($transformedImage, $this->_cachefile());
}
}
function addContentHeader() {
if ($this->suffix == ".jpg" || $this->suffix == ".jpeg") {
header('Content-Type: image/jpeg');
} else if ($this->suffix == ".gif") {
header('Content-Type: image/gif');
} else {
header('Content-Type: image/png');
}
header("Content-Length: " . filesize($this->_cachefile()));
}
function isAnimatedGif() {
return $this->_isAnimatedGif;
}
function copyThru() {
$this->prepareCacheFile();
copy($this->imagepath, $this->_cachefile());
}
// -----------------------------------------------------------------------------
function writeCached() {
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == filemtime($this->_cachefile()))) {
$this->addContentHeader();
$this->addCacheHeader(304);
} else {
$this->addContentHeader();
$this->addCacheHeader();
fpassthru(fopen($this->_cachefile(), 'rb'));
}
}
function isCached() {
$isCached = file_exists($this->_cachefile()) && filemtime($this->_cachefile()) > filemtime($this->imagepath);
return $isCached;
}
function _cachefile() {
return $this->cachedir . $this->_imagepath . $this->suffix;
}
function prepareCacheFile() {
$cachefile = $this->_cachefile();
$cachedir = preg_replace("/\\\\/", "/", dirname($cachefile));
if (!file_exists($cachedir)) {
mkdir($cachedir, 0755, true);
}
}
function addCacheHeader($code=200) {
$cachefile = $this->_cachefile();
header('Last-Modified: ' . gmdate("D, d M Y H:i:s", filemtime($cachefile)) ." GMT", true, $code);
}
}
class Resize {
function __construct() {}
function Resize() {}
function exec($inputImage, $args, $donotenlarge) {
list($width, $height) = $args;
if ($donotenlarge == true) {
$width = min($inputImage->width(), $width);
$height = min($inputImage->height(), $height);
}
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $width, $height);
}
$im = $inputImage->createTargetImage($width, $height);
if (!$im) {
err("could not create target image", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im, $inputImageRes, 0, 0, 0, 0, $width, $height, $inputImage->width(), $inputImage->height());
$inputImage->set($im);
}
}
class Downsize {
function __construct() {}
function Downsize() {}
function exec($inputImage, $args, $donotenlarge) {
$impl = new Scale();
$impl->exec($inputImage, $args, TRUE);
}
}
class Scale {
function __construct() {}
function Scale() {}
function exec($inputImage, $args, $donotenlarge) {
$scale = 1;
if (count($args) == 1) {
list($scale) = $args;
if ($donotenlarge == true) {
$scale = min($scale, 1);
}
} else {
list($maxWidth, $maxHeight) = $args;
if ($donotenlarge == true) {
$maxWidth = min($inputImage->width(), $maxWidth);
$maxHeight = min($inputImage->height(), $maxHeight);
}
if ($maxWidth != 0 && $maxHeight != 0) {
$scale = getUniformScale($inputImage->width(), $inputImage->height(), $maxWidth, $maxHeight);
} else if ($maxWidth != 0) {
$scale = $maxWidth / $inputImage->width();
} else if ($maxHeight != 0) {
$scale = $maxHeight / $inputImage->height();
}
}
$newWidth = $inputImage->width() * $scale;
$newHeight = $inputImage->height() * $scale;
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $width, $height);
}
$im = $inputImage->createTargetImage($newWidth, $newHeight);
if (!$im) {
err("could not create target image", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im, $inputImageRes, 0, 0, 0, 0, $newWidth, $newHeight, $inputImage->width(), $inputImage->height());
$inputImage->set($im);
}
}
class ScaleCrop {
function __construct() {}
function ScaleCrop() {}
function exec($inputImage, $args, $donotenlarge) {
list($width, $height) = $args;
if ($donotenlarge == true) {
$width = min($inputImage->width(), $width);
$height = min($inputImage->height(), $height);
}
$imageWidth = $inputImage->width();
$imageHeight = $inputImage->height();
$scaleWidth;
$scaleHeight;
if ($imageWidth / $width < $imageHeight / $height) {
$scaleWidth = $width;
$scaleHeight = floor($width / $imageWidth * $imageHeight);
} else {
$scaleWidth = floor($height / $imageHeight * $imageWidth);
$scaleHeight = $height;
}
$x = ($scaleWidth - $width) / 2;
$y = ($scaleHeight - $height) / 2;
$inputImageRes = $inputImage->get();
$im1 = $inputImage->createTargetImage($width, $height);
$im2 = $inputImage->createTargetImage($scaleWidth, $scaleHeight);
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $width, $height);
}
if (!$im1) {
err("could not create target image1", "500 Internal Server Error", $width, $height);
}
if (!$im2) {
err("could not create target image2", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im2, $inputImageRes, 0, 0, 0, 0, $scaleWidth, $scaleHeight, $imageWidth, $imageHeight);
@imagecopyresampled($im1, $im2, 0, 0, $x, $y, $width, $height, $width, $height);
@imagedestroy($im2);
$inputImage->set($im1);
}
}
class Center {
function __construct() {}
function Center() {}
function exec($inputImage, $args, $donotenlarge) {
$imageWidth = $inputImage->width();
$imageHeight = $inputImage->height();
list($width, $height, $color, $maxWidth, $maxHeight) = $args;
if ($donotenlarge == true) {
$width = min($inputImage->width(), $width);
$height = min($inputImage->height(), $height);
}
$scale = 1;
$color = hex2RGB($color);
if ($maxWidth) {
if ($maxHeight) {
if ($maxWidth != 0 && $maxHeight != 0) {
if ($donotenlarge == true) {
$maxWidth = min($inputImage->width(), $maxWidth);
$maxHeight = min($inputImage->height(), $maxHeight);
}
$scale = getUniformScale($imageWidth, $imageHeight, $maxWidth, $maxHeight);
} else if ($maxWidth != 0) {
$scale = $maxWidth / $imageWidth;
} else if ($maxHeight != 0) {
$scale = $maxHeight / $imageHeight;
}
} else {
$scale = $maxWidth;
if ($donotenlarge == true) {
$scale = min($scale, 1);
}
}
}
// Calculate target position of image
$x = floor(($width - floor($scale * $imageWidth)) / 2);
$y = floor(($height - floor($scale * $imageHeight)) / 2);
// step 1: scale
$inputImageRes;
if ($scale != 1) {
$newWidth = $imageWidth * $scale;
$newHeight =$imageHeight * $scale;
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $width, $height);
}
$im2 = $inputImage->createTargetImage($newWidth, $newHeight);
if (!$im2) {
err("could not create target image", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im2, $inputImageRes, 0, 0, 0, 0, $newWidth, $newHeight, $imageWidth, $imageHeight);
$inputImage->destroy();
// set values
$inputImageRes = $im2;
$imageWidth = $newWidth;
$imageHeight = $newHeight;
} else {
$inputImageRes = $inputImage->get();
}
$im = $inputImage->createTargetImage($width, $height);
imagefilledrectangle($im, 0, 0, $width, $height, imagecolorallocate($im, $color["red"], $color["green"], $color["blue"]));
if (!$im) {
err("could not create target image", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im, $inputImageRes, $x, $y, 0, 0, $imageWidth, $imageHeight, $imageWidth, $imageHeight);
$inputImage->set($im);
}
}
class Equalize {
function __construct() {}
function Equalize() {}
function exec($inputImage, $args, $donotenlarge) {
}
}
class Crop {
function __construct() {}
function Crop() {}
function exec($inputImage, $args, $donotenlarge) {
$x; $y; $width; $height;
$imageWidth = $inputImage->width();
$imageHeight = $inputImage->height();
if (count($args) > 3) {
list($x, $y, $width, $height) = $args;
} else {
list($width, $height) = $args;
$x = ($imageWidth - $width) / 2;
$y = ($imageHeight - $height) / 2;
}
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $width, $height);
}
$im = $inputImage->createTargetImage($width, $height);
if (!$im) {
err("could not create target image", "500 Internal Server Error", $width, $height);
}
@imagecopyresampled($im, $inputImageRes, 0, 0, $x, $y, $imageWidth, $imageHeight, $imageWidth, $imageHeight);
$inputImage->set($im);
}
}
class Rotate {
function __construct() {}
function Rotate() {}
function exec($inputImage, $args, $donotenlarge) {
list($angle) = $args;
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $inputImage->width(), $inputImage->height());
}
//$im = imagerotate($inputImageRes, $angle, 0); not working in newer ubuntu/debian
$im = rotateImage($inputImageRes, $angle, $inputImage);
if (!$im) {
err("currently only 90 degree steps are supported", "400 Bad Request", $inputImage->width(), $inputImage->height());
}
$inputImage->set($im);
}
}
class Grayscale {
function __construct() {}
function Grayscale() {}
function exec($inputImage, $args, $donotenlarge) {
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $inputImage->width(), $inputImage->height());
}
$im = grayscaleImage($inputImageRes, false, $inputImage);
if (!$im) {
err("could not create target image", "500 Internal Server Error", $inputImage->width(), $inputImage->height());
}
$inputImage->set($im);
}
}
class Colorize {
function __construct() {}
function Colorize() {}
function exec($inputImage, $args, $donotenlarge) {
list($color) = $args;
$color = hex2RGB($color);
$inputImageRes = $inputImage->get();
if (!$inputImageRes) {
err("could not read image", "500 Internal Server Error", $inputImage->width(), $inputImage->height());
}
$im = colorize($inputImageRes, $color);
if (!$im) {
err("could not create target image", "500 Internal Server Error", $inputImage->width(), $inputImage->height());
}
$inputImage->set($im);
}
}
if (!function_exists('imagecreatefrombmp')) { function imagecreatefrombmp($filename) {
//open file for reading
$fsize = @filesize($filename);
if (!$fsize || $fsize >= $GLOBALS['config']['maxiprocfilesize'] || $fsize < 0) {
error_log("imagecreatefrombmp: File [" . $filename . "] exceeds allowed filesize [" . $GLOBALS['config']['maxiprocfilesize'] . "] < [" . $fsize . "]");
return false;
}
if (!($fh = fopen($filename, "rb"))) {
error_log("imagecreatefrombmp: Can not open [" . $filename . "]");
return false;
}
// read file header
$meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14));
// check for bitmap
if ($meta['type'] != 19778) { //signature BM as integer
error_log("imagecreatefrombmp: [" . $filename . "] is not a bitmap!");
return false;
}
// read image header (DIB header)
$meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
if ($meta['width'] > $GLOBALS['config']["maxiprocimagesize"] || $meta['height'] > $GLOBALS['config']["maxiprocimagesize"] ) {
error_log("imagecreatefrombmp: File [" . $filename . "] exceeds allowed imagesize [" . $GLOBALS['config']["maxiprocimagesize"] . "] < [" . $meta['width'] . "] || [" . $meta['height'] . "]");
return false;
}
// read additional 16bit header
if ($meta['bits'] == 16) {
$meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
}
// set bytes and padding
$meta['bytes'] = $meta['bits'] / 8;
$meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
if ($meta['decal'] == 4) {
$meta['decal'] = 0;
}
// obtain imagesize
if ($meta['imagesize'] < 1) {
$meta['imagesize'] = $meta['filesize'] - $meta['offset'];
// in rare cases filesize is equal to offset so we need to read physical size
if ($meta['imagesize'] < 1) {
$meta['imagesize'] = @filesize($filename) - $meta['offset'];
if ($meta['imagesize'] < 1) {
error_log("imagecreatefrombmp: Can not obtain filesize of [" . $filename . "]!");
return false;
}
}
}
// calculate colors
$meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
// read color palette
$palette = array();
if ($meta['bits'] < 16) {
$palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
// in rare cases the color value is signed
if ($palette[1] < 0) {
foreach ($palette as $i => $color) {
$palette[$i] = $color + 16777216;
}
}
}
// create gd image
$im = imagecreatetruecolor($meta['width'], $meta['height']);
$data = fread($fh, $meta['imagesize']);
$p = 0;
$vide = chr(0);
$y = $meta['height'] - 1;
$error = "imagecreatefrombmp: [" . $filename . "] has not enough data!";
// loop through the image data beginning with the lower left corner
while ($y >= 0) {
$x = 0;
while ($x < $meta['width']) {
switch ($meta['bits']) {
case 32:
case 24:
if (!($part = substr($data, $p, 3))) {
error_log($error);
return $im;
}
$color = unpack('V', $part . $vide);
break;
case 16:
if (!($part = substr($data, $p, 2))) {
error_log($error);
return $im;
}
$color = unpack('v', $part);
$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
break;
case 8:
$color = unpack('n', $vide . substr($data, $p, 1));
$color[1] = $palette[ $color[1] + 1 ];
break;
case 4:
$color = unpack('n', $vide . substr($data, floor($p), 1));
$color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
$color[1] = $palette[ $color[1] + 1 ];
break;
case 1:
$color = unpack('n', $vide . substr($data, floor($p), 1));
switch (($p * 8) % 8) {
case 0:
$color[1] = $color[1] >> 7;
break;
case 1:
$color[1] = ($color[1] & 0x40) >> 6;
break;
case 2:
$color[1] = ($color[1] & 0x20) >> 5;
break;
case 3:
$color[1] = ($color[1] & 0x10) >> 4;
break;
case 4:
$color[1] = ($color[1] & 0x8) >> 3;
break;
case 5:
$color[1] = ($color[1] & 0x4) >> 2;
break;
case 6:
$color[1] = ($color[1] & 0x2) >> 1;
break;
case 7:
$color[1] = ($color[1] & 0x1);
break;
}
$color[1] = $palette[ $color[1] + 1 ];
break;
default:
error_log("imagecreatefrombmp: [" . $filename . "] has [" . $meta['bits'] . "] bits, this is not supported!");
return false;
}
imagesetpixel($im, $x, $y, $color[1]);
$x++;
$p += $meta['bytes'];
}
$y--;
$p += $meta['decal'];
}
fclose($fh);
return $im;
}}