如何使用canvas在图片上进行标注,以下代码不起作用,着实被坑到了(文末附完整代码)

news2024/11/28 4:51:32

今天发现一个有意思的问题:

如何使用canvas在图片上进行如下的标注,以下代码不起作用,如何修改

 

原始代码如下:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
 
<body>
    <img id="myimg" src="./yidongbangong20240124103725.png"></img>
    <canvas id="mycanvas"></canvas>
 
 
    <script>
        const resData = {
            data: {
                cont: [{
                    pos: [10, 20, 33, 40],
                    cont: "数据标注"
                }]
            }
        }
 
        const img = document.getElementById("myimg");
        const canvas = document.getElementById("mycanvas");
        // 调整画布大小
        const ctx = canvas.getContext("2d");
        canvas.width = img.width;
        canvas.height = img.height;
 
        console.log(1);
        // 根据数据循环生成标注框
 
        ctx.strokeStyle = "red";
        // 画布上显示图片
        ctx.drawImage(img, 0, 0, img.width, img.height);
        // 计算缩小比率
        const widthrat = (img.naturalWidth - img.width) / img.width;
        const heightrat = (img.naturalHeight - img.height) / img.height;
        resData.data.cont.forEach(value => {
            // 获取标注框的x、y坐标
            const x = value.pos[0] * widthrat;
            const y = value.pos[1] * heightrat;
            // 获取标注框的宽、高
            const wid = (value.pos[2] - value.pos[0]) * widthrat;
            const hei = (value.pos[3] - value.pos[1]) * heightrat;
            // 根据获取的数据绘制描边矩形
            
            ctx.rect(x, y, wid, hei);
 
            // 绘制描边矩形上的红色填充矩形,并稍微调整样式
            ctx.fillStyle = "red";
            ctx.fillRect(x, y - 20, ctx.measureText(value.cont).width + 20, 20);
 
            // 绘制填充矩形上的白色文字,并调整坐标
            ctx.fillStyle = '#fff';
            ctx.font = "16px Arial";
            ctx.fillText(value.cont, x + 10, y - 4);
        })
        ctx.stroke()
    </script>
</body>
 
</html>

为此,特意去网上补充了一下canvas的知识,下面是canvas的画图语法:

  • drawImage(image,x,y)

 可以知道,把一张图片画到canvas上面,具体例子如下:

<img id="img" src="logo.jpg" alt="The Scream" width="325" height="200"><p>Canvas:</p>
<canvas id="myCanvas" width="250" height="300" style="border:1px solid #eee;">
您的浏览器不支持 HTML5 canvas 标签。</canvas>

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("img");
ctx.drawImage(img, 10, 10);

 如果你也是用这个例子运行的话,也是不能运行出结果的

经过调试原始代码之后,我发现里面取到的img组件的width和height都是0

为什么都是0呢,会不会是img没有加载呢?

当然不是,因为界面都显示出来了

对于经验丰富的开发人员来说,很快就会想出原因,因为我不是专门的前端。

我实现之后才总结出原因,就是因为img是异步加载的,当我们使用canvas绘制的时候,img如果还没有加载完成,那么取到的width和height肯定都是0,因此我们需要等待图片加载完成后才能获取到宽和高。

类似解决方案代码如下:

var img = document.getElementById("img");

img.onload = function() {
	ctx.drawImage(img, 10, 10);
}

完整代码:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
 
<body>
    <img id="myimg" src="./CSDN封面/tomcat.png" width="200" height="200" onload="draw()"></img>
    <canvas id="mycanvas"></canvas>
 
 
    <script>
      function draw() { // 图片加载下载完毕时才进行标注
          const resData = {
              data: {
                  cont: [{
                      pos: [10, 20, 33, 40],
                      cont: "数据标注"
                  }]
              }
          }
   
          const img = document.getElementById("myimg");
          const canvas = document.getElementById("mycanvas");
          // 调整画布大小
          const ctx = canvas.getContext("2d");
          canvas.width = img.width;
          canvas.height = img.height;
   
          console.log(1);
          // 根据数据循环生成标注框
   
          ctx.strokeStyle = "red";
          // 画布上显示图片
          ctx.drawImage(img, 0, 0, img.width, img.height);
          // 计算缩小比率
          const widthrat = (img.naturalWidth - img.width) / img.width;
          const heightrat = (img.naturalHeight - img.height) / img.height;
          resData.data.cont.forEach(value => {
              // 获取标注框的x、y坐标
              const x = value.pos[0] * widthrat;
              const y = value.pos[1] * heightrat;
              // 获取标注框的宽、高
              const wid = (value.pos[2] - value.pos[0]) * widthrat;
              const hei = (value.pos[3] - value.pos[1]) * heightrat;
              // 根据获取的数据绘制描边矩形
              
              ctx.rect(x, y, wid, hei);
   
              // 绘制描边矩形上的红色填充矩形,并稍微调整样式
              ctx.fillStyle = "red";
              ctx.fillRect(x, y - 20, ctx.measureText(value.cont).width + 20, 20);
   
              // 绘制填充矩形上的白色文字,并调整坐标
              ctx.fillStyle = '#fff';
              ctx.font = "16px Arial";
              ctx.fillText(value.cont, x + 10, y - 4);
          })
          ctx.stroke()
        }
    </script>
</body>
 
</html>

问题来源:

https://ask.csdn.net/questions/8102015

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

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

相关文章

理解进程的基本概念

1. 什么是进程 进程&#xff0c;即执行中的程序 进程 程序执行 在计算机中&#xff0c;每一个运行的exe程序&#xff0c;就是一个进程 2.为什么会有进程 早期&#xff0c;操作系统只有一个程序&#xff0c;这样效率是很低的。为了提高CPU的利用率&#xff0c;人们将多个程…

时间复杂度的简单讲解

小伙伴们大家好&#xff0c;我们又见面了&#xff0c;这次我们直接进入正题 时间复杂度的概念 时间复杂度的定义&#xff1a;在计算机科学中&#xff0c; 算法的时间复杂度是一个函数 &#xff0c;它定量描述了该算法的运行时间。一 个算法执行所耗费的时间&#xff0c;从理论…

Hadoop-未授权访问-内置配合命令执行RCE

一、Hadoop常见端口及配置文件 Hadoop中有多种端口&#xff0c;这些端口用于不同的服务和通信。以下是Hadoop中常见的端口以及它们的用途&#xff1a; NameNode Web界面端口 (默认: 9870)NameNode 对客户端服务端口 (默认: 8020)Secondary NameNode Web界面端口 (默认: 9868)…

每日OJ题_贪心算法四⑤_力扣354. 俄罗斯套娃信封问题

目录 力扣354. 俄罗斯套娃信封问题 解析代码1_动态规划&#xff08;超时&#xff09; 解析代码2_重写排序贪心二分 力扣354. 俄罗斯套娃信封问题 354. 俄罗斯套娃信封问题 难度 困难 给你一个二维整数数组 envelopes &#xff0c;其中 envelopes[i] [wi, hi] &#xff0…

物联网杀虫灯—新型的环保杀虫设备

型号推荐&#xff1a;云境天合TH-FD2S】物联网杀虫灯是一种新型环保杀虫设备&#xff0c;其中风吸式太阳能杀虫灯作为其一种特殊类型&#xff0c;展现了独特的工作原理和优势。 风吸式太阳能杀虫灯以太阳能电池板为电源&#xff0c;白天储存电源&#xff0c;晚上为杀虫灯提供电…

资产公物仓管理系统|实现国有资产智能化管理

1、项目背景 资产公物仓管理系统&#xff08;智仓库DW-S201&#xff09;是一套成熟系统&#xff0c;依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 项目设计原则 方案对公物仓资…

Java 守护线程 ( Daemon Thread )详解

在Java中&#xff0c;线程分为两类&#xff1a;用户线程(User Thread)和守护线程(Daemon Thread)。守护线程是后台线程&#xff0c;主要服务于用户线程&#xff0c;当所有的用户线程结束时&#xff0c;守护线程也会自动结束&#xff0c;JVM会随之退出。守护线程的一个典型例子是…

docker(四):数据卷

数据卷 卷的设计目的就是数据的持久化&#xff0c;完全独立于容器的生存周期&#xff0c;因此Docker不会在容器删除时删除其挂载的数据卷。 1、docker run docker run -it --privilegedtrue -v /宿主机绝对路径目录:/容器内目录 镜像名2、挂载注意事项 --privilegedtru…

贪吃蛇(c实现)

目录 游戏说明&#xff1a; 第一个是又是封面&#xff0c;第二个为提示信息&#xff0c;第三个是游戏运行界面 游戏效果展示&#xff1a; 游戏代码展示&#xff1a; snack.c test.c snack.h 控制台程序的准备&#xff1a; 控制台程序名字修改&#xff1a; 参考&#xff1a…

【考研数学】汤家凤“免单“数学题被吐槽‘太难’,老汤回应「怎么还有脸笑」,网友:这些题有毒!

我看了汤家凤老师出的几道题&#xff0c;实际上对于考研的同学来说&#xff0c;确实是送分题 第一个是三角函数变换中的万能公式&#xff1b;第二个e^x的泰勒展开公式&#xff1b;第三个是第一类重要极限。只要复习过&#xff0c;那基本上都能正常做出来。 至于汤家凤老师说「…

C#中数组与列表,集合等的联系

C#中&#xff0c;所有数组都自动继承于System.Array这个抽象类&#xff0c;数组都为引用类型&#xff0c; 所有对数组的更新都会导致源数组的元素值的篡改。 而所有集合的根都来自可枚举接口IEnumerable 数组有三种样式&#xff1a; 数组的Rank&#xff08;秩&#xff09;属…

纯血鸿蒙APP实战开发——Grid和List内拖拽交换子组件位置

Grid和List内拖拽交换子组件位置 介绍 本示例分别通过onItemDrop()和onDrop()回调&#xff0c;实现子组件在Grid和List中的子组件位置交换。 效果图预览 使用说明&#xff1a; 拖拽Grid中子组件&#xff0c;到目标Grid子组件位置&#xff0c;进行两者位置互换。拖拽List中子…

【数据结构】环状链表OJ题

✨✨✨专栏&#xff1a;数据结构 &#x1f9d1;‍&#x1f393;个人主页&#xff1a;SWsunlight 一、OJ 环形链表&#xff1a; 快慢指针即可解决问题: 2情况&#xff1a; 快指针走到结尾&#xff08;不是环&#xff09;快指针和尾指针相遇&#xff08;是环的&#xff09; …

macos使用yarn创建vite时出现Usage Error: The nearest package directory问题

步骤是macos上使用了yarn create vite在window上是直接可以使用了yarn但是在macos上就出现报错 我们仔细看&#xff0c;它说的If /Users/chentianyu isnt intended to be a project, remove any yarn.lock and/or package.json file there.说是要我们清除yarn.lock和package.js…

OGG几何内核-网格化的改进

OGG社区于4月19日发布了OGG 1.0 preview版本。相对于OCCT 7.7.0有很多改进&#xff0c;目前在持续研究中。最近测试了一下网格化&#xff0c;确实有很好的改进。对比展示如下&#xff1a; 几何内核&#xff1a; OGG 1.0 preview 几何内核&#xff1a;OCCT 7.7.0 采用OCCT几何内…

线程同步--条件变量,信号量

生产者和消费者模型 案例 /*生产者消费者模型&#xff08;粗略的版本&#xff09; */ #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h>// 创建一个互斥量 pthread_mutex_t mutex;struct Node{int num;struct Node …

【ALM】ALM解决方案系列:质量保证

1软件的质量管理现状与痛点 在软件开发中&#xff0c;质量被视为软件产品的生命。保证软件质量&#xff0c;是贯穿整个软件生命周期的重要问题。如果在软件开发早期忽视质量管理&#xff0c;会导致软件项目管理出现问题。因此&#xff0c;重视并规范软件管理在软件项目管理中起…

[论文笔记]Corrective Retrieval Augmented Generation

引言 今天带来论文Corrective Retrieval Augmented Generation的笔记&#xff0c;这是一篇优化RAG的工作。 大型语言模型(LLMs) inevitable(不可避免)会出现幻觉&#xff0c;因为生成的文本的准确性不能仅仅由其参数化知识来确保。尽管检索增强生成(RAG)是LLMs的一个可行补充…

带你手撕红黑树! c++实现 带源码

目录 一、概念 二、特性 三、接口实现 1、插入 情况一&#xff1a;p为黑&#xff0c;结束 情况二&#xff1a;p为红 1&#xff09;叔叔存在且为红色 2&#xff09;u不存在/u存在且为黑色 &#xff08;1&#xff09;p在左&#xff0c;u在右 &#xff08;2&#xff09;…

【半夜学习MySQL】表的约束(含主键、唯一键、外键、zerofill、列描述、默认值、空属性详解)

&#x1f3e0;关于专栏&#xff1a;半夜学习MySQL专栏用于记录MySQL数据相关内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 前言空属性默认值列描述zerofill主键主键概述主键删除与追加复合主键 自增长唯一键外键综合案例 前言 上一篇文章中介绍了数…