2020-01-10 vue-cropper图片裁剪

552 阅读2分钟

需求:对本地上传、远程FTP上传和视频截取三种方式的获得图片放入裁剪区进行裁剪

无论哪种方式,都需要得到裁剪图片的文件file,然后通过window.URL.createObjectURL方法取得图片url,最后通过vue-cropper组件裁剪图片产出图片信息

获取图片文件file

1、本地上传通过组件el-upload(element-ui)中的钩子函数获得上传图片的file 2、通过其它方式获得图片url,首先要把url转为图片file 图片url转换为file的方法:包括跨域

export const imgConvert = {
  /**
   * 图片url获取base64数据(如果是跨域图片需要设置允许跨域)
   * @param img
   * @param width
   * @param height
   * @returns {{dataURL: string, type: string}}
   */
  getBase64Image(img, width, height) {
    let demoCanvas = document.createElement('canvas')
    demoCanvas.width = img.width;
    demoCanvas.height = img.height;
    const ctx = demoCanvas.getContext("2d")
    ctx.drawImage(img, 0, 0, width, height);
    const ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
    const dataURL = demoCanvas.toDataURL("image/" + ext);
    return {
      dataURL: dataURL,
      type: "image/" + ext
    };
  },
  /**
   * 图片base64 转为blob
   * @param base64
   * @returns {Blob}
   */
  convertBase64UrlToBlob(base64) {
    const urlData = base64.dataURL;
    const type = base64.type;
    const bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte
    // 处理异常,将ascii码小于0的转换为大于0
    const ab = new ArrayBuffer(bytes.length);
    const ia = new Uint8Array(ab);
    for (let i = 0; i < bytes.length; i++) {
      ia[i] = bytes.charCodeAt(i);
    }
    return new Blob([ab], {
      type: type
    });
  },
  /**
   * base64 转为file类型
   * @param dataurl
   * @param filename
   * @returns {File}
   */
  dataURLtoFile(dataurl, filename) {
    const arr = dataurl.dataURL.split(',')
    const mime = arr[0].match(/:(.*?);/)[1]
    const bstr = atob(arr[1])
    let n = bstr.length
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {
      type: mime
    });
  },
  //图片类型枚举
  imgType: {
    base64: 'base64',
    blob: 'blob',
    file: 'file'
  },
  /**
   * 图片url转化示例(跨域图片需允许跨域访问)
   * demo
   * >import {imgConvert} from './../../../util/util_file'
   * >logImg(){
   *   let url = 'http://192.168.1.74/image/role/zhengshi/0002/5100/0172/(2)_V23_sc.jpg'
        imgConvert.imgProcess(this.showImg, imgConvert.imgType.file, url, '')
   * },
   * > showImg(data) {
      console.log('data', data)
    },
   * @param callback 回调函数
   * @param imgType 图片类型
   * @param fileUrl 图片url地址
   * @param fileName 图片名称(可为空)
   */
  imgProcess(callback, imgType, fileUrl, fileName = '') {
    let image = new Image();
    // 设置跨域类型
    image.setAttribute("crossOrigin", 'anonymous');
    // image.setAttribute("crossOrigin", 'undefined');
    // 给img加上随机值一部分情况下能解决跨域
    image.src = fileUrl + '?timestamp=' + new Date().valueOf();
    // image.src = img + '?time=' + new Date().valueOf();
    let that = this
    image.onload = function () {
      const base64 = that.getBase64Image(image, image.width, image.height);
      switch (imgType) {
        case that.imgType.base64:
          return callback(base64)
          break
        case that.imgType.blob:
          const blob = that.convertBase64UrlToBlob(base64);
          return callback(blob)
          break
        case that.imgType.file:
          const file = that.dataURLtoFile(base64, fileName);
          return callback(file)
          break
      }
    }
  }
}

文件file初始化到裁剪区

然后再把上传的图片file初始化到裁剪区

// 上传的图片初始化截图框
    setUploadFile(file) {
      this.previewsTime = 0;
      const windowURL = window.URL || window.webkitURL;
      this.option.img = windowURL.createObjectURL(file);
      this.originalImg = this.option.img;
    },

裁剪区的组件vue-cropper:通过npm安装,插件地址:github.com/xyxiao001/v…

<vueCropper
      ref="vuecropper"
      v-bind="option"
      @realTime="realTime"
      @imgLoad="imgLoad"
      :img="option.img"
    ></vueCropper>

处理截取图片信息:用到daycaca包处理截取图片返回base64编码信息

// 截取
    handleCrop() {
      let cropW = this.$refs.vuecropper.cropW; // 有效的截图框宽度
      let cropH = this.$refs.vuecropper.cropH; // 有效的截图框高度
      let getCropAxis = this.$refs.vuecropper.getCropAxis(); // 获取截图框基于容器的坐标点
      let getImgAxis = this.$refs.vuecropper.getImgAxis(); // 获取图片基于容器的坐标点
      let originalImg = document.querySelector(".originalImg");
      let ratio = this.ratio;
      daycaca.crop(
        originalImg,
        {
          x: (getCropAxis.x1 - getImgAxis.x1) / ratio,
          y: (getCropAxis.y1 - getImgAxis.y1) / ratio,
          w: cropW / ratio,
          h: cropH / ratio
        },
        data => {
          this.fileArr[this.INDEX].src = data;
          this.handleCutReseult([this.fileArr[this.INDEX]]);
        }
      );
    },

之后就是把截取用daycaca方法得到的base64编码通过dataURLtoFile()转换为图片file,在调相关的接口信息即可。