LMLPHP后院

基于JavaScript在线头像图片编辑前端后台实现技术

maybe yes 发表于 2014-12-12 10:58

前端使用Jcrop实现预览和获取图片大小,选定位置等信息。关于Jcrop,项目地址在GITHUB上,它基于MIT开源协议。本人看了下项目的源代码,感觉作者蛮认真的。Jcrop做到了兼容IE系列和其他主流浏览器,非常稳定,让开发者不再为前端方面花费太多精力。加上本人不太喜欢Flash实现,纯JavaScript实现的功能效率会更高。由于时间比较仓促,代码没有过多的优化,有点乱,下面公布前端实现和服务端处理图片部分代码。

前端实现方式如下:

<link rel="stylesheet" href=".../jcrop/tapmodo-Jcrop-1902fbc/css/jquery.Jcrop.css">
<script src=".../jcrop/tapmodo-Jcrop-1902fbc/js/jquery.min.js"></script>
<script src=".../jcrop/tapmodo-Jcrop-1902fbc/js/jquery.Jcrop.js"></script>
<style>
#preview-pane{
    background-color: white;
    border: 1px solid rgba(0, 0, 0, 0.4);
    border-radius: 6px;
    box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
    display: none;
    padding: 6px;
    position: absolute;
    right: -160px;
    top: 0;
    z-index: 2000;
}
#preview-pane .preview-container {
    height: 100px;
    overflow: hidden;
    width: 100px;
}
.cropdiv{
    background: none repeat scroll 0 0 #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    box-shadow: 0 20px 20px rgba(0, 0, 0, 0.3);
    height: auto;
    left: 200px;
    opacity: 0.9;
    position: absolute;
    top: 230px;
    width: 600px;
    z-index: 100;
    padding:10px;
}

.cropdiv .preinfo{
    float: right;
    left: 500px;
    position: absolute;
    top: 160px;
}
.cropdiv .title{
    font-size:14px;
    font-weight:bold;
    margin-bottom:10px;
}
.cropdiv .save{
    text-align:center;
}
.cropdiv .save a{
    background-color: #ff832b;
    border-radius: 4px;
    color: #fff;
    display: inline-block;
    height: 30px;
    padding:2px 5px;
    font-size:16px;
    margin:5px;
}
</style>
<script>
var startcrop = function( imgsrc ) {
    var jcrop_api, boundx, boundy, posinfo,
    imgsrc_rand = imgsrc + '?' + Math.round(Math.random() * 10000);

    // Grab some information about the preview pane    
    var $preview_html = 
        '<div id="preview-pane">'
            +'<div class="preview-container">'
            +'<img src="" class="jcrop-preview" alt="Preview">'
            +'</div>'
        +'</div>';
    
    $(document.body).append($preview_html);
    var $preview = $('#preview-pane'),
    $pcnt = $('#preview-pane .preview-container'),
    $pimg = $('#preview-pane .preview-container img'),

    xsize = $pcnt.width(),
    ysize = $pcnt.height();
    $pimg.attr('src',imgsrc_rand);
    
    var cropimgdiv = $('<div/>').addClass('cropdiv').css({"opacity":.9})
    .append(function(){
        return $('<div/>').append("<span>编辑头像</span>").addClass('title');;
    })
    .append( function(){
        return $('<img/>').attr( {"src":imgsrc + '?' + Math.round(Math.random() * 10000)
            ,"id":"cropimg"}) 
    })
    .append(function(){
        return $('<div/>').append( $("<a/>").html("保存头像").click(function(){
            $.ajax({
                type:'POST',
                url: 'handle crop url',
                dataType:'json',
                data:{ 'posinfo':posinfo, "boundx":boundx, "boundy":boundy },
                success:function( data ) {
                    // do something on success
                    cropimgdiv.remove();
                    $preview.remove();
                }
            });
        }) ).addClass('save');
    })
    .appendTo(document.body);
    
    if ($("#cropimg").get(0).naturalWidth > 400) {
        $("#cropimg").attr({"width":400});
        JcropRun();
    } else { // IE6/7/8
        var image = new Image()
        image.src = imgsrc_rand;
        image.onload = function(){
            if( image.width > 400){
                $("#cropimg").attr({"width":400});
            }
            JcropRun();
        };
    } 

    function showCoords(c)
    {
        /* variables can be accessed here as
        // c.x, c.y, c.x2, c.y2, c.w, c.h*/
        posinfo = c;
        if (parseInt(c.w) > 0) {
            var rx = xsize / c.w;
            var ry = ysize / c.h;
            $pimg.css({
                width: Math.round(rx * boundx) + 'px',
                height: Math.round(ry * boundy) + 'px',
                marginLeft: '-' + Math.round(rx * c.x) + 'px',
                marginTop: '-' + Math.round(ry * c.y) + 'px'
            });
        }
    };
    
    var JcropRun = function(){
        $('#cropimg').Jcrop({
            onSelect:    showCoords,
            bgColor:     'black',
            bgOpacity:   .4,
            setSelect:   [ 100, 100, 0, 0 ],
            minSize:   [ 100, 100 ],
            aspectRatio: xsize / ysize
        },function(){
            // Use the API to get the real image size
            var bounds = this.getBounds();
            boundx = bounds[0];
            boundy = bounds[1];
            // Store the API in the jcrop_api variable
            jcrop_api = this;
            $preview.css({"display":"block"});
            // Move the preview into the jcrop container for css positioning
            $preview.appendTo(jcrop_api.ui.holder);
        });
    }
};
</script>

imagecropper方法在网上找的,写的比较差,以后有时间会整理下代码。后台图片处理方式如下:

<?php 

function imagecropper($source_path, $target_width, $target_height)
{
    $source_info   = getimagesize($source_path);
    $source_width  = $source_info[0];
    $source_height = $source_info[1];
    $source_mime   = $source_info['mime'];
    $source_ratio  = $source_height / $source_width;
    $target_ratio  = $target_height / $target_width;

    // 源图过高
    if ($source_ratio > $target_ratio)
    {
        $cropped_width  = $source_width;
        $cropped_height = $source_width * $target_ratio;
        $source_x = 0;
        $source_y = ($source_height - $cropped_height) / 2;
    }
    // 源图过宽
    elseif ($source_ratio < $target_ratio)
    {
        $cropped_width  = $source_height / $target_ratio;
        $cropped_height = $source_height;
        $source_x = ($source_width - $cropped_width) / 2;
        $source_y = 0;
    }
    // 源图适中
    else
    {
        $cropped_width  = $source_width;
        $cropped_height = $source_height;
        $source_x = 0;
        $source_y = 0;
    }

    switch ($source_mime)
    {
        case 'image/gif':
            $source_image = imagecreatefromgif($source_path);
            break;

        case 'image/jpeg':
            $source_image = imagecreatefromjpeg($source_path);
            break;

        case 'image/png':
            $source_image = imagecreatefrompng($source_path);
            break;

        default:
            return false;
            break;
    }

    $target_image  = imagecreatetruecolor($target_width, $target_height);
    $cropped_image = imagecreatetruecolor($cropped_width, $cropped_height);

    // 裁剪
    imagecopy($cropped_image, $source_image, 0, 0, $source_x, $source_y, $cropped_width, $cropped_height);
    // 缩放
    imagecopyresampled($target_image, $cropped_image, 0, 0, 0, 0, $target_width, $target_height, $cropped_width, $cropped_height);

    /* header('Content-Type: image/jpeg'); */
    ob_start();
    imagejpeg( $target_image );
    return ob_get_clean();
    /* imagedestroy($source_image);
    imagedestroy($target_image);
    imagedestroy($cropped_image);
    exit; */
}

$boundx = $_POST['boundx'];
$boundy = $_POST['boundy'];
$posinfo = $_POST['posinfo'];

$realimg = '用户上传后的原图地址';
$resizeimg = imagecropper($realimg, $boundx, $boundy);
file_put_contents($realimg, $resizeimg);
/* 上面完成了图片的大小压缩,下面将图片进行裁剪 */
$source_info   = getimagesize($realimg);
$source_mime   = $source_info['mime'];
switch ($source_mime)
{
    case 'image/gif':
        $source_image = imagecreatefromgif($realimg);
        break;

    case 'image/jpeg':
        $source_image = imagecreatefromjpeg($realimg);
        break;

    case 'image/png':
        $source_image = imagecreatefrompng($realimg);
        break;

    default:
        return false;
        break;
}
$target_image  = imagecreatetruecolor($posinfo['w'], $posinfo['h']);
$cropped_image = imagecreatetruecolor($posinfo['w'], $posinfo['h']);
imagecopy( $cropped_image, $source_image, 0, 0, $posinfo['x'], $posinfo['y'], $posinfo['w'], $posinfo['h'] );
imagecopyresampled($target_image, $cropped_image, 0, 0, 0, 0, $posinfo['w'], $posinfo['h'], $posinfo['w'], $posinfo['h']);
ob_start();
switch( $source_mime ){
    case 'image/gif':
        imagegif( $target_image );
        break;
    case 'image/jpeg':
        imagejpeg( $target_image );
        break;
    case 'image/png':
        imagepng( $target_image );
        break;
    default:
        return false;
}

file_put_contents($realimg, ob_get_clean() );

附上运行截图

JavaScript头像图片编辑运行图-LMLPHP后院

JavaScript头像图片编辑运行图-LMLPHP后院

相关文章
2024-04-25 03:36:25 1713987385 0.010309