天天看點

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();
});