← 返回 Skills 市场
frank17008

image-annotation-usage

作者 Frank · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
2
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install image-annotation-usage
功能描述
Use when integrating @frank17008/image-annotation React component into web applications, including basic setup, controlled/uncontrolled mode, custom image up...
使用说明 (SKILL.md)

Image Annotation Component Usage

Overview

@frank17008/image-annotation is a React + TypeScript image annotation component with Canvas 2D. Supports rectangle, circle, arrow, text, and freehand tools with undo/redo, drag, export, keyboard shortcuts, zoom/pan, and DPR-aware rendering.

Package location: packages/image-annotation/src/ Published path: @frank17008/image-annotation

When to Use

Trigger phrases:

  • "How to integrate image annotation component"
  • "Add annotation to my React app"
  • "Canvas blank even though image loads"
  • "Annotations not saving"
  • "Custom image upload with annotation"
  • "Controlled mode not working"
  • "HiDPI/Retina display blurry"

Installation

pnpm add @frank17008/image-annotation
# or
npm install @frank17008/image-annotation

Basic Integration

Minimal Setup

import { useState } from 'react';
import { ImageAnnotation, type Annotation } from '@frank17008/image-annotation';
import '@frank17008/image-annotation/dist/index.css';

export default function App() {
  const [annotations, setAnnotations] = useState\x3CAnnotation[]>([]);

  return (
    \x3Cdiv style={{ height: 600 }}>
      \x3CImageAnnotation
        src="https://example.com/image.jpg"
        onChange={setAnnotations}
      />
    \x3C/div>
  );
}

Critical: Parent container MUST have explicit height. Without it, canvas has 0×0 dimensions → blank canvas.

Type Import

Always use explicit type import for TypeScript:

import type { Annotation, ToolType } from '@frank17008/image-annotation';
// or
import { type Annotation, type ToolType } from '@frank17008/image-annotation';

Controlled vs Uncontrolled Mode

Uncontrolled (Default)

\x3CImageAnnotation
  src="image.jpg"
  onChange={(annotations) => console.log(annotations)}
/>

The component manages its own state internally.

Controlled (External State)

const [myAnnotations, setMyAnnotations] = useState\x3CAnnotation[]>([]);

\x3CImageAnnotation
  src="image.jpg"
  value={myAnnotations}
  onChange={setMyAnnotations}
/>

Rules:

  1. value → external annotations (read-only for component)
  2. onChange → called when annotations change
  3. If both value and onChange provided → controlled mode
  4. If neither → uncontrolled mode
  5. If only value without onChange → React warning

Sync Controlled to Uncontrolled

\x3CImageAnnotation
  src={src}
  value={annotations}
  onChange={(newAnnotations) => {
    setAnnotations(newAnnotations);
    // Save to backend, localStorage, etc.
    saveToBackend(newAnnotations);
  }}
/>

Custom Image Upload

Pattern 1: External Button

import { useState, useRef } from 'react';
import { ImageAnnotation } from '@frank17008/image-annotation';

export function ImageUploader() {
  const [imageSrc, setImageSrc] = useState\x3Cstring | null>(null);
  const fileInputRef = useRef\x3CHTMLInputElement>(null);

  const handleFileChange = (e: React.ChangeEvent\x3CHTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (event) => {
      const result = event.target?.result;
      if (typeof result === 'string') {
        setImageSrc(result); // base64 string
      }
    };
    reader.readAsDataURL(file);
    e.target.value = ''; // reset for same file re-select
  };

  return (
    \x3Cdiv style={{ height: 600 }}>
      \x3Cinput
        ref={fileInputRef}
        type="file"
        accept="image/*"
        onChange={handleFileChange}
        style={{ display: 'none' }}
      />
      \x3Cbutton onClick={() => fileInputRef.current?.click()}>
        Upload Image
      \x3C/button>
      {imageSrc && (
        \x3CImageAnnotation
          src={imageSrc}
          onChange={() => {}}
        />
      )}
    \x3C/div>
  );
}

Pattern 2: Component's Upload Button

const handleUpload = () => fileInputRef.current?.click();

\x3CImageAnnotation
  src={imageSrc}
  onChange={setAnnotations}
  onUpload={handleUpload}
/>

The component displays an upload button in toolbar when onUpload is provided.

Annotation Types Reference

// Rectangle annotation
{ type: 'rectangle', x: number, y: number, width: number, height: number, color: string, lineWidth?: number }

// Circle annotation
{ type: 'circle', x: number, y: number, radius: number, color: string, lineWidth?: number }

// Arrow annotation
{ type: 'arrow', x: number, y: number, toX: number, toY: number, color: string, lineWidth?: number }

// Text annotation
{ type: 'text', x: number, y: number, text: string, color: string, lineWidth?: number }

// Freehand annotation
{ type: 'freehand', points: Array\x3C{ x: number, y: number }>, color: string, lineWidth?: number }

Type Export

import type {
  Annotation,
  RectangleAnnotation,
  CircleAnnotation,
  ArrowAnnotation,
  TextAnnotation,
  FreehandAnnotation,
  ToolType,
  Point,
} from '@frank17008/image-annotation';

Props API

Prop Type Required Description
src string Image URL or base64
value Annotation[] Controlled annotations
onChange (annotations: Annotation[]) => void Annotation change callback
className string Container className
onUpload () => void Upload button callback

Zoom and Pan

Programmatic Zoom

const handleZoomIn = () => {
  // Component doesn't expose zoom API directly
  // Use keyboard shortcuts: Ctrl++
};

// Or via keyboard shortcuts (user must press):
// - Ctrl++ : Zoom in
// - Ctrl+- : Zoom out
// - Ctrl+0 : Reset zoom

Space + Drag Pan

Hold Space + drag to pan the canvas.

Zoom Ratio Display

The toolbar shows current zoom percentage (e.g., "100%", "150%").

Exporting Annotations

On Change Callback

\x3CImageAnnotation
  src={src}
  onChange={(annotations) => {
    // Save to database
    await saveAnnotations(imageId, annotations);

    // Or export as JSON
    const json = JSON.stringify(annotations, null, 2);
    download(json, 'annotations.json', 'application/json');
  }}
/>

Export Image with Annotations

Use the toolbar's export button, or programmatically:

import { download } from '@frank17008/image-annotation';
// Not currently exported - use toolbar button

Keyboard Shortcuts

Shortcut Action
Delete Delete selected annotation
Escape Cancel text input
Ctrl+Z Undo
Ctrl+Y / Ctrl+Shift+Z Redo
Ctrl++ / Ctrl+= Zoom in
Ctrl+- Zoom out
Ctrl+0 Reset zoom
Space + Drag Pan canvas

Styling Customization

CSS Variables

:root {
  --annotation-primary: #FF0000;
  --annotation-toolbar-bg: #FFFFFF;
}

Container Styling

\x3CImageAnnotation
  src={src}
  className="my-annotation-container"
/>
.my-annotation-container {
  border: 1px solid #ddd;
  border-radius: 8px;
}

Debugging Common Issues

Issue 1: Canvas Completely Blank

Symptoms:

  • Image loads successfully (network request completes)
  • Canvas area is empty/white

Root Causes and Solutions:

Cause Diagnosis Fix
Parent has no height Container has height: auto or no height set Set explicit height: style={{ height: 600 }}
DPR mismatch Retina/HiDPI display, canvas looks tiny Component handles DPR automatically
Image load error Check browser console for CORS errors Add crossOrigin="anonymous" to server
Zero canvas size Check canvas element dimensions Ensure parent has explicit dimensions

Issue 2: Annotations Not Saving

Symptoms:

  • Draw annotations but array remains empty
  • onChange callback never fires

Root Causes and Solutions:

Cause Diagnosis Fix
Stale state Using prev => prev incorrectly Pass new array directly: setAnnotations(newValue)
Missing onChange No callback provided Add onChange={setAnnotations}
Controlled conflict Both value and internal state Provide onChange with value

Correct pattern:

// WRONG - stale closure
onChange={(annotations) => {
  setAnnotations((prev) => [...prev, ...annotations]);
}}

// CORRECT - direct assignment
onChange={setAnnotations}

Issue 3: Blurry on HiDPI/Retina Displays

Diagnosis:

  • Canvas appears blurry or pixelated
  • Only happens on Retina displays

Root Cause: Missing devicePixelRatio scaling

Fix: The component handles DPR automatically since v1.x. Ensure:

  1. CSS import is included
  2. Parent container has proper dimensions

Issue 4: High-DPI Canvas Blank

Symptoms:

  • Works on standard displays
  • Blank on Retina/HiDPI

Root Cause: Canvas dimensions not scaled by devicePixelRatio

Diagnosis:

// In browser console
const canvas = document.querySelector('canvas');
console.log('Canvas size:', canvas.width, canvas.height);
console.log('Display size:', canvas.style.width, canvas.style.height);
console.log('DPR:', window.devicePixelRatio);

If canvas.width === canvas.style.width (not multiplied by DPR), this is the bug.

Issue 5: Text Annotation Not Updating

Symptoms:

  • Text tool selected
  • Click to add text
  • Text doesn't appear or doesn't save

Solution: Press Enter or click outside to commit text input.

Issue 6: Undo/Redo Not Working

Symptoms:

  • Press Ctrl+Z but nothing happens

Root Cause: No history to undo (first annotation can't be undone)

Issue 7: SSR/Next.js Issues

Symptoms:

  • "window is not defined"
  • Canvas only renders client-side

Solution:

'use client';
import dynamic from 'next/dynamic';

const ImageAnnotation = dynamic(
  () => import('@frank17008/image-annotation').then((mod) => mod.default),
  { ssr: false }
);

Build Commands

pnpm build:lib      # Build package to dist/
pnpm dev:lib       # Watch mode for library
pnpm start         # Run demo app
pnpm build:all    # Build everything

Dependencies

  • React 18+
  • TypeScript 4.5+
  • Canvas 2D API

Common Mistakes

❌ Forgetting CSS Import

// MISSING - component won't render correctly
import { ImageAnnotation } from '@frank17008/image-annotation';

// REQUIRED
import '@frank17008/image-annotation/dist/index.css';

❌ Parent Without Height

// WRONG - canvas has 0x0
\x3Cdiv>\x3CImageAnnotation src="..." />\x3C/div>

// CORRECT - explicit height
\x3Cdiv style={{ height: 600 }}>\x3CImageAnnotation src="..." />\x3C/div>

❌ Wrong Type Import

// WRONG
import { Annotation } from '@frank17008/image-annotation';

// CORRECT
import type { Annotation } from '@frank17008/image-annotation';

❌ Not Linking onChange with value

// WRONG - controlled without onChange (React warning)
\x3CImageAnnotation src="..." value={annotations} />

// CORRECT - controlled mode
\x3CImageAnnotation
  src="..."
  value={annotations}
  onChange={setAnnotations}
/>

Performance Tips

Large Images

For images > 5MB:

  1. Resize before passing to component
  2. Use appropriate container dimensions
  3. Consider lazy loading

Many Annotations (>100)

The component redraws on each change. For performance:

  1. Reduce lineWidth
  2. Simplify freehand paths (reduce point count)
安全使用建议
This skill appears safe and purpose-aligned as a documentation-only guide. Treat the npm package installation like any third-party dependency: verify that the package is the one you intend to use before adding it to your project.
功能分析
Type: OpenClaw Skill Name: image-annotation-usage Version: 1.0.0 The skill bundle provides comprehensive documentation and integration examples for a React-based image annotation component (@frank17008/image-annotation). The content in SKILL.md consists of standard React/TypeScript code snippets, API references, and troubleshooting guides for common UI issues like canvas rendering and state management. No evidence of data exfiltration, malicious execution, or prompt injection was found.
能力评估
Purpose & Capability
The skill’s stated purpose is to help integrate a React image annotation component, and the provided content is consistent with setup, props, examples, and troubleshooting guidance.
Instruction Scope
The instructions are documentation-style examples and do not direct the agent to override user intent, run hidden actions, or perform autonomous changes.
Install Mechanism
The skill includes user-directed npm/pnpm installation commands for the React package. This is expected for the stated purpose, but users should still trust the package before adding it to a project.
Credentials
The examples are scoped to a React web app and browser-based image upload/annotation behavior. No credentials, system access, or unrelated data access are requested.
Persistence & Privilege
No persistent background process, elevated privilege, credential use, or autonomous execution mechanism is shown in the provided artifacts.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install image-annotation-usage
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /image-annotation-usage 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release — concise integration and troubleshooting guide for the image annotation component. - Covers integrating @frank17008/image-annotation into React apps, including controlled/uncontrolled usage and custom image upload. - Details required parent container styling, common pitfalls (like blank canvas), and debugging tips. - Documents props, annotation types, keyboard shortcuts, and basic styling customization. - Provides usage patterns for exporting annotations and leveraging toolbar features. - Includes clear TypeScript usage guidance and typical integration code samples.
元数据
Slug image-annotation-usage
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

image-annotation-usage 是什么?

Use when integrating @frank17008/image-annotation React component into web applications, including basic setup, controlled/uncontrolled mode, custom image up... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 2 次。

如何安装 image-annotation-usage?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install image-annotation-usage」即可一键安装,无需额外配置。

image-annotation-usage 是免费的吗?

是的,image-annotation-usage 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

image-annotation-usage 支持哪些平台?

image-annotation-usage 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 image-annotation-usage?

由 Frank(@frank17008)开发并维护,当前版本 v1.0.0。

💬 留言讨论