当前位置: 首页 > news >正文

Annotorious入门教程:图片注释工具

本文简介

最近有工友问我前端怎么给图片做标注。使用 Fabric.js 或者 Konva.js 等库确实可以实现,但我又好奇有没有专门做图片标注的工具呢?

在网上搜了一下发现 Annotorious 可以实现这个功能。Annotorious 提供了图片注释和标注功能,而且用法很简单。

file


本文分为 【快速入门】和【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步:

  1. 在html部分插入图片
  2. 初始化 Annotorious,并绑定图片元素(元素的ID或者元素本身)

file


CDNNPM 在初始化时的用法稍微有点不同。

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()

file

<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) 方法把数据渲染出来即可。

file

<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 是根据浏览器的设置来确定使用哪种语言。

file


如果需要修改 Annotorious 使用的语言,可以在初始化时配置一下 locale 字段。

比如配置简体中文可以用 zh-CN,配置繁体中文可以用 zh-TW

file

<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>

如果同时配置了 localemessages ,会优先使用 message 的值。


空注释 allowEmpty

默认情况下,如果框选后没输入标签或者评论就按确定是不会保存选框的。

file

如果想保存空选框,可以将 allowEmpty 设置为 true

file

<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',allowEmpty: true // 允许空注释
})
</script>

框选辅助线 crosshair

有些鼠标指针可能并不是那么标准,会影响你框选的准确性。

如果需要非常准确去框选,可以开启辅助线功能,只需将 crosshair 设置为 true 即可。

file

<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

如果只需要画框框,不需要写注释,可以将 disableEditorallowEmpty 同时设置为 true

file

<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

箭头所指的就是手柄。

file

手柄的默认半径是6。如果需要修改手柄半径可以设置 handleRadius 属性。

file

<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》。

file

<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 代码,根据结构去修改样式即可。


筛选功能

输入时需要快速添加预选项时,可以这样配置:

file

<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image',widgets: ['COMMENT',{ widget: 'TAG', vocabulary: [ '雷猴', '鲨鱼辣椒', '蝎子莱莱'] }]
})
</script>

多边形选框

使用 setDrawingTool(toolName) 方法可以设置不同的绘制工具。

如果需要讲选框设置成多边形,可以传入 'polygon'

file

<img src="./img.jpg" id="my-image" /><script>
let anno = Annotorious.init({image: 'my-image'
})anno.setDrawingTool("polygon")
</script>

想要知道当前有哪些绘图工具,可以使用 anno.listDrawingTools() 方法查看

file

<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 等库确实可以实现&#xff0c;但我又好奇有没有专门做图片标注的工具呢&#xff1f; 在网上搜了一下发现 Annotorious 可以实现这个功能。Annotorious 提供了图片注释和标注功能&#xff0c;而且…...

一台服务器是否能够安装多个SSL证书?

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

如何使用UDP打洞进行内网穿透

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

如何滴水不漏的学完C语言?

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

数据库深入浅出,数据库介绍,SQL介绍,DDL、DML、DQL、TCL介绍

一、基础知识&#xff1a; 1.数据库基础知识 数据(Data)&#xff1a;文本信息(字母、数字、符号等)、音频、视频、图片等&#xff1b; 数据库(DataBase)&#xff1a;存储数据的仓库&#xff0c;本质文件&#xff0c;以文件的形式将数据保存到电脑磁盘中 数据库管理系统(DBMS)&…...

拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能

蒸汽机的发明为人类工业革命揭开序幕&#xff0c;引领了近现代产业变革。众所周知&#xff0c;而今AI技术的革命性突破&#xff0c;站在了时代舞台的中心&#xff0c;特别是大模型的崛起&#xff0c;无疑是第四次产业革命的焦点&#xff0c;它的地位可与当年的“蒸汽机”相提并…...

NEFU数字图像处理(3)图像分割

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

图论问题建模和floodfill算法

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

MySQL - 库的操作

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

多次kerberos认证服务超时

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

Vuex源码-各原理简单总结

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

vcpkg 使用 cmake 编译C/C++工程代码时指定使用静态库链接编译

参考文献&#xff1a; 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源数据配置中&#xff0c;只对表中的部分字段关注&#xff0c;通过监控部分字段进行数据更新或者不更新&#xff0c;对数据进行同步。主要通过以下两个参数&#xff1a; column.exclude.list 默认: 空字符串 一个可选的、以逗号分隔的正则表达式列表&#xff0c;与…...

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文件如下&#xff1a; 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欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端面试 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错…...

偶数矩阵判断【C语言作业】

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

stable-diffusion 电商领域prompt测评集合

和GhostReivew一个思路&#xff0c;还是从比较好的图片或者是civitai上找一些热门的prompt&#xff0c;从小红书上也找到了不少的prompt&#xff0c;lexica.art上也有不少&#xff0c;主要是为了电商场景的一些测评&#xff1a; 小红书、civitai、Lexica、Liblib.ai、 depth o…...

协方差矩阵

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

0基础学习VR全景平台篇第117篇:利用插件地拍补地 - PS教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 嗨&#xff0c;大家好&#xff0c;今天我们来介绍【PS利用插件地拍补地】。 之前已经教给大家补地插件的安装方法&#xff0c;今天我们教给大家如何使用这个插件进行补地。 首…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

xmind转换为markdown

文章目录 解锁思维导图新姿势&#xff1a;将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件&#xff08;ZIP处理&#xff09;2.解析JSON数据结构3&#xff1a;递归转换树形结构4&#xff1a;Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...