uni-app上传图片并添加水印

uni-app上传图片并添加水印:

效果:代码地址
在这里插入图片描述
image-picker 组件使用:

<template>
  <view>
	<ImagePicker v-model="imageList"></ImagePicker>
  </view>
</template>

<script>
import ImagePicker from '@/components/common/image-picker.vue'

export default {
  components: {
    ImagePicker,
  },
  data() {
  	// 图片回显
	imageList: [
	  {
	  	name: 'uni-app.jpg',
	  	url: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/9a952c80-6080-11eb-a16f-5b3e54966275.png',
	  	size: 1000, 
	  }
	]
  }
  ...
}
</script>

image-picker 组件如下:

<template>
  <view class="image-picker">
    <uni-file-picker
      v-model="imageValue"
      :auto-upload="false"
      :title="title"
      :limit="limit"
      :image-styles="imageStyles"
      :file-mediatype="fileMediatype"
      :mode="mode"
      @select="select"
    >
      <view v-if="fileMediatype === 'image'" class="form-item-column-center">
        <uni-icons type="image" size="30"></uni-icons>
        <view :style="{ marginTop: '5px' }">上传照片</view>
        <view>最多{{ limit }}</view>
      </view>
    </uni-file-picker>
    <view class="watermark-canvas">
      <canvas
        id="watermark-canvas"
        :style="{ width: canvasWidth, height: canvasHeight }"
        canvas-id="watermark-canvas"
      />
    </view>
  </view>
</template>

<script>
export default {
  name: 'ImagePicker',
  props: {
    limit: {
      type: Number,
      default: 1,
    },
    title: {
      type: String,
      default: null,
    },
    mode: {
      type: String,
      default: 'grid',
    },
    fileMediatype: {
      type: String,
      default: 'image',
    },
    imageStyles: {
      type: Object,
      default: null,
    },
    watermark: {
      type: Boolean,
      default: true,
    },
    // #ifdef VUE3
    modelValue: {
      type: Array,
      default() {
        return []
      },
    },
    // #endif

    // #ifndef VUE3
    value: {
      type: Array,
      default() {
        return []
      },
    },
    // #endif
  },
  emits: ['input', 'update:modelValue'],
  data() {
    return {
      imageValue: [],
      canvasWidth: '1080px',
      canvasHeight: '2160px',
    }
  },
  watch: {
    imageValue(newVal) {
      // #ifdef VUE3
      this.$emit('update:modelValue', newVal)
      // #endif
      // #ifndef VUE3
      this.$emit('input', newVal)
      // #endif
    },
    // #ifndef VUE3
    value: {
      handler(newVal) {
        this.imageValue = newVal
      },
      immediate: true,
    },
    // #endif
    // #ifdef VUE3
    modelValue: {
      handler(newVal) {
        this.imageValue = newVal
      },
      immediate: true,
    },
    // #endif
  },
  methods: {
    checkImage(url) {
      const checkNum = 5
      let currentCheckNum = 1

      return new Promise((resolve, reject) => {
        process()
        function process() {
          uni.getImageInfo({
            src: url,
            success: function (image) {
              resolve(image)
            },
            fail: function (err) {
              if (checkNum <= currentCheckNum) {
                uni.showToast({ title: '图片上传失败', icon: 'none' })
                reject(err)
              } else {
                currentCheckNum++
                const timer = setTimeout(() => {
                  clearTimeout(timer)
                  process()
                }, 300)
              }
            },
          })
        }
      })
    },
    async select(e) {
      const { name, size, extname, uuid } = e.tempFiles[0]
      let tempFilePath = e.tempFilePaths[0]
	  // 添加水印
      if (this.watermark) {
        tempFilePath = await this.addWatermark(tempFilePath)
      }
	  // 上传图片
      const url = await this.uploadFile(tempFilePath)
      // 检测图片,确保图片存在
      await this.checkImage(url)
      this.imageValue = [
        ...this.imageValue,
        {
          name,
          extname,
          url,
          size,
          uuid,
        },
      ]
    },
    async addWatermark(tempFilePath) {
      return new Promise((resolve, reject) => {
        uni.getImageInfo({
          src: tempFilePath,
          success: async (res) => {
            // 设置画布高度和宽度
            this.canvasWidth = `${res.width}px`
            this.canvasHeight = `${res.height}px`
            await this.sleep(200) // 某些平台 canvas 渲染慢,需要等待

            const ctx = uni.createCanvasContext('watermark-canvas', this)
            ctx.clearRect(0, 0, res.width, res.height)
            ctx.beginPath()
            ctx.drawImage(tempFilePath, 0, 0, res.width, res.height)

            // 水印 字体大小,颜色,内容,位置
            ctx.beginPath()
            ctx.setFontSize(24)
            ctx.setFillStyle('rgba(250,250,250,0.8)')
            ctx.fillText('我是水印1', 60, res.height - 90)
            ctx.fillText('我是水印2', 60, res.height - 60)

            // 开始绘制 (canvas -> 临时文件路径)
            ctx.draw(false, async () => {
              await this.sleep(500) // 某些平台 canvas 渲染慢,需要等待

              uni.canvasToTempFilePath(
                {
                  canvasId: 'watermark-canvas',
                  destWidth: res.width,
                  destHeight: res.height,
                  fileType: 'jpg',
                  quality: 0.8,
                  success: (fileRes) => {
                    resolve(fileRes.tempFilePath)
                  },
                  fail: (err) => {
                    console.log('[Error draw]', err)
                    uni.showToast({ title: err.errMsg, icon: 'none' })
                    reject()
                  },
                },
                this,
              )
            })
          },
          fail: (err) => {
            console.log('[Error getImageInfo]', err)
            uni.showToast({ title: err.errMsg, icon: 'none' })
            reject()
          },
        })
      })
    },
    async uploadFile(path) {
      const formData = {
        'params.bizType': 'xxx',
        'params.tags': 'xxx',
        'meta.code': 'xxxx',
        'meta.client': 'uniapp',
        'meta.tag': 'xxx',
        'meta.time': new Date().getTime(),
      }

      const res = await uni.uploadFile({
        url: `${process.env.VUE_APP_BASE_URL}/file/upload`,
        filePath: path,
        name: 'params.files',
        formData,
        header: {
          Authorization: uni.getStorageSync('accessToken'),
        },
      })

      return JSON.parse(res[1].data).data.filePaths[0]
    },
    sleep(millisecond) {
      return new Promise((resolve) => {
        setTimeout(resolve, millisecond)
      })
    },
  },
}
</script>

<style lang="scss">
.image-picker {
  position: relative;

  .form-item-column-center {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    flex-direction: column;
  }

  .watermark-canvas {
    position: absolute;
    top: 5px;
    left: 5px;
    width: 1px;
    height: 1px;
    overflow: hidden;
  }
}
</style>

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值