crop_view 0.1.0 copy "crop_view: ^0.1.0" to clipboard
crop_view: ^0.1.0 copied to clipboard

An aspect-locked image cropper for Flutter. The crop window stays fixed while the image pans, zooms and rotates behind it, so the crop is always fully covered. Crops to JPEG (with a quality factor) or [...]

example/lib/main.dart

import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:crop_view/crop_view.dart';
import 'package:flutter/material.dart';

void main() => runApp(const CropViewExampleApp());

/// A tiny app that generates an image, crops it, and shows the result.
class CropViewExampleApp extends StatelessWidget {
  /// Creates the example app.
  const CropViewExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'crop_view example',
      theme: ThemeData.dark(),
      home: const CropPage(),
    );
  }
}

/// Crops a generated gradient and shows the result underneath.
class CropPage extends StatefulWidget {
  /// Creates the crop page.
  const CropPage({super.key});

  @override
  State<CropPage> createState() => _CropPageState();
}

class _CropPageState extends State<CropPage> {
  final CropController _controller = CropController(aspectRatio: 1);
  Future<Uint8List>? _source;
  Uint8List? _result;

  @override
  void initState() {
    super.initState();
    _source = _generateImage();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  /// A colourful placeholder so the example needs no asset.
  Future<Uint8List> _generateImage() async {
    const size = 600;
    const full = Rect.fromLTWH(0, 0, 600, 600);
    final recorder = ui.PictureRecorder();
    final canvas = ui.Canvas(recorder);
    canvas.drawRect(
      full,
      ui.Paint()
        ..shader = const LinearGradient(
          colors: [Colors.indigo, Colors.pink, Colors.orange],
        ).createShader(full),
    );
    for (var i = 0; i < 6; i++) {
      canvas.drawCircle(
        Offset(size * (i + 1) / 7, size / 2),
        24,
        ui.Paint()..color = Colors.white.withValues(alpha: 0.7),
      );
    }
    final image = await recorder.endRecording().toImage(size, size);
    final data = await image.toByteData(format: ui.ImageByteFormat.png);
    image.dispose();
    return data!.buffer.asUint8List();
  }

  Future<void> _crop() async {
    final bytes = await _controller.crop(
      maxEdge: 512,
      format: const CropFormat.jpeg(quality: 85),
    );
    if (mounted) setState(() => _result = bytes);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('crop_view')),
      body: FutureBuilder<Uint8List>(
        future: _source,
        builder: (context, snapshot) {
          final bytes = snapshot.data;
          if (bytes == null) {
            return const Center(child: CircularProgressIndicator());
          }
          return Column(
            children: [
              Expanded(
                child: CropView(imageBytes: bytes, controller: _controller),
              ),
              _Toolbar(controller: _controller, onCrop: _crop),
              if (_result != null)
                Padding(
                  padding: const EdgeInsets.all(12),
                  child: Image.memory(_result!, height: 120),
                ),
            ],
          );
        },
      ),
    );
  }
}

class _Toolbar extends StatelessWidget {
  const _Toolbar({required this.controller, required this.onCrop});

  final CropController controller;
  final VoidCallback onCrop;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          IconButton(
            onPressed: controller.rotateLeft,
            icon: const Icon(Icons.rotate_left),
          ),
          IconButton(
            onPressed: controller.rotateRight,
            icon: const Icon(Icons.rotate_right),
          ),
          IconButton(
            onPressed: controller.zoomIn,
            icon: const Icon(Icons.zoom_in),
          ),
          IconButton(
            onPressed: controller.zoomOut,
            icon: const Icon(Icons.zoom_out),
          ),
          IconButton(
            onPressed: controller.reset,
            icon: const Icon(Icons.restore),
          ),
          FilledButton(onPressed: onCrop, child: const Text('Crop')),
        ],
      ),
    );
  }
}
0
likes
150
points
36
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

An aspect-locked image cropper for Flutter. The crop window stays fixed while the image pans, zooms and rotates behind it, so the crop is always fully covered. Crops to JPEG (with a quality factor) or PNG. Pure Dart and Flutter — no platform channels, no JavaScript, works on every platform including web.

Repository (GitHub)
View/report issues

Topics

#image #crop #cropper #editor #widget

License

MIT (license)

Dependencies

flutter, image

More

Packages that depend on crop_view