npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mui-image-editor

v0.3.4

Published

A React image editor component built with Material-UI

Readme

MUI Image Editor

A powerful, feature-rich React image editor component built with Material-UI. Edit images directly in your React applications with support for cropping, rotation, flipping, drawing, custom filters, and more.

MUI Image Editor Screenshot

Version License


Table of Contents


Features

  • 🎨 Comprehensive Editing Tools — Crop, rotate, flip, draw, and apply filters.
  • ✏️ Freehand Drawing — Brush with adjustable color, size, opacity, and an eraser tool.
  • 🖼️ Advanced Image Processing — High-quality canvas-based rendering with undo/redo, before/after comparison, and zoom/pan controls.
  • 🔌 Extensible Filter System — Plug in your own filters with rich UI controls (sliders, checkboxes, selects, color pickers).
  • 🌍 Internationalization — Built-in English and Polish translations. Supply your own locale strings or translation function.
  • 🎯 Imperative API — Full programmatic control via React refs: save, reset, undo, redo, zoom, get/set state.
  • 📐 Grid Overlays — Rule of thirds, golden ratio, and pixel grid overlays.
  • Performance — Efficient rendering engine with configurable preview scale, history management, and optional WebGL support.
  • 🎨 Fully Themeable — Customize colors, spacing, and typography via Material-UI theming and design tokens.

Installation

npm install mui-image-editor

Peer Dependencies

This package requires the following peer dependencies to be installed in your project:

npm install react react-dom @mui/material @mui/icons-material @emotion/react @emotion/styled

| Peer Dependency | Version | |------------------------|------------| | react | ^18.3.1 | | react-dom | ^18.3.1 | | @mui/material | ^7.1.2 | | @mui/icons-material | ^7.1.2 | | @emotion/react | ^11.0.0 | | @emotion/styled | ^11.0.0 |


Quick Start

import React, { useRef } from 'react';
import { ImageEditor, EditorHandle } from 'mui-image-editor';

function App() {
  const editorRef = useRef<EditorHandle>(null);

  return (
    <ImageEditor
      src="https://example.com/photo.jpg"
      onSave={(result) => {
        // result: { blob, dataUrl?, format, width, height, operations, exif? }
        const url = URL.createObjectURL(result.blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `edited.${result.format}`;
        a.click();
        URL.revokeObjectURL(url);
      }}
      ref={editorRef}
    />
  );
}

Note: The ImageEditor component fills its parent container. Ensure the parent element has explicit width and height (or uses flex layout) so the editor renders correctly.


Component Props

Required Props

| Prop | Type | Description | |----------|-----------------------------------------------|-----------------------------------------------------| | src | string | Image source URL or data URI to edit. | | onSave | (result: SaveResult) => void | Callback invoked when the user triggers a save. |

SaveResult Shape

{
  blob: Blob;                       // The edited image as a Blob
  dataUrl?: string;                 // Data URL (only if output.returnDataUrl is true)
  format: "png" | "jpeg" | "webp";  // Output format
  width: number;                    // Final image width in pixels
  height: number;                   // Final image height in pixels
  operations: OperationManifest;    // Array of all operations applied
  exif?: Record<string, any>;       // EXIF data (if preserveExif is true)
}

Optional Props

| Prop | Type | Default | Description | |------------------|-------------------------------------------------------------------------------|--------------------|--------------------------------------------------------------------------------------------------| | crossOrigin | "anonymous" \| "use-credentials" \| null | "anonymous" | CORS setting for image loading. | | imageLoader | (src: string) => Promise<Blob \| ArrayBuffer \| File> | — | Custom image loader function (e.g., for authenticated endpoints). Bypasses default URL loading. | | initialState | EditorState | — | Initial editor state to restore (operations, viewport). See State Management.| | onChange | (preview: HTMLCanvasElement \| ImageBitmap, operations: OperationManifest) => void | — | Callback on every edit operation. Useful for auto-save or live previews. | | onError | (err: Error) => void | — | Error handler for image loading failures. | | output | OutputOptions | — | Configure output format, quality, and sizing. See Output Options. | | ui | UIOptions | — | UI customization. See UI Options. | | filters | FilterDefinition[] | [traceLinesFilter]| Array of filter definitions. See Custom Filters. | | tools | ToolDefinition[] | — | Custom tool definitions. See Custom Tools. | | availableTools | ToolId[] | All tools | Restrict which built-in tools are shown. Possible values: "crop", "rotate", "flip", "filters", "draw". | | engine | EngineOptions | — | Engine performance options. See Engine Options. | | locale | SupportedLocale | "en" | Shorthand for built-in translations ("en" or "pl"). See Internationalization. | | i18n | I18nOptions | — | Advanced internationalization options. See I18n Options. |

Output Options

Control what the onSave callback receives.

output?: {
  format?: "png" | "jpeg" | "webp";     // Default: "png"
  quality?: number;                      // Default: 0.92 (for jpeg/webp, ignored for png)
  preserveExif?: boolean;                // Default: false — preserve original EXIF data
  background?: string | null;            // Background color for transparent areas (e.g., "#ffffff")
  colorProfile?: "sRGB" | "display-p3" | "auto"; // Color profile handling
  returnDataUrl?: boolean;               // Default: false — include dataUrl in SaveResult
  maxSize?: {
    width?: number;                      // Maximum output width
    height?: number;                     // Maximum output height
    fit?: "contain" | "cover" | "downscaleOnly";  // How to fit within maxSize
  };
}

Example — Save as JPEG, limit to 1080p:

<ImageEditor
  src="/photo.jpg"
  output={{
    format: 'jpeg',
    quality: 0.85,
    returnDataUrl: true,
    maxSize: { width: 1920, height: 1080, fit: 'contain' }
  }}
  onSave={(result) => {
    console.log(`Saved ${result.width}×${result.height} ${result.format}`);
  }}
/>

UI Options

Customize the editor's appearance and behavior.

ui?: {
  themeMode?: "light" | "dark" | "system";   // Default: inherits from MUI ThemeProvider
  themeOverrides?: object;                    // MUI theme overrides (createTheme options)
  tokens?: Partial<DesignTokens>;             // Design token overrides (see Theming section)
  toolbarPosition?: "top" | "left" | "right"; // Where the toolbar is rendered
  showGrid?: boolean;                         // Show grid overlays on the canvas
  gridType?: "ruleOfThirds" | "goldenRatio" | "pixel" | "none";  // Default: "ruleOfThirds"
  snapping?: boolean;                         // Enable snap-to-grid behavior
  keyboardShortcuts?: boolean;                // Default: true
  mobileLayout?: "compact" | "auto";          // Mobile layout mode
}

Engine Options

Fine-tune rendering performance.

engine?: {
  previewScale?: number;             // Preview resolution scale (e.g., 0.5 for half-res previews)
  useWebGL?: boolean;                // Use WebGL for filter rendering (if available)
  workerCount?: number;              // Number of web workers for parallel processing
  keyframeEvery?: number;            // How often to snapshot for instant undo (lower = more memory, faster undo)
  maxHistoryBytes?: number;          // Maximum memory for undo history (bytes)
  downscaleLargeImages?: {
    maxMP?: number;                  // Max megapixels before auto-downscaling
    method?: "pica" | "canvas";      // Downscale method ("pica" is higher quality)
  };
}

I18n Options

For most use cases, set the top-level locale prop instead:

<ImageEditor src="/photo.jpg" locale="pl" onSave={handleSave} />

For advanced customization (custom translation function, partial string overrides, RTL), use the i18n prop:

i18n?: {
  t?: (key: string, params?: Record<string, any>) => string;  // Custom translation function
  strings?: Partial<Record<EditorStringKey, string>>;          // Override specific strings
  locale?: string;                                              // Locale code (overrides the top-level locale prop)
  rtl?: boolean;                                                // Enable right-to-left layout
}

Resolution priority: i18n.t()i18n.strings → built-in translations for i18n.locale (or top-level locale, or "en").

See the Internationalization section for detailed usage.


Imperative API (EditorHandle)

Access the editor programmatically via a React ref:

import React, { useRef } from 'react';
import { ImageEditor, EditorHandle } from 'mui-image-editor';

function App() {
  const editorRef = useRef<EditorHandle>(null);

  return (
    <>
      <button onClick={() => editorRef.current?.save()}>Save</button>
      <button onClick={() => editorRef.current?.undo()}>Undo</button>
      <button onClick={() => editorRef.current?.redo()}>Redo</button>
      <button onClick={() => editorRef.current?.reset()}>Reset</button>
      <button onClick={() => editorRef.current?.zoomToFit()}>Fit</button>
      <ImageEditor src="/photo.jpg" onSave={console.log} ref={editorRef} />
    </>
  );
}

Available Methods

| Method | Return Type | Description | |----------------------------------------------|--------------------|--------------------------------------------------------------------------| | save() | Promise<void> | Render the full-resolution image and invoke the onSave callback. | | reset() | void | Reset the image to its original, unedited state. | | undo() | void | Undo the last operation. | | redo() | void | Redo the last undone operation. | | zoomToFit() | void | Fit the entire image in the viewport. | | zoom(scale: number) | void | Set the zoom level (clamped to 0.058). | | getState() | EditorState | Get the current editor state (operations, viewport, image metadata). | | setState(state: EditorState) | void | Restore a previously saved editor state. |


Editing Tools

The editor provides five built-in tools, each accessible from the tool panel on the right side of the editor.

Crop

Select a region of the image to keep. The crop tool supports:

  • Free-form cropping — drag to create any rectangle.
  • Aspect ratio presets — 1:1, 4:3, 3:2, 16:9, 9:16.
  • Lock ratio — toggle to constrain the crop rectangle to the selected aspect ratio.
  • Resize handles — drag corner and edge handles to adjust.
  • Move — drag the crop rectangle to reposition.
  • Apply / Cancel — commit or discard the crop.

Rotate

Rotate the image with fine-grained control:

  • Step rotation — quick -90° and +90° buttons for quarter turns.
  • Fine angle slider — adjust from -45° to +45° in 0.1° increments with real-time preview.
  • Angle text input — type an exact angle value.
  • Expand canvas — toggle whether the canvas grows to fit the rotated image (on) or clips it (off).
  • Background color — choose the fill color for areas revealed by rotation.
  • Apply / Cancel — commit the rotation or revert to the pre-rotation state.

Flip

Mirror the image instantly:

  • Flip Horizontal — mirror along the vertical axis (left ↔ right).
  • Flip Vertical — mirror along the horizontal axis (top ↔ bottom).

Flips are applied immediately (no apply/cancel step needed).

Draw

Freehand drawing and annotation directly on the image:

  • Brush color — pick any color via the color picker.
  • Brush size preview — visual indicator of the current brush size.
  • Line width — adjust from 1px to 50px.
  • Opacity — control brush transparency from 5% to 100%.
  • Eraser mode — toggle to erase strokes.
  • Undo / Redo — undo and redo individual strokes (separate from the main undo/redo history).
  • Clear all — remove all unapplied strokes.
  • Apply / Cancel — commit drawn strokes to the image or discard them.

Filters

Apply image filters with live preview:

  • Select a filter from the list of registered filters.
  • Adjust filter parameters using the auto-generated UI (sliders, selects, checkboxes, color pickers).
  • Preview — see the filter effect in real time.
  • Apply — commit the filter to the image.
  • Cancel — discard the filter.

The editor ships with the Trace Lines edge-detection filter by default. You can provide your own filters — see Custom Filters.


Custom Filters

Filter Definition

Create custom filters by implementing the FilterDefinition interface:

import { FilterDefinition, FilterContext } from 'mui-image-editor';

const myFilter: FilterDefinition = {
  id: 'grayscale',               // Unique identifier
  name: 'Grayscale',             // Display name in the UI
  version: '1.0.0',              // Optional version string (for state serialization)

  // UI controls (optional) — auto-generated in the filter panel
  ui: [
    { kind: 'slider', key: 'intensity', label: 'Intensity', min: 0, max: 100, step: 1, default: 100 }
  ],

  // Full-quality apply (required)
  apply: async (ctx: FilterContext, params: Record<string, any>): Promise<ImageBitmap | ImageData> => {
    const bitmap = await ctx.getImageBitmap();
    const canvas = ctx.utils.createCanvas(bitmap.width, bitmap.height);
    const c = canvas.getContext('2d')!;
    c.drawImage(bitmap, 0, 0);
    const imgData = c.getImageData(0, 0, canvas.width, canvas.height);

    const intensity = (params.intensity ?? 100) / 100;
    const { data } = imgData;
    for (let i = 0; i < data.length; i += 4) {
      const avg = 0.299 * data[i] + 0.587 * data[i+1] + 0.114 * data[i+2];
      data[i]   = data[i]   + (avg - data[i])   * intensity;
      data[i+1] = data[i+1] + (avg - data[i+1]) * intensity;
      data[i+2] = data[i+2] + (avg - data[i+2]) * intensity;
    }
    return imgData;
  },

  // Preview apply (optional) — used for real-time preview, can be lower quality
  preview: async (ctx, params) => {
    const bitmap = await ctx.getImageBitmap({ preview: true });
    // ... same logic on a smaller bitmap for speed
    return bitmap;
  },

  // WebGL apply (optional) — for GPU-accelerated rendering
  glApply: (gl, texture, params) => {
    // WebGL shader-based implementation
    return texture;
  }
};

Then pass your filters to the editor:

<ImageEditor
  src="/photo.jpg"
  filters={[myFilter, traceLinesFilter]}
  onSave={handleSave}
/>

FilterContext API

The FilterContext object is passed to your filter's apply and preview functions:

| Property | Type | Description | |------------------------|---------------------------------------------------------------|-----------------------------------------------------------------| | getImageBitmap(opts?) | (opts?: { preview?: boolean }) => Promise<ImageBitmap> | Get the current image. Pass { preview: true } for lower-res. | | canvas2d | HTMLCanvasElement | Shared canvas for temporary 2D operations. | | webgl | WebGLRenderingContext \| WebGL2RenderingContext \| undefined | WebGL context (if engine.useWebGL is enabled). | | abortSignal | AbortSignal \| undefined | Signal that fires if the user cancels the filter. | | utils.imageData(bitmap) | (bitmap: ImageBitmap) => ImageData | Convert an ImageBitmap to ImageData. | | utils.createCanvas(w, h) | (w: number, h: number) => HTMLCanvasElement | Create a temporary canvas with the given dimensions. |

Filter UI Parameters

Define auto-generated UI controls for your filter via the ui array:

| Kind | Properties | Description | |--------------|-----------------------------------------------------------------------------|----------------------------------------------| | slider | key, label, min, max, step?, default, unit? | Numeric slider with optional unit label. | | checkbox | key, label, default? | Boolean toggle. | | select | key, label, options: { label, value }[], default? | Dropdown selection. | | color | key, label, default? | Color picker. |

Built-in Filter: Trace Lines

The traceLinesFilter is a Sobel edge-detection filter that ships with the component.

import { traceLinesFilter } from 'mui-image-editor';

Parameters:

| Parameter | Type | Default | Description | |-------------|---------|---------|------------------------------------------| | threshold | Slider | 0.3 | Edge detection sensitivity (0–1). | | mode | Select | "thin"| Line style: "thin" or "bold" (dilated). |


Custom Tools

Extend the editor with custom tool panels:

import { ToolDefinition, EngineApi } from 'mui-image-editor';

const myTool: ToolDefinition = {
  id: 'watermark',
  label: 'Watermark',
  icon: MyWatermarkIcon,           // Optional React component
  Render: ({ engine, editorRef }) => {
    // Your custom tool UI — engine gives you full access to the editor engine
    return <div>My custom tool panel</div>;
  },
  shortcuts: [                      // Optional keyboard shortcuts
    { combo: 'w', action: 'toggleWatermark' }
  ]
};
<ImageEditor
  src="/photo.jpg"
  tools={[myTool]}
  onSave={handleSave}
/>

Internationalization (i18n)

Built-in Locales

The editor ships with two built-in locales:

  • en — English (default)
  • pl — Polish

Use the locale prop — no custom translation function or strings object needed:

<ImageEditor src="/photo.jpg" locale="pl" onSave={handleSave} />

The locale prop accepts a SupportedLocale value ("en" | "pl") and provides autocomplete in TypeScript.

Note: If you also pass i18n={{ locale: '...' }}, the i18n.locale value takes precedence over the top-level locale prop.

Providing Custom Translations

You have three ways to customize the editor's text, listed in order of priority:

1. Custom Translation Function

A function that receives the string key and optional parameters. If it returns a value different from the key, that value is used.

<ImageEditor
  src="/photo.jpg"
  i18n={{
    t: (key, params) => {
      // Look up key in your i18n library (e.g., i18next, react-intl)
      return myI18n.t(key, params);
    }
  }}
  onSave={handleSave}
/>

2. Custom Strings Object

Override individual string keys:

<ImageEditor
  src="/photo.jpg"
  i18n={{
    strings: {
      'editor.toolbar.save': 'Export Image',
      'editor.tools.crop': 'Trim',
      'editor.draw.title': 'Annotate'
    }
  }}
  onSave={handleSave}
/>

Strings support placeholder interpolation with {paramName} syntax:

i18n={{
  strings: {
    'editor.filters.applyFilter': 'Apply the {name} filter'
  }
}}

3. Built-in Translations (Fallback)

If neither the custom function nor custom strings provide a value, the built-in translation for the selected locale is used.

Translation Key Reference

Toolbar Actions: | Key | Default (English) | |-----|-------------------| | editor.toolbar.save | Save | | editor.toolbar.undo | Undo | | editor.toolbar.redo | Redo | | editor.toolbar.reset | Reset | | editor.toolbar.beforeAfter | Before/After | | editor.toolbar.zoomIn | Zoom In | | editor.toolbar.zoomOut | Zoom Out | | editor.toolbar.zoomToFit | Zoom to Fit | | editor.toolbar.panUp | Pan Up | | editor.toolbar.panDown | Pan Down | | editor.toolbar.panLeft | Pan Left | | editor.toolbar.panRight | Pan Right | | editor.toolbar.more | More |

Tool Names: | Key | Default (English) | |-----|-------------------| | editor.tools.crop | Crop | | editor.tools.rotate | Rotate | | editor.tools.flip | Flip | | editor.tools.filters | Filters | | editor.tools.draw | Draw |

Crop Tool: | Key | Default (English) | |-----|-------------------| | editor.crop.aspectRatio | Aspect Ratio | | editor.crop.free | Free | | editor.crop.lockRatio | Lock ratio | | editor.crop.instructions | Drag to create a crop. Use handles to resize. Move with drag. Ratios apply when locked. |

Rotate Tool: | Key | Default (English) | |-----|-------------------| | editor.rotate.title | Rotate | | editor.rotate.fineAngle | Fine Angle | | editor.rotate.angle | Angle | | editor.rotate.expandCanvas | Expand canvas | | editor.rotate.background | Background |

Flip Tool: | Key | Default (English) | |-----|-------------------| | editor.flip.title | Flip | | editor.flip.horizontal | Flip Horizontal | | editor.flip.vertical | Flip Vertical |

Filters: | Key | Default (English) | |-----|-------------------| | editor.filters.title | Filters | | editor.filters.apply | Apply | | editor.filters.preview | Preview | | editor.filters.cancel | Cancel | | editor.filters.noFilters | No filters registered. | | editor.filters.applyFilter | Apply {name} |

Draw Tool: | Key | Default (English) | |-----|-------------------| | editor.draw.title | Draw | | editor.draw.color | Brush Color | | editor.draw.lineWidth | Line Width | | editor.draw.opacity | Opacity | | editor.draw.eraser | Eraser | | editor.draw.clearAll | Clear All |

Using the Built-in Translations Object

You can also import the built-in translations to use as a base for your own:

import { translations } from 'mui-image-editor';

console.log(translations.en); // { "editor.toolbar.save": "Save", ... }
console.log(translations.pl); // { "editor.toolbar.save": "Zapisz", ... }

Right-to-Left (RTL) Support

Enable RTL layout for Arabic, Hebrew, and other RTL languages:

<ImageEditor
  src="/photo.jpg"
  i18n={{ locale: 'ar', rtl: true, strings: { /* ... */ } }}
  onSave={handleSave}
/>

Theming & Design Tokens

The editor integrates with Material-UI's theming system and exposes its own design tokens for fine-grained control.

Using MUI ThemeProvider

Wrap the editor in a ThemeProvider to inherit your app's theme:

import { ThemeProvider, createTheme } from '@mui/material';

const darkTheme = createTheme({ palette: { mode: 'dark' } });

<ThemeProvider theme={darkTheme}>
  <ImageEditor src="/photo.jpg" onSave={handleSave} />
</ThemeProvider>

Custom Design Tokens

Override the editor's internal design tokens via the ui.tokens prop:

<ImageEditor
  src="/photo.jpg"
  ui={{
    tokens: {
      radius: 16,                    // Border radius (default: 10)
      spacing: 12,                   // Base spacing unit (default: 8)
      toolbarHeight: 64,             // Toolbar height in px (default: 56)
      colors: {
        bg: '#1a1a2e',               // Main background
        panelBg: '#16213e',          // Side panel background
        surface: '#0f3460',          // Surface elements
        primary: '#e94560',          // Primary accent color
        text: '#f1f1f1',             // Text color
        outline: 'rgba(255,255,255,0.15)', // Borders and outlines
        selection: '#53a8d8'         // Selection highlight color
      }
    }
  }}
  onSave={handleSave}
/>

Default Token Values

| Token | Default | |----------------------|-------------------------------| | radius | 10 | | spacing | 8 | | toolbarHeight | 56 | | colors.bg | #0b0b0b | | colors.panelBg | #1b1b1b | | colors.surface | #121212 | | colors.primary | #1976d2 | | colors.text | #e0e0e0 | | colors.outline | rgba(255,255,255,0.12) | | colors.selection | #90caf9 |


State Management

Save and restore the editor's state to enable features like session persistence, collaborative editing, or preset management.

Saving State

const editorRef = useRef<EditorHandle>(null);

const saveToLocalStorage = () => {
  const state = editorRef.current?.getState();
  if (state) {
    localStorage.setItem('editorState', JSON.stringify(state));
  }
};

Restoring State

const [initialState, setInitialState] = useState<EditorState | undefined>();

useEffect(() => {
  const saved = localStorage.getItem('editorState');
  if (saved) setInitialState(JSON.parse(saved));
}, []);

return (
  <ImageEditor
    src="/photo.jpg"
    initialState={initialState}
    onSave={handleSave}
    ref={editorRef}
  />
);

Restoring via Ref

You can also restore state at any time using the imperative API:

editorRef.current?.setState(savedState);

EditorState Shape

{
  imageMeta: {
    naturalWidth: number;             // Original image width
    naturalHeight: number;            // Original image height
    exifOrientation?: number;         // EXIF orientation value
  };
  operations: OperationManifest;      // Array of applied operations
  viewport: {
    zoom: number;                     // Current zoom level
    panX: number;                     // Horizontal pan offset
    panY: number;                     // Vertical pan offset
  };
}

Keyboard Shortcuts

Keyboard shortcuts are enabled by default. Disable them with ui={{ keyboardShortcuts: false }}.

| Shortcut | Action | |-----------------------|-----------------------------| | Ctrl/Cmd + Z | Undo | | Ctrl/Cmd + Shift + Z | Redo | | Ctrl/Cmd + Y | Redo (alternative) | | + / = | Zoom in | | - | Zoom out | | H (hold) | Before/after comparison |


Viewport & Navigation

The editor provides a rich viewport with zoom, pan, and comparison features:

  • Zoom in/out — via toolbar buttons, keyboard shortcuts, or programmatic API.
  • Zoom to fit — fit the entire image in the viewport.
  • Pan — via toolbar directional buttons.
  • Before/after — hold H or use the toolbar button to toggle between the current and original image.
  • Grid overlays — enable with ui={{ showGrid: true }}. Choose from "ruleOfThirds", "goldenRatio", "pixel", or "none".

Operation Types

All editing operations are represented as typed objects, making them serializable and inspectable.

// Crop
{ type: "crop", rect: { x, y, width, height }, refSize?: { width, height }, aspect?: string | null }

// Rotate
{ type: "rotate", angle: number, expandCanvas: boolean, background?: string | null }

// Flip
{ type: "flip", axis: "x" | "y" }

// Filter
{ type: "filter", id: string, params: Record<string, any>, version?: string }

// Draw
{ type: "draw", strokes: DrawStroke[], refSize: { width, height } }

DrawStroke Shape

{
  points: { x: number; y: number }[];  // Array of drawing points
  color: string;                        // Brush color (hex)
  lineWidth: number;                    // Brush size in pixels
  opacity: number;                      // Brush opacity (0–1)
  eraser: boolean;                      // Whether this stroke erases
}

Exports

The package exports the following:

// Components
export { ImageEditor }             // The main editor component (default export)

// Types
export type { EditorHandle }       // Ref type for imperative API
export type { ImageEditorProps }    // Component props type
export type { EditorState }        // Serializable editor state
export type { Operation }          // Union of all operation types
export type { OperationManifest }  // Array of operations
export type { CropOperation }      // Crop operation type
export type { RotateOperation }    // Rotate operation type
export type { FlipOperation }      // Flip operation type
export type { FilterOperation }    // Filter operation type
export type { DrawOperation }      // Draw operation type
export type { DrawStroke }         // Individual draw stroke
export type { FilterDefinition }   // Filter plugin definition
export type { FilterContext }      // Context passed to filter functions
export type { FilterUiParam }      // Filter UI parameter definition
export type { ToolDefinition }     // Custom tool definition
export type { ToolId }             // Built-in tool identifiers
export type { EngineOptions }      // Engine configuration type
export type { DesignTokens }       // Theme token type
export type { EditorStringKey }    // i18n string key type
export type { SupportedLocale }    // Built-in locale type ("en" | "pl")
export type { EngineApi }          // Internal engine API type

// Filters
export { traceLinesFilter }        // Built-in edge detection filter

// i18n
export { translations }           // Built-in translation dictionaries { en, pl }

Browser Support

| Browser | Version | |--------------------|----------| | Chrome / Edge | Latest | | Firefox | Latest | | Safari | Latest |

Required browser features:

  • Canvas API
  • ImageBitmap API
  • ES2021+ JavaScript

Development

Building the Library

npm run build:lib

This creates a dist/ folder with:

  • mui-image-editor.es.js — ES module build
  • mui-image-editor.cjs.js — CommonJS build
  • index.d.ts — TypeScript declarations

Development Mode

npm run dev

Opens a test application with HMR at the Vite dev server.

Publishing to npm

# Simple publish
npm run publish:npm

# Interactive publish script
npm run publish:script

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues, questions, or feature requests, please open an issue on the GitHub repository.