YII实现图像上传裁剪功能

说明:是借鉴别人的文章思路,整合在yii上的单个图片裁剪功能。注意插件版本可能有不同。

借鉴以下两篇文章:

  1,Ajax+PHP+jQuery图片截图上传   

  2,PHP Uploadify+jQuery.imgAreaSelect插件+AJAX 实现图片上传裁剪 仿微博头像上传功能


要用的插件:

jQuery:jquery-1.10.2.min.js(版本可自己选);

uploadify:文件上传功能;

jquery.imgareaselect:对图片进行自定义区域选择;


客户端与服务器交互图

yii部分: (用到bootstrap,JS模块)


yii部署:

CSS: 



JS:

    - require.min.js  (JS模块化开发要用的插件)

    - main.js (入口JS 载入  jquery-1.10.2.min.js     jquery.imgareaselect.minjs      jquery.uploadify.min.js      json2.js


extensions(扩展): 处理上传图像和图像裁剪


代码:

- 视图

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="pragma" content="no-cache">  
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate">  
<meta http-equiv="expires" content="0">  
<title>图片上传裁剪</title>
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->homeUrl;?>css/whg/bootstrap.min.css" media="all">
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->homeUrl;?>js/whg/jquery.imgareaselect-0.9.10/css/imgareaselect-default.css" media="all" >
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->homeUrl;?>js/whg/uploadify/uploadify.css" media="all" >
<script data-main="<?php echo Yii::app()->homeUrl;?>js/whg/main" type="text/javascript" src="<?php echo Yii::app()->homeUrl;?>js/whg/require.min.js"></script>

<style type="text/css">
#image-uploaded,
#image-cuted{
    position:relative;
    max-width:100%;
}
#cut-preview-wrap{
    position:relative;
    display:block;
    padding:0;
    margin:0;
    border:0;
    width:100%;
    overflow:hidden;
}
#cut-preview{
    position:absolute;
    padding:0;
    margin:0;
    border:0;
    top:0;
    left:0;
}
</style>
</head>
<body>
<div class="container">
    <div class="page-header">
        <h1>
            图片上传裁剪 
        </h1>
    </div>

    <div class="row" id="cutone">
        <div class="col-xs-3">
        <label for="">图片上传</label>
          
			<div id="upload-wrap" style="margin-top:40px;">
                <input type="file"  id="file" name="file" />
                <span class="help-block">选择图片(1M以内);</span>
				<span class="help-block">图片格式必须为:png, jpeg, jpg, gif;</span>
				<span class="help-block">图片不允许涉及政治敏感与色情;</span>
                <p>
                    <a id="upload" class="btn btn-sm btn-success" style="display:none;" href="#">上传</a>
                </p>

                <br>
                <div class="col-xs-12" id="ratio-wrap" style="margin-top:30px;display:none;">
                    <div id="ratio-input" class="input-group">
                        <span class="input-group-addon">裁剪宽高比例</span>
                        <input type="text" id="ratio" class="form-control" placeholder="Ratio" value="1.1">
                     </div>
                    <span id="cut-help" class="help-block">输入宽高比进行裁剪初始化。例如1.3</span>
                    <p>
                        <a id="cutInit" class="btn btn-success" href="#">下一步</a>
                        <a id="cut" style="display:none;" class="btn btn-success" href="#">确定裁剪</a>
                    </p>
                </div>
            </div>
        </div>
        <div class="col-xs-4">
            <label for="">裁剪区域</label>
            <div class="row">
                <div class="col-xs-12" id="uploaded-wrap" style="display:none;">
                </div>
            </div>
        </div>
        <div class="col-xs-4" id="preview-wrap" style="display:none;">
            <label for="">裁剪预览</label>
            <div id="cut-preview-wrap">
                <img id="cut-preview" src="" alt="">
            </div>
            <p>
                <small id="log"></small>
            </p>
            
        </div>
    </div>

    <div class="row" id="cuted-wrap" style="display:none;">
        <div class="col-xs-offset-2 col-xs-8 text-center">
            <div class="page-header">
                <h4>成功预览</h4>
            </div>

            <p>
                <img id="image-cuted" src="" alt="">
            </p>
            <form method="post" action="<?php echo $this->createUrl('indexcut');?>">
            <p>
                <!--<a id="download" style="display:none;" class="btn btn-block btn-danger" href="#">下载成品</a>-->
                <input type="hidden" id="hide-cuted" name="hide-cuted" value="" />
                <input class="btn btn-success btn-lg btn-block" type="submit" value="保存图片">
            </p>
            </form>
        </div>
    </div>

</div>

</body>
</html>


主入口main.js

requirejs.config({
    baseUrl: '/js/whg/',
    paths: {
        jquery:'jquery-1.10.2.min',
        imgareaselect:'jquery.imgareaselect-0.9.10/jquery.imgareaselect.min',
        uploadify:'uploadify/jquery.uploadify.min'
    },
    shim:{
        'imgareaselect':['jquery'],
        'uploadify':['jquery']
    }
});
var requireApp = ["jquery","imgareaselect","uploadify"];
//JSON检测
if(  typeof JSON === 'undefined' ){
    requireApp.push('json2');
}

//调用依赖
require(requireApp, function($) {
    var $ = $.noConflict();
    var $field = $("input[type='file']");
    //Uploadify上传插件初始化
   //$("#init").click(function(e){
       // e.preventDefault();
        //$(this).remove();
       // $("#upload-wrap").show();
	$(function(e){
        //e.preventDefault();
        $field.uploadify({
             'buttonText': '选择图片'
            ,'swf': '/js/whg/uploadify/uploadify.swf?v=' + ( parseInt(Math.random()*1000) )
            ,'uploader'  : "/admin/emcee/emcee/shoot"
            ,'auto'      : false    
            ,'multi'     : false   
            ,'method'    : 'post'
            ,'fileObjName' : 'upload'
            ,'queueSizeLimit' : 1
            ,'fileSizeLimit' : '2000KB'
            ,'fileTypeExts': '*.gif; *.jpg; *.png; *.jpeg'
            ,'fileTypeDesc': '只允许.gif .jpg .png .jpeg 图片!' 
            ,'onSelect': function(file) {//选择文件后的触发事件
                //$("#upload").show();  
				//修改为选择图片后自动上传
				$field.uploadify('upload','*')
            }
            ,'onUploadSuccess' : function(file, data, response){  //上传成功后的触发事件
                $field.uploadify('disable', true);
                //$("#upload").remove();
                var rst =JSON.parse(data);
                //document.write(rst.data.path);
                if( rst.status == 0 ){
                    alert('上传失败:'+rst.info);
                }else{
                    var imageData = rst.data;
                    var $image = $("<img src='"+imageData.path+"' id='image-uploaded' data-width='"+imageData.width+"' data-height='"+imageData.height+"' data-name='"+imageData.name+"' />");
                    $("#uploaded-wrap").append( $image ).show();
                    $("#ratio-wrap").show();
                    //$image.bind('click',function(e){
                     //   e.preventDefault();
                     //   alert('请先设置裁剪宽高比例!');
                   // });

                }
            }
            ,'onUploadError' : function(file, errorCode, errorMsg, errorString){
                alert('进入失败');
                alert(errorString);
            }
        });
    });

    //点击上传   
    //$("#upload").click(function(e){
    //    e.preventDefault();
    //    $field.uploadify('upload','*');
   // });
   //注释以上代码,不用点击接钮上传,让其选择图片后自动上传

    //点击裁剪初始化时
    $("#cutInit").click(function(e){
        e.preventDefault();
        //确定裁剪宽高比
        var ratio = parseFloat($("#ratio").val());
        if( isNaN(ratio) ){
            alert("请输入正确的宽高比,必须为数字,例如0.6或1.3");
            return ;
        }

        //相关元素
        var $uploaded = $("#image-uploaded"),
            $previewWrap = $("#cut-preview-wrap"),
            $preview = $("#cut-preview");

        //图片宽高参数
        var realWidth = $uploaded.data('width'),
            realHeight = $uploaded.data('height'),
            uploadedWidth = $uploaded.outerWidth(),
            uploadedHeight = $uploaded.outerHeight(),
            uploadedRate = uploadedWidth/realWidth; //缩放比例

        
        //其他操作
        $(this).hide();
        $("#ratio-input").hide();
        $("#cut-help").html('原图宽:'+realWidth+' 高:'+realHeight+'<strong style="color:red;"> 在图片上进行拖拽确定裁剪区域!</strong>');
        $("#preview-wrap").show();
        $uploaded.unbind('click');

        //预览框宽高参数
        var previewWrapWidth = $previewWrap.outerWidth();
            previewWrapHeight = Math.round(previewWrapWidth/ratio);

        //初始化预览框
        $previewWrap.css( {
            width:previewWrapWidth+'px',
            height:previewWrapHeight+'px'
        } );

        //初始化预览图
        $preview.prop( 'src',$uploaded.attr('src') );


        //构造AreaSelect选择器
		$(document).ready(function () {
			var imgArea = $uploaded.imgAreaSelect({
				x1: 0, y1: 0, x2: 200, y2: 200,
				instance: true,  
				handles: true,   
				fadeSpeed: 300,
				aspectRatio:'1:'+(1/ratio),
				onSelectChange: function(img,selection){//选区改变时的触发事件
					//selection包括x1,y1,x2,y2,width,height,分别为选区的偏移和高宽。
					//console.log(selection);

					var rate = previewWrapWidth/selection.width;//预览区相对于选择区的倍数
					$preview.css({
						width: Math.round(uploadedWidth*rate)+'px',
						height: Math.round(uploadedHeight*rate)+'px',
						"left": Math.round(selection.x1*rate*-1),
						"top": Math.round(selection.y1*rate*-1) 
					});

					//换算后的真实参数
					var realSize = {
						width:     Math.round(selection.width/uploadedRate),
						height:    Math.round(selection.height/uploadedRate),
						offsetLeft:Math.round(selection.x1/uploadedRate),
						offsetTop: Math.round(selection.y1/uploadedRate)
					}

					$("#log").text('实际裁剪参数 - 宽:'+realSize.width+
									' 高:'+realSize.height
									//' 左偏移:'+realSize.offsetLeft+
									//' 上偏移:'+realSize.offsetTop
								);

					$preview.data( realSize );

				}
			});
		});

        //点击确认裁剪时
        $("#cut").show().click(function(e){
            e.preventDefault();
            var $this = $(this);
            var data = $preview.data();
            if( typeof data['width'] === 'undefined' ||
                data['width'] == ''||
                data['width'] == 0 ||
                data['height'] == '' ||
                data['height'] == 0 ){
                    alert('请先选择裁剪区域!');
                    return ;
            }

            $this.addClass('active').text('裁剪中...');
            data['name'] = $uploaded.data('name');
            $.ajax({
                url:'/admin/emcee/emcee/cutimg',
                type:'POST',
                data:data,
                success: function(data){
                    //console.log(data);
                    var rst = JSON.parse(data);
                    if( rst.status == 0 ){
                        alert('失败!'+rst.info);
                    }else{
                        $this.hide();
                        $("#download").show().prop('href',rst.url).prop('target','_blank');
                        $("#cuted-wrap").show();
                        $("#image-cuted").prop('src',rst.path);
                        $("#hide-cuted").prop('value',rst.path);
                        imgArea.setOptions({'disable':true,'hide':true});//去掉选区功能

                        alert('图片已裁剪!点击\'下载成品\'可下载!');
                    }
                }
                 
            });
        });

    });
});




控制器:

public function actionShoot(){
			if($_FILES){
				$data = yii::app()->UploadReceive->receive($_FILES['upload'],'/upload/cutimg/');
				echo json_encode($data);
			}else{
				$this->render('shoot');
			}
}

public function actionCutimg(){
		$filename = $_POST['name'];
		$file = $_SERVER['DOCUMENT_ROOT'].'upload/cutimg/'.$filename;
		//裁剪后的图片路径
		$cutPicfolder = '/upload/cutimg/';
		$cutPicPath = $_SERVER['DOCUMENT_ROOT'].$cutPicfolder;

		$urlPath = yii::app()->UploadReceive->get_current_url();
		//$urlPath = self::_get_current_url(); 
		$urlPath = rtrim($urlPath,'/').'/';
		$x1 = $_POST['offsetLeft'];
		$y1 = $_POST['offsetTop'];
		$width = $_POST['width'];
		$height = $_POST['height'];

		$type = exif_imagetype($file);
		$support_type=array(IMAGETYPE_JPEG , IMAGETYPE_PNG , IMAGETYPE_GIF);

		if(!in_array($type, $support_type,true)) {
		    $data['status'] = 0;
		    $data['info'] =  "不支持的格式!";
		    echo json_encode($data);
		    exit;
		}else{
		    switch($type) {
		    case IMAGETYPE_JPEG :
		        $image = imagecreatefromjpeg($file);
		        break;
		    case IMAGETYPE_PNG :
		        $image = imagecreatefrompng($file);
		        break;
		    case IMAGETYPE_GIF :
		        $image = imagecreatefromgif($file);
		        break;
		    default:
		        $data['status'] = 0;
		        $data['info'] =  "不支持的格式!";

		        echo json_encode($data);
		        exit;
		    }

		    //图片裁剪
		    $copy = yii::app()->UploadReceive->PIPHP_ImageCrop($image, $x1, $y1, $width, $height);
		    //$copy = self::_PIPHP_ImageCrop($image, $x1, $y1, $width, $height);
		    $newName = 'cut_'.$filename;
		    $targetPic = $cutPicPath.$newName;

		    //TODO 目录与写文件检测
		    if(false === imagejpeg($copy, $targetPic) ){
		        $data['status'] = 0;
		        $data['info'] =  "生成裁剪图片失败!请确认保存路径存在且可写!";
		        echo json_encode($data);
		        exit;
		    } 

		    @unlink($file);

		    $data['status'] = 1;
		    $data['path'] = $cutPicfolder.$newName;
		    $data['name'] = $newName;
		    $data['url']  = $urlPath.$data['path'];

		    echo json_encode($data);
		    exit;

		}
}


扩展应用:(extentions/UploadReceive)

备注:为了yii::app() 全局使用,在main.php配置如下

// application components
 'components'=>array(

     'UploadReceive'=>array(
            'class'=>'application.extensions.thumb.UploadReceive',
     ),

<?php
class UploadReceive extends CApplicationComponent{
    public function get_current_url($strip = true){
        // filter function
        $filter = function($input, $strip) {
            $input = urldecode($input);
            $input = str_ireplace(array("\0", '%00', "\x0a", '%0a', "\x1a", '%1a'), '', $input);
            if ($strip) {
                $input = strip_tags($input);
            }
            $input = htmlentities($input, ENT_QUOTES, 'UTF-8'); // or whatever encoding you use...
            return trim($input);
        };

        $url = array();
        // set protocol
        $url['protocol'] = 'http://';
        if (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) === 'on' || $_SERVER['HTTPS'] == 1)) {
            $url['protocol'] = 'https://';
        } elseif (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
            $url['protocol'] = 'https://';
        }
        // set host
        $url['host'] = $_SERVER['HTTP_HOST'];
        // set request uri in a secure way
        $url['request_uri'] = $filter( dirname($_SERVER['REQUEST_URI']), $strip);
        return join('', $url);
    }

    //裁剪图片
    public function PIPHP_ImageCrop($image, $x, $y, $w, $h)
    {
       // Plug-in 15: Image Crop
       //
       // This plug-in takes a GD image and returns a cropped
       // version of it. If any arguments are out of the
       // image bounds then FALSE is returned. The arguments
       // required are:
       //
       //    $image:   The image source
       //    $x & $y:  The top-left corner
       //    $w & $h : The width and height

       $tw = imagesx($image);
       $th = imagesy($image);

       if ($x > $tw || $y > $th || $w > $tw || $h > $th)
          return FALSE;

       $temp = imagecreatetruecolor($w, $h);
       imagecopyresampled($temp, $image, 0, 0, $x, $y,
          $w, $h, $w, $h);
       return $temp;
    }

    public function receive($file,$path){
        //存储相对地址
        $path = trim($path,'/').'/';
        //存储绝对地址
        $savepath = $_SERVER['DOCUMENT_ROOT'].'/'.$path;

        //url
        //$rootUrl = 'http://'.$_SERVER['SERVER_NAME'].'/';

        //初始检测
        if($file['error'] > 0){  
           $data['status'] = 0;
           switch($file['error']){  
             case 1: $data['info'] = '文件大小超过服务器限制';  
                     break;  
             case 2: $data['info'] = '文件太大!';  
                     break;  
             case 3: $data['info'] = '文件只加载了一部分!';  
                     break;  
             case 4: $data['info'] = '文件加载失败!';  
                     break;  
           }  
           return $data;
        }  

        //大小检测
        if($file['size'] > 1024*1024){  
           $data['status'] = 0;
           $data['info'] = '文件过大!';  
           return $data;
        }  
        
        //类型检测
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        //$ext = substr(strrchr($file['name'],"."),1);

        $typeAllow = array('jpg', 'jpeg', 'gif', 'png');

        if( in_array($ext, $typeAllow) ){
            //严格检测
            $imginfo = getimagesize($file['tmp_name']);
            if(empty($imginfo) || ($ext == 'gif' && empty($imginfo['bits']))){
                $data['status'] = 0;
                $data['info'] = '非法图像文件!';  
                return $data;
            }
        }else{
           $data['status'] = 0;
           $data['info'] = '文件类型不符!只接受'.implode(',',$typeAllow).'类型图片!';
           return $data;
        }

        //存储
        $time = uniqid('upload_');

        if( !is_dir($savepath) ){
            if( !mkdir($savepath, 0777, true) ){
                $data['status'] = 0;
                $data['info'] = '上传目录不存在或不可写!请尝试手动创建:'.$savepath;
                return $data;
            }
        }else{
            if( !is_writable($savepath) ){
                $data['status'] = 0;
                $data['info'] = '上传目录不可写!:'.$savepath;
                return $data;
            }
        }

        $filename = $time .'.'. $ext;
        $upfile = $savepath . $filename;

        if(is_uploaded_file($file['tmp_name'])){  
            if(!move_uploaded_file($file['tmp_name'], $upfile)){  
                $data['status'] = 0;
                $data['info'] = '移动文件失败!';  
                return $data;
            }else{
                $data['status'] = 1;
                $data['info'] = '成功';   

                $arr = getimagesize( $upfile );
                $strarr = explode("\"",$arr[3]);//分析图片宽高

                $data['data'] = array(
                    'path'=> '/'.$path.$filename,
                    'name'=>$filename,
                    'width'=>$strarr[1],
                    'height'=>$strarr[3]
                    //'url'=>$rootUrl.$path.$filename
                );

                return $data;
            }  
        }else{  
            $data['status'] = 0;
            $data['info'] = '文件丢失或不存在';  
            return $data;
        }  
    }
}













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值