havegd = true; $this->getGdInfo(); if ($isfile) { $this->filename = $image; parent::__construct(null, false); $this->loaded = false; } else { parent::__construct($image, false); $this->format = $format; $this->loaded = false; } } else { $this->havegd = false; $this->gdinfo = []; } } protected function loadData() { if (! $this->loaded && $this->havegd) { if (! empty($this->filename) && is_file($this->filename)) { $this->format = strtolower(substr($this->filename, strrpos($this->filename, '.') + 1)); list($this->width, $this->height, $type) = getimagesize($this->filename); if (function_exists("image_type_to_extension")) { $this->format = image_type_to_extension($type, false); } else { $tmp = image_type_to_mime_type($type); $this->format = strtolower(substr($tmp, strrpos($tmp, "/") + 1)); } if ($this->isSupported($this->format)) { if ($this->format == 'jpg') { $this->format = 'jpeg'; } $this->data = call_user_func('imagecreatefrom' . $this->format, $this->filename); $this->loaded = true; } } elseif ( ! empty($this->data) && $this->data != 'REFERENCE' && preg_match('/^[<]svg/', $this->data) == false //In some cases, an svg will be recognized as an alternate picture type, here we simply check the beginning for "data = imagecreatefromstring($this->data); $this->loaded = true; } else { parent::loadData(); } } } /** * @param $x * @param $y */ protected function resizeImage($x, $y) { if ($this->data) { if ($this->format == 'svg') { $svgAttributes = ' width="' . $x . '" height="' . $y . '" viewBox="0 0 ' . $this->width . ' ' . $this->height . '" preserveAspectRatio="xMinYMin meet"'; $this->data = preg_replace('/width="' . $this->width . '" height="' . $this->height . '"/', $svgAttributes, $this->data); } else { $t = imagecreatetruecolor($x, $y); // trick #2 to have a transparent background for png instead of black imagesavealpha($t, true); imagealphablending($t, false); imagecolortransparent($t, imagecolorallocatealpha($t, 0, 0, 0, 127)); imagecopyresampled($t, $this->data, 0, 0, 0, 0, $x, $y, $this->getWidth(), $this->getHeight()); $this->data = $t; unset($t); } } } public function resizeThumb() { if ($this->thumb !== null) { $this->data = imagecreatefromstring($this->thumb); $this->loaded = true; } else { $this->loadData(); } return parent::resizeThumb(); } /** * @return null|string */ public function display() { $this->loadData(); if ($this->data) { //@ob_end_flush(); // ignore E_NOTICE if no buffer ob_start(); switch (strtolower($this->format)) { case 'jpeg': case 'jpg': if ($this->quality !== 75) { imagejpeg($this->data, null, $this->quality); } else { imagejpeg($this->data); } break; case 'gif': imagegif($this->data); break; case 'png': if ($this->quality !== 75) { imagepng($this->data, null, (int)$this->quality / 10); } else { imagepng($this->data); } break; case 'wbmp': imagewbmp($this->data); break; case 'svg': echo $this->data; break; default: ob_end_clean(); return null; } $image = ob_get_contents(); ob_end_clean(); return $image; } else { return null; } } /** * @param $angle * @return bool */ public function rotate($angle) { $this->loadData(); if ($this->data) { $this->data = imagerotate($this->data, $angle, 0); return true; } else { return false; } } /** * @return array */ protected function getGdInfo() { $gdinfo = []; $gdversion = ''; if (function_exists("gd_info")) { $gdinfo = gd_info(); preg_match("/[0-9]+\.[0-9]+/", $gdinfo["GD Version"], $gdversiontmp); $gdversion = $gdversiontmp[0]; } else { //next try ob_start(); phpinfo(INFO_MODULES); $gdversion = preg_match('/GD Version.*2.0/', ob_get_contents()) ? '2.0' : '1.0'; $gdinfo["JPG Support"] = preg_match('/JPG Support.*enabled/', ob_get_contents()); $gdinfo["PNG Support"] = preg_match('/PNG Support.*enabled/', ob_get_contents()); $gdinfo["GIF Create Support"] = preg_match('/GIF Create Support.*enabled/', ob_get_contents()); $gdinfo["WBMP Support"] = preg_match('/WBMP Support.*enabled/', ob_get_contents()); $gdinfo["XBM Support"] = preg_match('/XBM Support.*enabled/', ob_get_contents()); ob_end_clean(); } if (isset($this)) { $this->gdinfo = $gdinfo; $this->gdversion = $gdversion; } return $gdinfo; } // This method do not need to be called on an instance /** * @param $format * @return bool|int */ public function isSupported($format) { if (! function_exists('imagetypes')) { $gdinfo = isset($this) ? $this->gdinfo : $this->getGdInfo(); } switch (strtolower($format)) { case 'jpeg': case 'jpg': if (isset($gdinfo) && $gdinfo['JPG Support']) { return true; } else { return ( imagetypes() & IMG_JPG ); } case 'png': if (isset($gdinfo) && $gdinfo['PNG Support']) { return true; } else { return ( imagetypes() & IMG_PNG ); } case 'gif': if (isset($gdinfo) && $gdinfo['GIF Create Support']) { return true; } else { return ( imagetypes() & IMG_GIF ); } case 'wbmp': if (isset($gdinfo) && $gdinfo['WBMP Support']) { return true; } else { return ( imagetypes() & IMG_WBMP ); } case 'xpm': if (isset($gdinfo) && $gdinfo['XPM Support']) { return true; } else { return ( imagetypes() & IMG_XPM ); } case 'svg': return true; } return false; } /** * @return int|null */ protected function getHeightImpl() { if ($this->loaded && $this->data) { if ($this->format == 'svg') { if (preg_match('/height="(\d+)"/', $this->data, $match)) { return $match[1]; } } else { return @imagesy($this->data); } } elseif ($this->height) { return $this->height; } elseif ($this->filename && is_readable($this->filename)) { list($this->width, $this->height, $type) = getimagesize($this->filename); if ($this->height) { return $this->height; } } if (! $this->loaded || ! $this->data) { $this->loadData(); } if ($this->data) { return @imagesy($this->data); } } /** * @return int|null */ protected function getWidthImpl() { if ($this->loaded && $this->data) { if ($this->format == 'svg') { if (preg_match('/width="(\d+)"/', $this->data, $match)) { return $match[1]; } } else { return @imagesx($this->data); } } elseif ($this->width) { return $this->width; } elseif ($this->filename && is_readable($this->filename)) { list($this->width, $this->height, $type) = getimagesize($this->filename); if ($this->width) { return $this->width; } } if (! $this->loaded || ! $this->data) { $this->loadData(); } if ($this->data) { return @imagesx($this->data); } } /** * Allow adding text as overlay to a image * @param $text * @return string || boolean */ public function addTextToImage($text) { if (! $this->loaded) { $this->loadData(); } if (! $this->data) { return false; } $fontFile = '/lib/captcha/DejaVuSansMono.ttf'; $padLeft = 20; $padBottom = $this->getHeight() - 20; $fontSize = 12; $textAngle = 0; $fontColor = imagecolorallocate($this->data, 255, 255, 0); $fontStroke = imagecolorallocate($this->data, 0, 0, 0); $fontStrokeWidth = 2; putenv('GDFONTPATH=' . realpath('.')); $result = $this->imageTtfStrokeText($this->data, $fontSize, $textAngle, $padLeft, $padBottom, $fontColor, $fontStroke, $fontFile, $text, $fontStrokeWidth); if (! $result) { return false; } return true; } /** * Adds text to the image, with a "shadow", to improve readability * * @param $image The current image (will be changed) * @param $size * @param $angle * @param $x * @param $y * @param $textcolor * @param $strokecolor * @param $fontfile * @param $text * @param $px * @return array */ protected function imageTtfStrokeText(&$image, $size, $angle, $x, $y, $textcolor, $strokecolor, $fontfile, $text, $px) { for ($c1 = ($x - abs($px)); $c1 <= ($x + abs($px)); $c1++) { for ($c2 = ($y - abs($px)); $c2 <= ($y + abs($px)); $c2++) { imagettftext($image, $size, $angle, $c1, $c2, $strokecolor, $fontfile, $text); } } return imagettftext($image, $size, $angle, $x, $y, $textcolor, $fontfile, $text); } }