|
<?php
class SaeImage extends SaeObject {
private $_img_data = ''; //图片数据
private $_options = array(); //图片选项
private $_width = 0;
private $_height = 0;
private $_image = null; //存储image资源
const image_limitsize = 2097152;
public function __construct($img_data='') {
parent::__construct();
return $this->setData($img_data);
}
//添加文字注释
public function annotate($txt, $opacity=0.5, $gravity=SAE_Static, $font=array()) {
$opacity = floatval($opacity);
if ($this->imageNull())
return false;
//设置默认字体样式
$font_default = array('name' => SAE_SimSun, 'size' => 15, 'weight' => 300, 'color' => 'black');
$font = array_merge($font_default, $font);
array_push($this->_options, array('act' => 'annotate', "txt" => $txt, "opacity" => $opacity,
"gravity" => $gravity, "font" => array("name" => $font['name'], "size" => $font["size"],
"weight" => $font["weight"], "color" => $font["color"])));
return true;
}
//数据重新初始化
public function clean() {
$this->_img_data = '';
$this->_options = array();
$this->_width = 0;
$this->_height = 0;
$this->_image = null;
}
//图片合成, data为数组,在其他操作执行前进行操作
public function composite($width, $height, $color="black") {
$width = intval($width);
$height = intval($height);
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'composite', "width" => $width, "height" => $height, "color" => $color));
return true;
}
//裁剪图片
public function crop($lx=0.25, $rx=0.75, $by=0.25, $ty=0.75) {
$lx = floatval($lx);
$rx = floatval($rx);
$by = floatval($by);
$ty = floatval($ty);
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'crop', "lx" => $lx, "rx" => $rx, "by" => $by, "ty" => $ty));
return true;
}
//进行图片处理操作
public function exec($format='jpg', $display=false) {
if ($this->imageNull())
return false;
if (!in_array($format, array('jpg', 'gif', 'png'))) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "format must be one of 'jpg', 'gif' and 'png'";
return false;
}
if ($format == "jpg")
$format = "jpeg";
if ($this->_options[0]["act"] == "composite" && !is_array($this->_img_data)) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "composite imagedata must be an array, pls see doc:";
return false;
}
if ($this->_options[0]["act"] != "composite" && is_array($this->_img_data)) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "imagedata is array only when composite image and composite must be the first operation";
return false;
}
if (!$this->_image_create())
return false;
//循环处理
foreach ($this->_options as $options) {
call_user_func(array($this, "_" . $options['act']), $options);
}
$imgFun = 'image' . $format;
if ($display) {
header("Content-Type: image/" . $format);
$imgFun($this->_image);
} else {
ob_start();
$imgFun($this->_image);
return ob_get_clean();
}
imagedestroy($this->_image);
}
//创建画布
private function _image_create() {
if ($this->_options[0]["act"] == "composite") {
//合并多张图片
$w = $this->_options[0]["width"];
$h = $this->_options[0]["height"];
$this->_width=$w;
$this->_height=$h;
$_image = imagecreatetruecolor($w, $h);
//设置背景颜色
$color = $this->toRGB($this->_options[0]['color']);
$bg = imagecolorallocate($_image, $color['r'], $color['g'], $color['b']);
imagefill($_image, 0, 0, $bg);
foreach ($this->_img_data as $data) {
$img_data = $data[0];
$x = isset($data[1]) ? $data[1] : 0;
$y = isset($data[2]) ? $data[2] : 0;
$o = isset($data[3]) ? $data[3] * 100 : 100;
$p = isset($data[4]) ? $data[4] : SAE_TOP_LEFT;
$tmp_file = tempnam(SAE_TMP_PATH, "SAE_IMAGE");
if (!file_put_contents($tmp_file, $img_data)) {
$this->errmsg = "file_put_contents to SAETMP_PATH failed when getImageAttr";
return false;
}
$info = getimagesize($tmp_file);
$sw = $info[0];
$sh = $info[1];
$image_type = strtolower(substr(image_type_to_extension($info[2]), 1));
$createFun = "imagecreatefrom" . $image_type;
$sImage = $createFun($tmp_file);
//设置位置
switch ($p) {
case SAE_TOP_LEFT:
$dst_x = $x;
$dst_y = -$y;
break;
case SAE_TOP_CENTER:
$dst_x = ($w - $sw) / 2 + $x;
$dst_y = -$y;
break;
case SAE_TOP_RIGHT:
$dst_x = $w - $sw + $x;
$dst_y = -$y;
break;
case SAE_CENTER_LEFT:
$dst_x = $x;
$dst_y = ($h - $sh) / 2 - $y;
break;
case SAE_CENTER_CENTER:
$dst_x = ($w - $sw) / 2 + $x;
$dst_y = ($h - $sh) / 2 - $y;
break;
case SAE_CENTER_RIGHT:
$dst_x = $w - $sw + $x;
$dst_y = ($h - $sh) / 2 - $y;
break;
case SAE_BOTTOM_LEFT:
$dst_x = $x;
$dst_y = $h - $sh - $y;
break;
case SAE_BOTTOM_CENTER:
$dst_x = ($w - $sw) / 2 + $x;
$dst_y = $h - $sh - $y;
break;
case SAE_BOTTOM_RIGHT:
$dst_x = $w - $sw + $x;
$dst_y = $h - $sh - $y;
break;
}
$this->imagecopymerge_alpha($_image, $sImage, $dst_x, $dst_y, 0, 0, $sw, $sh, $o);
unlink($tmp_file);
}
$this->_image = $_image;
unset($this->_options[0]);
} else {
if (is_null($this->_image))
$this->getImageAttr();
}
return true;
}
//修复合并时png透明问题
private function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
$w = imagesx($src_im);
$h = imagesy($src_im);
$cut = imagecreatetruecolor($src_w, $src_h);
imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);
imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);
imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h,$pct);
}
//水平翻转
public function flipH() {
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'flipH'));
return true;
}
//垂直翻转
public function flipV() {
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'flipV'));
return true;
}
//获取图像属性
public function getImageAttr() {
if ($this->imageNull())
return false;
$fn = tempnam(SAE_TMP_PATH, "SAE_IMAGE");
if ($fn == false) {
$this->errmsg = "tempnam call failed when getImageAttr";
return false;
}
if (!file_put_contents($fn, $this->_img_data)) {
$this->errmsg = "file_put_contents to SAETMP_PATH failed when getImageAttr";
return false;
}
if (!($size = getimagesize($fn, $info))) {
$this->errmsg = "getimagesize failed when getImageAttr";
return false;
}
foreach ($info as $k => $v) {
$size[$k] = $v;
}
$this->_width = $size[0];
$this->_height = $size[1];
//建立图片资源
$image_type = strtolower(substr(image_type_to_extension($size[2]), 1));
$createFun = "imagecreatefrom" . $image_type;
$this->_image = $createFun($fn);
unlink($fn); //删除临时文件
return $size;
}
//去噪点,改善图片质量,通常用于exec之前
public function improve() {
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'improve'));
return true;
}
//等比例缩放
public function resize($width=0, $height=0) {
$width = intval($width);
$height = intval($height);
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'resize', "width" => $width, "height" => $height));
return true;
}
//按比例缩放
public function resizeRatio($ratio=0.5) {
$ratio = floatval($ratio);
if ($this->imageNull())
return false;
if ($this->_width == 0) {
$attr = $this->getImageAttr();
if (!$attr)
return false;
}
array_push($this->_options, array('act' => 'resize', "width" => $this->_width * $ratio, "height" => $this->_height * $ratio));
return true;
}
//顺时针旋转图片
public function rotate($degree=90) {
$degree = intval($degree);
if ($this->imageNull())
return false;
array_push($this->_options, array('act' => 'rotate', "degree" => $degree));
return true;
}
//设置数据
public function setData($img_data) {
if (is_array($img_data)) {
$_size = 0;
foreach ($img_data as $k => $i) {
if (count($i) < 1 || count($i) > 5) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "image data array you supplied invalid";
return false;
}
if (is_null($i[1]) || $i[1] === false)
$img_data[$k][1] = 0;
if (is_null($i[2]) || $i[1] === false)
$img_data[$k][2] = 0;
if (is_null($i[3]) || $i[1] === false)
$img_data[$k][3] = 1;
if (is_null($i[4]) || $i[1] === false)
$img_data[$k][4] = SAE_TOP_LEFT;
$_size += strlen($i[0]);
}
if ($_size > self::image_limitsize) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "image datas length more than 2M";
return false;
}
} else if (strlen($img_data) > self::image_limitsize) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "image data length more than 2M";
return false;
}
$this->_img_data = $img_data;
return true;
}
//判断图片数据是否可用
private function imageNull() {
if (empty($this->_img_data)) {
$this->errno = SAE_ErrParameter;
$this->errmsg = "image data cannot be empty";
return true;
} else {
return false;
}
}
//将颜色转换为RGB格式
private function toRGB($color) {
$color = trim($color);
if (preg_match('/^rgb\((\d+),(\d+),(\d+)\)$/i', $color, $arr)) {
//支持rgb(r,g,b)格式
return array(
'r' => $arr[1],
'g' => $arr[2],
'b' => $arr[3]
);
}
$e_color = array(
//支持英文颜色名
'black' => '#000',
'red' => '#f00',
'blue'=>'#00f'
//TODU 增加其他
);
$hexColor = str_replace(array_keys($e_color), array_values($e_color), $color);
$color = str_replace('#', '', $hexColor);
if (strlen($color) > 3) {
$rgb = array(
'r' => hexdec(substr($color, 0, 2)),
'g' => hexdec(substr($color, 2, 2)),
'b' => hexdec(substr($color, 4, 2))
);
} else {
$color = str_replace('#', '', $hexColor);
$r = substr($color, 0, 1) . substr($color, 0, 1);
$g = substr($color, 1, 1) . substr($color, 1, 1);
$b = substr($color, 2, 1) . substr($color, 2, 1);
$rgb = array(
'r' => hexdec($r),
'g' => hexdec($g),
'b' => hexdec($b)
);
}
return $rgb;
}
/**
* 添加文字
* 参数格式
* array("txt" => $txt, "opacity" => $opacity,
"gravity" => $gravity, "font" => array("name" => $font['name'], "size" => $font["size"],
"weight" => $font["weight"], "color" => $font["color"]))
* @param array $args
*/
private function _annotate($args) {
$font = $args['font'];
$rgb = $this->toRGB($font['color']);
$color = imagecolorclosestalpha($this->_image, $rgb['r'], $rgb['g'], $rgb['b'], (1 - $args['opacity']) * 100);
//设置位置
$fontSize = imagettfbbox($font['size'], 0, $font['name'], $args['txt']);
$textWidth = $fontSize [4]; //取出宽
$textHeight = abs($fontSize[7]); //取出高
switch ($args['gravity']) {
case SAE_NorthWest:
$x=0;
$y=$textHeight;
break;
case SAE_North:
$x=($this->_width-$textWidth)/2;;
$y=$textHeight;
break;
case SAE_NorthEast:
$x=$this->_width-$textWidth;;
$y=$textHeight;
break;
case SAE_West:
$x=0;
$y=($this->_height-$textHeight)/2;
break;
case SAE_East:
$x=$this->_width-$textWidth;
$y=($this->_height-$textHeight)/2;
break;
case SAE_SouthWest:
$x=0;
$y=$this->_height-$textHeight;
break;
case SAE_South:
$x=($this->_width-$textWidth)/2;
$y=$this->_height-$textHeight;
break;
case SAE_SouthEast:
$x=$this->_width-$textWidth;
$y=$this->_height-$textHeight;
break;
case SAE_Static:
default :
$x=($this->_width-$textWidth)/2;
$y=($this->_height-$textHeight)/2;
break;
}
imagettftext($this->_image, $font['size'], 0, $x, $y, $color, $font['name'], $args['txt']);
}
/**
*截取图片
* 参数 array("lx" => $lx, "rx" => $rx, "by" => $by, "ty" => $ty)
* @param array $args
*/
private function _crop($args){
$width=($args['rx']-$args['lx'])*$this->_width;
$height=($args['ty']-$args['by'])*$this->_height;
$x=$args['lx']*$this->_width;
$y=$args['by']*$this->_height;
$_image=imagecreatetruecolor($width, $height);
imagecopyresampled($_image,$this->_image,0,0,$x,$y,
$width,$height,$width,$height);
$this->_image=$_image;
}
/**
*图片放缩
* 参数:array( "width" => $width, "height" => $height)
* @param array $args
*/
private function _resize($args){
if($args['width']==0 && $args['heigth']==0) return ;
if($args['width']==0){
//高度固定等比例放缩
$h=$args['heigth'];
$w=$h/$this->_height*$this->_width;
}elseif($args['heigth']==0){
//宽度固定等比例放缩
$w=$args['width'];
$h=$w/$this->_width*$this->_height;
}else{
$w=$args['width'];
$h=$args['height'];
}
$_image=imagecreatetruecolor($w, $h);
imagecopyresampled($_image, $this->_image, 0, 0, 0, 0, $w, $h, $this->_width, $this->_height);
$this->_image=$_image;
}
/**
*旋转角度
* @param array $args
*/
private function _rotate($args){
$this->_image=imagerotate($this->_image, 360-$args['degree'],0);
}
//水平翻转
private function _flipH($args) {
$_image=imagecreatetruecolor($this->_width, $this->_height);
for ($i = 0; $i < $this->_width; $i++) {
imagecopyresampled($_image, $this->_image, ($this->_width - $i), 0, $i, 0, 1, $this->_height, 1, $this->_height);
}
$this->_image=$_image;
}
//垂直翻转
private function _flipV($args) {
$this->_flipH(array());
$this->_rotate(array('degree'=>180));
}
//去除噪点
private function _improve($args){
//本地不做任何处理
}
}
|