1. 程式人生 > 其它 >演示webuploader和cropperjs圖片裁剪上傳

演示webuploader和cropperjs圖片裁剪上傳

最近有個專案要在瀏覽器端裁剪並上傳圖片。由於缺乏人力,只能我上陣殺敵。通過參考各種文章,最後決定用cropperjs進行圖片裁剪,用webuploader上傳檔案。本文涉及到的知識至少有Java基礎、SpringMVC、thymeleaf模版引擎、JS基礎、JQuery基礎、Bootstrap元件,但是文章重點只是cropperjs和webuploader的組合運用,其他的都是輔助。

1. 依賴JS庫

webuploader官網
cropperjs演示主頁
cropperjs開源主頁

2. 核心流程

  • 2.1 選擇檔案按鈕

previewImg用於預覽上傳後的圖片;picker用於選擇圖片,webuploader會自動給picker賦予選擇檔案的特性。fileInput用於接收檔案資料。

<div class="form-group"> 
   <img id="previewImg" width="200px" /> 
   <div> 
    <a href="javascript:void(0)" id="picker">選擇圖片</a> 
    <input type="file" id="fileInput" style="display: none" /> 
   </div> 
  </div>

下面程式碼給fileInput元件觸發了點選事件

    $("#picker").on('click', function () {
        $("#fileInput").trigger("click");
    });
  • 2.2 定義元件引數和事件

以下程式碼定義上傳元件物件

    var uploader = WebUploader.create({
        auto: true,// 選完檔案後,是否自動上傳。
        server: '/upload',
        fileSingleSizeLimit: 2 * 1024 * 1024,
        duplicate: true,
        accept: {// 只允許選擇圖片檔案。
            title: 'Images',
            extensions: 'jpg,jpeg,png',
            mimeTypes: 'image/jpg,image/jpeg,image/png'
        },
        //如果有表單資料要上傳,可以給formData賦值
        formData: {
            id: 0
        }
    });

以下程式碼定義上傳元件事件。WebUploader元件不提供UI,如果需要定製介面,實現下面的方法即可。

    //提交額外的表單資料
    uploader.on('uploadBeforeSend', function (object, data, header) {
        data.id = $('#id').val();
    });

    // 當有檔案被新增進佇列的時候
    uploader.on('fileQueued', function (file) {
        $('#file_list').append('<div id="' + file.id + '" class="item">' +
            '<h4 class="info">' + file.name + '</h4>' +
            '<p class="state">等待上傳...</p>' +
            '</div>');
    });

    // 上傳成功
    uploader.on('uploadSuccess', function (file, response) {
        $('#' + file.id).find('p.state').text('已上傳');
        console.log(response._raw);
        var object = $.parseJSON(response._raw);
        //給預覽元件賦值
        $('#previewImg').attr("src", object.url);
    });

    // 上傳發生錯誤
    uploader.on('uploadError', function (file) {
        $('#' + file.id).find('p.state').text('上傳出錯');
    });

    // 上傳中
    uploader.on('startUpload', function (file, rs) {
        console.log("檔案正在上傳中,請稍候");
    });
  • 2.3 定義裁剪元件引數和事件

以下程式碼定義裁剪圖片的對話方塊,cropperImage是上傳後的圖片,被裁剪的目標物件。

<div class="modal" id="cropperImageModal" tabindex="-1" role="dialog" aria-labelledby="cropperImageModal"
     aria-hidden="true">
    <div class="modal-dialog" style="width: 50%;">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                <h4 class="modal-title">裁剪圖片</h4>
            </div>
            <div class="modal-body">
                <!-- cropperImage是上傳後的圖片,被裁剪的目標物件 -->
                <img src="" id="cropperImage" style="max-width: 100%"/>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal" id="modalClose">關閉</button>
                <button type="button" class="btn btn-primary" id="modalSubmit">儲存</button>
            </div>
        </div>
    </div>
</div>

以下程式碼定義圖片裁剪引數,更多引數參考cropper.js的API詳解。如果不需要固定裁剪區域大小,刪除ready函式即可。

    var cropperImage = $("#cropperImage");
    var cropperOptions = {
        viewMode: 1,
        dragMode: 'none',
        aspectRatio: 1,
        background: false,
        autoCropArea: 0.6,
        crop: function (event) {
            //裁剪的實時事件
            console.log(event.detail.width);
            console.log(event.detail.height);
        },
        ready: function () {
            //限定裁剪區域大小為500
            cropperImage.cropper('crop');
            cropperImage.cropper('setData', {
                width: 500,
                height: 500
            })
        }
    };
  • 2.5 觸發裁剪和上傳事件

fileInput元件的change事件會採用FileReader物件獲得上傳的Image,初始化cropperjs裁剪方法。

    $("#fileInput").on('change', function () {
        var file = this.files[0];
        //定義讀檔案物件
        var reader = new FileReader();
        reader.onload = function () {
            imageOnload(reader.result);

        };
        reader.readAsDataURL(file);//File物件轉換為dataURL
    });

    //圖片物件載入方法
    function imageOnload(url) {
        var cropperImg = new Image();
        cropperImg.src = url;
        //destroy方法是為了重入不出錯
        cropperImage.cropper('destroy').attr('src', url).cropper(cropperOptions);
        cropperImg.onload = function () {
            //彈窗裁剪
            $('#cropperImageModal').modal();
            $("#modalClose").on('click', function () {
                $("#fileInput").val('');
                $('#cropperImageModal').modal('hide');
            });

            $("#modalSubmit").on('click', function () {
                var canVas = $("#cropperImage").cropper("getCroppedCanvas", {});//獲取裁剪後得到的canvas資料
                var file = convertBase64UrlToBlob(canVas.toDataURL('image/jpeg', '0.0'));//將canvas轉換為Blob格式
                uploader.addFiles(file);//將裁剪後的圖片新增進webuploader上傳到後臺
                $('#cropperImageModal').modal('hide');
                $("#fileInput").val('');
            });
        };
    }

採用cropperImage.cropper('getCroppedCanvas').toblob(function(blob){})也可以獲取圖片二進位制物件,但是預設是png格式,體積很大,不利於網路傳輸,採用下面的方法可以指定圖片格式。

    /**
     * base64轉為blob,圖片為jpeg格式
     */
    function convertBase64UrlToBlob(urlData) {
        //去掉url的頭,並轉換為byte
        var bytes = window.atob(urlData.split(',')[1]);
        //處理異常,將ascii碼小於0的轉換為大於0
        var ab = new ArrayBuffer(bytes.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i);
        }
        return new Blob([ab], {type: 'image/jpeg'});
    }
  • 2.6 後端介面實現

@Controller
public class IndexController {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/index")
    public String list(ModelMap map) {
        return "index";
    }

    @PostMapping("/upload")
    @ResponseBody
    public UploadFileVo uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("id") Integer id, HttpServletResponse response) {
        response.setContentType("text/html");
        //儲存圖片到服務端,返回訪問地址
        UploadFileVo uploadFileVo = new UploadFileVo();
        //這裡為了演示,返回一張網圖
        uploadFileVo.setUrl("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
        logger.info("上傳成功,url:{},id:{}", uploadFileVo.getUrl(), id);
        return uploadFileVo;
    }

}
  • 2.7 最終效果圖

3. 完整程式碼

查閱演示程式碼

參考

https://www.codingbrick.com/archives/456.html