Canvas:掌握图像变换合成与裁剪状态像素操作

想象一下,用几行代码就能创造出如此逼真的图像和动画,仿佛将艺术与科技完美融合,前端开发的Canvas技术正是这个数字化时代中最具魔力的一环,它不仅仅是网页的一部分,更是一个无限创意的画布,一个让你的想象力自由驰骋的平台。

目录

图像变换设置

图像合成设置

裁剪路径设置

状态保存与恢复

像素操作设置

图像变换设置

接下来我们开始讲解如何对canvas绘制的图像进行一些简单的操作,这里借助代码进行一个简单的概述及演示:

位移操作:这里借助translate函数传递两个参数代表水平和竖直移动的距离:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 位移,translate,位移坐标系,水平位移和竖直位移ctx.translate(100, 100)// 绘制矩形ctx.fillRect(0, 0, 50, 50)</script>
</body>

缩放操作:这里借助scale函数传递两个参数代表水平和竖直缩放的倍速:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 缩放,scale,水平缩放5倍,垂直缩放2倍ctx.scale(5, 2)// 绘制矩形ctx.fillRect(0, 0, 50, 50)</script>
</body>

旋转操作:这里借助rotate函数传递一个参数代表旋转的角度:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 旋转,rotate,旋转的角度ctx.rotate(Math.PI / 4);ctx.translate(300, 0);// 绘制矩形ctx.fillRect(-250, -25, 500, 50)</script>
</body>

综合操作:这里借助transform函数传递六个参数代表不同的作用:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// transform,参数分别代表:/*1. 水平缩放2. 水平倾斜3. 垂直倾斜4. 垂直缩放5. 水平位移6. 垂直位移*/ctx.transform(2, 1, -1, 2, 50, 0); // 绘制矩形ctx.fillRect(0, 0, 50, 50)</script>
</body>

图像合成设置

在canvas中不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分(清除区域不仅限于矩形,像clearRect()方法做的那样)以及更多其他操作,这里就其做一个简单的概述,globalCompositeOperation = type 这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识 12 种遮盖方式的字符串。这里给出其简易的示例代码:

source-over:这是默认设置,并在现有画布上下文之上绘制新图形。

source-in:新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制矩形ctx.fillStyle = "rgba(0, 0, 255, 1)"; // 蓝色ctx.fillRect(300, 200, 100, 100)ctx.globalCompositeOperation='source-in'; // 蓝色和红色重叠部分的红色区域ctx.fillStyle = "rgba(255, 0, 0, 1)"; // 红色ctx.fillRect(250, 150, 100, 100)</script>
</body>

source-out:在不与现有画布内容重叠的地方绘制新图形。

source-atop:新图形只在与现有画布内容重叠的地方绘制。

destination-over:在现有的画布内容后面绘制新的图形。

destination-in:现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。

destination-out:现有内容保持在新图形不重叠的地方。

destination-atop:现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。

lighter:两个重叠图形的颜色是通过颜色值相加来确定的。

copy:只显示新图形。

当然还有一些其他的属性,如下供大家参考:

xor:图像中,那些重叠和正常绘制之外的其他地方是透明的。

multiply:将顶层像素与底层相应像素相乘,结果是一幅更黑暗的图片。

screen:像素被倒转,相乘,再倒转,结果是一幅更明亮的图片。

overlay:multiply和screen的结合,原本暗的地方更暗,原本亮的地方更亮。

darken:保留两个图层中最暗的像素。

lighten:保留两个图层中最亮的像素。

color-dodge:将底层除以顶层的反置。

color-burn:将反置的底层除以顶层,然后将结果反过来。

hard-light:屏幕相乘(Acombinationofmultiplyandscreen)类似于叠加,但上下图层互换了。

soft-light:用顶层减去底层或者相反来得到一个正值。

difference:一个柔和版本的强光(hard-light)。纯黑或纯白不会导致纯黑或纯白。

exclusion:和difference相似,但对比度较低。

hue:保留了底层的亮度(luma)和色度(chroma),同时采用了顶层的色调(hue)。

saturation:保留底层的亮度(luma)和色调(hue),同时采用顶层的色度(chroma)。

color:保留了底层的亮度(luma),同时采用了顶层的色调(hue)和色度(chroma)。

luminosity:保持底层的色调(hue)和色度(chroma),同时采用顶层的亮度(luma)。

接下来我们可以借助globalCompositeOperation属性中的destination-out属性值实现一个类似刮刮卡的效果出来,具体的代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#ggk {width: 600px;height: 400px;font-size: 30px;font-weight: 900;text-align: center;line-height: 400px;overflow: hidden;position: absolute;left: 0;top: 0;z-index: -1;}</style>
</head>
<body><div id="ggk">谢谢回顾</div><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 是否可以挂卡let isDraw = false// 设置canvas背景let img = new Image();img.src = "./1.jpg"img.onload = function () {ctx.drawImage(img, 0, 0, 600, 400)}// 鼠标按下去可以挂卡canvas.onmousedown = function () {isDraw = true}// 鼠标抬起可以停止挂卡canvas.onmouseup = function () {isDraw = false}// 鼠标移动可以挂卡canvas.onmousemove = function (e) {if (isDraw) {let x = e.pageXlet y = e.pageYctx.globalCompositeOperation = "destination-out";ctx.arc(x, y, 20, 0, 2 * Math.PI)ctx.fill()}}// 随机中奖事件let random = Math.random()if (random < 0.1) {let ggkDiv = document.getElementById("ggk");ggkDiv.innerHTML = "恭喜你中奖了"}</script>
</body>
</html> 

最终呈现的效果如下所示:

裁剪路径设置

裁切路径和普通的canvas图形差不多,不同的是它的作用是遮罩,用来隐藏不需要的部分,如果和上面介绍的globalCompositeOperation属性作一比较,它可以实现与source-in和source-atop差不多的效果。最重要的区别是裁切路径不会在canvas上绘制东西,而且它永远不受新图形的影响。这些特性使得它在特定区域里绘制图形时相当好用。给出如下代码示例:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");let chatPath = new Path2D();chatPath.moveTo(200, 300)chatPath.quadraticCurveTo(150, 300, 150, 200); chatPath.quadraticCurveTo(150, 100, 300, 100); chatPath.quadraticCurveTo(450, 100, 450, 200); chatPath.quadraticCurveTo(450, 300, 250, 300); chatPath.quadraticCurveTo(250, 350, 150, 350); chatPath.quadraticCurveTo(200, 350, 200, 300); ctx.clip(chatPath) // 裁剪路径// 获取图片let img = new Image();img.src = "./1.jpg";img.onload = function () {ctx.drawImage(img, 0, 0, 600, 400)ctx.lineWidth = 5 // 路径的宽度ctx.stroke(chatPath) // 显示路径,可有可无}</script>
</body>

最终呈现的效果如下所示:

状态保存与恢复

canvas的状态就是当前画面应用的所有样式和变形的一个快照,save和restore方法是用来保存和恢复canvas状态的且都没有参数,canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。示例代码如下所示:

<body><canvas id="canvas" width="800" height="800"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制矩形ctx.fillStyle = "red";ctx.fillRect(0, 0, 100, 100);ctx.save() // 保存当前状态ctx.fillStyle = "green";ctx.fillRect(100, 100, 100, 100);ctx.save() // 保存当前状态ctx.fillStyle = "blue";ctx.fillRect(200, 200, 100, 100);ctx.save() // 保存当前状态ctx.fillStyle = "yellow";ctx.fillRect(300, 300, 100, 100);ctx.restore() // 恢复到上一次保存的状态ctx.fillRect(400, 400, 100, 100) // 蓝色ctx.restore() // 恢复到上一次保存的状态ctx.fillRect(500, 500, 100, 100) // 绿色</script>
</body>

最终呈现的效果如下所示:

像素操作设置

在canvas中我们可以直接通过ImageData对象操纵像素数据,直接读取或将数据数组写入该对象中,接下来我们开始讲解如何控制图像使其平滑(反锯齿)以及如何从canvas画布中保存对象。在让一些代码中我们通过getImageData获取图片的像素数据,并对其进行像素数据的修改,如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 获取图片let img = new Image();img.src = "./1.jpg"img.onload = function () {ctx.drawImage(img, 0, 0, 600, 400);let imageData = ctx.getImageData(0, 0, 600, 400) // 获取图片信息数组for (let i = 0; i < imageData.data.length; i+=4) {// 计算当前像素的平均值let avg = (imageData.data[i] + imageData.data[i+1] + imageData.data[i+2]) / 3;imageData.data[i] = avgimageData.data[i + 1] = avgimageData.data[i + 2] = avgimageData.data[i + 3] = 255}// 将修改后的数据呈现渲染到画布上ctx.putImageData(imageData, 0, 0)}</script>
</body>

最终呈现的效果如下所示,可以看到我们对原本的图片实现了一个复古效果的展示:

如果想实现对图片像素的反向操作,可以设置如下的代码进行实现:

呈现的效果如下所示: 

如果想绘制从某一坐标到另一坐标的的区域位置的话,可以通过如下代码操作:

ctx.putImageData(imageData, 0, 0, 300, 200, 600, 400)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/44022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java使用poi-tl模版引擎导出word之if判断条件的使用

文章目录 模版中if语句条件的使用1.数据为False或空集合2.非False或非空集合 模版中if语句条件的使用 如果区块对的值是 null 、false 或者空的集合&#xff0c;位于区块中的所有文档元素将不会显示&#xff0c;这就等同于if语句的条件为 false。语法示例&#xff1a;{{?stat…

视图库对接系列(GA-T 1400)十四、视图库对接系列(本级)新增、修改订阅

说明 之前我们已经对接的设备,设备的话比较简单,是设备主动推送数据到平台的。 相信大家已经会了,那今天开始的话,我们来做对接平台,相对难点点。 但搞懂了核心的订阅流程的话,其实就不难了。 对接平台 订阅接口 订阅接口的话,有几个,添加、查询、更新、删除、取消…

Linux镜像源设置不再难:一键脚本,新手也能成为优化高手(一键切换镜像源/Docker一键安装脚本)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 更换镜像源 📒📝 一键切换软件源📝 Docker一键安装脚本⚓️ 相关链接 ⚓️📖 介绍 📖 在国内,Linux系统用户经常会遇到下载软件包时速度慢的问题,这通常是因为默认的镜像源并不总是最优选择。对于新手来说,手动设置…

亚马逊速卖通卖家必看:自养号测评策略,下单高效防关联全攻略

在跨境电商的激烈竞争中&#xff0c;自养号测评策略已成为众多卖家追求低成本、高效推广的优选路径。然而&#xff0c;其成功实施离不开一系列精心策划与严格执行的关键要素。以下是对这些核心条件的深入剖析&#xff0c;旨在指导您安全、有效地构建并运营自养号测评体系。 一、…

【内网渗透】MSF渗透阶段的常用指令笔记

目录 渗透阶段划分 msfvenom 常用参数 各平台生成payload命令 Meterpreter Meterpreter的常用命令 基本命令 常用命令 针对安卓手机的一些命令 针对Windows的一些命令 文件系统命令 生成木马反弹shell(以linux靶机为例) 木马生成 配置监控 攻击利用 渗透阶段划分…

从零开学C++:入门

引言&#xff1a;经过C语言和数据结构等编程知识的洗礼&#xff0c;到了暑假&#xff0c;我们就将要踏上C编程语言的学习了&#xff0c;C的学习难度比python等其他语言的学习难度更大&#xff0c;但是我们已经熟练地掌握了C语言的知识&#xff0c;相信学习起来C应该还是会简单许…

RSRS研报复现——年化21.5%,含RSRS标准分,右偏标准分的Backtrader指标计算(代码+数据)

原创文章第583篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 继续Backtrader&#xff0c;今天讲讲指标扩展。 作为规则型的量化框架&#xff0c;指标是非常重要的元素&#xff0c;它是策略的基础。 我们来扩展一个经典的指标&#xff0c;RSR…

matlab数值溢出该怎么解决?

&#x1f3c6;本文收录于《CSDN问答解惑》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

LabVIEW自动测控与故障识别系统

使用LabVIEW 2019在Win10 64位系统上开发自动测控软件&#xff0c;通过与基恩士NR-X100数据采集仪通讯&#xff0c;实时采集和分析数据&#xff0c;自动识别判断产品是否合格&#xff0c;并增加数据记录和仿真功能。 具体解决方案&#xff1a; 1. 系统架构设计 硬件接口&#…

前端面试题38(js原型与对象)

在JavaScript中&#xff0c;原型&#xff08;prototype&#xff09;是核心特性之一&#xff0c;它用于实现对象之间的继承和属性方法的共享。理解原型和对象的关系对于深入学习JavaScript至关重要。下面我会详细解释这两个概念以及它们是如何工作的&#xff0c;并给出一些示例代…

Java设计模式---(创建型模式)工厂、单例、建造者、原型

目录 前言一、工厂模式&#xff08;Factory&#xff09;1.1 工厂方法模式&#xff08;Factory Method&#xff09;1.1.1 普通工厂方法模式1.1.2 多个工厂方法模式1.1.3 静态工厂方法模式 1.2 抽象工厂模式&#xff08;Abstract Factory&#xff09; 二、单例模式&#xff08;Si…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥协商(ArkTS)】

密钥协商(ArkTS) 以协商密钥类型为X25519 256&#xff0c;并密钥仅在HUKS内使用为例&#xff0c;完成密钥协商。 开发步骤 生成密钥 设备A、设备B各自生成一个非对称密钥&#xff0c;具体请参考[密钥生成]或[密钥导入]。 密钥生成时&#xff0c;可指定参数HUKS_TAG_DERIVE…

LLM-文本分块(langchain)与向量化(阿里云DashVector)存储,嵌入LLM实践

文章目录 前言向量、令牌、嵌入分块按字符拆分按字符递归拆分按token拆分 向量化使用 TextEmbedding 实现语义搜索数据准备通过 DashScope 生成 Embedding 向量通过 DashVector 构建检索&#xff1a;向量入库语义检索&#xff1a;向量查询完整代码 总结 前言 Transformer 架构…

[C++][ProtoBuf][Proto3语法][三]详细讲解

目录 1.默认值2.更新消息1.更新规则2.保留字段reserved 3.未知字段1.是什么&#xff1f;2.未知字段从哪获取 4.前后兼容性5.选项option1.选项分类2.常用选项列举3.设置自定义选项 1.默认值 反序列化消息时&#xff0c;如果被反序列化的⼆进制序列中不包含某个字段&#xff0c;…

基于Spring Boot的旅游信息推荐信息系统设计与实现(源码+lw+部署+讲解)

技术指标 开发语言&#xff1a;Java 框架&#xff1a;Spring BootJSP JDK版本&#xff1a;JDK1.8 数据库&#xff1a;MySQL5.7 数据库工具&#xff1a;Navicat16 开发软件&#xff1a;IDEA Maven包&#xff1a;Maven3.6.3 浏览器&#xff1a;IE浏览器 功能描述 旅游信…

Hadoop-19 Flume Agent批量采集数据到HDFS集群 监听Hive的日志 操作则把记录写入到HDFS 方便后续分析

章节内容 上一节我们完成了内容&#xff1a; Flume 启动测试Flume Conf编写Flume 测试发送和接收数据 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0c;但…

深入探索大语言模型

深入探索大语言模型 引言 大语言模型&#xff08;LLM&#xff09;是现代人工智能领域中最为重要的突破之一。这些模型在自然语言处理&#xff08;NLP&#xff09;任务中展示了惊人的能力&#xff0c;从文本生成到问答系统&#xff0c;无所不包。本文将从多个角度全面介绍大语…

AGE agtype 简介

AGE 使用一种名为 agtype 的自定义数据类型&#xff0c;这是 AGE 返回的唯一数据类型。agtype 是 Json 的超集&#xff0c;也是 JsonB 的自定义实现。 简单数据类型 Null 在Cypher中&#xff0c;null用于表示缺失或未定义的值。概念上&#xff0c;null表示“缺失的未知值”&…

路径规划 | 基于蚁群算法的三维无人机航迹规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 基于蚁群算法的三维无人机航迹规划&#xff08;Matlab&#xff09;。 蚁群算法&#xff08;Ant Colony Optimization&#xff0c;ACO&#xff09;是一种模拟蚂蚁觅食行为的启发式算法。该算法通过模拟蚂蚁在寻找食物时…

【安全设备】Web应用防火墙

一、什么是Web应用防火墙 Web应用程序防火墙&#xff08;Web Application Firewall&#xff09;的缩写是WAF&#xff0c;用于保护Web应用程序免受各种恶意攻击和漏洞利用。WAF通过监控和过滤进出Web应用程序的HTTP/HTTPS流量来工作。它位于Web应用程序和用户之间&#xff0c;分…