今天发现一个有意思的问题:
如何使用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