• 【vue】 typeScript OSS图片压缩处理工具类


    import Exif from 'exif-js'
    import logUtil from '@/utils/logUtil'
    
    /**
     * 图片压缩处理工具
     * 
     * @hxq/utils打包为ES5后在安卓4.4.4版本中会报错。!!!!
     * 先拷贝到此。2019.12.28
     * 
     * `ImageUtil.handle(file, 0.1)`
     */
    export class ImageUtil {
      /**
       * 处理图片
       * @param file 文件
       * @param quality 质量 0~1
       */
      public static handle (file: File, quality = 0.8): Promise<Blob> {
        const fileReader = FileReader
    
        return new Promise(async (resolve, reject) => {
          // 看支持不支持FileReader
          if (!file || !fileReader) {
            reject(new Error('不支持压缩'))
          }
    
          if (/^image/.test(file.type)) {
            try {
              const orientation = await ImageUtil.getOrientation(file)
              // 创建一个reader
              const reader = new FileReader()
              // 将图片转成 base64 格式
              reader.readAsDataURL(file)
              // 读取成功后的回调
              reader.onloadend = () => {
                const result: any = reader.result
                const img = new Image()
                img.src = result
                // 判断图片是否大于100K,是就压缩,反之直接上传
                if (result.length <= (100 * 1024)) {
                  resolve(file)
                } else {
                  img.onload = () => {
                    const baseData = ImageUtil.compress(img, orientation, quality)
                    resolve(ImageUtil.b64toBlob(baseData))
                  }
                }
              }
            } catch (error) {
              reject(error)
              logUtil.report({
                model: 'code',
                method: 'imageUtil-handler',
                code: '图片压缩',
                msg: error.stack // 上报栈信息 2020.04.08
              })
            }
          } else {
            reject(new Error('请上传图片文件: ' + file.type))
          }
        })
      }
    
      /**
       * base64转Blob
       * @param b64Data base64字符串
       * @param sliceSize 分片大小
       * @returns Blob 阿里上传图片需要Blob型
       */
      public static b64toBlob (baseData: string, sliceSize = 512) {
        const contentType = ImageUtil.base64ContentType(baseData)
        const realData = ImageUtil.base64RealData(baseData)
        const byteCharacters = atob(realData)
        const byteArrays = []
        for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
          const slice = byteCharacters.slice(offset, offset + sliceSize)
          const byteNumbers = new Array(slice.length)
          for (let i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i)
          }
          const byteArray = new Uint8Array(byteNumbers)
          byteArrays.push(byteArray)
        }
        return new Blob(byteArrays, {
          type: contentType
        })
      }
    
      /**
       * dataUrl图片类型
       * @param b64Data base64字符串
       */
      public static base64ContentType (b64Data: string) {
        const block = b64Data.split(';')
        const contentType = block[0].split(':')[1]
        return contentType
      }
    
      /**
       * dataUrl中的base64数据
       * @param b64Data base64字符串
       */
      public static base64RealData (b64Data: string) {
        const block = b64Data.split(';')
        const realData = block[1].split(',')[1]
        return realData
      }
    
      /**
       * 去获取拍照时的信息,解决拍出来的照片旋转问题
       * @param file 文件对象
       */
      public static getOrientation (file: File): Promise<number> {
        return new Promise((resolve, reject) => {
          Exif.getData(file as any, () => {
            const orientation = Exif.getTag(file, 'Orientation')
            resolve(orientation)
          })
        })
      }
    
      /**
       * 旋转图片
       * @param img 图片
       * @param degreeNum 旋转角度,如:90、-90、180
       * @param canvas 画布
       */
      public static rotateImg (img: HTMLImageElement, degreeNum: number, canvas: HTMLCanvasElement) {
        const width = canvas.width
        const height = canvas.height
        // 旋转角度以弧度值为参数
        const degree = degreeNum * Math.PI / 180
        const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
        switch (degreeNum) {
          case 0:
            break
          case 90:
            canvas.width = height
            canvas.height = width
            ctx.rotate(degree)
            ctx.drawImage(img, 0, -height, width, height)
            break
          case 180:
          case -180:
            ctx.rotate(degree)
            ctx.drawImage(img, -width, -height, width, height)
            break
          case 270:
          case -90:
            canvas.width = height
            canvas.height = width
            ctx.rotate(degree)
            ctx.drawImage(img, -width, 0, width, height)
            break
        }
      }
    
      /**
       * 压缩图片
       * @param img 图片
       * @param orientation orientation
       * @param quality 质量
       */
      public static compress (img: HTMLImageElement, orientation: number, quality = 0.8) {
        const canvas: HTMLCanvasElement = document.createElement('canvas')
        const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
        const initSize = img.src.length
        let width = img.width
        let height = img.height
    
        // 最长边控制到1024以下
        const max = 1024
        if (width > height) {
          if (width > max) {
            height = Math.floor(max / width * height)
            width = max
          }
        } else {
          if (height > max) {
            width = Math.floor(max / height * width)
            height = max
          }
        }
    
        canvas.width = width
        canvas.height = height
        // 铺底色
        ctx.fillStyle = '#fff'
        ctx.fillRect(0, 0, canvas.width, canvas.height)
    
        // 修复ios上传图片的时候 被旋转的问题
        if (orientation && orientation !== 1) {
          switch (orientation) {
            case 6: // 需要顺时针(向左)90度旋转
              ImageUtil.rotateImg(img, 90, canvas)
              break
            case 8: // 需要逆时针(向右)90度旋转
              ImageUtil.rotateImg(img, -90, canvas)
              break
            case 3: // 需要180度旋转
              ImageUtil.rotateImg(img, 180, canvas)
              break
          }
        } else {
          ctx.drawImage(img, 0, 0, width, height)
        }
        // 进行最小压缩
        const ndata = canvas.toDataURL('image/jpeg', quality)
        console.log('压缩前:' + initSize)
        console.log('压缩后:' + ndata.length)
        console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%')
        canvas.width = canvas.height = 0
        return ndata
      }
    }
  • 相关阅读:
    hdu 4963(中途相遇法)
    UVALive 6869(后缀数组)
    AC自动机小结
    poj 2409+2154+2888(Burnside定理)
    HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)
    bunoj 34990(hash)
    CSU 1506(最小费用最大流)
    CF 514C(hash)
    lightoj 1297(三分)
    lightoj 1179(线段树)
  • 原文地址:https://www.cnblogs.com/binli/p/12800586.html
Copyright © 2020-2023  润新知