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

news2025/2/27 8:36:55

想象一下,用几行代码就能创造出如此逼真的图像和动画,仿佛将艺术与科技完美融合,前端开发的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.pageX
                let y = e.pageY
                ctx.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] = avg
                imageData.data[i + 1] = avg
                imageData.data[i + 2] = avg
                imageData.data[i + 3] = 255
            }
            // 将修改后的数据呈现渲染到画布上
            ctx.putImageData(imageData, 0, 0)
        }
    </script>
</body>

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

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

呈现的效果如下所示: 

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

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

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

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

相关文章

【深度学习(42)】通过vscode使用anaconda的python环境

按ctrlshiftp&#xff0c;选择Python:Select Interpreter 选择anaconda下的python虚拟环境

【spark】Exception in thread “main“ ExitCodeException exitCode=-1073741701

在window上运行spark程序写到本地文件的时候报错。 val rdd sc.sparkContext.parallelize(list)val arr rdd.collect()arr.foreach(println)rdd.saveAsTextFile("test1")sc.close()错误信息: zhangsan lisi wangwu Exception in thread "main" ExitCode…

连续6年夺冠 6项细分领域第一,中电金信持续领跑中国银行业IT解决方案市场

7月9日&#xff0c;工信部赛迪顾问发布《2023年度中国银行业IT解决方案市场分析报告》&#xff08;简称《报告》&#xff09;。中电金信以7.38%的市场份额再度蝉联2023中国银行业IT解决方案市场份额第一&#xff0c;以显著优势持续领跑中国银行业IT解决方案市场。在细分领域&am…

【普中】基于51单片机的矩阵电子密码锁LCD1602液晶显示 proteus仿真+程序+设计报告+讲解视频

【普中】基于51单片机的矩阵电子密码锁LCD1602液晶显示设计 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接&#xff1a; 【普中】基于51单片机的矩阵电子密码锁LCD1602液晶显示设计 ( proteus仿真…

UV胶,它是否有毒?如同那些隐藏在黑暗中的危险之物?

UV胶&#xff0c;它是否有毒&#xff1f;如同那些隐藏在黑暗中的危险之物&#xff1f; 关于uv胶的毒性问题&#xff0c;或许我们可以这样深入探讨。UV胶&#xff0c;如同一位戴着神秘面纱的访客&#xff0c;在我们的生活中悄然出现&#xff0c;却带着诸多疑问。那么&#xff0…

怎样把视频字幕提取出来?分享4个零门槛的字幕提取工具

暑假正是弯道超车的好机会&#xff01;相信不少朋友都会选择宅在家自学网课。 不可否认的是&#xff0c;海量学习资源的确可以让学习变得更加便捷与自由。然而&#xff0c;如何高效地吸收和理解在线课程也就成为了一个关键问题。不敢想倘若此时能够拥有一款高效又实用的视频提…

菜花插画:成都亚恒丰创教育科技有限公司

菜花插画&#xff1a;田园诗意的视觉盛宴 在纷扰繁杂的都市生活中&#xff0c;人们往往渴望一抹清新与宁静&#xff0c;以慰藉心灵的疲惫。而菜花插画&#xff0c;恰似一股来自乡野的清风&#xff0c;以其独特的田园诗意&#xff0c;成都亚恒丰创教育科技有限公司为我们的视觉…

结构体案例1

代码 #include <iostream> using namespace std; #include <string> #include <ctime>//学生的结构体 struct Student {string sName;int score; }; //老师的结构体定义 struct Teacher {string tName;struct Student sArray[5]; };//给老师和学生赋值的函数…

HTML5使用<progress>进度条、<meter>刻度条

1、<progress>进度条 定义进度信息使用的是 progress 标签。它表示一个任务的完成进度&#xff0c;这个进度可以是不确定的&#xff0c;只是表示进度正在进行&#xff0c;但是不清楚还有多少工作量没有完成&#xff0c;也可以用0到某个最大数字&#xff08;如&#xff1…

在网上申请流量卡审核失败,可能是你的年龄有问题!

在网上申请流量卡审核失败&#xff0c;可能是你的年龄有问题&#xff01; 先上个图&#xff1a; ​ 网上的流量卡并不是随意申请的&#xff0c;而是填写申请信息后由运营商进行审核&#xff0c;审核通过后才会发卡&#xff0c;如果你提交的订单没有审核通过&#xff0c;那么大…

Unity之OpenXR+XR Interaction Toolkit实现 Gaze眼部追踪

使用 Unity OpenXR 实现Gaze眼部追踪 在虚拟现实(VR)和增强现实(AR)应用中,眼动追踪是一项强大而受欢迎的技术。它可以让开发者更好地理解用户的注意力和行为,并创造出更加沉浸和智能的体验。在本文中,我们将探讨如何使用 Unity OpenXR 实现Gaze眼部追踪功能。 Unity …

MySQL体系架构解析

1.MySQL体系架构 1.1.MySQL的分支与变种 MySQL变种有好几个,主要有三个久经考验的主流变种:Percona Server,MariaDB和 Drizzle。它们都有活跃的用户社区和一些商业支持,均由独立的服务供应商支持。同时还有几个优秀的开源关系数据库,值得我们了解一下。 1.1.1.Drizzle …

RockyLinux9上安装Nacos2.3.0(非Docker安装)

RockyLinux9上安装Nacos2.3.0 说明什么是Nacos下载并安装创建一个nacos-conf数据库修改application.properties文件 启动如果在项目中使用需要注意访问网址查看是否成功 开启访问鉴权 说明 本文采用的是&#xff1a;安装包安装&#xff0c;非Docker安装&#xff0c;系统采用的R…

雷池WAF动态防护功能初体验

一、 介绍 大名鼎鼎的雷池WAF最近新上了个名为 动态防护 的功能 所谓动态防护&#xff0c;是在用户浏览到的网页内容不变的情况下&#xff0c;将网页赋予动态特性&#xff0c;即使是静态页面&#xff0c;也会具有动态的随机性。 说白了就是给你网站的 html 和 js 代码加上加密…

Linux下为什么ls直接就可以运行,而你的程序要写./dir1/dir2/bin/bwa才可以

习惯了Windows电脑下的所见即所得&#xff0c;找到程序或文件双击即可运行或打开&#xff1b;于是我们被惯得以为电脑会像人一样聪明&#xff0c;给他一个名字就可以运行程序或打开文件&#xff1b;于是在命令行下或程序里不断碰壁&#xff0c;为啥这个命令不运行了呢&#xff…

2024年的设计理念革新:快速获取设计趋势的资源集合!

随着2024年第三季度开始&#xff0c;今年的设计趋势也逐渐出现。与2023 年设计相比&#xff0c;趋势变化空间不大&#xff0c;大部分是在 2023 年度设计趋势的延伸和发展。即使趋势不会一直改变&#xff0c;了解趋势对设计师来说仍然非常重要。接下来&#xff0c;本文将与你分享…

lora训练调参

Stable Diffusion 训练指南 (LyCORIS) | Coding HuskyStable Diffusion 文字生成图片的教程已经很多了。这篇文章是讲解如何用 Kohya Trainer 在 Google Colab 上训练一个 LyCORIS 模型。在读之前希望你已经至少玩过 Stable Diffusion。https://ericfu.me/stable-diffusion-fin…

阿里云通义千问开源两款语音基座模型分别是SenseVoice和CosyVoice

阿里巴巴近期发布了开源语音大模型项目FunAudioLLM&#xff0c;该项目包含了两个核心模型&#xff1a;SenseVoice和CosyVoice。可以精准多语言识别并且进行语音克隆。 SenseVoice&#xff1a;精准多语言识别与情感辨识 SenseVoice主要致力于高精度多语言语音识别、情感辨识和…

【搭建Nacos服务】centos7 docker从0搭建Nacos服务

前言 本次搭建基于阿里云服务器系统为&#xff08;CentOS7 Linux&#xff09;、Nacos&#xff08;2.0.3&#xff09;、Docker version 26.1.4 本次搭建基于一个新的云服务器 安装java yum install -y java-1.8.0-openjdk.x86_64安装驱动以及gcc等前置需要的命令 yum install …

暑期旅游季必备,用这款客服神器应对爆棚的客流咨询

解决暑期旅游客流高峰问题 暑期是旅游高峰季节&#xff0c;客流量剧增&#xff0c;客户咨询纷至沓来。在这个时候&#xff0c;如何高效处理客户的咨询成为每家旅游机构和景点不可忽视的挑战。 聊天宝快捷回复助手是一款强大的工具&#xff0c;可帮助企业在客流高峰期快速回复客…