canvas压缩上传图片,添加水印不模糊

解决问题:1、图片上传成功后,由于图片过大,页面上没有及时显示;2、压缩图片后添加水印随着图片一起降低品质了
本文实现:以上问题均在本文中解决。1、使用canvas进行压缩后再进行上传,可以自行调整encoderOptions(图片品质)和压缩后图片的宽高来控制图片的清晰度和图片显示的速度;2、给压缩后的图片添加水印

本文压缩文件功能代码出自迷途小码农零零发

uniapp页面调用代码

import imgCompress from "shared/utils/imgCompress"
choseImage () {
	const WaterMarkContent = {
	   font: "24px 宋体",
	   fillStyle: "white",
	   textAlign: 'right',
	   fillText: [
	     {
	       text: `水印1`
	     }
	   ]
	 }
	 uni.chooseImage({
	   count: 1,
	   sizeType: ['original', 'compressed'],
	   sourceType: ['album', 'camera'],
	   success: chooseImageRes => {
	     const token = uni.getStorageSync('token')
	     const url = `${apiUrl.api.protocol}://${apiUrl.api.host}:${apiUrl.api.port === '' ? '' : apiUrl.api.port === '80' ? '' : apiUrl.api.port}`
	     const method = api.upload
	     const formData = new ActionAxios(method, JSON.stringify({})).setData()
	     uni.showLoading({title: '正在上传头像'})
	     imgCompress(chooseImageRes.tempFiles[0], WaterMarkContent).then(res => {
	       uni.uploadFile({
	         url,
	         filePath: res,
	         name: 'fileName',
	         header: { Authorization: token },
	         formData,
	         // timeout: 5000,
	         success: (res) => {
	           const data = JSON.parse(res.data).xxx_response
	           if (data.code !== '10000') {
	             uni.showLoading({title: '上传失败', icon: 'none'})
	           } else {
	             this.baseList[0].msg = data.url
	             uni.showLoading({title: '上传成功', icon: 'none'})
	           }
	           setTimeout(() => {
	             uni.hideLoading()
	           }, 1000)
	         },
	         fail: err => {
	           console.log('err', err);
	         }
	       })
	     })
	   }
	 })
	},

功能代码(压缩&水印)

// 这是图片上传压缩的核心所在,我们先使用CanvasRenderingContext2D.drawImage()方法将上传的图片文件在画布上绘制出来;
// 再使用Canvas.toDataURL()将画布上的图片信息转换成base64(DataURL)格式的数据。
const imgCompress = function (file, WaterMarkContent) {
  const Radio = file.size / (1024 * 1024 * 2)  // 默认到2m以下
  let encoderOptions = Radio > 1 ? (1 / Math.ceil(Radio)) : 1   // encoderOptions图片质量取值0-1
  return new Promise(function (resolve, reject) {
    let fileType = file.type
    let imgResult = ''
    let reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = function () {
      let img = new Image() //先创建图片对象
      img.src = this.result
      let canvas = document.createElement('canvas')
      let ctx = canvas.getContext('2d')
      img.onload = function () { //图片加载完后
        // 做适配
        let width = 800
        if (img.width < 800) {
          width = img.width
        }
        canvas.width = width
        canvas.height = (img.height / img.width) * width
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height)  //绘制图像;把大图片画在一张小画布上,压缩就这么实现了
        imgResult = canvas.toDataURL(fileType, encoderOptions)
        // 设置文字水印
        if (WaterMarkContent) imgResult = setWaterMark(file, WaterMarkContent, imgResult)
        // 返回base64
        // encoderOptions表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果
        resolve(imgResult)

        // 这时可能后端要求我们传文件格式图片 base64转Blob
        // const blobImg = that.converrVase64UrlToBlob(imgResult , fileType)
        // resolve(blobImg)
      }
    }
    reader.onerror = function (error) {
      reject(error)
    }
  })
}
// dataURL转File
function dataURLtoFile(dataURL, filename) {
  const arr = 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 })
}

// 设置水印
function setWaterMark (file, WaterMarkContent, imgResult) {
  const FileNew = dataURLtoFile(imgResult, file.name)
  let reader = new FileReader()
  return new Promise(function (resolve, reject) {
    reader.readAsDataURL(FileNew)
    reader.onload = function () {
      let img = new Image()
      img.src = this.result
      let canvas = document.createElement('canvas')
      let ctx = canvas.getContext('2d')
      img.onload = function () {
        canvas.width = img.width
        canvas.height = img.height
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
        // 设置填充字号和字体,样式
        WaterMarkContent.font && (ctx.font = WaterMarkContent.font)
        WaterMarkContent.fillStyle && (ctx.fillStyle = WaterMarkContent.fillStyle)
        WaterMarkContent.textAlign && (ctx.textAlign = WaterMarkContent.textAlign)
        const FillTextArr = WaterMarkContent.fillText || []
        FillTextArr.forEach((element, index) => {
          const X = element.x || (canvas.width - 20)
          const Y = element.y || (canvas.height - 30 * (FillTextArr.length - index))
          ctx.fillText(element.text, X, Y)
        });
        resolve(canvas.toDataURL(file.type, 1))
      }
    }
    reader.onerror = function (error) {
      reject(error)
    }
  })
}
// base64转Blob
const converrVase64UrlToBlob = function (base64, mimeType) {
  // mimeType 图片类型,例如 mimeType='image/png'
  const bytes = window.atob(base64.split(',')[1]) // atob方法用于解码base64
  // 创建一个长度为 bytes.length 的 buffer(一个二进制文件), 它会分配一个 16 字节(byte)的连续内存空间,并用 0 进行预填充。
  const ab = new ArrayBuffer(bytes.length)

  // Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0255 之间的单个数字(每个字节是 8 位)。这称为 “8 位无符号整数”。
  const ia = new Uint8Array(ab)
  for (let i = 0; i < bytes.length; i++) {
    // 更改里面的初始化内容
    ia[i] = bytes.charCodeAt(i)
  }
  // 创建blob格式数据,并传入二进制文件和文件原本类型
  return new Blob([ia], { type: mimeType })
}

export default imgCompress
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值