picker_image_cropper 0.0.2 copy "picker_image_cropper: ^0.0.2" to clipboard
picker_image_cropper: ^0.0.2 copied to clipboard

A modern Flutter package for selecting and cropping images with a professional UI and advanced features.

example/lib/main.dart

// ignore_for_file: use_build_context_synchronously, unused_element

import 'dart:typed_data';

import 'package:example/new.dart';
import 'package:flutter/material.dart';
import 'package:picker_image_cropper/picker_image_cropper.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Image Picker Cropper Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const ExampleScreen(),
    );
  }
}

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

  @override
  State<ExampleScreen> createState() => _ExampleScreenState();
}

class _ExampleScreenState extends State<ExampleScreen> {
  Uint8List? _croppedImageBytes;
  CropResult? _cropResult;

  CropperTheme _selectedTheme = CropperTheme.dark;
  CropAspectRatio _selectedAspectRatio = CropAspectRatio.square();
  CropOverlayType _selectedOverlayType = CropOverlayType.rectangle;
  bool _useDraggableCropper = true;
  OutputType _selectedOutputType = OutputType.both;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Image Picker Cropper',
          style: TextStyle(fontWeight: FontWeight.w600),
        ),
        centerTitle: true,
        backgroundColor: colorScheme.surface,
        foregroundColor: colorScheme.onSurface,
        elevation: 1,
        shadowColor: Colors.black12,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Settings Section
            Card(
              elevation: 2,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(16),
              ),
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Icon(
                          Icons.settings,
                          color: colorScheme.primary,
                          size: 20,
                        ),
                        const SizedBox(width: 8),
                        Text(
                          'تنظیمات برش تصویر',
                          style: TextStyle(
                            fontSize: 14,
                            fontWeight: FontWeight.w600,
                            color: colorScheme.primary,
                            letterSpacing: 0.5,
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 20),

                    // Theme Selection
                    _buildSettingItem(
                      title: 'تم رنگی',
                      child: DropdownButton<CropperTheme>(
                        value: _selectedTheme,
                        isExpanded: true,
                        dropdownColor: colorScheme.surfaceContainer,
                        borderRadius: BorderRadius.circular(12),
                        style: TextStyle(color: colorScheme.onSurface),
                        items: const [
                          DropdownMenuItem(
                            value: CropperTheme.dark,
                            child: Text('تم تیره'),
                          ),
                          DropdownMenuItem(
                            value: CropperTheme.light,
                            child: Text('تم روشن'),
                          ),
                          DropdownMenuItem(
                            value: CropperTheme.blue,
                            child: Text('تم آبی'),
                          ),
                        ],
                        onChanged: (theme) {
                          if (theme != null) {
                            setState(() => _selectedTheme = theme);
                          }
                        },
                      ),
                    ),

                    // Aspect Ratio Selection
                    _buildSettingItem(
                      title: 'نسبت ابعاد',
                      child: DropdownButton<CropAspectRatio>(
                        value: _selectedAspectRatio,
                        isExpanded: true,
                        dropdownColor: colorScheme.surfaceContainer,
                        borderRadius: BorderRadius.circular(12),
                        style: TextStyle(color: colorScheme.onSurface),
                        items: [
                          DropdownMenuItem(
                            value: CropAspectRatio.free(),
                            child: Text(CropAspectRatio.free().displayName),
                          ),
                          DropdownMenuItem(
                            value: CropAspectRatio.square(),
                            child: Text(CropAspectRatio.square().displayName),
                          ),
                          DropdownMenuItem(
                            value: CropAspectRatio.standard(),
                            child: Text(CropAspectRatio.standard().displayName),
                          ),
                          DropdownMenuItem(
                            value: CropAspectRatio.widescreen(),
                            child: Text(
                              CropAspectRatio.widescreen().displayName,
                            ),
                          ),
                          DropdownMenuItem(
                            value: CropAspectRatio.photo(),
                            child: Text(CropAspectRatio.photo().displayName),
                          ),
                          DropdownMenuItem(
                            value: CropAspectRatio.portrait(),
                            child: Text(CropAspectRatio.portrait().displayName),
                          ),
                        ],
                        onChanged: (ratio) {
                          if (ratio != null) {
                            setState(() => _selectedAspectRatio = ratio);
                          }
                        },
                      ),
                    ),

                    // Overlay Type Selection
                    _buildSettingItem(
                      title: 'نوع برش',
                      child: DropdownButton<CropOverlayType>(
                        value: _selectedOverlayType,
                        isExpanded: true,
                        dropdownColor: colorScheme.surfaceContainer,
                        borderRadius: BorderRadius.circular(12),
                        style: TextStyle(color: colorScheme.onSurface),
                        items: const [
                          DropdownMenuItem(
                            value: CropOverlayType.rectangle,
                            child: Text('مستطیل'),
                          ),
                          DropdownMenuItem(
                            value: CropOverlayType.circle,
                            child: Text('دایره'),
                          ),
                        ],
                        onChanged: (type) {
                          if (type != null) {
                            setState(() => _selectedOverlayType = type);
                          }
                        },
                      ),
                    ),

                    // Output Type Selection
                    _buildSettingItem(
                      title: 'نوع خروجی',
                      child: DropdownButton<OutputType>(
                        value: _selectedOutputType,
                        isExpanded: true,
                        dropdownColor: colorScheme.surfaceContainer,
                        borderRadius: BorderRadius.circular(12),
                        style: TextStyle(color: colorScheme.onSurface),
                        items: const [
                          DropdownMenuItem(
                            value: OutputType.bytes,
                            child: Text('فقط بایت'),
                          ),
                          DropdownMenuItem(
                            value: OutputType.file,
                            child: Text('فقط فایل'),
                          ),
                          DropdownMenuItem(
                            value: OutputType.both,
                            child: Text('هر دو (بایت + فایل)'),
                          ),
                        ],
                        onChanged: (type) {
                          if (type != null) {
                            setState(() => _selectedOutputType = type);
                          }
                        },
                      ),
                    ),

                    // Cropper Type Selection
                    Container(
                      decoration: BoxDecoration(
                        color: colorScheme.surfaceContainerLowest,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      child: SwitchListTile(
                        title: const Text(
                          'برش قابل جابجایی',
                          style: TextStyle(fontWeight: FontWeight.w500),
                        ),
                        subtitle: const Text('فعال کردن جعبه برش قابل جابجایی'),
                        value: _useDraggableCropper,
                        onChanged: (value) {
                          setState(() => _useDraggableCropper = value);
                        },
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 28),

            // Action Buttons
            Row(
              children: [
                Expanded(
                  child: FilledButton.tonalIcon(
                    onPressed: () => _pickAndCropFromGallery(),
                    icon: const Icon(Icons.photo_library),
                    label: const Text('گالری'),
                    style: FilledButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: FilledButton.tonalIcon(
                    onPressed: () => _pickAndCropFromCamera(),
                    icon: const Icon(Icons.camera_alt),
                    label: const Text('دوربین'),
                    style: FilledButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                  ),
                ),
              ],
            ),

            const SizedBox(height: 16),

            // New Direct Methods Section
            Text(
              'متدهای جدید (مستقیم)',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.w600,
                color: colorScheme.primary,
              ),
            ),
            const SizedBox(height: 12),

            Row(
              children: [
                Expanded(
                  child: FilledButton.icon(
                    onPressed: () => _pickFromGalleryAndCrop(),
                    icon: const Icon(Icons.photo_library_outlined),
                    label: const Text('گالری مستقیم'),
                    style: FilledButton.styleFrom(
                      backgroundColor: colorScheme.secondary,
                      foregroundColor: colorScheme.onSecondary,
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: FilledButton.icon(
                    onPressed: () => _captureAndCrop(),
                    icon: const Icon(Icons.camera_enhance),
                    label: const Text('دوربین مستقیم'),
                    style: FilledButton.styleFrom(
                      backgroundColor: colorScheme.tertiary,
                      foregroundColor: colorScheme.onTertiary,
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                  ),
                ),
              ],
            ),

            const SizedBox(height: 28),

            // Result Section
            if (_cropResult != null || _croppedImageBytes != null) ...[
              // File Path Information
              if (_cropResult?.hasFilePath == true) ...[
                Card(
                  elevation: 1,
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Row(
                          children: [
                            Icon(
                              Icons.folder,
                              color: colorScheme.primary,
                              size: 20,
                            ),
                            const SizedBox(width: 8),
                            Text(
                              'اطلاعات فایل',
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                color: colorScheme.primary,
                              ),
                            ),
                          ],
                        ),
                        const SizedBox(height: 12),
                        Text(
                          'مسیر فایل:',
                          style: TextStyle(
                            fontWeight: FontWeight.w500,
                            color: colorScheme.onSurface.withValues(alpha: 0.7),
                          ),
                        ),
                        const SizedBox(height: 4),
                        Container(
                          width: double.infinity,
                          padding: const EdgeInsets.all(12),
                          decoration: BoxDecoration(
                            color: colorScheme.surfaceContainerHighest,
                            borderRadius: BorderRadius.circular(8),
                            border: Border.all(
                              color: colorScheme.outline.withValues(alpha: 0.2),
                            ),
                          ),
                          child: Text(
                            _cropResult!.actualFilePath ?? 'No path available',
                            style: TextStyle(
                              fontFamily: 'monospace',
                              fontSize: 12,
                              color: colorScheme.onSurface,
                            ),
                          ),
                        ),
                        if (_cropResult!.hasBytes) ...[
                          const SizedBox(height: 8),
                          Text(
                            'حجم بایت: ${_cropResult!.bytesSize} bytes',
                            style: TextStyle(
                              fontSize: 12,
                              color: colorScheme.onSurface.withValues(
                                alpha: 0.6,
                              ),
                            ),
                          ),
                        ],
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 20),
              ],

              Text(
                'تصویر برش خورده (نمایش مستطیلی)',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                  color: colorScheme.primary,
                  letterSpacing: 0.5,
                ),
              ),
              const SizedBox(height: 16),

              // Rectangle Preview
              Container(
                decoration: BoxDecoration(
                  color: colorScheme.surfaceContainer,
                  borderRadius: BorderRadius.circular(16),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withValues(alpha: 0.1),
                      blurRadius: 8,
                      offset: const Offset(0, 2),
                    ),
                  ],
                ),
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(16),
                  child: Builder(
                    builder: (context) {
                      final bytes = _croppedImageBytes ?? _cropResult!.bytes!;
                      debugPrint(
                        'Image display - bytes type: ${bytes.runtimeType}',
                      );

                      // Safe conversion to Uint8List
                      Uint8List imageBytes;
                      imageBytes = bytes;

                      return Image.memory(
                        imageBytes,
                        fit: BoxFit.contain,
                        height: 300,
                      );
                    },
                  ),
                ),
              ),

              const SizedBox(height: 20),

              // Circle Preview Box
              Text(
                'تصویر برش خورده (نمایش دایره‌ای)',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                  color: colorScheme.primary,
                  letterSpacing: 0.5,
                ),
              ),
              const SizedBox(height: 16),

              Center(
                child: Builder(
                  builder: (context) {
                    final bytes = _croppedImageBytes ?? _cropResult!.bytes!;
                    debugPrint(
                      'CircleAvatar - bytes type: ${bytes.runtimeType}',
                    );

                    // Safe conversion to Uint8List
                    Uint8List imageBytes;
                    imageBytes = bytes;

                    return CircleAvatar(
                      radius: 80,
                      backgroundColor: colorScheme.surfaceContainer,
                      backgroundImage: MemoryImage(imageBytes),
                    );
                  },
                ),
              ),

              const SizedBox(height: 20),

              Row(
                children: [
                  Expanded(
                    child: FilledButton(
                      onPressed: _saveImage,
                      style: FilledButton.styleFrom(
                        padding: const EdgeInsets.symmetric(vertical: 16),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                      ),
                      child: const Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Icon(Icons.save, size: 20),
                          SizedBox(width: 8),
                          Text('ذخیره تصویر'),
                        ],
                      ),
                    ),
                  ),
                  const SizedBox(width: 16),
                  Expanded(
                    child: OutlinedButton(
                      onPressed: _clearImage,
                      style: OutlinedButton.styleFrom(
                        padding: const EdgeInsets.symmetric(vertical: 16),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                      ),
                      child: const Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Icon(Icons.clear, size: 20),
                          SizedBox(width: 8),
                          Text('پاک کردن'),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ] else ...[
              Container(
                height: 200,
                decoration: BoxDecoration(
                  color: colorScheme.surfaceContainer,
                  borderRadius: BorderRadius.circular(16),
                  border: Border.all(
                    color: colorScheme.outlineVariant,
                    width: 1,
                  ),
                ),
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(
                        Icons.image_outlined,
                        size: 64,
                        color: colorScheme.onSurface.withValues(alpha: 0.5),
                      ),
                      const SizedBox(height: 16),
                      Text(
                        'هیچ تصویری انتخاب نشده',
                        style: TextStyle(
                          color: colorScheme.onSurface.withValues(alpha: 0.5),
                          fontSize: 16,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'از گالری یا دوربین تصویر انتخاب کنید',
                        style: TextStyle(
                          color: colorScheme.onSurface.withValues(alpha: 0.3),
                          fontSize: 14,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(
            context,
          ).push(MaterialPageRoute(builder: (context) => NewScreen()));
        },
        tooltip: 'انتخاب تصویر از گالری',
        backgroundColor: colorScheme.primary,
        foregroundColor: colorScheme.onPrimary,
        child: const Icon(Icons.add_a_photo),
      ),
    );
  }

  Widget _buildSettingItem({required String title, required Widget child}) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: TextStyle(
              fontWeight: FontWeight.w500,
              fontSize: 14,
              color: Theme.of(
                context,
              ).colorScheme.onSurface.withValues(alpha: 0.8),
            ),
          ),
          const SizedBox(height: 8),
          Container(
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.surfaceContainerLowest,
              borderRadius: BorderRadius.circular(12),
            ),
            padding: const EdgeInsets.symmetric(horizontal: 12),
            child: child,
          ),
        ],
      ),
    );
  }

  Future<void> _pickAndCropFromGallery() async {
    // Use the updated pickAndCrop method that now supports CropResult
    final result = await ImagePickerCropper.pickAndCrop(
      context: context,
      fromCamera: false,
      theme: _selectedTheme,
      aspectRatio: _selectedAspectRatio,
      overlayType: _selectedOverlayType,
      useDraggableCropper: _useDraggableCropper,
      outputType: _selectedOutputType,
    );

    if (result == null) {
      debugPrint("result is null:$result");
    }

    if (result != null) {
      setState(() {
        debugPrint("result.bytes: ${result.bytes}");
        debugPrint('Gallery method - result type: ${result.runtimeType}');
        debugPrint(
          'Gallery method - result.bytes type: ${result.bytes.runtimeType}',
        );
        _cropResult = result;
        _croppedImageBytes = result
            .bytes; // Direct assignment - result.bytes is already Uint8List?
      });
    }
  }

  Future<void> _pickAndCropFromGalleryWithCallback() async {
    // Use the new callback-based method
    await ImagePickerCropper.pickAndCropWithCallback(
      context: context,
      fromCamera: false,
      theme: _selectedTheme,
      aspectRatio: _selectedAspectRatio,
      overlayType: _selectedOverlayType,
      useDraggableCropper: _useDraggableCropper,
      onCompleted: (file, bytes) {
        setState(() {
          debugPrint("Callback - file: $file");
          debugPrint("Callback - bytes: $bytes");
          if (file != null && bytes != null) {
            _cropResult = CropResult.both(file: file, bytes: bytes);
          } else if (file != null) {
            _cropResult = CropResult.file(file);
          } else if (bytes != null) {
            _cropResult = CropResult.bytes(bytes);
          }
          _croppedImageBytes = bytes;
        });
      },
      onFileCompleted: (file) {
        debugPrint("File callback - file: $file");
      },
      onBytesCompleted: (bytes) {
        debugPrint("Bytes callback - bytes length: ${bytes.length}");
      },
    );
  }

  Future<void> _pickAndCropFromCamera() async {
    // Use the updated pickAndCrop method that now supports CropResult
    final result = await ImagePickerCropper.pickAndCrop(
      context: context,
      fromCamera: true,
      theme: _selectedTheme,
      aspectRatio: _selectedAspectRatio,
      overlayType: _selectedOverlayType,
      useDraggableCropper: _useDraggableCropper,
      outputType: _selectedOutputType,
    );

    if (result != null) {
      setState(() {
        _cropResult = result;
        _croppedImageBytes = result
            .bytes; // Direct assignment - result.bytes is already Uint8List?
      });
    }
  }

  void _saveImage() {
    String message = 'تصویر با موفقیت ذخیره شد!';

    if (_cropResult?.hasFilePath == true) {
      message += '\nمسیر: ${_cropResult!.actualFilePath}';
    }

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: Theme.of(context).colorScheme.primary,
        behavior: SnackBarBehavior.floating,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
        duration: const Duration(seconds: 4),
      ),
    );
  }

  void _clearImage() {
    setState(() {
      _croppedImageBytes = null;
      _cropResult = null;
    });
  }

  // متد جدید برای گرفتن عکس مستقیم از دوربین و کراپ کردن
  Future<void> _captureAndCrop() async {
    try {
      final result = await ImagePickerCropper.captureAndCrop(
        context: context,
        theme: _selectedTheme,
        aspectRatio: _selectedAspectRatio,
        overlayType: _selectedOverlayType,
        useDraggableCropper: _useDraggableCropper,
        outputType: _selectedOutputType,
      );

      if (result != null) {
        setState(() {
          debugPrint('Capture method - result type: ${result.runtimeType}');
          debugPrint(
            'Capture method - result.bytes type: ${result.bytes.runtimeType}',
          );
          _cropResult = result;
          _croppedImageBytes = result.bytes;
        });

        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('عکس با موفقیت گرفته شد و کراپ شد!'),
            backgroundColor: Colors.green,
            behavior: SnackBarBehavior.floating,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(8),
            ),
          ),
        );
      }
    } catch (e) {
      debugPrint('Error in _captureAndCrop: $e');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('خطا در گرفتن عکس: $e'),
          backgroundColor: Colors.red,
          behavior: SnackBarBehavior.floating,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
        ),
      );
    }
  }

  // متد جدید برای انتخاب مستقیم از گالری و کراپ کردن
  Future<void> _pickFromGalleryAndCrop() async {
    try {
      final result = await ImagePickerCropper.pickFromGalleryAndCrop(
        context: context,
        theme: _selectedTheme,
        aspectRatio: _selectedAspectRatio,
        overlayType: _selectedOverlayType,
        useDraggableCropper: _useDraggableCropper,
        outputType: _selectedOutputType,
      );

      if (result != null) {
        setState(() {
          debugPrint(
            'Gallery direct method - result type: ${result.runtimeType}',
          );
          debugPrint(
            'Gallery direct method - result.bytes type: ${result.bytes.runtimeType}',
          );
          _cropResult = result;
          _croppedImageBytes = result.bytes;
        });

        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('تصویر با موفقیت انتخاب شد و کراپ شد!'),
            backgroundColor: Colors.green,
            behavior: SnackBarBehavior.floating,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(8),
            ),
          ),
        );
      }
    } catch (e) {
      debugPrint('Error in _pickFromGalleryAndCrop: $e');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('خطا در انتخاب تصویر: $e'),
          backgroundColor: Colors.red,
          behavior: SnackBarBehavior.floating,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
        ),
      );
    }
  }
}
1
likes
160
points
209
downloads

Publisher

verified publisherswanflutterdev.com

Weekly Downloads

A modern Flutter package for selecting and cropping images with a professional UI and advanced features.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

equatable, flutter, image, image_picker, image_picker_for_web, path

More

Packages that depend on picker_image_cropper