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

,\n numberSeparator: ','\n },\n 'de': {\n locale: 'de-DE',\n dateFormat: 'DD.MM.YYYY',\n timeFormat: '24-hour',\n currencySymbol: '€',\n numberSeparator: '.'\n },\n 'ja': {\n locale: 'ja-JP',\n dateFormat: 'YYYY年MM月DD日',\n timeFormat: '24-hour',\n currencySymbol: '¥',\n numberSeparator: ','\n }\n};\n\nfunction getLanguageFeatures(locale: string): LanguageFeatures {\n return languageFeatures[locale] || languageFeatures['en'];\n}\n```\n\n### Focus Management\n\n```tsx\nclass AccessibleFocusManager {\n private focusableElements: HTMLElement[] = [];\n \n initialize(): void {\n const selector = 'button, [href], input, [tabindex]:not([tabindex=\"-1\"])';\n this.focusableElements = Array.from(document.querySelectorAll(selector));\n }\n \n focusFirst(): void {\n this.focusableElements[0]?.focus();\n }\n \n focusNext(current: HTMLElement): void {\n const index = this.focusableElements.indexOf(current);\n if (index \u003c this.focusableElements.length - 1) {\n this.focusableElements[index + 1]?.focus();\n }\n }\n \n focusPrevious(current: HTMLElement): void {\n const index = this.focusableElements.indexOf(current);\n if (index > 0) {\n this.focusableElements[index - 1]?.focus();\n }\n }\n}\n\nconst focusManager = new AccessibleFocusManager();\nfocusManager.initialize();\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9964,"content_sha256":"85c569c275737dce301afe4fab518531799e050a6e3aa5c47d5950afc308ed8f"},{"filename":"references/api.md","content":"# Image Editor API Reference\n\nComplete API documentation for the Syncfusion React ImageEditorComponent. This reference covers all properties, methods, and events available for programmatic interaction.\n\n## Component Declaration\n\n```tsx\n\u003cImageEditorComponent>\u003c/ImageEditorComponent>\n```\n\n---\n\n## Properties\n\n### Core Configuration\n\n#### `width` (string)\n- **Description:** Specifies the width of the Image Editor container\n- **Default Value:** `'100%'`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent width=\"550px\" />\n ```\n\n#### `height` (string)\n- **Description:** Specifies the height of the Image Editor container\n- **Default Value:** `'100%'`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent height=\"350px\" />\n ```\n\n#### `disabled` (boolean)\n- **Description:** Defines whether the Image Editor component is enabled or disabled\n- **Default Value:** `false`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent disabled={true} />\n ```\n\n#### `cssClass` (string)\n- **Description:** Defines one or more CSS classes for customizing the appearance of the Image Editor component\n- **Default Value:** `''`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent cssClass=\"custom-editor-class\" />\n ```\n\n### Editing and Operations\n\n#### `allowUndoRedo` (boolean)\n- **Description:** Specifies whether undo/redo operations are enabled in the image editor\n- **Default Value:** `true`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent allowUndoRedo={true} />\n ```\n\n#### `imageSmoothingEnabled` (boolean)\n- **Description:** Determines whether high-quality images should be smoothed when rendered\n- **Default Value:** `false`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent imageSmoothingEnabled={true} />\n ```\n\n### Toolbar Configuration\n\n#### `toolbar` (string[] | ItemModel[])\n- **Description:** Specifies the toolbar items to perform UI interactions. Accepts string array of predefined commands or custom ItemModel array\n- **Default Value:** `null` (renders default toolbar with all commands)\n- **Available Commands:**\n - `Crop` - Crop image with various selection shapes and aspect ratios\n - `Straightening` - Rotate image by specified angle\n - `Annotate` - Insert shapes, text, images, and freehand drawings\n - `Transform` - Rotate and flip operations\n - `Finetunes` - Color adjustments (brightness, contrast, saturation, etc.)\n - `Filters` - Apply predefined color filters\n - `Frame` - Add decorative borders\n - `Resize` - Modify image dimensions\n - `ZoomIn` - Zoom in on image\n - `ZoomOut` - Zoom out from image\n - `Save` - Export modified image\n - `Open` - Open image for editing\n - `Undo` - Revert last action\n - `Redo` - Redo last action\n - `Reset` - Restore original image\n- **Example:**\n ```tsx\n const toolbar = ['Crop', 'ZoomIn', 'ZoomOut', 'Transform', { text: 'Custom' }];\n \u003cImageEditorComponent toolbar={toolbar} />\n ```\n\n#### `toolbarTemplate` (string | Function)\n- **Description:** Specifies a custom template for the toolbar. If defined, the toolbar property has no effect\n- **Default Value:** `null`\n- **Example:**\n ```tsx\n function customToolbar() {\n return \u003cButtonComponent content='Custom' />;\n }\n \u003cImageEditorComponent toolbarTemplate={customToolbar} />\n ```\n\n#### `showQuickAccessToolbar` (boolean)\n- **Description:** Specifies whether to show or hide the quick access toolbar\n- **Default Value:** `true`\n- **Example:**\n ```tsx\n \u003cImageEditorComponent showQuickAccessToolbar={true} />\n ```\n\n#### `quickAccessToolbarTemplate` (string | Function)\n- **Description:** Specifies a template for the quick access toolbar for customization\n- **Default Value:** `null`\n- **Example:**\n ```tsx\n function customQuickToolbar() {\n return \u003cdiv>Quick Toolbar Items\u003c/div>;\n }\n \u003cImageEditorComponent quickAccessToolbarTemplate={customQuickToolbar} />\n ```\n\n### Advanced Configuration\n\n#### `theme` (string | Theme)\n- **Description:** Specifies the theme of the Image Editor. Determines the appearance of shape selections and UI elements\n- **Default Value:** `Theme.Bootstrap5`\n- **Supported Themes:** Bootstrap5, and other Syncfusion themes\n- **Example:**\n ```tsx\n \u003cImageEditorComponent theme=\"Bootstrap5\" />\n ```\n\n#### `locale` (string)\n- **Description:** Overrides the global culture and localization value for this component\n- **Default Value:** `'en-US'`\n- **Supported Locales:** 120+ language codes (de-DE, fr-FR, es-ES, etc.)\n- **Example:**\n ```tsx\n \u003cImageEditorComponent locale=\"de-DE\" />\n ```\n\n### Settings Objects\n\n#### `finetuneSettings` (FinetuneSettingsModel)\n- **Description:** Specifies finetune settings for color adjustments in the image editor\n- **Default Value:** `null`\n- **Properties:**\n - `brightness` - Brightness adjustment range (min, max, defaultValue)\n - `contrast` - Contrast adjustment range\n - `saturation` - Saturation adjustment range\n - `hue` - Hue adjustment range\n - `exposure` - Exposure adjustment range\n - `blur` - Blur adjustment range\n - `opacity` - Opacity adjustment range\n- **Example:**\n ```tsx\n const finetune = {\n brightness: { min: -100, max: 100, defaultValue: 0 },\n contrast: { min: -100, max: 100, defaultValue: 0 }\n };\n \u003cImageEditorComponent finetuneSettings={finetune} />\n ```\n\n#### `fontFamily` (FontFamilyModel)\n- **Description:** Predefines font families that populate in the font family dropdown list from the toolbar\n- **Default Value:** `null`\n- **Example:**\n ```tsx\n const fonts = ['Arial', 'Courier New', 'Georgia'];\n \u003cImageEditorComponent fontFamily={fonts} />\n ```\n\n#### `selectionSettings` (SelectionSettingsModel)\n- **Description:** Specifies selection settings to customize selection appearance and behavior\n- **Default Value:** `null`\n- **Example:**\n ```tsx\n const selectionSettings = {\n // Customization options\n };\n \u003cImageEditorComponent selectionSettings={selectionSettings} />\n ```\n\n#### `zoomSettings` (ZoomSettingsModel)\n- **Description:** Specifies zoom settings for zooming actions\n- **Default Value:** `null`\n- **Properties:**\n - `minZoomFactor` - Minimum zoom factor\n - `maxZoomFactor` - Maximum zoom factor\n - `zoomFactor` - Current zoom factor\n - `zoomTrigger` - Zoom triggers (MouseWheel, Pinch, Toolbar, Commands)\n - `zoomPoint` - Point to zoom in/out on (Point object with x, y)\n- **Example:**\n ```tsx\n const zoomSettings = {\n minZoomFactor: 1,\n maxZoomFactor: 100,\n zoomFactor: 1,\n zoomTrigger: ZoomTrigger.MouseWheel | ZoomTrigger.Pinch\n };\n \u003cImageEditorComponent zoomSettings={zoomSettings} />\n ```\n\n#### `uploadSettings` (UploadSettingsModel)\n- **Description:** Represents settings for configuring image uploads with restrictions\n- **Default Value:** `null`\n- **Properties:**\n - `allowedExtensions` - Allowed file extensions (e.g., ['jpg', 'png', 'svg'])\n - `minFileSize` - Minimum file size in bytes\n - `maxFileSize` - Maximum file size in bytes\n- **Example:**\n ```tsx\n const uploadSettings = {\n allowedExtensions: ['jpg', 'png', 'svg', 'webp', 'bmp'],\n maxFileSize: 5242880 // 5MB in bytes\n };\n \u003cImageEditorComponent uploadSettings={uploadSettings} />\n ```\n\n---\n\n## Methods\n\n### Image Operations\n\n#### `open(data: string | ImageData): void`\n- **Description:** Opens an image as URL, base64 string, blob, or ImageData for editing\n- **Parameters:**\n - `data` (string | ImageData) - URL, base64 string, blob, or ImageData object\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.open('https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png');\n ```\n\n#### `clearImage(): void`\n- **Description:** Clears the loaded image in the Image Editor and resets the state\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.clearImage();\n ```\n\n#### `reset(): void`\n- **Description:** Resets all modifications done in the image editor and reverts to the original image\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.reset();\n ```\n\n#### `export(type?: string, fileName?: string, imageQuality?: number): void`\n- **Description:** Exports the edited image using specified file format, name, and quality\n- **Parameters:**\n - `type` (string, optional) - Image format: 'image/png', 'image/jpeg', 'image/svg+xml', 'image/webp'\n - `fileName` (string, optional) - Name for the saved file\n - `imageQuality` (number, optional) - Quality of image (0-1). Default is 1\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.export('image/png', 'edited-image', 0.95);\n ```\n\n#### `getImageData(): ImageData`\n- **Description:** Returns image as ImageData to load it into a canvas\n- **Returns:** ImageData object\n- **Example:**\n ```tsx\n const imageData = imageObj.getImageData();\n ```\n\n#### `getImageDimension(): Dimension`\n- **Description:** Gets the dimension of the image including x, y, width, and height. Useful after cropping\n- **Returns:** Dimension object with x, y, width, height properties\n- **Example:**\n ```tsx\n const dimension = imageObj.getImageDimension();\n console.log(dimension.width, dimension.height);\n ```\n\n#### `resize(width: number, height: number, isAspectRatio?: boolean): boolean`\n- **Description:** Resizes the image by changing its width and height\n- **Parameters:**\n - `width` (number) - New width in pixels\n - `height` (number) - New height in pixels\n - `isAspectRatio` (boolean, optional) - Whether to maintain aspect ratio\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.resize(800, 600, true);\n ```\n\n### Selection and Cropping\n\n#### `select(type: string, startX?: number, startY?: number, width?: number, height?: number): void`\n- **Description:** Performs selection in the image editor for cropping purposes\n- **Parameters:**\n - `type` (string) - Selection type: 'circle', 'square', 'custom', or aspect ratio like '16:9', '4:3', '3:2', etc.\n - `startX` (number, optional) - Start x-coordinate of selection\n - `startY` (number, optional) - Start y-coordinate of selection\n - `width` (number, optional) - Width of selection area\n - `height` (number, optional) - Height of selection area\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.select('16:9', 10, 10, 400, 225);\n ```\n\n#### `clearSelection(resetCrop?: boolean): void`\n- **Description:** Clears the current selection performed in the image editor\n- **Parameters:**\n - `resetCrop` (boolean, optional) - Whether to reset last cropped image\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.clearSelection(true);\n ```\n\n#### `crop(): boolean`\n- **Description:** Crops an image based on the selection done in the image editor\n- **Returns:** boolean (true if crop successful)\n- **Example:**\n ```tsx\n imageObj.select('16:9', 10, 10);\n imageObj.crop();\n ```\n\n### Transformation Methods\n\n#### `rotate(degree: number): boolean`\n- **Description:** Rotates an image clockwise (positive) or counter-clockwise (negative)\n- **Parameters:**\n - `degree` (number) - Rotation angle in degrees. Positive for clockwise, negative for counter-clockwise\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.rotate(90); // Rotate 90 degrees clockwise\n imageObj.rotate(-45); // Rotate 45 degrees counter-clockwise\n ```\n\n#### `flip(direction: Direction): void`\n- **Description:** Flips the image horizontally or vertically\n- **Parameters:**\n - `direction` (Direction) - Flip direction: Direction.Horizontal or Direction.Vertical\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.flip(Direction.Horizontal); // Flip left-right\n imageObj.flip(Direction.Vertical); // Flip top-bottom\n ```\n\n#### `straightenImage(degree: number): boolean`\n- **Description:** Straightens an image by rotating it clockwise or counter-clockwise\n- **Parameters:**\n - `degree` (number) - Degree value for straightening. Positive for clockwise, negative for counter-clockwise\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.straightenImage(5);\n ```\n\n### Zoom and Pan Methods\n\n#### `zoom(zoomFactor: number, zoomPoint?: Point): void`\n- **Description:** Zooms in or out on a specific point in the image editor\n- **Parameters:**\n - `zoomFactor` (number) - Percentage-based zoom factor (e.g., 20 for 2x zoom)\n - `zoomPoint` (Point, optional) - Point to zoom on with x, y coordinates\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.zoom(40, { x: 400, y: 400 });\n ```\n\n#### `pan(value: boolean, x?: number, y?: number): void`\n- **Description:** Enables or disables panning on the image editor\n- **Parameters:**\n - `value` (boolean) - Whether to enable or disable panning\n - `x` (number, optional) - Horizontal pan value\n - `y` (number, optional) - Vertical pan value\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.pan(true, 50, 30);\n ```\n\n#### `freehandDraw(value: boolean): void`\n- **Description:** Enables or disables freehand drawing in the image editor\n- **Parameters:**\n - `value` (boolean) - Whether to enable or disable freehand drawing\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.freehandDraw(true);\n ```\n\n### Annotation: Drawing Shapes\n\n#### `drawRectangle(x?: number, y?: number, width?: number, height?: number, strokeWidth?: number, strokeColor?: string, fillColor?: string, degree?: number, isSelected?: boolean, borderRadius?: number): boolean`\n- **Description:** Draws a rectangle on the image\n- **Parameters:**\n - `x` (number, optional) - X-coordinate of rectangle\n - `y` (number, optional) - Y-coordinate of rectangle\n - `width` (number, optional) - Width of rectangle\n - `height` (number, optional) - Height of rectangle\n - `strokeWidth` (number, optional) - Stroke width\n - `strokeColor` (string, optional) - Stroke color (hex or rgb)\n - `fillColor` (string, optional) - Fill color\n - `degree` (number, optional) - Rotation degree\n - `isSelected` (boolean, optional) - Show in selected state\n - `borderRadius` (number, optional) - Border radius\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawRectangle(50, 50, 100, 80, 2, '#FF0000', '#FFFF00', 0, true);\n ```\n\n#### `drawEllipse(x?: number, y?: number, radiusX?: number, radiusY?: number, strokeWidth?: number, strokeColor?: string, fillColor?: string, degree?: number, isSelected?: boolean): boolean`\n- **Description:** Draws an ellipse on the image\n- **Parameters:**\n - `x` (number, optional) - X-coordinate of ellipse center\n - `y` (number, optional) - Y-coordinate of ellipse center\n - `radiusX` (number, optional) - Horizontal radius\n - `radiusY` (number, optional) - Vertical radius\n - `strokeWidth` (number, optional) - Stroke width\n - `strokeColor` (string, optional) - Stroke color\n - `fillColor` (string, optional) - Fill color\n - `degree` (number, optional) - Rotation degree\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawEllipse(150, 100, 40, 60, 2, '#0000FF', '', 0, true);\n ```\n\n#### `drawLine(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number, strokeColor?: string, isSelected?: boolean): boolean`\n- **Description:** Draws a line on the image\n- **Parameters:**\n - `startX` (number, optional) - Start X-coordinate\n - `startY` (number, optional) - Start Y-coordinate\n - `endX` (number, optional) - End X-coordinate\n - `endY` (number, optional) - End Y-coordinate\n - `strokeWidth` (number, optional) - Stroke width\n - `strokeColor` (string, optional) - Stroke color\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawLine(10, 10, 100, 100, 2, '#000000', true);\n ```\n\n#### `drawArrow(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number, strokeColor?: string, arrowStart?: ArrowheadType, arrowEnd?: ArrowheadType, isSelected?: boolean): boolean`\n- **Description:** Draws an arrow on the image\n- **Parameters:**\n - `startX` (number, optional) - Start X-coordinate\n - `startY` (number, optional) - Start Y-coordinate\n - `endX` (number, optional) - End X-coordinate\n - `endY` (number, optional) - End Y-coordinate\n - `strokeWidth` (number, optional) - Stroke width\n - `strokeColor` (string, optional) - Stroke color\n - `arrowStart` (ArrowheadType, optional) - Start arrowhead type (default: None)\n - `arrowEnd` (ArrowheadType, optional) - End arrowhead type (default: SolidArrow)\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawArrow(20, 20, 150, 150, 2, '#FF0000', ArrowheadType.None, ArrowheadType.SolidArrow);\n ```\n\n#### `drawPath(pointColl: Point[], strokeWidth?: number, strokeColor?: string, isSelected?: boolean): boolean`\n- **Description:** Draws a path (polyline) on the image\n- **Parameters:**\n - `pointColl` (Point[]) - Array of points with x, y coordinates\n - `strokeWidth` (number, optional) - Stroke width\n - `strokeColor` (string, optional) - Stroke color\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n const points = [{ x: 10, y: 10 }, { x: 50, y: 50 }, { x: 100, y: 20 }];\n imageObj.drawPath(points, 2, '#000000', true);\n ```\n\n#### `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`\n- **Description:** Draws text annotation on the image\n- **Parameters:**\n - `x` (number, optional) - X-coordinate of text\n - `y` (number, optional) - Y-coordinate of text\n - `text` (string, optional) - Text content\n - `fontFamily` (string, optional) - Font family name\n - `fontSize` (number, optional) - Font size in pixels\n - `bold` (boolean, optional) - Whether text is bold\n - `italic` (boolean, optional) - Whether text is italic\n - `color` (string, optional) - Text color\n - `isSelected` (boolean, optional) - Show in selected state\n - `degree` (number, optional) - Rotation degree\n - `fillColor` (string, optional) - Background fill color\n - `strokeColor` (string, optional) - Text outline color\n - `strokeWidth` (number, optional) - Outline stroke width\n - `underline` (boolean, optional) - Whether text is underlined\n - `strikethrough` (boolean, optional) - Whether text has strikethrough\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawText(100, 100, 'Syncfusion', 'Arial', 20, true, false, '#000000');\n ```\n\n#### `drawImage(data: string | ImageData, x?: number, y?: number, width?: number, height?: number, isAspectRatio?: boolean, degree?: number, opacity?: number, isSelected?: boolean): boolean`\n- **Description:** Draws an image as annotation on the image\n- **Parameters:**\n - `data` (string | ImageData) - Image URL or ImageData\n - `x` (number, optional) - X-coordinate\n - `y` (number, optional) - Y-coordinate\n - `width` (number, optional) - Width of image\n - `height` (number, optional) - Height of image\n - `isAspectRatio` (boolean, optional) - Maintain aspect ratio\n - `degree` (number, optional) - Rotation degree\n - `opacity` (number, optional) - Opacity value (0-1)\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawImage('watermark.png', 50, 50, 100, 100, true, 0, 0.5);\n ```\n\n#### `drawFrame(frameType: FrameType, color?: string, gradientColor?: string, size?: number, inset?: number, offset?: number, borderRadius?: number, frameLineStyle?: FrameLineStyle, lineCount?: number): boolean`\n- **Description:** Draws a frame decoration on the image\n- **Parameters:**\n - `frameType` (FrameType) - Frame type to apply\n - `color` (string, optional) - Frame color (default: '#fff')\n - `gradientColor` (string, optional) - Gradient color for frame\n - `size` (number, optional) - Frame size as percentage (default: 20)\n - `inset` (number, optional) - Inset value for specific frame types\n - `offset` (number, optional) - Offset value for specific frame types\n - `borderRadius` (number, optional) - Border radius for line-type frames\n - `frameLineStyle` (FrameLineStyle, optional) - Line style (default: Solid)\n - `lineCount` (number, optional) - Number of lines for line-type frames\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawFrame(FrameType.Mat, '#CCCCCC', '', 15);\n ```\n\n### Annotation: Redaction\n\n#### `drawRedact(type?: RedactType, x?: number, y?: number, width?: number, height?: number, value?: number): boolean`\n- **Description:** Draws a redaction (blur or pixelate) on the image for sensitive information\n- **Parameters:**\n - `type` (RedactType, optional) - Redaction type: Blur or Pixelate (default: Blur)\n - `x` (number, optional) - X-coordinate of redaction\n - `y` (number, optional) - Y-coordinate of redaction\n - `width` (number, optional) - Width of redaction area (default: 100)\n - `height` (number, optional) - Height of redaction area (default: 50)\n - `value` (number, optional) - Blur value or pixel size (default: 20)\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n imageObj.drawRedact(RedactType.Blur, 100, 100, 150, 80, 20);\n ```\n\n#### `deleteRedact(id: string): void`\n- **Description:** Deletes a redaction based on the given redaction ID\n- **Parameters:**\n - `id` (string) - Redaction ID to delete\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.deleteRedact('redact_1');\n ```\n\n#### `updateRedact(setting: RedactSettings, isSelected?: boolean): boolean`\n- **Description:** Updates existing redaction by changing height, width, blur, or pixel size\n- **Parameters:**\n - `setting` (RedactSettings) - Redaction settings to update\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n const redactSettings = { id: 'redact_1', width: 200, height: 100 };\n imageObj.updateRedact(redactSettings, true);\n ```\n\n#### `selectRedact(id: string): boolean`\n- **Description:** Selects a redaction based on the given redaction ID\n- **Parameters:**\n - `id` (string) - Redaction ID to select\n- **Returns:** boolean (true if selected)\n- **Example:**\n ```tsx\n imageObj.selectRedact('redact_1');\n ```\n\n#### `getRedacts(): RedactSettings[]`\n- **Description:** Gets all redaction details that are drawn on the image editor\n- **Returns:** Array of RedactSettings objects\n- **Example:**\n ```tsx\n const redacts = imageObj.getRedacts();\n console.log(redacts);\n ```\n\n### Annotation: Shape Management\n\n#### `deleteShape(id: string): void`\n- **Description:** Deletes a shape annotation based on the given shape ID\n- **Parameters:**\n - `id` (string) - Shape ID to delete\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.deleteShape('shape_1');\n ```\n\n#### `updateShape(setting: ShapeSettings, isSelected?: boolean): boolean`\n- **Description:** Updates existing shape by changing height, width, color, and font styles\n- **Parameters:**\n - `setting` (ShapeSettings) - Shape settings to update\n - `isSelected` (boolean, optional) - Show in selected state\n- **Returns:** boolean (true if successful)\n- **Example:**\n ```tsx\n const shapeSettings = { id: 'shape_1', strokeColor: '#FF0000', strokeWidth: 3 };\n imageObj.updateShape(shapeSettings, true);\n ```\n\n#### `selectShape(id: string): boolean`\n- **Description:** Selects a shape based on the given shape ID\n- **Parameters:**\n - `id` (string) - Shape ID to select\n- **Returns:** boolean (true if selected)\n- **Example:**\n ```tsx\n imageObj.selectShape('shape_1');\n ```\n\n#### `getShapeSetting(id: string): ShapeSettings`\n- **Description:** Gets a specific shape's details based on its ID\n- **Parameters:**\n - `id` (string) - Shape ID\n- **Returns:** ShapeSettings object\n- **Example:**\n ```tsx\n const shape = imageObj.getShapeSetting('shape_1');\n console.log(shape.type, shape.strokeColor);\n ```\n\n#### `getShapeSettings(): ShapeSettings[]`\n- **Description:** Gets all shape details drawn on the image editor\n- **Returns:** Array of ShapeSettings objects\n- **Example:**\n ```tsx\n const shapes = imageObj.getShapeSettings();\n ```\n\n#### `cloneShape(shapeId: string): boolean`\n- **Description:** Duplicates a shape based on the given shape ID\n- **Parameters:**\n - `shapeId` (string) - Shape ID to clone\n- **Returns:** boolean (true if cloned successfully)\n- **Example:**\n ```tsx\n imageObj.cloneShape('shape_1');\n ```\n\n### Annotation: Z-Order Management\n\n#### `bringForward(shapeId: string): void`\n- **Description:** Moves a shape ahead of one shape based on the given shape ID\n- **Parameters:**\n - `shapeId` (string) - Shape ID to move forward\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.bringForward('shape_1');\n ```\n\n#### `bringToFront(shapeId: string): void`\n- **Description:** Moves a shape to the front of all other shapes\n- **Parameters:**\n - `shapeId` (string) - Shape ID to bring to front\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.bringToFront('shape_1');\n ```\n\n#### `sendBackward(shapeId: string): void`\n- **Description:** Moves a shape behind one shape based on the given shape ID\n- **Parameters:**\n - `shapeId` (string) - Shape ID to move backward\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.sendBackward('shape_1');\n ```\n\n#### `sendToBack(shapeId: string): void`\n- **Description:** Moves a shape to behind all other shapes\n- **Parameters:**\n - `shapeId` (string) - Shape ID to send to back\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.sendToBack('shape_1');\n ```\n\n### Effects and Filters\n\n#### `applyImageFilter(filterOption: ImageFilterOption): void`\n- **Description:** Applies a filter to the image\n- **Parameters:**\n - `filterOption` (ImageFilterOption) - Filter options object with filter type and parameters\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.applyImageFilter({ type: 'Chrome' });\n imageObj.applyImageFilter({ type: 'Grayscale' });\n ```\n\n#### `getImageFilter(filterOption: ImageFilterOption): string`\n- **Description:** Gets and updates filter to the canvas in the image editor\n- **Parameters:**\n - `filterOption` (ImageFilterOption) - Filter options to retrieve\n- **Returns:** string (filter result)\n- **Example:**\n ```tsx\n const filter = imageObj.getImageFilter({ type: 'Sepia' });\n ```\n\n#### `finetuneImage(finetuneOption: ImageFinetuneOption, value: number): void`\n- **Description:** Fine-tunes image with specified adjustment type and value\n- **Parameters:**\n - `finetuneOption` (ImageFinetuneOption) - Finetune option: Brightness, Contrast, Saturation, Hue, Exposure, Blur, Opacity\n - `value` (number) - Adjustment value\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.finetuneImage(ImageFinetuneOption.Brightness, 30);\n imageObj.finetuneImage(ImageFinetuneOption.Contrast, -15);\n ```\n\n### Text Editing\n\n#### `enableTextEditing(): void`\n- **Description:** Enables text area editing in the image editor\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.enableTextEditing();\n ```\n\n### Shape Drawing Control\n\n#### `enableShapeDrawing(shapeType: ShapeType, isEnabled?: boolean): void`\n- **Description:** Enables or disables shape drawing option in the image editor\n- **Parameters:**\n - `shapeType` (ShapeType) - Type of shape to enable/disable\n - `isEnabled` (boolean, optional) - Enable or disable (default: true)\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.enableShapeDrawing(ShapeType.Circle, true);\n imageObj.enableShapeDrawing(ShapeType.Rectangle, false);\n ```\n\n### Undo/Redo Operations\n\n#### `undo(): void`\n- **Description:** Reverses the last action performed by the user\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.undo();\n ```\n\n#### `redo(): void`\n- **Description:** Redoes the last user action that was undone\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.redo();\n ```\n\n#### `canUndo(): boolean`\n- **Description:** Specifies if it's possible to undo the last recent action\n- **Returns:** boolean (true if undo is available)\n- **Example:**\n ```tsx\n if (imageObj.canUndo()) {\n imageObj.undo();\n }\n ```\n\n#### `canRedo(): boolean`\n- **Description:** Specifies if it's possible to redo the last recent action\n- **Returns:** boolean (true if redo is available)\n- **Example:**\n ```tsx\n if (imageObj.canRedo()) {\n imageObj.redo();\n }\n ```\n\n### Canvas Management\n\n#### `apply(): void`\n- **Description:** Applies the operations performed in the image editor (annotation drawings)\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.apply();\n ```\n\n#### `discard(): void`\n- **Description:** Discards the operations performed in the image editor\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.discard();\n ```\n\n#### `update(): void`\n- **Description:** Refreshes the canvas wrapper to reflect changes\n- **Returns:** void\n- **Example:**\n ```tsx\n imageObj.update();\n ```\n\n---\n\n## Events\n\n### Lifecycle Events\n\n#### `created`\n- **Type:** `EmitType\u003cEvent>`\n- **Description:** Triggered after the Image Editor component is rendered\n- **Use Case:** Load initial image, apply default settings\n- **Example:**\n ```tsx\n function handleCreated(): void {\n imageObj.open('https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png');\n }\n \u003cImageEditorComponent created={handleCreated} />\n ```\n\n#### `destroyed`\n- **Type:** `EmitType\u003cEvent>`\n- **Description:** Triggered once the component is destroyed with its elements and bound events\n- **Use Case:** Cleanup, dispose resources\n- **Example:**\n ```tsx\n function handleDestroyed(): void {\n console.log('Component destroyed');\n }\n \u003cImageEditorComponent destroyed={handleDestroyed} />\n ```\n\n### File Operations\n\n#### `fileOpened`\n- **Type:** `EmitType\u003cOpenEventArgs>`\n- **Description:** Triggered once an image is opened in the image editor\n- **Event Args:**\n - `fileName` - Name of opened file\n - `fileSize` - Size of opened file\n- **Use Case:** Add watermarks, apply default effects, validate image\n- **Example:**\n ```tsx\n function handleFileOpened(args: OpenEventArgs): void {\n console.log('File opened:', args.fileName);\n }\n \u003cImageEditorComponent fileOpened={handleFileOpened} />\n ```\n\n#### `beforeSave`\n- **Type:** `EmitType\u003cBeforeSaveEventArgs>`\n- **Description:** Triggered before an image is saved\n- **Event Args:** Save event details\n- **Use Case:** Validation, add metadata, confirm save\n- **Example:**\n ```tsx\n function handleBeforeSave(args: BeforeSaveEventArgs): void {\n console.log('About to save image');\n }\n \u003cImageEditorComponent beforeSave={handleBeforeSave} />\n ```\n\n#### `saved`\n- **Type:** `EmitType\u003cSaveEventArgs>`\n- **Description:** Triggered once an image is successfully saved\n- **Event Args:** Save event details\n- **Use Case:** Show success message, upload to server\n- **Example:**\n ```tsx\n function handleSaved(args: SaveEventArgs): void {\n console.log('Image saved successfully');\n }\n \u003cImageEditorComponent saved={handleSaved} />\n ```\n\n### Interaction Events\n\n#### `click`\n- **Type:** `EmitType\u003cImageEditorClickEventArgs>`\n- **Description:** Triggered while clicking on an image in the image editor\n- **Event Args:**\n - `pageX` - X-coordinate of click\n - `pageY` - Y-coordinate of click\n- **Use Case:** Handle custom click interactions\n- **Example:**\n ```tsx\n function handleClick(args: ImageEditorClickEventArgs): void {\n console.log('Clicked at:', args.pageX, args.pageY);\n }\n \u003cImageEditorComponent click={handleClick} />\n ```\n\n### Transformation Events\n\n#### `cropping`\n- **Type:** `EmitType\u003cCropEventArgs>`\n- **Description:** Triggered while cropping an image\n- **Event Args:** Crop event details with dimensions\n- **Use Case:** Prevent invalid crops, lock aspect ratio\n- **Example:**\n ```tsx\n function handleCropping(args: CropEventArgs): void {\n console.log('Cropping...');\n }\n \u003cImageEditorComponent cropping={handleCropping} />\n ```\n\n#### `rotating`\n- **Type:** `EmitType\u003cRotateEventArgs>`\n- **Description:** Triggered while rotating an image\n- **Event Args:** Rotation angle and details\n- **Use Case:** Track rotation state\n- **Example:**\n ```tsx\n function handleRotating(args: RotateEventArgs): void {\n console.log('Rotating to:', args.degree);\n }\n \u003cImageEditorComponent rotating={handleRotating} />\n ```\n\n#### `flipping`\n- **Type:** `EmitType\u003cFlipEventArgs>`\n- **Description:** Triggered while flipping an image\n- **Event Args:** Flip direction\n- **Use Case:** Track flip state\n- **Example:**\n ```tsx\n function handleFlipping(args: FlipEventArgs): void {\n console.log('Flipped:', args.direction);\n }\n \u003cImageEditorComponent flipping={handleFlipping} />\n ```\n\n#### `resizing`\n- **Type:** `EmitType\u003cResizeEventArgs>`\n- **Description:** Triggered while resizing an image\n- **Event Args:** New width and height\n- **Use Case:** Validate dimensions, show resize preview\n- **Example:**\n ```tsx\n function handleResizing(args: ResizeEventArgs): void {\n console.log('Resizing to:', args.width, args.height);\n }\n \u003cImageEditorComponent resizing={handleResizing} />\n ```\n\n### Zoom and Pan Events\n\n#### `zooming`\n- **Type:** `EmitType\u003cZoomEventArgs>`\n- **Description:** Triggered while zooming an image\n- **Event Args:** Zoom factor and point\n- **Use Case:** Update UI indicators, sync other components\n- **Example:**\n ```tsx\n function handleZooming(args: ZoomEventArgs): void {\n console.log('Zoom factor:', args.zoomFactor);\n }\n \u003cImageEditorComponent zooming={handleZooming} />\n ```\n\n#### `panning`\n- **Type:** `EmitType\u003cPanEventArgs>`\n- **Description:** Triggered while panning an image\n- **Event Args:** Pan offset values\n- **Use Case:** Track pan state\n- **Example:**\n ```tsx\n function handlePanning(args: PanEventArgs): void {\n console.log('Panning...');\n }\n \u003cImageEditorComponent panning={handlePanning} />\n ```\n\n### Effect Events\n\n#### `imageFiltering`\n- **Type:** `EmitType\u003cImageFilterEventArgs>`\n- **Description:** Triggered when applying a filter to an image\n- **Event Args:** Filter type and parameters\n- **Use Case:** Preview filter, log applied filters\n- **Example:**\n ```tsx\n function handleImageFiltering(args: ImageFilterEventArgs): void {\n console.log('Applied filter:', args.filterType);\n }\n \u003cImageEditorComponent imageFiltering={handleImageFiltering} />\n ```\n\n#### `finetuneValueChanging`\n- **Type:** `EmitType\u003cFinetuneEventArgs>`\n- **Description:** Triggered when applying fine-tune adjustments to an image\n- **Event Args:** Finetune type and value\n- **Use Case:** Show finetune preview, track adjustments\n- **Example:**\n ```tsx\n function handleFinetuneValueChanging(args: FinetuneEventArgs): void {\n console.log('Finetune:', args.type, args.value);\n }\n \u003cImageEditorComponent finetuneValueChanging={handleFinetuneValueChanging} />\n ```\n\n#### `frameChange`\n- **Type:** `EmitType\u003cFrameChangeEventArgs>`\n- **Description:** Triggered while applying frames on an image\n- **Event Args:** Frame type and properties\n- **Use Case:** Track frame application\n- **Example:**\n ```tsx\n function handleFrameChange(args: FrameChangeEventArgs): void {\n console.log('Frame changed');\n }\n \u003cImageEditorComponent frameChange={handleFrameChange} />\n ```\n\n### Selection Events\n\n#### `selectionChanging`\n- **Type:** `EmitType\u003cSelectionChangeEventArgs>`\n- **Description:** Triggered while changing selection in the image editor\n- **Event Args:** Selection dimensions\n- **Use Case:** Update UI, validate selection\n- **Example:**\n ```tsx\n function handleSelectionChanging(args: SelectionChangeEventArgs): void {\n console.log('Selection changed');\n }\n \u003cImageEditorComponent selectionChanging={handleSelectionChanging} />\n ```\n\n### Shape and Annotation Events\n\n#### `shapeChanging`\n- **Type:** `EmitType\u003cShapeChangeEventArgs>`\n- **Description:** Triggered while changing shapes in the image editor\n- **Event Args:** Shape properties and changes\n- **Use Case:** Customize shape appearance, validate changes\n- **Example:**\n ```tsx\n function handleShapeChanging(args: ShapeChangeEventArgs): void {\n // Customize shape on the fly\n if (args.type === 'text') {\n args.fillColor = '#FF0000';\n }\n }\n \u003cImageEditorComponent shapeChanging={handleShapeChanging} />\n ```\n\n#### `shapeChange`\n- **Type:** `EmitType\u003cShapeChangeEventArgs>`\n- **Description:** Triggered after shape changing action is completed\n- **Event Args:** Final shape properties\n- **Use Case:** Log changes, update data model\n- **Example:**\n ```tsx\n function handleShapeChange(args: ShapeChangeEventArgs): void {\n console.log('Shape changed:', args.id);\n }\n \u003cImageEditorComponent shapeChange={handleShapeChange} />\n ```\n\n#### `editComplete`\n- **Type:** `EmitType\u003cEditCompleteEventArgs>`\n- **Description:** Triggered after completion of any editing action in the image editor\n- **Event Args:** Edit action details\n- **Use Case:** Update UI, save state, trigger related actions\n- **Example:**\n ```tsx\n function handleEditComplete(args: EditCompleteEventArgs): void {\n console.log('Edit complete:', args.action);\n }\n \u003cImageEditorComponent editComplete={handleEditComplete} />\n ```\n\n### Toolbar Events\n\n#### `toolbarCreated`\n- **Type:** `EmitType\u003cToolbarEventArgs>`\n- **Description:** Triggered once the toolbar is created\n- **Event Args:** Toolbar items and configuration\n- **Use Case:** Add/remove toolbar items, customize appearance\n- **Example:**\n ```tsx\n function handleToolbarCreated(args: ToolbarEventArgs): void {\n console.log('Toolbar created');\n }\n \u003cImageEditorComponent toolbarCreated={handleToolbarCreated} />\n ```\n\n#### `toolbarUpdating`\n- **Type:** `EmitType\u003cToolbarEventArgs>`\n- **Description:** Triggered while updating or refreshing the toolbar\n- **Event Args:** Toolbar type and items\n- **Use Case:** Dynamically customize contextual toolbars\n- **Example:**\n ```tsx\n function handleToolbarUpdating(args: ToolbarEventArgs): void {\n if (args.toolbarType === 'shapes') {\n args.toolbarItems = ['fillColor', 'strokeColor', 'strokeWidth'];\n }\n }\n \u003cImageEditorComponent toolbarUpdating={handleToolbarUpdating} />\n ```\n\n#### `toolbarItemClicked`\n- **Type:** `EmitType\u003cClickEventArgs>`\n- **Description:** Triggered once a toolbar item is clicked\n- **Event Args:** Clicked item information\n- **Use Case:** Handle custom toolbar item actions\n- **Example:**\n ```tsx\n function handleToolbarItemClicked(args: ClickEventArgs): void {\n console.log('Toolbar item clicked');\n }\n \u003cImageEditorComponent toolbarItemClicked={handleToolbarItemClicked} />\n ```\n\n### Quick Access Toolbar Events\n\n#### `quickAccessToolbarOpen`\n- **Type:** `EmitType\u003cQuickAccessToolbarEventArgs>`\n- **Description:** Triggered when the quick access toolbar opens\n- **Event Args:** Toolbar configuration\n- **Use Case:** Customize quick access items\n- **Example:**\n ```tsx\n function handleQuickAccessToolbarOpen(args: QuickAccessToolbarEventArgs): void {\n console.log('Quick access toolbar opened');\n }\n \u003cImageEditorComponent quickAccessToolbarOpen={handleQuickAccessToolbarOpen} />\n ```\n\n#### `quickAccessToolbarItemClick`\n- **Type:** `EmitType\u003cClickEventArgs>`\n- **Description:** Triggered when a quick access toolbar item is clicked\n- **Event Args:** Clicked item information\n- **Use Case:** Handle quick access item actions\n- **Example:**\n ```tsx\n function handleQuickAccessToolbarItemClick(args: ClickEventArgs): void {\n console.log('Quick access toolbar item clicked');\n }\n \u003cImageEditorComponent quickAccessToolbarItemClick={handleQuickAccessToolbarItemClick} />\n ```\n\n---\n\n## Enums and Type Definitions\n\n### Direction\nDirection for flip operations:\n- `Horizontal` - Flip left-right\n- `Vertical` - Flip top-bottom\n\n### ArrowheadType\nArrowhead style for arrow annotations:\n- `None` - No arrowhead\n- `SolidArrow` - Solid arrowhead\n- `BarArrow` - Bar arrowhead\n\n### RedactType\nType of redaction:\n- `Blur` - Blur sensitive content\n- `Pixelate` - Pixelate sensitive content\n\n### FrameType\nFrame decoration styles:\n- `Mat` - Matte frame\n- `Bevel` - Beveled frame\n- `Line` - Line frame\n- `Inset` - Inset frame\n- `Hook` - Hook frame\n\n### ShapeType\nShape types for enabling/disabling:\n- `Rectangle`, `Ellipse`, `Line`, `Arrow`, `Path`, `Text`, `Image`, `Freehand`, `RedactRectangle`, `RedactEllipse`\n\n### ImageFinetuneOption\nFine-tune adjustment types:\n- `Brightness` - Adjust brightness\n- `Contrast` - Adjust contrast\n- `Saturation` - Adjust saturation\n- `Hue` - Adjust hue\n- `Exposure` - Adjust exposure\n- `Blur` - Apply blur effect\n- `Opacity` - Adjust opacity\n\n### Theme\nAvailable themes:\n- `Bootstrap5`\n\n### ZoomTrigger\nZoom activation methods (can be combined with bitwise OR):\n- `MouseWheel` - Scroll to zoom\n- `Pinch` - Pinch gesture on touch devices\n- `Toolbar` - Zoom buttons\n- `Commands` - Programmatic zoom via methods\n\n---\n\n## Complete API Example\n\n```tsx\nimport { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';\nimport React, { useRef } from 'react';\n\nfunction ImageEditorDemo() {\n const imageEditorRef = useRef\u003cImageEditorComponent>(null);\n\n const handleCreated = () => {\n imageEditorRef.current?.open(\n 'https://ej2.syncfusion.com/demos/src/image-editor/images/bridge.png'\n );\n };\n\n const handleRotate = () => {\n imageEditorRef.current?.rotate(90);\n };\n\n const handleCrop = () => {\n imageEditorRef.current?.select('16:9', 10, 10);\n imageEditorRef.current?.crop();\n };\n\n const handleExport = () => {\n imageEditorRef.current?.export('image/png', 'edited-image');\n };\n\n const handleAddText = () => {\n const dimension = imageEditorRef.current?.getImageDimension();\n imageEditorRef.current?.drawText(\n dimension?.x || 100,\n dimension?.y || 100,\n 'Sample Text',\n 'Arial',\n 20,\n false,\n false,\n '#000000'\n );\n };\n\n return (\n \u003cdiv>\n \u003cImageEditorComponent\n ref={imageEditorRef}\n width=\"550px\"\n height=\"350px\"\n created={handleCreated}\n toolbar={['Crop', 'ZoomIn', 'ZoomOut', 'Transform', 'Save', 'Reset']}\n />\n \u003cdiv>\n \u003cbutton onClick={handleRotate}>Rotate 90°\u003c/button>\n \u003cbutton onClick={handleCrop}>Crop 16:9\u003c/button>\n \u003cbutton onClick={handleAddText}>Add Text\u003c/button>\n \u003cbutton onClick={handleExport}>Export\u003c/button>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default ImageEditorDemo;\n```\n\n---\n\n## Related References\n\n- [Getting Started](getting-started.md) - Installation and basic setup\n- [Opening and Saving Images](opening-saving-images.md) - File operations\n- [Selection and Cropping](selection-cropping.md) - Crop functionality\n- [Transform, Rotate, Flip](transform-rotate-flip.md) - Image transformations\n- [Text Annotations](text-annotations.md) - Adding text\n- [Shape Annotations](shape-annotations.md) - Drawing shapes\n- [Filters](filters.md) - Apply image filters\n- [Fine-Tuning](finetune.md) - Color adjustments\n- [Accessibility and Localization](accessibility-localization.md) - Accessibility features\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":42889,"content_sha256":"aa73199469f2abf9b5502885761bd437f08deb9c6127bfb4efff72ac8236adfb"},{"filename":"references/clear-image.md","content":"# Clear Image\n\n## Overview\n\nThe `clearImage()` method resets the Image Editor to a blank state, removing all images and clearing the canvas.\n\n## Clear Image\n\n### Basic Clear\n\n```tsx\nfunction clearCurrentImage(): void {\n imgObj.clearImage();\n}\n```\n\n### With Confirmation\n\n```tsx\nfunction clearWithConfirmation(): void {\n if (window.confirm('Are you sure you want to clear the image? This action cannot be undone.')) {\n imgObj.clearImage();\n }\n}\n```\n\n## Use Cases\n\n### Reset After Save\n\nClear image after exporting:\n\n```tsx\nasync function exportAndClear(): Promise\u003cvoid> {\n // Save image\n imgObj.export('image/png', 'edited-image');\n \n // Clear editor\n imgObj.clearImage();\n}\n```\n\n### Prepare for New Image\n\nClear before opening new file:\n\n```tsx\nfunction openNewImage(imageUrl: string): void {\n // Clear existing\n imgObj.clearImage();\n \n // Load new\n imgObj.open(imageUrl);\n}\n```\n\n### Undo All Changes\n\nReset to blank state:\n\n```tsx\nfunction clearAllChanges(): void {\n imgObj.clearImage();\n}\n```\n\n## Advanced Patterns\n\n### Clear with Dialog Confirmation\n\n```tsx\nfunction clearImageWithDialog(): void {\n const userChoice = confirm(\n 'Clear current image?\\n\\nThis will remove all edits and annotations.'\n );\n \n if (userChoice) {\n imgObj.clearImage();\n logAction('Image cleared');\n }\n}\n```\n\n### Clear Specific Elements\n\n```tsx\n// Clear all annotations but keep the image\nfunction clearAnnotations(): void {\n const shapes = imgObj.getShapeSettings();\n shapes.forEach(shape => {\n imgObj.deleteShape(shape.id);\n });\n}\n\n// Clear specific shape types\nfunction clearRectangles(): void {\n const shapes = imgObj.getShapeSettings();\n shapes\n .filter(s => s.type === 'Rectangle')\n .forEach(s => imgObj.deleteShape(s.id));\n}\n```\n\n### Clear with Undo Support\n\n```tsx\nfunction clearImageWithUndo(): void {\n // Image Editor's undo will handle this\n imgObj.clearImage();\n \n // User can press Ctrl+Z to redo\n}\n```\n\n### Batch Clear\n\n```tsx\nfunction clearMultipleEditors(editors: ImageEditor[]): void {\n editors.forEach(editor => {\n editor.clearImage();\n });\n}\n```\n\n### Smart Clear with Shape Check\n\n```tsx\nfunction smartClear(): void {\n const shapes = imgObj.getShapeSettings();\n \n if (shapes.length === 0) {\n // Already empty\n console.log('Nothing to clear');\n return;\n }\n \n if (!confirm('Clear all content?')) {\n return;\n }\n \n imgObj.clearImage();\n}\n```\n\n### Clear with State Tracking\n\n```tsx\nclass EditorState {\n private hasContent: boolean = false;\n \n setContent(hasContent: boolean): void {\n this.hasContent = hasContent;\n }\n \n clear(): void {\n if (this.hasContent) {\n imgObj.clearImage();\n this.hasContent = false;\n }\n }\n \n hasContent(): boolean {\n return this.hasContent;\n }\n}\n\nconst state = new EditorState();\nstate.setContent(true);\nstate.clear();\n```\n\n### Dialog-Based Editor Pattern\n\n```tsx\ninterface DialogEditorConfig {\n containerId: string;\n dialogId: string;\n reuseEditor: boolean;\n}\n\nfunction renderImageEditorDialog(config: DialogEditorConfig): void {\n const dialogElement = document.getElementById(config.dialogId);\n \n if (!dialogElement) return;\n \n // Create or reuse editor instance\n if (config.reuseEditor) {\n // Clear existing content\n imgObj.clearImage();\n } else {\n // Create new instance\n // imgObj = new ImageEditor();\n }\n \n // Show dialog\n if ('show' in dialogElement && typeof dialogElement.show === 'function') {\n (dialogElement as any).show();\n }\n}\n\n// Usage\nconst editorConfig: DialogEditorConfig = {\n containerId: 'editor-container',\n dialogId: 'editor-dialog',\n reuseEditor: true\n};\n\nrenderImageEditorDialog(editorConfig);\n```\n\n### Auto-Clear on Timer\n\n```tsx\nfunction autoClearAfterDelay(delayMs: number = 300000): void {\n // Auto-clear after 5 minutes of inactivity\n let timeoutId: NodeJS.Timeout | null = null;\n \n const resetTimer = (): void => {\n if (timeoutId) clearTimeout(timeoutId);\n \n timeoutId = setTimeout(() => {\n if (confirm('Clear inactive editor?')) {\n imgObj.clearImage();\n }\n }, delayMs);\n };\n \n document.addEventListener('mousemove', resetTimer);\n document.addEventListener('keypress', resetTimer);\n}\n```\n\n### Clear with Notification\n\n```tsx\nfunction clearImageWithNotification(): void {\n imgObj.clearImage();\n \n // Notify user\n showNotification({\n type: 'info',\n message: 'Image cleared',\n duration: 3000\n });\n}\n\ninterface Notification {\n type: 'info' | 'warning' | 'error' | 'success';\n message: string;\n duration: number;\n}\n\nfunction showNotification(notification: Notification): void {\n const element = document.createElement('div');\n element.className = `notification notification-${notification.type}`;\n element.textContent = notification.message;\n element.setAttribute('role', 'status');\n element.setAttribute('aria-live', 'polite');\n \n document.body.appendChild(element);\n \n setTimeout(() => element.remove(), notification.duration);\n}\n```\n\n### Conditional Clear\n\n```tsx\ninterface ClearConditions {\n hasAnnotations: boolean;\n hasShapes: boolean;\n}\n\nfunction getClearConditions(): ClearConditions {\n const shapes = imgObj.getShapeSettings();\n \n return {\n hasAnnotations: shapes.length > 0,\n hasShapes: shapes.length > 0\n };\n}\n\nfunction conditionalClear(): void {\n const conditions = getClearConditions();\n \n if (conditions.hasAnnotations) {\n if (confirm('Clear all annotations?')) {\n imgObj.clearImage();\n }\n } else {\n console.log('No annotations to clear');\n }\n}\n```\n\n### Clear with History Export\n\n```tsx\nclass EditorWithHistory {\n private history: Array\u003c{ timestamp: Date; action: string }> = [];\n \n clear(): void {\n this.history.push({\n timestamp: new Date(),\n action: 'Image cleared'\n });\n \n imgObj.clearImage();\n }\n \n exportHistory(): string {\n return this.history\n .map(entry => `${entry.timestamp.toISOString()}: ${entry.action}`)\n .join('\\n');\n }\n}\n\nconst editorWithHistory = new EditorWithHistory();\neditorWithHistory.clear();\nconsole.log(editorWithHistory.exportHistory());\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6102,"content_sha256":"e6eddac22b5f0a1103f1169fabf5c754adcab4a0dfe31e61458494b47b16569d"},{"filename":"references/filters.md","content":"# Filters\n\n## Available Filters\n\nThe Image Editor supports 6 predefined filters for instant visual effects:\n\n| Filter | Effect | Use Case |\n|--------|--------|----------|\n| Chrome | Metallic effect | Modern look |\n| Cold | Blue tones | Winter/cool mood |\n| Warm | Orange/yellow tones | Sunset/warm mood |\n| Grayscale | Black & white | Professional/vintage |\n| Sepia | Brown tones | Vintage/antique |\n| Invert | Negative colors | X-ray effect |\n\n## Applying Filters\n\n### Apply Single Filter\n\n```tsx\nimport { ImageFilterOption } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyChrome(): void {\n imgObj.applyImageFilter(ImageFilterOption.Chrome);\n}\n\nfunction applyCold(): void {\n imgObj.applyImageFilter(ImageFilterOption.Cold);\n}\n\nfunction applyWarm(): void {\n imgObj.applyImageFilter(ImageFilterOption.Warm);\n}\n\nfunction applyGrayscale(): void {\n imgObj.applyImageFilter(ImageFilterOption.Grayscale);\n}\n\nfunction applySepia(): void {\n imgObj.applyImageFilter(ImageFilterOption.Sepia);\n}\n\nfunction applyInvert(): void {\n imgObj.applyImageFilter(ImageFilterOption.Invert);\n}\n```\n\n### Filter Toolbar Integration\n\nAdd filter buttons to toolbar:\n\n```tsx\nconst toolbar = [\n 'Open',\n 'Filter',\n 'ZoomIn',\n 'ZoomOut',\n {text: 'Chrome', prefixIcon: 'e-icons e-filter'},\n {text: 'Sepia', prefixIcon: 'e-icons e-filter'},\n 'Save'\n];\n\nfunction toolbarItemClicked(args: any): void {\n if (args.item.text === 'Chrome') {\n imgObj.applyImageFilter(ImageFilterOption.Chrome);\n } else if (args.item.text === 'Sepia') {\n imgObj.applyImageFilter(ImageFilterOption.Sepia);\n }\n}\n\n\u003cImageEditorComponent toolbar={toolbar} toolbarItemClicked={toolbarItemClicked} />\n```\n\n## Filter Effects Gallery\n\n### Chrome Effect\n\nModern metallic appearance:\n\n```tsx\nfunction applyChromeEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Chrome);\n}\n```\n\n### Cold Effect\n\nCool blue tone enhancement:\n\n```tsx\nfunction applyColdEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Cold);\n}\n```\n\n### Warm Effect\n\nWarm orange/yellow tone:\n\n```tsx\nfunction applyWarmEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Warm);\n}\n```\n\n### Sepia Effect\n\nVintage brown tone:\n\n```tsx\nfunction applySepiaEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Sepia);\n}\n```\n\n### Grayscale Effect\n\nBlack and white conversion:\n\n```tsx\nfunction applyGrayscaleEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Grayscale);\n}\n```\n\n### Invert Effect\n\nNegative/inverted colors:\n\n```tsx\nfunction applyInvertEffect(): void {\n imgObj.applyImageFilter(ImageFilterOption.Invert);\n}\n```\n\n## Filter Events\n\n### Detect Filter Application\n\nReact to filter changes:\n\n```tsx\nfunction imageFiltering(args: any): void {\n console.log('Applying filter:', args.filter);\n // args.cancel = true; // Prevent filter if needed\n}\n\n\u003cImageEditorComponent imageFiltering={imageFiltering} />\n```\n\n### Log Filter History\n\nTrack applied filters:\n\n```tsx\nlet filterHistory: string[] = [];\n\nfunction imageFiltering(args: any): void {\n filterHistory.push(args.filter);\n console.log('Filter history:', filterHistory);\n}\n```\n\n## Advanced Patterns\n\n### Filter Toggle\n\nApply and remove filters:\n\n```tsx\nlet currentFilter: string | null = null;\n\nfunction toggleFilter(filter: ImageFilterOption): void {\n if (currentFilter === filter) {\n imgObj.reset(); // Remove filter\n currentFilter = null;\n } else {\n if (currentFilter) {\n imgObj.undo(); // Remove previous filter\n }\n imgObj.applyImageFilter(filter);\n currentFilter = filter;\n }\n}\n```\n\n### Filter Preview\n\nShow before/after comparison:\n\n```tsx\nfunction previewFilter(filter: ImageFilterOption): void {\n // Save original state\n const originalImage = imgObj.getImageData();\n \n // Apply filter\n imgObj.applyImageFilter(filter);\n \n // User can accept or undo\n}\n```\n\n### Sequential Filters\n\nApply multiple filters in sequence:\n\n```tsx\nfunction applyFilterSequence(): void {\n imgObj.applyImageFilter(ImageFilterOption.Grayscale);\n imgObj.applyImageFilter(ImageFilterOption.Cold);\n}\n\n// Result: Grayscale + Cold combined\n```\n\n### Undo Filter\n\nRemove last applied filter:\n\n```tsx\nfunction undoFilter(): void {\n imgObj.undo();\n}\n```\n\n### Reset All Filters\n\nRemove all effects:\n\n```tsx\nfunction resetFilters(): void {\n imgObj.reset();\n}\n```\n\n### Filter with Fine-tuning\n\nCombine filter with adjustments:\n\n```tsx\nfunction enhancedSepia(): void {\n // Apply sepia\n imgObj.applyImageFilter(ImageFilterOption.Sepia);\n \n // Fine-tune contrast\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, 20);\n \n // Fine-tune saturation\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, 15);\n}\n```\n\n### Dynamic Filter Selection\n\nFilter selector UI:\n\n```tsx\nfunction selectFilter(filterName: string): void {\n const filterMap = {\n 'chrome': ImageFilterOption.Chrome,\n 'cold': ImageFilterOption.Cold,\n 'warm': ImageFilterOption.Warm,\n 'grayscale': ImageFilterOption.Grayscale,\n 'sepia': ImageFilterOption.Sepia,\n 'invert': ImageFilterOption.Invert\n };\n \n const filter = filterMap[filterName];\n if (filter) {\n imgObj.applyImageFilter(filter);\n }\n}\n\n// Usage\nselectFilter('sepia');\n```\n\n### Filter History Playback\n\nReplay previous filters:\n\n```tsx\nlet appliedFilters: ImageFilterOption[] = [];\n\nfunction recordAndApplyFilter(filter: ImageFilterOption): void {\n appliedFilters.push(filter);\n imgObj.applyImageFilter(filter);\n}\n\nfunction replayFilters(): void {\n imgObj.reset();\n appliedFilters.forEach(filter => {\n imgObj.applyImageFilter(filter);\n });\n}\n```\n\n### Non-Destructive Filtering\n\nKeep original with filter layer:\n\n```tsx\nlet hasFilter = false;\nlet filterApplied: ImageFilterOption | null = null;\n\nfunction applyNonDestructive(filter: ImageFilterOption): void {\n if (hasFilter && filterApplied) {\n imgObj.undo();\n }\n \n imgObj.applyImageFilter(filter);\n hasFilter = true;\n filterApplied = filter;\n}\n\nfunction removeFilter(): void {\n if (hasFilter) {\n imgObj.undo();\n hasFilter = false;\n filterApplied = null;\n }\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6035,"content_sha256":"8203f63f789114d8b241395284d28637110b9feab124ec43267e22e4bf834d5f"},{"filename":"references/finetune.md","content":"# Fine-Tuning\n\n## Fine-Tune Options\n\nAdjust image properties with precise control:\n\n| Option | Range | Effect |\n|--------|-------|--------|\n| Brightness | -100 to +100 | Light/dark intensity |\n| Contrast | -100 to +100 | Tone separation |\n| Saturation | -100 to +100 | Color intensity |\n| Hue | -180 to +180 | Color shift |\n| Exposure | -100 to +100 | Overall brightness |\n| Blur | 0 to +100 | Blur intensity |\n| Opacity | 0 to +100 | Transparency |\n\n## Adjusting Brightness\n\n```tsx\nimport { ImageFinetuneOption } from '@syncfusion/ej2-react-image-editor';\n\nfunction increaseBrightness(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Brightness, 30);\n}\n\nfunction decreaseBrightness(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Brightness, -30);\n}\n```\n\n## Adjusting Contrast\n\n```tsx\nfunction increaseContrast(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, 40);\n}\n\nfunction decreaseContrast(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, -20);\n}\n```\n\n## Adjusting Saturation\n\n```tsx\nfunction increaseSaturation(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, 50);\n}\n\nfunction decreaseSaturation(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, -50);\n}\n\n// Full desaturation (grayscale)\nfunction removeColor(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, -100);\n}\n```\n\n## Adjusting Hue\n\nShift colors across the spectrum:\n\n```tsx\nfunction shiftHueRed(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Hue, 30);\n}\n\nfunction shiftHueGreen(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Hue, 120);\n}\n\nfunction shiftHueBlue(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Hue, -60);\n}\n```\n\n## Adjusting Exposure\n\nControl overall brightness:\n\n```tsx\nfunction increaseExposure(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Exposure, 40);\n}\n\nfunction decreaseExposure(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Exposure, -40);\n}\n```\n\n## Adjusting Blur\n\nAdd blur effects:\n\n```tsx\nfunction lightBlur(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Blur, 10);\n}\n\nfunction mediumBlur(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Blur, 30);\n}\n\nfunction heavyBlur(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Blur, 60);\n}\n```\n\n## Adjusting Opacity\n\n```tsx\nfunction makeTransparent(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Opacity, 50);\n}\n\nfunction makeOpaque(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Opacity, 100);\n}\n```\n\n## Fine-Tune Events\n\n### Detect Fine-Tune Changes\n\n```tsx\nfunction finetuneValueChanging(args: any): void {\n console.log('Fine-tune type:', args.finetune);\n console.log('Value:', args.value);\n // args.cancel = true; // Prevent adjustment\n}\n\n\u003cImageEditorComponent finetuneValueChanging={finetuneValueChanging} />\n```\n\n## Advanced Patterns\n\n### Slider-Based Fine-Tuning\n\nConnect slider to fine-tune value:\n\n```tsx\nfunction createBrightnessSlider(): void {\n const slider = document.getElementById('brightness-slider') as HTMLInputElement;\n \n slider.addEventListener('input', (e) => {\n const value = parseInt(e.target.value);\n imgObj.finetuneImage(ImageFinetuneOption.Brightness, value);\n });\n}\n```\n\n### Multiple Adjustments\n\nApply several adjustments:\n\n```tsx\nfunction enhanceImage(): void {\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, 20);\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, 30);\n imgObj.finetuneImage(ImageFinetuneOption.Brightness, 15);\n}\n```\n\n### Reset Specific Adjustment\n\nUndo specific fine-tune:\n\n```tsx\nfunction resetBrightness(): void {\n imgObj.undo(); // Undo last adjustment\n}\n\nfunction resetAll(): void {\n imgObj.reset(); // Reset all changes\n}\n```\n\n### Preset Adjustments\n\nCreate adjustment presets:\n\n```tsx\nconst presets = {\n vivid: [\n { option: ImageFinetuneOption.Saturation, value: 40 },\n { option: ImageFinetuneOption.Contrast, value: 20 }\n ],\n muted: [\n { option: ImageFinetuneOption.Saturation, value: -30 },\n { option: ImageFinetuneOption.Brightness, value: 10 }\n ],\n vintage: [\n { option: ImageFinetuneOption.Hue, value: -20 },\n { option: ImageFinetuneOption.Saturation, value: -20 },\n { option: ImageFinetuneOption.Brightness, value: 5 }\n ]\n};\n\nfunction applyPreset(presetName: string): void {\n presets[presetName].forEach(adj => {\n imgObj.finetuneImage(adj.option, adj.value);\n });\n}\n\n// Usage\napplyPreset('vivid');\n```\n\n### Real-Time Preview\n\nLive adjustment preview:\n\n```tsx\nlet adjustmentValue = 0;\n\nfunction liveAdjust(option: ImageFinetuneOption, value: number): void {\n // Cancel previous and apply new\n imgObj.undo();\n imgObj.finetuneImage(option, value);\n adjustmentValue = value;\n}\n\n// On slider input\nslider.addEventListener('input', (e) => {\n liveAdjust(ImageFinetuneOption.Contrast, parseInt(e.target.value));\n});\n```\n\n### Conditional Fine-Tuning\n\nApply adjustments based on conditions:\n\n```tsx\nfunction smartEnhance(): void {\n const dim = imgObj.getImageDimension();\n \n // If image is large, reduce blur\n if (dim.width > 800) {\n imgObj.finetuneImage(ImageFinetuneOption.Blur, 5);\n } else {\n imgObj.finetuneImage(ImageFinetuneOption.Blur, 10);\n }\n \n // Always increase contrast\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, 15);\n}\n```\n\n### Undo/Redo with Fine-Tuning\n\n```tsx\nlet adjustmentHistory: any[] = [];\n\nfunction recordAdjustment(option: ImageFinetuneOption, value: number): void {\n adjustmentHistory.push({ option, value });\n imgObj.finetuneImage(option, value);\n}\n\nfunction undoAdjustment(): void {\n imgObj.undo();\n adjustmentHistory.pop();\n}\n\nfunction redoAdjustment(): void {\n imgObj.redo();\n adjustmentHistory.push(adjustmentHistory[adjustmentHistory.length - 1]);\n}\n```\n\n### Combined Filter + Fine-Tune\n\nPerfect professional editing workflow:\n\n```tsx\nfunction professionalEnhancement(): void {\n // Apply sepia filter\n imgObj.applyImageFilter(ImageFilterOption.Sepia);\n \n // Fine-tune for better result\n imgObj.finetuneImage(ImageFinetuneOption.Contrast, 10);\n imgObj.finetuneImage(ImageFinetuneOption.Saturation, 5);\n imgObj.finetuneImage(ImageFinetuneOption.Brightness, -5);\n}\n```\n\n### Batch Fine-Tuning\n\nApply list of adjustments:\n\n```tsx\nfunction batchFinetuneImage(adjustments: Array\u003c{option: ImageFinetuneOption, value: number}>): void {\n adjustments.forEach(adj => {\n imgObj.finetuneImage(adj.option, adj.value);\n });\n}\n\n// Usage\nbatchFinetuneImage([\n { option: ImageFinetuneOption.Brightness, value: 20 },\n { option: ImageFinetuneOption.Contrast, value: 15 },\n { option: ImageFinetuneOption.Saturation, value: 25 }\n]);\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6577,"content_sha256":"1276e73fb3ef0c72289d7a3bd327207808f97682843be306c2d950b2d7ca3ba3"},{"filename":"references/fit-width-height.md","content":"# Fit to Width and Height\n\n## Table of Contents\n\n- [Fit to Width](#fit-to-width)\n- [Fit to Height](#fit-to-height)\n- [Fit to Viewport](#fit-to-viewport)\n- [Smart Zoom Patterns](#smart-zoom-patterns)\n\n## Fit to Width\n\n### Zoom to Fit Width\n\nScale image to fit container width:\n\n```tsx\nfunction fitToWidth(): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const scale = containerWidth / dim.width;\n \n imgObj.zoom(scale);\n}\n```\n\n### Calculate Width Zoom\n\n```tsx\nfunction calculateZoomForWidth(containerWidth: number, imageWidth: number): number {\n const padding = 20; // Account for padding/margins\n const availableWidth = containerWidth - padding;\n return availableWidth / imageWidth;\n}\n\n// Usage\nconst zoom = calculateZoomForWidth(800, 1200);\nimgObj.zoom(zoom);\n```\n\n### Fit with Padding\n\n```tsx\nfunction fitToWidthWithPadding(paddingPercent: number = 10): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const availableWidth = containerWidth * (1 - paddingPercent / 100);\n const scale = availableWidth / dim.width;\n \n imgObj.zoom(scale);\n}\n\n// Fit with 10% padding\nfitToWidthWithPadding(10);\n```\n\n## Fit to Height\n\n### Zoom to Fit Height\n\nScale image to fit container height:\n\n```tsx\nfunction fitToHeight(): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerHeight = container.clientHeight;\n const scale = containerHeight / dim.height;\n \n imgObj.zoom(scale);\n}\n```\n\n### Calculate Height Zoom\n\n```tsx\nfunction calculateZoomForHeight(containerHeight: number, imageHeight: number): number {\n const padding = 20;\n const availableHeight = containerHeight - padding;\n return availableHeight / imageHeight;\n}\n\n// Usage\nconst zoom = calculateZoomForHeight(600, 1600);\nimgObj.zoom(zoom);\n```\n\n### Fit with Padding\n\n```tsx\nfunction fitToHeightWithPadding(paddingPercent: number = 10): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerHeight = container.clientHeight;\n const availableHeight = containerHeight * (1 - paddingPercent / 100);\n const scale = availableHeight / dim.height;\n \n imgObj.zoom(scale);\n}\n\n// Fit with 10% padding\nfitToHeightWithPadding(10);\n```\n\n## Fit to Viewport\n\n### Fit Best (Contain)\n\nScale to fit entire image in view:\n\n```tsx\nfunction fitBest(): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n \n const widthScale = containerWidth / dim.width;\n const heightScale = containerHeight / dim.height;\n \n const scale = Math.min(widthScale, heightScale);\n imgObj.zoom(scale);\n}\n```\n\n### Fit to Cover\n\nScale to cover entire viewport:\n\n```tsx\nfunction fitCover(): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n \n const widthScale = containerWidth / dim.width;\n const heightScale = containerHeight / dim.height;\n \n const scale = Math.max(widthScale, heightScale);\n imgObj.zoom(scale);\n}\n```\n\n### Fit Exact\n\nFill viewport exactly (may distort):\n\n```tsx\nfunction fitExact(): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n \n imgObj.zoom(containerWidth / dim.width);\n imgObj.zoom(containerHeight / dim.height);\n}\n```\n\n## Smart Zoom Patterns\n\n### Auto Zoom on Load\n\n```tsx\nconst handleImageOpened = (): void => {\n // Auto-fit on load\n fitBest();\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent fileOpened={handleImageOpened} />\n);\n```\n\n### Responsive Fit\n\n```tsx\nfunction setupResponsiveFit(): void {\n const resizeObserver = new ResizeObserver(() => {\n fitBest();\n });\n \n const container = document.querySelector('.editor-container');\n if (container) {\n resizeObserver.observe(container);\n }\n}\n\n// Usage on component mount\nuseEffect(() => {\n setupResponsiveFit();\n}, []);\n```\n\n### Orientation-Based Fit\n\n```tsx\nfunction fitByOrientation(): void {\n const dim = imgObj.getImageDimension();\n const isPortrait = dim.height > dim.width;\n \n if (isPortrait) {\n fitToHeight();\n } else {\n fitToWidth();\n }\n}\n```\n\n### Zoom with Constraints\n\n```tsx\ninterface ZoomConstraints {\n minZoom: number;\n maxZoom: number;\n}\n\nfunction fitWithConstraints(scale: number, constraints: ZoomConstraints): void {\n const constrainedScale = Math.max(\n constraints.minZoom,\n Math.min(scale, constraints.maxZoom)\n );\n \n imgObj.zoom(constrainedScale);\n}\n\n// Usage\nconst constraints: ZoomConstraints = { minZoom: 0.1, maxZoom: 3 };\nfitWithConstraints(1.5, constraints);\n```\n\n### Fit to Specific Aspect Ratio\n\n```tsx\nfunction fitToAspectRatio(targetAspect: number): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n const containerAspect = containerWidth / containerHeight;\n \n let scale: number;\n \n if (containerAspect > targetAspect) {\n // Container wider\n scale = containerHeight / dim.height;\n } else {\n // Container taller\n scale = containerWidth / dim.width;\n }\n \n imgObj.zoom(scale);\n}\n\n// Fit to 16:9\nfitToAspectRatio(16 / 9);\n```\n\n### Fit with Animation\n\n```tsx\nfunction fitWithAnimation(targetScale: number, duration: number = 500): void {\n const startScale = imgObj.zoom();\n const startTime = Date.now();\n \n function animate(): void {\n const elapsed = Date.now() - startTime;\n const progress = Math.min(elapsed / duration, 1);\n \n // Easing function\n const eased = progress \u003c 0.5\n ? 2 * progress * progress\n : -1 + (4 - 2 * progress) * progress;\n \n const currentScale = startScale + (targetScale - startScale) * eased;\n imgObj.zoom(currentScale);\n \n if (progress \u003c 1) {\n requestAnimationFrame(animate);\n }\n }\n \n animate();\n}\n\n// Usage\nfitWithAnimation(1.5, 500);\n```\n\n### Fit with Transition\n\n```tsx\nfunction fitWithTransition(action: () => void, duration: number = 300): void {\n const editor = document.querySelector('.editor-container');\n if (editor) {\n (editor as HTMLElement).style.transition = `transform ${duration}ms ease-in-out`;\n }\n \n action();\n \n setTimeout(() => {\n if (editor) {\n (editor as HTMLElement).style.transition = '';\n }\n }, duration);\n}\n\n// Usage\nfitWithTransition(() => fitBest(), 300);\n```\n\n### Smart Fit Strategy\n\n```tsx\nenum FitStrategy {\n Auto = 'auto',\n Width = 'width',\n Height = 'height',\n Contain = 'contain'\n}\n\nfunction smartFit(strategy: FitStrategy = FitStrategy.Auto): void {\n const dim = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container');\n \n if (!container) return;\n \n const containerWidth = container.clientWidth;\n const containerHeight = container.clientHeight;\n \n switch (strategy) {\n case FitStrategy.Width:\n fitToWidth();\n break;\n case FitStrategy.Height:\n fitToHeight();\n break;\n case FitStrategy.Contain:\n fitBest();\n break;\n case FitStrategy.Auto:\n // Auto-select best strategy\n const isPortrait = dim.height > dim.width;\n const isLandscape = dim.width > dim.height;\n \n if (isPortrait) {\n fitToHeight();\n } else if (isLandscape) {\n fitToWidth();\n } else {\n fitBest();\n }\n break;\n }\n}\n\n// Usage\nsmartFit(FitStrategy.Auto);\n```\n\n### Keyboard Shortcuts for Fit\n\n```tsx\nconst fitKeyboardShortcuts: Record\u003cstring, () => void> = {\n 'f': fitBest,\n 'w': fitToWidth,\n 'h': fitToHeight,\n 'c': fitCover\n};\n\ndocument.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.altKey && fitKeyboardShortcuts[e.key]) {\n e.preventDefault();\n fitKeyboardShortcuts[e.key]();\n }\n});\n```\n\n### Fit with Toolbar Integration\n\n```tsx\nconst customToolbar = [\n 'Open',\n 'Save',\n {\n id: 'fit-width',\n text: 'Fit Width',\n tooltipText: 'Fit to Width'\n },\n {\n id: 'fit-height',\n text: 'Fit Height',\n tooltipText: 'Fit to Height'\n },\n {\n id: 'fit-best',\n text: 'Fit Best',\n tooltipText: 'Fit Best'\n }\n];\n\nconst handleToolbarClick = (args: any): void => {\n switch (args.id) {\n case 'fit-width':\n fitToWidth();\n break;\n case 'fit-height':\n fitToHeight();\n break;\n case 'fit-best':\n fitBest();\n break;\n }\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent\n toolbar={customToolbar}\n toolbarItemClick={handleToolbarClick}\n />\n);\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9258,"content_sha256":"e3350030c3d7d3e9211ab1af9f5df65867ab4b4c398a9ee096ab1365f7a90712"},{"filename":"references/frame-decoration.md","content":"# Frame Decoration\n\n## Table of Contents\n\n- [Frame Types](#frame-types)\n- [Apply Frame](#apply-frame)\n- [Frame Customization](#frame-customization)\n- [Frame Events](#frame-events)\n- [Advanced Patterns](#advanced-patterns)\n\n## Frame Types\n\nThe Image Editor supports 5 frame types:\n\n| Frame Type | Description | Use Case |\n|-----------|-------------|----------|\n| Mat | Solid border with inner bevel | Professional photos |\n| Bevel | 3D beveled border | Formal documents |\n| Line | Simple line border | Minimalist design |\n| Inset | Pressed/embedded appearance | Classic photos |\n| Hook | Decorative hook-style frame | Artistic images |\n\n## Apply Frame\n\n### Mat Frame\n\nClassic solid border:\n\n```tsx\nimport { FrameType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyMatFrame(): void {\n imgObj.drawFrame(\n FrameType.Mat,\n '#CCCCCC', // Color\n '', // gradientColor\n 20 // size as percentage\n );\n}\n```\n\n### Bevel Frame\n\n3D beveled effect:\n\n```tsx\nimport { FrameType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyBevelFrame(): void {\n imgObj.drawFrame(\n FrameType.Bevel,\n '#999999',\n '',\n 15\n );\n}\n```\n\n### Line Frame\n\nSimple border:\n\n```tsx\nimport { FrameType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyLineFrame(): void {\n imgObj.drawFrame(\n FrameType.Line,\n '#000000',\n '',\n 10\n );\n}\n```\n\n### Inset Frame\n\nEmbedded appearance:\n\n```tsx\nimport { FrameType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyInsetFrame(): void {\n imgObj.drawFrame(\n FrameType.Inset,\n '#666666',\n '',\n 15\n );\n}\n```\n\n### Hook Frame\n\nDecorative frame:\n\n```tsx\nimport { FrameType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyHookFrame(): void {\n imgObj.drawFrame(\n FrameType.Hook,\n '#8B7355',\n '',\n 20\n );\n}\n```\n\n## Frame Customization\n\n### Custom Frame Width\n\nControl frame thickness:\n\n```tsx\nfunction applyCustomFrame(frameType: FrameType, width: number, color: string): void {\n imgObj.drawFrame(frameType, color, '', width);\n}\n\n// Thin frame\napplyCustomFrame(FrameType.Mat, 10, '#CCCCCC');\n\n// Thick frame\napplyCustomFrame(FrameType.Bevel, 80, '#999999');\n\n// Extra thick frame\napplyCustomFrame(FrameType.Hook, 100, '#8B7355');\n```\n\n### Custom Frame Color\n\nSelect frame color:\n\n```tsx\nconst frameColors = {\n light: '#EEEEEE',\n medium: '#CCCCCC',\n dark: '#666666',\n gold: '#FFD700',\n silver: '#C0C0C0',\n wood: '#8B4513'\n};\n\nfunction applyColoredFrame(colorName: keyof typeof frameColors): void {\n imgObj.drawFrame(\n FrameType.Mat,\n frameColors[colorName],\n '',\n 40\n );\n}\n\n// Apply gold frame\napplyColoredFrame('gold');\n```\n\n### Dynamic Frame Properties\n\n```tsx\ninterface FrameConfig {\n type: FrameType;\n width: number;\n color: string;\n}\n\nfunction applyDynamicFrame(config: FrameConfig): void {\n imgObj.drawFrame(config.type, config.width, config.color);\n}\n\n// Usage\nconst config: FrameConfig = {\n type: FrameType.Bevel,\n width: 50,\n color: '#C0C0C0'\n};\n\napplyDynamicFrame(config);\n```\n\n## Frame Events\n\n### Capturing Frame Events\n\n```tsx\nconst handleFrameDrawing = (args: any): void => {\n console.log('Frame applied:', {\n type: args.frameType,\n width: args.width,\n color: args.color\n });\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent\n onFrameChange={handleFrameDrawing}\n />\n);\n```\n\n### Before Frame Application\n\n```tsx\nconst handleBeforeFrame = (args: any): void => {\n // Validate or modify frame before applying\n if (args.width > 100) {\n console.warn('Frame width exceeds maximum');\n args.cancel = true;\n }\n};\n```\n\n## Advanced Patterns\n\n### Frame Presets\n\n```tsx\ninterface FramePreset {\n name: string;\n type: FrameType;\n width: number;\n color: string;\n}\n\nconst framePresets: FramePreset[] = [\n {\n name: 'Classic',\n type: FrameType.Mat,\n width: 30,\n color: '#8B8B8B'\n },\n {\n name: 'Elegant',\n type: FrameType.Bevel,\n width: 40,\n color: '#C0C0C0'\n },\n {\n name: 'Modern',\n type: FrameType.Line,\n width: 10,\n color: '#000000'\n },\n {\n name: 'Vintage',\n type: FrameType.Hook,\n width: 50,\n color: '#8B7355'\n },\n {\n name: 'Minimal',\n type: FrameType.Line,\n width: 5,\n color: '#CCCCCC'\n }\n];\n\nfunction applyFramePreset(presetName: string): void {\n const preset = framePresets.find(p => p.name === presetName);\n if (preset) {\n imgObj.drawFrame(preset.type, preset.color, '', preset.width);\n }\n}\n\n// Usage\napplyFramePreset('Elegant');\n```\n\n### Frame by Use Case\n\n```tsx\nenum ImageCategory {\n Portrait = 'portrait',\n Landscape = 'landscape',\n Square = 'square',\n Document = 'document'\n}\n\nfunction getAppropriateFrame(category: ImageCategory): FramePreset {\n const frameMap: { [key in ImageCategory]: FramePreset } = {\n [ImageCategory.Portrait]: {\n name: 'Portrait',\n type: FrameType.Bevel,\n width: 35,\n color: '#8B7355'\n },\n [ImageCategory.Landscape]: {\n name: 'Landscape',\n type: FrameType.Mat,\n width: 30,\n color: '#C0C0C0'\n },\n [ImageCategory.Square]: {\n name: 'Square',\n type: FrameType.Hook,\n width: 40,\n color: '#FFD700'\n },\n [ImageCategory.Document]: {\n name: 'Document',\n type: FrameType.Line,\n width: 10,\n color: '#000000'\n }\n };\n \n return frameMap[category];\n}\n\nfunction autoSelectFrame(): void {\n const dim = imgObj.getImageDimension();\n let category: ImageCategory;\n \n if (dim.width > dim.height) {\n category = ImageCategory.Landscape;\n } else if (dim.height > dim.width) {\n category = ImageCategory.Portrait;\n } else {\n category = ImageCategory.Square;\n }\n \n const frame = getAppropriateFrame(category);\n imgObj.drawFrame(frame.type, frame.width, frame.color);\n}\n```\n\n### Responsive Frame Width\n\nAdjust frame based on image size:\n\n```tsx\nfunction applyResponsiveFrame(baseWidth: number): void {\n const dim = imgObj.getImageDimension();\n \n // Scale frame width proportionally to image size\n const scale = Math.min(dim.width, dim.height) / 1000;\n const scaledWidth = Math.round(baseWidth * scale);\n \n imgObj.drawFrame(FrameType.Mat, '#CCCCCC', '', scaledWidth);\n}\n\n// Frame scales with image size\napplyResponsiveFrame(50);\n```\n\n### Frame with Color Palette\n\n```tsx\ninterface ColorPalette {\n light: string;\n medium: string;\n dark: string;\n accent: string;\n}\n\nconst palettes: { [key: string]: ColorPalette } = {\n warm: {\n light: '#FFE4C4',\n medium: '#D2691E',\n dark: '#8B4513',\n accent: '#FF8C00'\n },\n cool: {\n light: '#ADD8E6',\n medium: '#4682B4',\n dark: '#191970',\n accent: '#00CED1'\n },\n neutral: {\n light: '#E8E8E8',\n medium: '#808080',\n dark: '#2F2F2F',\n accent: '#C0C0C0'\n }\n};\n\nfunction applyPaletteFrame(paletteName: string, toneLevel: 'light' | 'medium' | 'dark'): void {\n const palette = palettes[paletteName];\n if (palette) {\n imgObj.drawFrame(FrameType.Mat, palette[toneLevel], '', 35);\n }\n}\n\n// Usage\napplyPaletteFrame('warm', 'dark');\n```\n\n### Frame Combination\n\n```tsx\nfunction applyDoubleFrame(): void {\n // Apply outer frame\n imgObj.drawFrame(FrameType.Bevel, '#8B7355', '', 40);\n \n // Inner frame effect would require additional processing\n}\n\nfunction applyStyledFrame(thickness: number, style: 'solid' | 'decorative' | 'modern'): void {\n const styleConfig = {\n solid: { type: FrameType.Mat, color: '#808080' },\n decorative: { type: FrameType.Hook, color: '#8B7355' },\n modern: { type: FrameType.Line, color: '#000000' }\n };\n \n const config = styleConfig[style];\n imgObj.drawFrame(config.type, thickness, config.color);\n}\n\n// Usage\napplyStyledFrame(30, 'decorative');\n```\n\n### Frame Styles by Context\n\n```tsx\ninterface FrameContext {\n purpose: 'web' | 'print' | 'social' | 'gallery';\n mood: 'professional' | 'casual' | 'artistic' | 'vintage';\n}\n\nfunction selectFrameByContext(context: FrameContext): void {\n const contextFrames: { [key: string]: FramePreset } = {\n 'web-professional': {\n name: 'Web Pro',\n type: FrameType.Line,\n width: 5,\n color: '#000000'\n },\n 'print-artistic': {\n name: 'Print Art',\n type: FrameType.Hook,\n width: 60,\n color: '#8B7355'\n },\n 'social-casual': {\n name: 'Social',\n type: FrameType.Mat,\n width: 20,\n color: '#FFD700'\n },\n 'gallery-vintage': {\n name: 'Gallery',\n type: FrameType.Bevel,\n width: 50,\n color: '#CD853F'\n }\n };\n \n const key = `${context.purpose}-${context.mood}`;\n const frame = contextFrames[key];\n \n if (frame) {\n imgObj.drawFrame(frame.type, frame.width, frame.color);\n }\n}\n\n// Usage\nselectFrameByContext({\n purpose: 'print',\n mood: 'artistic'\n});\n```\n\n### Frame Undo/Redo Integration\n\n```tsx\nlet appliedFrames: FramePreset[] = [];\n\nfunction applyFrameWithHistory(preset: FramePreset): void {\n appliedFrames.push(preset);\n imgObj.drawFrame(preset.type, preset.width, preset.color);\n}\n\nfunction undoFrame(): void {\n if (appliedFrames.length > 0) {\n appliedFrames.pop();\n imgObj.undo();\n }\n}\n\nfunction redoFrame(): void {\n if (appliedFrames.length > 0) {\n const frame = appliedFrames[appliedFrames.length - 1];\n imgObj.drawFrame(frame.type, frame.width, frame.color);\n }\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9244,"content_sha256":"5e03cc92131b6fd127fe94b2b977684ca1e112161a0ce135bad7a390985d1969"},{"filename":"references/freehand-drawing.md","content":"# Freehand Drawing\n\n## Table of Contents\n- [Enable Freehand Drawing](#enable-freehand-drawing)\n- [Stroke Customization](#stroke-customization)\n- [Managing Drawings](#managing-drawings)\n- [Drawing Events](#drawing-events)\n\n## Enable Freehand Drawing\n\n### Start Drawing\n\nEnable freehand drawing mode:\n\n```tsx\nfunction startDrawing(): void {\n imgObj.freeHandDraw(true);\n}\n```\n\n### Stop Drawing\n\nDisable freehand drawing mode:\n\n```tsx\nfunction stopDrawing(): void {\n imgObj.freeHandDraw(false);\n}\n```\n\n### Toggle Drawing Mode\n\nSwitch drawing on/off:\n\n```tsx\nlet drawingEnabled = false;\n\nfunction toggleDrawing(): void {\n drawingEnabled = !drawingEnabled;\n imgObj.freeHandDraw(drawingEnabled);\n}\n```\n\n## Stroke Customization\n\n### Customize Stroke via Event\n\nModify stroke properties when drawing:\n\n```tsx\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n args.currentShapeSettings.strokeColor = 'red';\n args.currentShapeSettings.strokeWidth = 5;\n }\n}\n\n\u003cImageEditorComponent shapeChanging={shapeChanging} />\n```\n\n### Change Stroke Color\n\nSet custom stroke color for drawings:\n\n```tsx\nfunction drawWithRedStroke(): void {\n const customStroke = { strokeColor: 'red' };\n \n function shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n args.currentShapeSettings.strokeColor = customStroke.strokeColor;\n }\n }\n \n imgObj.freeHandDraw(true);\n}\n```\n\n### Change Stroke Width\n\nAdjust line thickness:\n\n```tsx\nlet strokeWidth = 2;\n\nfunction increaseStroke(): void {\n strokeWidth += 1;\n}\n\nfunction decreaseStroke(): void {\n if (strokeWidth > 1) {\n strokeWidth -= 1;\n }\n}\n\nfunction applyStroke(): void {\n function shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n args.currentShapeSettings.strokeWidth = strokeWidth;\n }\n }\n}\n```\n\n### Multiple Stroke Presets\n\nOffer predefined stroke styles:\n\n```tsx\nconst strokePresets = {\n thin: { color: 'black', width: 1 },\n normal: { color: 'black', width: 3 },\n bold: { color: 'black', width: 5 },\n highlight: { color: 'yellow', width: 8 }\n};\n\nfunction applyStrokePreset(preset: string): void {\n const style = strokePresets[preset];\n \n function shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n args.currentShapeSettings.strokeColor = style.color;\n args.currentShapeSettings.strokeWidth = style.width;\n }\n }\n \n imgObj.freeHandDraw(true);\n}\n```\n\n## Managing Drawings\n\n### Get All Drawings\n\nRetrieve all freehand drawing annotations:\n\n```tsx\nfunction getAllDrawings(): void {\n const shapes = imgObj.getShapeSettings();\n const drawings = shapes.filter(s => s.type === 'FreehandDraw');\n console.log('Freehand drawings:', drawings);\n}\n```\n\n### Delete Drawing\n\nRemove freehand annotation by shape ID:\n\n```tsx\nfunction deleteDrawing(): void {\n imgObj.deleteShape('pen_1');\n}\n```\n\n### Delete Last Drawing\n\nRemove the most recently added drawing:\n\n```tsx\nfunction deleteLastDrawing(): void {\n const shapes = imgObj.getShapeSettings();\n if (shapes.length > 0) {\n const lastDrawing = shapes[shapes.length - 1];\n if (lastDrawing.type === 'FreehandDraw') {\n imgObj.deleteShape(lastDrawing.id);\n }\n }\n}\n```\n\n### Clear All Drawings\n\nDelete all freehand annotations:\n\n```tsx\nfunction clearAllDrawings(): void {\n const shapes = imgObj.getShapeSettings();\n shapes\n .filter(s => s.type === 'FreehandDraw')\n .forEach(s => imgObj.deleteShape(s.id));\n}\n```\n\n### Select Specific Drawing\n\nHighlight a drawing for editing:\n\n```tsx\nfunction selectDrawing(drawingId: string): void {\n const shapes = imgObj.getShapeSettings();\n const drawing = shapes.find(s => s.id === drawingId);\n if (drawing) {\n drawing.isSelected = true;\n imgObj.updateShape(drawing);\n }\n}\n```\n\n## Drawing Events\n\n### Shape Changing Event\n\nReact to drawing modifications:\n\n```tsx\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n console.log('Drawing stroke color:', args.currentShapeSettings.strokeColor);\n console.log('Drawing stroke width:', args.currentShapeSettings.strokeWidth);\n }\n}\n\n\u003cImageEditorComponent shapeChanging={shapeChanging} />\n```\n\n### Track Drawing Count\n\nMonitor number of active drawings:\n\n```tsx\nlet drawingCount = 0;\n\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw' && args.action === 'insert') {\n drawingCount++;\n console.log(`Drawing #${drawingCount} created`);\n }\n}\n```\n\n## Advanced Patterns\n\n### Artistic Styles\n\nApply different artistic styles to drawings:\n\n```tsx\nconst artisticStyles = {\n sketch: { color: '#444', width: 2, opacity: 0.7 },\n marker: { color: '#FF6B6B', width: 6, opacity: 0.8 },\n pen: { color: '#000', width: 1, opacity: 1 }\n};\n\nfunction applyArtisticStyle(style: string): void {\n const styleConfig = artisticStyles[style];\n \n function shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n args.currentShapeSettings.strokeColor = styleConfig.color;\n args.currentShapeSettings.strokeWidth = styleConfig.width;\n }\n }\n \n imgObj.freeHandDraw(true);\n}\n```\n\n### Annotate and Markup Workflow\n\nCombined drawing and text annotation:\n\n```tsx\nfunction markupImage(): void {\n // Add text label\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(dimension.x + 20, dimension.y + 20, 'Review:');\n \n // Enable drawing for marks\n imgObj.freeHandDraw(true);\n}\n\nfunction completeMarkup(): void {\n imgObj.freeHandDraw(false);\n \n // Get all annotations\n const shapes = imgObj.getShapeSettings();\n console.log('Marked up image with', shapes.length, 'annotations');\n}\n```\n\n### Drawing History\n\nTrack drawings in undo/redo stack:\n\n```tsx\nfunction undoLastDrawing(): void {\n imgObj.undo(); // Undo last drawing\n}\n\nfunction redoLastDrawing(): void {\n imgObj.redo(); // Redo last drawing\n}\n```\n\n### Conditional Drawing\n\nAllow drawing only under certain conditions:\n\n```tsx\nlet allowDrawing = false;\n\nfunction enableDrawingMode(): void {\n allowDrawing = true;\n imgObj.freeHandDraw(true);\n}\n\nfunction disableDrawingMode(): void {\n allowDrawing = false;\n imgObj.freeHandDraw(false);\n}\n\nfunction shapeChanging(args: any): void {\n if (!allowDrawing && args.currentShapeSettings.type === 'FreehandDraw') {\n args.cancel = true;\n }\n}\n```\n\n### Export Drawings as Data\n\nSave drawing data for later use:\n\n```tsx\nfunction exportDrawings(): void {\n const shapes = imgObj.getShapeSettings();\n const drawings = shapes\n .filter(s => s.type === 'FreehandDraw')\n .map(d => ({\n id: d.id,\n stroke: d.strokeColor,\n width: d.strokeWidth\n }));\n \n const json = JSON.stringify(drawings);\n localStorage.setItem('drawings', json);\n}\n\nfunction importDrawings(): void {\n const json = localStorage.getItem('drawings');\n if (json) {\n const drawings = JSON.parse(json);\n console.log('Available drawings:', drawings);\n }\n}\n```\n\n### Drawing Constraints\n\nLimit drawing to specific areas:\n\n```tsx\nlet drawingArea = { x: 50, y: 50, width: 400, height: 300 };\n\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'FreehandDraw') {\n // Check if drawing is within bounds\n const shape = args.currentShapeSettings;\n if (shape.x! \u003c drawingArea.x || shape.x! > drawingArea.x + drawingArea.width) {\n args.cancel = true;\n }\n }\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7455,"content_sha256":"f09f497415a3e2a549580f859342a049a9eaabe173afd38643c896b3d126e7f1"},{"filename":"references/getting-started.md","content":"# Getting Started with Image Editor\n\n## Table of Contents\n- [Installation](#installation)\n- [CSS Setup](#css-setup)\n- [Basic Component](#basic-component)\n- [Initialization](#initialization)\n\n## Installation\n\nThe Syncfusion React Image Editor is available as an npm package. Install it using your preferred package manager.\n\n### Using npm\n\n```bash\nnpm install @syncfusion/ej2-react-image-editor --save\n```\n\n### Vite Setup\n\nCreate a new React application with Vite for faster development:\n\n```bash\nnpm create vite@latest my-app -- --template react\ncd my-app\nnpm run dev\n```\n\nThen install the Image Editor package:\n\n```bash\nnpm install @syncfusion/ej2-react-image-editor --save\n```\n\n## CSS Setup\n\nAdd the required CSS files to your `src/App.css` for styling the Image Editor and its dependencies:\n\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/image-editor/index.css\";\n```\n\nImport this CSS file in your `App.tsx`:\n\n```tsx\nimport './App.css';\n```\n\n## Basic Component\n\nHere's a minimal setup for the Image Editor:\n\n```tsx\nimport { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';\nimport React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv id=\"container\">\n \u003cImageEditorComponent width=\"550px\" height=\"350px\" />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Initialization\n\nTo initialize the Image Editor with an image on component creation, use the `created` event:\n\n```tsx\nimport { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';\nimport { Browser } from '@syncfusion/ej2-base';\nimport React from 'react';\nimport './App.css';\n\nfunction App() {\n let imgObj: ImageEditorComponent;\n\n function imageEditorCreated(): void {\n // Detect device and load appropriate image\n if (Browser.isDevice) {\n imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/flower.jpeg');\n } else {\n imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/bridge.jpeg');\n }\n }\n\n return (\n \u003cdiv id=\"container\">\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img }}\n width=\"550px\"\n height=\"350px\"\n created={imageEditorCreated}\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Running the Application\n\nStart your development server:\n\n```bash\nnpm run dev\n```\n\nThe application will compile and serve at `http://localhost:5173` (for Vite).\n\n## Key Properties in Setup\n\n| Property | Purpose |\n|----------|---------|\n| `width` | Sets the canvas width (e.g., \"550px\", \"100%\") |\n| `height` | Sets the canvas height (e.g., \"350px\", \"100%\") |\n| `toolbar` | Customize toolbar items (default: all built-in items) |\n| `created` | Event fired when component is ready |\n| `ref` | Access component instance for method calls |\n\n## Next Steps\n\n- Open images using the [opening-saving-images.md](./opening-saving-images.md) reference\n- Apply transformations with [transform-rotate-flip.md](./transform-rotate-flip.md)\n- Add annotations with [text-annotations.md](./text-annotations.md), [shape-annotations.md](./shape-annotations.md), or [freehand-drawing.md](./freehand-drawing.md)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3139,"content_sha256":"4be6a6d488f4a18ac86fd11302a44ef683936ddd55a7de73fa9d747d12f44fe9"},{"filename":"references/image-annotations.md","content":"# Image Annotations\n\n## Adding Image Annotations\n\n### Basic Image Annotation\n\nInsert an image as annotation:\n\n```tsx\nfunction addImage(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://ej2.syncfusion.com/react/documentation/image-editor/images/flower.jpeg',\n dimension.x,\n dimension.y,\n 100, // width\n 80 // height\n );\n}\n```\n\n### Image with Aspect Ratio\n\nMaintain aspect ratio when adding image:\n\n```tsx\nfunction addImageWithAspectRatio(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/logo.png',\n dimension.x + 50,\n dimension.y + 50,\n 100,\n 80,\n true // isAspectRatio - maintains aspect ratio\n );\n}\n```\n\n### Rotated Image Annotation\n\nAdd image rotated by degrees:\n\n```tsx\nfunction addRotatedImage(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/icon.png',\n dimension.x + 100,\n dimension.y + 100,\n 80,\n 80,\n true, // aspect ratio\n 45 // degree rotation\n );\n}\n```\n\n### Image with Opacity\n\nAdd semi-transparent image:\n\n```tsx\nfunction addTransparentImage(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/watermark.png',\n dimension.x,\n dimension.y,\n 150,\n 100,\n true,\n 0,\n 0.5 // opacity (0-1, where 0.5 is 50% transparent)\n );\n}\n```\n\n### Image as Selected Annotation\n\nAdd image in selected state:\n\n```tsx\nfunction addSelectedImage(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/image.jpg',\n dimension.x,\n dimension.y,\n 100,\n 100,\n true,\n 0,\n 1,\n true // isSelected - shows selection handles\n );\n}\n```\n\n## Image Watermarks\n\n### Add Watermark Logo\n\nPlace watermark at specific location:\n\n```tsx\nfunction addWatermark(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/company-logo.png',\n dimension.x + dimension.width - 120,\n dimension.y + dimension.height - 80,\n 100,\n 60,\n true,\n 0,\n 0.6 // Semi-transparent watermark\n );\n}\n```\n\n### Center Watermark\n\nCenter watermark on image:\n\n```tsx\nfunction addCenterWatermark(): void {\n const dimension = imgObj.getImageDimension();\n const centerX = dimension.x + dimension.width / 2 - 50;\n const centerY = dimension.y + dimension.height / 2 - 40;\n \n imgObj.drawImage(\n 'https://example.com/watermark.png',\n centerX,\n centerY,\n 100,\n 80,\n true,\n 0,\n 0.4\n );\n}\n```\n\n### Copyright Badge\n\nAdd copyright image in corner:\n\n```tsx\nfunction addCopyrightBadge(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawImage(\n 'https://example.com/copyright-badge.png',\n dimension.x + 10,\n dimension.y + dimension.height - 50,\n 40,\n 40,\n true,\n 0,\n 0.8\n );\n}\n```\n\n## Managing Image Annotations\n\n### Get All Image Annotations\n\nRetrieve all image annotations:\n\n```tsx\nfunction getAllImages(): void {\n const shapes = imgObj.getShapeSettings();\n const images = shapes.filter(s => s.type === 'Image');\n console.log('Image annotations:', images);\n}\n```\n\n### Delete Image Annotation\n\nRemove image by shape ID:\n\n```tsx\nfunction deleteImage(shapeId: string): void {\n imgObj.deleteShape(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes.length > 0) {\n deleteImage(shapes[0].id);\n}\n```\n\n### Delete All Images\n\nRemove all image annotations:\n\n```tsx\nfunction deleteAllImages(): void {\n const shapes = imgObj.getShapeSettings();\n shapes\n .filter(s => s.type === 'Image')\n .forEach(s => imgObj.deleteShape(s.id));\n}\n```\n\n### Update Image Properties\n\nModify existing image annotation:\n\n```tsx\nfunction updateImageOpacity(shapeId: string, opacity: number): void {\n const shapes = imgObj.getShapeSettings();\n const imageShape = shapes.find(s => s.id === shapeId && s.type === 'Image');\n \n if (imageShape) {\n imageShape.opacity = opacity;\n imgObj.updateShape(imageShape);\n }\n}\n\n// Usage\nupdateImageOpacity('shape_1', 0.3);\n```\n\n## Advanced Patterns\n\n### Multiple Watermarks\n\nLayer multiple watermarks:\n\n```tsx\nfunction addMultipleWatermarks(): void {\n const dimension = imgObj.getImageDimension();\n \n // Top-left logo\n imgObj.drawImage(\n 'https://example.com/logo1.png',\n dimension.x + 10,\n dimension.y + 10,\n 80,\n 60,\n true,\n 0,\n 0.5\n );\n \n // Bottom-right watermark\n imgObj.drawImage(\n 'https://example.com/watermark.png',\n dimension.x + dimension.width - 110,\n dimension.y + dimension.height - 70,\n 100,\n 60,\n true,\n 0,\n 0.4\n );\n \n // Center watermark\n imgObj.drawImage(\n 'https://example.com/center-mark.png',\n dimension.x + dimension.width / 2 - 50,\n dimension.y + dimension.height / 2 - 40,\n 100,\n 80,\n true,\n 0,\n 0.2\n );\n}\n```\n\n### Branded Overlay\n\nAdd branded image overlay:\n\n```tsx\nfunction addBrandedOverlay(): void {\n const dimension = imgObj.getImageDimension();\n \n // Brand bar\n imgObj.drawRectangle(\n dimension.x,\n dimension.y,\n dimension.width,\n 60,\n 0,\n 'transparent',\n '#F0F0F0'\n );\n \n // Brand logo\n imgObj.drawImage(\n 'https://example.com/brand-logo.png',\n dimension.x + 10,\n dimension.y + 10,\n 40,\n 40,\n true\n );\n}\n```\n\n### Rotated Logo Annotation\n\nCombine rotation with positioning:\n\n```tsx\nfunction addRotatedLogo(): void {\n const dimension = imgObj.getImageDimension();\n \n imgObj.drawImage(\n 'https://example.com/logo.png',\n dimension.x + dimension.width / 2,\n dimension.y + dimension.height / 2,\n 120,\n 120,\n true,\n 45, // 45-degree rotation\n 0.6\n );\n}\n```\n\n### Icon Annotation\n\nSmall icon with label:\n\n```tsx\nfunction addIconWithLabel(): void {\n const dimension = imgObj.getImageDimension();\n \n // Icon\n imgObj.drawImage(\n 'https://example.com/icon.png',\n dimension.x + 200,\n dimension.y + 100,\n 40,\n 40,\n true\n );\n \n // Text label\n imgObj.drawText(\n dimension.x + 250,\n dimension.y + 110,\n 'Featured',\n 'Arial',\n 12\n );\n}\n```\n\n### Thumbnail Annotation\n\nAdd thumbnail image for reference:\n\n```tsx\nfunction addThumbnail(): void {\n const dimension = imgObj.getImageDimension();\n \n imgObj.drawRectangle(\n dimension.x + dimension.width - 110,\n dimension.y + 10,\n 100,\n 75,\n 2,\n 'black',\n 'white'\n );\n \n imgObj.drawImage(\n 'https://example.com/thumbnail.jpg',\n dimension.x + dimension.width - 105,\n dimension.y + 15,\n 90,\n 65,\n true\n );\n}\n```\n\n### Duplicate Image Annotation\n\nClone existing image:\n\n```tsx\nfunction duplicateImage(shapeId: string): void {\n const shapes = imgObj.getShapeSettings();\n const original = shapes.find(s => s.id === shapeId && s.type === 'Image');\n \n if (original) {\n // Create a copy offset from the original\n imgObj.drawImage(\n original.src || '',\n (original.x || 0) + 20,\n (original.y || 0) + 20,\n original.width || 100,\n original.height || 100,\n true,\n original.degree || 0,\n original.opacity || 1\n );\n }\n}\n```\n\n### Scale Image Annotation\n\nResize existing image:\n\n```tsx\nfunction scaleImage(shapeId: string, factor: number): void {\n // Use updateShape to modify image dimensions\n // Get current shape first\n const shape = imgObj.getShapeSetting(shapeId);\n \n if (shape && shape.type === 'Image') {\n // Calculate new dimensions\n const currentWidth = shape.width || 100;\n const currentHeight = shape.height || 100;\n const newWidth = currentWidth * factor;\n const newHeight = currentHeight * factor;\n \n // Update via API\n imgObj.updateShape(shapeId, { \n width: newWidth, \n height: newHeight \n });\n }\n}\n\n// Usage\nscaleImage('shape_1', 1.5); // Scale to 150%\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7848,"content_sha256":"20c37ecff13de5dd8fe9efdf11944f000bbf754b22b8cf585831d76df53ed4d5"},{"filename":"references/image-restrictions-validation.md","content":"# Image Restrictions and Validation\n\n## Table of Contents\n\n- [File Type Restrictions](#file-type-restrictions)\n- [Size Restrictions](#size-restrictions)\n- [Dimension Restrictions](#dimension-restrictions)\n- [Validation](#validation)\n- [Error Handling](#error-handling)\n- [Advanced Patterns](#advanced-patterns)\n\n## File Type Restrictions\n\n### Allowed Image Formats\n\n```tsx\nconst allowedFormats = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'];\n\nfunction isValidFormat(filename: string): boolean {\n const extension = filename.split('.').pop()?.toLowerCase();\n return allowedFormats.includes(extension || '');\n}\n\n// Usage\nif (isValidFormat('photo.jpg')) {\n // Proceed with image\n}\n```\n\n### File Extension Validation\n\n```tsx\nconst fileTypeRestrictions = {\n 'jpg': true,\n 'jpeg': true,\n 'png': true,\n 'gif': true,\n 'bmp': true,\n 'svg': true,\n 'webp': true\n};\n\nfunction validateFileExtension(file: File): boolean {\n const extension = file.name.split('.').pop()?.toLowerCase();\n return extension ? fileTypeRestrictions[extension as keyof typeof fileTypeRestrictions] : false;\n}\n\n// Usage\nconst fileInput = document.querySelector('input[type=\"file\"]');\nif (fileInput) {\n fileInput.addEventListener('change', (e: Event) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (file && !validateFileExtension(file)) {\n alert('Invalid file format. Please use JPG, PNG, GIF, BMP, or WebP');\n }\n });\n}\n```\n\n### MIME Type Validation\n\n```tsx\nfunction validateMimeType(file: File): boolean {\n const validMimeTypes = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/bmp',\n 'image/svg+xml',\n 'image/webp'\n ];\n \n return validMimeTypes.includes(file.type);\n}\n\n// Usage\nconst file = new File([''], 'image.jpg', { type: 'image/jpeg' });\nif (validateMimeType(file)) {\n // File is valid\n}\n```\n\n## Size Restrictions\n\n### Maximum File Size\n\n```tsx\nconst MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB\n\nfunction validateFileSize(file: File): { valid: boolean; message?: string } {\n if (file.size > MAX_FILE_SIZE) {\n return {\n valid: false,\n message: `File size exceeds ${MAX_FILE_SIZE / (1024 * 1024)} MB limit`\n };\n }\n return { valid: true };\n}\n\n// Usage\nconst file = new File(['data'], 'image.jpg', { type: 'image/jpeg' });\nconst validation = validateFileSize(file);\nif (!validation.valid) {\n console.log(validation.message);\n}\n```\n\n### Minimum File Size\n\n```tsx\nconst MIN_FILE_SIZE = 1024; // 1 KB\n\nfunction validateMinimumSize(file: File): boolean {\n return file.size >= MIN_FILE_SIZE;\n}\n```\n\n### File Size Constraints\n\n```tsx\ninterface FileSizeConstraints {\n minSize: number;\n maxSize: number;\n}\n\nconst defaultConstraints: FileSizeConstraints = {\n minSize: 1024, // 1 KB\n maxSize: 5 * 1024 * 1024 // 5 MB\n};\n\nfunction validateFileSize(file: File, constraints: FileSizeConstraints): boolean {\n return file.size >= constraints.minSize && file.size \u003c= constraints.maxSize;\n}\n```\n\n## Dimension Restrictions\n\n### Maximum Dimensions\n\n```tsx\ninterface ImageDimensions {\n maxWidth: number;\n maxHeight: number;\n}\n\nconst maxDimensions: ImageDimensions = {\n maxWidth: 4000,\n maxHeight: 4000\n};\n\nfunction validateImageDimensions(width: number, height: number, constraints: ImageDimensions): boolean {\n return width \u003c= constraints.maxWidth && height \u003c= constraints.maxHeight;\n}\n\n// Usage\nconst dim = imgObj.getImageDimension();\nif (!validateImageDimensions(dim.width, dim.height, maxDimensions)) {\n alert('Image dimensions exceed maximum allowed');\n}\n```\n\n### Minimum Dimensions\n\n```tsx\ninterface MinimumDimensions {\n minWidth: number;\n minHeight: number;\n}\n\nconst minDimensions: MinimumDimensions = {\n minWidth: 100,\n minHeight: 100\n};\n\nfunction validateMinimumDimensions(width: number, height: number, constraints: MinimumDimensions): boolean {\n return width >= constraints.minWidth && height >= constraints.minHeight;\n}\n```\n\n### Aspect Ratio Validation\n\n```tsx\ninterface AspectRatioConstraint {\n minRatio: number;\n maxRatio: number;\n}\n\nfunction validateAspectRatio(width: number, height: number, constraint: AspectRatioConstraint): boolean {\n const ratio = width / height;\n return ratio >= constraint.minRatio && ratio \u003c= constraint.maxRatio;\n}\n\n// Usage: 4:3 to 16:9\nconst constraint: AspectRatioConstraint = {\n minRatio: 4 / 3, // 1.33\n maxRatio: 16 / 9 // 1.78\n};\n\nconst dim = imgObj.getImageDimension();\nif (!validateAspectRatio(dim.width, dim.height, constraint)) {\n alert('Image aspect ratio not supported');\n}\n```\n\n## Validation\n\n### Complete File Validation\n\n```tsx\ninterface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\ninterface ValidationConstraints {\n allowedFormats: string[];\n maxFileSize: number;\n maxWidth: number;\n maxHeight: number;\n minWidth: number;\n minHeight: number;\n}\n\nfunction validateImage(file: File, constraints: ValidationConstraints): ValidationResult {\n const errors: string[] = [];\n \n // Check file type\n const ext = file.name.split('.').pop()?.toLowerCase();\n if (!ext || !constraints.allowedFormats.includes(ext)) {\n errors.push(`File format not allowed. Use: ${constraints.allowedFormats.join(', ')}`);\n }\n \n // Check file size\n if (file.size > constraints.maxFileSize) {\n errors.push(`File size exceeds ${constraints.maxFileSize / (1024 * 1024)} MB`);\n }\n \n return {\n valid: errors.length === 0,\n errors\n };\n}\n\n// Usage\nconst constraints: ValidationConstraints = {\n allowedFormats: ['jpg', 'jpeg', 'png', 'webp'],\n maxFileSize: 5 * 1024 * 1024,\n maxWidth: 4000,\n maxHeight: 4000,\n minWidth: 100,\n minHeight: 100\n};\n\nconst result = validateImage(new File([], 'image.jpg'), constraints);\nif (!result.valid) {\n result.errors.forEach(error => console.log(error));\n}\n```\n\n### Before Opening Image\n\n```tsx\nconst handleFileOpened = (file: File): void => {\n const result = validateImage(file, constraints);\n \n if (!result.valid) {\n alert('Image validation failed:\\n' + result.errors.join('\\n'));\n return;\n }\n \n // Load image\n imgObj.open(URL.createObjectURL(file));\n};\n```\n\n## Error Handling\n\n### Invalid File Detection\n\n```tsx\nfunction handleInvalidFile(error: Error): void {\n console.error('Image loading failed:', error.message);\n \n if (error.message.includes('format')) {\n alert('Unsupported image format');\n } else if (error.message.includes('size')) {\n alert('File is too large');\n } else if (error.message.includes('dimension')) {\n alert('Image dimensions invalid');\n } else {\n alert('Failed to load image');\n }\n}\n```\n\n### Graceful Degradation\n\n```tsx\nasync function loadImageWithFallback(url: string, fallbackUrl?: string): Promise\u003cvoid> {\n try {\n imgObj.open(url);\n } catch (error) {\n console.error('Failed to load image:', error);\n \n if (fallbackUrl) {\n try {\n imgObj.open(fallbackUrl);\n } catch (fallbackError) {\n alert('Failed to load both primary and fallback image');\n }\n }\n }\n}\n```\n\n## Advanced Patterns\n\n### Custom Validation Rules\n\n```tsx\ninterface ValidationRule {\n name: string;\n test: (file: File, dimensions?: any) => boolean;\n message: string;\n}\n\nconst customRules: ValidationRule[] = [\n {\n name: 'format',\n test: (file) => ['jpg', 'png'].includes(file.name.split('.').pop()?.toLowerCase() || ''),\n message: 'Only JPG and PNG allowed'\n },\n {\n name: 'size',\n test: (file) => file.size \u003c= 2 * 1024 * 1024,\n message: 'File must be under 2 MB'\n },\n {\n name: 'dimensions',\n test: (file, dim) => dim?.width \u003c= 2000 && dim?.height \u003c= 2000,\n message: 'Image must be under 2000x2000 pixels'\n }\n];\n\nfunction applyCustomValidation(file: File, dimensions?: any): ValidationResult {\n const errors: string[] = [];\n \n customRules.forEach(rule => {\n if (!rule.test(file, dimensions)) {\n errors.push(rule.message);\n }\n });\n \n return {\n valid: errors.length === 0,\n errors\n };\n}\n```\n\n### Validation Presets\n\n```tsx\nenum ValidationPreset {\n Web = 'web',\n Mobile = 'mobile',\n Print = 'print',\n Social = 'social'\n}\n\nconst presets: Record\u003cValidationPreset, ValidationConstraints> = {\n [ValidationPreset.Web]: {\n allowedFormats: ['jpg', 'png', 'webp'],\n maxFileSize: 2 * 1024 * 1024,\n maxWidth: 2000,\n maxHeight: 2000,\n minWidth: 200,\n minHeight: 200\n },\n [ValidationPreset.Mobile]: {\n allowedFormats: ['jpg', 'png', 'webp'],\n maxFileSize: 1 * 1024 * 1024,\n maxWidth: 1200,\n maxHeight: 1600,\n minWidth: 100,\n minHeight: 100\n },\n [ValidationPreset.Print]: {\n allowedFormats: ['jpg', 'png', 'tiff'],\n maxFileSize: 50 * 1024 * 1024,\n maxWidth: 8000,\n maxHeight: 8000,\n minWidth: 800,\n minHeight: 800\n },\n [ValidationPreset.Social]: {\n allowedFormats: ['jpg', 'png'],\n maxFileSize: 5 * 1024 * 1024,\n maxWidth: 1200,\n maxHeight: 1200,\n minWidth: 400,\n minHeight: 400\n }\n};\n\nfunction getPreset(preset: ValidationPreset): ValidationConstraints {\n return presets[preset];\n}\n```\n\n### Batch Validation\n\n```tsx\nasync function validateBatch(files: File[]): Promise\u003cArray\u003c{ file: File; valid: boolean; errors: string[] }>> {\n const constraints = presets[ValidationPreset.Web];\n \n return files.map(file => ({\n file,\n ...validateImage(file, constraints)\n }));\n}\n\n// Usage\nconst files = Array.from(document.querySelector('input[type=\"file\"]')?.files || []);\nconst results = await validateBatch(files);\n\nresults.forEach(result => {\n if (!result.valid) {\n console.log(`${result.file.name}: ${result.errors.join(', ')}`);\n }\n});\n```\n\n### Validation with Warnings\n\n```tsx\ninterface ValidationSeverity {\n level: 'error' | 'warning' | 'info';\n message: string;\n}\n\nfunction validateWithSeverity(file: File, constraints: ValidationConstraints): ValidationSeverity[] {\n const issues: ValidationSeverity[] = [];\n \n // Errors\n if (file.size > constraints.maxFileSize) {\n issues.push({\n level: 'error',\n message: 'File too large'\n });\n }\n \n // Warnings\n if (file.size > constraints.maxFileSize * 0.8) {\n issues.push({\n level: 'warning',\n message: 'File is approaching size limit'\n });\n }\n \n // Info\n issues.push({\n level: 'info',\n message: `File size: ${(file.size / 1024).toFixed(2)} KB`\n });\n \n return issues;\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10251,"content_sha256":"108443a0862071ee8c5e809379a08bfccbe6502199d2cfa95f057b459a83c120"},{"filename":"references/opening-saving-images.md","content":"# Opening and Saving Images\n\n## Table of Contents\n- [Supported Formats](#supported-formats)\n- [Opening Images](#opening-images)\n- [Saving and Exporting](#saving-and-exporting)\n- [Image Events](#image-events)\n- [Advanced Scenarios](#advanced-scenarios)\n\n## Supported Formats\n\n**Supported for Opening:** PNG, JPEG, JPG, SVG, WEBP, BMP (from URLs, files, base64, blobs)\n**Default Save Format:** PNG\n**Supported for Saving:** PNG, JPEG, SVG, WEBP\n\n## Opening Images\n\n### From URL\n\nOpen images from a publicly accessible URL:\n\n```tsx\nfunction imageEditorCreated(): void {\n imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/bridge.jpeg');\n}\n```\n\n### From Base64 String\n\nOpen images stored as base64 encoded strings:\n\n```tsx\nlet base64String: string = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...';\nimgObj.open(base64String);\n```\n\nExport as base64 or blob:\n\n```tsx\nfunction exportImage(): void {\n // Export as PNG file\n imgObj.export('image/png', 'edited-image');\n \n // Or get image data for processing\n const imageData = imgObj.getImageData();\n if (imageData) {\n console.log('Image data captured');\n }\n}\n```\n\n### From Blob\n\nOpen images from blob objects:\n\n```tsx\nfunction openFromBlob(blob: Blob): void {\n // Create object URL from blob\n const blobUrl = URL.createObjectURL(blob);\n imgObj.open(blobUrl);\n \n // Clean up after loading\n setTimeout(() => URL.revokeObjectURL(blobUrl), 1000);\n}\n\nfunction exportToBlob(): void {\n // Export will generate downloadable file\n imgObj.export('image/png', 'edited-image');\n}\n```\n\n### From File Uploader\n\nIntegrate with Syncfusion Uploader for file selection:\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction selected(args: any): void {\n if (args.filesData.length > 0) {\n const reader = new FileReader();\n reader.onload = () => {\n imgObj.open(reader.result);\n };\n reader.readAsDataURL(args.filesData[0].rawFile);\n }\n}\n\nreturn (\n \u003cdiv>\n \u003cUploaderComponent selected={selected} showFileList={false} />\n \u003cImageEditorComponent ref={(img) => { imgObj = img }} />\n \u003c/div>\n);\n```\n\n### From File Manager\n\nUse Syncfusion File Manager for browsing and selecting images:\n\n```tsx\nimport { FileManagerComponent } from '@syncfusion/ej2-react-filemanager';\n\nconst fileOpen = (args: any) => {\n if (args.fileDetails.isFile && args.fileDetails.imageUrl) {\n args.cancel = true;\n imgObj.open(args.fileDetails.imageUrl);\n }\n};\n\nreturn (\n \u003cdiv>\n \u003cFileManagerComponent fileOpen={fileOpen} />\n \u003cImageEditorComponent ref={(img) => { imgObj = img }} />\n \u003c/div>\n);\n```\n\n### From TreeView\n\nSelect images from a hierarchical tree structure:\n\n```tsx\nimport { TreeViewComponent } from '@syncfusion/ej2-react-navigations';\n\nconst clicked = (args: any) => {\n const nodeData = treeView.getTreeData(args.node.getAttribute('data-uid'))[0];\n if (nodeData && nodeData.image) {\n imgObj.open(nodeData.image);\n }\n};\n\nreturn (\n \u003cdiv>\n \u003cTreeViewComponent nodeClicked={clicked} />\n \u003cImageEditorComponent ref={(img) => { imgObj = img }} />\n \u003c/div>\n);\n```\n\n### Open Image from Different Sources\n\nOpen images using the open method with URL or ImageData:\n\n```tsx\n// Open from URL\nimgObj.open('https://example.com/image.jpg');\n\n// Open from base64 string\nimgObj.open('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...');\n\n// Open from blob\nconst blob = new Blob([imageData], { type: 'image/png' });\nconst blobUrl = URL.createObjectURL(blob);\nimgObj.open(blobUrl);\n```\n\n## Saving and Exporting\n\n### Export with Format\n\nExport edited image with specific format and filename:\n\n```tsx\n// Save as PNG\nimgObj.export('image/png', 'my-edited-image');\n\n// Save as JPEG\nimgObj.export('image/jpeg', 'my-edited-image', 0.95);\n\n// Save as SVG\nimgObj.export('image/svg+xml', 'my-edited-image');\n\n// Save as WEBP\nimgObj.export('image/webp', 'my-edited-image');\n```\n\n### Quick Save with Keyboard Shortcut\n\nUsers can press `Ctrl+S` to download the image in its original format.\n\n### Save to Server\n\nExport edited image for storage or transmission:\n\n```tsx\nfunction saveToServer(): void {\n // Export image (triggers download)\n imgObj.export('image/png', 'edited-image');\n \n // For API upload, use export event\n // The export method handles file download automatically\n}\n\nfunction setupCustomExport(): void {\n // Listen to saving event to intercept before export\n const onSaving = (args: any) => {\n console.log('Image being saved', args);\n };\n}\n```\n\n### Save with Format Selection\n\nExport in multiple formats:\n\n```tsx\nfunction exportInFormat(format: 'PNG' | 'JPEG' | 'SVG' | 'WEBP'): void {\n const mimeType = {\n PNG: 'image/png',\n JPEG: 'image/jpeg',\n SVG: 'image/svg+xml',\n WEBP: 'image/webp'\n }[format];\n \n imgObj.export(mimeType, `edited-image.${format.toLowerCase()}`);\n}\n\n// Usage\nexportInFormat('PNG');\nexportInFormat('JPEG');\n```\n\n### Get Image Dimensions\n\nRetrieve edited image dimensions:\n\n```tsx\nfunction getImageDimensions(): void {\n const dimension = imgObj.getImageDimension();\n if (dimension) {\n console.log(`Image size: ${dimension.width}x${dimension.height}`);\n }\n}\n\nfunction resizeAndExport(newWidth: number, newHeight: number): void {\n imgObj.resize(newWidth, newHeight);\n imgObj.export('image/png', 'resized-image');\n}\n```\n\n## Image Events\n\n### File Opened Event\n\nTriggered after image is successfully loaded:\n\n```tsx\nfunction fileOpened(args: any): void {\n console.log('Filename:', args.fileName);\n console.log('Filetype:', args.fileType);\n // Add watermark or apply defaults here\n}\n\n\u003cImageEditorComponent fileOpened={fileOpened} />\n```\n\n### BeforeSave Event\n\nTriggered before image is saved/exported:\n\n```tsx\nfunction beforeSave(args: any): void {\n console.log('About to save image');\n // args.cancel = true; // Prevent default save\n}\n\n\u003cImageEditorComponent beforeSave={beforeSave} />\n```\n\n### Created Event\n\nTriggered when component is initialized:\n\n```tsx\nfunction created(): void {\n console.log('Image Editor ready');\n}\n\n\u003cImageEditorComponent created={created} />\n```\n\n### Destroyed Event\n\nTriggered when component is removed:\n\n```tsx\nfunction destroyed(): void {\n console.log('Image Editor cleaned up');\n}\n\n\u003cImageEditorComponent destroyed={destroyed} />\n```\n\n## Advanced Scenarios\n\n### Add Watermark on Open\n\nAutomatically add watermark when image opens:\n\n```tsx\nfunction fileOpened(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Syncfusion',\n 'Arial',\n 40,\n false,\n false,\n '#80330075' // Semi-transparent color\n );\n}\n\n\u003cImageEditorComponent fileOpened={fileOpened} />\n```\n\n### Custom Save with Server Upload\n\nIntercept save event for custom handling:\n\n```tsx\nfunction onSaving(args: any): void {\n // Handle pre-save logic\n console.log('Image is being saved');\n \n // Export with specific format\n imgObj.export('image/png', 'edited-image');\n \n // Optionally send to server\n fetch('/api/image-saved', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n }).then(res => res.json()).then(data => {\n console.log('Uploaded:', data);\n });\n });\n}\n\n\u003cImageEditorComponent beforeSave={beforeSave} />\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7198,"content_sha256":"7d95c49eb0ca580695f677f8d73a2d7b999083c1091a4cbfd693372602eab658"},{"filename":"references/quick-access-toolbar.md","content":"# Quick Access Toolbar\n\n## Overview\n\nThe Quick Access toolbar provides frequently-used commands for rapid access without navigating the main toolbar.\n\n## Enable Quick Access Toolbar\n\n### Basic Setup\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={['Undo', 'Redo', 'Save']}\n />\n);\n```\n\n### Default Configuration\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={['Undo', 'Redo', 'Open', 'Save']}\n />\n);\n```\n\n## Configure Quick Access Items\n\n### Select Frequently Used Commands\n\n```tsx\nconst quickAccess = [\n 'Undo',\n 'Redo',\n 'Crop',\n 'Rotate Left',\n 'Rotate Right',\n 'Flip Horizontal',\n 'Save'\n];\n\nconst imageEditor = (\n \u003cImageEditorComponent quickAccessToolbar={quickAccess} />\n);\n```\n\n### Organize by Workflow\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={[\n 'Open',\n 'Crop',\n 'Text',\n 'Filters',\n 'Save'\n ]}\n />\n);\n```\n\n## Show/Hide Items\n\n### Toggle Quick Access Toolbar\n\nDynamically show/hide toolbar:\n\n```tsx\nconst [showQuickAccess, setShowQuickAccess] = useState(true);\n\nconst quickAccessToolbar = showQuickAccess\n ? ['Undo', 'Redo', 'Crop', 'Save']\n : [];\n\nreturn (\n \u003c>\n \u003cbutton onClick={() => setShowQuickAccess(!showQuickAccess)}>\n Toggle Quick Access\n \u003c/button>\n \u003cImageEditorComponent quickAccessToolbar={quickAccessToolbar} />\n \u003c/>\n);\n```\n\n### Conditional Items\n\nShow items based on context:\n\n```tsx\nconst [mode, setMode] = useState('basic');\n\nconst quickAccess = mode === 'basic'\n ? ['Open', 'Save', 'Undo', 'Redo']\n : ['Open', 'Save', 'Undo', 'Redo', 'Crop', 'Text', 'Filters', 'Fine-tune'];\n\nreturn (\n \u003cImageEditorComponent quickAccessToolbar={quickAccess} />\n);\n```\n\n## Custom Quick Access Items\n\n### Add Custom Commands\n\n```tsx\nconst customQuickAccess = [\n 'Open',\n 'Save',\n {\n id: 'quick-reset',\n tooltipText: 'Reset to Original',\n prefixIcon: 'e-icon-refresh'\n },\n {\n id: 'quick-grayscale',\n tooltipText: 'Apply Grayscale',\n prefixIcon: 'e-icon-filter'\n }\n];\n\nconst handleQuickAccessClick = (args: any): void => {\n if (args.id === 'quick-reset') {\n imgObj.reset();\n } else if (args.id === 'quick-grayscale') {\n imgObj.applyImageFilter(ImageFilterOption.Grayscale);\n }\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={customQuickAccess}\n toolbarItemClick={handleQuickAccessClick}\n />\n);\n```\n\n## Quick Access Events\n\n### Item Click Handling\n\nCapture quick access interactions:\n\n```tsx\nconst handleQuickAccessItemClick = (args: ToolbarClickEventArgs): void => {\n console.log('Quick access item clicked:', args.id);\n \n // Log usage analytics\n logAnalytics({\n feature: 'quick-access',\n action: args.id,\n timestamp: new Date()\n });\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={['Undo', 'Redo', 'Save']}\n toolbarItemClick={handleQuickAccessItemClick}\n />\n);\n```\n\n### State Tracking\n\nMonitor quick access usage:\n\n```tsx\nconst [quickAccessStats, setQuickAccessStats] = useState({\n undoClicks: 0,\n redoClicks: 0,\n saveClicks: 0\n});\n\nconst handleQuickAccessClick = (args: ToolbarClickEventArgs): void => {\n if (args.id === 'Undo') {\n setQuickAccessStats(prev => ({ ...prev, undoClicks: prev.undoClicks + 1 }));\n } else if (args.id === 'Redo') {\n setQuickAccessStats(prev => ({ ...prev, redoClicks: prev.redoClicks + 1 }));\n } else if (args.id === 'Save') {\n setQuickAccessStats(prev => ({ ...prev, saveClicks: prev.saveClicks + 1 }));\n }\n};\n\nreturn (\n \u003c>\n \u003cImageEditorComponent\n quickAccessToolbar={['Undo', 'Redo', 'Save']}\n toolbarItemClick={handleQuickAccessClick}\n />\n \u003cdiv>Undo: {quickAccessStats.undoClicks} clicks\u003c/div>\n \u003c/>\n);\n```\n\n## Quick Access Patterns\n\n### Minimal Quick Access\n\nShow only critical items:\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={['Undo', 'Redo', 'Save']}\n />\n);\n```\n\n### Extended Quick Access\n\nShow comprehensive quick access:\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n quickAccessToolbar={[\n 'Undo',\n 'Redo',\n 'Open',\n 'Crop',\n 'Rotate Left',\n 'Rotate Right',\n 'Flip Horizontal',\n 'Text',\n 'Filters',\n 'Save'\n ]}\n />\n);\n```\n\n### Task-Based Quick Access\n\nOrganize by workflow:\n\n```tsx\ninterface WorkflowQuickAccess {\n basic: string[];\n editing: string[];\n publishing: string[];\n}\n\nconst workflowAccess: WorkflowQuickAccess = {\n basic: ['Open', 'Undo', 'Redo'],\n editing: ['Crop', 'Rotate', 'Flip', 'Text', 'Filters'],\n publishing: ['Save', 'Export']\n};\n\ninterface WorkflowState {\n currentPhase: 'basic' | 'editing' | 'publishing';\n}\n\nfunction getQuickAccess(workflow: WorkflowState): string[] {\n return workflowAccess[workflow.currentPhase];\n}\n\nconst [workflow, setWorkflow] = useState\u003cWorkflowState>({ currentPhase: 'basic' });\n\nreturn (\n \u003c>\n \u003cImageEditorComponent\n quickAccessToolbar={getQuickAccess(workflow)}\n />\n \u003cbutton onClick={() => setWorkflow({ currentPhase: 'editing' })}>\n Enter Edit Mode\n \u003c/button>\n \u003c/>\n);\n```\n\n### Role-Based Quick Access\n\nTailor for user roles:\n\n```tsx\ntype UserRole = 'viewer' | 'editor' | 'admin';\n\ninterface RoleQuickAccess {\n [role in UserRole]: string[];\n}\n\nconst roleAccess: RoleQuickAccess = {\n viewer: ['Open', 'Zoom In', 'Zoom Out'],\n editor: ['Open', 'Undo', 'Redo', 'Crop', 'Text', 'Save'],\n admin: [\n 'Open',\n 'Undo',\n 'Redo',\n 'Crop',\n 'Text',\n 'Filters',\n 'Fine-tune',\n 'Frame',\n 'Z-Order',\n 'Save'\n ]\n};\n\nfunction renderEditor(role: UserRole): JSX.Element {\n return (\n \u003cImageEditorComponent\n quickAccessToolbar={roleAccess[role]}\n />\n );\n}\n```\n\n### Contextual Quick Access\n\nUpdate based on selected tool:\n\n```tsx\nconst [selectedTool, setSelectedTool] = useState('basic');\n\nconst toolQuickAccess: { [key: string]: string[] } = {\n basic: ['Undo', 'Redo', 'Open', 'Save'],\n crop: ['Undo', 'Redo', 'Crop', 'Save'],\n annotate: ['Undo', 'Redo', 'Text', 'Shapes', 'Save'],\n filter: ['Undo', 'Redo', 'Filters', 'Fine-tune', 'Save']\n};\n\nreturn (\n \u003c>\n \u003cdiv className=\"tool-selector\">\n \u003cbutton onClick={() => setSelectedTool('basic')}>Basic\u003c/button>\n \u003cbutton onClick={() => setSelectedTool('crop')}>Crop\u003c/button>\n \u003cbutton onClick={() => setSelectedTool('annotate')}>Annotate\u003c/button>\n \u003cbutton onClick={() => setSelectedTool('filter')}>Filter\u003c/button>\n \u003c/div>\n \u003cImageEditorComponent\n quickAccessToolbar={toolQuickAccess[selectedTool]}\n />\n \u003c/>\n);\n```\n\n### Keyboard Support\n\nAdd keyboard access to quick access items:\n\n```tsx\nconst quickAccessMap: { [key: string]: () => void } = {\n 'Ctrl+U': () => imgObj.undo(),\n 'Ctrl+R': () => imgObj.redo(),\n 'Ctrl+O': () => openImageDialog(),\n 'Ctrl+S': () => saveImage()\n};\n\nconst handleGlobalKeyDown = (e: KeyboardEvent): void => {\n const shortcut = `${e.ctrlKey ? 'Ctrl+' : ''}${e.key.toUpperCase()}`;\n if (quickAccessMap[shortcut]) {\n e.preventDefault();\n quickAccessMap[shortcut]();\n }\n};\n\nuseEffect(() => {\n window.addEventListener('keydown', handleGlobalKeyDown);\n return () => window.removeEventListener('keydown', handleGlobalKeyDown);\n}, []);\n```\n\n## Best Practices\n\n### Recommended Quick Access\n\nStart with these essential items:\n\n```tsx\nconst recommendedQuickAccess = [\n 'Open',\n 'Undo',\n 'Redo',\n 'Crop',\n 'Save'\n];\n```\n\n### Avoid Quick Access Overload\n\nKeep to 5-7 most-used items:\n\n```tsx\n// Good - focused on essentials\nconst goodQuickAccess = ['Undo', 'Redo', 'Crop', 'Save'];\n\n// Avoid - too many items\nconst poorQuickAccess = [\n 'Open', 'Save', 'Undo', 'Redo', 'Crop', 'Rotate',\n 'Flip', 'Text', 'Shapes', 'Filters', 'Fine-tune'\n];\n```\n\n### Performance Optimization\n\nMinimize items in frequently-updated scenarios:\n\n```tsx\nconst performanceOptimized = ['Undo', 'Redo', 'Save'];\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7860,"content_sha256":"81496b1ef49971d1f644b75078fc3e470dfb7cfa6ed73fa4fea4c86f770b9336"},{"filename":"references/redact-sensitive-info.md","content":"# Redact Sensitive Information\n\n## Table of Contents\n\n- [Redaction Overview](#redaction-overview)\n- [Apply Redaction](#apply-redaction)\n- [Redaction Modes](#redaction-modes)\n- [Management](#management)\n- [Advanced Patterns](#advanced-patterns)\n\n## Redaction Overview\n\nRedaction safely removes or obscures sensitive information from images using blur or pixelation effects.\n\n### Use Cases\n\n- Hide personal information (names, addresses, phone numbers)\n- Redact confidential data in documents\n- Comply with privacy regulations (GDPR, HIPAA)\n- Secure financial information\n- Remove license plates or identification numbers\n\n## Apply Redaction\n\n### Blur Redaction\n\nHide content with blur effect using the redaction API:\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyBlurRedaction(): void {\n imgObj.drawRedact(RedactType.Blur, 100, 100, 300, 150, 20);\n}\n```\n\n### Pixelate Redaction\n\nHide content with pixelation:\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction applyPixelRedaction(): void {\n imgObj.drawRedact(RedactType.Pixelate, 100, 100, 300, 150, 8);\n}\n```\n\n### Use Official Redaction API\n\nRedact sensitive areas using the official API:\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction redactArea(x: number, y: number, width: number, height: number): void {\n // Use blur for standard redaction\n imgObj.drawRedact(RedactType.Blur, x, y, width, height, 20);\n}\n\n// Usage: Redact a social security number area\nredactArea(150, 200, 200, 40);\n```\n\n## Redaction Modes\n\n### Full Blur Redaction\n\nComplete coverage with blur:\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction fullBlurRedact(x: number, y: number, width: number, height: number): void {\n imgObj.drawRedact(RedactType.Blur, x, y, width, height, 30);\n}\n\n// Redact entire name field\nfullBlurRedact(50, 75, 400, 40);\n```\n\n### Full Pixelate Redaction\n\nComplete coverage with pixelation:\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction fullPixelateRedact(x: number, y: number, width: number, height: number): void {\n imgObj.drawRedact(RedactType.Pixelate, x, y, width, height, 10);\n}\n\n// Redact entire name field\nfullPixelateRedact(50, 75, 400, 40);\n```\n\n### Text-Based Redaction\n\nTarget specific text:\n\n```tsx\nfunction redactText(searchText: string, x: number, y: number): void {\n const textWidth = searchText.length * 8; // Approximate\n imgObj.drawRectangle(x, y, textWidth + 10, 25, true, '#000000');\n}\n\n// Redact email address\nredactText('[email protected]', 100, 150);\n```\n\n## Management\n\n### Get Redacted Items\n\nAccess all redactions:\n\n```tsx\nfunction getRedactions(): void {\n const redacts = imgObj.getRedacts();\n \n console.log('Redacted areas:', redacts.length);\n redacts.forEach((redaction, index) => {\n console.log(`Redaction ${index}:`, {\n id: redaction.id,\n x: redaction.x,\n y: redaction.y,\n width: redaction.width,\n height: redaction.height\n });\n });\n}\n```\n\n### Delete Redaction\n\nRemove redaction:\n\n```tsx\nfunction deleteRedaction(redactionId: string): void {\n imgObj.deleteRedact(redactionId);\n}\n```\n\n### Update Redaction\n\nModify existing redaction:\n\n```tsx\nimport { RedactSettings } from '@syncfusion/ej2-react-image-editor';\n\nfunction updateRedaction(redactionId: string, x: number, y: number, width: number, height: number): void {\n // Use updateRedact with proper parameters\n imgObj.updateRedact(redactionId, {\n x: x,\n y: y,\n width: width,\n height: height\n });\n}\n```\n\n### Clear All Redactions\n\nRemove all redactions:\n\n```tsx\nfunction clearAllRedactions(): void {\n const redacts = imgObj.getRedacts();\n redacts.forEach(redaction => {\n imgObj.deleteRedact(redaction.id);\n });\n}\n```\n\n## Advanced Patterns\n\n### Automatic Redaction Zones\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\ninterface RedactionZone {\n name: string;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst redactionZones: RedactionZone[] = [\n { name: 'Name', x: 50, y: 75, width: 400, height: 40 },\n { name: 'SSN', x: 50, y: 120, width: 200, height: 40 },\n { name: 'Phone', x: 50, y: 165, width: 300, height: 40 },\n { name: 'Address', x: 50, y: 210, width: 400, height: 80 }\n];\n\nfunction applyZoneRedactions(): void {\n redactionZones.forEach(zone => {\n imgObj.drawRedact(RedactType.Blur, zone.x, zone.y, zone.width, zone.height, 20);\n });\n}\n```\n\n### Conditional Redaction\n\n```tsx\ninterface RedactionRule {\n field: string;\n condition: (value: string) => boolean;\n zones: RedactionZone[];\n}\n\nconst redactionRules: RedactionRule[] = [\n {\n field: 'email',\n condition: (val) => val.includes('@'),\n zones: [{ name: 'Email', x: 50, y: 150, width: 300, height: 30 }]\n },\n {\n field: 'phone',\n condition: (val) => /\\d{3}-\\d{3}-\\d{4}/.test(val),\n zones: [{ name: 'Phone', x: 50, y: 190, width: 200, height: 30 }]\n },\n {\n field: 'ssn',\n condition: (val) => /\\d{3}-\\d{2}-\\d{4}/.test(val),\n zones: [{ name: 'SSN', x: 50, y: 230, width: 150, height: 30 }]\n }\n];\n\nfunction applyConditionalRedactions(data: Record\u003cstring, string>): void {\n redactionRules.forEach(rule => {\n if (rule.condition(data[rule.field])) {\n rule.zones.forEach(zone => {\n imgObj.drawRectangle(zone.x, zone.y, zone.width, zone.height, true, '#000000');\n });\n }\n });\n}\n```\n\n### Batch Redaction\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nfunction batchRedact(redactionList: Array\u003c{ x: number; y: number; width: number; height: number }>): void {\n redactionList.forEach(rect => {\n imgObj.drawRedact(RedactType.Blur, rect.x, rect.y, rect.width, rect.height, 20);\n });\n}\n\n// Usage\nconst redactions = [\n { x: 50, y: 75, width: 400, height: 40 }, // Name\n { x: 50, y: 120, width: 200, height: 40 }, // SSN\n { x: 50, y: 165, width: 300, height: 40 } // Phone\n];\n\nbatchRedact(redactions);\n```\n\n### Redaction with Tracking\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nclass RedactionTracker {\n private redactions: Array\u003c{ id: string; field: string; timestamp: Date }> = [];\n \n addRedaction(fieldName: string, x: number, y: number, width: number, height: number): void {\n imgObj.drawRedact(RedactType.Blur, x, y, width, height, 20);\n \n const redacts = imgObj.getRedacts();\n const lastRedaction = redacts[redacts.length - 1];\n \n this.redactions.push({\n id: lastRedaction.id,\n field: fieldName,\n timestamp: new Date()\n });\n }\n \n getRedactionHistory(): string {\n return this.redactions\n .map(r => `${r.field} redacted at ${r.timestamp.toISOString()}`)\n .join('\\n');\n }\n \n exportAuditLog(): void {\n const log = this.getRedactionHistory();\n console.log('Audit Log:\\n' + log);\n }\n}\n\nconst tracker = new RedactionTracker();\ntracker.addRedaction('Name', 50, 75, 400, 40);\ntracker.addRedaction('Phone', 50, 165, 300, 40);\ntracker.exportAuditLog();\n```\n\n### Undo Redactions\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nconst redactionHistory: Array\u003c{ zone: RedactionZone; id: string }> = [];\n\nfunction redactZoneWithHistory(zone: RedactionZone): void {\n imgObj.drawRedact(RedactType.Blur, zone.x, zone.y, zone.width, zone.height, 20);\n \n const redacts = imgObj.getRedacts();\n const lastRedaction = redacts[redacts.length - 1];\n \n redactionHistory.push({\n zone: zone,\n id: lastRedaction.id\n });\n}\n\nfunction undoLastRedaction(): void {\n if (redactionHistory.length > 0) {\n const lastRedaction = redactionHistory.pop();\n if (lastRedaction) {\n imgObj.deleteRedact(lastRedaction.id);\n }\n }\n}\n\nfunction redoRedaction(): void {\n imgObj.redo();\n}\n```\n\n### Redaction with Verification\n\n```tsx\nimport { RedactType } from '@syncfusion/ej2-react-image-editor';\n\nclass SecureRedaction {\n private redactedField: Map\u003cstring, string> = new Map();\n \n redactWithVerification(fieldName: string, x: number, y: number, width: number, height: number): void {\n // Mark field as redacted\n this.redactedField.set(fieldName, 'redacted');\n \n // Apply visual redaction\n imgObj.drawRedact(RedactType.Blur, x, y, width, height, 20);\n }\n \n isFullyRedacted(requiredFields: string[]): boolean {\n return requiredFields.every(field => this.redactedField.has(field));\n }\n \n canExport(): boolean {\n return this.redactedField.size > 0 && this.isFullyRedacted(Array.from(this.redactedField.keys()));\n }\n}\n\nconst secureRedaction = new SecureRedaction();\nsecureRedaction.redactWithVerification('Name', 50, 75, 400, 40);\nsecureRedaction.redactWithVerification('SSN', 50, 120, 200, 40);\n\nif (secureRedaction.canExport()) {\n // Safe to export\n}\n```\n\n### Smart Redaction Suggestions\n\n```tsx\ninterface ContentArea {\n type: 'email' | 'phone' | 'ssn' | 'address' | 'credit_card';\n pattern: RegExp;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst contentPatterns: ContentArea[] = [\n {\n type: 'email',\n pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/,\n x: 0,\n y: 0,\n width: 0,\n height: 0\n },\n {\n type: 'phone',\n pattern: /(\\d{3}[-.]?\\d{3}[-.]?\\d{4})/,\n x: 0,\n y: 0,\n width: 0,\n height: 0\n },\n {\n type: 'ssn',\n pattern: /(\\d{3}-\\d{2}-\\d{4})/,\n x: 0,\n y: 0,\n width: 0,\n height: 0\n }\n];\n\nfunction suggestRedactions(content: string): ContentArea[] {\n return contentPatterns.filter(pattern => pattern.pattern.test(content));\n}\n\nfunction applySuggestedRedactions(): void {\n import { RedactType } from '@syncfusion/ej2-react-image-editor';\n \n const suggestions = suggestRedactions('Name: John Doe, Email: [email protected], Phone: 555-123-4567');\n suggestions.forEach(suggestion => {\n imgObj.drawRedact(RedactType.Blur, suggestion.x, suggestion.y, suggestion.width, suggestion.height, 20);\n });\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9903,"content_sha256":"8fd2cfc24a3ef497b5a7b4a96de2994707e9080afaa230acd1e5e10b86927d20"},{"filename":"references/render-in-dialog.md","content":"# Render Image Editor in Dialog\n\n## Table of Contents\n\n- [Dialog Setup](#dialog-setup)\n- [Integration](#integration)\n- [Content Template](#content-template)\n- [Advanced Patterns](#advanced-patterns)\n\n## Dialog Setup\n\n### Basic Dialog Integration\n\n```tsx\nimport { DialogComponent } from '@syncfusion/ej2-react-popups';\nimport { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';\n\nconst ImageEditorDialog = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n \n return (\n \u003c>\n \u003cbutton onClick={() => setIsOpen(true)}>Open Editor\u003c/button>\n \n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n header=\"Image Editor\"\n width=\"800px\"\n height=\"600px\"\n >\n \u003cImageEditorComponent />\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n```\n\n### Dialog with Toolbar\n\n```tsx\nconst EditorDialogWithToolbar = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n \n return (\n \u003c>\n \u003cbutton onClick={() => setIsOpen(true)}>Edit Image\u003c/button>\n \n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n header=\"Image Editor\"\n width=\"1000px\"\n height=\"700px\"\n >\n \u003cdiv className=\"dialog-toolbar\">\n \u003cbutton>Open\u003c/button>\n \u003cbutton>Save\u003c/button>\n \u003cbutton>Close\u003c/button>\n \u003c/div>\n \n \u003cImageEditorComponent />\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n```\n\n## Integration\n\n### Open Image in Dialog\n\n```tsx\ninterface DialogEditorProps {\n imageUrl?: string;\n onSave?: (base64: string) => void;\n onClose?: () => void;\n}\n\nconst ImageEditorDialog: React.FC\u003cDialogEditorProps> = ({\n imageUrl,\n onSave,\n onClose\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n let imgObj: ImageEditor;\n \n const handleOpen = (): void => {\n setIsOpen(true);\n };\n \n const handleImageOpened = (): void => {\n if (imageUrl) {\n imgObj.open(imageUrl);\n }\n };\n \n const handleSave = (): void => {\n // Export the current image\n imgObj.export('image/png', 'edited-image');\n if (onSave) {\n // Note: Use getImageData() for direct data access\n const imageData = imgObj.getImageData();\n }\n setIsOpen(false);\n };\n \n const handleClose = (): void => {\n if (onClose) {\n onClose();\n }\n setIsOpen(false);\n };\n \n return (\n \u003c>\n \u003cbutton onClick={handleOpen}>Edit Image\u003c/button>\n \n \u003cDialogComponent\n visible={isOpen}\n onClose={handleClose}\n header=\"Image Editor\"\n width=\"900px\"\n height=\"700px\"\n buttons={[\n {\n buttonModel: { content: 'Save' },\n onClick: handleSave\n },\n {\n buttonModel: { content: 'Cancel' },\n onClick: handleClose\n }\n ]}\n >\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n fileOpened={handleImageOpened}\n width=\"100%\"\n height=\"100%\"\n />\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n\n// Usage\n\u003cImageEditorDialog\n imageUrl=\"image.jpg\"\n onSave={(base64) => console.log('Saved:', base64)}\n onClose={() => console.log('Closed')}\n/>\n```\n\n### Modal Dialog Pattern\n\n```tsx\nconst ModalImageEditor = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n const [imageData, setImageData] = useState\u003cstring | null>(null);\n let imgObj: ImageEditor;\n \n const handleOpen = (imageUrl: string): void => {\n setImageData(imageUrl);\n setIsOpen(true);\n };\n \n const handleApply = (): void => {\n imgObj.export('image/png', 'edited-image');\n console.log('Changes applied and exported');\n setIsOpen(false);\n };\n \n return (\n \u003c>\n \u003cbutton onClick={() => handleOpen('image.jpg')}>Edit\u003c/button>\n \n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n isModal={true}\n header=\"Image Editor\"\n width=\"900px\"\n height=\"700px\"\n >\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n created={() => {\n if (imageData) imgObj.open(imageData);\n }}\n />\n \n \u003cdiv style={{ marginTop: '10px' }}>\n \u003cbutton onClick={handleApply}>Apply\u003c/button>\n \u003cbutton onClick={() => setIsOpen(false)}>Cancel\u003c/button>\n \u003c/div>\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n```\n\n## Content Template\n\n### Custom Dialog Layout\n\n```tsx\nconst CustomDialogLayout = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n let imgObj: ImageEditor;\n \n return (\n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n header=\"Image Editor\"\n width=\"1200px\"\n height=\"800px\"\n >\n \u003cdiv style={{ display: 'flex', gap: '10px', height: '100%' }}>\n {/* Sidebar */}\n \u003caside style={{ width: '200px', borderRight: '1px solid #ccc' }}>\n \u003ch3>Tools\u003c/h3>\n \u003cul>\n \u003cli>\u003cbutton>Crop\u003c/button>\u003c/li>\n \u003cli>\u003cbutton>Rotate\u003c/button>\u003c/li>\n \u003cli>\u003cbutton>Text\u003c/button>\u003c/li>\n \u003cli>\u003cbutton>Filters\u003c/button>\u003c/li>\n \u003c/ul>\n \u003c/aside>\n \n {/* Main Editor */}\n \u003cmain style={{ flex: 1 }}>\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n width=\"100%\"\n height=\"100%\"\n />\n \u003c/main>\n \u003c/div>\n \u003c/DialogComponent>\n );\n};\n```\n\n### Dialog with Preview\n\n```tsx\nconst DialogWithPreview = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n const [preview, setPreview] = useState\u003cstring | null>(null);\n let imgObj: ImageEditor;\n \n const handlePreview = (): void => {\n const imageData = imgObj.getImageData();\n setPreview(imageData ? 'image-data-captured' : null);\n };\n \n return (\n \u003c>\n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n header=\"Image Editor\"\n width=\"1000px\"\n height=\"600px\"\n >\n \u003cdiv style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>\n {/* Editor */}\n \u003cdiv>\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n width=\"100%\"\n height=\"500px\"\n />\n \u003c/div>\n \n {/* Preview */}\n \u003cdiv>\n \u003ch3>Preview\u003c/h3>\n {preview && \u003cimg src={preview} alt=\"Preview\" style={{ maxWidth: '100%' }} />}\n \u003cbutton onClick={handlePreview}>Update Preview\u003c/button>\n \u003c/div>\n \u003c/div>\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n```\n\n## Advanced Patterns\n\n### Reusable Dialog Editor\n\n```tsx\nclass DialogEditorManager {\n private dialog: DialogComponent | null = null;\n private editor: ImageEditor | null = null;\n \n initialize(dialogId: string): void {\n this.dialog = document.querySelector(`#${dialogId}`) as any;\n }\n \n open(imageUrl: string): void {\n if (this.editor) {\n this.editor.open(imageUrl);\n }\n this.dialog?.show?.();\n }\n \n close(): void {\n this.dialog?.hide?.();\n }\n \n exportImage(filename: string = 'edited-image'): void {\n this.editor?.export('image/png', filename);\n }\n \n clear(): void {\n this.editor?.clearImage();\n }\n}\n\nconst manager = new DialogEditorManager();\nmanager.initialize('editor-dialog');\nmanager.open('image.jpg');\n```\n\n### Multiple Dialogs\n\n```tsx\ninterface EditorDialogState {\n id: string;\n isOpen: boolean;\n imageUrl: string;\n}\n\nconst MultipleDialogEditor = (): JSX.Element => {\n const [dialogs, setDialogs] = useState\u003cEditorDialogState[]>([]);\n \n const addDialog = (): void => {\n setDialogs([\n ...dialogs,\n { id: `dialog-${Date.now()}`, isOpen: true, imageUrl: '' }\n ]);\n };\n \n return (\n \u003c>\n \u003cbutton onClick={addDialog}>Add Editor\u003c/button>\n \n {dialogs.map(dialog => (\n \u003cDialogComponent\n key={dialog.id}\n visible={dialog.isOpen}\n onClose={() => {\n setDialogs(dialogs.filter(d => d.id !== dialog.id));\n }}\n >\n \u003cImageEditorComponent width=\"100%\" height=\"100%\" />\n \u003c/DialogComponent>\n ))}\n \u003c/>\n );\n};\n```\n\n### Dialog with Upload\n\n```tsx\nconst DialogWithUpload = (): JSX.Element => {\n const [isOpen, setIsOpen] = useState(false);\n let imgObj: ImageEditor;\n \n const handleFileUpload = (e: ChangeEvent\u003cHTMLInputElement>): void => {\n const file = e.target.files?.[0];\n if (file) {\n const reader = new FileReader();\n reader.onload = () => {\n imgObj.open(reader.result as string);\n };\n reader.readAsDataURL(file);\n }\n };\n \n return (\n \u003c>\n \u003cDialogComponent\n visible={isOpen}\n onClose={() => setIsOpen(false)}\n header=\"Image Editor\"\n >\n \u003cinput\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n />\n \n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n width=\"100%\"\n height=\"500px\"\n />\n \u003c/DialogComponent>\n \u003c/>\n );\n};\n```\n\n### Dialog with Tabs\n\n```tsx\nconst DialogWithTabs = (): JSX.Element => {\n const [activeTab, setActiveTab] = useState(0);\n let imgObj: ImageEditor;\n \n return (\n \u003cDialogComponent header=\"Image Editor\" width=\"900px\" height=\"700px\">\n \u003cdiv className=\"tabs\">\n \u003cbutton\n className={activeTab === 0 ? 'active' : ''}\n onClick={() => setActiveTab(0)}\n >\n Editor\n \u003c/button>\n \u003cbutton\n className={activeTab === 1 ? 'active' : ''}\n onClick={() => setActiveTab(1)}\n >\n Effects\n \u003c/button>\n \u003cbutton\n className={activeTab === 2 ? 'active' : ''}\n onClick={() => setActiveTab(2)}\n >\n Settings\n \u003c/button>\n \u003c/div>\n \n {activeTab === 0 && (\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img; }}\n width=\"100%\"\n height=\"500px\"\n />\n )}\n \n {activeTab === 1 && (\n \u003cdiv>\n \u003cp>Filter Controls\u003c/p>\n {/* Filter UI */}\n \u003c/div>\n )}\n \n {activeTab === 2 && (\n \u003cdiv>\n \u003cp>Settings\u003c/p>\n {/* Settings UI */}\n \u003c/div>\n )}\n \u003c/DialogComponent>\n );\n};\n```\n\n### Dialog Size Management\n\n```tsx\ninterface DialogSize {\n width: string;\n height: string;\n}\n\nconst ResponsiveDialog = (): JSX.Element => {\n const [size, setSize] = useState\u003cDialogSize>({ width: '80%', height: '80vh' });\n \n const getDialogSize = (): DialogSize => {\n const width = window.innerWidth;\n const height = window.innerHeight;\n \n if (width \u003c 768) {\n return { width: '95%', height: '95vh' };\n } else if (width \u003c 1024) {\n return { width: '85%', height: '85vh' };\n } else {\n return { width: '80%', height: '80vh' };\n }\n };\n \n useEffect(() => {\n setSize(getDialogSize());\n const handleResize = (): void => setSize(getDialogSize());\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n \n return (\n \u003cDialogComponent\n width={size.width}\n height={size.height}\n header=\"Image Editor\"\n >\n \u003cImageEditorComponent width=\"100%\" height=\"100%\" />\n \u003c/DialogComponent>\n );\n};\n```\n\n### Dialog State Persistence\n\n```tsx\nconst PersistentDialog = (): JSX.Element => {\n const [dialogState, setDialogState] = useState(() => {\n const saved = localStorage.getItem('editorDialogState');\n return saved ? JSON.parse(saved) : { isOpen: false };\n });\n \n const updateDialogState = (state: any): void => {\n setDialogState(state);\n localStorage.setItem('editorDialogState', JSON.stringify(state));\n };\n \n return (\n \u003cDialogComponent\n visible={dialogState.isOpen}\n onClose={() => updateDialogState({ isOpen: false })}\n onOpen={() => updateDialogState({ isOpen: true })}\n >\n \u003cImageEditorComponent width=\"100%\" height=\"100%\" />\n \u003c/DialogComponent>\n );\n};\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12055,"content_sha256":"25e186db64ba66f6541bbd110a30d3688dd5c910b367626bfedf589d906df0d7"},{"filename":"references/reset-image.md","content":"# Reset Image\n\n## Overview\n\nThe `reset()` method reverts all edits and returns the image to its original state. Unlike `clearImage()`, which removes the image entirely, `reset()` preserves the loaded image but removes all modifications.\n\n## Reset Image\n\n### Basic Reset\n\n```tsx\nfunction resetImage(): void {\n imgObj.reset();\n}\n```\n\n### Reset with Confirmation\n\n```tsx\nfunction resetWithConfirmation(): void {\n if (window.confirm('Reset all changes? Original image will be restored.')) {\n imgObj.reset();\n }\n}\n```\n\n## Use Cases\n\n### Discard All Edits\n\nCancel editing session:\n\n```tsx\nfunction discardEdits(): void {\n imgObj.reset();\n console.log('All edits discarded, image restored to original');\n}\n```\n\n### Revert to Original\n\n```tsx\nconst handleRevertClick = (): void => {\n imgObj.reset();\n updateUIState('edited', false);\n};\n```\n\n### Start Fresh with Same Image\n\n```tsx\nfunction startOver(): void {\n // Preserve the loaded image, remove all edits\n imgObj.reset();\n}\n```\n\n### Reset Before Export\n\n```tsx\nfunction exportOriginal(): void {\n // Reset to ensure original is exported\n imgObj.reset();\n \n imgObj.export('image/jpeg', 'original');\n}\n```\n\n## Advanced Patterns\n\n### Reset with State Tracking\n\n```tsx\nclass EditorWithReset {\n private isModified: boolean = false;\n \n reset(): void {\n imgObj.reset();\n this.isModified = false;\n this.onResetCallback();\n }\n \n recordEdit(): void {\n this.isModified = true;\n }\n \n private onResetCallback(): void {\n console.log('Image reset to original state');\n }\n \n isEdited(): boolean {\n return this.isModified;\n }\n}\n\nconst editor = new EditorWithReset();\neditor.recordEdit();\neditor.reset();\n```\n\n### Reset with Undo Alternative\n\n```tsx\nfunction undoAllChanges(): void {\n // Option 1: Reset (faster)\n imgObj.reset();\n \n // Option 2: Multiple undo (slower)\n // for (let i = 0; i \u003c 16; i++) {\n // imgObj.undo();\n // }\n}\n```\n\n### Reset with Validation\n\n```tsx\nfunction safeReset(): void {\n const shapes = imgObj.getShapeSettings();\n \n if (shapes.length === 0) {\n console.log('No changes to reset');\n return;\n }\n \n const hasAnnotations = shapes.length > 0;\n \n if (hasAnnotations) {\n const message = 'This will remove all annotations. Continue?';\n if (!confirm(message)) {\n return;\n }\n }\n \n imgObj.reset();\n}\n```\n\n### Reset with History\n\n```tsx\nclass ResetHistory {\n private resetEvents: Array\u003c{ timestamp: Date; message: string }> = [];\n \n reset(): void {\n imgObj.reset();\n this.recordReset();\n }\n \n private recordReset(): void {\n this.resetEvents.push({\n timestamp: new Date(),\n message: 'Image reset to original'\n });\n }\n \n getHistory(): string {\n return this.resetEvents\n .map(e => `${e.timestamp.toISOString()}: ${e.message}`)\n .join('\\n');\n }\n}\n\nconst history = new ResetHistory();\nhistory.reset();\nconsole.log(history.getHistory());\n```\n\n### Reset with Notification\n\n```tsx\nfunction resetWithNotification(): void {\n imgObj.reset();\n \n showNotification({\n type: 'success',\n message: 'Image reset to original',\n duration: 3000\n });\n}\n\ninterface Notification {\n type: 'success' | 'error' | 'warning' | 'info';\n message: string;\n duration: number;\n}\n\nfunction showNotification(notification: Notification): void {\n const element = document.createElement('div');\n element.className = `notification notification-${notification.type}`;\n element.textContent = notification.message;\n \n document.body.appendChild(element);\n \n setTimeout(() => element.remove(), notification.duration);\n}\n```\n\n### Reset Specific Edits\n\n```tsx\nclass SelectiveReset {\n resetAnnotations(): void {\n // Remove all annotations\n const shapes = imgObj.getShapeSettings();\n shapes.forEach(shape => {\n imgObj.deleteShape(shape.id);\n });\n }\n \n resetFilters(): void {\n // Reload without filters\n imgObj.reset();\n }\n \n resetTransforms(): void {\n // Reset rotation, flip, straighten\n imgObj.reset();\n }\n \n resetAll(): void {\n imgObj.reset();\n }\n}\n\nconst selectiveReset = new SelectiveReset();\nselectiveReset.resetAnnotations();\n```\n\n### Reset with Auto-save\n\n```tsx\nasync function resetWithAutoSave(): Promise\u003cvoid> {\n // Save current state before reset\n const imageData = imgObj.getImageData();\n await saveToBackup(imageData);\n \n // Reset\n imgObj.reset();\n}\n\nasync function saveToBackup(): Promise\u003cvoid> {\n // Export and backup current state\n imgObj.export('image/png', 'backup-image');\n \n // Or save metadata\n const dimension = imgObj.getImageDimension();\n localStorage.setItem('backup_metadata', JSON.stringify({\n width: dimension?.width,\n height: dimension?.height,\n timestamp: new Date().toISOString()\n }));\n}\n```\n\n### Reset in Batch Operations\n\n```tsx\nfunction batchResetEditors(editors: ImageEditor[]): void {\n editors.forEach(editor => {\n editor.reset();\n });\n}\n\n// Usage\nconst editors = [imgObj1, imgObj2, imgObj3];\nbatchResetEditors(editors);\n```\n\n### Reset with Keyboard Shortcut\n\n```tsx\nfunction setupResetShortcut(): void {\n document.addEventListener('keydown', (e: KeyboardEvent) => {\n // Ctrl+Shift+Z or Cmd+Shift+Z\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z') {\n e.preventDefault();\n resetImage();\n }\n });\n}\n```\n\n### Reset Timer\n\n```tsx\nclass AutoResetManager {\n private timer: NodeJS.Timeout | null = null;\n private resetAfterMs: number;\n \n constructor(resetAfterMs: number = 3600000) { // 1 hour\n this.resetAfterMs = resetAfterMs;\n }\n \n start(): void {\n this.timer = setTimeout(() => {\n imgObj.reset();\n console.log('Auto-reset triggered');\n }, this.resetAfterMs);\n }\n \n stop(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n \n restart(): void {\n this.stop();\n this.start();\n }\n}\n\nconst autoReset = new AutoResetManager(600000); // 10 minutes\nautoReset.start();\n```\n\n### Reset with UI Update\n\n```tsx\nfunction resetAndUpdateUI(): void {\n // Reset image\n imgObj.reset();\n \n // Update UI state\n updateEditButton(false);\n updateCancelButton(false);\n updateSaveButton(false);\n clearAnnotationPanel();\n clearHistoryPanel();\n \n setEditMode(false);\n}\n\nfunction updateEditButton(enabled: boolean): void {\n const button = document.querySelector('[data-action=\"edit\"]');\n if (button) {\n (button as HTMLButtonElement).disabled = !enabled;\n }\n}\n```\n\n### Reset Before/After Lifecycle\n\n```tsx\nconst handleBeforeReset = (): void => {\n console.log('About to reset...');\n};\n\nconst handleAfterReset = (): void => {\n console.log('Reset complete');\n};\n\nfunction resetWithLifecycle(): void {\n handleBeforeReset();\n imgObj.reset();\n handleAfterReset();\n}\n```\n\n### Conditional Reset\n\n```tsx\ninterface ResetConditions {\n hasChanges: boolean;\n hasAnnotations: boolean;\n hasFilters: boolean;\n}\n\nfunction getResetConditions(): ResetConditions {\n const shapes = imgObj.getShapeSettings();\n \n return {\n hasChanges: shapes.length > 0,\n hasAnnotations: shapes.some(obj => obj.type !== 'Image'),\n hasFilters: false // Would track actual filter state\n };\n}\n\nfunction conditionalReset(): void {\n const conditions = getResetConditions();\n \n if (!conditions.hasChanges) {\n console.log('No changes to reset');\n return;\n }\n \n if (conditions.hasAnnotations) {\n const message = 'Reset will remove annotations. Continue?';\n if (!confirm(message)) {\n return;\n }\n }\n \n imgObj.reset();\n}\n```\n\n### Reset and Export Comparison\n\n```tsx\nclass ImageComparison {\n revertToOriginal(): void {\n imgObj.reset();\n }\n \n exportEdited(): void {\n imgObj.export('image/png', 'edited-image');\n }\n \n getDimension(): void {\n const dim = imgObj.getImageDimension();\n console.log('Image dimensions:', dim.width, 'x', dim.height);\n }\n}\n\nconst comparison = new ImageComparison();\ncomparison.getDimension();\n// ... user edits ...\ncomparison.exportEdited();\ncomparison.revertToOriginal();\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7977,"content_sha256":"12b564da3f59b88b213a90e290d61b2a915bdf6e1097138450e3f1d1b5f66c1a"},{"filename":"references/resize-image.md","content":"# Resize Image\n\n## Table of Contents\n\n- [Basic Resize](#basic-resize)\n- [Resize with Aspect Ratio](#resize-with-aspect-ratio)\n- [Resize Dialog](#resize-dialog)\n- [Programmatic Resize](#programmatic-resize)\n- [Resize Events](#resize-events)\n- [Advanced Patterns](#advanced-patterns)\n\n## Basic Resize\n\n### Resize Without Aspect Ratio\n\nChange image dimensions independently:\n\n```tsx\nconst dim = imgObj.getImageDimension();\nconsole.log('Current dimensions:', dim.width, 'x', dim.height);\n\n// Resize to specific dimensions\nimgObj.resize(800, 600);\n```\n\n### Resize Parameters\n\n```tsx\ninterface ResizeOptions {\n width: number;\n height: number;\n maintainAspectRatio?: boolean;\n}\n```\n\n## Resize with Aspect Ratio\n\n### Maintain Aspect Ratio\n\nPreserve image proportions:\n\n```tsx\n// This example shows conceptual approach\n// Resize maintains aspect ratio when specified\nfunction resizeWithAspectRatio(targetWidth: number): void {\n const dim = imgObj.getImageDimension();\n const aspectRatio = dim.width / dim.height;\n const newHeight = Math.round(targetWidth / aspectRatio);\n \n imgObj.resize(targetWidth, newHeight);\n}\n\n// Usage: Resize to 800px wide, height auto-adjusts\nresizeWithAspectRatio(800);\n```\n\n### Lock Aspect Ratio\n\n```tsx\nfunction resizeWithConstraints(width: number, height: number): void {\n const dim = imgObj.getImageDimension();\n const aspectRatio = dim.width / dim.height;\n \n // Adjust height based on width\n const adjustedHeight = Math.round(width / aspectRatio);\n \n imgObj.resize(width, adjustedHeight);\n}\n\n// Resize to 1024x auto-calculated height\nresizeWithConstraints(1024, 0);\n```\n\n## Resize Dialog\n\n### Open Resize Dialog\n\nShow resize UI:\n\n```tsx\nfunction openResizeDialog(): void {\n const resizeButton = document.querySelector('[title*=\"Resize\"]');\n if (resizeButton) {\n (resizeButton as HTMLElement).click();\n }\n}\n```\n\n### Resize Dialog Integration\n\n```tsx\nconst handleToolbarClick = (args: ToolbarClickEventArgs): void => {\n if (args.id === 'Resize') {\n // Resize dialog opens automatically\n }\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent toolbarItemClick={handleToolbarClick} />\n);\n```\n\n## Programmatic Resize\n\n### Resize to Specific Dimensions\n\n```tsx\ninterface ResizeTarget {\n width: number;\n height: number;\n}\n\nfunction resizeTo(target: ResizeTarget): void {\n imgObj.resize(target.width, target.height);\n}\n\n// Usage\nresizeTo({ width: 1920, height: 1080 });\n```\n\n### Resize by Percentage\n\n```tsx\nfunction resizeByPercentage(percentage: number): void {\n const dim = imgObj.getImageDimension();\n const factor = percentage / 100;\n \n const newWidth = Math.round(dim.width * factor);\n const newHeight = Math.round(dim.height * factor);\n \n imgObj.resize(newWidth, newHeight);\n}\n\n// Resize to 50% of original size\nresizeByPercentage(50);\n\n// Resize to 150% of original size\nresizeByPercentage(150);\n```\n\n### Resize to Fit Container\n\n```tsx\nfunction resizeToFitContainer(containerWidth: number, containerHeight: number): void {\n const dim = imgObj.getImageDimension();\n const imageAspect = dim.width / dim.height;\n const containerAspect = containerWidth / containerHeight;\n \n let newWidth: number;\n let newHeight: number;\n \n if (imageAspect > containerAspect) {\n // Image is wider\n newWidth = containerWidth;\n newHeight = Math.round(containerWidth / imageAspect);\n } else {\n // Image is taller\n newHeight = containerHeight;\n newWidth = Math.round(containerHeight * imageAspect);\n }\n \n imgObj.resize(newWidth, newHeight);\n}\n\n// Usage\nconst container = document.querySelector('.editor-container');\nif (container) {\n const rect = container.getBoundingClientRect();\n resizeToFitContainer(rect.width, rect.height);\n}\n```\n\n## Resize Events\n\n### Capturing Resize Event\n\n```tsx\nconst handleResizing = (args: ResizingEventArgs): void => {\n console.log('Image resizing:', {\n width: args.width,\n height: args.height\n });\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent resizing={handleResizing} />\n);\n```\n\n### Before/After Resize\n\n```tsx\nlet resizeHistory: { before: any; after: any }[] = [];\n\nconst handleBeforeResize = (): void => {\n const dim = imgObj.getImageDimension();\n resizeHistory.push({\n before: { width: dim.width, height: dim.height },\n after: null\n });\n};\n\nconst handleAfterResize = (): void => {\n if (resizeHistory.length > 0) {\n const dim = imgObj.getImageDimension();\n resizeHistory[resizeHistory.length - 1].after = {\n width: dim.width,\n height: dim.height\n };\n }\n};\n```\n\n### Validate Resize\n\n```tsx\nconst handleResizing = (args: ResizingEventArgs): void => {\n // Minimum dimensions\n if (args.width \u003c 100 || args.height \u003c 100) {\n args.cancel = true;\n console.warn('Image too small');\n return;\n }\n \n // Maximum dimensions\n if (args.width > 4000 || args.height > 4000) {\n args.cancel = true;\n console.warn('Image too large');\n return;\n }\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent resizing={handleResizing} />\n);\n```\n\n## Advanced Patterns\n\n### Common Resize Targets\n\n```tsx\ninterface ResizePreset {\n name: string;\n width: number;\n height: number;\n}\n\nconst resizePresets: ResizePreset[] = [\n { name: 'Thumbnail', width: 200, height: 200 },\n { name: 'Web Small', width: 640, height: 480 },\n { name: '720p', width: 1280, height: 720 },\n { name: '1080p', width: 1920, height: 1080 },\n { name: '4K', width: 3840, height: 2160 },\n { name: 'Instagram Square', width: 1080, height: 1080 },\n { name: 'Instagram Portrait', width: 1080, height: 1350 },\n { name: 'Twitter', width: 1200, height: 675 }\n];\n\nfunction applyPreset(presetName: string): void {\n const preset = resizePresets.find(p => p.name === presetName);\n if (preset) {\n imgObj.resize(preset.width, preset.height);\n }\n}\n\n// Usage\napplyPreset('1080p');\n```\n\n### Batch Resize\n\n```tsx\nasync function batchResize(imageUrls: string[], targetWidth: number): Promise\u003cvoid> {\n for (const url of imageUrls) {\n imgObj.open(url);\n await new Promise(resolve => setTimeout(resolve, 500));\n \n const dim = imgObj.getImageDimension();\n const aspectRatio = dim.width / dim.height;\n const newHeight = Math.round(targetWidth / aspectRatio);\n \n imgObj.resize(targetWidth, newHeight);\n \n // Export the resized image\n imgObj.export('image/png', `resized-${url.split('/').pop()}`);\n }\n}\n\n// Usage\nbatchResize(['image1.jpg', 'image2.jpg', 'image3.jpg'], 800);\n```\n\n### Responsive Resize\n\n```tsx\nfunction makeResponsive(): void {\n const updateSize = (): void => {\n const container = document.querySelector('.editor-container');\n if (container) {\n const rect = container.getBoundingClientRect();\n resizeToFitContainer(rect.width, rect.height);\n }\n };\n \n // Initial resize\n updateSize();\n \n // Resize on window change\n window.addEventListener('resize', updateSize);\n}\n\n// Usage\nmakeResponsive();\n```\n\n### Resize with Constraints\n\n```tsx\ninterface ResizeConstraints {\n minWidth: number;\n minHeight: number;\n maxWidth: number;\n maxHeight: number;\n aspectRatio?: number;\n}\n\nfunction resizeWithConstraints(\n width: number,\n height: number,\n constraints: ResizeConstraints\n): void {\n let finalWidth = width;\n let finalHeight = height;\n \n // Apply constraints\n if (finalWidth \u003c constraints.minWidth) finalWidth = constraints.minWidth;\n if (finalHeight \u003c constraints.minHeight) finalHeight = constraints.minHeight;\n if (finalWidth > constraints.maxWidth) finalWidth = constraints.maxWidth;\n if (finalHeight > constraints.maxHeight) finalHeight = constraints.maxHeight;\n \n // Maintain aspect ratio\n if (constraints.aspectRatio) {\n finalHeight = Math.round(finalWidth / constraints.aspectRatio);\n }\n \n imgObj.resize(finalWidth, finalHeight);\n}\n\n// Usage\nconst constraints: ResizeConstraints = {\n minWidth: 200,\n minHeight: 200,\n maxWidth: 2000,\n maxHeight: 2000,\n aspectRatio: 16 / 9\n};\n\nresizeWithConstraints(1920, 1080, constraints);\n```\n\n### Dimension Presets with Custom Sizes\n\n```tsx\nclass ResizeManager {\n private presets: Map\u003cstring, [number, number]> = new Map([\n ['small', [400, 300]],\n ['medium', [800, 600]],\n ['large', [1600, 1200]]\n ]);\n \n addPreset(name: string, width: number, height: number): void {\n this.presets.set(name, [width, height]);\n }\n \n applyPreset(name: string): void {\n const preset = this.presets.get(name);\n if (preset) {\n imgObj.resize(preset[0], preset[1]);\n }\n }\n \n getAllPresets(): string[] {\n return Array.from(this.presets.keys());\n }\n}\n\nconst manager = new ResizeManager();\nmanager.applyPreset('large');\n```\n\n### Compression via Resize\n\n```tsx\nfunction compressImage(targetSize: number): void {\n // Reduce file size by resizing\n const dim = imgObj.getImageDimension();\n const scale = Math.sqrt(targetSize / (dim.width * dim.height));\n \n const newWidth = Math.round(dim.width * scale);\n const newHeight = Math.round(dim.height * scale);\n \n imgObj.resize(newWidth, newHeight);\n}\n\n// Compress to ~50% area\ncompressImage(0.5);\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8997,"content_sha256":"f9f9a56e6fd7dd39da27e5e3d3c5fbd0900fec3f5d35d4bfdaab97b7685f3412"},{"filename":"references/selection-cropping.md","content":"# Selection and Cropping\n\n## Table of Contents\n- [Selection Methods](#selection-methods)\n- [Cropping](#cropping)\n- [Selection Events](#selection-events)\n- [Advanced Patterns](#advanced-patterns)\n\n## Selection Methods\n\n### Custom Selection\n\nCreate a custom rectangular selection with specified dimensions:\n\n```tsx\nfunction selectCustom(): void {\n imgObj.select('Custom', 50, 50, 300, 200);\n // startX=50, startY=50, width=300, height=200\n}\n```\n\n### Square Selection\n\nInsert a square selection:\n\n```tsx\nfunction selectSquare(): void {\n imgObj.select('Square', 100, 100, 200, 200);\n}\n```\n\n### Circle Selection\n\nInsert a circular selection:\n\n```tsx\nfunction selectCircle(): void {\n imgObj.select('Circle', 150, 150, 100, 100);\n}\n```\n\n### Aspect Ratio Selections\n\nSelect with predefined aspect ratios:\n\n```tsx\n// 16:9 aspect ratio\nfunction select16_9(): void {\n imgObj.select('16:9', 50, 50);\n}\n\n// 9:16 aspect ratio\nfunction select9_16(): void {\n imgObj.select('9:16', 50, 50);\n}\n\n// 4:3 aspect ratio\nfunction select4_3(): void {\n imgObj.select('4:3', 50, 50);\n}\n\n// 3:4 aspect ratio\nfunction select3_4(): void {\n imgObj.select('3:4', 50, 50);\n}\n\n// Supported ratios: 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 5:7, 7:5, 9:16, 16:9\n```\n\n## Cropping\n\n### Basic Crop\n\nCrop the image based on current selection:\n\n```tsx\nfunction cropImage(): void {\n imgObj.select('Square');\n imgObj.crop();\n}\n```\n\n### Crop with Circle Selection\n\nCombine circle selection with cropping:\n\n```tsx\nfunction circleCrop(): void {\n imgObj.select('Circle');\n imgObj.crop();\n}\n```\n\n### Crop with Ratio\n\nCrop using a specific aspect ratio:\n\n```tsx\nfunction cropWith16_9(): void {\n imgObj.select('16:9', 50, 50);\n imgObj.crop();\n}\n```\n\n## Selection Events\n\n### Cropping Event\n\nTriggered during the crop operation:\n\n```tsx\nfunction cropping(args: any): void {\n console.log('Start point:', args.startPoint);\n console.log('End point:', args.endPoint);\n // args.cancel = true; // Cancel crop if needed\n}\n\n\u003cImageEditorComponent cropping={cropping} />\n```\n\n### Maintain Original Image Size During Cropping\n\nPrevent automatic scaling after cropping:\n\n```tsx\nfunction cropping(args: any): void {\n args.preventScaling = true;\n}\n\n\u003cImageEditorComponent cropping={cropping} />\n```\n\n**Result:** Image retains its original size without enlargement.\n\n### Selection Changing Event\n\nTriggered when selection is resized or modified:\n\n```tsx\nfunction selectionChanging(args: any): void {\n console.log('Action:', args.action); // 'insert' or 'resize'\n console.log('Current selection:', args.currentSelectionSettings);\n console.log('Previous selection:', args.previousSelectionSettings);\n}\n\n\u003cImageEditorComponent selectionChanging={selectionChanging} />\n```\n\n### Lock Selection Area During Resizing\n\nPrevent users from resizing the selection:\n\n```tsx\nfunction selectionChanging(args: any): void {\n if (args.action === 'resize') {\n args.currentSelectionSettings = args.previousSelectionSettings;\n }\n}\n\n\u003cImageEditorComponent selectionChanging={selectionChanging} />\n```\n\n**Result:** Selection handles appear but resize operations are ignored.\n\n## Advanced Patterns\n\n### Custom Ratio Selection\n\nEnforce custom ratio during selection resizing:\n\n```tsx\nfunction selectionChanging(args: any): void {\n if (args.action === 'insert' && args.currentSelectionSettings.type === 'Custom') {\n // Validate and adjust selection before applying\n if (args.currentSelectionSettings.height > 500) {\n args.currentSelectionSettings.height = 500;\n }\n if (args.currentSelectionSettings.width > 500) {\n args.currentSelectionSettings.width = 500;\n }\n }\n}\n\n\u003cImageEditorComponent selectionChanging={selectionChanging} />\n```\n\n### Sequential Selections and Crops\n\nPerform multiple selections and crops:\n\n```tsx\nfunction multiCrop(): void {\n // First crop\n imgObj.select('16:9', 0, 0);\n imgObj.crop();\n \n // Clear and second crop\n imgObj.select('Square', 50, 50);\n imgObj.crop();\n}\n```\n\n### Selection with Panning\n\nPan to adjust crop area:\n\n```tsx\nfunction selectAndPan(): void {\n // Create selection\n imgObj.select('Custom', 100, 100, 300, 300);\n \n // Pan is available when selection exceeds canvas size\n // User can drag to reposition the crop area\n}\n```\n\n### Dynamic Selection Based on Image Dimensions\n\nAutomatically select based on image size:\n\n```tsx\nfunction intelligentSelect(): void {\n const dimension = imgObj.getImageDimension();\n const width = dimension.width;\n const height = dimension.height;\n \n // Select 80% of image\n const selWidth = width * 0.8;\n const selHeight = height * 0.8;\n const startX = (width - selWidth) / 2;\n const startY = (height - selHeight) / 2;\n \n imgObj.select('Custom', startX, startY, selWidth, selHeight);\n}\n```\n\n### Crop to Specific Dimensions\n\nAlways crop to exact dimensions:\n\n```tsx\nfunction cropToSize(): void {\n const targetWidth = 500;\n const targetHeight = 300;\n \n imgObj.select('Custom', 50, 50, targetWidth, targetHeight);\n imgObj.crop();\n \n // After crop, image will be exactly 500x300 (or close, depending on aspect ratio)\n}\n```\n\n### Undo Crop Selection\n\nUse undo to revert crop operation:\n\n```tsx\nfunction undoCrop(): void {\n imgObj.undo(); // Reverts the last crop\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5209,"content_sha256":"cd6e295f25ea3daff48ab86248b7ef8f9a95d545d28f87cc3ac170cc6f1f3e80"},{"filename":"references/shape-annotations.md","content":"# Shape Annotations\n\n## Table of Contents\n- [Drawing Shapes](#drawing-shapes)\n- [Shape Properties](#shape-properties)\n- [Managing Shapes](#managing-shapes)\n- [Customization Events](#customization-events)\n\n## Drawing Shapes\n\n### Draw Rectangle\n\nAdd rectangular annotation:\n\n```tsx\nfunction drawRectangle(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawRectangle(\n dimension.x + 10, // x\n dimension.y + 60, // y\n 150, // width\n 70 // height\n );\n}\n```\n\n### Draw Ellipse\n\nAdd elliptical annotation:\n\n```tsx\nfunction drawEllipse(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawEllipse(\n dimension.x + 100, // center x\n dimension.y + 100, // center y\n 80, // radiusX\n 50 // radiusY\n );\n}\n```\n\n### Draw Line\n\nAdd line annotation:\n\n```tsx\nfunction drawLine(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawLine(\n dimension.x + 50, // startX\n dimension.y + 50, // startY\n dimension.x + 300, // endX\n dimension.y + 150 // endY\n );\n}\n```\n\n### Draw Arrow\n\nAdd arrow annotation with direction:\n\n```tsx\nfunction drawArrow(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawArrow(\n dimension.x + 100, // startX\n dimension.y + 100, // startY\n dimension.x + 300, // endX\n dimension.y + 200, // endY\n 2, // strokeWidth\n 'black', // strokeColor\n ArrowheadType.None, // arrowStart\n ArrowheadType.SolidArrow // arrowEnd\n );\n}\n```\n\n### Draw Path\n\nAdd complex path annotation:\n\n```tsx\nfunction drawPath(): void {\n const dimension = imgObj.getImageDimension();\n const points = [\n { x: dimension.x, y: dimension.y },\n { x: dimension.x + 50, y: dimension.y + 50 },\n { x: dimension.x + 100, y: dimension.y + 20 },\n { x: dimension.x + 150, y: dimension.y + 80 }\n ];\n \n imgObj.drawPath(points, 5, 'blue');\n}\n```\n\n## Shape Properties\n\n### Rectangle with Stroke and Fill\n\nCustomize rectangle appearance:\n\n```tsx\nfunction customRectangle(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawRectangle(\n dimension.x + 10,\n dimension.y + 60,\n 150,\n 70,\n 2, // strokeWidth\n 'red', // strokeColor\n 'yellow', // fillColor\n 0, // degree\n false, // isSelected\n 8 // borderRadius\n );\n}\n```\n\n### Ellipse with Custom Stroke\n\nCustomize ellipse styling:\n\n```tsx\nfunction styledEllipse(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawEllipse(\n dimension.x + 100,\n dimension.y + 100,\n 80,\n 50,\n 3, // strokeWidth\n 'green', // strokeColor\n 'lightgreen', // fillColor\n 0, // degree\n false // isSelected\n );\n}\n```\n\n### Rotated Shape\n\nRotate shape by degree:\n\n```tsx\nfunction rotatedRectangle(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawRectangle(\n dimension.x + 100,\n dimension.y + 100,\n 100,\n 50,\n 2,\n 'black',\n 'transparent',\n 45 // Rotate 45 degrees\n );\n}\n```\n\n### Arrow Head Types\n\nDifferent arrow variations:\n\n```tsx\nimport { ArrowheadType } from '@syncfusion/ej2-react-image-editor';\n\nfunction differentArrows(): void {\n const dimension = imgObj.getImageDimension();\n \n // Arrow with solid head at end only\n imgObj.drawArrow(50, 50, 150, 50, 2, 'black', ArrowheadType.None, ArrowheadType.SolidArrow);\n \n // Arrow with no heads\n imgObj.drawArrow(50, 100, 150, 100, 2, 'blue', ArrowheadType.None, ArrowheadType.None);\n \n // Double arrow (heads at both ends)\n imgObj.drawArrow(50, 150, 150, 150, 2, 'red', ArrowheadType.SolidArrow, ArrowheadType.SolidArrow);\n}\n```\n\n## Managing Shapes\n\n### Get All Shapes\n\nRetrieve all shape annotations:\n\n```tsx\nfunction getAllShapes(): void {\n const shapes = imgObj.getShapeSettings();\n const shapeTypes = shapes.map(s => s.type);\n console.log('Shape types:', shapeTypes);\n}\n```\n\n### Delete Shape\n\nRemove shape by ID:\n\n```tsx\nfunction deleteShape(): void {\n imgObj.deleteShape('shape_1');\n}\n```\n\n### Delete Multiple Shapes\n\nRemove all shapes of specific type:\n\n```tsx\nfunction deleteAllShapesOfType(shapeType: string): void {\n const shapes = imgObj.getShapeSettings();\n shapes\n .filter(s => s.type === shapeType)\n .forEach(s => imgObj.deleteShape(s.id));\n}\n\n// Usage: Delete all rectangles\ndeleteAllShapesOfType('Rectangle');\n```\n\n### Update Shape\n\nModify existing shape properties:\n\n```tsx\nfunction updateShapeColor(): void {\n const shapes = imgObj.getShapeSettings();\n if (shapes && shapes.length > 0) {\n const shape = shapes[0];\n shape.strokeColor = 'purple';\n imgObj.updateShape(shape);\n }\n}\n```\n\n### Select Shape\n\nHighlight shape for editing:\n\n```tsx\nfunction selectShapeById(shapeId: string): void {\n imgObj.selectShape(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes && shapes.length > 0) {\n selectShapeById(shapes[0].id);\n}\n```\n\n## Customization Events\n\n### Customize Default Stroke Colors\n\nApply custom defaults via event:\n\n```tsx\nlet changeColor = true;\n\nfunction shapeChanging(args: any): void {\n if (changeColor && args.action === 'insert' && args.currentShapeSettings.type === 'Rectangle') {\n args.currentShapeSettings.strokeColor = 'red';\n args.currentShapeSettings.fillColor = 'lightyellow';\n changeColor = false;\n }\n}\n\n\u003cImageEditorComponent shapeChanging={shapeChanging} />\n```\n\n### Prevent Specific Shapes\n\nBlock certain shape types:\n\n```tsx\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'Arrow' && args.action === 'insert') {\n args.cancel = true;\n console.log('Arrows not allowed');\n }\n}\n```\n\n## Advanced Patterns\n\n### Annotate Regions\n\nHighlight important areas with rectangles:\n\n```tsx\nfunction highlightRegions(): void {\n // Region 1\n imgObj.drawRectangle(50, 50, 150, 100, 2, 'red', 'transparent');\n \n // Region 2\n imgObj.drawRectangle(200, 150, 150, 100, 2, 'green', 'transparent');\n \n // Region 3\n imgObj.drawRectangle(350, 50, 150, 100, 2, 'blue', 'transparent');\n}\n```\n\n### Create Measurement Lines\n\nDraw lines for distance indication:\n\n```tsx\nfunction drawMeasurementLines(): void {\n const dim = imgObj.getImageDimension();\n \n // Horizontal measurement\n imgObj.drawLine(dim.x, dim.y + 100, dim.x + 200, dim.y + 100, 2, 'black');\n imgObj.drawLine(dim.x, dim.y + 95, dim.x, dim.y + 105, 2, 'black');\n imgObj.drawLine(dim.x + 200, dim.y + 95, dim.x + 200, dim.y + 105, 2, 'black');\n}\n```\n\n### Draw Grid Pattern\n\nCreate overlay grid:\n\n```tsx\nfunction drawGrid(): void {\n const dim = imgObj.getImageDimension();\n const gridSize = 50;\n \n for (let x = 0; x \u003c dim.width; x += gridSize) {\n imgObj.drawLine(dim.x + x, dim.y, dim.x + x, dim.y + dim.height, 1, '#CCC');\n }\n \n for (let y = 0; y \u003c dim.height; y += gridSize) {\n imgObj.drawLine(dim.x, dim.y + y, dim.x + dim.width, dim.y + y, 1, '#CCC');\n }\n}\n```\n\n### Flowchart Elements\n\nBuild diagram shapes:\n\n```tsx\nfunction createFlowchart(): void {\n const dim = imgObj.getImageDimension();\n \n // Start\n imgObj.drawEllipse(dim.x + 200, dim.y + 50, 40, 30, 2, 'black', 'green');\n \n // Process\n imgObj.drawRectangle(dim.x + 150, dim.y + 150, 100, 60, 2, 'black', 'lightblue');\n \n // Decision\n imgObj.drawPath([\n { x: dim.x + 200, y: dim.y + 300 },\n { x: dim.x + 250, y: dim.y + 350 },\n { x: dim.x + 200, y: dim.y + 400 },\n { x: dim.x + 150, y: dim.y + 350 }\n ], 2, 'black');\n}\n```\n\n### Shape History Tracking\n\nMonitor shape creation:\n\n```tsx\nlet shapeHistory: any[] = [];\n\nfunction shapeChanging(args: any): void {\n if (args.action === 'insert') {\n shapeHistory.push({\n type: args.currentShapeSettings.type,\n timestamp: new Date(),\n id: args.currentShapeSettings.id\n });\n }\n}\n\nfunction undoLastShape(): void {\n imgObj.undo();\n shapeHistory.pop();\n}\n```\n\n### Batch Drawing\n\nDraw multiple related shapes:\n\n```tsx\nfunction batchDraw(shapes: any[]): void {\n shapes.forEach(shape => {\n if (shape.type === 'rectangle') {\n imgObj.drawRectangle(shape.x, shape.y, shape.w, shape.h, shape.stroke);\n } else if (shape.type === 'ellipse') {\n imgObj.drawEllipse(shape.x, shape.y, shape.rx, shape.ry, shape.stroke);\n }\n });\n}\n\nconst diagramShapes = [\n { type: 'rectangle', x: 50, y: 50, w: 100, h: 80, stroke: 2 },\n { type: 'ellipse', x: 200, y: 100, rx: 40, ry: 30, stroke: 2 }\n];\n\nbatchDraw(diagramShapes);\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8662,"content_sha256":"9228db7dc6f800a3b8d3916b892ddc834d503998a5a8eb6e8455a5e6b8973aa1"},{"filename":"references/text-annotations.md","content":"# Text Annotations\n\n## Table of Contents\n- [Adding Text](#adding-text)\n- [Text Styling](#text-styling)\n- [Font Customization](#font-customization)\n- [Multiline Text](#multiline-text)\n- [Managing Text Annotations](#managing-text-annotations)\n\n## Adding Text\n\n### Basic Text\n\nAdd simple text annotation at specific coordinates:\n\n```tsx\nfunction addText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(dimension.x, dimension.y, 'Sample Text');\n}\n```\n\n### Text with Font Properties\n\nAdd text with customized font settings:\n\n```tsx\nfunction addStyledText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x + 50, // x coordinate\n dimension.y + 50, // y coordinate\n 'Syncfusion', // text content\n 'Arial', // font family\n 30, // font size\n false, // bold (boolean)\n false, // italic (boolean)\n 'blue' // color\n );\n}\n```\n\n### Text with Background and Outline\n\nAdd text with background color and stroke:\n\n```tsx\nfunction addTextWithOutline(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x + 100,\n dimension.y + 100,\n 'Watermark',\n 'Arial',\n 40,\n false,\n false,\n 'white', // font color\n false, // isSelected\n 0, // degree\n 'red', // fillColor (background)\n 'black', // strokeColor (outline)\n 2 // strokeWidth\n );\n}\n```\n\n### Text with Rotation\n\nAdd text rotated by specific degree:\n\n```tsx\nfunction addRotatedText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x + 50,\n dimension.y + 50,\n 'Rotated Text',\n 'Arial',\n 25,\n false,\n false,\n 'black',\n false,\n 45 // 45 degree rotation\n );\n}\n```\n\n## Text Styling\n\n### Bold Text\n\nAdd bold text annotations:\n\n```tsx\nfunction addBoldText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Bold Text',\n 'Arial',\n 25,\n true, // bold = true\n false\n );\n}\n```\n\n### Italic Text\n\nAdd italic styled text:\n\n```tsx\nfunction addItalicText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Italic Text',\n 'Arial',\n 25,\n false,\n true // italic = true\n );\n}\n```\n\n### Bold Italic Text\n\nCombine bold and italic:\n\n```tsx\nfunction addBoldItalicText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Bold Italic',\n 'Arial',\n 25,\n true, // bold\n true // italic\n );\n}\n```\n\n### Underline and Strikethrough\n\nAdd text with underline or strikethrough using the drawText method:\n\n```tsx\nfunction addUnderlineText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Underlined Text',\n 'Arial',\n 20,\n false,\n false,\n '#000000',\n false,\n 0,\n '',\n '',\n 0,\n true, // underline\n false // strikethrough\n );\n}\n\nfunction addStrikethroughText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Strikethrough Text',\n 'Arial',\n 20,\n false,\n false,\n '#000000',\n false,\n 0,\n '',\n '',\n 0,\n false, // underline\n true // strikethrough\n );\n}\n```\n\n## Font Customization\n\n### Add Custom Font Families\n\nExtend available fonts:\n\n```tsx\nconst fontFamily = {\n default: 'Arial',\n items: [\n { id: 'arial', text: 'Arial' },\n { id: 'brush script mt', text: 'Brush Script MT' },\n { id: 'papyrus', text: 'Papyrus' },\n { id: 'times new roman', text: 'Times New Roman' },\n { id: 'courier new', text: 'Courier New' }\n ]\n};\n\n\u003cImageEditorComponent fontFamily={fontFamily} />\n```\n\n### Use Custom Fonts\n\nApply custom font when adding text:\n\n```tsx\nfunction addWithCustomFont(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Fancy Text',\n 'Papyrus', // Custom font\n 28\n );\n}\n```\n\n### Change Font via Event\n\nCustomize font family dynamically:\n\n```tsx\nfunction shapeChanging(args: any): void {\n if (args.currentShapeSettings.type === 'Text') {\n args.currentShapeSettings.color = 'red';\n args.currentShapeSettings.fontFamily = 'Times New Roman';\n }\n}\n\n\u003cImageEditorComponent shapeChanging={shapeChanging} />\n```\n\n## Multiline Text\n\n### Add Multiline Text\n\nUse newline character `\\n` for multiple lines:\n\n```tsx\nfunction addMultilineText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x,\n dimension.y,\n 'Line 1\\nLine 2\\nLine 3',\n 'Arial',\n 20\n );\n}\n```\n\n### Multiline with Styling\n\nStyle multiline text:\n\n```tsx\nfunction addStyledMultiline(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x + 50,\n dimension.y + 50,\n 'Header\\nSubtitle\\nDescription',\n 'Arial',\n 25,\n true, // bold header effect\n false,\n 'darkblue'\n );\n}\n```\n\n## Managing Text Annotations\n\n### Get All Text Annotations\n\nRetrieve all shapes (including text):\n\n```tsx\nfunction getAllText(): void {\n const shapes = imgObj.getShapeSettings();\n const textShapes = shapes.filter(s => s.type === 'Text');\n console.log('Text annotations:', textShapes);\n}\n```\n\n### Delete Text Annotation\n\nRemove text by shape ID:\n\n```tsx\nfunction deleteText(): void {\n imgObj.deleteShape('shape_1');\n}\n\n// Or delete last added text\nfunction deleteLastText(): void {\n const shapes = imgObj.getShapeSettings();\n if (shapes.length > 0) {\n imgObj.deleteShape(shapes[shapes.length - 1].id);\n }\n}\n```\n\n### Update Text Properties\n\nModify existing text annotation:\n\n```tsx\nfunction updateTextColor(): void {\n const shapes = imgObj.getShapeSettings();\n if (shapes && shapes[0].type === 'Text') {\n shapes[0].color = 'green';\n imgObj.updateShape(shapes[0]);\n }\n}\n```\n\n### Find Text Containing Keyword\n\nSearch for specific text:\n\n```tsx\nfunction findText(keyword: string): any {\n const shapes = imgObj.getShapeSettings();\n return shapes.find(s => \n s.type === 'Text' && s.text.includes(keyword)\n );\n}\n\nconst found = findText('Sync');\nif (found) {\n console.log('Found:', found);\n}\n```\n\n## Advanced Patterns\n\n### Text Positioning\n\nAlign text at specific positions:\n\n```tsx\nfunction addTopLeftText(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(dimension.x + 10, dimension.y + 10, 'Top Left');\n}\n\nfunction addCenterText(): void {\n const dimension = imgObj.getImageDimension();\n const centerX = dimension.x + dimension.width / 2;\n const centerY = dimension.y + dimension.height / 2;\n imgObj.drawText(centerX, centerY, 'Center');\n}\n\nfunction addBottomRightText(): void {\n const dimension = imgObj.getImageDimension();\n const x = dimension.x + dimension.width - 100;\n const y = dimension.y + dimension.height - 30;\n imgObj.drawText(x, y, 'Bottom Right');\n}\n```\n\n### Watermark Pattern\n\nAdd semi-transparent watermark:\n\n```tsx\nfunction addWatermark(): void {\n const dimension = imgObj.getImageDimension();\n imgObj.drawText(\n dimension.x + 50,\n dimension.y + 50,\n 'WATERMARK',\n 'Arial',\n 50,\n false,\n false,\n '#80808080' // Semi-transparent gray\n );\n}\n```\n\n### Date Timestamp\n\nAdd current date as text:\n\n```tsx\nfunction addTimestamp(): void {\n const dimension = imgObj.getImageDimension();\n const now = new Date().toLocaleString();\n imgObj.drawText(\n dimension.x + 10,\n dimension.y + dimension.height - 30,\n `Created: ${now}`,\n 'Arial',\n 12\n );\n}\n```\n\n### Duplicate Text\n\nClone existing text annotation:\n\n```tsx\nfunction duplicateText(): void {\n const shapes = imgObj.getShapeSettings();\n if (shapes && shapes.length > 0 && shapes[0].type === 'Text') {\n const original = shapes[0];\n // Create offset copy of the text\n imgObj.drawText(\n (original.x || 0) + 20,\n (original.y || 0) + 20,\n original.text || 'Text',\n original.fontFamily || 'Arial',\n original.fontSize || 12,\n false,\n false,\n original.color || '#000000'\n );\n }\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8282,"content_sha256":"79feb36ca638a4f196958d828864f38e236b2451bb42ce63d50a6d82d3b38ecc"},{"filename":"references/toolbar-customization.md","content":"# Toolbar Customization\n\n## Built-in Toolbar Items\n\nThe Image Editor includes these default toolbar items:\n\n- **File**: Open, Save\n- **Edit**: Undo, Redo\n- **Transform**: Rotate, Flip, Straighten\n- **Zoom**: Zoom In/Out, Fit to Width/Height, Reset\n- **Crop & Resize**: Crop, Resize\n- **Annotation**: Text, Shapes (Rectangle, Ellipse, Line, Arrow), Freehand\n- **Filters**: Chrome, Cold, Warm, Grayscale, Sepia, Invert\n- **Fine-tune**: Brightness, Contrast, Saturation, Hue, Exposure, Blur, Opacity\n- **Other**: Frame, Z-Order, Redact\n\n## Customize Built-in Items\n\n### Show/Hide Items\n\nControl toolbar visibility:\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n toolbar={['Open', 'Save', 'Undo', 'Redo', 'Crop', 'Rotate', 'Flip']}\n />\n);\n```\n\n### Item Arrangement\n\nReorder toolbar items:\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n toolbar={[\n 'Open',\n 'Save',\n 'Undo',\n 'Redo',\n 'Zoom In',\n 'Zoom Out',\n 'Reset Transform',\n 'Crop',\n 'Text',\n 'Shapes',\n 'Filters'\n ]}\n />\n);\n```\n\n### Grouped Items\n\nUse separators:\n\n```tsx\nconst imageEditor = (\n \u003cImageEditorComponent\n toolbar={[\n 'Open',\n 'Save',\n '|', // Separator\n 'Undo',\n 'Redo',\n '|',\n 'Crop',\n 'Rotate',\n 'Flip'\n ]}\n />\n);\n```\n\n## Custom Toolbar Items\n\n### Add Custom Button\n\nInsert custom actions:\n\n```tsx\nconst customToolbar = [\n 'Open',\n 'Save',\n {\n id: 'custom-reset',\n tooltipText: 'Reset to Original',\n text: 'Reset',\n prefixIcon: 'e-icon-refresh'\n },\n {\n id: 'custom-export',\n tooltipText: 'Export as PNG',\n text: 'Export',\n prefixIcon: 'e-icon-export'\n }\n];\n\nconst imageEditor = (\n \u003cImageEditorComponent toolbar={customToolbar} />\n);\n```\n\n### Custom Button with Event\n\nHandle custom toolbar actions:\n\n```tsx\nconst handleCustomAction = (args: any): void => {\n switch (args.id) {\n case 'custom-reset':\n imgObj.reset();\n break;\n case 'custom-export':\n imgObj.export('image/png', 'edited-image');\n break;\n }\n};\n\nconst customToolbar = [\n {\n id: 'custom-reset',\n text: 'Reset',\n prefixIcon: 'e-icon-refresh'\n }\n];\n\nconst imageEditor = (\n \u003cImageEditorComponent\n toolbar={customToolbar}\n toolbarItemClick={handleCustomAction}\n />\n);\n```\n\n### Custom Icon\n\nUse custom SVG or CSS class:\n\n```tsx\nconst customToolbar = [\n {\n id: 'custom-print',\n tooltipText: 'Print Image',\n prefixIcon: 'custom-print-icon', // Custom CSS class\n align: 'Left'\n },\n {\n id: 'custom-email',\n text: 'Email',\n prefixIcon: 'e-icon-email'\n }\n];\n\n// CSS\nconst styles = `\n .custom-print-icon::before {\n content: '🖨️';\n }\n`;\n```\n\n## Contextual Toolbar\n\n### Show/Hide Based on State\n\nToggle toolbar items dynamically:\n\n```tsx\nconst [editMode, setEditMode] = useState(false);\nconst [showAdvanced, setShowAdvanced] = useState(false);\n\nconst baseToolbar = ['Open', 'Save', 'Undo', 'Redo'];\nconst editingToolbar = [...baseToolbar, 'Crop', 'Rotate', 'Flip', 'Text'];\nconst advancedToolbar = [\n ...editingToolbar,\n 'Filters',\n 'Fine-tune',\n 'Frame'\n];\n\nconst currentToolbar = showAdvanced ? advancedToolbar : editMode ? editingToolbar : baseToolbar;\n\nreturn (\n \u003c>\n \u003cImageEditorComponent toolbar={currentToolbar} />\n \u003cbutton onClick={() => setEditMode(!editMode)}>Toggle Edit Mode\u003c/button>\n \u003cbutton onClick={() => setShowAdvanced(!showAdvanced)}>Toggle Advanced\u003c/button>\n \u003c/>\n);\n```\n\n### Context-Sensitive Items\n\nEnable/disable based on selection:\n\n```tsx\nconst handleSelectionChange = (args: any): void => {\n // Update toolbar based on selection\n const hasText = checkForTextAnnotations();\n const toolbar = hasText\n ? ['Open', 'Save', 'Delete Selection', 'Edit Text', 'Filters']\n : ['Open', 'Save', 'Crop', 'Rotate'];\n};\n```\n\n## Toolbar Positioning\n\n### Align Items\n\nSet item alignment:\n\n```tsx\nconst customToolbar = [\n {\n id: 'open',\n text: 'Open',\n align: 'Left'\n },\n {\n id: 'undo',\n text: 'Undo',\n align: 'Left'\n },\n {\n id: 'help',\n text: 'Help',\n align: 'Right'\n }\n];\n\nconst imageEditor = (\n \u003cImageEditorComponent toolbar={customToolbar} />\n);\n```\n\n## Toolbar Events\n\n### Toolbar Item Click\n\nCapture toolbar interactions:\n\n```tsx\nconst handleToolbarClick = (args: ToolbarClickEventArgs): void => {\n console.log('Toolbar item clicked:', args.id);\n \n if (args.id === 'open') {\n openImageDialog();\n } else if (args.id === 'save') {\n saveImage();\n }\n};\n\nconst imageEditor = (\n \u003cImageEditorComponent toolbarItemClick={handleToolbarClick} />\n);\n```\n\n### Before Toolbar Render\n\nModify toolbar before display:\n\n```tsx\nconst handleBeforeRender = (args: any): void => {\n // Add custom properties or modify items\n args.toolbarItems.forEach((item: any) => {\n if (item.id === 'custom-reset') {\n item.enabled = false; // Disable initially\n }\n });\n};\n```\n\n## Advanced Toolbar Patterns\n\n### Dynamic Toolbar\n\nUpdate toolbar based on loaded image:\n\n```tsx\nconst [imageLoaded, setImageLoaded] = useState(false);\nlet imgObj: ImageEditor;\n\nconst handleImageOpened = (): void => {\n setImageLoaded(true);\n // Show editing tools only after image loads\n};\n\nconst toolbar = imageLoaded\n ? ['Open', 'Save', 'Undo', 'Redo', 'Crop', 'Rotate', 'Text', 'Filters']\n : ['Open'];\n\nreturn (\n \u003cImageEditorComponent\n toolbar={toolbar}\n fileOpened={handleImageOpened}\n ref={(img) => { imgObj = img; }}\n />\n);\n```\n\n### Toolbar with Dropdowns\n\nMulti-option toolbar items:\n\n```tsx\nconst customToolbar = [\n {\n id: 'open',\n text: 'Open',\n prefixIcon: 'e-icon-open'\n },\n {\n id: 'transform-menu',\n text: 'Transform',\n prefixIcon: 'e-icon-transform',\n items: [\n { id: 'rotate-90', text: 'Rotate 90°' },\n { id: 'rotate-180', text: 'Rotate 180°' },\n { id: 'flip-h', text: 'Flip Horizontal' }\n ]\n }\n];\n\nconst handleDropdownSelect = (args: any): void => {\n switch (args.id) {\n case 'rotate-90':\n imgObj.rotate(90);\n break;\n case 'rotate-180':\n imgObj.rotate(180);\n break;\n }\n};\n```\n\n### Keyboard Shortcuts for Toolbar\n\nMap keyboard to toolbar:\n\n```tsx\nconst handleKeyDown = (e: KeyboardEvent): void => {\n if (e.ctrlKey) {\n switch (e.key) {\n case 'o':\n e.preventDefault();\n // Trigger open action\n break;\n case 's':\n e.preventDefault();\n // Trigger save action\n break;\n case 'e':\n e.preventDefault();\n // Trigger export action\n break;\n }\n }\n};\n\ndocument.addEventListener('keydown', handleKeyDown);\n```\n\n### Conditional Toolbar Loading\n\nLoad toolbar based on permissions:\n\n```tsx\ninterface UserPermissions {\n canEdit: boolean;\n canDelete: boolean;\n canExport: boolean;\n}\n\nfunction getToolbarForUser(permissions: UserPermissions): string[] {\n const toolbar = ['Open', 'Undo', 'Redo'];\n \n if (permissions.canEdit) {\n toolbar.push('Crop', 'Rotate', 'Flip', 'Text');\n }\n \n if (permissions.canDelete) {\n toolbar.push('Delete');\n }\n \n if (permissions.canExport) {\n toolbar.push('Save');\n }\n \n return toolbar;\n}\n\nconst userPermissions: UserPermissions = {\n canEdit: true,\n canDelete: false,\n canExport: true\n};\n\nconst toolbar = getToolbarForUser(userPermissions);\nconst imageEditor = (\n \u003cImageEditorComponent toolbar={toolbar} />\n);\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7334,"content_sha256":"51e506fd7892ee8c2b1d6c9f230570a0f9ab78c781ef0e2db9e51ddcc939b5a8"},{"filename":"references/transform-rotate-flip.md","content":"# Transform: Rotate, Flip, and Straighten\n\n## Table of Contents\n- [Rotation](#rotation)\n- [Flipping](#flipping)\n- [Straightening](#straightening)\n- [Transform Events](#transform-events)\n- [Combining Transformations](#combining-transformations)\n\n## Rotation\n\n### Rotate Clockwise\n\nRotate image by positive degrees (clockwise):\n\n```tsx\nfunction rotateClockwise(): void {\n imgObj.rotate(90); // 90 degrees clockwise\n}\n\nfunction rotate180(): void {\n imgObj.rotate(180); // 180 degrees\n}\n\nfunction rotate270(): void {\n imgObj.rotate(270); // 270 degrees clockwise\n}\n```\n\n### Rotate Counter-Clockwise\n\nRotate image by negative degrees (counter-clockwise):\n\n```tsx\nfunction rotateCounterClockwise(): void {\n imgObj.rotate(-90); // 90 degrees counter-clockwise\n}\n```\n\n### Best Practices for Rotation\n\nUse multiples of 90° for proper alignment:\n\n```tsx\n// Good - clean rotations\nimgObj.rotate(90); // ✓\nimgObj.rotate(180); // ✓\nimgObj.rotate(270); // ✓\n\n// Not recommended - partial rotations\nimgObj.rotate(45); // ⚠️ May cause image quality loss\nimgObj.rotate(30); // ⚠️ May cause artifacts\n```\n\n### Rotate with Annotations\n\nAll annotations rotate along with the image:\n\n```tsx\nfunction rotateWithAnnotations(): void {\n // Add annotations first\n imgObj.drawText(100, 100, 'Sample Text');\n imgObj.drawRectangle(50, 50, 150, 100);\n \n // Rotate - annotations rotate too\n imgObj.rotate(90);\n}\n```\n\n## Flipping\n\n### Flip Horizontally\n\nCreate mirror effect along vertical axis:\n\n```tsx\nfunction flipHorizontal(): void {\n imgObj.flip('Horizontal');\n}\n```\n\n### Flip Vertically\n\nCreate mirror effect along horizontal axis:\n\n```tsx\nfunction flipVertical(): void {\n imgObj.flip('Vertical');\n}\n```\n\n### Flip Combinations\n\nCombine multiple flips:\n\n```tsx\nfunction flipBoth(): void {\n imgObj.flip('Horizontal');\n imgObj.flip('Vertical');\n // Result: 180° rotation via flips\n}\n```\n\n### Flip with Annotations\n\nAnnotations are transformed along with flip:\n\n```tsx\nfunction flipWithAnnotations(): void {\n imgObj.drawText(100, 100, 'Text');\n imgObj.drawArrow(50, 50, 150, 150);\n \n imgObj.flip('Horizontal');\n // Annotations flip along with image\n}\n```\n\n## Straightening\n\n### Straighten Image\n\nFine-tune rotation for slight angle corrections (-45° to +45°):\n\n```tsx\nfunction straightenClockwise(): void {\n imgObj.straightenImage(45); // Rotate up to 45° clockwise\n}\n\nfunction straightenCounterClockwise(): void {\n imgObj.straightenImage(-20); // Rotate 20° counter-clockwise\n}\n\nfunction subtleAdjustment(): void {\n imgObj.straightenImage(5); // Minor 5° adjustment\n}\n```\n\n### Straighten Range\n\nThe straightening function accepts degrees between -45 and +45:\n\n```tsx\n// Valid range\nimgObj.straightenImage(-45); // Max counter-clockwise\nimgObj.straightenImage(0); // No change\nimgObj.straightenImage(45); // Max clockwise\n```\n\n### Use Case: Fix Tilted Photos\n\nCorrect slightly tilted images:\n\n```tsx\nfunction fixTiltedPhoto(): void {\n // User determines angle needed, e.g., -8 degrees\n imgObj.straightenImage(-8);\n}\n```\n\n## Transform Events\n\n### Rotating Event\n\nTriggered during rotation:\n\n```tsx\nfunction rotating(args: any): void {\n console.log('Previous degree:', args.previousDegree);\n console.log('Current degree:', args.currentDegree);\n // args.cancel = true; // Cancel rotation\n}\n\n\u003cImageEditorComponent rotating={rotating} />\n```\n\n### Flipping Event\n\nTriggered during flip operation:\n\n```tsx\nfunction flipping(args: any): void {\n console.log('Flip direction:', args.direction); // 'Horizontal' or 'Vertical'\n // args.cancel = true; // Cancel flip\n}\n\n\u003cImageEditorComponent flipping={flipping} />\n```\n\n### Validate Rotation Angle\n\nPrevent excessive rotations:\n\n```tsx\nfunction rotating(args: any): void {\n const newDegree = args.currentDegree;\n \n // Only allow 0, 90, 180, 270\n const validDegrees = [0, 90, 180, 270];\n if (!validDegrees.includes(newDegree % 360)) {\n args.cancel = true;\n }\n}\n```\n\n## Combining Transformations\n\n### Sequential Transformations\n\nApply multiple transforms in sequence:\n\n```tsx\nfunction complexTransform(): void {\n imgObj.rotate(90); // Rotate\n imgObj.flip('Horizontal'); // Flip\n imgObj.straightenImage(5); // Straighten\n}\n```\n\n### Transform with Zoom and Pan\n\nCombine transforms with zoom/pan:\n\n```tsx\nfunction transformAndZoom(): void {\n imgObj.rotate(90);\n imgObj.zoom(1.5); // Zoom to 1.5x\n imgObj.pan(true); // Enable panning\n}\n```\n\n### Reset Transformations\n\nUse undo or reset to revert transformations:\n\n```tsx\nfunction undoTransform(): void {\n imgObj.undo(); // Undo last transformation\n}\n\nfunction resetAll(): void {\n imgObj.reset(); // Reset all changes to original\n}\n```\n\n### Transform Pipeline\n\nApply transforms in a controlled pipeline:\n\n```tsx\nfunction transformPipeline(): void {\n const transforms = [\n () => imgObj.rotate(90),\n () => imgObj.flip('Horizontal'),\n () => imgObj.straightenImage(10)\n ];\n \n transforms.forEach(transform => transform());\n}\n```\n\n### Get Current Rotation State\n\nTrack current transformation state:\n\n```tsx\nlet rotationState = 0;\n\nfunction trackRotation(): void {\n function rotating(args: any): void {\n rotationState = args.currentDegree;\n console.log('Current rotation:', rotationState);\n }\n \n return \u003cImageEditorComponent rotating={rotating} />;\n}\n```\n\n### Transform with Annotations\n\nApply transforms that affect all elements:\n\n```tsx\nfunction transformAll(): void {\n // Add various annotations\n imgObj.drawText(50, 50, 'Label');\n imgObj.drawRectangle(100, 100, 150, 100);\n imgObj.drawCircle(250, 250);\n \n // Rotate everything together\n imgObj.rotate(90);\n \n // All annotations rotate with the image\n}\n```\n\n### Prevent Transform\n\nCancel specific transformations based on conditions:\n\n```tsx\nfunction rotating(args: any): void {\n // Don't allow rotation if image dimensions exceed limits\n if (args.currentDegree !== 0 && args.currentDegree % 90 !== 0) {\n args.cancel = true;\n console.log('Only 90° rotations allowed');\n }\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6011,"content_sha256":"4134dc333197d109925db5f84db4d45fc642b4487d86ef97286b2db3ba8aedd5"},{"filename":"references/undo-redo.md","content":"# Undo and Redo\n\n## History Capacity\n\nThe Image Editor maintains a 16-step history. Once the limit is reached, the oldest action is removed.\n\n## Undo Operations\n\n### Undo Last Action\n\nRevert the most recent edit:\n\n```tsx\nfunction undoLastAction(): void {\n imgObj.undo();\n}\n```\n\n### Multiple Undo\n\nStep back through history:\n\n```tsx\nfunction undoMultiple(steps: number): void {\n for (let i = 0; i \u003c steps; i++) {\n imgObj.undo();\n }\n}\n\n// Undo last 3 actions\nundoMultiple(3);\n```\n\n### Keyboard Shortcut\n\nUse Ctrl+Z:\n\n```tsx\n// Built-in support - users can press Ctrl+Z\n// No code needed\n```\n\n## Redo Operations\n\n### Redo Last Undone Action\n\nReapply the most recently undone edit:\n\n```tsx\nfunction redoLastAction(): void {\n imgObj.redo();\n}\n```\n\n### Multiple Redo\n\nStep forward through history:\n\n```tsx\nfunction redoMultiple(steps: number): void {\n for (let i = 0; i \u003c steps; i++) {\n imgObj.redo();\n }\n}\n\n// Redo last 2 actions\nredoMultiple(2);\n```\n\n### Keyboard Shortcut\n\nUse Ctrl+Y:\n\n```tsx\n// Built-in support - users can press Ctrl+Y\n// No code needed\n```\n\n## Undo/Redo Patterns\n\n### Toggle Between States\n\nSwitch between original and edited:\n\n```tsx\nlet isUndone = false;\n\nfunction toggleState(): void {\n if (isUndone) {\n imgObj.redo();\n } else {\n imgObj.undo();\n }\n isUndone = !isUndone;\n}\n```\n\n### Clear History\n\nReset undo/redo stack:\n\n```tsx\nfunction clearHistory(): void {\n imgObj.reset(); // Resets to original state\n}\n```\n\n### Track Edit Count\n\nMonitor number of changes:\n\n```tsx\nlet editCount = 0;\n\n// Increment on edit operations\nfunction editAction(): void {\n editCount++;\n console.log('Edits made:', editCount);\n}\n\nfunction undoAction(): void {\n if (editCount > 0) {\n editCount--;\n }\n imgObj.undo();\n}\n```\n\n### Save Before Major Edit\n\nCheckpoint system:\n\n```tsx\nlet checkpointImage: ImageData;\n\nfunction createCheckpoint(): void {\n checkpointImage = imgObj.getImageData();\n}\n\nfunction revertToCheckpoint(): void {\n // Cannot directly restore ImageData, so use undo\n // Or implement custom save/load logic\n imgObj.undo();\n}\n```\n\n## Built-in Keyboard Shortcuts\n\n| Shortcut | Action |\n|----------|--------|\n| Ctrl+Z | Undo |\n| Ctrl+Y | Redo |\n| Ctrl+S | Save |\n| Ctrl+O | Open |\n| Delete | Delete selected annotation |\n| Enter | Apply crop/resize |\n| Escape | Cancel operations |\n\n## Advanced Patterns\n\n### Undo/Redo History Display\n\nShow action history:\n\n```tsx\nlet actionHistory: string[] = [];\n\nfunction recordAction(description: string): void {\n actionHistory.push(description);\n}\n\nfunction displayHistory(): void {\n console.log('Edit history:');\n actionHistory.forEach((action, index) => {\n console.log(`${index + 1}. ${action}`);\n });\n}\n\n// Usage\nrecordAction('Rotated 90°');\nrecordAction('Added text \"Title\"');\nrecordAction('Applied Sepia filter');\ndisplayHistory();\n```\n\n### Conditional Undo\n\nOnly undo specific action types:\n\n```tsx\nlet lastAction: string | null = null;\n\nfunction recordAndExecute(actionType: string, action: () => void): void {\n lastAction = actionType;\n action();\n}\n\nfunction undoIfType(type: string): void {\n if (lastAction === type) {\n imgObj.undo();\n lastAction = null;\n }\n}\n\n// Usage\nrecordAndExecute('text', () => {\n const dim = imgObj.getImageDimension();\n imgObj.drawText(dim.x, dim.y, 'Sample');\n});\n\nundoIfType('text'); // Only undo if last action was text\n```\n\n### Batch Undo\n\nUndo multiple related actions as one:\n\n```tsx\nfunction batchEdit(): void {\n imgObj.rotate(90);\n imgObj.flip('Horizontal');\n imgObj.zoom(1.5);\n}\n\nfunction undoBatch(): void {\n // Need to undo 3 times\n for (let i = 0; i \u003c 3; i++) {\n imgObj.undo();\n }\n}\n```\n\n### Undo Within Limits\n\nPrevent undoing beyond available history:\n\n```tsx\nlet undoCount = 0;\nconst maxUndo = 16;\n\nfunction safeUndo(): void {\n if (undoCount \u003c maxUndo) {\n imgObj.undo();\n undoCount++;\n } else {\n console.log('Maximum undo reached');\n }\n}\n```\n\n### Redo Validation\n\nCheck if redo is available:\n\n```tsx\nfunction canRedo(): boolean {\n // Image Editor doesn't expose history state directly\n // This is a conceptual pattern\n return undoCount > 0;\n}\n\nfunction smartRedo(): void {\n if (canRedo()) {\n imgObj.redo();\n }\n}\n```\n\n### Persistent History\n\nSave history to localStorage:\n\n```tsx\nfunction saveHistory(): void {\n const history = actionHistory;\n localStorage.setItem('editHistory', JSON.stringify(history));\n}\n\nfunction loadHistory(): void {\n const saved = localStorage.getItem('editHistory');\n if (saved) {\n actionHistory = JSON.parse(saved);\n }\n}\n```\n\n### Combined Operations\n\nTreat related edits as single unit:\n\n```tsx\nlet groupedEdits: (() => void)[] = [];\n\nfunction beginGroup(): void {\n groupedEdits = [];\n}\n\nfunction addToGroup(edit: () => void): void {\n groupedEdits.push(edit);\n}\n\nfunction executeGroup(): void {\n groupedEdits.forEach(edit => edit());\n}\n\nfunction undoGroup(): void {\n // Undo all grouped edits\n for (let i = 0; i \u003c groupedEdits.length; i++) {\n imgObj.undo();\n }\n}\n\n// Usage\nbeginGroup();\naddToGroup(() => imgObj.rotate(90));\naddToGroup(() => imgObj.drawText(50, 50, 'Text'));\naddToGroup(() => imgObj.zoom(1.5));\nexecuteGroup();\n\n// Single undo removes all 3\nundoGroup();\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5196,"content_sha256":"4ef26c490352452cce935853e2d8e98696d5d56e8241950dfad43367a72cdca7"},{"filename":"references/z-order-layering.md","content":"# Z-Order and Layering\n\n## Table of Contents\n\n- [Z-Order Operations](#z-order-operations)\n- [Layer Management](#layer-management)\n- [Stacking Patterns](#stacking-patterns)\n- [Advanced Patterns](#advanced-patterns)\n\n## Z-Order Operations\n\n### Bring Forward\n\nMove annotation one layer forward:\n\n```tsx\nfunction bringForward(shapeId: string): void {\n imgObj.bringForward(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes.length > 0) {\n bringForward(shapes[0].id);\n}\n```\n\n### Send Backward\n\nMove annotation one layer backward:\n\n```tsx\nfunction sendBackward(shapeId: string): void {\n imgObj.sendBackward(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes.length > 0) {\n sendBackward(shapes[0].id);\n}\n```\n\n### Bring to Front\n\nMove annotation to topmost layer:\n\n```tsx\nfunction bringToFront(shapeId: string): void {\n imgObj.bringToFront(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes.length > 0) {\n bringToFront(shapes[0].id);\n}\n```\n\n### Send to Back\n\nMove annotation to bottom layer:\n\n```tsx\nfunction sendToBack(shapeId: string): void {\n imgObj.sendToBack(shapeId);\n}\n\n// Usage\nconst shapes = imgObj.getShapeSettings();\nif (shapes.length > 0) {\n sendToBack(shapes[0].id);\n}\n```\n\n## Layer Management\n\n### Get All Shapes\n\nAccess all annotations:\n\n```tsx\nfunction getAllShapes(): void {\n const shapes = imgObj.getShapeSettings();\n console.log('Total annotations:', shapes.length);\n \n shapes.forEach((shape, index) => {\n console.log(`Shape ${index}:`, {\n type: shape.type,\n id: shape.id\n });\n });\n}\n```\n\n### Get Specific Shape\n\nGet a particular shape by ID:\n\n```tsx\nfunction getShapeById(shapeId: string): void {\n const shape = imgObj.getShapeSetting(shapeId);\n if (shape) {\n console.log('Shape details:', {\n type: shape.type,\n id: shape.id\n });\n }\n}\n```\n\n### Layer Order Display\n\n```tsx\nfunction displayLayerStack(): void {\n const objects = imgObj.getShapeSettings();\n \n console.log('=== Layer Stack ===');\n objects.forEach((obj, index) => {\n console.log(`${index}: ${obj.type}`);\n });\n}\n```\n\n## Stacking Patterns\n\n### Arrange Multiple Items\n\nOrganize stack of annotations:\n\n```tsx\nfunction arrangeStack(): void {\n // Select text first\n const textItem = imgObj.getShapeSettings().find(obj => obj.type === 'Text');\n if (textItem) {\n imgObj.bringToFront(textItem.id);\n }\n \n // Shape behind text\n const shapeItem = imgObj.getShapeSettings().find(obj => obj.type === 'Shape');\n if (shapeItem) {\n imgObj.sendToBack(shapeItem.id);\n }\n}\n```\n\n### Layer Priority\n\n```tsx\ninterface LayerPriority {\n name: string;\n type: string;\n priority: number;\n}\n\nconst layerPriorities: LayerPriority[] = [\n { name: 'Background', type: 'Background', priority: 0 },\n { name: 'Base Shapes', type: 'Shape', priority: 1 },\n { name: 'Images', type: 'Image', priority: 2 },\n { name: 'Text', type: 'Text', priority: 3 },\n { name: 'Overlay', type: 'Freehand', priority: 4 }\n];\n\nfunction organizeByPriority(): void {\n const objects = imgObj.getShapeSettings();\n \n // Sort by priority\n const sorted = objects.sort((a, b) => {\n const priorityA = layerPriorities.find(p => p.type === a.type)?.priority ?? 999;\n const priorityB = layerPriorities.find(p => p.type === b.type)?.priority ?? 999;\n return priorityA - priorityB;\n });\n}\n```\n\n### Move Between Specific Layers\n\n```tsx\nfunction moveToLayer(itemId: string, targetIndex: number): void {\n const objects = imgObj.getShapeSettings();\n const currentIndex = objects.findIndex(obj => obj.id === itemId);\n \n if (currentIndex \u003c targetIndex) {\n // Move forward\n for (let i = currentIndex; i \u003c targetIndex; i++) {\n imgObj.bringForward(itemId);\n }\n } else if (currentIndex > targetIndex) {\n // Move backward\n for (let i = currentIndex; i > targetIndex; i--) {\n imgObj.sendBackward(itemId);\n }\n }\n}\n\n// Usage: Move item to position 2\nmoveToLayer('shape-1', 2);\n```\n\n## Advanced Patterns\n\n### Automatic Layering\n\n```tsx\nclass LayerManager {\n private layerMap: Map\u003cstring, number> = new Map();\n \n addLayer(itemId: string, zIndex: number): void {\n this.layerMap.set(itemId, zIndex);\n }\n \n arrangeAll(): void {\n const sorted = Array.from(this.layerMap.entries())\n .sort((a, b) => a[1] - b[1]);\n \n sorted.forEach(([itemId]) => {\n imgObj.sendToBack(itemId);\n });\n }\n \n moveUp(itemId: string): void {\n imgObj.bringForward(itemId);\n }\n \n moveDown(itemId: string): void {\n imgObj.sendBackward(itemId);\n }\n}\n\nconst layerManager = new LayerManager();\nlayerManager.addLayer('text-1', 10);\nlayerManager.addLayer('shape-1', 5);\nlayerManager.arrangeAll();\n```\n\n### Group Operations\n\n```tsx\ninterface LayerGroup {\n name: string;\n items: string[];\n}\n\nconst layerGroups: LayerGroup[] = [\n { name: 'Watermarks', items: ['watermark-1', 'watermark-2'] },\n { name: 'Annotations', items: ['note-1', 'note-2', 'note-3'] },\n { name: 'Highlights', items: ['highlight-1'] }\n];\n\nfunction bringGroupForward(groupName: string): void {\n const group = layerGroups.find(g => g.name === groupName);\n if (group) {\n group.items.forEach(itemId => {\n imgObj.bringForward(itemId);\n });\n }\n}\n\nfunction sendGroupToBack(groupName: string): void {\n const group = layerGroups.find(g => g.name === groupName);\n if (group) {\n group.items.forEach(itemId => {\n imgObj.sendToBack(itemId);\n });\n }\n}\n\n// Usage\nbringGroupForward('Watermarks');\n```\n\n### Layer Visibility Toggle\n\n```tsx\ninterface LayerVisibility {\n itemId: string;\n visible: boolean;\n}\n\nclass VisibilityManager {\n private visibilityMap: Map\u003cstring, boolean> = new Map();\n \n setVisibility(itemId: string, visible: boolean): void {\n this.visibilityMap.set(itemId, visible);\n this.updateVisibility(itemId, visible);\n }\n \n private updateVisibility(itemId: string, visible: boolean): void {\n // Note: Direct visibility toggle not available in official API\n // Use updateRedact() or shape updates through proper API methods\n this.visibilityMap.set(itemId, visible);\n }\n \n toggleVisibility(itemId: string): void {\n const current = this.visibilityMap.get(itemId) ?? true;\n this.setVisibility(itemId, !current);\n }\n}\n\nconst visibilityManager = new VisibilityManager();\nvisibilityManager.setVisibility('watermark-1', false);\nvisibilityManager.toggleVisibility('watermark-1');\n```\n\n### Layer Hierarchy Display\n\n```tsx\nfunction renderLayerPanel(): void {\n const objects = imgObj.getShapeSettings();\n \n const layerHTML = objects\n .map((obj, index) => `\n \u003cdiv class=\"layer-item\" data-id=\"${obj.id}\">\n \u003cspan class=\"layer-index\">${index}\u003c/span>\n \u003cspan class=\"layer-type\">${obj.type}\u003c/span>\n \u003cbutton onclick=\"bringToFrontLayer('${obj.id}')\">↑\u003c/button>\n \u003cbutton onclick=\"sendToBackLayer('${obj.id}')\">↓\u003c/button>\n \u003c/div>\n `)\n .join('');\n \n const panel = document.querySelector('.layer-panel');\n if (panel) {\n panel.innerHTML = `\u003cdiv class=\"layer-stack\">${layerHTML}\u003c/div>`;\n }\n}\n\nfunction bringToFrontLayer(itemId: string): void {\n imgObj.bringToFront(itemId);\n renderLayerPanel();\n}\n\nfunction sendToBackLayer(itemId: string): void {\n imgObj.sendToBack(itemId);\n renderLayerPanel();\n}\n```\n\n### Batch Z-Order Management\n\n```tsx\ninterface ZOrderConfig {\n itemId: string;\n operation: 'front' | 'back' | 'forward' | 'backward';\n}\n\nfunction batchUpdateZOrder(configs: ZOrderConfig[]): void {\n configs.forEach(config => {\n switch (config.operation) {\n case 'front':\n imgObj.bringToFront(config.itemId);\n break;\n case 'back':\n imgObj.sendToBack(config.itemId);\n break;\n case 'forward':\n imgObj.bringForward(config.itemId);\n break;\n case 'backward':\n imgObj.sendBackward(config.itemId);\n break;\n }\n });\n}\n\n// Usage\nconst orders: ZOrderConfig[] = [\n { itemId: 'text-1', operation: 'front' },\n { itemId: 'shape-1', operation: 'backward' },\n { itemId: 'image-1', operation: 'back' }\n];\n\nbatchUpdateZOrder(orders);\n```\n\n### Lock Layer Order\n\n```tsx\nclass LockedLayerManager {\n private lockedOrder: string[] = [];\n \n lockCurrentOrder(): void {\n const objects = imgObj.getShapeSettings();\n this.lockedOrder = objects.map(obj => obj.id);\n }\n \n restoreLockedOrder(): void {\n this.lockedOrder.forEach((itemId, targetIndex) => {\n const objects = imgObj.getShapeSettings();\n const currentIndex = objects.findIndex(obj => obj.id === itemId);\n \n if (currentIndex !== targetIndex) {\n if (currentIndex \u003c targetIndex) {\n for (let i = 0; i \u003c (targetIndex - currentIndex); i++) {\n imgObj.bringForward(itemId);\n }\n } else {\n for (let i = 0; i \u003c (currentIndex - targetIndex); i++) {\n imgObj.sendBackward(itemId);\n }\n }\n }\n });\n }\n}\n\nconst lockedManager = new LockedLayerManager();\nlockedManager.lockCurrentOrder();\n// ... user makes changes ...\nlockedManager.restoreLockedOrder();\n```\n\n### Smart Layering\n\n```tsx\nfunction smartLayerArrangement(): void {\n const objects = imgObj.getShapeSettings();\n \n // Categorize objects\n const categories = {\n text: objects.filter(obj => obj.type === 'Text'),\n shapes: objects.filter(obj => obj.type === 'Shape'),\n images: objects.filter(obj => obj.type === 'Image'),\n freehand: objects.filter(obj => obj.type === 'Freehand')\n };\n \n // Arrange by category: backgrounds bottom, text top\n const order = [\n ...categories.images,\n ...categories.shapes,\n ...categories.freehand,\n ...categories.text\n ];\n \n order.forEach((obj, index) => {\n if (index === order.length - 1) {\n imgObj.bringToFront(obj.id);\n } else {\n imgObj.sendToBack(obj.id);\n }\n });\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9797,"content_sha256":"1198f27121f4508630c9cb6898e634d78030a9a044ed25f457121b9d31fce869"},{"filename":"references/zooming-panning.md","content":"# Zooming and Panning\n\n## Table of Contents\n- [Zoom Methods](#zoom-methods)\n- [Zoom Settings](#zoom-settings)\n- [Panning](#panning)\n- [Zoom and Pan Events](#zoom-and-pan-events)\n\n## Zoom Methods\n\n### Zoom In\n\nIncrease magnification level:\n\n```tsx\nfunction zoomIn(): void {\n imgObj.zoom(1.5); // 150% zoom\n}\n\nfunction zoomIn2x(): void {\n imgObj.zoom(2); // 200% zoom\n}\n```\n\n### Zoom Out\n\nDecrease magnification level:\n\n```tsx\nfunction zoomOut(): void {\n imgObj.zoom(0.8); // 80% zoom\n}\n\nfunction zoomOutToFit(): void {\n imgObj.zoom(0.5); // 50% zoom\n}\n```\n\n### Reset Zoom\n\nReturn to 100% (original size):\n\n```tsx\nfunction resetZoom(): void {\n imgObj.zoom(1); // 100% - original size\n}\n```\n\n### Zoom at Specific Point\n\nZoom centered on specific coordinates:\n\n```tsx\nfunction zoomAtPoint(): void {\n const zoomFactor = 2;\n const centerX = 150;\n const centerY = 100;\n \n imgObj.zoom(zoomFactor, { x: centerX, y: centerY });\n}\n```\n\n## Zoom Settings\n\n### Configure Min and Max Zoom\n\nSet zoom boundaries in `zoomSettings`:\n\n```tsx\nimport { ZoomSettingsModel } from '@syncfusion/ej2-react-image-editor';\n\nfunction App() {\n const zoomSettings: ZoomSettingsModel = {\n minZoomFactor: 0.1, // Can zoom out to 10% of original\n maxZoomFactor: 30 // Can zoom in to 30x original\n };\n \n return \u003cImageEditorComponent zoomSettings={zoomSettings} />;\n}\n```\n\n### Default Zoom Limits\n\nBy default:\n- **Minimum:** 0.1 (10% of original)\n- **Maximum:** 10 (10x original size)\n\n### Implement Zoom Controls\n\nCreate zoom in/out buttons with limits:\n\n```tsx\nlet currentZoom = 1;\n\nfunction zoomInClick(): void {\n if (currentZoom \u003c 1) {\n currentZoom += 0.1;\n } else {\n currentZoom += 1;\n }\n \n if (currentZoom > zoomSettings.maxZoomFactor!) {\n currentZoom = zoomSettings.maxZoomFactor!;\n }\n \n imgObj.zoom(currentZoom);\n}\n\nfunction zoomOutClick(): void {\n if (currentZoom \u003c= 1) {\n currentZoom -= 0.1;\n } else {\n currentZoom -= 1;\n }\n \n if (currentZoom \u003c zoomSettings.minZoomFactor!) {\n currentZoom = zoomSettings.minZoomFactor!;\n }\n \n imgObj.zoom(currentZoom);\n}\n\nreturn (\n \u003cdiv>\n \u003cbutton onClick={zoomInClick}>Zoom In\u003c/button>\n \u003cbutton onClick={zoomOutClick}>Zoom Out\u003c/button>\n \u003cspan>{Math.round(currentZoom * 100)}%\u003c/span>\n \u003c/div>\n);\n```\n\n## Panning\n\n### Enable Panning Mode\n\nAllow users to drag and pan the image:\n\n```tsx\nfunction enablePan(): void {\n imgObj.pan(true);\n}\n\nfunction disablePan(): void {\n imgObj.pan(false);\n}\n```\n\n### Pan When Zoomed\n\nPanning is typically enabled when image exceeds canvas size:\n\n```tsx\nfunction zoomAndPan(): void {\n imgObj.zoom(3); // Zoom to 300%\n imgObj.pan(true); // Enable dragging to move image\n}\n```\n\n### Pan During Cropping\n\nUsers can pan within crop selection:\n\n```tsx\nfunction selectAndPan(): void {\n imgObj.select('Square', 50, 50, 300, 300);\n // Panning automatically becomes available for repositioning crop area\n}\n```\n\n## Zoom and Pan Events\n\n### Zooming Event\n\nTriggered during zoom operation:\n\n```tsx\nfunction zooming(args: any): void {\n console.log('Zoom point:', args.zoomPoint);\n console.log('Previous zoom:', args.previousZoomFactor);\n console.log('Current zoom:', args.currentZoomFactor);\n console.log('Trigger:', args.zoomTrigger); // toolbar, mouse, keyboard, etc.\n \n // args.cancel = true; // Cancel zoom if needed\n}\n\n\u003cImageEditorComponent zooming={zooming} />\n```\n\n### Validate Zoom Level\n\nRestrict zoom to specific increments:\n\n```tsx\nfunction zooming(args: any): void {\n // Only allow zoom at 0.5x increments\n const validZooms = [0.5, 1, 1.5, 2, 2.5, 3];\n \n if (!validZooms.includes(args.currentZoomFactor)) {\n args.cancel = true;\n }\n}\n```\n\n### Panning Event\n\nTriggered when user drags the image:\n\n```tsx\nfunction panning(args: any): void {\n console.log('Start point:', args.startPoint);\n console.log('End point:', args.endpoint);\n \n // args.cancel = true; // Cancel panning if needed\n}\n\n\u003cImageEditorComponent panning={panning} />\n```\n\n### Handle Pan Events\n\nReact to panning operations:\n\n```tsx\nfunction panning(args: any): void {\n console.log('Panning started');\n console.log('Start point:', args.startPoint);\n console.log('End point:', args.endpoint);\n \n // You can cancel panning if needed\n // args.cancel = true;\n}\n\n\u003cImageEditorComponent panning={panning} />\n```\n\n## Combined Patterns\n\n### Zoom Level Display\n\nShow current zoom percentage:\n\n```tsx\nlet currentZoomLevel = 100;\n\nfunction zooming(args: any): void {\n currentZoomLevel = Math.round(args.currentZoomFactor * 100);\n updateZoomDisplay(currentZoomLevel);\n}\n\nfunction updateZoomDisplay(level: number): void {\n document.getElementById('zoom-display').textContent = `${level}%`;\n}\n```\n\n### Zoom to Fit Width\n\nScale image to fit container width:\n\n```tsx\nfunction zoomToWidth(): void {\n const dimension = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container') as HTMLElement;\n if (container) {\n const containerWidth = container.offsetWidth;\n const zoomFactor = containerWidth / dimension.width;\n imgObj.zoom(zoomFactor);\n }\n}\n```\n\n### Zoom to Fit Height\n\nScale image to fit container height:\n\n```tsx\nfunction zoomToHeight(): void {\n const dimension = imgObj.getImageDimension();\n const container = document.querySelector('.editor-container') as HTMLElement;\n if (container) {\n const containerHeight = container.offsetHeight;\n const zoomFactor = containerHeight / dimension.height;\n imgObj.zoom(zoomFactor);\n }\n}\n```\n\n### Continuous Zoom\n\nSmooth zoom animation:\n\n```tsx\nfunction continuousZoom(targetZoom: number, steps: number = 10): void {\n let currentZoom = 1;\n const step = (targetZoom - 1) / steps;\n \n const interval = setInterval(() => {\n currentZoom += step;\n imgObj.zoom(currentZoom);\n \n if (currentZoom >= targetZoom) {\n clearInterval(interval);\n }\n }, 50);\n}\n\n// Usage\ncontinuousZoom(2); // Smooth zoom to 200%\n```\n\n### Keyboard Zoom\n\nSupport zoom with keyboard shortcuts:\n\n```tsx\ndocument.addEventListener('keydown', (e) => {\n if (e.ctrlKey) {\n if (e.key === '+' || e.key === '=') {\n e.preventDefault();\n imgObj.zoom(currentZoom + 0.1);\n } else if (e.key === '-') {\n e.preventDefault();\n imgObj.zoom(currentZoom - 0.1);\n }\n }\n});\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6250,"content_sha256":"eeb7bc7784ef2a53efd7d04bfd0a34183a9a22e03e0c1da3f897fcdbeef93982"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Implementing Syncfusion React Image Editor","type":"text"}]},{"type":"paragraph","content":[{"text":"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.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Component Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"The Image Editor combines a canvas-based editing environment with a comprehensive toolbar and contextual tools. It supports:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multiple Input Sources:","type":"text","marks":[{"type":"strong"}]},{"text":" Files, URLs, base64, blobs, file managers, treeviews","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rich Annotation Support:","type":"text","marks":[{"type":"strong"}]},{"text":" Text (with styling), shapes, freehand drawings, watermarks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Professional Effects:","type":"text","marks":[{"type":"strong"}]},{"text":" Filters and fine-tuning controls","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Advanced Operations:","type":"text","marks":[{"type":"strong"}]},{"text":" Z-order management, redaction, frame decoration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Accessibility First:","type":"text","marks":[{"type":"strong"}]},{"text":" Full keyboard navigation, WCAG compliance, RTL support, 120+ localization keys","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Flexible Integration:","type":"text","marks":[{"type":"strong"}]},{"text":" Standalone or within dialogs, with customizable toolbars","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Documentation and Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"🔹 API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Complete API documentation with all properties, methods, and events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Properties overview (core, toolbar, settings)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods for image operations, transformations, annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events for lifecycle, interactions, effects, and toolbars","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enums and type definitions (ArrowheadType, FrameType, RedactType, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Complete working examples with verified method signatures","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation with Vite and create-react-app","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS imports and theme setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Basic component initialization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting width, height, and initial rendering","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Opening and Saving Images","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/opening-saving-images.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/opening-saving-images.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open from file paths, URLs, base64 strings, blobs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open from file uploader, file manager, and treeview","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save/export as PNG, JPEG, SVG, WEBP","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Image dimensions and aspect ratio control","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"File opened, saving, and lifecycle events","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Selection and Cropping","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/selection-cropping.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/selection-cropping.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Insert custom, square, and circle selections","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Crop with aspect ratios (2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 5:7, 7:5, 9:16, 16:9)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Crop method and selection events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Maintain original image size during cropping","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Lock selection area during resizing","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Transform: Rotate, Flip, and Straighten","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/transform-rotate-flip.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/transform-rotate-flip.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rotate clockwise/counter-clockwise by degrees","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Flip horizontally and vertically","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Straighten images with fine degree adjustments (-45° to +45°)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Transform annotations along with image","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rotating and flipping events","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Zoom and Pan Operations","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/zooming-panning.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/zooming-panning.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Zoom in/out with configurable min/max factors","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pan when zoomed or during cropping","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Zoom triggers (toolbar, pinch, mouse wheel, keyboard)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Zooming and panning events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Zoom point calculations","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Text Annotations","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/text-annotations.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/text-annotations.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add text with position, content, and font settings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Text styling (bold, italic, underline, strikethrough)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Font families, sizes, and colors","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multiline text with newline characters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete text annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize font color via shapeChanging event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Freehand Drawing","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/freehand-drawing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/freehand-drawing.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enable/disable freehand drawing mode","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize stroke width and color","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete freehand annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adjust stroke during drawing via shapeChanging event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Shape Annotations","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/shape-annotations.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/shape-annotations.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Draw rectangles, ellipses, lines, arrows, and paths","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize shapes with stroke color, stroke width, and fill color","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rotate shapes with degree parameter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete shape annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize default stroke colors","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shape changing and customization events","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Image Annotations","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/image-annotations.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/image-annotations.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add images or icons as annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Control position, size, rotation, and opacity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Aspect ratio preservation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Watermarks and decorative elements","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Filters","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/filters.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/filters.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply predefined filters (Chrome, Cold, Warm, Grayscale, Sepia, Invert)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Image filtering event","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reset filter to original","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Fine-Tuning","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/finetune.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/finetune.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adjust brightness, contrast, saturation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Control hue, exposure, blur, opacity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Finetune value changing events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Real-time adjustments with sliders","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Undo and Redo","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/undo-redo.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/undo-redo.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Undo/redo operations with 16-step history","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard shortcuts (Ctrl+Z, Ctrl+Y)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"History management and limits","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Toolbar Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/toolbar-customization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/toolbar-customization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Built-in toolbar items (20+ default tools)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add, remove, enable, disable toolbar items","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom toolbar items with event handlers","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Contextual toolbar for annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Toolbar templates for complete customization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Toolbar created and item clicked events","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Access Toolbar","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/quick-access-toolbar.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/quick-access-toolbar.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quick access toolbar for annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Show/hide quick access toolbar","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add custom items to quick access toolbar","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quick access toolbar open event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Resize Image","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/resize-image.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/resize-image.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resize with or without aspect ratio","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Width and height parameters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resizing event with before/after dimensions","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Frame Decoration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/frame-decoration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/frame-decoration.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply frames (Mat, Bevel, Line, Inset, Hook)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize frame color, size, and line style","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Frame changing event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Z-Order Layering","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/z-order-layering.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/z-order-layering.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Bring forward/send backward annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Bring to front/send to back","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Manage annotation layer order","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Redact Sensitive Information","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/redact-sensitive-info.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/redact-sensitive-info.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Blur sensitive areas","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pixelate sensitive information","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Redact CRUD operations (select, update, delete, get)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Privacy and compliance","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Accessibility and Localization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility-localization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/accessibility-localization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2, Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard shortcuts (Ctrl+Z, Ctrl+S, Ctrl+O, Delete, Enter, Escape)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RTL language support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Localization with 120+ locale keys","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Image Restrictions and Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/image-restrictions-validation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/image-restrictions-validation.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Allowed file extensions (.jpg, .png, .svg, .webp, .bmp)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Min and max file size restrictions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"File validation and error alerts","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Clear Image","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/clear-image.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/clear-image.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear editor state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dialog reuse patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Remove previously loaded images","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Fit to Width and Height","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/fit-width-height.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/fit-width-height.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fit image to editor container width","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fit image to editor container height","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Zoom calculations for perfect fit","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Render in Dialog","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/render-in-dialog.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/render-in-dialog.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Render Image Editor within Dialog component","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Content template integration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dialog show/hide patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Reset Image","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/reset-image.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/reset-image.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reset all modifications to original state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Restore unmodified version","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear annotations and effects","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Start Example","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { ImageEditorComponent } from '@syncfusion/ej2-react-image-editor';\nimport React from 'react';\n\nfunction App() {\n let imgObj: ImageEditorComponent;\n\n function imageEditorCreated(): void {\n imgObj.open('https://ej2.syncfusion.com/react/documentation/image-editor/images/bridge.jpeg');\n }\n\n return (\n \u003cdiv>\n \u003cImageEditorComponent\n ref={(img) => { imgObj = img }}\n width=\"550px\"\n height=\"350px\"\n created={imageEditorCreated}\n />\n \u003c/div>\n );\n}\n\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pattern 1: Open + Edit + Save Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open image via ","type":"text"},{"text":"open()","type":"text","marks":[{"type":"code_inline"}]},{"text":" method","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply transformations, annotations, or effects","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"export()","type":"text","marks":[{"type":"code_inline"}]},{"text":" to save as PNG/JPEG/SVG/WEBP","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optionally convert to base64 or blob for backend storage","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pattern 2: Responsive Toolbar","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Define custom toolbar items in ","type":"text"},{"text":"toolbar","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Handle clicks via ","type":"text"},{"text":"toolbarItemClicked","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Execute methods like ","type":"text"},{"text":"rotate()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"zoom()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"drawText()","type":"text","marks":[{"type":"code_inline"}]},{"text":" based on clicked item","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Update contextual toolbar via ","type":"text"},{"text":"toolbarUpdating","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pattern 3: Annotation Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enable annotation mode (freehand, text, shape)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize via ","type":"text"},{"text":"shapeChanging","type":"text","marks":[{"type":"code_inline"}]},{"text":" event (color, stroke, font)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete via ","type":"text"},{"text":"deleteShape()","type":"text","marks":[{"type":"code_inline"}]},{"text":" with shape ID","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Manage layers via z-order methods","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pattern 4: Dialog Integration","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Render Image Editor in Dialog's ","type":"text"},{"text":"content","type":"text","marks":[{"type":"code_inline"}]},{"text":" template","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Load image when dialog opens via ","type":"text"},{"text":"fileOpened","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Call ","type":"text"},{"text":"clearImage()","type":"text","marks":[{"type":"code_inline"}]},{"text":" before closing dialog","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Retrieve edited image data via ","type":"text"},{"text":"export()","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"getImageData()","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pattern 5: Filter + Finetune Pipeline","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply filter via ","type":"text"},{"text":"applyImageFilter()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fine-tune via ","type":"text"},{"text":"finetuneImage()","type":"text","marks":[{"type":"code_inline"}]},{"text":" (brightness, contrast, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Listen to ","type":"text"},{"text":"imageFiltering","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"finetuneValueChanging","type":"text","marks":[{"type":"code_inline"}]},{"text":" events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Combine effects for professional results","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Properties","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"width","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Editor canvas width (e.g., \"550px\", \"100%\")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"height","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Editor canvas height (e.g., \"350px\", \"100%\")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"toolbar","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"array","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Customize toolbar items and visibility","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fontFamily","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add custom font families","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uploadSettings","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Configure file restrictions (extensions, size)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"zoomSettings","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Set min/max zoom factors","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showQuickAccessToolbar","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show/hide quick access toolbar","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"locale","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Set localization (e.g., 'de-DE')","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Events","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Event","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Trigger","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Case","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Component initialized","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Load image on startup","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fileOpened","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Image loaded","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add watermarks, apply defaults","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"beforeSave","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Before export","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Validate, add metadata","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cropping","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"During crop","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prevent scaling, lock dimensions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"zooming","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"During zoom","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Validate zoom level","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rotating","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"During rotate","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Track rotation angle","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"shapeChanging","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Annotation modified","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Customize stroke, font","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"toolbarUpdating","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Toolbar rendered","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add/remove contextual items","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Supported File Formats","type":"text"}]},{"type":"paragraph","content":[{"text":"Open:","type":"text","marks":[{"type":"strong"}]},{"text":" PNG, JPEG, JPG, SVG, WEBP, BMP (local, URL, base64, blob) ","type":"text"},{"text":"Save/Export:","type":"text","marks":[{"type":"strong"}]},{"text":" PNG, JPEG, SVG, WEBP","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Next Steps","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Start with ","type":"text"},{"text":"getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/getting-started.md","title":null}}]},{"text":" for setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Explore ","type":"text"},{"text":"opening-saving-images.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/opening-saving-images.md","title":null}}]},{"text":" to understand data flow","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check specific features in their dedicated reference files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"accessibility-localization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/accessibility-localization.md","title":null}}]},{"text":" for multi-language support","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"syncfusion-react-image-editor","author":"@skillopedia","source":{"stars":3,"repo_name":"react-ui-components-skills","origin_url":"https://github.com/syncfusion/react-ui-components-skills/blob/HEAD/skills/syncfusion-react-image-editor/SKILL.md","repo_owner":"syncfusion","body_sha256":"1b779e37658a71ab1e50af0bda3b84201caf9e3b9ecc4414b8f508fa8ef0d50b","cluster_key":"140f03feef8741ec715cd854de879347158e685e8be62a86845ace3c9a53628b","clean_bundle":{"format":"clean-skill-bundle-v1","source":"syncfusion/react-ui-components-skills/skills/syncfusion-react-image-editor/SKILL.md","text_bytes":229493,"source_commit":"4baa652dcd2a01ebb3cf9ca66051cc18ffa40f81","skills_sh_rank":15708,"attachment_count":25,"text_attachments":25,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/syncfusion-react-image-editor/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"media-content","category_label":"Media"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"media-content","metadata":{"author":"Syncfusion Inc","version":"34.1.29","category":"File Viewers & Editors"},"import_tag":"skills-sh-top20k-2026-11","description":"Master Syncfusion React Image Editor for comprehensive image editing. Use this when users need to edit images, add annotations, apply filters, manage layers, or implement image editing features. Supports multiple formats (PNG, JPEG, SVG, WEBP, BMP), annotations (text, shapes, freehand, images), effects (filters, finetune), and accessibility features."}},"renderedAt":1793676151088}

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