canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(二)

简介: canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(二)

canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(一):https://developer.aliyun.com/article/1558608

调整亮度(变亮变暗)

实现算法:

将红、绿、蓝三个通道值,分别同时加上一个正值或负值。

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      var a = 50;
                      data[i + 0] += a;
                      data[i + 1] += a;
                      data[i + 2] += a;
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

a = 50 变亮的效果:

a = -50 变暗的效果:

调整透明度

cxt.globalAlpha用于调整整个Canvas的透明度,这里只是希望将图片透明化

实现算法:

将每一个像素的透明度乘以n,n的取值范围为0.0~1.0

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      data[i + 3] = data[i + 3] * 0.3;
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

颜色反转(底片)

即图片颜色颠倒,效果类似相机的底片。

实现算法:

红、绿、蓝这三个通道的像素取各自的相反值,也就是(255-原值)

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                       data[i + 0] = 255 - data[i + 0];
                       data[i + 1] = 255 - data[i + 1];
                       data[i + 2] = 255 - data[i + 2];
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

黑白效果(灰度图)

指将彩色图片转换成黑白图片。

实现算法:

首先取红、绿、蓝三个通道的平均值,也就是(data[i+0]+data[i+1]+data[i+2])/3。然后data[i+0]、data[i+1]和data[i+2]全部保存为这个平均值。

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      var average = (data[i + 0] + data[i + 1] + data[i + 2] + data[i + 3]) / 3;
                      data[i + 0] = average;  //红
                      data[i + 1] = average;  //绿
                      data[i + 2] = average;  //蓝
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

效果优化——加权平均

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      var grayscale = data[i] * 0.3 + data[i + 1] * 0.6 + data[i + 2] * 0.1;
                      data[i + 0] = grayscale;  //红
                      data[i + 1] = grayscale;  //绿
                      data[i + 2] = grayscale;  //蓝
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

复古

使得图片有一种古旧效果。

实现算法:

将红、绿、蓝三个通道,分别取这三个值的某种加权平均值。

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      var r = data[i + 0];
                      var g = data[i + 1];
                      var b = data[i + 2];

                      data[i + 0] = r * 0.39 + g * 0.76 + b * 0.18;
                      data[i + 1] = r * 0.35 + g * 0.68 + b * 0.16;
                      data[i + 2] = r * 0.27 + g * 0.53 + b * 0.13;
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

红色蒙版

让图片呈现一种偏红的效果

实现算法:

将红通道(r)赋值为红、绿、蓝这三个的平均值,并且将绿通道、蓝通道都赋值为0。

同样的方式可以实现类似效果的绿色蒙版、蓝色蒙版等。

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 10, 10);
                 var imgData = cxt.getImageData(10, 10, 120, 120);
                 var data = imgData.data;
                 //遍历每个像素
                 for (var i = 0; i < data.length; i += 4) {
                      var r = data[i + 0];
                      var g = data[i + 1];
                      var b = data[i + 2];

                      var average = (r + g + b) / 3;
                      data[i + 0] = average;
                      data[i + 1] = 0;
                      data[i + 2] = 0;
                 }
                 //在指定位置输出图片
                 cxt.putImageData(imgData, 140, 10);
             }

创建像素区域 createImageData()

cxt.createImageData(sw,sh);      //第1种格式

sw,sh 为像素区域的宽和高

cxt.createImageData(imageData);  //第2种格式

imageData为一个像素对象,最终像素区域的宽高和这个像素对象相同


createImageData()和putImageData()配合使用是对一个区域进行像素操作的。只有使用createImageData()创建了一个区域,才可以对该区域进行相应的像素操作。

             var imgData = cxt.createImageData(100, 100);
             var data = imgData.data;
             for (var i = 0; i < 100 * 100 * 4; i += 4) {
                  data[i + 0] = 0;
                  data[i + 1] = 0;
                  data[i + 2] = 255;
                  data[i + 3] = 255;
             }
             cxt.putImageData(imgData, 20, 20);

             var image = new Image();
             image.src = "images/princess.png";

             image.onload = function () {
                 cxt.drawImage(image, 0, 0, 60, 60);
                 //获取一个图片的imgData
                 var imgData1 = cxt.getImageData(0, 0, 60, 60);
                 //利用这个图片的imgData作为参数
                 var imgData2 = cxt.createImageData(imgData1);
                 var data = imgData2.data;
                 for (var i = 0; i < imgData2.width * imgData2.height * 4; i += 4) {
                       data[i + 0] = 0;
                       data[i + 1] = 0;
                       data[i + 2] = 255;
                       data[i + 3] = 255;
                  }
                  cxt.putImageData(imgData2, 80, 0);
             }

变换元素

变换可用于图形,也可以用于图片和文字。

变换的本质都是通过“变换矩阵transform()”实现的,涉及到线性代数,平时并不会用,不必深究,简单了解即可:

  • translate(e,f)等价于transform(1,0,0,1,e,f)。
  • scale(a,d)等价于transform(a,0,0,d,0,0)。
  • rotate(θ)等价于transform(cosθ,sinθ,-sinθ,cosθ,0,0)。

setTransform() 与 transform() 用法相同,只是transform() 是在变换后的基础上继续变换,而setTransform() 会重置图形的状态,再进行变换。

             var cnv = $$("canvas");
             var cxt = cnv.getContext("2d");

             cxt.fillStyle = "yellow";
             cxt.fillRect(0, 0, 100, 50)

             cxt.setTransform(1, 0.5, -0.5, 1, 30, 10);
             cxt.fillStyle = "red";
             cxt.fillRect(0, 0, 100, 50);

             cxt.setTransform(1, 0.5, -0.5, 1, 30, 10);
             cxt.fillStyle = "blue";
             cxt.fillRect(0, 0, 100, 50);

将 setTransform 改为 transform 后效果为

平移 translate()

本质是移动了整个坐标轴

cxt.translate(x,y);
  • x 为x轴方向的移动距离,单位px,为正,则是向右移动,为负,则向左移动
  • y 为y轴方向的移动距离,单位px,为正,则是向下移动,为负,则向上移动
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title></title>
   <meta charset="utf-8" />
   <script type="text/javascript">
        function $$(id) {
             return document.getElementById(id);
        }
        window.onload = function () {
             var cnv = $$("canvas");
             var cxt = cnv.getContext("2d");

             //绘制初始图形
             cxt.fillStyle = "HotPink";
             cxt.fillRect(30, 30, 50, 50);

             $$("btn").onclick = function () {
                  // 清空canvas
                  cxt.clearRect(0, 0, cnv.width, cnv.height);
                  cxt.translate(10, 10);
                  cxt.fillStyle = "HotPink";
                  // 重绘
                  cxt.fillRect(30, 30, 50, 50);
             }
        }
   </script>
</head>
<body>
   <canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas><br />
   <input id="btn" type="button" value="移动"/>
</body>
</html>

缩放 scale ()

cxt.scale(x,y);


  • x 为x轴方向的缩放倍数
  • y 为y轴方向的缩放倍数
  • x,y 的值为0~1时为缩小,大于1时为放大,也可以为负,但基本不用。
    使用 scale 缩放时,图形的左上角坐标、宽度和高度、线条宽度都会同步缩放,若不是预期效果,记得进行相应的处理!
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
    <meta charset="utf-8" />
    <script type="text/javascript">
      function $$(id) {
        return document.getElementById(id);
      }
      window.onload = function () {
        var cnv = $$("canvas");
        var cxt = cnv.getContext("2d");

        //绘制初始图形
        cxt.fillStyle = "HotPink";
        cxt.fillRect(30, 30, 50, 50);

        //图形放大
        $$("btn-big").onclick = function () {
          // 清空canvas
          cxt.clearRect(0, 0, cnv.width, cnv.height);
          cxt.scale(1.5, 1.5);
          cxt.fillStyle = "HotPink";
          //  添加平移,抵消左上角坐标的放大
          cxt.translate(-10, -10);
          cxt.fillRect(30, 30, 50, 50);
        };

        //图形缩小
        $$("btn-small").onclick = function () {
          // 清空canvas
          cxt.clearRect(0, 0, cnv.width, cnv.height);
          cxt.scale(0.5, 0.5);
          cxt.fillStyle = "HotPink";
          //  反向平移,抵消左上角坐标的縮小
          cxt.translate(30, 30);
          cxt.fillRect(30, 30, 50, 50);
        };
      };
    </script>
  </head>
  <body>
    <canvas
      id="canvas"
      width="200"
      height="150"
      style="border: 1px dashed gray"
    ></canvas
    ><br />
    <input id="btn-big" type="button" value="放大" />
    <input id="btn-small" type="button" value="缩小" />
  </body>
</html>

旋转 rotate()

cxt.rotate(angle);
  • angle 为图形旋转的角度,取值为-Math.PI2~Math.PI2。当angle>0时,图形顺时针旋转;当angel<0时,图形逆时针旋转。
120*Math.PI/180  //120°
150*Math.PI/180  //150°

默认情况下,rotate()方法的旋转中心就是原点坐标(0,0)

cxt.fillStyle = "HotPink";
cxt.fillRect(30, 30, 50, 50);

$$("btn").onclick = function () {
   cxt.rotate(-30 * Math.PI / 180);   //逆时针旋转30°
   cxt.fillStyle = "LightSkyBlue ";
   cxt.fillRect(30, 30, 50, 50); //注意,这里仍然是fillRect(30, 30, 50, 50) 
}

改变旋转中心

先使用translate(x,y),然后再使用rotate()方法

             var i = 0;
             var rectWidth = 100;
             var rectHeight = 50;
             setInterval(function () {
                  i++;
                  cxt.clearRect(0, 0, cnv.width, cnv.height);
                  cxt.save();
                  cxt.translate(cnv.width / 2, cnv.height / 2); //将坐标移动到中心
                  cxt.rotate(Math.PI * (i / 100));           //累进旋转
                  cxt.fillStyle = "HotPink";
                  cxt.fillRect(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight); //填充矩形
                  cxt.restore();
             }, 10);

使用translate()方法结合图形的长宽将旋转中心移动到图形中心上。

本例中,将矩形的中心与画布的中心重合,是为了方便操作。

实战范例 1 —— 内卷花纹

             cxt.translate(150, 0);
             cxt.fillStyle = "rgba(255,0,0,0.25)";
             for (var i = 0; i < 50; i++) {
                   cxt.translate(25, 25);      //图形平移
                   cxt.scale(0.95, 0.95);      //图形缩放
                   cxt.rotate(Math.PI / 10);   //图形旋转
                   cxt.fillRect(0, 0, 100, 50);
             }

实战范例 2 —— 彩虹

//定义数组,存储7种颜色
             var colors = ["red", "orange", "yellow", "green", "blue", "navy", "purple"];
             cxt.lineWidth = 12;
             cxt.translate(50,0); 

             //循环绘制圆弧
             for (var i = 0; i < colors.length; i++) {
                  //每次向下移动10px
                  cxt. translate(0,10); 
                  //定义颜色
                  cxt.strokeStyle = colors[i];
                  //绘制圆弧
                  cxt.beginPath();
                  cxt.arc(50, 100, 100, 0, 180 * Math.PI / 180, true);
                  cxt.stroke();
             }
```![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/00258c688cd24e07be5544a4429c24be.png)

目录
相关文章
|
4月前
PPT 动画-多层旋转(圆角三角形)
PPT 动画-多层旋转(圆角三角形)
38 0
|
5月前
|
存储 前端开发 JavaScript
canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(一)
canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(一)
501 0
|
7月前
[MFC] 将像素坐标点缩放,准确的画在所在控件的图片上
[MFC] 将像素坐标点缩放,准确的画在所在控件的图片上
103 0
cesium中绘制立方体、设置材质、操作相机及获取鼠标经纬度和高度的方法
cesium中绘制立方体、设置材质、操作相机及获取鼠标经纬度和高度的方法
277 0
|
数据可视化 PyTorch 算法框架/工具
数据增强之裁剪、翻转与旋转
数据增强之裁剪、翻转与旋转
155 0
数据增强之裁剪、翻转与旋转
|
前端开发 JavaScript
【Three.js入门】渲染第一个场景及物体(轨道控制器、坐标轴辅助器、移动缩放旋转)
【Three.js入门】渲染第一个场景及物体(轨道控制器、坐标轴辅助器、移动缩放旋转)
303 0
|
JavaScript
问题解决:百分比宽度页面缩放会变形
问题解决:百分比宽度页面缩放会变形
235 1
问题解决:百分比宽度页面缩放会变形
|
算法 定位技术 C#
C#开发:不规则裁切图片
C#开发:不规则裁切图片
159 0
|
前端开发 JavaScript
canvas中的拖拽、缩放、旋转 (上) —— 数学知识准备
canvas中的拖拽、缩放、旋转 (上) —— 数学知识准备
910 0
canvas中的拖拽、缩放、旋转 (上) —— 数学知识准备
|
前端开发 开发者
Canvas中的拖拽、缩放、旋转 (下)——代码实现
Canvas中的拖拽、缩放、旋转 (下)——代码实现
593 0
Canvas中的拖拽、缩放、旋转 (下)——代码实现