
Syncfusion React Image Editor
- 389 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
syncfusion-react-image-editor is a Syncfusion React agent skill that helps developers embed canvas-based image editing with annotations, filters, transforms, and multi-format export in React applications.
About
syncfusion-react-image-editor is an agent skill from syncfusion/react-ui-components-skills for the Syncfusion React Image Editor at version 33.1.44. It covers opening images from files, URLs, base64, blobs, or file managers; cropping with 10 preset aspect ratios; rotate, flip, zoom, text and shape annotations, freehand drawing, filters, finetune, undo-redo, and toolbar customization. The component supports PNG, JPEG, SVG, WEBP, and BMP export, plus keyboard navigation, RTL, and 120+ localization keys. The skill indexes 28 reference guides inside the broader 62-skill Syncfusion React catalog. Reach for it when you need a polished in-app editor instead of stitching separate crop and markup libraries.
- syncfusion-react-image-editor
Syncfusion React Image Editor by the numbers
- 389 all-time installs (skills.sh)
- +25 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,080 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-image-editorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 389 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
How do you add in-browser image editing to React?
Use syncfusion-react-image-editor for development tasks
Who is it for?
React teams using Syncfusion who need a single component for crop, annotate, filter, and save flows with accessibility and i18n support.
Skip if: Server-side image pipelines or apps that only need static image display without editing controls.
When should I use this skill?
The user requests Syncfusion Image Editor setup, annotation tools, preset crop ratios, filter pipelines, or export handlers in React.
What you get
ImageEditor React components, annotation layers, crop and transform settings, and exported PNG, JPEG, SVG, or WEBP assets.
- ImageEditor React component
- Annotation and filter configuration
- Exported image assets
By the numbers
- Documents Syncfusion React Image Editor version 33.1.44
- Links to 28 reference guides across editing workflows
- Supports 5 image formats and 10 preset crop aspect ratios
Files
Implementing Syncfusion React Image Editor
The Syncfusion React Image Editor is a comprehensive, feature-rich component for editing images directly in your React applications. It provides an intuitive interface with powerful tools for transformations, annotations, effects, and more.
Component Overview
The Image Editor combines a canvas-based editing environment with a comprehensive toolbar and contextual tools. It supports:
- Multiple Input Sources: Files, URLs, base64, blobs, file managers, treeviews
- Rich Annotation Support: Text (with styling), shapes, freehand drawings, watermarks
- Professional Effects: Filters and fine-tuning controls
- Advanced Operations: Z-order management, redaction, frame decoration
- Accessibility First: Full keyboard navigation, WCAG compliance, RTL support, 120+ localization keys
- Flexible Integration: Standalone or within dialogs, with customizable toolbars
Documentation and Navigation Guide
🔹 API Reference
📄 Read: references/api.md
- Complete API documentation with all properties, methods, and events
- Properties overview (core, toolbar, settings)
- Methods for image operations, transformations, annotations
- Events for lifecycle, interactions, effects, and toolbars
- Enums and type definitions (ArrowheadType, FrameType, RedactType, etc.)
- Complete working examples with verified method signatures
Getting Started
📄 Read: references/getting-started.md
- Installation with Vite and create-react-app
- CSS imports and theme setup
- Basic component initialization
- Setting width, height, and initial rendering
Opening and Saving Images
📄 Read: references/opening-saving-images.md
- Open from file paths, URLs, base64 strings, blobs
- Open from file uploader, file manager, and treeview
- Save/export as PNG, JPEG, SVG, WEBP
- Image dimensions and aspect ratio control
- File opened, saving, and lifecycle events
Selection and Cropping
📄 Read: references/selection-cropping.md
- Insert custom, square, and circle selections
- Crop with aspect ratios (2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 5:7, 7:5, 9:16, 16:9)
- Crop method and selection events
- Maintain original image size during cropping
- Lock selection area during resizing
Transform: Rotate, Flip, and Straighten
📄 Read: references/transform-rotate-flip.md
- Rotate clockwise/counter-clockwise by degrees
- Flip horizontally and vertically
- Straighten images with fine degree adjustments (-45° to +45°)
- Transform annotations along with image
- Rotating and flipping events
Zoom and Pan Operations
📄 Read: references/zooming-panning.md
- Zoom in/out with configurable min/max factors
- Pan when zoomed or during cropping
- Zoom triggers (toolbar, pinch, mouse wheel, keyboard)
- Zooming and panning events
- Zoom point calculations
Text Annotations
📄 Read: references/text-annotations.md
- Add text with position, content, and font settings
- Text styling (bold, italic, underline, strikethrough)
- Font families, sizes, and colors
- Multiline text with newline characters
- Delete text annotations
- Customize font color via shapeChanging event
Freehand Drawing
📄 Read: references/freehand-drawing.md
- Enable/disable freehand drawing mode
- Customize stroke width and color
- Delete freehand annotations
- Adjust stroke during drawing via shapeChanging event
Shape Annotations
📄 Read: references/shape-annotations.md
- Draw rectangles, ellipses, lines, arrows, and paths
- Customize shapes with stroke color, stroke width, and fill color
- Rotate shapes with degree parameter
- Delete shape annotations
- Customize default stroke colors
- Shape changing and customization events
Image Annotations
📄 Read: references/image-annotations.md
- Add images or icons as annotations
- Control position, size, rotation, and opacity
- Aspect ratio preservation
- Watermarks and decorative elements
Filters
📄 Read: references/filters.md
- Apply predefined filters (Chrome, Cold, Warm, Grayscale, Sepia, Invert)
- Image filtering event
- Reset filter to original
Fine-Tuning
📄 Read: references/finetune.md
- Adjust brightness, contrast, saturation
- Control hue, exposure, blur, opacity
- Finetune value changing events
- Real-time adjustments with sliders
Undo and Redo
📄 Read: references/undo-redo.md
- Undo/redo operations with 16-step history
- Keyboard shortcuts (Ctrl+Z, Ctrl+Y)
- History management and limits
Toolbar Customization
📄 Read: references/toolbar-customization.md
- Built-in toolbar items (20+ default tools)
- Add, remove, enable, disable toolbar items
- Custom toolbar items with event handlers
- Contextual toolbar for annotations
- Toolbar templates for complete customization
- Toolbar created and item clicked events
Quick Access Toolbar
📄 Read: references/quick-access-toolbar.md
- Quick access toolbar for annotations
- Show/hide quick access toolbar
- Add custom items to quick access toolbar
- Quick access toolbar open event
Resize Image
📄 Read: references/resize-image.md
- Resize with or without aspect ratio
- Width and height parameters
- Resizing event with before/after dimensions
Frame Decoration
📄 Read: references/frame-decoration.md
- Apply frames (Mat, Bevel, Line, Inset, Hook)
- Customize frame color, size, and line style
- Frame changing event
Z-Order Layering
📄 Read: references/z-order-layering.md
- Bring forward/send backward annotations
- Bring to front/send to back
- Manage annotation layer order
Redact Sensitive Information
📄 Read: references/redact-sensitive-info.md
- Blur sensitive areas
- Pixelate sensitive information
- Redact CRUD operations (select, update, delete, get)
- Privacy and compliance
Accessibility and Localization
📄 Read: references/accessibility-localization.md
- WCAG 2.2, Section 508 compliance
- Screen reader support
- Keyboard shortcuts (Ctrl+Z, Ctrl+S, Ctrl+O, Delete, Enter, Escape)
- RTL language support
- Localization with 120+ locale keys
Image Restrictions and Validation
📄 Read: references/image-restrictions-validation.md
- Allowed file extensions (.jpg, .png, .svg, .webp, .bmp)
- Min and max file size restrictions
- File validation and error alerts
Clear Image
📄 Read: references/clear-image.md
- Clear editor state
- Dialog reuse patterns
- Remove previously loaded images
Fit to Width and Height
📄 Read: references/fit-width-height.md
- Fit image to editor container width
- Fit image to editor container height
- Zoom calculations for perfect fit
Render in Dialog
📄 Read: references/render-in-dialog.md
- Render Image Editor within Dialog component
- Content template integration
- Dialog show/hide patterns
Reset Image
📄 Read: references/reset-image.md
- Reset all modifications to original state
- Restore unmodified version
- Clear annotations and effects
Quick Start Example
import { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';
import React from 'react';
function App() {
let imgObj: ImageEditorComponent;
function imageEditorCreated(): void {
imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/bridge.jpeg');
}
return (
<div>
<ImageEditorComponent
ref={(img) => { imgObj = img }}
width="550px"
height="350px"
created={imageEditorCreated}
/>
</div>
);
}
export default App;Common Patterns
Pattern 1: Open + Edit + Save Workflow
1. Open image via open() method 2. Apply transformations, annotations, or effects 3. Use export() to save as PNG/JPEG/SVG/WEBP 4. Optionally convert to base64 or blob for backend storage
Pattern 2: Responsive Toolbar
1. Define custom toolbar items in toolbar property 2. Handle clicks via toolbarItemClicked event 3. Execute methods like rotate(), zoom(), drawText() based on clicked item 4. Update contextual toolbar via toolbarUpdating event
Pattern 3: Annotation Workflow
1. Enable annotation mode (freehand, text, shape) 2. Customize via shapeChanging event (color, stroke, font) 3. Delete via deleteShape() with shape ID 4. Manage layers via z-order methods
Pattern 4: Dialog Integration
1. Render Image Editor in Dialog's content template 2. Load image when dialog opens via fileOpened event 3. Call clearImage() before closing dialog 4. Retrieve edited image data via export() or getImageData()
Pattern 5: Filter + Finetune Pipeline
1. Apply filter via applyImageFilter() 2. Fine-tune via finetuneImage() (brightness, contrast, etc.) 3. Listen to imageFiltering and finetuneValueChanging events 4. Combine effects for professional results
Key Properties
| Property | Type | Purpose |
|---|---|---|
width | string | Editor canvas width (e.g., "550px", "100%") |
height | string | Editor canvas height (e.g., "350px", "100%") |
toolbar | array | Customize toolbar items and visibility |
fontFamily | object | Add custom font families |
uploadSettings | object | Configure file restrictions (extensions, size) |
zoomSettings | object | Set min/max zoom factors |
showQuickAccessToolbar | boolean | Show/hide quick access toolbar |
locale | string | Set localization (e.g., 'de-DE') |
Key Events
| Event | Trigger | Use Case |
|---|---|---|
created | Component initialized | Load image on startup |
fileOpened | Image loaded | Add watermarks, apply defaults |
beforeSave | Before export | Validate, add metadata |
cropping | During crop | Prevent scaling, lock dimensions |
zooming | During zoom | Validate zoom level |
rotating | During rotate | Track rotation angle |
shapeChanging | Annotation modified | Customize stroke, font |
toolbarUpdating | Toolbar rendered | Add/remove contextual items |
Supported File Formats
Open: PNG, JPEG, JPG, SVG, WEBP, BMP (local, URL, base64, blob) Save/Export: PNG, JPEG, SVG, WEBP
Next Steps
- Start with getting-started.md for setup
- Explore opening-saving-images.md to understand data flow
- Check specific features in their dedicated reference files
- Use accessibility-localization.md for multi-language support
Accessibility and Localization
Table of Contents
Accessibility
WCAG Compliance
Image Editor supports WCAG 2.1 Level AA standards:
const imageEditor = (
<ImageEditorComponent
// Accessibility built-in
ariaLabel="Image editing workspace"
role="application"
/>
);Keyboard Navigation
Default Shortcuts
| Shortcut | Action |
|---|---|
| Tab | Navigate controls |
| Shift+Tab | Reverse navigation |
| Enter | Confirm action |
| Escape | Close dialog |
| Ctrl+Z | Undo |
| Ctrl+Y | Redo |
| Ctrl+O | Open |
| Ctrl+S | Save |
| Delete | Remove selected |
| Arrow Keys | Move annotations |
Custom Keyboard Shortcuts
const handleKeyDown = (e: KeyboardEvent): void => {
if (e.altKey) {
switch (e.key) {
case 'c':
e.preventDefault();
imgObj.crop();
break;
case 't':
e.preventDefault();
openTextDialog();
break;
case 'r':
e.preventDefault();
imgObj.rotate(90);
break;
case 'f':
e.preventDefault();
imgObj.flip('Horizontal');
break;
}
}
};
document.addEventListener('keydown', handleKeyDown);Screen Reader Support
function announceAction(message: string): void {
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.setAttribute('aria-atomic', 'true');
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => announcement.remove(), 3000);
}
// Usage
const handleCrop = (): void => {
imgObj.crop();
announceAction('Image cropped successfully');
};Semantic HTML
const ImageEditorContainer = (): JSX.Element => {
return (
<article className="image-editor-container">
<header>
<h1>Image Editor</h1>
<p>Edit and enhance your images</p>
</header>
<main>
<ImageEditorComponent />
</main>
<footer>
<p>Status: Ready</p>
</footer>
</article>
);
};Color Contrast
const accessibleTheme = {
buttonBackground: '#0056B3',
buttonText: '#FFFFFF',
tooltipBackground: '#333333',
tooltipText: '#FFFFFF',
borderColor: '#000000'
};
const imageEditor = (
<ImageEditorComponent
theme={accessibleTheme}
/>
);Localization
Supported Locales
The Image Editor supports 120+ locales. Common ones:
// English (default)
<ImageEditorComponent />
// Español
<ImageEditorComponent locale="es" />
// Français
<ImageEditorComponent locale="fr" />
// Deutsch
<ImageEditorComponent locale="de" />
// 日本語
<ImageEditorComponent locale="ja" />
// 中文
<ImageEditorComponent locale="zh" />
// हिन्दी
<ImageEditorComponent locale="hi" />Locale-Specific Setup
import { L10n } from '@syncfusion/ej2-base';
// Register custom locale
L10n.load({
'es': {
'imageeditor': {
'Open': 'Abrir',
'Save': 'Guardar',
'Undo': 'Deshacer',
'Redo': 'Rehacer',
'Crop': 'Recortar',
'Rotate': 'Girar',
'Text': 'Texto',
'Filters': 'Filtros'
}
}
});
const imageEditor = (
<ImageEditorComponent locale="es" />
);Custom Localization
interface LocalizationStrings {
[locale: string]: {
[key: string]: string;
};
}
const customLocales: LocalizationStrings = {
'en': {
'Open': 'Open Image',
'Save': 'Save Image',
'Crop': 'Crop Selection',
'Rotate': 'Rotate Image'
},
'es': {
'Open': 'Abrir Imagen',
'Save': 'Guardar Imagen',
'Crop': 'Recortar Selección',
'Rotate': 'Girar Imagen'
},
'fr': {
'Open': 'Ouvrir Image',
'Save': 'Enregistrer Image',
'Crop': 'Recadrer Sélection',
'Rotate': 'Tourner Image'
}
};
L10n.load(customLocales);
const imageEditor = (
<ImageEditorComponent locale="fr" />
);RTL (Right-to-Left) Support
// Hebrew
<ImageEditorComponent locale="he" enableRtl={true} />
// Arabic
<ImageEditorComponent locale="ar" enableRtl={true} />
// Urdu
<ImageEditorComponent locale="ur" enableRtl={true} />Best Practices
Multi-Language UI
const LanguageSelector = (): JSX.Element => {
const [language, setLanguage] = useState('en');
return (
<>
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
<option value="ja">日本語</option>
<option value="zh">中文</option>
</select>
<ImageEditorComponent locale={language} />
</>
);
};Accessible Tooltips
function createAccessibleTooltip(text: string, target: HTMLElement): void {
const tooltip = document.createElement('div');
tooltip.setAttribute('role', 'tooltip');
tooltip.setAttribute('aria-label', text);
tooltip.className = 'accessible-tooltip';
tooltip.textContent = text;
target.addEventListener('mouseenter', () => {
target.parentElement?.appendChild(tooltip);
});
target.addEventListener('mouseleave', () => {
tooltip.remove();
});
}Language-Aware Date/Time
interface LocalDateTimeOptions {
locale: string;
}
function formatDateTime(date: Date, options: LocalDateTimeOptions): string {
return date.toLocaleString(options.locale, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
// Usage
console.log(formatDateTime(new Date(), { locale: 'es' }));
// Output: "15 de enero de 2024, 14:30"Advanced Patterns
Dynamic Localization
class LocalizationManager {
private currentLocale: string = 'en';
private locales: LocalizationStrings = {};
setLocale(locale: string): void {
this.currentLocale = locale;
this.applyLocale();
}
private applyLocale(): void {
L10n.load(this.locales);
// Trigger UI update
window.location.reload();
}
registerLocale(locale: string, strings: Record<string, string>): void {
this.locales[locale] = strings;
}
getTranslation(key: string): string {
return this.locales[this.currentLocale]?.[key] ?? key;
}
}
const localizationManager = new LocalizationManager();Detect User Locale
function detectUserLocale(): string {
// Check browser language
const browserLang = navigator.language.split('-')[0];
// Supported locales
const supportedLocales = ['en', 'es', 'fr', 'de', 'ja', 'zh', 'hi'];
// Return supported locale or default to English
return supportedLocales.includes(browserLang) ? browserLang : 'en';
}
const userLocale = detectUserLocale();
const imageEditor = (
<ImageEditorComponent locale={userLocale} />
);Accessibility Audit
class AccessibilityAudit {
checkKeyboardNavigation(): boolean {
// Verify all controls are keyboard accessible
return document.querySelectorAll('[tabindex="-1"]').length === 0;
}
checkContrast(): boolean {
// Verify sufficient color contrast
const elements = document.querySelectorAll('button, [role="button"]');
// Implementation would check computed styles
return elements.length > 0;
}
checkAriaLabels(): boolean {
// Verify all interactive elements have labels
const interactive = document.querySelectorAll('button, [role="button"], input');
let labeled = 0;
interactive.forEach(element => {
if (element.getAttribute('aria-label') ||
element.getAttribute('aria-labelledby') ||
element.textContent?.trim()) {
labeled++;
}
});
return labeled === interactive.length;
}
runFullAudit(): void {
console.log({
keyboardNavigation: this.checkKeyboardNavigation(),
colorContrast: this.checkContrast(),
ariaLabels: this.checkAriaLabels()
});
}
}
const audit = new AccessibilityAudit();
audit.runFullAudit();Language-Specific Features
interface LanguageFeatures {
locale: string;
dateFormat: string;
timeFormat: string;
currencySymbol: string;
numberSeparator: string;
}
const languageFeatures: Record<string, LanguageFeatures> = {
'en': {
locale: 'en-US',
dateFormat: 'MM/DD/YYYY',
timeFormat: '12-hour',
currencySymbol: '$',
numberSeparator: ','
},
'de': {
locale: 'de-DE',
dateFormat: 'DD.MM.YYYY',
timeFormat: '24-hour',
currencySymbol: '€',
numberSeparator: '.'
},
'ja': {
locale: 'ja-JP',
dateFormat: 'YYYY年MM月DD日',
timeFormat: '24-hour',
currencySymbol: '¥',
numberSeparator: ','
}
};
function getLanguageFeatures(locale: string): LanguageFeatures {
return languageFeatures[locale] || languageFeatures['en'];
}Focus Management
class AccessibleFocusManager {
private focusableElements: HTMLElement[] = [];
initialize(): void {
const selector = 'button, [href], input, [tabindex]:not([tabindex="-1"])';
this.focusableElements = Array.from(document.querySelectorAll(selector));
}
focusFirst(): void {
this.focusableElements[0]?.focus();
}
focusNext(current: HTMLElement): void {
const index = this.focusableElements.indexOf(current);
if (index < this.focusableElements.length - 1) {
this.focusableElements[index + 1]?.focus();
}
}
focusPrevious(current: HTMLElement): void {
const index = this.focusableElements.indexOf(current);
if (index > 0) {
this.focusableElements[index - 1]?.focus();
}
}
}
const focusManager = new AccessibleFocusManager();
focusManager.initialize();Image Editor API Reference
Complete API documentation for the Syncfusion React ImageEditorComponent. This reference covers all properties, methods, and events available for programmatic interaction.
Component Declaration
<ImageEditorComponent></ImageEditorComponent>---
Properties
Core Configuration
width (string)
- Description: Specifies the width of the Image Editor container
- Default Value:
'100%' - Example:
<ImageEditorComponent width="550px" />height (string)
- Description: Specifies the height of the Image Editor container
- Default Value:
'100%' - Example:
<ImageEditorComponent height="350px" />disabled (boolean)
- Description: Defines whether the Image Editor component is enabled or disabled
- Default Value:
false - Example:
<ImageEditorComponent disabled={true} />cssClass (string)
- Description: Defines one or more CSS classes for customizing the appearance of the Image Editor component
- Default Value:
'' - Example:
<ImageEditorComponent cssClass="custom-editor-class" />Editing and Operations
allowUndoRedo (boolean)
- Description: Specifies whether undo/redo operations are enabled in the image editor
- Default Value:
true - Example:
<ImageEditorComponent allowUndoRedo={true} />imageSmoothingEnabled (boolean)
- Description: Determines whether high-quality images should be smoothed when rendered
- Default Value:
false - Example:
<ImageEditorComponent imageSmoothingEnabled={true} />Toolbar Configuration
toolbar (string[] | ItemModel[])
- Description: Specifies the toolbar items to perform UI interactions. Accepts string array of predefined commands or custom ItemModel array
- Default Value:
null(renders default toolbar with all commands) - Available Commands:
Crop- Crop image with various selection shapes and aspect ratiosStraightening- Rotate image by specified angleAnnotate- Insert shapes, text, images, and freehand drawingsTransform- Rotate and flip operationsFinetunes- Color adjustments (brightness, contrast, saturation, etc.)Filters- Apply predefined color filtersFrame- Add decorative bordersResize- Modify image dimensionsZoomIn- Zoom in on imageZoomOut- Zoom out from imageSave- Export modified imageOpen- Open image for editingUndo- Revert last actionRedo- Redo last actionReset- Restore original image- Example:
const toolbar = ['Crop', 'ZoomIn', 'ZoomOut', 'Transform', { text: 'Custom' }];
<ImageEditorComponent toolbar={toolbar} />toolbarTemplate (string | Function)
- Description: Specifies a custom template for the toolbar. If defined, the toolbar property has no effect
- Default Value:
null - Example:
function customToolbar() {
return <ButtonComponent content='Custom' />;
}
<ImageEditorComponent toolbarTemplate={customToolbar} />showQuickAccessToolbar (boolean)
- Description: Specifies whether to show or hide the quick access toolbar
- Default Value:
true - Example:
<ImageEditorComponent showQuickAccessToolbar={true} />quickAccessToolbarTemplate (string | Function)
- Description: Specifies a template for the quick access toolbar for customization
- Default Value:
null - Example:
function customQuickToolbar() {
return <div>Quick Toolbar Items</div>;
}
<ImageEditorComponent quickAccessToolbarTemplate={customQuickToolbar} />Advanced Configuration
theme (string | Theme)
- Description: Specifies the theme of the Image Editor. Determines the appearance of shape selections and UI elements
- Default Value:
Theme.Bootstrap5 - Supported Themes: Bootstrap5, and other Syncfusion themes
- Example:
<ImageEditorComponent theme="Bootstrap5" />locale (string)
- Description: Overrides the global culture and localization value for this component
- Default Value:
'en-US' - Supported Locales: 120+ language codes (de-DE, fr-FR, es-ES, etc.)
- Example:
<ImageEditorComponent locale="de-DE" />Settings Objects
finetuneSettings (FinetuneSettingsModel)
- Description: Specifies finetune settings for color adjustments in the image editor
- Default Value:
null - Properties:
brightness- Brightness adjustment range (min, max, defaultValue)contrast- Contrast adjustment rangesaturation- Saturation adjustment rangehue- Hue adjustment rangeexposure- Exposure adjustment rangeblur- Blur adjustment rangeopacity- Opacity adjustment range- Example:
const finetune = {
brightness: { min: -100, max: 100, defaultValue: 0 },
contrast: { min: -100, max: 100, defaultValue: 0 }
};
<ImageEditorComponent finetuneSettings={finetune} />fontFamily (FontFamilyModel)
- Description: Predefines font families that populate in the font family dropdown list from the toolbar
- Default Value:
null - Example:
const fonts = ['Arial', 'Courier New', 'Georgia'];
<ImageEditorComponent fontFamily={fonts} />selectionSettings (SelectionSettingsModel)
- Description: Specifies selection settings to customize selection appearance and behavior
- Default Value:
null - Example:
const selectionSettings = {
// Customization options
};
<ImageEditorComponent selectionSettings={selectionSettings} />zoomSettings (ZoomSettingsModel)
- Description: Specifies zoom settings for zooming actions
- Default Value:
null - Properties:
minZoomFactor- Minimum zoom factormaxZoomFactor- Maximum zoom factorzoomFactor- Current zoom factorzoomTrigger- Zoom triggers (MouseWheel, Pinch, Toolbar, Commands)zoomPoint- Point to zoom in/out on (Point object with x, y)- Example:
const zoomSettings = {
minZoomFactor: 1,
maxZoomFactor: 100,
zoomFactor: 1,
zoomTrigger: ZoomTrigger.MouseWheel | ZoomTrigger.Pinch
};
<ImageEditorComponent zoomSettings={zoomSettings} />uploadSettings (UploadSettingsModel)
- Description: Represents settings for configuring image uploads with restrictions
- Default Value:
null - Properties:
allowedExtensions- Allowed file extensions (e.g., ['jpg', 'png', 'svg'])minFileSize- Minimum file size in bytesmaxFileSize- Maximum file size in bytes- Example:
const uploadSettings = {
allowedExtensions: ['jpg', 'png', 'svg', 'webp', 'bmp'],
maxFileSize: 5242880 // 5MB in bytes
};
<ImageEditorComponent uploadSettings={uploadSettings} />---
Methods
Image Operations
open(data: string | ImageData): void
- Description: Opens an image as URL, base64 string, blob, or ImageData for editing
- Parameters:
data(string | ImageData) - URL, base64 string, blob, or ImageData object- Returns: void
- Example:
imageObj.open('https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png');clearImage(): void
- Description: Clears the loaded image in the Image Editor and resets the state
- Returns: void
- Example:
imageObj.clearImage();reset(): void
- Description: Resets all modifications done in the image editor and reverts to the original image
- Returns: void
- Example:
imageObj.reset();export(type?: string, fileName?: string, imageQuality?: number): void
- Description: Exports the edited image using specified file format, name, and quality
- Parameters:
type(string, optional) - Image format: 'image/png', 'image/jpeg', 'image/svg+xml', 'image/webp'fileName(string, optional) - Name for the saved fileimageQuality(number, optional) - Quality of image (0-1). Default is 1- Returns: void
- Example:
imageObj.export('image/png', 'edited-image', 0.95);getImageData(): ImageData
- Description: Returns image as ImageData to load it into a canvas
- Returns: ImageData object
- Example:
const imageData = imageObj.getImageData();getImageDimension(): Dimension
- Description: Gets the dimension of the image including x, y, width, and height. Useful after cropping
- Returns: Dimension object with x, y, width, height properties
- Example:
const dimension = imageObj.getImageDimension();
console.log(dimension.width, dimension.height);resize(width: number, height: number, isAspectRatio?: boolean): boolean
- Description: Resizes the image by changing its width and height
- Parameters:
width(number) - New width in pixelsheight(number) - New height in pixelsisAspectRatio(boolean, optional) - Whether to maintain aspect ratio- Returns: boolean (true if successful)
- Example:
imageObj.resize(800, 600, true);Selection and Cropping
select(type: string, startX?: number, startY?: number, width?: number, height?: number): void
- Description: Performs selection in the image editor for cropping purposes
- Parameters:
type(string) - Selection type: 'circle', 'square', 'custom', or aspect ratio like '16:9', '4:3', '3:2', etc.startX(number, optional) - Start x-coordinate of selectionstartY(number, optional) - Start y-coordinate of selectionwidth(number, optional) - Width of selection areaheight(number, optional) - Height of selection area- Returns: void
- Example:
imageObj.select('16:9', 10, 10, 400, 225);clearSelection(resetCrop?: boolean): void
- Description: Clears the current selection performed in the image editor
- Parameters:
resetCrop(boolean, optional) - Whether to reset last cropped image- Returns: void
- Example:
imageObj.clearSelection(true);crop(): boolean
- Description: Crops an image based on the selection done in the image editor
- Returns: boolean (true if crop successful)
- Example:
imageObj.select('16:9', 10, 10);
imageObj.crop();Transformation Methods
rotate(degree: number): boolean
- Description: Rotates an image clockwise (positive) or counter-clockwise (negative)
- Parameters:
degree(number) - Rotation angle in degrees. Positive for clockwise, negative for counter-clockwise- Returns: boolean (true if successful)
- Example:
imageObj.rotate(90); // Rotate 90 degrees clockwise
imageObj.rotate(-45); // Rotate 45 degrees counter-clockwiseflip(direction: Direction): void
- Description: Flips the image horizontally or vertically
- Parameters:
direction(Direction) - Flip direction: Direction.Horizontal or Direction.Vertical- Returns: void
- Example:
imageObj.flip(Direction.Horizontal); // Flip left-right
imageObj.flip(Direction.Vertical); // Flip top-bottomstraightenImage(degree: number): boolean
- Description: Straightens an image by rotating it clockwise or counter-clockwise
- Parameters:
degree(number) - Degree value for straightening. Positive for clockwise, negative for counter-clockwise- Returns: boolean (true if successful)
- Example:
imageObj.straightenImage(5);Zoom and Pan Methods
zoom(zoomFactor: number, zoomPoint?: Point): void
- Description: Zooms in or out on a specific point in the image editor
- Parameters:
zoomFactor(number) - Percentage-based zoom factor (e.g., 20 for 2x zoom)zoomPoint(Point, optional) - Point to zoom on with x, y coordinates- Returns: void
- Example:
imageObj.zoom(40, { x: 400, y: 400 });pan(value: boolean, x?: number, y?: number): void
- Description: Enables or disables panning on the image editor
- Parameters:
value(boolean) - Whether to enable or disable panningx(number, optional) - Horizontal pan valuey(number, optional) - Vertical pan value- Returns: void
- Example:
imageObj.pan(true, 50, 30);freehandDraw(value: boolean): void
- Description: Enables or disables freehand drawing in the image editor
- Parameters:
value(boolean) - Whether to enable or disable freehand drawing- Returns: void
- Example:
imageObj.freehandDraw(true);Annotation: Drawing Shapes
drawRectangle(x?: number, y?: number, width?: number, height?: number, strokeWidth?: number, strokeColor?: string, fillColor?: string, degree?: number, isSelected?: boolean, borderRadius?: number): boolean
- Description: Draws a rectangle on the image
- Parameters:
x(number, optional) - X-coordinate of rectangley(number, optional) - Y-coordinate of rectanglewidth(number, optional) - Width of rectangleheight(number, optional) - Height of rectanglestrokeWidth(number, optional) - Stroke widthstrokeColor(string, optional) - Stroke color (hex or rgb)fillColor(string, optional) - Fill colordegree(number, optional) - Rotation degreeisSelected(boolean, optional) - Show in selected stateborderRadius(number, optional) - Border radius- Returns: boolean (true if successful)
- Example:
imageObj.drawRectangle(50, 50, 100, 80, 2, '#FF0000', '#FFFF00', 0, true);drawEllipse(x?: number, y?: number, radiusX?: number, radiusY?: number, strokeWidth?: number, strokeColor?: string, fillColor?: string, degree?: number, isSelected?: boolean): boolean
- Description: Draws an ellipse on the image
- Parameters:
x(number, optional) - X-coordinate of ellipse centery(number, optional) - Y-coordinate of ellipse centerradiusX(number, optional) - Horizontal radiusradiusY(number, optional) - Vertical radiusstrokeWidth(number, optional) - Stroke widthstrokeColor(string, optional) - Stroke colorfillColor(string, optional) - Fill colordegree(number, optional) - Rotation degreeisSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
imageObj.drawEllipse(150, 100, 40, 60, 2, '#0000FF', '', 0, true);drawLine(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number, strokeColor?: string, isSelected?: boolean): boolean
- Description: Draws a line on the image
- Parameters:
startX(number, optional) - Start X-coordinatestartY(number, optional) - Start Y-coordinateendX(number, optional) - End X-coordinateendY(number, optional) - End Y-coordinatestrokeWidth(number, optional) - Stroke widthstrokeColor(string, optional) - Stroke colorisSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
imageObj.drawLine(10, 10, 100, 100, 2, '#000000', true);drawArrow(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number, strokeColor?: string, arrowStart?: ArrowheadType, arrowEnd?: ArrowheadType, isSelected?: boolean): boolean
- Description: Draws an arrow on the image
- Parameters:
startX(number, optional) - Start X-coordinatestartY(number, optional) - Start Y-coordinateendX(number, optional) - End X-coordinateendY(number, optional) - End Y-coordinatestrokeWidth(number, optional) - Stroke widthstrokeColor(string, optional) - Stroke colorarrowStart(ArrowheadType, optional) - Start arrowhead type (default: None)arrowEnd(ArrowheadType, optional) - End arrowhead type (default: SolidArrow)isSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
imageObj.drawArrow(20, 20, 150, 150, 2, '#FF0000', ArrowheadType.None, ArrowheadType.SolidArrow);drawPath(pointColl: Point[], strokeWidth?: number, strokeColor?: string, isSelected?: boolean): boolean
- Description: Draws a path (polyline) on the image
- Parameters:
pointColl(Point[]) - Array of points with x, y coordinatesstrokeWidth(number, optional) - Stroke widthstrokeColor(string, optional) - Stroke colorisSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
const points = [{ x: 10, y: 10 }, { x: 50, y: 50 }, { x: 100, y: 20 }];
imageObj.drawPath(points, 2, '#000000', true);drawText(x?: number, y?: number, text?: string, fontFamily?: string, fontSize?: number, bold?: boolean, italic?: boolean, color?: string, isSelected?: boolean, degree?: number, fillColor?: string, strokeColor?: string, strokeWidth?: number, underline?: boolean, strikethrough?: boolean): boolean
- Description: Draws text annotation on the image
- Parameters:
x(number, optional) - X-coordinate of texty(number, optional) - Y-coordinate of texttext(string, optional) - Text contentfontFamily(string, optional) - Font family namefontSize(number, optional) - Font size in pixelsbold(boolean, optional) - Whether text is bolditalic(boolean, optional) - Whether text is italiccolor(string, optional) - Text colorisSelected(boolean, optional) - Show in selected statedegree(number, optional) - Rotation degreefillColor(string, optional) - Background fill colorstrokeColor(string, optional) - Text outline colorstrokeWidth(number, optional) - Outline stroke widthunderline(boolean, optional) - Whether text is underlinedstrikethrough(boolean, optional) - Whether text has strikethrough- Returns: boolean (true if successful)
- Example:
imageObj.drawText(100, 100, 'Syncfusion', 'Arial', 20, true, false, '#000000');drawImage(data: string | ImageData, x?: number, y?: number, width?: number, height?: number, isAspectRatio?: boolean, degree?: number, opacity?: number, isSelected?: boolean): boolean
- Description: Draws an image as annotation on the image
- Parameters:
data(string | ImageData) - Image URL or ImageDatax(number, optional) - X-coordinatey(number, optional) - Y-coordinatewidth(number, optional) - Width of imageheight(number, optional) - Height of imageisAspectRatio(boolean, optional) - Maintain aspect ratiodegree(number, optional) - Rotation degreeopacity(number, optional) - Opacity value (0-1)isSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
imageObj.drawImage('watermark.png', 50, 50, 100, 100, true, 0, 0.5);drawFrame(frameType: FrameType, color?: string, gradientColor?: string, size?: number, inset?: number, offset?: number, borderRadius?: number, frameLineStyle?: FrameLineStyle, lineCount?: number): boolean
- Description: Draws a frame decoration on the image
- Parameters:
frameType(FrameType) - Frame type to applycolor(string, optional) - Frame color (default: '#fff')gradientColor(string, optional) - Gradient color for framesize(number, optional) - Frame size as percentage (default: 20)inset(number, optional) - Inset value for specific frame typesoffset(number, optional) - Offset value for specific frame typesborderRadius(number, optional) - Border radius for line-type framesframeLineStyle(FrameLineStyle, optional) - Line style (default: Solid)lineCount(number, optional) - Number of lines for line-type frames- Returns: boolean (true if successful)
- Example:
imageObj.drawFrame(FrameType.Mat, '#CCCCCC', '', 15);Annotation: Redaction
drawRedact(type?: RedactType, x?: number, y?: number, width?: number, height?: number, value?: number): boolean
- Description: Draws a redaction (blur or pixelate) on the image for sensitive information
- Parameters:
type(RedactType, optional) - Redaction type: Blur or Pixelate (default: Blur)x(number, optional) - X-coordinate of redactiony(number, optional) - Y-coordinate of redactionwidth(number, optional) - Width of redaction area (default: 100)height(number, optional) - Height of redaction area (default: 50)value(number, optional) - Blur value or pixel size (default: 20)- Returns: boolean (true if successful)
- Example:
imageObj.drawRedact(RedactType.Blur, 100, 100, 150, 80, 20);deleteRedact(id: string): void
- Description: Deletes a redaction based on the given redaction ID
- Parameters:
id(string) - Redaction ID to delete- Returns: void
- Example:
imageObj.deleteRedact('redact_1');updateRedact(setting: RedactSettings, isSelected?: boolean): boolean
- Description: Updates existing redaction by changing height, width, blur, or pixel size
- Parameters:
setting(RedactSettings) - Redaction settings to updateisSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
const redactSettings = { id: 'redact_1', width: 200, height: 100 };
imageObj.updateRedact(redactSettings, true);selectRedact(id: string): boolean
- Description: Selects a redaction based on the given redaction ID
- Parameters:
id(string) - Redaction ID to select- Returns: boolean (true if selected)
- Example:
imageObj.selectRedact('redact_1');getRedacts(): RedactSettings[]
- Description: Gets all redaction details that are drawn on the image editor
- Returns: Array of RedactSettings objects
- Example:
const redacts = imageObj.getRedacts();
console.log(redacts);Annotation: Shape Management
deleteShape(id: string): void
- Description: Deletes a shape annotation based on the given shape ID
- Parameters:
id(string) - Shape ID to delete- Returns: void
- Example:
imageObj.deleteShape('shape_1');updateShape(setting: ShapeSettings, isSelected?: boolean): boolean
- Description: Updates existing shape by changing height, width, color, and font styles
- Parameters:
setting(ShapeSettings) - Shape settings to updateisSelected(boolean, optional) - Show in selected state- Returns: boolean (true if successful)
- Example:
const shapeSettings = { id: 'shape_1', strokeColor: '#FF0000', strokeWidth: 3 };
imageObj.updateShape(shapeSettings, true);selectShape(id: string): boolean
- Description: Selects a shape based on the given shape ID
- Parameters:
id(string) - Shape ID to select- Returns: boolean (true if selected)
- Example:
imageObj.selectShape('shape_1');getShapeSetting(id: string): ShapeSettings
- Description: Gets a specific shape's details based on its ID
- Parameters:
id(string) - Shape ID- Returns: ShapeSettings object
- Example:
const shape = imageObj.getShapeSetting('shape_1');
console.log(shape.type, shape.strokeColor);getShapeSettings(): ShapeSettings[]
- Description: Gets all shape details drawn on the image editor
- Returns: Array of ShapeSettings objects
- Example:
const shapes = imageObj.getShapeSettings();cloneShape(shapeId: string): boolean
- Description: Duplicates a shape based on the given shape ID
- Parameters:
shapeId(string) - Shape ID to clone- Returns: boolean (true if cloned successfully)
- Example:
imageObj.cloneShape('shape_1');Annotation: Z-Order Management
bringForward(shapeId: string): void
- Description: Moves a shape ahead of one shape based on the given shape ID
- Parameters:
shapeId(string) - Shape ID to move forward- Returns: void
- Example:
imageObj.bringForward('shape_1');bringToFront(shapeId: string): void
- Description: Moves a shape to the front of all other shapes
- Parameters:
shapeId(string) - Shape ID to bring to front- Returns: void
- Example:
imageObj.bringToFront('shape_1');sendBackward(shapeId: string): void
- Description: Moves a shape behind one shape based on the given shape ID
- Parameters:
shapeId(string) - Shape ID to move backward- Returns: void
- Example:
imageObj.sendBackward('shape_1');sendToBack(shapeId: string): void
- Description: Moves a shape to behind all other shapes
- Parameters:
shapeId(string) - Shape ID to send to back- Returns: void
- Example:
imageObj.sendToBack('shape_1');Effects and Filters
applyImageFilter(filterOption: ImageFilterOption): void
- Description: Applies a filter to the image
- Parameters:
filterOption(ImageFilterOption) - Filter options object with filter type and parameters- Returns: void
- Example:
imageObj.applyImageFilter({ type: 'Chrome' });
imageObj.applyImageFilter({ type: 'Grayscale' });getImageFilter(filterOption: ImageFilterOption): string
- Description: Gets and updates filter to the canvas in the image editor
- Parameters:
filterOption(ImageFilterOption) - Filter options to retrieve- Returns: string (filter result)
- Example:
const filter = imageObj.getImageFilter({ type: 'Sepia' });finetuneImage(finetuneOption: ImageFinetuneOption, value: number): void
- Description: Fine-tunes image with specified adjustment type and value
- Parameters:
finetuneOption(ImageFinetuneOption) - Finetune option: Brightness, Contrast, Saturation, Hue, Exposure, Blur, Opacityvalue(number) - Adjustment value- Returns: void
- Example:
imageObj.finetuneImage(ImageFinetuneOption.Brightness, 30);
imageObj.finetuneImage(ImageFinetuneOption.Contrast, -15);Text Editing
enableTextEditing(): void
- Description: Enables text area editing in the image editor
- Returns: void
- Example:
imageObj.enableTextEditing();Shape Drawing Control
enableShapeDrawing(shapeType: ShapeType, isEnabled?: boolean): void
- Description: Enables or disables shape drawing option in the image editor
- Parameters:
shapeType(ShapeType) - Type of shape to enable/disableisEnabled(boolean, optional) - Enable or disable (default: true)- Returns: void
- Example:
imageObj.enableShapeDrawing(ShapeType.Circle, true);
imageObj.enableShapeDrawing(ShapeType.Rectangle, false);Undo/Redo Operations
undo(): void
- Description: Reverses the last action performed by the user
- Returns: void
- Example:
imageObj.undo();redo(): void
- Description: Redoes the last user action that was undone
- Returns: void
- Example:
imageObj.redo();canUndo(): boolean
- Description: Specifies if it's possible to undo the last recent action
- Returns: boolean (true if undo is available)
- Example:
if (imageObj.canUndo()) {
imageObj.undo();
}canRedo(): boolean
- Description: Specifies if it's possible to redo the last recent action
- Returns: boolean (true if redo is available)
- Example:
if (imageObj.canRedo()) {
imageObj.redo();
}Canvas Management
apply(): void
- Description: Applies the operations performed in the image editor (annotation drawings)
- Returns: void
- Example:
imageObj.apply();discard(): void
- Description: Discards the operations performed in the image editor
- Returns: void
- Example:
imageObj.discard();update(): void
- Description: Refreshes the canvas wrapper to reflect changes
- Returns: void
- Example:
imageObj.update();---
Events
Lifecycle Events
created
- Type:
EmitType<Event> - Description: Triggered after the Image Editor component is rendered
- Use Case: Load initial image, apply default settings
- Example:
function handleCreated(): void {
imageObj.open('https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png');
}
<ImageEditorComponent created={handleCreated} />destroyed
- Type:
EmitType<Event> - Description: Triggered once the component is destroyed with its elements and bound events
- Use Case: Cleanup, dispose resources
- Example:
function handleDestroyed(): void {
console.log('Component destroyed');
}
<ImageEditorComponent destroyed={handleDestroyed} />File Operations
fileOpened
- Type:
EmitType<OpenEventArgs> - Description: Triggered once an image is opened in the image editor
- Event Args:
fileName- Name of opened filefileSize- Size of opened file- Use Case: Add watermarks, apply default effects, validate image
- Example:
function handleFileOpened(args: OpenEventArgs): void {
console.log('File opened:', args.fileName);
}
<ImageEditorComponent fileOpened={handleFileOpened} />beforeSave
- Type:
EmitType<BeforeSaveEventArgs> - Description: Triggered before an image is saved
- Event Args: Save event details
- Use Case: Validation, add metadata, confirm save
- Example:
function handleBeforeSave(args: BeforeSaveEventArgs): void {
console.log('About to save image');
}
<ImageEditorComponent beforeSave={handleBeforeSave} />saved
- Type:
EmitType<SaveEventArgs> - Description: Triggered once an image is successfully saved
- Event Args: Save event details
- Use Case: Show success message, upload to server
- Example:
function handleSaved(args: SaveEventArgs): void {
console.log('Image saved successfully');
}
<ImageEditorComponent saved={handleSaved} />Interaction Events
click
- Type:
EmitType<ImageEditorClickEventArgs> - Description: Triggered while clicking on an image in the image editor
- Event Args:
pageX- X-coordinate of clickpageY- Y-coordinate of click- Use Case: Handle custom click interactions
- Example:
function handleClick(args: ImageEditorClickEventArgs): void {
console.log('Clicked at:', args.pageX, args.pageY);
}
<ImageEditorComponent click={handleClick} />Transformation Events
cropping
- Type:
EmitType<CropEventArgs> - Description: Triggered while cropping an image
- Event Args: Crop event details with dimensions
- Use Case: Prevent invalid crops, lock aspect ratio
- Example:
function handleCropping(args: CropEventArgs): void {
console.log('Cropping...');
}
<ImageEditorComponent cropping={handleCropping} />rotating
- Type:
EmitType<RotateEventArgs> - Description: Triggered while rotating an image
- Event Args: Rotation angle and details
- Use Case: Track rotation state
- Example:
function handleRotating(args: RotateEventArgs): void {
console.log('Rotating to:', args.degree);
}
<ImageEditorComponent rotating={handleRotating} />flipping
- Type:
EmitType<FlipEventArgs> - Description: Triggered while flipping an image
- Event Args: Flip direction
- Use Case: Track flip state
- Example:
function handleFlipping(args: FlipEventArgs): void {
console.log('Flipped:', args.direction);
}
<ImageEditorComponent flipping={handleFlipping} />resizing
- Type:
EmitType<ResizeEventArgs> - Description: Triggered while resizing an image
- Event Args: New width and height
- Use Case: Validate dimensions, show resize preview
- Example:
function handleResizing(args: ResizeEventArgs): void {
console.log('Resizing to:', args.width, args.height);
}
<ImageEditorComponent resizing={handleResizing} />Zoom and Pan Events
zooming
- Type:
EmitType<ZoomEventArgs> - Description: Triggered while zooming an image
- Event Args: Zoom factor and point
- Use Case: Update UI indicators, sync other components
- Example:
function handleZooming(args: ZoomEventArgs): void {
console.log('Zoom factor:', args.zoomFactor);
}
<ImageEditorComponent zooming={handleZooming} />panning
- Type:
EmitType<PanEventArgs> - Description: Triggered while panning an image
- Event Args: Pan offset values
- Use Case: Track pan state
- Example:
function handlePanning(args: PanEventArgs): void {
console.log('Panning...');
}
<ImageEditorComponent panning={handlePanning} />Effect Events
imageFiltering
- Type:
EmitType<ImageFilterEventArgs> - Description: Triggered when applying a filter to an image
- Event Args: Filter type and parameters
- Use Case: Preview filter, log applied filters
- Example:
function handleImageFiltering(args: ImageFilterEventArgs): void {
console.log('Applied filter:', args.filterType);
}
<ImageEditorComponent imageFiltering={handleImageFiltering} />finetuneValueChanging
- Type:
EmitType<FinetuneEventArgs> - Description: Triggered when applying fine-tune adjustments to an image
- Event Args: Finetune type and value
- Use Case: Show finetune preview, track adjustments
- Example:
function handleFinetuneValueChanging(args: FinetuneEventArgs): void {
console.log('Finetune:', args.type, args.value);
}
<ImageEditorComponent finetuneValueChanging={handleFinetuneValueChanging} />frameChange
- Type:
EmitType<FrameChangeEventArgs> - Description: Triggered while applying frames on an image
- Event Args: Frame type and properties
- Use Case: Track frame application
- Example:
function handleFrameChange(args: FrameChangeEventArgs): void {
console.log('Frame changed');
}
<ImageEditorComponent frameChange={handleFrameChange} />Selection Events
selectionChanging
- Type:
EmitType<SelectionChangeEventArgs> - Description: Triggered while changing selection in the image editor
- Event Args: Selection dimensions
- Use Case: Update UI, validate selection
- Example:
function handleSelectionChanging(args: SelectionChangeEventArgs): void {
console.log('Selection changed');
}
<ImageEditorComponent selectionChanging={handleSelectionChanging} />Shape and Annotation Events
shapeChanging
- Type:
EmitType<ShapeChangeEventArgs> - Description: Triggered while changing shapes in the image editor
- Event Args: Shape properties and changes
- Use Case: Customize shape appearance, validate changes
- Example:
function handleShapeChanging(args: ShapeChangeEventArgs): void {
// Customize shape on the fly
if (args.type === 'text') {
args.fillColor = '#FF0000';
}
}
<ImageEditorComponent shapeChanging={handleShapeChanging} />shapeChange
- Type:
EmitType<ShapeChangeEventArgs> - Description: Triggered after shape changing action is completed
- Event Args: Final shape properties
- Use Case: Log changes, update data model
- Example:
function handleShapeChange(args: ShapeChangeEventArgs): void {
console.log('Shape changed:', args.id);
}
<ImageEditorComponent shapeChange={handleShapeChange} />editComplete
- Type:
EmitType<EditCompleteEventArgs> - Description: Triggered after completion of any editing action in the image editor
- Event Args: Edit action details
- Use Case: Update UI, save state, trigger related actions
- Example:
function handleEditComplete(args: EditCompleteEventArgs): void {
console.log('Edit complete:', args.action);
}
<ImageEditorComponent editComplete={handleEditComplete} />Toolbar Events
toolbarCreated
- Type:
EmitType<ToolbarEventArgs> - Description: Triggered once the toolbar is created
- Event Args: Toolbar items and configuration
- Use Case: Add/remove toolbar items, customize appearance
- Example:
function handleToolbarCreated(args: ToolbarEventArgs): void {
console.log('Toolbar created');
}
<ImageEditorComponent toolbarCreated={handleToolbarCreated} />toolbarUpdating
- Type:
EmitType<ToolbarEventArgs> - Description: Triggered while updating or refreshing the toolbar
- Event Args: Toolbar type and items
- Use Case: Dynamically customize contextual toolbars
- Example:
function handleToolbarUpdating(args: ToolbarEventArgs): void {
if (args.toolbarType === 'shapes') {
args.toolbarItems = ['fillColor', 'strokeColor', 'strokeWidth'];
}
}
<ImageEditorComponent toolbarUpdating={handleToolbarUpdating} />toolbarItemClicked
- Type:
EmitType<ClickEventArgs> - Description: Triggered once a toolbar item is clicked
- Event Args: Clicked item information
- Use Case: Handle custom toolbar item actions
- Example:
function handleToolbarItemClicked(args: ClickEventArgs): void {
console.log('Toolbar item clicked');
}
<ImageEditorComponent toolbarItemClicked={handleToolbarItemClicked} />Quick Access Toolbar Events
quickAccessToolbarOpen
- Type:
EmitType<QuickAccessToolbarEventArgs> - Description: Triggered when the quick access toolbar opens
- Event Args: Toolbar configuration
- Use Case: Customize quick access items
- Example:
function handleQuickAccessToolbarOpen(args: QuickAccessToolbarEventArgs): void {
console.log('Quick access toolbar opened');
}
<ImageEditorComponent quickAccessToolbarOpen={handleQuickAccessToolbarOpen} />quickAccessToolbarItemClick
- Type:
EmitType<ClickEventArgs> - Description: Triggered when a quick access toolbar item is clicked
- Event Args: Clicked item information
- Use Case: Handle quick access item actions
- Example:
function handleQuickAccessToolbarItemClick(args: ClickEventArgs): void {
console.log('Quick access toolbar item clicked');
}
<ImageEditorComponent quickAccessToolbarItemClick={handleQuickAccessToolbarItemClick} />---
Enums and Type Definitions
Direction
Direction for flip operations:
Horizontal- Flip left-rightVertical- Flip top-bottom
ArrowheadType
Arrowhead style for arrow annotations:
None- No arrowheadSolidArrow- Solid arrowheadBarArrow- Bar arrowhead
RedactType
Type of redaction:
Blur- Blur sensitive contentPixelate- Pixelate sensitive content
FrameType
Frame decoration styles:
Mat- Matte frameBevel- Beveled frameLine- Line frameInset- Inset frameHook- Hook frame
ShapeType
Shape types for enabling/disabling:
Rectangle,Ellipse,Line,Arrow,Path,Text,Image,Freehand,RedactRectangle,RedactEllipse
ImageFinetuneOption
Fine-tune adjustment types:
Brightness- Adjust brightnessContrast- Adjust contrastSaturation- Adjust saturationHue- Adjust hueExposure- Adjust exposureBlur- Apply blur effectOpacity- Adjust opacity
Theme
Available themes:
Bootstrap5
ZoomTrigger
Zoom activation methods (can be combined with bitwise OR):
MouseWheel- Scroll to zoomPinch- Pinch gesture on touch devicesToolbar- Zoom buttonsCommands- Programmatic zoom via methods
---
Complete API Example
import { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';
import React, { useRef } from 'react';
function ImageEditorDemo() {
const imageEditorRef = useRef<ImageEditorComponent>(null);
const handleCreated = () => {
imageEditorRef.current?.open(
'https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png'
);
};
const handleRotate = () => {
imageEditorRef.current?.rotate(90);
};
const handleCrop = () => {
imageEditorRef.current?.select('16:9', 10, 10);
imageEditorRef.current?.crop();
};
const handleExport = () => {
imageEditorRef.current?.export('image/png', 'edited-image');
};
const handleAddText = () => {
const dimension = imageEditorRef.current?.getImageDimension();
imageEditorRef.current?.drawText(
dimension?.x || 100,
dimension?.y || 100,
'Sample Text',
'Arial',
20,
false,
false,
'#000000'
);
};
return (
<div>
<ImageEditorComponent
ref={imageEditorRef}
width="550px"
height="350px"
created={handleCreated}
toolbar={['Crop', 'ZoomIn', 'ZoomOut', 'Transform', 'Save', 'Reset']}
/>
<div>
<button onClick={handleRotate}>Rotate 90°</button>
<button onClick={handleCrop}>Crop 16:9</button>
<button onClick={handleAddText}>Add Text</button>
<button onClick={handleExport}>Export</button>
</div>
</div>
);
}
export default ImageEditorDemo;---
Related References
- Getting Started - Installation and basic setup
- Opening and Saving Images - File operations
- Selection and Cropping - Crop functionality
- Transform, Rotate, Flip - Image transformations
- Text Annotations - Adding text
- Shape Annotations - Drawing shapes
- Filters - Apply image filters
- Fine-Tuning - Color adjustments
- Accessibility and Localization - Accessibility features
Clear Image
Overview
The clearImage() method resets the Image Editor to a blank state, removing all images and clearing the canvas.
Clear Image
Basic Clear
function clearCurrentImage(): void {
imgObj.clearImage();
}With Confirmation
function clearWithConfirmation(): void {
if (window.confirm('Are you sure you want to clear the image? This action cannot be undone.')) {
imgObj.clearImage();
}
}Use Cases
Reset After Save
Clear image after exporting:
async function exportAndClear(): Promise<void> {
// Save image
imgObj.export('image/png', 'edited-image');
// Clear editor
imgObj.clearImage();
}Prepare for New Image
Clear before opening new file:
function openNewImage(imageUrl: string): void {
// Clear existing
imgObj.clearImage();
// Load new
imgObj.open(imageUrl);
}Undo All Changes
Reset to blank state:
function clearAllChanges(): void {
imgObj.clearImage();
}Advanced Patterns
Clear with Dialog Confirmation
function clearImageWithDialog(): void {
const userChoice = confirm(
'Clear current image?\n\nThis will remove all edits and annotations.'
);
if (userChoice) {
imgObj.clearImage();
logAction('Image cleared');
}
}Clear Specific Elements
// Clear all annotations but keep the image
function clearAnnotations(): void {
const shapes = imgObj.getShapeSettings();
shapes.forEach(shape => {
imgObj.deleteShape(shape.id);
});
}
// Clear specific shape types
function clearRectangles(): void {
const shapes = imgObj.getShapeSettings();
shapes
.filter(s => s.type === 'Rectangle')
.forEach(s => imgObj.deleteShape(s.id));
}Clear with Undo Support
function clearImageWithUndo(): void {
// Image Editor's undo will handle this
imgObj.clearImage();
// User can press Ctrl+Z to redo
}Batch Clear
function clearMultipleEditors(editors: ImageEditor[]): void {
editors.forEach(editor => {
editor.clearImage();
});
}Smart Clear with Shape Check
function smartClear(): void {
const shapes = imgObj.getShapeSettings();
if (shapes.length === 0) {
// Already empty
console.log('Nothing to clear');
return;
}
if (!confirm('Clear all content?')) {
return;
}
imgObj.clearImage();
}Clear with State Tracking
class EditorState {
private hasContent: boolean = false;
setContent(hasContent: boolean): void {
this.hasContent = hasContent;
}
clear(): void {
if (this.hasContent) {
imgObj.clearImage();
this.hasContent = false;
}
}
hasContent(): boolean {
return this.hasContent;
}
}
const state = new EditorState();
state.setContent(true);
state.clear();Dialog-Based Editor Pattern
interface DialogEditorConfig {
containerId: string;
dialogId: string;
reuseEditor: boolean;
}
function renderImageEditorDialog(config: DialogEditorConfig): void {
const dialogElement = document.getElementById(config.dialogId);
if (!dialogElement) return;
// Create or reuse editor instance
if (config.reuseEditor) {
// Clear existing content
imgObj.clearImage();
} else {
// Create new instance
// imgObj = new ImageEditor();
}
// Show dialog
if ('show' in dialogElement && typeof dialogElement.show === 'function') {
(dialogElement as any).show();
}
}
// Usage
const editorConfig: DialogEditorConfig = {
containerId: 'editor-container',
dialogId: 'editor-dialog',
reuseEditor: true
};
renderImageEditorDialog(editorConfig);Auto-Clear on Timer
function autoClearAfterDelay(delayMs: number = 300000): void {
// Auto-clear after 5 minutes of inactivity
let timeoutId: NodeJS.Timeout | null = null;
const resetTimer = (): void => {
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
if (confirm('Clear inactive editor?')) {
imgObj.clearImage();
}
}, delayMs);
};
document.addEventListener('mousemove', resetTimer);
document.addEventListener('keypress', resetTimer);
}Clear with Notification
function clearImageWithNotification(): void {
imgObj.clearImage();
// Notify user
showNotification({
type: 'info',
message: 'Image cleared',
duration: 3000
});
}
interface Notification {
type: 'info' | 'warning' | 'error' | 'success';
message: string;
duration: number;
}
function showNotification(notification: Notification): void {
const element = document.createElement('div');
element.className = `notification notification-${notification.type}`;
element.textContent = notification.message;
element.setAttribute('role', 'status');
element.setAttribute('aria-live', 'polite');
document.body.appendChild(element);
setTimeout(() => element.remove(), notification.duration);
}Conditional Clear
interface ClearConditions {
hasAnnotations: boolean;
hasShapes: boolean;
}
function getClearConditions(): ClearConditions {
const shapes = imgObj.getShapeSettings();
return {
hasAnnotations: shapes.length > 0,
hasShapes: shapes.length > 0
};
}
function conditionalClear(): void {
const conditions = getClearConditions();
if (conditions.hasAnnotations) {
if (confirm('Clear all annotations?')) {
imgObj.clearImage();
}
} else {
console.log('No annotations to clear');
}
}Clear with History Export
class EditorWithHistory {
private history: Array<{ timestamp: Date; action: string }> = [];
clear(): void {
this.history.push({
timestamp: new Date(),
action: 'Image cleared'
});
imgObj.clearImage();
}
exportHistory(): string {
return this.history
.map(entry => `${entry.timestamp.toISOString()}: ${entry.action}`)
.join('\n');
}
}
const editorWithHistory = new EditorWithHistory();
editorWithHistory.clear();
console.log(editorWithHistory.exportHistory());Filters
Available Filters
The Image Editor supports 6 predefined filters for instant visual effects:
| Filter | Effect | Use Case |
|---|---|---|
| Chrome | Metallic effect | Modern look |
| Cold | Blue tones | Winter/cool mood |
| Warm | Orange/yellow tones | Sunset/warm mood |
| Grayscale | Black & white | Professional/vintage |
| Sepia | Brown tones | Vintage/antique |
| Invert | Negative colors | X-ray effect |
Applying Filters
Apply Single Filter
import { ImageFilterOption } from '@syncfusion/ej2-react-image-editor';
function applyChrome(): void {
imgObj.applyImageFilter(ImageFilterOption.Chrome);
}
function applyCold(): void {
imgObj.applyImageFilter(ImageFilterOption.Cold);
}
function applyWarm(): void {
imgObj.applyImageFilter(ImageFilterOption.Warm);
}
function applyGrayscale(): void {
imgObj.applyImageFilter(ImageFilterOption.Grayscale);
}
function applySepia(): void {
imgObj.applyImageFilter(ImageFilterOption.Sepia);
}
function applyInvert(): void {
imgObj.applyImageFilter(ImageFilterOption.Invert);
}Filter Toolbar Integration
Add filter buttons to toolbar:
const toolbar = [
'Open',
'Filter',
'ZoomIn',
'ZoomOut',
{text: 'Chrome', prefixIcon: 'e-icons e-filter'},
{text: 'Sepia', prefixIcon: 'e-icons e-filter'},
'Save'
];
function toolbarItemClicked(args: any): void {
if (args.item.text === 'Chrome') {
imgObj.applyImageFilter(ImageFilterOption.Chrome);
} else if (args.item.text === 'Sepia') {
imgObj.applyImageFilter(ImageFilterOption.Sepia);
}
}
<ImageEditorComponent toolbar={toolbar} toolbarItemClicked={toolbarItemClicked} />Filter Effects Gallery
Chrome Effect
Modern metallic appearance:
function applyChromeEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Chrome);
}Cold Effect
Cool blue tone enhancement:
function applyColdEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Cold);
}Warm Effect
Warm orange/yellow tone:
function applyWarmEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Warm);
}Sepia Effect
Vintage brown tone:
function applySepiaEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Sepia);
}Grayscale Effect
Black and white conversion:
function applyGrayscaleEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Grayscale);
}Invert Effect
Negative/inverted colors:
function applyInvertEffect(): void {
imgObj.applyImageFilter(ImageFilterOption.Invert);
}Filter Events
Detect Filter Application
React to filter changes:
function imageFiltering(args: any): void {
console.log('Applying filter:', args.filter);
// args.cancel = true; // Prevent filter if needed
}
<ImageEditorComponent imageFiltering={imageFiltering} />Log Filter History
Track applied filters:
let filterHistory: string[] = [];
function imageFiltering(args: any): void {
filterHistory.push(args.filter);
console.log('Filter history:', filterHistory);
}Advanced Patterns
Filter Toggle
Apply and remove filters:
let currentFilter: string | null = null;
function toggleFilter(filter: ImageFilterOption): void {
if (currentFilter === filter) {
imgObj.reset(); // Remove filter
currentFilter = null;
} else {
if (currentFilter) {
imgObj.undo(); // Remove previous filter
}
imgObj.applyImageFilter(filter);
currentFilter = filter;
}
}Filter Preview
Show before/after comparison:
function previewFilter(filter: ImageFilterOption): void {
// Save original state
const originalImage = imgObj.getImageData();
// Apply filter
imgObj.applyImageFilter(filter);
// User can accept or undo
}Sequential Filters
Apply multiple filters in sequence:
function applyFilterSequence(): void {
imgObj.applyImageFilter(ImageFilterOption.Grayscale);
imgObj.applyImageFilter(ImageFilterOption.Cold);
}
// Result: Grayscale + Cold combinedUndo Filter
Remove last applied filter:
function undoFilter(): void {
imgObj.undo();
}Reset All Filters
Remove all effects:
function resetFilters(): void {
imgObj.reset();
}Filter with Fine-tuning
Combine filter with adjustments:
function enhancedSepia(): void {
// Apply sepia
imgObj.applyImageFilter(ImageFilterOption.Sepia);
// Fine-tune contrast
imgObj.finetuneImage(ImageFinetuneOption.Contrast, 20);
// Fine-tune saturation
imgObj.finetuneImage(ImageFinetuneOption.Saturation, 15);
}Dynamic Filter Selection
Filter selector UI:
function selectFilter(filterName: string): void {
const filterMap = {
'chrome': ImageFilterOption.Chrome,
'cold': ImageFilterOption.Cold,
'warm': ImageFilterOption.Warm,
'grayscale': ImageFilterOption.Grayscale,
'sepia': ImageFilterOption.Sepia,
'invert': ImageFilterOption.Invert
};
const filter = filterMap[filterName];
if (filter) {
imgObj.applyImageFilter(filter);
}
}
// Usage
selectFilter('sepia');Filter History Playback
Replay previous filters:
let appliedFilters: ImageFilterOption[] = [];
function recordAndApplyFilter(filter: ImageFilterOption): void {
appliedFilters.push(filter);
imgObj.applyImageFilter(filter);
}
function replayFilters(): void {
imgObj.reset();
appliedFilters.forEach(filter => {
imgObj.applyImageFilter(filter);
});
}Non-Destructive Filtering
Keep original with filter layer:
let hasFilter = false;
let filterApplied: ImageFilterOption | null = null;
function applyNonDestructive(filter: ImageFilterOption): void {
if (hasFilter && filterApplied) {
imgObj.undo();
}
imgObj.applyImageFilter(filter);
hasFilter = true;
filterApplied = filter;
}
function removeFilter(): void {
if (hasFilter) {
imgObj.undo();
hasFilter = false;
filterApplied = null;
}
}Fine-Tuning
Fine-Tune Options
Adjust image properties with precise control:
| Option | Range | Effect |
|---|---|---|
| Brightness | -100 to +100 | Light/dark intensity |
| Contrast | -100 to +100 | Tone separation |
| Saturation | -100 to +100 | Color intensity |
| Hue | -180 to +180 | Color shift |
| Exposure | -100 to +100 | Overall brightness |
| Blur | 0 to +100 | Blur intensity |
| Opacity | 0 to +100 | Transparency |
Adjusting Brightness
import { ImageFinetuneOption } from '@syncfusion/ej2-react-image-editor';
function increaseBrightness(): void {
imgObj.finetuneImage(ImageFinetuneOption.Brightness, 30);
}
function decreaseBrightness(): void {
imgObj.finetuneImage(ImageFinetuneOption.Brightness, -30);
}Adjusting Contrast
function increaseContrast(): void {
imgObj.finetuneImage(ImageFinetuneOption.Contrast, 40);
}
function decreaseContrast(): void {
imgObj.finetuneImage(ImageFinetuneOption.Contrast, -20);
}Adjusting Saturation
function increaseSaturation(): void {
imgObj.finetuneImage(ImageFinetuneOption.Saturation, 50);
}
function decreaseSaturation(): void {
imgObj.finetuneImage(ImageFinetuneOption.Saturation, -50);
}
// Full desaturation (grayscale)
function removeColor(): void {
imgObj.finetuneImage(ImageFinetuneOption.Saturation, -100);
}Adjusting Hue
Shift colors across the spectrum:
function shiftHueRed(): void {
imgObj.finetuneImage(ImageFinetuneOption.Hue, 30);
}
function shiftHueGreen(): void {
imgObj.finetuneImage(ImageFinetuneOption.Hue, 120);
}
function shiftHueBlue(): void {
imgObj.finetuneImage(ImageFinetuneOption.Hue, -60);
}Adjusting Exposure
Control overall brightness:
function increaseExposure(): void {
imgObj.finetuneImage(ImageFinetuneOption.Exposure, 40);
}
function decreaseExposure(): void {
imgObj.finetuneImage(ImageFinetuneOption.Exposure, -40);
}Adjusting Blur
Add blur effects:
function lightBlur(): void {
imgObj.finetuneImage(ImageFinetuneOption.Blur, 10);
}
function mediumBlur(): void {
imgObj.finetuneImage(ImageFinetuneOption.Blur, 30);
}
function heavyBlur(): void {
imgObj.finetuneImage(ImageFinetuneOption.Blur, 60);
}Adjusting Opacity
function makeTransparent(): void {
imgObj.finetuneImage(ImageFinetuneOption.Opacity, 50);
}
function makeOpaque(): void {
imgObj.finetuneImage(ImageFinetuneOption.Opacity, 100);
}Fine-Tune Events
Detect Fine-Tune Changes
function finetuneValueChanging(args: any): void {
console.log('Fine-tune type:', args.finetune);
console.log('Value:', args.value);
// args.cancel = true; // Prevent adjustment
}
<ImageEditorComponent finetuneValueChanging={finetuneValueChanging} />Advanced Patterns
Slider-Based Fine-Tuning
Connect slider to fine-tune value:
function createBrightnessSlider(): void {
const slider = document.getElementById('brightness-slider') as HTMLInputElement;
slider.addEventListener('input', (e) => {
const value = parseInt(e.target.value);
imgObj.finetuneImage(ImageFinetuneOption.Brightness, value);
});
}Multiple Adjustments
Apply several adjustments:
function enhanceImage(): void {
imgObj.finetuneImage(ImageFinetuneOption.Contrast, 20);
imgObj.finetuneImage(ImageFinetuneOption.Saturation, 30);
imgObj.finetuneImage(ImageFinetuneOption.Brightness, 15);
}Reset Specific Adjustment
Undo specific fine-tune:
function resetBrightness(): void {
imgObj.undo(); // Undo last adjustment
}
function resetAll(): void {
imgObj.reset(); // Reset all changes
}Preset Adjustments
Create adjustment presets:
const presets = {
vivid: [
{ option: ImageFinetuneOption.Saturation, value: 40 },
{ option: ImageFinetuneOption.Contrast, value: 20 }
],
muted: [
{ option: ImageFinetuneOption.Saturation, value: -30 },
{ option: ImageFinetuneOption.Brightness, value: 10 }
],
vintage: [
{ option: ImageFinetuneOption.Hue, value: -20 },
{ option: ImageFinetuneOption.Saturation, value: -20 },
{ option: ImageFinetuneOption.Brightness, value: 5 }
]
};
function applyPreset(presetName: string): void {
presets[presetName].forEach(adj => {
imgObj.finetuneImage(adj.option, adj.value);
});
}
// Usage
applyPreset('vivid');Real-Time Preview
Live adjustment preview:
let adjustmentValue = 0;
function liveAdjust(option: ImageFinetuneOption, value: number): void {
// Cancel previous and apply new
imgObj.undo();
imgObj.finetuneImage(option, value);
adjustmentValue = value;
}
// On slider input
slider.addEventListener('input', (e) => {
liveAdjust(ImageFinetuneOption.Contrast, parseInt(e.target.value));
});Conditional Fine-Tuning
Apply adjustments based on conditions:
function smartEnhance(): void {
const dim = imgObj.getImageDimension();
// If image is large, reduce blur
if (dim.width > 800) {
imgObj.finetuneImage(ImageFinetuneOption.Blur, 5);
} else {
imgObj.finetuneImage(ImageFinetuneOption.Blur, 10);
}
// Always increase contrast
imgObj.finetuneImage(ImageFinetuneOption.Contrast, 15);
}Undo/Redo with Fine-Tuning
let adjustmentHistory: any[] = [];
function recordAdjustment(option: ImageFinetuneOption, value: number): void {
adjustmentHistory.push({ option, value });
imgObj.finetuneImage(option, value);
}
function undoAdjustment(): void {
imgObj.undo();
adjustmentHistory.pop();
}
function redoAdjustment(): void {
imgObj.redo();
adjustmentHistory.push(adjustmentHistory[adjustmentHistory.length - 1]);
}Combined Filter + Fine-Tune
Perfect professional editing workflow:
function professionalEnhancement(): void {
// Apply sepia filter
imgObj.applyImageFilter(ImageFilterOption.Sepia);
// Fine-tune for better result
imgObj.finetuneImage(ImageFinetuneOption.Contrast, 10);
imgObj.finetuneImage(ImageFinetuneOption.Saturation, 5);
imgObj.finetuneImage(ImageFinetuneOption.Brightness, -5);
}Batch Fine-Tuning
Apply list of adjustments:
function batchFinetuneImage(adjustments: Array<{option: ImageFinetuneOption, value: number}>): void {
adjustments.forEach(adj => {
imgObj.finetuneImage(adj.option, adj.value);
});
}
// Usage
batchFinetuneImage([
{ option: ImageFinetuneOption.Brightness, value: 20 },
{ option: ImageFinetuneOption.Contrast, value: 15 },
{ option: ImageFinetuneOption.Saturation, value: 25 }
]);Fit to Width and Height
Table of Contents
Fit to Width
Zoom to Fit Width
Scale image to fit container width:
function fitToWidth(): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const scale = containerWidth / dim.width;
imgObj.zoom(scale);
}Calculate Width Zoom
function calculateZoomForWidth(containerWidth: number, imageWidth: number): number {
const padding = 20; // Account for padding/margins
const availableWidth = containerWidth - padding;
return availableWidth / imageWidth;
}
// Usage
const zoom = calculateZoomForWidth(800, 1200);
imgObj.zoom(zoom);Fit with Padding
function fitToWidthWithPadding(paddingPercent: number = 10): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const availableWidth = containerWidth * (1 - paddingPercent / 100);
const scale = availableWidth / dim.width;
imgObj.zoom(scale);
}
// Fit with 10% padding
fitToWidthWithPadding(10);Fit to Height
Zoom to Fit Height
Scale image to fit container height:
function fitToHeight(): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerHeight = container.clientHeight;
const scale = containerHeight / dim.height;
imgObj.zoom(scale);
}Calculate Height Zoom
function calculateZoomForHeight(containerHeight: number, imageHeight: number): number {
const padding = 20;
const availableHeight = containerHeight - padding;
return availableHeight / imageHeight;
}
// Usage
const zoom = calculateZoomForHeight(600, 1600);
imgObj.zoom(zoom);Fit with Padding
function fitToHeightWithPadding(paddingPercent: number = 10): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerHeight = container.clientHeight;
const availableHeight = containerHeight * (1 - paddingPercent / 100);
const scale = availableHeight / dim.height;
imgObj.zoom(scale);
}
// Fit with 10% padding
fitToHeightWithPadding(10);Fit to Viewport
Fit Best (Contain)
Scale to fit entire image in view:
function fitBest(): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
const widthScale = containerWidth / dim.width;
const heightScale = containerHeight / dim.height;
const scale = Math.min(widthScale, heightScale);
imgObj.zoom(scale);
}Fit to Cover
Scale to cover entire viewport:
function fitCover(): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
const widthScale = containerWidth / dim.width;
const heightScale = containerHeight / dim.height;
const scale = Math.max(widthScale, heightScale);
imgObj.zoom(scale);
}Fit Exact
Fill viewport exactly (may distort):
function fitExact(): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
imgObj.zoom(containerWidth / dim.width);
imgObj.zoom(containerHeight / dim.height);
}Smart Zoom Patterns
Auto Zoom on Load
const handleImageOpened = (): void => {
// Auto-fit on load
fitBest();
};
const imageEditor = (
<ImageEditorComponent fileOpened={handleImageOpened} />
);Responsive Fit
function setupResponsiveFit(): void {
const resizeObserver = new ResizeObserver(() => {
fitBest();
});
const container = document.querySelector('.editor-container');
if (container) {
resizeObserver.observe(container);
}
}
// Usage on component mount
useEffect(() => {
setupResponsiveFit();
}, []);Orientation-Based Fit
function fitByOrientation(): void {
const dim = imgObj.getImageDimension();
const isPortrait = dim.height > dim.width;
if (isPortrait) {
fitToHeight();
} else {
fitToWidth();
}
}Zoom with Constraints
interface ZoomConstraints {
minZoom: number;
maxZoom: number;
}
function fitWithConstraints(scale: number, constraints: ZoomConstraints): void {
const constrainedScale = Math.max(
constraints.minZoom,
Math.min(scale, constraints.maxZoom)
);
imgObj.zoom(constrainedScale);
}
// Usage
const constraints: ZoomConstraints = { minZoom: 0.1, maxZoom: 3 };
fitWithConstraints(1.5, constraints);Fit to Specific Aspect Ratio
function fitToAspectRatio(targetAspect: number): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
const containerAspect = containerWidth / containerHeight;
let scale: number;
if (containerAspect > targetAspect) {
// Container wider
scale = containerHeight / dim.height;
} else {
// Container taller
scale = containerWidth / dim.width;
}
imgObj.zoom(scale);
}
// Fit to 16:9
fitToAspectRatio(16 / 9);Fit with Animation
function fitWithAnimation(targetScale: number, duration: number = 500): void {
const startScale = imgObj.zoom();
const startTime = Date.now();
function animate(): void {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function
const eased = progress < 0.5
? 2 * progress * progress
: -1 + (4 - 2 * progress) * progress;
const currentScale = startScale + (targetScale - startScale) * eased;
imgObj.zoom(currentScale);
if (progress < 1) {
requestAnimationFrame(animate);
}
}
animate();
}
// Usage
fitWithAnimation(1.5, 500);Fit with Transition
function fitWithTransition(action: () => void, duration: number = 300): void {
const editor = document.querySelector('.editor-container');
if (editor) {
(editor as HTMLElement).style.transition = `transform ${duration}ms ease-in-out`;
}
action();
setTimeout(() => {
if (editor) {
(editor as HTMLElement).style.transition = '';
}
}, duration);
}
// Usage
fitWithTransition(() => fitBest(), 300);Smart Fit Strategy
enum FitStrategy {
Auto = 'auto',
Width = 'width',
Height = 'height',
Contain = 'contain'
}
function smartFit(strategy: FitStrategy = FitStrategy.Auto): void {
const dim = imgObj.getImageDimension();
const container = document.querySelector('.editor-container');
if (!container) return;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
switch (strategy) {
case FitStrategy.Width:
fitToWidth();
break;
case FitStrategy.Height:
fitToHeight();
break;
case FitStrategy.Contain:
fitBest();
break;
case FitStrategy.Auto:
// Auto-select best strategy
const isPortrait = dim.height > dim.width;
const isLandscape = dim.width > dim.height;
if (isPortrait) {
fitToHeight();
} else if (isLandscape) {
fitToWidth();
} else {
fitBest();
}
break;
}
}
// Usage
smartFit(FitStrategy.Auto);Keyboard Shortcuts for Fit
const fitKeyboardShortcuts: Record<string, () => void> = {
'f': fitBest,
'w': fitToWidth,
'h': fitToHeight,
'c': fitCover
};
document.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.altKey && fitKeyboardShortcuts[e.key]) {
e.preventDefault();
fitKeyboardShortcuts[e.key]();
}
});Fit with Toolbar Integration
const customToolbar = [
'Open',
'Save',
{
id: 'fit-width',
text: 'Fit Width',
tooltipText: 'Fit to Width'
},
{
id: 'fit-height',
text: 'Fit Height',
tooltipText: 'Fit to Height'
},
{
id: 'fit-best',
text: 'Fit Best',
tooltipText: 'Fit Best'
}
];
const handleToolbarClick = (args: any): void => {
switch (args.id) {
case 'fit-width':
fitToWidth();
break;
case 'fit-height':
fitToHeight();
break;
case 'fit-best':
fitBest();
break;
}
};
const imageEditor = (
<ImageEditorComponent
toolbar={customToolbar}
toolbarItemClick={handleToolbarClick}
/>
);Frame Decoration
Table of Contents
Frame Types
The Image Editor supports 5 frame types:
| Frame Type | Description | Use Case |
|---|---|---|
| Mat | Solid border with inner bevel | Professional photos |
| Bevel | 3D beveled border | Formal documents |
| Line | Simple line border | Minimalist design |
| Inset | Pressed/embedded appearance | Classic photos |
| Hook | Decorative hook-style frame | Artistic images |
Apply Frame
Mat Frame
Classic solid border:
import { FrameType } from '@syncfusion/ej2-react-image-editor';
function applyMatFrame(): void {
imgObj.drawFrame(
FrameType.Mat,
'#CCCCCC', // Color
'', // gradientColor
20 // size as percentage
);
}Bevel Frame
3D beveled effect:
import { FrameType } from '@syncfusion/ej2-react-image-editor';
function applyBevelFrame(): void {
imgObj.drawFrame(
FrameType.Bevel,
'#999999',
'',
15
);
}Line Frame
Simple border:
import { FrameType } from '@syncfusion/ej2-react-image-editor';
function applyLineFrame(): void {
imgObj.drawFrame(
FrameType.Line,
'#000000',
'',
10
);
}Inset Frame
Embedded appearance:
import { FrameType } from '@syncfusion/ej2-react-image-editor';
function applyInsetFrame(): void {
imgObj.drawFrame(
FrameType.Inset,
'#666666',
'',
15
);
}Hook Frame
Decorative frame:
import { FrameType } from '@syncfusion/ej2-react-image-editor';
function applyHookFrame(): void {
imgObj.drawFrame(
FrameType.Hook,
'#8B7355',
'',
20
);
}Frame Customization
Custom Frame Width
Control frame thickness:
function applyCustomFrame(frameType: FrameType, width: number, color: string): void {
imgObj.drawFrame(frameType, color, '', width);
}
// Thin frame
applyCustomFrame(FrameType.Mat, 10, '#CCCCCC');
// Thick frame
applyCustomFrame(FrameType.Bevel, 80, '#999999');
// Extra thick frame
applyCustomFrame(FrameType.Hook, 100, '#8B7355');Custom Frame Color
Select frame color:
const frameColors = {
light: '#EEEEEE',
medium: '#CCCCCC',
dark: '#666666',
gold: '#FFD700',
silver: '#C0C0C0',
wood: '#8B4513'
};
function applyColoredFrame(colorName: keyof typeof frameColors): void {
imgObj.drawFrame(
FrameType.Mat,
frameColors[colorName],
'',
40
);
}
// Apply gold frame
applyColoredFrame('gold');Dynamic Frame Properties
interface FrameConfig {
type: FrameType;
width: number;
color: string;
}
function applyDynamicFrame(config: FrameConfig): void {
imgObj.drawFrame(config.type, config.width, config.color);
}
// Usage
const config: FrameConfig = {
type: FrameType.Bevel,
width: 50,
color: '#C0C0C0'
};
applyDynamicFrame(config);Frame Events
Capturing Frame Events
const handleFrameDrawing = (args: any): void => {
console.log('Frame applied:', {
type: args.frameType,
width: args.width,
color: args.color
});
};
const imageEditor = (
<ImageEditorComponent
onFrameChange={handleFrameDrawing}
/>
);Before Frame Application
const handleBeforeFrame = (args: any): void => {
// Validate or modify frame before applying
if (args.width > 100) {
console.warn('Frame width exceeds maximum');
args.cancel = true;
}
};Advanced Patterns
Frame Presets
interface FramePreset {
name: string;
type: FrameType;
width: number;
color: string;
}
const framePresets: FramePreset[] = [
{
name: 'Classic',
type: FrameType.Mat,
width: 30,
color: '#8B8B8B'
},
{
name: 'Elegant',
type: FrameType.Bevel,
width: 40,
color: '#C0C0C0'
},
{
name: 'Modern',
type: FrameType.Line,
width: 10,
color: '#000000'
},
{
name: 'Vintage',
type: FrameType.Hook,
width: 50,
color: '#8B7355'
},
{
name: 'Minimal',
type: FrameType.Line,
width: 5,
color: '#CCCCCC'
}
];
function applyFramePreset(presetName: string): void {
const preset = framePresets.find(p => p.name === presetName);
if (preset) {
imgObj.drawFrame(preset.type, preset.color, '', preset.width);
}
}
// Usage
applyFramePreset('Elegant');Frame by Use Case
enum ImageCategory {
Portrait = 'portrait',
Landscape = 'landscape',
Square = 'square',
Document = 'document'
}
function getAppropriateFrame(category: ImageCategory): FramePreset {
const frameMap: { [key in ImageCategory]: FramePreset } = {
[ImageCategory.Portrait]: {
name: 'Portrait',
type: FrameType.Bevel,
width: 35,
color: '#8B7355'
},
[ImageCategory.Landscape]: {
name: 'Landscape',
type: FrameType.Mat,
width: 30,
color: '#C0C0C0'
},
[ImageCategory.Square]: {
name: 'Square',
type: FrameType.Hook,
width: 40,
color: '#FFD700'
},
[ImageCategory.Document]: {
name: 'Document',
type: FrameType.Line,
width: 10,
color: '#000000'
}
};
return frameMap[category];
}
function autoSelectFrame(): void {
const dim = imgObj.getImageDimension();
let category: ImageCategory;
if (dim.width > dim.height) {
category = ImageCategory.Landscape;
} else if (dim.height > dim.width) {
category = ImageCategory.Portrait;
} else {
category = ImageCategory.Square;
}
const frame = getAppropriateFrame(category);
imgObj.drawFrame(frame.type, frame.width, frame.color);
}Responsive Frame Width
Adjust frame based on image size:
function applyResponsiveFrame(baseWidth: number): void {
const dim = imgObj.getImageDimension();
// Scale frame width proportionally to image size
const scale = Math.min(dim.width, dim.height) / 1000;
const scaledWidth = Math.round(baseWidth * scale);
imgObj.drawFrame(FrameType.Mat, '#CCCCCC', '', scaledWidth);
}
// Frame scales with image size
applyResponsiveFrame(50);Frame with Color Palette
interface ColorPalette {
light: string;
medium: string;
dark: string;
accent: string;
}
const palettes: { [key: string]: ColorPalette } = {
warm: {
light: '#FFE4C4',
medium: '#D2691E',
dark: '#8B4513',
accent: '#FF8C00'
},
cool: {
light: '#ADD8E6',
medium: '#4682B4',
dark: '#191970',
accent: '#00CED1'
},
neutral: {
light: '#E8E8E8',
medium: '#808080',
dark: '#2F2F2F',
accent: '#C0C0C0'
}
};
function applyPaletteFrame(paletteName: string, toneLevel: 'light' | 'medium' | 'dark'): void {
const palette = palettes[paletteName];
if (palette) {
imgObj.drawFrame(FrameType.Mat, palette[toneLevel], '', 35);
}
}
// Usage
applyPaletteFrame('warm', 'dark');Frame Combination
function applyDoubleFrame(): void {
// Apply outer frame
imgObj.drawFrame(FrameType.Bevel, '#8B7355', '', 40);
// Inner frame effect would require additional processing
}
function applyStyledFrame(thickness: number, style: 'solid' | 'decorative' | 'modern'): void {
const styleConfig = {
solid: { type: FrameType.Mat, color: '#808080' },
decorative: { type: FrameType.Hook, color: '#8B7355' },
modern: { type: FrameType.Line, color: '#000000' }
};
const config = styleConfig[style];
imgObj.drawFrame(config.type, thickness, config.color);
}
// Usage
applyStyledFrame(30, 'decorative');Frame Styles by Context
interface FrameContext {
purpose: 'web' | 'print' | 'social' | 'gallery';
mood: 'professional' | 'casual' | 'artistic' | 'vintage';
}
function selectFrameByContext(context: FrameContext): void {
const contextFrames: { [key: string]: FramePreset } = {
'web-professional': {
name: 'Web Pro',
type: FrameType.Line,
width: 5,
color: '#000000'
},
'print-artistic': {
name: 'Print Art',
type: FrameType.Hook,
width: 60,
color: '#8B7355'
},
'social-casual': {
name: 'Social',
type: FrameType.Mat,
width: 20,
color: '#FFD700'
},
'gallery-vintage': {
name: 'Gallery',
type: FrameType.Bevel,
width: 50,
color: '#CD853F'
}
};
const key = `${context.purpose}-${context.mood}`;
const frame = contextFrames[key];
if (frame) {
imgObj.drawFrame(frame.type, frame.width, frame.color);
}
}
// Usage
selectFrameByContext({
purpose: 'print',
mood: 'artistic'
});Frame Undo/Redo Integration
let appliedFrames: FramePreset[] = [];
function applyFrameWithHistory(preset: FramePreset): void {
appliedFrames.push(preset);
imgObj.drawFrame(preset.type, preset.width, preset.color);
}
function undoFrame(): void {
if (appliedFrames.length > 0) {
appliedFrames.pop();
imgObj.undo();
}
}
function redoFrame(): void {
if (appliedFrames.length > 0) {
const frame = appliedFrames[appliedFrames.length - 1];
imgObj.drawFrame(frame.type, frame.width, frame.color);
}
}Freehand Drawing
Table of Contents
Enable Freehand Drawing
Start Drawing
Enable freehand drawing mode:
function startDrawing(): void {
imgObj.freeHandDraw(true);
}Stop Drawing
Disable freehand drawing mode:
function stopDrawing(): void {
imgObj.freeHandDraw(false);
}Toggle Drawing Mode
Switch drawing on/off:
let drawingEnabled = false;
function toggleDrawing(): void {
drawingEnabled = !drawingEnabled;
imgObj.freeHandDraw(drawingEnabled);
}Stroke Customization
Customize Stroke via Event
Modify stroke properties when drawing:
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
args.currentShapeSettings.strokeColor = 'red';
args.currentShapeSettings.strokeWidth = 5;
}
}
<ImageEditorComponent shapeChanging={shapeChanging} />Change Stroke Color
Set custom stroke color for drawings:
function drawWithRedStroke(): void {
const customStroke = { strokeColor: 'red' };
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
args.currentShapeSettings.strokeColor = customStroke.strokeColor;
}
}
imgObj.freeHandDraw(true);
}Change Stroke Width
Adjust line thickness:
let strokeWidth = 2;
function increaseStroke(): void {
strokeWidth += 1;
}
function decreaseStroke(): void {
if (strokeWidth > 1) {
strokeWidth -= 1;
}
}
function applyStroke(): void {
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
args.currentShapeSettings.strokeWidth = strokeWidth;
}
}
}Multiple Stroke Presets
Offer predefined stroke styles:
const strokePresets = {
thin: { color: 'black', width: 1 },
normal: { color: 'black', width: 3 },
bold: { color: 'black', width: 5 },
highlight: { color: 'yellow', width: 8 }
};
function applyStrokePreset(preset: string): void {
const style = strokePresets[preset];
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
args.currentShapeSettings.strokeColor = style.color;
args.currentShapeSettings.strokeWidth = style.width;
}
}
imgObj.freeHandDraw(true);
}Managing Drawings
Get All Drawings
Retrieve all freehand drawing annotations:
function getAllDrawings(): void {
const shapes = imgObj.getShapeSettings();
const drawings = shapes.filter(s => s.type === 'FreehandDraw');
console.log('Freehand drawings:', drawings);
}Delete Drawing
Remove freehand annotation by shape ID:
function deleteDrawing(): void {
imgObj.deleteShape('pen_1');
}Delete Last Drawing
Remove the most recently added drawing:
function deleteLastDrawing(): void {
const shapes = imgObj.getShapeSettings();
if (shapes.length > 0) {
const lastDrawing = shapes[shapes.length - 1];
if (lastDrawing.type === 'FreehandDraw') {
imgObj.deleteShape(lastDrawing.id);
}
}
}Clear All Drawings
Delete all freehand annotations:
function clearAllDrawings(): void {
const shapes = imgObj.getShapeSettings();
shapes
.filter(s => s.type === 'FreehandDraw')
.forEach(s => imgObj.deleteShape(s.id));
}Select Specific Drawing
Highlight a drawing for editing:
function selectDrawing(drawingId: string): void {
const shapes = imgObj.getShapeSettings();
const drawing = shapes.find(s => s.id === drawingId);
if (drawing) {
drawing.isSelected = true;
imgObj.updateShape(drawing);
}
}Drawing Events
Shape Changing Event
React to drawing modifications:
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
console.log('Drawing stroke color:', args.currentShapeSettings.strokeColor);
console.log('Drawing stroke width:', args.currentShapeSettings.strokeWidth);
}
}
<ImageEditorComponent shapeChanging={shapeChanging} />Track Drawing Count
Monitor number of active drawings:
let drawingCount = 0;
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw' && args.action === 'insert') {
drawingCount++;
console.log(`Drawing #${drawingCount} created`);
}
}Advanced Patterns
Artistic Styles
Apply different artistic styles to drawings:
const artisticStyles = {
sketch: { color: '#444', width: 2, opacity: 0.7 },
marker: { color: '#FF6B6B', width: 6, opacity: 0.8 },
pen: { color: '#000', width: 1, opacity: 1 }
};
function applyArtisticStyle(style: string): void {
const styleConfig = artisticStyles[style];
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
args.currentShapeSettings.strokeColor = styleConfig.color;
args.currentShapeSettings.strokeWidth = styleConfig.width;
}
}
imgObj.freeHandDraw(true);
}Annotate and Markup Workflow
Combined drawing and text annotation:
function markupImage(): void {
// Add text label
const dimension = imgObj.getImageDimension();
imgObj.drawText(dimension.x + 20, dimension.y + 20, 'Review:');
// Enable drawing for marks
imgObj.freeHandDraw(true);
}
function completeMarkup(): void {
imgObj.freeHandDraw(false);
// Get all annotations
const shapes = imgObj.getShapeSettings();
console.log('Marked up image with', shapes.length, 'annotations');
}Drawing History
Track drawings in undo/redo stack:
function undoLastDrawing(): void {
imgObj.undo(); // Undo last drawing
}
function redoLastDrawing(): void {
imgObj.redo(); // Redo last drawing
}Conditional Drawing
Allow drawing only under certain conditions:
let allowDrawing = false;
function enableDrawingMode(): void {
allowDrawing = true;
imgObj.freeHandDraw(true);
}
function disableDrawingMode(): void {
allowDrawing = false;
imgObj.freeHandDraw(false);
}
function shapeChanging(args: any): void {
if (!allowDrawing && args.currentShapeSettings.type === 'FreehandDraw') {
args.cancel = true;
}
}Export Drawings as Data
Save drawing data for later use:
function exportDrawings(): void {
const shapes = imgObj.getShapeSettings();
const drawings = shapes
.filter(s => s.type === 'FreehandDraw')
.map(d => ({
id: d.id,
stroke: d.strokeColor,
width: d.strokeWidth
}));
const json = JSON.stringify(drawings);
localStorage.setItem('drawings', json);
}
function importDrawings(): void {
const json = localStorage.getItem('drawings');
if (json) {
const drawings = JSON.parse(json);
console.log('Available drawings:', drawings);
}
}Drawing Constraints
Limit drawing to specific areas:
let drawingArea = { x: 50, y: 50, width: 400, height: 300 };
function shapeChanging(args: any): void {
if (args.currentShapeSettings.type === 'FreehandDraw') {
// Check if drawing is within bounds
const shape = args.currentShapeSettings;
if (shape.x! < drawingArea.x || shape.x! > drawingArea.x + drawingArea.width) {
args.cancel = true;
}
}
}Getting Started with Image Editor
Table of Contents
Installation
The Syncfusion React Image Editor is available as an npm package. Install it using your preferred package manager.
Using npm
npm install @syncfusion/ej2-react-image-editor --saveVite Setup
Create a new React application with Vite for faster development:
npm create vite@latest my-app -- --template react
cd my-app
npm run devThen install the Image Editor package:
npm install @syncfusion/ej2-react-image-editor --saveCSS Setup
Add the required CSS files to your src/App.css for styling the Image Editor and its dependencies:
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-image-editor/styles/tailwind3.css";Import this CSS file in your App.tsx:
import './App.css';Basic Component
Here's a minimal setup for the Image Editor:
import { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';
import React from 'react';
import './App.css';
function App() {
return (
<div id="container">
<ImageEditorComponent width="550px" height="350px" />
</div>
);
}
export default App;Initialization
To initialize the Image Editor with an image on component creation, use the created event:
import { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';
import { Browser } from '@syncfusion/ej2-base';
import React from 'react';
import './App.css';
function App() {
let imgObj: ImageEditorComponent;
function imageEditorCreated(): void {
// Detect device and load appropriate image
if (Browser.isDevice) {
imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/flower.jpeg');
} else {
imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/bridge.jpeg');
}
}
return (
<div id="container">
<ImageEditorComponent
ref={(img) => { imgObj = img }}
width="550px"
height="350px"
created={imageEditorCreated}
/>
</div>
);
}
export default App;Running the Application
Start your development server:
npm run devThe application will compile and serve at http://localhost:5173 (for Vite).
Key Properties in Setup
| Property | Purpose |
|---|---|
width | Sets the canvas width (e.g., "550px", "100%") |
height | Sets the canvas height (e.g., "350px", "100%") |
toolbar | Customize toolbar items (default: all built-in items) |
created | Event fired when component is ready |
ref | Access component instance for method calls |
Next Steps
- Open images using the opening-saving-images.md reference
- Apply transformations with transform-rotate-flip.md
- Add annotations with text-annotations.md, shape-annotations.md, or freehand-drawing.md
Image Annotations
Adding Image Annotations
Basic Image Annotation
Insert an image as annotation:
function addImage(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://ej2.syncfusion.com/react/documentation/image-editor/images/flower.jpeg',
dimension.x,
dimension.y,
100, // width
80 // height
);
}Image with Aspect Ratio
Maintain aspect ratio when adding image:
function addImageWithAspectRatio(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/logo.png',
dimension.x + 50,
dimension.y + 50,
100,
80,
true // isAspectRatio - maintains aspect ratio
);
}Rotated Image Annotation
Add image rotated by degrees:
function addRotatedImage(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/icon.png',
dimension.x + 100,
dimension.y + 100,
80,
80,
true, // aspect ratio
45 // degree rotation
);
}Image with Opacity
Add semi-transparent image:
function addTransparentImage(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/watermark.png',
dimension.x,
dimension.y,
150,
100,
true,
0,
0.5 // opacity (0-1, where 0.5 is 50% transparent)
);
}Image as Selected Annotation
Add image in selected state:
function addSelectedImage(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/image.jpg',
dimension.x,
dimension.y,
100,
100,
true,
0,
1,
true // isSelected - shows selection handles
);
}Image Watermarks
Add Watermark Logo
Place watermark at specific location:
function addWatermark(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/company-logo.png',
dimension.x + dimension.width - 120,
dimension.y + dimension.height - 80,
100,
60,
true,
0,
0.6 // Semi-transparent watermark
);
}Center Watermark
Center watermark on image:
function addCenterWatermark(): void {
const dimension = imgObj.getImageDimension();
const centerX = dimension.x + dimension.width / 2 - 50;
const centerY = dimension.y + dimension.height / 2 - 40;
imgObj.drawImage(
'https://example.com/watermark.png',
centerX,
centerY,
100,
80,
true,
0,
0.4
);
}Copyright Badge
Add copyright image in corner:
function addCopyrightBadge(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/copyright-badge.png',
dimension.x + 10,
dimension.y + dimension.height - 50,
40,
40,
true,
0,
0.8
);
}Managing Image Annotations
Get All Image Annotations
Retrieve all image annotations:
function getAllImages(): void {
const shapes = imgObj.getShapeSettings();
const images = shapes.filter(s => s.type === 'Image');
console.log('Image annotations:', images);
}Delete Image Annotation
Remove image by shape ID:
function deleteImage(shapeId: string): void {
imgObj.deleteShape(shapeId);
}
// Usage
const shapes = imgObj.getShapeSettings();
if (shapes.length > 0) {
deleteImage(shapes[0].id);
}Delete All Images
Remove all image annotations:
function deleteAllImages(): void {
const shapes = imgObj.getShapeSettings();
shapes
.filter(s => s.type === 'Image')
.forEach(s => imgObj.deleteShape(s.id));
}Update Image Properties
Modify existing image annotation:
function updateImageOpacity(shapeId: string, opacity: number): void {
const shapes = imgObj.getShapeSettings();
const imageShape = shapes.find(s => s.id === shapeId && s.type === 'Image');
if (imageShape) {
imageShape.opacity = opacity;
imgObj.updateShape(imageShape);
}
}
// Usage
updateImageOpacity('shape_1', 0.3);Advanced Patterns
Multiple Watermarks
Layer multiple watermarks:
function addMultipleWatermarks(): void {
const dimension = imgObj.getImageDimension();
// Top-left logo
imgObj.drawImage(
'https://example.com/logo1.png',
dimension.x + 10,
dimension.y + 10,
80,
60,
true,
0,
0.5
);
// Bottom-right watermark
imgObj.drawImage(
'https://example.com/watermark.png',
dimension.x + dimension.width - 110,
dimension.y + dimension.height - 70,
100,
60,
true,
0,
0.4
);
// Center watermark
imgObj.drawImage(
'https://example.com/center-mark.png',
dimension.x + dimension.width / 2 - 50,
dimension.y + dimension.height / 2 - 40,
100,
80,
true,
0,
0.2
);
}Branded Overlay
Add branded image overlay:
function addBrandedOverlay(): void {
const dimension = imgObj.getImageDimension();
// Brand bar
imgObj.drawRectangle(
dimension.x,
dimension.y,
dimension.width,
60,
0,
'transparent',
'#F0F0F0'
);
// Brand logo
imgObj.drawImage(
'https://example.com/brand-logo.png',
dimension.x + 10,
dimension.y + 10,
40,
40,
true
);
}Rotated Logo Annotation
Combine rotation with positioning:
function addRotatedLogo(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawImage(
'https://example.com/logo.png',
dimension.x + dimension.width / 2,
dimension.y + dimension.height / 2,
120,
120,
true,
45, // 45-degree rotation
0.6
);
}Icon Annotation
Small icon with label:
function addIconWithLabel(): void {
const dimension = imgObj.getImageDimension();
// Icon
imgObj.drawImage(
'https://example.com/icon.png',
dimension.x + 200,
dimension.y + 100,
40,
40,
true
);
// Text label
imgObj.drawText(
dimension.x + 250,
dimension.y + 110,
'Featured',
'Arial',
12
);
}Thumbnail Annotation
Add thumbnail image for reference:
function addThumbnail(): void {
const dimension = imgObj.getImageDimension();
imgObj.drawRectangle(
dimension.x + dimension.width - 110,
dimension.y + 10,
100,
75,
2,
'black',
'white'
);
imgObj.drawImage(
'https://example.com/thumbnail.jpg',
dimension.x + dimension.width - 105,
dimension.y + 15,
90,
65,
true
);
}Duplicate Image Annotation
Clone existing image:
function duplicateImage(shapeId: string): void {
const shapes = imgObj.getShapeSettings();
const original = shapes.find(s => s.id === shapeId && s.type === 'Image');
if (original) {
// Create a copy offset from the original
imgObj.drawImage(
original.src || '',
(original.x || 0) + 20,
(original.y || 0) + 20,
original.width || 100,
original.height || 100,
true,
original.degree || 0,
original.opacity || 1
);
}
}Scale Image Annotation
Resize existing image:
function scaleImage(shapeId: string, factor: number): void {
// Use updateShape to modify image dimensions
// Get current shape first
const shape = imgObj.getShapeSetting(shapeId);
if (shape && shape.type === 'Image') {
// Calculate new dimensions
const currentWidth = shape.width || 100;
const currentHeight = shape.height || 100;
const newWidth = currentWidth * factor;
const newHeight = currentHeight * factor;
// Update via API
imgObj.updateShape(shapeId, {
width: newWidth,
height: newHeight
});
}
}
// Usage
scaleImage('shape_1', 1.5); // Scale to 150%Image Restrictions and Validation
Table of Contents
- File Type Restrictions
- Size Restrictions
- Dimension Restrictions
- Validation
- Error Handling
- Advanced Patterns
File Type Restrictions
Allowed Image Formats
const allowedFormats = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'];
function isValidFormat(filename: string): boolean {
const extension = filename.split('.').pop()?.toLowerCase();
return allowedFormats.includes(extension || '');
}
// Usage
if (isValidFormat('photo.jpg')) {
// Proceed with image
}File Extension Validation
const fileTypeRestrictions = {
'jpg': true,
'jpeg': true,
'png': true,
'gif': true,
'bmp': true,
'svg': true,
'webp': true
};
function validateFileExtension(file: File): boolean {
const extension = file.name.split('.').pop()?.toLowerCase();
return extension ? fileTypeRestrictions[extension as keyof typeof fileTypeRestrictions] : false;
}
// Usage
const fileInput = document.querySelector('input[type="file"]');
if (fileInput) {
fileInput.addEventListener('change', (e: Event) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file && !validateFileExtension(file)) {
alert('Invalid file format. Please use JPG, PNG, GIF, BMP, or WebP');
}
});
}MIME Type Validation
function validateMimeType(file: File): boolean {
const validMimeTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/bmp',
'image/svg+xml',
'image/webp'
];
return validMimeTypes.includes(file.type);
}
// Usage
const file = new File([''], 'image.jpg', { type: 'image/jpeg' });
if (validateMimeType(file)) {
// File is valid
}Size Restrictions
Maximum File Size
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB
function validateFileSize(file: File): { valid: boolean; message?: string } {
if (file.size > MAX_FILE_SIZE) {
return {
valid: false,
message: `File size exceeds ${MAX_FILE_SIZE / (1024 * 1024)} MB limit`
};
}
return { valid: true };
}
// Usage
const file = new File(['data'], 'image.jpg', { type: 'image/jpeg' });
const validation = validateFileSize(file);
if (!validation.valid) {
console.log(validation.message);
}Minimum File Size
const MIN_FILE_SIZE = 1024; // 1 KB
function validateMinimumSize(file: File): boolean {
return file.size >= MIN_FILE_SIZE;
}File Size Constraints
interface FileSizeConstraints {
minSize: number;
maxSize: number;
}
const defaultConstraints: FileSizeConstraints = {
minSize: 1024, // 1 KB
maxSize: 5 * 1024 * 1024 // 5 MB
};
function validateFileSize(file: File, constraints: FileSizeConstraints): boolean {
return file.size >= constraints.minSize && file.size <= constraints.maxSize;
}Dimension Restrictions
Maximum Dimensions
interface ImageDimensions {
maxWidth: number;
maxHeight: number;
}
const maxDimensions: ImageDimensions = {
maxWidth: 4000,
maxHeight: 4000
};
function validateImageDimensions(width: number, height: number, constraints: ImageDimensions): boolean {
return width <= constraints.maxWidth && height <= constraints.maxHeight;
}
// Usage
const dim = imgObj.getImageDimension();
if (!validateImageDimensions(dim.width, dim.height, maxDimensions)) {
alert('Image dimensions exceed maximum allowed');
}Minimum Dimensions
interface MinimumDimensions {
minWidth: number;
minHeight: number;
}
const minDimensions: MinimumDimensions = {
minWidth: 100,
minHeight: 100
};
function validateMinimumDimensions(width: number, height: number, constraints: MinimumDimensions): boolean {
return width >= constraints.minWidth && height >= constraints.minHeight;
}Aspect Ratio Validation
interface AspectRatioConstraint {
minRatio: number;
maxRatio: number;
}
function validateAspectRatio(width: number, height: number, constraint: AspectRatioConstraint): boolean {
const ratio = width / height;
return ratio >= constraint.minRatio && ratio <= constraint.maxRatio;
}
// Usage: 4:3 to 16:9
const constraint: AspectRatioConstraint = {
minRatio: 4 / 3, // 1.33
maxRatio: 16 / 9 // 1.78
};
const dim = imgObj.getImageDimension();
if (!validateAspectRatio(dim.width, dim.height, constraint)) {
alert('Image aspect ratio not supported');
}Validation
Complete File Validation
interface ValidationResult {
valid: boolean;
errors: string[];
}
interface ValidationConstraints {
allowedFormats: string[];
maxFileSize: number;
maxWidth: number;
maxHeight: number;
minWidth: number;
minHeight: number;
}
function validateImage(file: File, constraints: ValidationConstraints): ValidationResult {
const errors: string[] = [];
// Check file type
const ext = file.name.split('.').pop()?.toLowerCase();
if (!ext || !constraints.allowedFormats.includes(ext)) {
errors.push(`File format not allowed. Use: ${constraints.allowedFormats.join(', ')}`);
}
// Check file size
if (file.size > constraints.maxFileSize) {
errors.push(`File size exceeds ${constraints.maxFileSize / (1024 * 1024)} MB`);
}
return {
valid: errors.length === 0,
errors
};
}
// Usage
const constraints: ValidationConstraints = {
allowedFormats: ['jpg', 'jpeg', 'png', 'webp'],
maxFileSize: 5 * 1024 * 1024,
maxWidth: 4000,
maxHeight: 4000,
minWidth: 100,
minHeight: 100
};
const result = validateImage(new File([], 'image.jpg'), constraints);
if (!result.valid) {
result.errors.forEach(error => console.log(error));
}Before Opening Image
const handleFileOpened = (file: File): void => {
const result = validateImage(file, constraints);
if (!result.valid) {
alert('Image validation failed:\n' + result.errors.join('\n'));
return;
}
// Load image
imgObj.open(URL.createObjectURL(file));
};Error Handling
Invalid File Detection
function handleInvalidFile(error: Error): void {
console.error('Image loading failed:', error.message);
if (error.message.includes('format')) {
alert('Unsupported image format');
} else if (error.message.includes('size')) {
alert('File is too large');
} else if (error.message.includes('dimension')) {
alert('Image dimensions invalid');
} else {
alert('Failed to load image');
}
}Graceful Degradation
async function loadImageWithFallback(url: string, fallbackUrl?: string): Promise<void> {
try {
imgObj.open(url);
} catch (error) {
console.error('Failed to load image:', error);
if (fallbackUrl) {
try {
imgObj.open(fallbackUrl);
} catch (fallbackError) {
alert('Failed to load both primary and fallback image');
}
}
}
}Advanced Patterns
Custom Validation Rules
interface ValidationRule {
name: string;
test: (file: File, dimensions?: any) => boolean;
message: string;
}
const customRules: ValidationRule[] = [
{
name: 'format',
test: (file) => ['jpg', 'png'].includes(file.name.split('.').pop()?.toLowerCase() || ''),
message: 'Only JPG and PNG allowed'
},
{
name: 'size',
test: (file) => file.size <= 2 * 1024 * 1024,
message: 'File must be under 2 MB'
},
{
name: 'dimensions',
test: (file, dim) => dim?.width <= 2000 && dim?.height <= 2000,
message: 'Image must be under 2000x2000 pixels'
}
];
function applyCustomValidation(file: File, dimensions?: any): ValidationResult {
const errors: string[] = [];
customRules.forEach(rule => {
if (!rule.test(file, dimensions)) {
errors.push(rule.message);
}
});
return {
valid: errors.length === 0,
errors
};
}Validation Presets
enum ValidationPreset {
Web = 'web',
Mobile = 'mobile',
Print = 'print',
Social = 'social'
}
const presets: Record<ValidationPreset, ValidationConstraints> = {
[ValidationPreset.Web]: {
allowedFormats: ['jpg', 'png', 'webp'],
maxFileSize: 2 * 1024 * 1024,
maxWidth: 2000,
maxHeight: 2000,
minWidth: 200,
minHeight: 200
},
[ValidationPreset.Mobile]: {
allowedFormats: ['jpg', 'png', 'webp'],
maxFileSize: 1 * 1024 * 1024,
maxWidth: 1200,
maxHeight: 1600,
minWidth: 100,
minHeight: 100
},
[ValidationPreset.Print]: {
allowedFormats: ['jpg', 'png', 'tiff'],
maxFileSize: 50 * 1024 * 1024,
maxWidth: 8000,
maxHeight: 8000,
minWidth: 800,
minHeight: 800
},
[ValidationPreset.Social]: {
allowedFormats: ['jpg', 'png'],
maxFileSize: 5 * 1024 * 1024,
maxWidth: 1200,
maxHeight: 1200,
minWidth: 400,
minHeight: 400
}
};
function getPreset(preset: ValidationPreset): ValidationConstraints {
return presets[preset];
}Batch Validation
async function validateBatch(files: File[]): Promise<Array<{ file: File; valid: boolean; errors: string[] }>> {
const constraints = presets[ValidationPreset.Web];
return files.map(file => ({
file,
...validateImage(file, constraints)
}));
}
// Usage
const files = Array.from(document.querySelector('input[type="file"]')?.files || []);
const results = await validateBatch(files);
results.forEach(result => {
if (!result.valid) {
console.log(`${result.file.name}: ${result.errors.join(', ')}`);
}
});Validation with Warnings
interface ValidationSeverity {
level: 'error' | 'warning' | 'info';
message: string;
}
function validateWithSeverity(file: File, constraints: ValidationConstraints): ValidationSeverity[] {
const issues: ValidationSeverity[] = [];
// Errors
if (file.size > constraints.maxFileSize) {
issues.push({
level: 'error',
message: 'File too large'
});
}
// Warnings
if (file.size > constraints.maxFileSize * 0.8) {
issues.push({
level: 'warning',
message: 'File is approaching size limit'
});
}
// Info
issues.push({
level: 'info',
message: `File size: ${(file.size / 1024).toFixed(2)} KB`
});
return issues;
}Related skills
How it compares
Use syncfusion-react-image-editor when you already standardize on Syncfusion React and want one editor component instead of combining separate crop, draw, and filter libraries.
FAQ
Which image formats does syncfusion-react-image-editor support?
syncfusion-react-image-editor documents opening and saving PNG, JPEG, SVG, WEBP, and BMP images. Inputs can come from files, URLs, base64 strings, blobs, or connected file-manager and treeview sources.
What editing features are covered beyond basic crop?
syncfusion-react-image-editor maps guides for rotate, flip, zoom, text and shape annotations, freehand drawing, filters, finetune, undo-redo, z-order management, redaction, and customizable toolbars with accessibility support.