canvas rotate正负时针旋转,镜面上下/左右翻转

该博客主要展示了如何使用canvas进行图像的旋转和缩放操作。通过提供的JavaScript函数,可以实现图像的逆时针和顺时针旋转,以及垂直和水平缩放。在Vue组件中,结合点击事件,动态改变图像的旋转角度和缩放比例,实现了交互式的图像处理效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对照着canvas镜面翻转,写了rotate对应的
逆时针左转,公式(i, j) = (j, n - i) // n指的是方阵的阶数

    turnLeft(sourceData, newData) {
      for (let i = 0, h = sourceData.height; i < h; i++) {
        for (let j = 0, w = sourceData.width; j < w; j++) {
          newData.data[i * w * 4 + j * 4 + 0] =
            sourceData.data[j * w * 4 + (h - i) * 4 + 0];
          newData.data[i * w * 4 + j * 4 + 1] =
            sourceData.data[j * w * 4 + (h - i) * 4 + 1];
          newData.data[i * w * 4 + j * 4 + 2] =
            sourceData.data[j * w * 4 + (h - i) * 4 + 2];
          newData.data[i * w * 4 + j * 4 + 3] =
            sourceData.data[j * w * 4 + (h - i) * 4 + 3];
        }
      }
      return newData;
    },

顺时针右转,公式(i, j) = (n - j, i) // n指的是方阵的阶数

    turnRight(sourceData, newData) {
      for (let i = 0, h = sourceData.height; i < h; i++) {
        for (let j = 0, w = sourceData.width; j < w; j++) {
          newData.data[i * w * 4 + j * 4 + 0] =
            sourceData.data[(h - j) * w * 4 + i * 4 + 0];
          newData.data[i * w * 4 + j * 4 + 1] =
            sourceData.data[(h - j) * w * 4 + i * 4 + 1];
          newData.data[i * w * 4 + j * 4 + 2] =
            sourceData.data[(h - j) * w * 4 + i * 4 + 2];
          newData.data[i * w * 4 + j * 4 + 3] =
            sourceData.data[(h - j) * w * 4 + i * 4 + 3];
        }
      }
      return newData;
    },
<template>
  <div class="hello">
    <!-- <h1>{{ msg }}</h1> -->
    <div class="diva">
      <canvas ref="canvas" width=400 height="400"></canvas>
      <div class="div-2">
        <div @click="rotate" style="margn-right:30px;">rotate-90</div>
        <div @click="rotateReverse">rotate90</div>
        <div @click="scale">上下scale</div>
        <div @click="scaleLeft">左右scale</div>
      </div>
    </div>
  </div>
</template>

<script>
let i = 0;
let j = 0;

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  mounted() {
    this.init();
  },
  data() {
    return {
      audioCtx: null,
      canvas: null,
      ctx: null,
      imgData: null,
      originWidth: null,
      originHeight: null,
      lastOperation: '',

    }
  },
  methods: {
    init() {
      // let audioCtx = this.audioCtx = new AudioContext();
      // let source = audioCtx.createBufferSource();
      function getBase64ByURL(imgUrl) {
        return new Promise(resolve => {
          var xhr = new XMLHttpRequest();
          xhr.open("get", imgUrl, true);
          xhr.responseType = "blob";
          xhr.onload = function () {
            if (this.status == 200) {
              var blob = this.response;
              let oFileReader = new FileReader();
              oFileReader.onloadend = function (e) {
                resolve({blob,base64:e.target.result})
              };
              oFileReader.readAsDataURL(blob);
            }
          };
          xhr.send();
        });
      }
      let url = 'aa.jpg';
      let _this = this;
      getBase64ByURL(url).then(res=>{
        let {blob,base64} = res;
        let canvas = _this.canvas = _this.$refs.canvas;
        let ctx = _this.ctx = canvas.getContext('2d');
        let img = new Image();
        img.src= URL.createObjectURL(blob);
        img.onload = function() {
          let w = img.width;
          let h = img.height;
          _this.originWidth = w;
          _this.originHeight = h;
          console.log(w);
          console.log(h);
          _this.imgData = img;
          ctx.drawImage(img, 0, 0, w, h, 0, 0, w, h);
          _this.ctx.strokeStyle = 'red';
          _this.ctx.strokeRect(0,0,100, 350);
          _this.ctx.strokeStyle = 'green';
          _this.ctx.strokeRect(0,0,200, 150);
        }
        // console.log(blob,base64,"blob,base64")
      })
    },
    rotate() {
      i--;
      if(i<-3) {
        i = 0;
      }
      this.ctx.save();
      this.ctx.clearRect(0,0,this.originWidth, this.originHeight)
      this.canvas.style.height = this.originWidth + 'px';
      this.canvas.style.width = this.originHeight + 'px';
      let ctx = this.ctx = this.canvas.getContext('2d');
      ctx.clearRect(0,0, this.originHeight,this.originWidth)
      ctx.rotate(90*i*Math.PI/180);
      let o = {
        '-1': [-this.originHeight,0],
        '-2': [-this.originHeight,-this.originWidth],
        '-3': [0,-this.originWidth],
        0: [0,0],
      }
      let wh = i%2===1
        ? [this.originWidth,this.originHeight]
        : [this.originHeight,this.originWidth];
      ctx.drawImage( // rotate之后坐标系已经发生变化
        this.imgData,
        0,0,
        ...wh,
        ...o[i>0?i-4:i], // 此时w已经是h
        this.originHeight,this.originWidth
      );
      console.log('-----iiiiiiiiiiiiiii', i);
      [this.originHeight,this.originWidth] = [this.originWidth,this.originHeight];
      this.ctx.restore();
    },
    rotateReverse() {
      i++;
      if(i>3) {
        i = 0;
      }
      this.ctx.save();
      this.ctx.clearRect(0,0,this.originWidth, this.originHeight)
      this.canvas.style.height = this.originWidth + 'px';
      this.canvas.style.width = this.originHeight + 'px';
      let ctx = this.ctx = this.canvas.getContext('2d');
      this.ctx.clearRect(0,0, this.originHeight,this.originWidth)
      this.ctx.rotate(90*i*Math.PI/180);
      let o = {
        // 1: [this.originHeight,0],
        1: [0,-this.originWidth],
        // 2: [this.originHeight,this.originWidth],
        2: [-this.originHeight,-this.originWidth],
        3: [-this.originHeight,0],
        0: [0,0],
      }
      let wh = i%2===1
        ? [this.originWidth,this.originHeight]
        : [this.originHeight,this.originWidth];
      ctx.drawImage( // rotate之后坐标系已经发生变化
        this.imgData,
        0,0,
        ...wh,
        ...o[i<0?4+i:i], // 此时w已经是h
        this.originHeight,this.originWidth
      );
      console.log('iiiiiiiiiiiiiii', i);
      [this.originHeight,this.originWidth] = [this.originWidth,this.originHeight];
      this.ctx.restore();
    },
    scale() {
      j++;
      if(j>1) {
        j = 0;
      }
      this.ctx.clearRect(0,0,this.originWidth, this.originHeight)
      this.ctx.scale(1, -1);

      this.ctx.drawImage( // rotate之后坐标系已经发生变化
        this.imgData,
        0,0,
        this.originWidth,this.originHeight,
        0,-this.originHeight,
        this.originWidth,this.originHeight,
      );
      this.ctx.translate(0,-this.originHeight);
      this.ctx.restore();
    },
    scaleLeft() {
      j--;
      if(j<-1) {
        j = 0;
      }
      this.ctx.clearRect(0,0,this.originWidth, this.originHeight)
      this.ctx.scale(-1, 1);

      this.ctx.drawImage( // rotate之后坐标系已经发生变化
        this.imgData,
        0,0,
        this.originWidth,this.originHeight,
        -this.originWidth, 0,
        this.originWidth,this.originHeight,
      );
      this.ctx.translate(-this.originWidth, 0);
      this.ctx.restore();
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
.diva {
  position: relative;
  padding: 0 0 100px 0;
  height: 500px;
}
.diva canvas {
  position: absolute;
  left:0;
  top:0;
}
.diva .div-2 {
  position: absolute;
  left: 30px;
  top: 30px;
  display: flex;
  justify-content: space-around;
}
.diva .div-2  > div {
  background: rgba(0,0,0,.5);
  color: #fff;
  padding: 20px;
  margin-right: 10px;

}
</style>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值