前端开发系列027-基础篇之Canvas绘图(图像)
一、Canvas画布图像绘制基础

绘制图像
语法
ctx.drawImage(image,dx,dy);ctx.drawImage(image,dx,dy,dw,dh);ctx.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh);
作用 该方法可以将一幅图像绘制到Canvas画布中(源图像 - 目标图像)。
参数
dx 目标图像的原点坐标(X轴)
dy 目标图像的原点坐标(Y轴)
sx 源图像的原点坐标(X轴)
sy 源图像的原点坐标(Y轴)
sh 源图像的大小(高度)
sw 源图像的大小(宽度)
dw 目标图像的大小(宽度)
dh 目标图像的大小(高度)
image 绘制到canvas上面的图像(HTMLImageElement)
说明
[1] drawImage方法的第一个参数可以是HTMLImageElement类型的图像或HTMLCanvasElement类型的Canvas对象
或者HTMLVideoElement类型的视频对象。
[2] drawImage方法可以将一幅图像(Canvas对象 」视频帧)的整体或部分绘制到Canvas中,在绘制到画布的时候可以
任意指定绘制的位置以及缩放的比例。
图示

示例-01
<canvas id="canvas" width="800" height="1000"></canvas>
<script>
//[1] 获取画布和对应的上下文
var ctx = document.getElementById("canvas").getContext("2d");
//[2] 创建Image图像并设置数据源
var img = new Image();
img.src = "PQ.png";
img.alt = "我是一头小猪,我全家都是猪~";
//[3] 监听图片加载完毕,绘制图片到画布
img.onload = function(){
//演示001
//把图片绘制到Canvas画布上,绘制参考的原点坐标为(0,0),等比例缩放图片大小至宽高均为200
ctx.drawImage(img,0,0,200,200)
//演示002
//剪切(剪切起点的参考坐标为[150,0])图片的一部分(右半边)绘制到画布上,绘制参考的原点坐标为(205,0)
ctx.drawImage(img,150,0,150,300,205,0,150,300)
//演示003
//把图片(300 * 300)绘制到画布的指定位置,绘制参考的原点坐标为(360,0)
ctx.drawImage(img,360,0);
}
</script>

示例-02
<canvas id="canvas" width="2000" height="800"></canvas>
<script>
//[1] 获取页面中的Canvas和对应的上下文
var ctx = document.getElementById("canvas").getContext("2d");
//[2] 创建Image图像并设置数据源
var img = new Image();
img.src = "hero.png";
//[3] 定义变量(源图片的宽度、高度、等分数量)
var width = 1620,height = 240,equalDivisionCount = 7;
//[4] 监听Image图像的加载
img.onload = function(){
//[5] 等Image图像加载完成后先把完整的图像绘制到画布
ctx.drawImage(img,0,0)
//[6] 通过定时器来控制图像的绘制(动画)
var i = 0;
var timer = setInterval(function () {
ctx.canvas.width = 2000;
ctx.drawImage(
img,
width * i/equalDivisionCount,0,
width/equalDivisionCount,height,
width * i/equalDivisionCount,0,
width/equalDivisionCount,height
);
i++;
if(i == 7)
{
clearInterval(timer);
ctx.drawImage(img,0,0)
}
},200);
}
</script>

把Canvas画布转换为图像
语法 canvas.toDataURL()
作用 该方法用于将Canvas画布的内容转换为图像。
示例
<canvas id="canvas" width="200" height="200"></canvas>
<img src="" alt="">
<script>
//[1] 获取页面中的img标签
var oImage = document.getElementsByTagName("img")[0];
//[2] 获取页面中的canvas标签
var canvas = document.getElementById("canvas");
//[3] 获取画布的上下文对象
var ctx = canvas.getContext("2d");
//[4] 创建Image图片对象
var img = new Image();
//[5] 设置Image图像的数据源
img.src = "PQ.png";
//[6] 监听Image图像的加载
img.onload = function () {
//[7] 把图像绘制到Canvas画布中
ctx.drawImage(img, 0,0,200,200);
//[8] 把画布转换为图像保存并显示
oImage.src = canvas.toDataURL();
}
</script>

Canvas标签对象的toDataURL方法把画布转换为Base64表示的图像。
getImageData
语法 ctx.getImageData(dx,dy,w,h)
作用 获取(复制)Canvas画布上指定矩形区域的像素数据。
putImageData
语法 ctx.putImageData(imgData,dx,dy,[dirtyX],[dirtyY],[dirtyWidth],[dirtyHeight]);
作用 该方法用于将指定ImageData对象的图像数据放回到画布上。
参数
imgData 规定要放回画布的ImageData对象
dx 绘制到画布的位置(X坐标),以像素计。
dy 绘制到画布的位置(Y坐标),以像素计。
dirtyX 部分截取imageData对象的位置(X坐标),默认为0。
dirtyY 部分截取imageData对象的位置(Y坐标),默认为0。
dirtyWidth 部分截取imageData对象的大小(宽度),默认为整幅图像的宽度。
dirtyHeight 部分截取imageData对象的大小(高度),默认为整幅图像的高度。
说明 putImageData()方法的后四个参数是可选的,在调用时要么传递3个参数要么传递7个参数。
示例
<canvas id="canvas" width="1000" height="400"></canvas>
<script>
//[1] 获取页面中的Canvas画布
var canvas = document.getElementById("canvas");
//[2] 获取Cnavas的上下文对象
var ctx = canvas.getContext("2d");
//[3] 在画布指定位置绘制一个填空矩形
ctx.fillStyle="#f9f";
ctx.fillRect(10,10,100,50);
//演示001
//[4] 获取画布中指定矩形区域的图像数据,然后再放到画布的指定位置(相当于复制)
ctx.putImageData(ctx.getImageData(10,10,100,50),120,10);
ctx.putImageData(ctx.getImageData(10,10,100,50),230,10,0,0,50,50);
//[5] 创建Image图像
var img = new Image();
//[6] 设置Image图像的数据源
img.src = "Yu.jpg";
//[7] 监听Image图像的加载
img.onload = function () {
//[8] 把图像绘制到Canvas画布中
ctx.drawImage(img,10,70,100,60);
//演示002
//[9] 获取画布中指定矩形区域的图像数据,然后再放到画布的指定位置(测试参数)
var imgData = ctx.getImageData(10,70,100,60);
/*
* 3个参数的情况
* 第一个参数:imageData对象
* 第二个参数:绘制到画布的位置(X)
* 第三个参数:绘制到画布的位置(Y)
* */
ctx.putImageData(imgData,120,70);
/*
* 7个参数的情况
* 第一个参数:imageData对象
* 第二个参数:绘制到画布的位置(X)
* 第三个参数:绘制到画布的位置(Y)
* 第四个参数:部分截取imageData对象的位置(X)
* 第五个参数:部分截取imageData对象的位置(Y)
* 第六个参数:部分截取imageData对象的大小(宽度)
* 第七个参数:部分截取imageData对象的大小(高度)
* */
ctx.putImageData(imgData,230,70,50,0,100,60);
ctx.putImageData(imgData,340,70,0,30,100,60);
ctx.putImageData(imgData,450,70,0,0,100,30);
ctx.putImageData(imgData,560,70,0,0,100,60);
}
</script>

在指定Canvas偏移量的时候,需要以CSS像素为单位,然而在指定图像数据中矩形区域时需要以设置像素为单位。此外,需要注意putImageData的后四个参数确定的区域被称为脏矩形(dirty rectangle),当浏览器将脏矩形赋值到Canvas画布的时候,会默认将设备像素转换为CSS像素。
二、ImageData对象
在上文中介绍的getImageData()方法,其返回的是ImageData类型的对象,该对象包含width、height以及data等三个属性。其中width代表的是以设备像素(device pixel)为单位的图像数据宽度,而height相应的代表着数据的高度,此外data是包含着各个设备像素数值的数组。
在ImageData对象中,data属性所包含的每个数组元素,均对应表示图像数据中的相应像素值。
每个像素中都存在四方面的信息,分别代表当前像素的颜色(RGB - Red 」Green 」Blue)和透明度(A - alpha)。这些信息都使用包含8个二进制位(2的八次方)的整数来表示,取值范围为 0 ~ 255 。
也就是说,
ImageData.data[0]代表的是红色数值,
ImageData.data[1]代表的是绿色数值,
ImageData.data[2]代表的是蓝色数值,
ImageData.data[3]代表的是透明度数值。
循环往复(如果数据数组的长度为n,那么`ImageData.data[n-4]`代表红色数值,其它的类推)。
createImageData方法
语法
ctx.createImageData(w,h);ctx.createImageData(imageDataOther);
作用 该方法根据指定的宽高(目标对象的宽高)来创建新的空白的ImageData对象。
参数
w 指定的宽度。
h 指定的高度。
imageDataOther 参考的图像数据。
示例-01
<canvas id="canvas" width="600" height="400"></canvas>
<script>
//[1] 获取页面中的Canvas画布和对应的上下文
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//[2] 创建ImageData对象
var imageData = ctx.createImageData(2,2);
console.log(imageData);
/*
* data: Uint8ClampedArray(16) [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
* height: 2
* width: 2
*/
//[3] 在画布中绘制红色矩形
ctx.fillStyle = "red";
ctx.fillRect(0,0,20,20);
//[4] 获取画布中指定区域的图像数据
imageData = ctx.getImageData(0,0,2,2);
console.log(imageData);
/*
* data: Uint8ClampedArray(16) [255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255]
* height: 2
* width: 2
*/
</script>
新对象的默认像素值
transparent black,表示为(0, 0 , 0 , 0)。其中前三项代表的是颜色,最后一项代表的是透明度,color/alpha以数组形式存在,而数组的大小为ImageData对象的四倍。
示例说明
在上面的代码中ctx.createImageData(2,2)表示要创建2 * 2区域的空白ImageData对象。
调用方法后得到的ImageData对象拥有 2 * 2 = 4个像素,每个像素由数组中的四个元素表示。
打印ImageData属性得到的结果([4])显示为:
data:Uint8ClampedArray(16) [255,0,0,255,255,0,0,255,255,0,0,255,255,0,0,255]
我们观察下标0~3的这组数据:255,0,0,255,尝试给出标注结果为255(Red),0(Green),0(Blue),255(alpha)
通过上面的分析,在掌握ImageData内部表示结构后,我们发现通过代码完全可以精准的控制图像的任何一个像素的显示,包括该像素的RGB颜色和透明度均可以控制,结合相应的算法和计算公式就可以简单的实现任何滤镜效果。
示例-02
<canvas id="canvas" height="400" width="600"></canvas>
<script>
//[1] 获取画布和绘图上下文
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//[2] 创建ImageData对象(10 * 10)
var imgData = ctx.createImageData(10,10);
//[3] 设置ImageData图像使用红色填充
var length = imgData.data.length;
for (var i = 0; i<length; i+=4)
{
imgData.data[i+0] = 255;
imgData.data[i+1] = 0;
imgData.data[i+2] = 0;
imgData.data[i+3] = 255;
}
//[4] 把图像数据绘制到画布上面
ctx.putImageData(imgData,0,0);
</script>

前端开发系列027-基础篇之Canvas绘图(图像)的更多相关文章
- 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)
背景 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...
- 前端开发:css基础知识之盒模型以及浮动布局。
前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西? 为什么这个浮动没有效果? 这个问题楼主已经回答了n遍.今天则是把 ...
- ESP8266开发之旅 基础篇① 走进ESP8266的世界
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- openlayers5-webpack 入门开发系列一初探篇(附源码下载)
前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...
- leaflet-webpack 入门开发系列一初探篇(附源码下载)
前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...
- 【Windows10 IoT开发系列】配置篇
原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...
- ESP8266开发之旅 基础篇④ ESP8266与EEPROM
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
随机推荐
- HashMap 的 put 方法源码分析(JDK 1.8)
一.HashMap 的 put 方法源码分析(JDK 1.8) 以下是 HashMap 的 put 方法的源码(JDK 1.8): hash(key) 方法 hash(key) 方法用于计算键的哈希值 ...
- 剑气纵横千行码:AI写就的设计模式侠客行助您仗剑走天涯
烟火里的江湖旧忆 暮色里,代码侠的电动车在巷口急刹,外卖箱里的热汤晃出细响,恍惚间竟像当年工厂堡锻造炉的轰鸣.难得休息之余,他抹了把额头的汗,扶了扶常开网约车的腰,摸了摸自己晒黑的脸,偶感那颠炒粉的手 ...
- 题解:CF1433D Districts Connection
一道简单构造题,一次性 AC. 一种想法是将所有值一样的点全部连到同一个不同值的点上,这样就是所有同一种值的点都有同一个父亲,即可避免连在一起的问题,无解的情况就是只有一种值. 时间复杂度 O(n2) ...
- 【工具】FreePic2PDF+PdgCntEditor|PDF批量添加书签(Windows)
这俩软件都不大,比较便携. FreePic2PDF: 我下载的来源:https://www.52pojie.cn/thread-1317140-1-1.html(包含下载链接https://www.l ...
- SOUI2-布局系统
布局系统 每个UI界面都是由大量的界面元素构成的,在window编程中,这些界面元素的最小单位被称为控件,而布局则是这些控件在界面的相对位置和大小. 目前SOUI支持锚点布局.线性布局.网格布局,下面 ...
- ASCII字符与非ASCII字符的正则
private static System.Text.RegularExpressions.Regex regex = new Regex("([\u0000-\uffff])") ...
- Tomcat启动信息乱码
异常描述:大概看到这个鬼样子-- 打开tomcat解压后文件: conf -> logging.properties 右键,选择以记事本或其他方式打开(只要能修改文件内容的软件都OK) 找到 j ...
- SpringBoot3整合SpringSecurity6(四)添加用户、密码加密
写在前面 还记得在之前的文章中,我们在user表中手动插入了3条数据吗? 当时,大家就会有疑问.这一串密码是怎么来的呢,我们为啥要对密码进行加密? 带着这些疑问,我们继续上路.我们在开发一个应用系统, ...
- WindowsPE文件格式入门11.资源表
https://www.bpsend.net/thread-411-1-1.html 资源表 资源的管理方式采用windows资源管理器目录的管理方式,一般有三层目录. 根目录 结构体IMAGE_RE ...
- 敏捷史话(十六):我对《敏捷宣言》没有半点贡献—— Brian Marick
" 虽然我是敏捷宣言的作者之一,但我实际上的贡献只是提供了'宣言'这个词而已."Brian Marick 在一次演讲上说道.他说完,现场传来阵阵笑声.因为大家都明白,这只是他的自谦 ...