【canvas】canvas基础使用(七):绘制图像

news2024/9/21 12:40:46

简言

学习canvas如何绘制图片或视频。

绘制图像

给定一个图像,一般使用drawImage()方法绘制。

drawImage 绘制图像

Canvas 2D API 中的 CanvasRenderingContext2D.drawImage() 方法提供了多种在画布(Canvas)上绘制图像的方式。
语法:
指定绘制位置快速绘制:
drawImage(image, dx, dy);
指定绘制位置宽高快速绘制:
drawImage(image, dx, dy, dWidth, dHeight);
指定图像被绘制区域和绘制区域绘制:
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
在这里插入图片描述

使用方法有三种

参数:

  • image
    绘制到上下文的元素。允许任何的画布图像源,例如:HTMLImageElement、SVGImageElement (en-US)、HTMLVideoElement、HTMLCanvasElement、ImageBitmap、OffscreenCanvas 或 VideoFrame (en-US)。

  • sx 可选
    需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的左上角 X 轴坐标。可以使用 3 参数或 5 参数语法来省略这个参数。

  • sy 可选
    需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的左上角 Y 轴坐标。可以使用 3 参数或 5 参数语法来省略这个参数。

  • sWidth 可选
    需要绘制到目标上下文中的,image 的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的 sx 和 sy 开始,到 image 的右下角结束。可以使用 3 参数或 5 参数语法来省略这个参数。使用负值将翻转这个图像。

  • sHeight 可选
    需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。使用负值将翻转这个图像。

  • dx
    image 的左上角在目标画布上 X 轴坐标。

  • dy
    image 的左上角在目标画布上 Y 轴坐标。

  • dWidth
    image 在目标画布上绘制的宽度。允许对绘制的 image 进行缩放。如果不说明,在绘制时 image 宽度不会缩放。注意,这个参数不包含在 3 参数语法中。

  • dHeight
    image 在目标画布上绘制的高度。允许对绘制的 image 进行缩放。如果不说明,在绘制时 image 高度不会缩放。注意,这个参数不包含在 3 参数语法中。

注意

  • 当 drawImage() 需要在 HTMLVideoElement 工作时,仅当 HTMLMediaElement.readyState 大于 1 时 drawImage() 才能正常工作。
  • 在绘制,裁剪和/或缩放时,drawImage() 将始终使用源元素的固有尺寸(以 CSS 像素为单位)。
  • 在某些旧版本浏览器中,drawImage() 将忽略图像中的所有 EXIF 元数据,包括方向。此行为在 iOS 设备上尤其麻烦。你应该自己检测方向并使用 rotate() 使其正确。

示例

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const image = document.getElementById("source");

image.addEventListener("load", (e) => {
  ctx.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104);
});

ImageData 绘制图像

获得一个ImageData 对象后,使用putImageData()方法绘制。

可以通过CanvasRenderingContext2D.getImageData()获得一个ImageData 对象,用来描述 canvas 区域隐含的像素数据。

语法:
ImageData ctx.getImageData(sx, sy, sw, sh);
参数:

  • sx
    将要被提取的图像数据矩形区域的左上角 x 坐标。

  • sy
    将要被提取的图像数据矩形区域的左上角 y 坐标。

  • sw
    将要被提取的图像数据矩形区域的宽度。

  • sh
    将要被提取的图像数据矩形区域的高度。

getImageData()

CanvasRenderingContext2D.getImageData() 返回一个ImageData对象,用来描述 canvas 区域隐含的像素数据,这个区域通过矩形表示,起始点为*(sx, sy)、宽为sw、高为sh。*

putImageData()

CanvasRenderingContext2D.putImageData() 是 Canvas 2D API 将数据从已有的 ImageData 对象绘制到位图的方法。如果提供了一个绘制过的矩形,则只绘制该矩形的像素。此方法不受画布转换矩阵的影响。
语法:
void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
参数:

  • imageData
    ImageData,包含像素值的数组对象。

  • dx
    源图像数据在目标画布中的位置偏移量(x 轴方向的偏移量)。

  • dy
    源图像数据在目标画布中的位置偏移量(y 轴方向的偏移量)。

  • dirtyX 可选
    在源图像数据中,矩形区域左上角的位置。默认是整个图像数据的左上角(x 坐标)。

  • dirtyY 可选
    在源图像数据中,矩形区域左上角的位置。默认是整个图像数据的左上角(y 坐标)。

  • dirtyWidth 可选
    在源图像数据中,矩形区域的宽度。默认是图像数据的宽度。

  • dirtyHeight 可选
    在源图像数据中,矩形区域的高度。默认是图像数据的高度。

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图像剪辑</title>
  <style>
    html,
    body {
      width: 100vw;
      height: 100%;
      margin: 0;
      padding: 0;
    }

    .box {
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      padding: 24px;
    }

    .box-content {
      margin-top: 16px;
      box-sizing: border-box;
      width: 100%;
      /* height: 500px; */
      /* display: flex; */
      align-items: center;
      text-align: center;
      border: 1px solid #000;
    }

    #origin {
      width: 500px;
      height: 500px;
      border: 1px solid #000;
    }
  </style>
</head>

<body>
  <div class="box">
    <div>
      <h1>图像查看</h1>
      <input type="file" name="file" id="file">

    </div>
    <div class="box-content">
      <canvas id="origin" width="500" height="500">
      </canvas>

    </div>
    <div>
    </div>
  </div>
  <script>
    const file = document.getElementById('file');
    const origin = document.getElementById('origin');
    const ctx = origin.getContext('2d');
    const img = document.createElement('img');
    //  辅助线
    let fx = 0
    let fy = 0
    let showf = false
    //  图片缩放
    let scale = 1 //  图片缩放比例
    let dx = 0 //  图片偏移 x
    let dy = 0//  图片偏移 y
    let dw = origin.width
    let dh = origin.height


    let modify = false

    origin.addEventListener("mousedown", (e) => {
      modify = true
      showf = true
      lastX = e.offsetX
      lastY = e.offsetY
    });
    origin.addEventListener("mousemove", (e) => {
      if (!ctx) return

      let x = e.offsetX
      let y = e.offsetY


      if (modify) {
        fx = x
        fy = y

        dx += (x - lastX)
        dy += (y - lastY)
        lastX = x
        lastY = y
        drawOperatingLine()
      }
    })
    origin.addEventListener('mouseup', (e) => {
      if (modify) {
        modify = false
        showf = false

        drawOperatingLine()

      }
    })
    origin.addEventListener("contextmenu", (e) => {
      e.preventDefault()
      if (img.width > img.height) {
        scale = origin.width / img.width
      } else {
        scale = origin.height / img.height
      }
      dx = (origin.width - scale * img.width) / (origin.width / e.offsetX)
      dy = (origin.height - scale * img.height) / (origin.height / e.offsetY)
      drawOperatingLine()
    })

    origin.addEventListener('wheel', (e) => {
      const { deltaY } = e

      if (deltaY > 0) { // 下滑放大
        scale += 0.1
      } else if (scale > 0.1) { // 上滑缩小
        scale -= 0.1

      }
      dx = (origin.width - scale * img.width) / (origin.width / e.offsetX)
      dy = (origin.height - scale * img.height) / (origin.height / e.offsetY)

      drawOperatingLine()
    })

    file.addEventListener('change', (e) => {
      const file = e.target.files[0];

      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = (e) => {
        img.src = e.target.result;
        img.onload = () => {
          //  更新图片缩放比例
          if (img.width > img.height) {
            scale = origin.width / img.width
          } else {
            scale = origin.height / img.height
          }
          drawOperatingLine(true)
        }

      }
    })
    //  绘制裁剪控制图像
    function drawOperatingLine(init = false) {

      ctx.clearRect(0, 0, origin.width, origin.height)
      //  绘制图像
      dx = init ? (origin.width - scale * img.width) / 2 : dx  //  图片偏移 x
      dy = init ? (origin.height - scale * img.height) / 2 : dy //  图片偏移 y
      dw = scale * img.width
      dh = scale * img.height
      ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, dw, dh);

      //  辅助线
      if (showf) {
        ctx.save()
        ctx.beginPath();
        ctx.strokeStyle = 'red'
        ctx.setLineDash([3, 3])
        ctx.moveTo(0, fy);
        ctx.lineTo(origin.width, fy);
        ctx.moveTo(fx, 0);
        ctx.lineTo(fx, origin.height);
        ctx.stroke();
        ctx.restore()
      }

    }


  </script>
</body>

</html>

在这里插入图片描述

结语

结束了。

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

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

相关文章

租用境外服务器,越南服务器的优势有哪些

自从中国加入世界贸易组织之后&#xff0c;国内经济增加速度非常快&#xff0c;同时越来越多的人选择去东南亚国家发展&#xff0c;因为当地的中国人很多&#xff0c;所以中国企业在当地面临着更小的文化差异。东南亚地区也是最新的经济体&#xff0c;互联网正处于蓬勃发展的阶…

docker-compose部署RabbitMQ(一步到位)

docker-compose如下 version: 3.1 services:rabbitmq:restart: alwaysimage: rabbitmq:managementcontainer_name: rabbitmqhostname: rabbitports:- 5672:5672- 15672:15672environment:TZ: Asia/ShanghaiRABBITMQ_DEFAULT_USER: rabbitRABBITMQ_DEFAULT_PASS: 123456volumes…

(弟弟14)递归•按顺序打印一个整数的每一位

这里是目录哦 题目代码运行截图递归思路递归停止条件如何实现“按顺序”悟了✨加油&#x1f389; 题目 按顺序打印一个整数的每一位。 代码 #include<stdio.h> void Print(int n) {if (n > 9)//递归停止条件{Print(n / 10);//不断趋近递归停止条件}printf("%d…

如何在Linux通过docker搭建Plik文件系统并实现无公网IP管理内网文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

宝塔面板部署腾讯云的域名

一、腾讯云&#xff0c;搜索我的证书&#xff0c;点击打开如图所示&#xff0c;点击下砸 二、点击宝塔的证书&#xff0c;然后下载到桌面 三、解压 四、打开宝塔&#xff0c;网站》自己的项目列表中要绑定的ssl 五、对应的文件内容复制进去&#xff0c;保存并启用证书 六、有了…

SCI 四区(JEI)投稿到录用过程中的经历和心得体会

计算机视觉领域中&#xff0c;包含目标检测、三维重建、语义分割、图像分类等分支。其中&#xff0c;目标检测分支最卷&#xff0c;你知道的&#xff0c;没有背景和资源&#xff0c;发一篇SCI属实不易。本篇博客详细介绍本人投稿到录用过程中的经历和心得。 目录 1. 硬件资源落…

docker服务无法启动

背景&#xff1a;断电重启经常会导致磁盘io错误&#xff0c;甚至出现磁盘坏块 这时可以使用xfs_repair来修复磁盘&#xff0c;但是修复过程可能会导致部分数据丢失 xfs_repair -f -L /dev/sdc问题一&#xff1a; Apr 15 19:27:15 Centos7.6 systemd[1]: Unit docker.service e…

【Linux C | 多线程编程】线程同步 | 互斥量(互斥锁)介绍和使用

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

vmware esxi6.0安装配置操作

系统安装及配置 在服务器上安装ESXI 6.0 提示是否继续安装 如果不想安装,按ESC后再按F11即可,稍后电脑会重启. 继续安装,则按回车键 按F11同意声明继续 选择将EXSI 安装到哪个硬盘上,我这里使用的是虚拟机,所以只有这一个选项 选择默认键盘布局,默认的美国键盘即可 设置root…

每日一题---OJ题: 有效的括号

片头 嗨! 小伙伴们,大家好! 我们又见面啦! 今天我们来一起尝试一下这道题目---有效的括号,准备好了吗? 我们开始咯! 说实话,我刚开始做这道题的时候也是一脸懵,怎么进行括号匹配呢? 别慌,我们一起画个图,分析分析括号匹配的过程~ 如下图所示,上方表示一个字符串数组,存放不…

hadoop最新详细版安装教程 2024 最新版

文章目录 hadoop安装教程 2024最新版提前准备工作用户配置安装 SSH Server免密登录设置编辑 SSH server 配置文件配置Java环境查看java 版本验证 环境变量设置安装Hadoop下载hadoop解压hadoop查看hadoop 版本hadoop 配置编辑编辑配置文件core-site.xml编辑配置文件hdfs-site.xm…

gma 2 用户文档(pdf版)更新计划

随着 gma 2 整体构建完成&#xff0c;下一步继续针对库内所有功能完成一个用户指南&#xff08;非网站&#xff09;。相较于上次更新用户文档pdf版&#xff0c;已经过去了大半年。当然&#xff0c;PDF 版比网站上内容更丰富&#xff0c;也更新&#xff08;文档基于 gma 2.0.9a2…

Spring Cloud Gateway详细介绍以及实现动态路由

一. 简介 Spring Cloud Gateway This project provides a libraries for building an API Gateway on top of Spring WebFlux or Spring WebMVC. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to …

【读书笔记】自动驾驶与机器人中的SLAM技术——高翔

文章会对本书第五章节及以后章节进行总结概括。每日更新一部分。一起读书吧。 第五章——基础点云处理 重点&#xff1a;点云的相邻关系是许多算法的基础 5.1 激光雷达传感器与点云的数学模型 5.1.1激光雷达传感器的数学模型 雷达有两种&#xff1a;机械旋转式激光雷达&…

018——红外遥控模块驱动开发(基于HS0038和I.MX6uLL)

目录 一、 模块介绍 1.1 简介 1.2 协议 二、 驱动代码 三、 应用代码 四、 实验 五、 程序优化 一、 模块介绍 1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中&#xff0c;像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和…

RISCV指令集体系简读之RV32M

RV32M向RV32I中添加了整数乘法和除法指令&#xff1b; RV32M具有有符号和无符号整数的除法指令&#xff1a;divide(div)和divide unsigned(divu)&#xff0c;它们将 商放入目标寄存器。在少数情况下&#xff0c;程序员需要余数而不是商&#xff0c;因此RV32M提供 remainder(rem…

46.HarmonyOS鸿蒙系统 App(ArkUI)网格布局

Grid(){GridItem(){Button(按钮1).fontSize(28)}.backgroundColor(Color.Blue)GridItem(){Text(数学).fontSize(28)}.backgroundColor(Color.Yellow)GridItem(){Text(语文).fontSize(28)}.backgroundColor(Color.Green)GridItem(){Text(英语).fontSize(28)}.backgroundColor(Co…

结构型模式--3.组合模式【草帽大船团】

1. 好大一棵树 路飞在德雷斯罗萨打败多弗朗明哥之后&#xff0c;一些被路飞解救的海贼团自愿加入路飞麾下&#xff0c;自此组成了草帽大船团&#xff0c;旗下有7为船长&#xff0c;分别是&#xff1a; 俊美海贼团75人 巴托俱乐部56人 八宝水军1000人 艾迪欧海贼团4人 咚塔塔海…

暴雨信息专场推介会亮相武汉国际创科展

4月14日&#xff0c;暴雨信息专场推介会亮相2024年武汉国际创科展。推介会以“智慧聚变新生”为主题&#xff0c;集中展示推介暴雨信息旗下多项颇具市场优势的智能化产品和解决方案&#xff0c;邀请多位专家分享在数字化转型领域的成果和实践经验&#xff0c;与业界同仁共同探讨…

osg渲染过程

目录 1、渲染最简单代码 2、详解run方法 3、详细过程 4、回调函数 5、Node Visitor 1、渲染最简单代码 2、详解run方法 3、详细过程 3.1 advance()方法 进行帧计数 3.2 eventTraversal() eventTraversal()响应用户操作,eventTraversal()遍历的是事件队列&#xff0c;而…