Annotorious入门教程:图片注释工具
本文简介
最近有工友问我前端怎么给图片做标注。使用 Fabric.js
或者 Konva.js
等库确实可以实现,但我又好奇有没有专门做图片标注的工具呢?
在网上搜了一下发现 Annotorious
可以实现这个功能。Annotorious
提供了图片注释和标注功能,而且用法很简单。
本文分为 【快速入门】和【API讲解】两部分。
【快速入门】部分包含 Annotorious
的安装、使用、导入导出的讲解。这几点应该是项目中比较核心的流程,给希望快速入门的工友提供一丢丢帮助。
【API讲解】这部分主要讲一下我认为比较常用的功能。注意:是“我认为”。
快速入门
快速入门部分会讲解Annotorious
的安装、使用、导入和导出数据功能。
安装 Annotorious
CDN
<!-- 引入样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@recogito/annotorious@2.7.10/dist/annotorious.min.css"><!-- 引入js -->
<script src="https://cdn.jsdelivr.net/npm/@recogito/annotorious@2.7.10/dist/annotorious.min.js"></script>
你可以把这两份文件下载到自己的项目里再引入。
NPM
用以下命令安装 Annotorious
npm install @recogito/annotorious
然后在项目中引入
import { Annotorious } from '@recogito/annotorious'
import '@recogito/annotorious/dist/annotorious.min.css'
使用 annotorious
把 Annotorious
安装到项目后就可以使用了。
Annotorious
的用法很简单,只需做以下2步:
- 在html部分插入图片
- 初始化
Annotorious
,并绑定图片元素(元素的ID或者元素本身)
CDN
和 NPM
在初始化时的用法稍微有点不同。
CDN
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image' // 元素ID
})
</script>
使用 CDN
的方式引入 Annotorious
,在初始化时要 Annotorious.init
这样写。
NPM
<img src="./img.jpg" id="my-image" /><script>
const anno = new Annotorious({image: document.getElementById('my-image') // 元素本身
})
</script>
使用 NPM
的方式引入 Annotorious
在初始化时需要 new Annotorious
这样写。
注意:在 Annotorious
初始化代码最好放在你所使用的框架的页面加载完成后的生命周期函数里!
导出数据 getAnnotations()
如果你需要将图片上的标注保存到服务器,就需要把数据导出。
所用到的方法是 getAnnotations()
。
<button οnclick="save()">保存</button>
<img src="./44.jpg" id="img" /><script>let anno = nullonload = function() {anno = Annotorious.init({image: 'img'})}function save() {let res = anno.getAnnotations()console.log(res)}
</script>
导入数据 loadAnnotations(url)
Annotorious
可以通过 loadAnnotations()
方法加载数据。
loadAnnotations(url)
支持传入一个 URL
参数,这个 URL
所指的是数据文件地址。
比如我在本地创建一个 data.json
文件,文件内容是使用前面讲到的 getAnnotations()
方法导出的数据,我的数据内容如下:
[{"@context": "http://www.w3.org/ns/anno.jsonld","type": "Annotation","body": [{"type": "TextualBody","value": "1","purpose": "commenting"}],"target": {"source": "http://127.0.0.1:5500/44.jpg","selector": {"type": "FragmentSelector","conformsTo": "http://www.w3.org/TR/media-frags/","value": "xywh=pixel:100,100,500,300"}},"id": "#cabe2e71-b19f-4499-80c6-235882fd50ba"}
]
在本地测试时,我使用了本地服务器把 data.json
管理起来,在浏览器可以通过 http://127.0.0.1:5500/data.json
访问到该文件。
然后再使用 loadAnnotations(url)
方法把数据渲染出来即可。
<button οnclick="load()">加载</button>
<img src="./44.jpg" id="img" /><script>
let anno = nullonload = function() {anno = Annotorious.init({image: 'img'})
}function load() {anno.loadAnnotations("http://127.0.0.1:5500/data.json")
}
</script>
点击加载按钮后,图片上就会出现一个选框,点击选框可以看到数据已经成功加载出来。
添加数据 addAnnotation()
但在实际项目中,后台不一定会给前端返回一个文件地址,后台可能会直接返回一个json数据。
这时候如果使用 loadAnnotations()
方法加载 json
数据是行不通的,要通过遍历读取数据中心的 data
里的数据,然后调用 addAnnotation()
方法将元素添加到页面。
我使用 json-server
简单的在本地搭建一个服务器给前端访问对应的资源,前端用 axios
请求资源。
<button οnclick="load()">加载</button>
<img src="./44.jpg" id="img" /><script>
let anno = nullonload = function() {anno = Annotorious.init({image: 'img'})
}function load() {axios.get('http://localhost:3000/anno').then(res => {res.data.data.forEach(item => {anno.addAnnotation(item)})})
}
</script>
很久之前写过一篇 《『前端必备』本地数据接口 —— json-server 从入门到膨胀》 文章介绍 json-server
的基础用法,有兴趣的工友可以去瞧瞧。
API讲解
这部分主要讲一些我关注到的功能,如果想全面了解 Annotorious
可以查看文档。
汉化 locale
Annotorious
是根据浏览器的设置来确定使用哪种语言。
如果需要修改 Annotorious
使用的语言,可以在初始化时配置一下 locale
字段。
比如配置简体中文可以用 zh-CN
,配置繁体中文可以用 zh-TW
。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',locale: 'zh-CN' // 修改语言
})
</script>
自定义提示文本 messages
如果想自定义按钮或者输入框的提示文本可以配置 messages
。
<img src="./img.jpg" id="my-image" /><script>// 创建一个包含自定义消息的对象
var customMessages = {"Add a comment...": "评论评论","Add a reply...": "回复两句","Add tag...": "这是标签啊","Cancel": "取消","Close": "关闭","Edit": "编辑~","Delete": "删除❌","Ok": "确定"
}let anno = Annotorious.init({image: 'my-image',messages: customMessages // 自定义消息内容
})
</script>
如果同时配置了 locale
和 messages
,会优先使用 message
的值。
空注释 allowEmpty
默认情况下,如果框选后没输入标签或者评论就按确定是不会保存选框的。
如果想保存空选框,可以将 allowEmpty
设置为 true
。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',allowEmpty: true // 允许空注释
})
</script>
框选辅助线 crosshair
有些鼠标指针可能并不是那么标准,会影响你框选的准确性。
如果需要非常准确去框选,可以开启辅助线功能,只需将 crosshair
设置为 true
即可。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',crosshair: true // 开启辅助线
})
</script>
只读 readOnly
如果不打算提供框选、添加和删除信息的操作给用户,可以将 readOnly
设置为 true
。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',readOnly: true // 只读模式
})
</script>
禁止编辑 disableEditor
如果只需要画框框,不需要写注释,可以将 disableEditor
和 allowEmpty
同时设置为 true
。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',allowEmpty: true, // 允许空注释disableEditor: true // 禁用编辑
})
</script>
为什么要同时将 allowEmpty
设为 true
?
因为如果你不允许注释为空的话,当你点击空白处时选框就会消失。
禁止选中选框 disableSelect
将 disableSelect
设置为 true
后,画布上的选框就无法再次选中了。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',disableSelect: true // 禁止选中选框
})
</script>
虽然还没想到有什么引用场景,但还是打算记录一下。
手柄半径 handleRadius
箭头所指的就是手柄。
手柄的默认半径是6。如果需要修改手柄半径可以设置 handleRadius
属性。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',handleRadius: 20 // 设置手柄半径
})
</script>
自定义选框样式
Annotorious
的选框和编辑器都是可以使用 css
设置样式的。
选框部分使用了 SVG
,编辑器部分直接用了 HTML
元素。
对 SVG
不了解的工友可以阅读 《SVG专栏》。
回到 Annotorious
,官方也有给出一个自定义样式的案例 《Customizing Visual Appearance》。
<style>/* 选框 *//* 隐藏外部形状-对于这种风格,我们只需要一个 */svg.a9s-annotationlayer .a9s-selection .a9s-outer, svg.a9s-annotationlayer .a9s-annotation .a9s-outer {display:none;}svg.a9s-annotationlayer .a9s-handle .a9s-handle-outer {display:none;}/* 虚线边框 */svg.a9s-annotationlayer .a9s-selection .a9s-inner,svg.a9s-annotationlayer .a9s-annotation .a9s-inner {stroke-width:4;stroke:white;stroke-dasharray:5;}/* 选中时的填充色 */svg.a9s-annotationlayer .a9s-annotation.editable:hover .a9s-inner {fill:transparent;}/* 手柄颜色 */svg.a9s-annotationlayer .a9s-handle .a9s-handle-inner {fill:white;stroke:white;}/* 选中选框时,遮罩层颜色 */svg.a9s-annotationlayer .a9s-selection-mask {fill:rgba(0, 0, 0, 0.6);}/* 编辑器 *//* 容器 */.r6o-editor .r6o-editor-inner {box-sizing: border-box;padding: 10px;border-radius: 6px;background: #F4F2DE;}/* 箭头 */.r6o-editor .r6o-arrow:after {background-color: #F4F2DE;}/* 编辑器 */.r6o-widget.comment.editable,.r6o-widget.r6o-tag {background-color: #EEE3CB;}.r6o-widget.comment {background-color: #D7C0AE;}.r6o-editor .r6o-editor-inner .r6o-widget {border-bottom-color: #7C9D96;}.r6o-editor .r6o-editor-inner .r6o-widget.r6o-tag {border-bottom: none;}/* 按钮 */.r6o-editor .r6o-btn {border-radius: 100px;background-color: #7C9D96;border-color: #7C9D96;color: #fff;}/* 线框按钮 */.r6o-editor .r6o-btn.outline {color: #7C9D96;background-color: transparent;}
</style><img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',locale: 'zh-CN' // 修改语言
})
</script>
上面这份代码选框的样式是从 Annotorious
官网教程搬过来的。
编辑器的样式我随便配了一下,工友们也可以打开浏览器控制台看 Elements
面板的 HTML
代码,根据结构去修改样式即可。
筛选功能
输入时需要快速添加预选项时,可以这样配置:
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',widgets: ['COMMENT',{ widget: 'TAG', vocabulary: [ '雷猴', '鲨鱼辣椒', '蝎子莱莱'] }]
})
</script>
多边形选框
使用 setDrawingTool(toolName)
方法可以设置不同的绘制工具。
如果需要讲选框设置成多边形,可以传入 'polygon'
。
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image'
})anno.setDrawingTool("polygon")
</script>
想要知道当前有哪些绘图工具,可以使用 anno.listDrawingTools()
方法查看
<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image'
})const toolNames = anno.listDrawingTools()
console.log(toolNames)
</script>
其他
除了上面介绍到的 API
外,Annotorious
还有很多玩法的,比如删除指定注释、清空所有注释等。
详情请看 《annotorious API文档》
插件
Annotorious
也有一些好玩的插件,有兴趣的可以看看 《Annotorious 插件推荐》。
推荐阅读
👍《提升日期处理效率:day.js 实战经验分享》
👍《OpenLayers.js 入门教程:打造互动地图的入门指南》
👍《物理世界的互动之旅:Matter.js入门指南》
👍《p5.js 光速入门》
👍《眨个眼就学会了Pixi.js》
👍《Fabric.js 从入门到膨胀》
点赞 + 关注 + 收藏 = 学会了 代码仓库
相关文章:

Annotorious入门教程:图片注释工具
本文简介 最近有工友问我前端怎么给图片做标注。使用 Fabric.js 或者 Konva.js 等库确实可以实现,但我又好奇有没有专门做图片标注的工具呢? 在网上搜了一下发现 Annotorious 可以实现这个功能。Annotorious 提供了图片注释和标注功能,而且…...

一台服务器是否能够安装多个SSL证书?
在今天的互联网世界中,网络安全是至关重要的,而SSL证书是为了保护网络通信安全而设计的加密协议。然而,对于一台服务器是否能够安装多个SSL证书这个问题,仍然存在一些疑问。本文将探讨这个问题,并提供一些相关的解析和…...

如何使用UDP打洞进行内网穿透
内网穿透是一种将局域网中的设备暴露到互联网上的技术,UDP打洞是内网穿透的一种方法。它允许您通过家庭网络中的NAT(网络地址转换)设备访问位于不同网络的设备,例如家庭服务器或物联网设备。本文将指导您如何使用UDP打洞实现内网穿…...

如何滴水不漏的学完C语言?
如何滴水不漏的学完C语言? 学习C语言需要掌握的知识点确实非常广泛。如果你觉得学校教学中所涉及的内容有所欠缺,可以有很多其他方式进行补充学习。最近很多小伙伴找我,说想要一些C语言资料,然后我根据自己从业十年经验ÿ…...

数据库深入浅出,数据库介绍,SQL介绍,DDL、DML、DQL、TCL介绍
一、基础知识: 1.数据库基础知识 数据(Data):文本信息(字母、数字、符号等)、音频、视频、图片等; 数据库(DataBase):存储数据的仓库,本质文件,以文件的形式将数据保存到电脑磁盘中 数据库管理系统(DBMS)&…...

拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能
蒸汽机的发明为人类工业革命揭开序幕,引领了近现代产业变革。众所周知,而今AI技术的革命性突破,站在了时代舞台的中心,特别是大模型的崛起,无疑是第四次产业革命的焦点,它的地位可与当年的“蒸汽机”相提并…...

NEFU数字图像处理(3)图像分割
一、图像分割的基本概念 1.1专有名词 前景和背景 在图像分割中,我们通常需要将图像分为前景和背景两个部分。前景是指图像中我们感兴趣、要分割出来的部分,背景是指和前景不相关的部分。例如,对于一张人物照片,人物就是前景&…...

图论问题建模和floodfill算法
目录 引入:leetcode695.岛屿的最大面积 分析与转换 一维二维转换 四联通 完整代码解答: 1)显示的创建图解决问题的代码 2)不显示的创建图解决此问题的代码 floodfill算法 定义 引入:leetcode695.岛屿的最大面…...

MySQL - 库的操作
目录 1.库的操作1.1创建数据库1.2创建数据库案例 2.字符集和校验规则3.操纵数据库4.备份和恢复5.查看连接情况 1.库的操作 1.1创建数据库 语法: CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specifica…...

多次kerberos认证服务超时
调整 /var/kerberos/krb5kdc/kdc.conf 文件,有则修改,无则添加 [kdcdefaults] kdc_tcp_listen_backlog 7调整 /etc/krb5.conf [dbmodules] disable_last_success true调整 /etc/sysconfig/krb5kdc KRB5KDC_ARGS‘-w 48’ #增大kdc的进程数量生效上述配…...

Vuex源码-各原理简单总结
1,简单总结 Vuex就是一个构造函数,他拥有install方法和Store类这两个属性。在vue初始化调用new Vue的时候,将store作为参数传入,然后调用Vue.use()实际是调用install方法将store这个实例挂载到全局,从而可以保证全局只…...

vcpkg 使用 cmake 编译C/C++工程代码时指定使用静态库链接编译
参考文献: CMake 项目中的 vcpkg | Microsoft Learn c - Using static Boost libraries with vcpkg and CMake - Stack Overflow Vcpkg updates: Static linking is now available - C Team Blog (microsoft.com) microsoft/vcpkg: C Library Manager for Windo…...

FlinkCDC系列:数据同步对部分字段的处理,只更新部分字段
在flinkCDC源数据配置中,只对表中的部分字段关注,通过监控部分字段进行数据更新或者不更新,对数据进行同步。主要通过以下两个参数: column.exclude.list 默认: 空字符串 一个可选的、以逗号分隔的正则表达式列表,与…...

Linux 包操作 (rpm)
目录 1. rpm 包1.1. 提取和安装 rpm 包1.2. 查看一个 rpm 包中的文件安装到那里去 1. rpm 包 rpm --version1.1. 提取和安装 rpm 包 使用以下命令来解压 rpm 包: rpm2cpio package.rpm | cpio -idmv其中, package.rpm 是你要解压的 rpm 包的文件名。这个命令将会将 rpm 包解…...

Docker中OceanBase挂载过后,删除再启动无限重启的解决办法
ob-compose.yml文件如下: version: 3 services:oceanbase1:image: oceanbase/oceanbase-ce:latestcontainer_name: oceanbase1hostname: oceanbase1ports:- 2881:2881restart: alwaysprivileged: truevolumes:#- //d/obdata/ob:/root/ob#- //d/obdata/obd:/root/.o…...

react中的forwardRef 和memo的区别?
文章目录 前言介绍forwardRefmemo适用场景优点缺点后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:前端面试 🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错…...

偶数矩阵判断【C语言作业】
题目 若一个布尔矩阵所有行和所有列的和都是偶数,则称为偶数矩阵。请编写一个程序,判断一个布尔矩阵是否是偶数矩阵。 要求: (1)输入:首先输入一个正整数n(n<100),代表该矩阵的大小,接下来是n行n列的矩…...

stable-diffusion 电商领域prompt测评集合
和GhostReivew一个思路,还是从比较好的图片或者是civitai上找一些热门的prompt,从小红书上也找到了不少的prompt,lexica.art上也有不少,主要是为了电商场景的一些测评: 小红书、civitai、Lexica、Liblib.ai、 depth o…...

协方差矩阵
将变量两两之间的协方差排成矩阵的形式,就是协方差矩阵。 用个例子来说明下,帮助理解。 下面这组数据有三个变量:身高x、体重y、年龄z,每个变量都有5个取值: 身高x(cm)体重y(kg&a…...

0基础学习VR全景平台篇第117篇:利用插件地拍补地 - PS教程
上课!全体起立~ 大家好,欢迎观看蛙色官方系列全景摄影课程! 嗨,大家好,今天我们来介绍【PS利用插件地拍补地】。 之前已经教给大家补地插件的安装方法,今天我们教给大家如何使用这个插件进行补地。 首…...

git的命令操作
1、基本命令 目录 1、基本命令 创建 Git 存储库 添加文件/目录到索引 将更改提交到本地存储库 撤消上一次提交的更改 显示工作树状态 显示对工作树和索引的更改 显示提交日志 显示提交详细信息 重命名文件 从工作树和索引中移除文件 从工作树中移除未跟踪文件 将…...

Nginx+keepalived实现七层的负载均衡
1.keepalived VRRP 介绍 keepalived是什么? keepalived是集群管理中保证集群高可用的一个服务软件,用来防止单点故障。 keepalived工作原理 keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol&…...

至少在两个数组中出现的值
给你三个整数数组 nums1、nums2 和 nums3 ,请你构造并返回一个 元素各不相同的 数组,且由 至少 在 两个 数组中出现的所有值组成。数组中的元素可以按 任意 顺序排列。 示例 1: 输入:nums1 [1,1,3,2], nums2 [2,3], nums3 [3]…...

子女关于骨灰发生争议,骨灰该如何安置?
亲属去世后,争房产、争车辆、争存款的事情不少,但争骨灰却是稀罕事儿。近日,江苏省无锡市梁溪区人民法院审结了一起人格权案件,马某与继母因父亲老马骨灰安葬引发的纷争,历经2年多终于落幕。 老马与前妻离婚后&…...

android隐藏输入法的一些尝试,最后一个可行
一、背景: 基于android开发自己的输入法app,用户需要手动收起输入法 二、准备工作: 定义类 public class CustIMS extends InputMethodService {} 和 xml声明三、尝试验证: 1、CustIMS.hideWindow(); 结论:这个在…...

【go-zero】go-zero 脚手架 simple-admin 第一章:通过goctls生成rpc整个项目 | go-zero整合 ENT数据库orm框架
往期回顾 【simple-admin 开篇:安装 了解 goctls】https://ctraplatform.blog.csdn.net/article/details/133988572 本章内容 往期回顾一、simple-admin 创建rpc项目实战1、创建git仓库1.1、创建任意git仓库1.2、克隆到本地2、创建RPC项目2.1、goctls 安装 rpc项目2.2、复制项…...

Ubuntu 使用 nginx 搭建 https 文件服务器
Ubuntu 使用 nginx 搭建 https 文件服务器 搭建步骤安装 nginx生成证书修改 config重启 nginx 搭建步骤 安装 nginx生成证书修改 config重启 nginx 安装 nginx apt 安装: sudo apt-get install nginx生成证书 使用 openssl 生成证书: 到对应的路径…...

团队表 -多级团队设计
团队表 -多级团队设计 user_team团队表 ,如果存在子团队 1.我们可以通过每一个团队字段加一个parentid (相当于一对多的关系) 2.还可以设置一个字段CodingNum,比如这样: //系统为了管理查询团队自动生成的有序编号 可以使用3位数代表一个…...

LeetCode每日一题——2103. Rings and Rods
文章目录 一、题目二、题解 一、题目 There are n rings and each ring is either red, green, or blue. The rings are distributed across ten rods labeled from 0 to 9. You are given a string rings of length 2n that describes the n rings that are placed onto the…...

ant-design-vue form表单自定义校验规则
<a-form-itemlabel"市场价"class"status-barcode"name"marketPrice":rules"[{ required: true, message: },{ validator: validateNumber },]"><a-inputshow-count:maxlength"10"v-model:value"formState.ma…...