【jQuery插件】使用cropper完成简单的头像裁剪并上传

插件介绍

那是1个本身在写在此以前的花色的中途发现的一个同胞写的jQuery图像裁剪插件,当时想完毕用户资料的头像上传效用,并且能够预览图片,和对图纸展开简要的剪裁、旋转,花了重重时日才看到了这些插件,感觉效果挺全面,代码达成起来也挺不难,再加上用的是Bootstrap,对移动端操作也有适配,于是就用了。今后不怎么有点时间就记录一下,方便未来再用的时候查阅。其余也有照应的js版本。

官方文书档案(英文)

兼容性

匹配全数支持了Canvas的浏览器(IE9+),一小部分效率不一,具体请查看官方文书档案。

参数

viewMode

  • Type: Number
  • Default: 0
  • Options: 0,1,2,3

其一具体每种值对应的法力自身也不是很精通,推荐在上头的法定示例里都试一试,小编都以比较喜欢2。

dragMode

  • Type: String
  • Default: 'crop'
  • Options:
    • 'crop': 在裁剪框外拖动鼠标会转移2个新的裁剪框。
    • 'move': 在裁剪框外拖动鼠标会活动原图。
    • 'none': 在裁剪框外拖动鼠标则什么也不做。

aspectRatio

  • Type: Number
  • Default: NaN

以此是裁剪框的纵横比,暗中认可是不限量的。例如1:1的头像就写1,16:9可写成16 / 9

data

  • Type: Object
  • Default: null

The previous cropped data if you had stored, will be passed to setData
method automatically.

(没怎么用过,都以一向用setData方法)

preview

  • Type: String (jQuery selector)
  • Default: ''

预览图的职位,用jQuery接纳器表示。

responsive

  • Type: Boolean
  • Default: true

在转移窗口大小后是或不是又一次渲染cropper。

restore

  • Type: Boolean
  • Default: true

在变更窗口大小后是或不是复苏裁剪区域。

checkCrossOrigin

  • Type: Boolean
  • Default: true

自我批评图像是不是是跨域图像。(具体查看官方文书档案)

checkOrientation

  • Type: Boolean
  • Default: true

(具体查看官方文书档案)

modal

  • Type: Boolean
  • Default: true

非裁剪区域是还是不是用黑罩遮盖。

guides

  • Type: Boolean
  • Default: true

剪裁区域是或不是出示虚线。

center

  • Type: Boolean
  • Default: true

剪裁区域正大旨是或不是出示+号。

highlight

  • Type: Boolean
  • Default: true

剪裁区域是还是不是高亮显示。

background

  • Type: Boolean
  • Default: true

是还是不是出示背景的黑白方格(类似PS里透明图层的展现方式)。

autoCrop

  • Type: Boolean
  • Default: true

cropper初步化完成后是或不是自动突显裁剪框

autoCropArea

  • Type: Number
  • Default: 0.8 (80% of the image)

电动展现的裁剪框的轻重。由此,数字应该在0~1之间。

movable

  • Type: Boolean
  • Default: true

是不是同意移动原图。(假如那里填false那正是说即使dragMode的值是move,在裁剪框外拖动也不会移动原图)

rotatable

  • Type: Boolean
  • Default: true

是还是不是足以旋转原图。

scalable

  • Type: Boolean
  • Default: true

是不是足以对原图实行纵横拉伸。

比如说把原图宽度增加为原本的2倍也许增长为原本的-1倍(即水平翻转)。

zoomable

  • Type: Boolean
  • Default: true

是或不是能够对原图进行裁减放大。

zoomOnTouch

  • Type: Boolean
  • Default: true

是还是不是同目的在于活动端上采纳双指触摸缩放原图。

zoomOnWheel

  • Type: Boolean
  • Default: true

是不是同意利用鼠标滚轮缩放原图。

wheelZoomRatio

  • Type: Number
  • Default: 0.1

当使用鼠标滚轮缩放时的比例。

cropBoxMovable

  • Type: Boolean
  • Default: true

是或不是允许移动裁剪框。

cropBoxResizable

  • Type: Boolean
  • Default: true

是否允许通过拖动裁剪框的边框来调整裁剪框的尺寸。

toggleDragModeOnDblclick

  • Type: Boolean
  • Default: true

是不是同意通过双击来在cropmove中间切换dragMode

minContainerWidth

  • Type: Number
  • Default: 200

容器宽度最小值。

minContainerHeight

  • Type: Number
  • Default: 100

容器中度最小值。

minCanvasWidth

  • Type: Number
  • Default: 0

canvas(原图)宽度最小值。

minCanvasHeight

  • Type: Number
  • Default: 0

canvas(原图)中度最小值。

minCropBoxWidth

  • Type: Number
  • Default: 0

划分框宽度最小值。

Note: This size is relative to the page, not the image.

minCropBoxHeight

  • Type: Number
  • Default: 0

细分框中度最小值。

Note: This size is relative to the page, not the image.

ready

  • Type: Function
  • Default: null

A shortcut of the “ready” event.

cropstart

  • Type: Function
  • Default: null

A shortcut of the “cropstart” event.

cropmove

  • Type: Function
  • Default: null

A shortcut of the “cropmove” event.

cropend

  • Type: Function
  • Default: null

A shortcut of the “cropend” event.

crop

  • Type: Function
  • Default: null

A shortcut of the “crop” event.

zoom

  • Type: Function
  • Default: null

A shortcut of the “zoom” event.

常用方法

除外”setAspectRatio”,”replace”和”destroy”以外,全体的办法都要在ready后才能采用。那里只介绍多少个常用的点子,全体的主意请到官方文书档案查阅。

措施的应用格式为

$().cropper('method',arg0,arg1,arg2,...);

crop()

手动突显裁剪框。

$().cropper({
  autoCrop: false,
  ready: function () {
    // Do something here
    // ...

    // And then
    $(this).cropper('crop');
  }
});

reset()

平复全部到起来状态。

replace(url[, onlyColorChanged])

  • url:
  • Type: String
  • A new image url.

  • onlyColorChanged (optional):

  • Type: Boolean
  • If only change the color, not the size, then the cropper only need
    to change the srcs of all related images, not need to rebuild the
    cropper. This can be used for applying filters.
  • If not present, its default value is false.

轮换cropper中的图像文件,经常第①个参数不管。

destroy()

销毁cropper,并且会移除img标签的src属性的值。

getCroppedCanvas([options])

  • options (optional):
    • Type: Object
    • Properties:
      • width: the destination width of the output canvas.
      • height: the destination height of the output canvas.
      • minWidth: the minimum destination width of the output
        canvas, the default value is 0.
      • minHeight: the minimum destination height of the output
        canvas, the default value is 0.
      • maxWidth: the maximum destination width of the output
        canvas, the default value is Infinity.
      • maxHeight: the maximum destination height of the output
        canvas, the default value is Infinity.
      • fillColor: a color to fill any alpha values in the output
        canvas, the default value is transparent.
      • imageSmoothingEnabled:
        set to change if images are smoothed (true, default) or
        not (false).
      • imageSmoothingQuality:
        set the quality of image smoothing, one of “low” (default),
        “medium”, or “high”.
  • (return value):
    • Type: HTMLCanvasElement
    • A canvas drawn the cropped image.
  • Notes:
    • 输出的canvas的纵横比会自动适应于裁剪框的纵横比.
    • 设若打算得到JPEG图像,那么相应先安装fillColor参数,否则裁剪后的透明部分暗许会由铁黄填充。
  • Browser support:

收获裁剪到的图像的canvas,如若没有裁剪,那么就赶回的是一切原图图像的canvas。

那是最要紧的3个艺术,通过这一个办法就能够博得裁剪后的图像,再采用toDataURL()得到base64
dataUTiggoL(不点名格式的话会是png格式)可能toBlob()收获Blob,然后就足以很自在地将图片上传至服务器上大概呈现在有些img标签中了。例如:

// 转换为png格式的dataURL
var dataURL = $().cropper('getCroppedCanvas', {
    width:100,
    height:100
}).toDataURL('image/png');

// 转换为Blob后显示在img标签中
var URL = window.URL || window.webkitURL;
$().cropper('getCroppedCanvas', {
    width:100,
    height:100
}).toBlob(function (blob) {
    $().attr('src',URL.createObjectURL(blob));
});

粗略实例

在页面一贯行使cropper

接下去只是实现二个简练的作用:网页中能够上传图片,然后对图纸展开裁剪,点击分明后会彰显出裁剪后的图形。

代码如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>裁剪图片</title>
<link href="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
        .row{
            margin-bottom: 5px;
        }
        #photo {
            max-width: 100%;
        }
        .img-preview {
            width: 100px;
            height: 100px;
            overflow: hidden;
        }
        button {
            margin-top:10px;
        }
        #result {
            width: 150px;
            height: 150px;
        }
</style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm-12 text-center">
            <label for="input" class="btn btn-danger" id="">
            选择图片
            <input type="file" id="input" class="sr-only">
            </label>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-6 col-sm-offset-2">
            <img src="" id="photo">
        </div>
        <div class="col-sm-2">
            <div>
                <p>
                    预览(100*100):
                </p>
                <div class="img-preview">
                </div>
            </div>
            <button class="btn btn-primary" onclick="crop()">裁剪图片</button>
            <div>
                <br/>
                <p>
                    结果:
                </p>
                <img src="" alt="裁剪结果" id="result">
            </div>
        </div>
    </div>
</div>
<!-- Scripts -->
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
        // 修改自官方demo的js
        var initCropper = function (img, input){
            var $image = img;
            var options = {
                aspectRatio: 1, // 纵横比
                viewMode: 2,
                preview: '.img-preview' // 预览图的class名
            };
            $image.cropper(options);
            var $inputImage = input;
            var uploadedImageURL;
            if (URL) {
                // 给input添加监听
                $inputImage.change(function () {
                    var files = this.files;
                    var file;
                    if (!$image.data('cropper')) {
                        return;
                    }
                    if (files && files.length) {
                        file = files[0];
                        // 判断是否是图像文件
                        if (/^image\/\w+$/.test(file.type)) {
                            // 如果URL已存在就先释放
                            if (uploadedImageURL) {
                                URL.revokeObjectURL(uploadedImageURL);
                            }
                            uploadedImageURL = URL.createObjectURL(file);
                            // 销毁cropper后更改src属性再重新创建cropper
                            $image.cropper('destroy').attr('src', uploadedImageURL).cropper(options);
                            $inputImage.val('');
                        } else {
                          window.alert('请选择一个图像文件!');
                      }
                  }
              });
            } else {
                $inputImage.prop('disabled', true).addClass('disabled');
            }
        }
        var crop = function(){
            var $image = $('#photo');
            var $target = $('#result');
            $image.cropper('getCroppedCanvas',{
                width:300, // 裁剪后的长宽
                height:300
            }).toBlob(function(blob){
                // 裁剪后将图片放到指定标签
                $target.attr('src', URL.createObjectURL(blob));
            });
        }
        $(function(){
            initCropper($('#photo'),$('#input'));
        });
    </script>
</body>
</html>

图片 1

在bootstrap模态框中使用cropper

就算在模态框中能够像上边一样使用cropper,甚至本身从前写的花色也是跟下边一样,可是此次整治的时候猛然意识了二个bug:当隐藏模态框后调整浏览器大小(甚至按f12),再打开模态框后cropper的容器会转移,导致难以使用。于是,小编在GitHub中翻找了issue,在合法的example中找到了对应的化解措施。但骨子里这一个化解情势也是一种暴力解法,即模态框隐藏后绝迹cropper,打开后再一次成立cropper,恐怕会有其他办法,因为不明确会不会有其余bug,所以一时如故用合法的法门相比好。

代码如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>上传头像</title>
<link href="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
    body{
        text-align: center;
    }
    #user-photo {
        width:300px;
        height:300px;
        margin-top: 10px;
    }
    #photo {
        max-width:100%;
        max-height:350px;
    }
    .img-preview-box {
        text-align: center;
    }
    .img-preview-box > div {
        display: inline-block;;
        margin-right: 10px;
    }
    .img-preview {
        overflow: hidden;
    }
    .img-preview-box .img-preview-lg {
        width: 150px;
        height: 150px;
    }
    .img-preview-box .img-preview-md {
        width: 100px;
        height: 100px;
    }
    .img-preview-box .img-preview-sm {
        width: 50px;
        height: 50px;
        border-radius: 50%;
    }
</style>
</head>
<body>
<button class="btn btn-primary" data-target="#changeModal" data-toggle="modal">打开</button><br/>
<div class="user-photo-box">
    <img id="user-photo" src="">
</div>
</div>
<div class="modal fade" id="changeModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title text-primary">
            <i class="fa fa-pencil"></i>
                        更换头像
            </h4>
        </div>
        <div class="modal-body">
            <p class="tip-info text-center">
                未选择图片
            </p>
            <div class="img-container hidden">
                <img src="" alt="图片 2" id="photo">
            </div>
            <div class="img-preview-box hidden">
                <hr>
                150*150:
                <div class="img-preview img-preview-lg">
                </div>
                100*100:
                <div class="img-preview img-preview-md">
                </div>
                30*30:
                <div class="img-preview img-preview-sm">
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <label class="btn btn-danger pull-left" for="photoInput">
            <input type="file" class="sr-only" id="photoInput" accept="image/*">
            打开图片
            </label>
            <button class="btn btn-primary disabled" disabled="true" onclick="sendPhoto();">提交</button>
            <button class="btn btn-close" aria-hidden="true" data-dismiss="modal">取消</button>
        </div>
    </div>
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
        var initCropperInModal = function(img, input, modal){
            var $image = img;
            var $inputImage = input;
            var $modal = modal;
            var options = {
                aspectRatio: 1, // 纵横比
                viewMode: 2,
                preview: '.img-preview' // 预览图的class名
            };
            // 模态框隐藏后需要保存的数据对象
            var saveData = {};
            var URL = window.URL || window.webkitURL;
            var blobURL;
            $modal.on('show.bs.modal',function () {
                // 如果打开模态框时没有选择文件就点击“打开图片”按钮
                if(!$inputImage.val()){
                    $inputImage.click();
                }
            }).on('shown.bs.modal', function () {
                // 重新创建
                $image.cropper( $.extend(options, {
                    ready: function () {
                        // 当剪切界面就绪后,恢复数据
                        if(saveData.canvasData){
                            $image.cropper('setCanvasData', saveData.canvasData);
                            $image.cropper('setCropBoxData', saveData.cropBoxData);
                        }
                    }
                }));
            }).on('hidden.bs.modal', function () {
                // 保存相关数据
                saveData.cropBoxData = $image.cropper('getCropBoxData');
                saveData.canvasData = $image.cropper('getCanvasData');
                // 销毁并将图片保存在img标签
                $image.cropper('destroy').attr('src',blobURL);
            });
            if (URL) {
                $inputImage.change(function() {
                    var files = this.files;
                    var file;
                    if (!$image.data('cropper')) {
                        return;
                    }
                    if (files && files.length) {
                        file = files[0];
                        if (/^image\/\w+$/.test(file.type)) {

                            if(blobURL) {
                                URL.revokeObjectURL(blobURL);
                            }
                            blobURL = URL.createObjectURL(file);

                            // 重置cropper,将图像替换
                            $image.cropper('reset').cropper('replace', blobURL);

                            // 选择文件后,显示和隐藏相关内容
                            $('.img-container').removeClass('hidden');
                            $('.img-preview-box').removeClass('hidden');
                            $('#changeModal .disabled').removeAttr('disabled').removeClass('disabled');
                            $('#changeModal .tip-info').addClass('hidden');

                        } else {
                            window.alert('请选择一个图像文件!');
                        }
                    }
                });
            } else {
                $inputImage.prop('disabled', true).addClass('disabled');
            }
        }
    }

    var sendPhoto = function(){
        $('#photo').cropper('getCroppedCanvas',{
            width:300,
            height:300
        }).toBlob(function(blob){
            // 转化为blob后更改src属性,隐藏模态框
            $('#user-photo').attr('src',URL.createObjectURL(blob));
            $('#changeModal').modal('hide');
        });
    }

    $(function(){
        initCropperInModal($('#photo'),$('#photoInput'),$('#changeModal'));
    });
</script>
</body>
</html>

图片 3

图片 4

使用cropper来上传图片到服务器

鉴于cropper能够获取三种裁剪后图片的数码(即blob和dataU奇骏L),所以对应的上传到后台也会有二种格局,在这里作者只写一种选取ajax上传base64
dataU本田UR-VL的,另一种办法假设有趣味,能够友善尝尝。

页面中,将地点的sendPhoto方法改为:

var sendPhoto = function () {
    // 得到PNG格式的dataURL
    var photo = $('#photo').cropper('getCroppedCanvas', {
        width: 300,
        height: 300
    }).toDataURL('image/png');

    $.ajax({
        url: '上传地址', // 要上传的地址
        type: 'post',
        data: {
            'imgData': photo
        },
        dataType: 'json',
        success: function (data) {
            if (data.status == 0) {
                // 将上传的头像的地址填入,为保证不载入缓存加个随机数
                $('.user-photo').attr('src', '头像地址?t=' + Math.random());
                $('#changeModal').modal('hide');
            } else {
                alert(data.info);
            }
        }
    });
}

后德雷斯顿,Java的重庆大学代码如下:(使用了jdk8的Base64,,假设是低版本请自行替换)

    /**
     * 将Base64位编码的图片进行解码,并保存到指定目录
     */
    public static void decodeBase64DataURLToImage(String dataURL, String path, String imgName) throws IOException {
        // 将dataURL开头的非base64字符删除
        String base64 = dataURL.substring(dataURL.indexOf(",") + 1);
        FileOutputStream write = new FileOutputStream(new File(path + imgName));
        byte[] decoderBytes = Base64.getDecoder().decode(base64);
        write.write(decoderBytes);
        write.close();
    }

小结

cropper能做到的业务还广大,那里只是简短利用了须臾间,更加多职能能够在有想法的再切磋下。

那是针对从前项目用的cropper的三个整理,结果因为那前卫未看官方例子,途中发现了在模态框中使用的3个bug,现在会专注那上头。此外,整理这一部分资料时也参照了很多的互联网资料,在那里就不一一记录了。

最后,由于自身能力有限,若发现错误希望能建议,本人会及时改良,万分感激。

相关文章