Bootstrap【jQuery插件】使用cropper实现简单的头像裁剪并臻传

插件介绍

眼看是一个本人在描写以前的路之路上发现的一个国人写的jQuery图像裁剪插件,当时想实现用户资料之头像上传功能,并且能够预览图,和对图纸展开简短的剪裁、旋转,花了成百上千工夫才看了是插件,感觉功能很圆,代码实现起来吧充分简单,再加上用的是Bootstrap,对移动端操作也来适配,于是就因此了。现在稍微有些时间就记录转,方便以后还就此底时光翻。另外呢产生相应的js版本。

法定文档(英文)

  • jQuery
    • GitHub项目地址
    • 官示例
  • js
    • GitHub项目地址

兼容性

配合所有支持了Canvas的浏览器(IE9+),一微片功能差,具体要查看官方文档。

参数

viewMode

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

斯实际每个值对应之功用自己吧无是死清楚,推荐以点的官方示例里还尝试一摸索,我还是比较喜欢2。

dragMode

  • Type: String
  • Default: 'crop'
  • Options:
    • 'crop': 在推框外拖动鼠标会生成一个初的裁剪框。
    • '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:
    • Basic image: requires Canvas
      support (IE 9+).
    • Rotated image: requires CSS3 2D
      Transforms support (IE 9+).
    • Cross-origin image: requires HTML5 CORS settings
      attributes
      support (IE 11+).

抱裁剪到的图像的canvas,如果无裁剪,那么就返回的凡举原图图像的canvas。

立刻是最好要的一个方,通过是措施就得博裁剪后的图像,再使用toDataURL()收获base64
dataURL(不点名格式的言辞会是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>

Bootstrap 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="Bootstrap 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>

Bootstrap 3

Bootstrap 4

使cropper来达到传图片及服务器

由cropper可以取得两种植裁剪后图片的多少(即blob和dataURL),所以对应的上传到后台也会有些许种植方式,在此处自己才写一栽采取ajax上传base64
dataURL的,另一样种植艺术要生趣味,可以自己尝尝。

页面被,将方面的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的一个理,结果以那儿尚无看官方例子,途中发现了在模态框中使用的一个bug,以后会小心就上头。另外,整理这有的素材时也参照了成百上千的网资料,在此处就不一一记录了。

末,由于自身能力有限,若发现错误希望能指出,本人会立即改正,非常感谢。

相关文章