flutter_img_editor 0.0.6 copy "flutter_img_editor: ^0.0.6" to clipboard
flutter_img_editor: ^0.0.6 copied to clipboard

Image_editor is an embeddable Flutter image editing component that offers common editing tools such as cropping, rotating, and text overlay.

Image Editor Flutter SDK #

中文

Overview #

Image Editor is an embeddable Flutter component that brings cropping, rotation, and text overlays to your app. It ships with platform-friendly image loading/export helpers and a reactive ImageEditorController, enabling native-like editing workflows in minutes.

Highlights #

  • Rich toolset: cropping (free, 16:9, 5:4, 1:1), rotation (free angle, ±90°), and text layers.
  • Stateful workflow: built-in history stack with undo and reset-to-original.
  • Highly configurable: tune tool availability, crop presets, rotation options, and top toolbar copy/colors via ImageEditorConfig.
  • Cross-platform loaders: helpers such as loadImageFromAssets, loadImageFromFile, and loadImageFromNetwork hide platform differences.
  • Pixel export: convert edited ui.Image instances to PNG/JPEG bytes, optionally apply ImageCompressionConfig scaling, or persist them via saveImageToTempFile when a file path is required.
  • Gesture friendly: pinch-to-zoom, drag, and tap to select text layers.

Project Layout #

lib/
  image_editor.dart          # Package entry point
  controller/                # Core controller, crop/rotation/text/history handlers
  models/                    # Configurations and data models
  utils/                     # Image loading, exporting, coordinate helpers
  widgets/                   # Main view, toolbars, and painter

See doc/api_reference.md for detailed API descriptions.

Installation #

Add to your pubspec.yaml:

dependencies:
  flutter_img_editor: ^0.0.3 # last verions

Run:

flutter pub get

Quick Start #

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_img_editor/image_editor.dart';

class AvatarEditorDemo extends StatefulWidget {
  const AvatarEditorDemo({super.key});

  @override
  State<AvatarEditorDemo> createState() => _AvatarEditorDemoState();
}

class _AvatarEditorDemoState extends State<AvatarEditorDemo> {
  ui.Image? _avatar;
  ui.Image? _edited;

  @override
  void initState() {
    super.initState();
    _loadAvatar();
  }

  Future<void> _loadAvatar() async {
    final ui.Image image = await loadImageFromAssets('assets/sample.jpg');
    if (!mounted) return;
    setState(() {
      _avatar = image;
    });
  }

  Future<void> _openEditor() async {
    final ui.Image? avatar = _avatar;
    if (avatar == null) return;
    final ui.Image? result = await Navigator.push<ui.Image?>(
      context,
      MaterialPageRoute(
        builder: (_) => ImageEditor(
          image: avatar,
          config: const ImageEditorConfig(
            // lockToTool: LockToTool.crop1_1, // These parameters will be directly ignored. lockToTool has the highest priority and will immediately perform cropping. 
            enableText: false,
            cropOptions: CropOptionConfig(
              enableFree: false,
              enable16By9: false,
              enable5By4: false,
              enable1By1: true,
            ),
            rotateOptions: RotateOptionConfig(
              enableFree: false,
              enableFixed: true,
            ),
            topToolbar: TopToolbarConfig(
              titleText: 'Edit Avatar',
              confirmText: 'Done',
            ),
            compression: ImageCompressionConfig(
              enabled: true,
              scale: 0.5,
            ),
          ),
        ),
      ),
    );
    if (!mounted || result == null) return;
    setState(() {
      _edited = result;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Avatar Editor Demo')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: _avatar == null ? null : _openEditor,
              child: const Text('Open Editor'),
            ),
            const SizedBox(height: 16),
            if (_edited != null)
              SizedBox(
                height: 180,
                child: RawImage(image: _edited),
              ),
          ],
        ),
      ),
    );
  }
}

1. Load an image resource #

final ui.Image image = await loadImageFromAssets('assets/sample.jpg');

Other entry points:

  • loadImageFromFile(path): available on IO-capable platforms only.
  • loadImageFromNetwork(url): accepts custom http.Client and headers.

2. Embed the editor #

Place ImageEditor in your widget tree, passing the ui.Image to edit alongside optional configuration. The controller manages lifecycle, undo/apply operations, and exposes the latest editing state (see API reference).

3. Export the result #

final Uint8List? pngBytes = await convertUiImageToBytes(editedImage);
// For workflows that absolutely need a path, use:
final String? tempPath = await saveImageToTempFile(
  editedImage,
  compression: const ImageCompressionConfig(scale: 0.5),
);

Recommendation
Prefer rendering ui.Image directly or sending Uint8List buffers. Converting to a temporary file path blocks on disk IO and may take ~1–2 seconds on mid-range devices.

4. Optional: enable export-time compression #

const compression = ImageCompressionConfig(
  enabled: true,
  scale: 0.3, // downscale width/height
  format: ui.ImageByteFormat.png,
);

final ui.Image? result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => ImageEditor(
      image: avatar,
      config: ImageEditorConfig(compression: compression),
    ),
  ),
);

final Uint8List? compressedBytes =
    await convertUiImageToBytes(result!, compression: compression);

Use scale to shrink pixel dimensions and reduce memory/disk footprint. enabled defaults to true, and values in (0,1] take effect. PNG remains lossless; apply custom pipelines if you need additional compression.

Example App #

The example/ folder showcases asset, gallery, camera, and network flows. Run it with:

cd example
flutter run

FAQ #

  • Why is a crop ratio missing? Disable a ratio in ImageEditorConfig.cropOptions and it disappears from the toolbar.
  • How do I control rotation options? Use ImageEditorConfig.rotateOptions to enable/disable free rotation (enableFree) and fixed-angle rotation (enableFixed). When disabled, corresponding buttons are hidden.
  • loadImageFromFile throws on Web? Web lacks direct file system access; the helper throws UnsupportedError. Use a file picker and manually decode bytes.
  • How do I observe editor state? Use ImageEditorController to read active tool, crop rect, text layers, and more.

Contributing #

Issues and pull requests are welcome. Please run flutter test and update documentation before submitting changes.

License #

Released under the MIT License.


Extra API details live in doc/api_reference.md.

8
likes
150
points
47
downloads

Publisher

unverified uploader

Weekly Downloads

Image_editor is an embeddable Flutter image editing component that offers common editing tools such as cropping, rotating, and text overlay.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

cupertino_icons, flutter, http, path_provider

More

Packages that depend on flutter_img_editor