Skip to content

Serialization

osdlabel provides built-in functions for serializing its internal state into a standard JSON document format and deserializing it back.

osdlabel uses a flat JSON array format for persisting annotations:

[
{
"id": "ann-1",
"imageId": "sample-1",
"contextId": "general",
"geometry": {
"type": "rectangle",
"origin": { "x": 100, "y": 200 },
"width": 300,
"height": 150,
"rotation": 0
},
"rawAnnotationData": {
"format": "fabric",
"fabricVersion": "7.2.0",
"data": { ... }
},
"createdAt": "2026-03-06T12:00:00.000Z",
"updatedAt": "2026-03-06T12:00:00.000Z"
}
]

Use serialize() to create a flat array of annotations from the current state:

import { serialize } from 'osdlabel';
const { annotationState } = useAnnotator();
const doc = serialize(annotationState);
const json = JSON.stringify(doc, null, 2);
// Save to file, send to API, etc.

Use deserialize() to parse an array and load it into the store:

import { deserialize } from 'osdlabel';
const { actions } = useAnnotator();
const parsed = JSON.parse(jsonString);
const { byImage } = deserialize(parsed);
actions.loadAnnotations(byImage);

deserialize() validates the basic structure of the array and throws SerializationError on invalid input. For deep validation, the library integrates with Valibot in @osdlabel/validation.

The library provides comprehensive Valibot schemas for annotation validation in the @osdlabel/validation package:

import * as v from 'valibot';
import { BaseAnnotationSchema } from '@osdlabel/validation';
if (v.safeParse(BaseAnnotationSchema, unknownData).success) {
// unknownData is basically valid BaseAnnotation
}

Validation checks include:

  • Required string fields (id, imageId, timestamps)
  • Geometry type and shape validation
  • Numeric bounds checking (coordinates, dimensions)
  • Extension fields (when composed into a custom schema)

The onAnnotationsChange callback fires whenever annotations are added, updated, or deleted:

<AnnotatorProvider
onAnnotationsChange={(annotations) => {
// annotations: Annotation[] — flat list of all annotations
saveToBackend(annotations);
}}
>
{/* ... */}
</AnnotatorProvider>

Use getAllAnnotationsFlat() to extract a flat array from the state at any time:

import { getAllAnnotationsFlat } from '@osdlabel/viewer-api';
const { annotationState } = useAnnotator();
const allAnnotations = getAllAnnotationsFlat(annotationState);