天天看点

cropper.js基础上,添加压缩图片功能,可选原图或截图,上传

原本在网上找的截图插件已经可以满足截图需求了,但是后面,需求又增加了。要有图片压缩的功能,还有能选原图或者截图。所以把代码改了一下(后续可能还会修改):

引入CSS、JS:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropper/3.1.3/cropper.min.css" target="_blank" rel="external nofollow" >
<script src="https://cdn.bootcss.com/jquery/2.1.0-beta3/jquery.min.js"></script>
<script src="http://malsup.github.io/jquery.form.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropper/3.1.3/cropper.min.js"></script>
           

CSS:

@charset 'utf-8';

.btn {
    display: inline-block;
    text-align: center;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    padding: 6px 12px;
    background: transparent;
    border: 0;
    border-radius: 4px;
}

.btn-demo {
    height: 35px;
    background-color: #d9534f;
    border: #d9534f;
    color: #fff;
    /*margin: 20px;*/
}

.update-bg {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background-color: rgba(0, 0, 0, 0.5);
    display: none;
}

.update-bg .btn {
    display: inline-block;
    text-align: center;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    padding: 6px 12px;
    background: transparent;
    border: 0;
    border-radius: 4px;
}

.update-bg .clearfix:after {
    display: block;
    content: '';
    clear: both;
}

.update-bg .update-wrapper {
    position: relative;
    margin: 50px auto;
    width: 900px;
    min-height: 580px;
    background-color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.2);
    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
    border-radius: 6px;
}

.update-bg .update-wrapper .update-header {
    padding: 15px;
    min-height: 20px;
    border-bottom: 1px solid #e5e5e5;
}

.update-bg .update-wrapper .update-header .text {
    font-size: 18px;
    font-weight: 500;
    float: left;
}

.update-bg .update-wrapper .update-header .close {
    float: right;
    padding: 0;
    font-size: 22px;
    color: #000;
    text-shadow: 0 1px 0 #fff;
    font-weight: bold;
    opacity: .2;
}

.update-bg .update-wrapper .update-main {
    padding: 15px 30px;
}

.update-bg .update-wrapper .update-main .update-btn {
    height: 35px;
    background-color: #d9534f;
    border: #d9534f;
    color: #fff;
}

.update-bg .update-wrapper .update-main .update-body {
    margin-top: 15px;
}

.update-bg .update-wrapper .update-main .update-body .body-left {
    float: left;
    width: 620px;
    height: 360px;
    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.25);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.25);
    background-color: #fcfcfc;
    overflow: hidden;
}

.update-bg .update-wrapper .update-main .update-body .body-left .update-img {
    display: none;
}

.update-bg .update-wrapper .update-main .update-body .body-right {
    float: right;
    width: 180px;
    height: 180px;
    border: 1px solid #eee;
    border-radius: 4px;
    background-color: #fff;
    overflow: hidden;
}

.update-bg .update-wrapper .update-main .update-body .body-right .user-header {
    display: none;
}

.update-bg .update-wrapper .update-main .operation-wrapper {
    margin-top: 15px;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left {
    float: left;
    width: 620px;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left .btn {
    height: 35px;
    background-color: #d9534f;
    border: #d9534f;
    color: #fff;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left .left-container {
    float: left;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left .left-container .btn {
    margin-right: 10px;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left .right-container {
    float: right;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-left .right-container .btn {
    margin-left: 10px;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-right {
    float: right;
    width: 180px;
}

.update-bg .update-wrapper .update-main .operation-wrapper .operation-right .btn {
    width: 100%;
    height: 35px;
    background-color: #d9534f;
    border: #d9534f;
    color: #fff;
}

.pic-cont {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 180px;
    height: 180px;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}
#J-user-header-img {
    width: auto;
    height: 100%;
}
.btn-demo {
    display: flex;
    margin-top: 10px;
}

           

HTML:

<!-- 上传图片-截图 -->
<div class="pic-cont">
    <img src="" alt="" id="J-user-header-img">
</div>
<button class="btn btn-demo" id="J-demo">上传图片</button>

<div class="update-bg" id="J-update-wrapper">
    <input type="file" id="J-update-img-file" style="display: none">
    <div class="update-wrapper">
        <div class="update-header clearfix">
            <h3 class="text">上传图片</h3>
            <button class="btn close J-close">x</button>
        </div>
        <div class="update-main">
            <button class="btn update-btn J-update-btn">请选择图片</button>
            <div class="update-body clearfix">
                <div class="body-left">
                    <img id="J-update-img" class="update-img" src="" alt="">
                </div>
                <div class="body-right">
                    <img src="" class="user-header" id="J-update-user-header">
                </div>
            </div>
            <div class="operation-wrapper clearfix">
                <div class="operation-left">
                    <div class="left-container">
                        <button class="btn J-operation-btn" data-type="rote-left">向左旋转</button>
                        <button class="btn J-operation-btn" data-type="rote-right">向右旋转</button>
                        <input id="artwork" name="img" type="radio" value="" checked="checked" /> 原图
                        <input id="cropper" name="img" type="radio" value="" /> 截图
                    </div>
                    <div class="right-container">
                        <button class="btn J-operation-btn" data-type="scale-b">放大</button>
                        <button class="btn J-operation-btn" data-type="scale-s">缩小</button>
                    </div>
                </div>
                <div class="operation-right">
                    <button class="btn J-operation-save">保存图片</button>
                </div>
            </div>
        </div>
    </div>
</div>
           

JS:

'use strict';

var _createClass = function () {
    function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }
    return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);
        if (staticProps) defineProperties(Constructor, staticProps);
        return Constructor;
    };
}();

function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

var imgInfo = {
    width: null,
    height: null,
    rotate: 0,
    scale: 1
};

var imgArtwork = ''

var cropperIng = void 0;
// jq对象 cropper的宿主
var cropperTarget = void 0;
// jq对象 裁剪实时呈现的效果图像
var userImg = void 0;
// 裁剪图片功能封装类

var UpdateCropper = function () {
    // 回调方法
    function UpdateCropper(callBack) {
        _classCallCheck(this, UpdateCropper);

        this.callBack = callBack;
    }

    _createClass(UpdateCropper, [{
        key: 'init',
        value: function init() {
            imgInfo.width = null;
            imgInfo.height = null;
            imgInfo.rotate = 0;
            imgInfo.scale = 1;
            cropperIng = false;
            cropperTarget = $('#J-update-img');
            userImg = $('#J-update-user-header');
            $('#J-update-wrapper').fadeIn('slow');
            this.addEvent();
        }
    }, {
        key: 'addEvent',
        value: function addEvent() {
            var _this2 = this;

            var _this = this;
            $('#J-update-img-file').on('change', function (e) {
                if (!this.files[0] || !window.FileReader) return
                if (this.files[0].type !== 'image/jpeg') {
                    alert('请选择jpg格式的图片!');
                    return
                }
                // 创建一个reader
                const reader = new FileReader()
                const that = this
                // 将图片转成base64格式
                reader.readAsDataURL(this.files[0])
                // 读取成功后的回调
                reader.onloadend = function () {
                    const result = this.result
                    const img = new Image()
                    img.src = result
                    console.log("********未压缩前的图片大小********")
                    console.log(result)
                    console.log(result.length)

                    img.onload = function () {
                        const data = compress(img, 0.1) // - 图片质量:取值范围为0到1
                        console.log("********压缩后的图片大小********")
                        console.log(data)
                        console.log(data.length)

                        var imgSrc = data
                        imgArtwork = data
                        _this.createCropper(imgSrc)
                    }

                }
            });
            $('#J-update-wrapper').on('click', '.J-close', function () {
                _this2.destroy();
            });
            $('#J-update-wrapper').on('click', '.J-update-btn', function () {
                document.getElementById('J-update-img-file').click();
            });
            // 操作按钮
            $('#J-update-wrapper').on('click', '.J-operation-btn', function () {
                _this.operation($(this));
            });
            $('#J-update-wrapper').on('click', '.J-operation-save', function () {
                _this2.getCroppedCanvas();
            });
            // J-close
        }
    }, {
        key: 'destroy',
        value: function destroy() {
            this.removeEvent();
            cropperTarget.cropper('destroy');
            userImg.attr('src', '').hide();
            cropperTarget.attr('src', '').hide();
            $('#J-update-wrapper').fadeOut('slow');
            // $('#J-update-wrapper').hide();
        }
    }, {
        key: 'removeEvent',
        value: function removeEvent() {
            $('#J-update-img-file').off();
            $('#J-update-wrapper').off();
        }
        /**
         * 创建cropper容器 巴拉巴拉
         * @param {string} src 
         */

    }, {
        key: 'createCropper',
        value: function createCropper(src) {
            var _this3 = this;

            document.getElementById('J-update-img').onload = function () {
                var elem = document.getElementById('J-update-img');
                // 获取图片真实宽高,用于后期比例计算
                imgInfo.width = elem.naturalWidth;
                imgInfo.height = elem.naturalHeight;
                userImg.attr('src', src).show();
                cropperIng = true;
                cropperTarget.cropper('destroy');
                cropperTarget.cropper({
                    aspectRatio: 9 / 9, // 类型:Number,默认值NaN。设置剪裁容器的比例
                    viewMode: 1,
                    // 创建 用户操作都会改变显示对象
                    crop: function crop(e) {
                        // console.log('=.=', e)
                        _this3.changeImg(e);
                    }
                });
            };
            cropperTarget.attr('src', src).show();
        }
        // 右侧显示对象改变

    }, {
        key: 'changeImg',
        value: function changeImg(detail) {
            // console.log('====', detail)
            var num = 180 / detail.width;
            userImg.css({
                transform: 'translate(-' + detail.x * num + 'px, -' + detail.y * num + 'px) rotate(' + imgInfo.rotate + 'deg)',
                width: imgInfo.width * num + 'px',
                height: imgInfo.heigh * num + 'px'
            });
        }
        // 操作方法

    }, {
        key: 'operation',
        value: function operation(target) {
            if (!cropperIng) {
                return;
            }
            var type = target.data('type');
            switch (type) {
                case 'rote-left':
                    imgInfo.rotate -= 90;
                    $('#J-update-img').cropper('rotate', -90);
                    break;
                case 'rote-right':
                    imgInfo.rotate += 90;
                    $('#J-update-img').cropper('rotate', 90);
                    break;
                case 'scale-b':
                    $('#J-update-img').cropper('zoom', 0.1);
                    break;
                case 'scale-s':
                    $('#J-update-img').cropper('zoom', -0.1);
                    break;
            }
        }
        // 转换成base64输出

    }, {
        key: 'getCroppedCanvas',
        value: function getCroppedCanvas() {
            if (!cropperIng) {
                return;
            }
            console.log('...', imgArtwork)
            var base64 = ''
            // 原图
            if (!$("#artwork[type='radio']").is(':checked')) {
                var cas = cropperTarget.cropper('getCroppedCanvas');
                base64 = cas.toDataURL('image/jpeg');
                this.callBack(base64);
                this.destroy();
            } else {
                base64 = imgArtwork;
                this.callBack(base64);
                this.destroy();
            }

            const blob = dataURItoBlob(base64)
            const formData = new FormData()
            var nameImg = new Date().getTime() + '.jpg'
            formData.append('file', blob, nameImg)
            var uploadUrl = '' // 上传图片接口地址
            // 请求后台接口
            $.ajax({
                url: uploadUrl,
                type: "POST",
                data: formData,
                success: function (data) {
                    console.log(data)
                }
            })
        }
    }]);

    return UpdateCropper;
}();

// 压缩图片
function compress(img, compressNum) {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const width = img.width
    const height = img.height
    canvas.width = width
    canvas.height = height
    // 铺底色
    ctx.fillStyle = '#fff'
    ctx.fillRect(0, 0, canvas.width, canvas.height)
    ctx.drawImage(img, 0, 0, width, height)

    // 进行压缩 compressNum - 图片质量:取值范围为0到1
    const ndata = canvas.toDataURL('image/jpeg', compressNum)
    return ndata
}

// base64转成bolb对象
function dataURItoBlob(base64Data) {
    var byteString
    if (base64Data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(base64Data.split(',')[1])
    } else {
        byteString = unescape(base64Data.split(',')[1])
    }
    var mimeString = base64Data
        .split(',')[0]
        .split(':')[1]
        .split(';')[0]
    var ia = new Uint8Array(byteString.length)
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i)
    }
    return new Blob([ia], {
        type: mimeString
    })
}
           

点击时调用:

// 上传图片-截图
var update;
$('#J-demo').click(function () {
    if (!update) {
        update = new UpdateCropper((base64url) => {
            $('#J-user-header-img').attr('src', base64url);
        });
    }
    update.init();
});