Getting Started with Annotorious: A Tool for Image Annotation

Overview

Recently, a colleague asked how to annotate images using frontend technologies. While libraries like Fabric.js or Konva.js can achieve this, I was curious if there are specialized tools designed specifically for image annotation.

Upon searching online, I discovered Annotorious, which offers image annotation and tagging capabilities with an easy-to-use interface.

This article covers two sections: "Quick Start" and "API Reference." The first section explains installation, usage, and data import/export processes—core aspects useful for rapid implementation. The second part highlights commonly used features based on personal experience.

Quick Start

This section details installing, initializing, importing, and exporting data with Annotorious.

Installing Annotorious

CDN

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@recogito/annotorious@2.7.10/dist/annotorious.min.css">
<script src="https://cdn.jsdelivr.net/npm/@recogito/annotorious@2.7.10/dist/annotorious.min.js"></script>

Alternatively, download these files into your project directory and reference them locally.

NPM

Install via npm:

npm install @recogito/annotorious

Then import in your project:

import { Annotorious } from '@recogito/annotorious'
import '@recogito/annotorious/dist/annotorious.min.css'

Using Annotorious

After installation, initialize Annotorious with two simple steps:

  1. Insert an image element in HTML.
  2. Initialize Annotorious with the image element (by ID or DOM node).

Initialization varies slightly between CDN and NPM setups.

CDN Initialization

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

NPM Initialization

<img src="./img.jpg" id="my-image" />
<script>
  const anno = new Annotorious({
    image: document.getElementById('my-image')
  })
</script>

Note: Place initialization code with in the lifecycle hooks of your framework after the page has fully loaded.

Exporting Annotations: getAnnotations()

To save annotations to a server, use getAnnotations().

<button onclick="save()">Save</button>
<img src="./44.jpg" id="img" />
<script>
  let anno = null;
  
onload = function() {
    anno = Annotorious.init({
      image: 'img'
    });
  };

  function save() {
    let res = anno.getAnnotations();
    console.log(res);
  }
</script>

Importing Annotations: loadAnnotations(url)

Data can be imported using loadAnnotations(url), which accepts a URL pointing to a data file.

Suppose we have a data.json file containing annotations exported via 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"
  }
]

Use a local server to serve data.json. Then load it:

<button onclick="load()">Load</button>
<img src="./44.jpg" id="img" />
<script>
  let anno = null;
  
onload = function() {
    anno = Annotorious.init({
      image: 'img'
    });
  };

  function load() {
    anno.loadAnnotations("http://127.0.0.1:5500/data.json");
  }
</script>

Clicking the Load button will render the annotation box with its content.

Adding Annotations: addAnnotation()

In real-world projects, backend services may return JSON data instead of a file path. To handle such cases, iterate through the data and call addAnnotation().

Using json-server and axios for demonstration:

<button onclick="load()">Load</button>
<img src="./44.jpg" id="img" />
<script>
  let anno = null;
  
onload = 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>

API Reference

This section discusses frequently used functionalities of Annotorious. For full documentation, refer to the official site.

Localization: locale

The default language depends on browser settings.

Override it by setting locale during initialization:

<img src="./img.jpg" id="my-image" />
<script>
  let anno = Annotorious.init({
    image: 'my-image',
    locale: 'zh-CN'
  });
</script>

Custom Messages: messages

Customize UI text by passing a messages object:

<img src="./img.jpg" id="my-image" />
<script>
  var customMessages = {
    "Add a comment...": "Add comment",
    "Add a reply...": "Reply here",
    "Add tag...": "Enter tag",
    "Cancel": "Cancel",
    "Close": "Close",
    "Edit": "Edit",
    "Delete": "Delete",
    "Ok": "OK"
  };

  let anno = Annotorious.init({
    image: 'my-image',
    messages: customMessages
  });
</script>

If both locale and messages are set, messages takes precedence.

Empty Annotations: allowEmpty

By default, empty annotations are not saved. Set allowEmpty to true to enable saving them:

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

Crosshair: crosshair

Enable precise selection by activating crosshair:

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

Read-only Mode: readOnly

Disable editing features by setting readOnly to true:

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

Disable Editor: disableEditor

To allow drawing without comments, set both disableEditor and allowEmpty to true:

<img src="./img.jpg" id="my-image" />
<script>
  let anno = Annotorious.init({
    image: 'my-image',
    allowEmpty: true,
    disableEditor: true
  });
</script>

Disable Selection: disableSelect

Prevent selecting existing annotations by enabling disableSelect:

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

Handle Radius: handleRadius

Adjust the size of handles with handleRadius:

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

Custom Styles

Styling can be applied to annotations and editors using CSS. Annotations are rendered via SVG, while editors use standard HTML elements.

Example custom styles:

/* Annotation styling */
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);
}

/* Editor styling */
.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;
}

Predefined Widgets

Configure predefined options during input:

<img src="./img.jpg" id="my-image" />
<script>
  let anno = Annotorious.init({
    image: 'my-image',
    widgets: [
      'COMMENT',
      { widget: 'TAG', vocabulary: ['tag1', 'tag2', 'tag3'] }
    ]
  });
</script>

Polygon Drawing

Change drawing tools with setDrawingTool():

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

  anno.setDrawingTool("polygon");
</script>

List available tools using listDrawingTools():

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

  const toolNames = anno.listDrawingTools();
  console.log(toolNames);
</script>

Additional Features

Beyond the mentioned APIs, Annotorious supports deleting specific annotations or clearing all annotations. Refer to the official API documentation for more.

Plugins

Explore additional functionality through plugins listed in the Annotorious plugin recommendations.

Tags: image annotation Annotorious Frontend Development Web Tools JavaScript library

Posted on Wed, 12 Aug 2026 16:46:28 +0000 by compt