A flutter plugin which provides Crop Widget for cropping images.

Overview

crop_your_image

A flutter plugin which provides Crop Widget for cropping images.

crop_your_image provides only minimum UI for deciding cropping area inside images. Other UI parts, such as "Crop" button or "Change Aspect Ratio" button, need to be prepared by each app developers.

This policy helps app developers to build "Cropping page" with the design of their own brand.In order to control the actions for cropping images, you can use CropController from whatever your Widgets.

Image Cropping Preview

Features

  • Minimum UI restrictions.
  • Flexible Crop widget which can be placed anywhere on your widget tree.
  • CropController to control crop actions.
  • Crop with both rect and circle
  • Fix aspect ratio.
  • Set the rect of cropping area programmatically.

Note that this package DON'T

  • read / download image data from any storages, such as gallery, internet, etc.
  • resize, tilt, or other conversions which can be done with image package directly.
  • provide UI parts other than cropping editor, such as "Crop" button, "Preview" button or "Change Aspect Ratio" menu. Building UI is completely UP TO YOU!

Note

Please note that this package is at the very starting point of developping. I'm always waiting for your feedbacks and Pull Requests for making crop_your_image more handy and useful with less bugs.

Usage

Basics

Place Crop Widget wherever you want to place image cropping UI.

final _controller = CropController();

Widget build(BuildContext context) {
  return Crop(
    image: _imageData,
    controller: _controller,
    onCropped: (image) {
      // do something with image data 
    }
  );
}

Then, Crop widget will automatically display cropping editor UI on users screen with given image.

By creating a CropController instance and pass it to controller property of Crop, you can controll the Crop widget from your own designed Widgets.

For example, when you want to crop the image with current selected cropping area, you can just call _controller.crop() wherever you want, such like the code below.

ElevatedButton(
  child: Text('Crop it!')
  onPressed: _cropController.crop,
),

Because _controller.crop() only kicks the cropping process, this method returns immediately without any cropped image data. You can always obtain the result of cropping images via onCropped callback of Crop Widget.

Advanced

All the properties of Crop and their usages are below.

final _controller = CropController();

Widget build(BuildContext context) {
  return Crop(
    image: _imageData,
    controller: _controller,
    onCropped: (image) {
      // do something with image data 
    },
    aspectRatio: 4 / 3,
    initialSize: 0.5,
    // initialArea: Rect.fromLTWH(240, 212, 800, 600),
    // withCircleUi: true,
    baseColor: Colors.blue.shade900,
    maskColor: Colors.white.withAlpha(100),
    onMoved: (newRect) {
      // do something with current cropping area.
    }
    cornerDotBuilder: (size, cornerIndex) => const DotControl(color: Colors.blue),
  );
}
  • image is Image data whose type is UInt8List, and the result of cropping can be obtained via onCropped callback.
  • aspectRatio is the aspect ratio of cropping area. Set null or just omit if you want to crop images with any aspect ratio.
  • aspectRatio can be changed dynamically via setter of CropController.aspectRatio. (see below)
  • initialSize is the initial size of cropping area. 1.0 (or null, by default) fits the size of image, which means cropping area extends as much as possible. 0.5 would be the half. This value is also referred when aspectRatio changes via CropController.aspectRatio.
  • initialArea is the initial Rect of cropping area based on actual image data.
  • withCircleUi flag is to decide the shape of cropping UI. If true, aspectRatio is automatically set 1.0 and the shape of cropping UI would be circle. Note that this flag does NOT affect to the result of cropping image. If you want cropped images with circle shape, call CropController.cropCircle instead of CropController.crop.
  • baseColor is the color of the mask widget which is placed over the cropping editor.
  • maskColor is the color of the base color of the cropping editor.
  • onMoved callback is called when cropping area is moved regardless of its reasons. newRect of argument is current Rect of cropping area.
  • cornerDotBuilder is the builder to build Widget placed at corners. The builder passes size which widget must follow and cornerIndex which indicates the position: 0: left-top, 1: right-top, 2: left-bottom, 3: right-bottom.

In addition, image, aspectRatio, withCircleUi, rect and area can also be changed via CropController, and other properties, such as baseColor, maskColor and cornerDotBuilder, can be changed by setState.

Gallery App

The repository below is for a sample app of using crop_your_image.

chooyan-eng/crop_your_image_gallery

You can find several examples with executable source codes here.

Contact

If you have anything you want to inform me (@chooyan-eng), such as suggestions to enhance this package or functionalities you want etc, feel free to make issues on GitHub or send messages on Twitter @chooyan_i18n.

Comments
  • big image problem

    big image problem

    dear @chooyan-eng thank you for this good crop image i like it

    it has one problem on big image

    you can see it on this video :

    https://user-images.githubusercontent.com/15640035/112752765-d0e8c600-8fe9-11eb-9a58-a6d4ad571431.mp4

    opened by kiaxseventh 10
  • Not compatible with Flutter 1.17.5

    Not compatible with Flutter 1.17.5

    I need to use this plugin in Flutter 1.17.5.

    If i upgrade to Flutter latest version and add this plugin. Version solving is failing due to other dependencies.

    opened by Dinesh41 7
  • [PROPOSAL] Give ability to customize the loading indicator

    [PROPOSAL] Give ability to customize the loading indicator

    Hi! It will be very good to have access to change the progress indicator.

    Could you please add a new parameter to the Crop widget, so we can pass our custom progress indicator widget? Many thank in advance.

    image

    opened by PTLam25 3
  • LateError (LateInitializationError: Field '_delegate@130417691' has not been initialized.)

    LateError (LateInitializationError: Field '_delegate@130417691' has not been initialized.)

    I am facing this issue occasionally. sometimes it works and sometimes not.

    Exception has occurred.
    LateError (LateInitializationError: Field '_delegate@130417691' has not been initialized.)
    
    

    My use case -> I turned a pdf into a list of images (each page as image) and rendering each page in a Pageview widget. on each page i instantiate a crop controller and wrap the image under Crop widget . There is a button in the end which on clicking executes controller.crop() method.

    Putting screenshot here IMG_627195AD7A61-1

    Pasting the code below too if it helps.

    builder: (context, constraints) => PreloadPageView.builder(
                controller: controller.preloadPageController,
                physics: NeverScrollableScrollPhysics(),
                preloadPagesCount: 1,
                itemCount: pageCount,
                itemBuilder: (context, index) => FutureBuilder<Uint8List>(
                  future: controller.getPageImage(pdfDocument!, index + 1),
                  builder: (context, AsyncSnapshot<Uint8List> snapshot) {
                    final cropController = CropController();
                    return !snapshot.hasData
                        ? Container()
                        : SafeArea(
                            child: Column(
                              children: [
                                Expanded(
                                  child: Crop(
                                    image: snapshot.data!,
                                    controller: cropController,
                                    onCropped: (image) {
                                      controller.saveImage(image);
                                    },
                                    initialSize: 0.5,
                                  ),
                                ),
                                Row(
                                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                  children: [
                                    Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceEvenly,
                                      children: [
                                        IconButton(
                                          onPressed: index == 0
                                              ? null
                                              : () {
                                                  controller.preloadPageController
                                                      .previousPage(
                                                          duration: Duration(
                                                              milliseconds: 300),
                                                          curve: Curves.easeIn);
                                                },
                                          icon: Icon(Icons.navigate_before),
                                          iconSize: 32,
                                        ),
                                        Text("${index + 1}/$pageCount"),
                                        IconButton(
                                          onPressed: index == (pageCount - 1)
                                              ? null
                                              : () {
                                                  controller.preloadPageController
                                                      .nextPage(
                                                          duration: Duration(
                                                              milliseconds: 300),
                                                          curve: Curves.easeIn);
                                                },
                                          icon: Icon(Icons.navigate_next),
                                          iconSize: 32,
                                        ),
                                      ],
                                    ),
                                    ElevatedButton.icon(
                                        onPressed: () {
                                          cropController.crop();
                                        },
                                        icon: Icon(Icons.crop),
                                        label: Text('Snap')),
                                    Padding(
                                        padding:
                                            EdgeInsets.symmetric(horizontal: 4),
                                        child: OutlinedButton(
                                          onPressed: () {
                                            Navigator.push(
                                                context,
                                                MaterialPageRoute(
                                                  builder: (context) =>
                                                      SnappedItems(),
                                                ));
                                          },
                                          child: Obx(() => Text(
                                              "Save ${controller.snappedImgs.length} Notes")),
                                        ))
                                  ],
                                )
                              ],
                            ),
                          );
                  },
                ),
    
    opened by deepu 3
  • Widget fails in WidgetTest

    Widget fails in WidgetTest

    Hi,

    I'm having a hard time writing widget tests, when I use your widget. Have you ever tried using your widget in a widget test? It seems like images are not getting loaded, no matter how long I wait in the widget test.

    Do you have any suggestions on that?

    Thanks!

    opened by NikoBoerger 2
  • Freeze UI

    Freeze UI

    The code in this line takes a very long time to execute https://github.com/chooyan-eng/crop_your_image/blob/7bf38421e5469b212e9d7a2dc574d29f8f6a4f4f/lib/src/crop.dart#L192

    I think it must be async or move to Isolate.

    enhancement 
    opened by DrobyshevAlex 2
  • added progressIndicator param

    added progressIndicator param

    Usage

    Crop(
      progressIndicator: const CircularProgressIndicator(),
    ),
    

    or

    Crop(
      progressIndicator: const Text('preparing image...'),
    ),
    

    This change will fix widget test failure.

    opened by chooyan-eng 0
  • The cropping image is too large when interactive is true

    The cropping image is too large when interactive is true

    After the value of 'interactive' was set to true, the cropping image shown on the screen turned too large. When interactive was false, the cropping image automatically fitted the width of the screen or another. I tried to reset the size of the cropping image shown on the screen. So I looked up for the parameter to resize the initial size of the cropping image, but there wasn't. What I wanted to was to resize the shown image to crop hoping you to add a new parameter function such as initialImageSize for instance.

    {ImageSize Function()? imageSize} Type: ImageSize Function()?

    ImageSize({double? width, double? height});

    Example initialImageSize: ImageSize(width, height);

    With the param, initialImageSize, the image to crop will be shown possibly to fit either of the width or the height of the screen with 'interactive' set to true.

    opened by KT99-bit 0
  • Feedback on interactive mode

    Feedback on interactive mode

    I use Crop in interactive: true, fixArea: true mode. It work great, but encountered two situations where API wasn't adequate with interactive mode:

    • No equivalent of onMove; couldn't detect when user started to interact with crop widget. Use case: I wanted to display a hint animation on usage, that should disappear when user start using crop widget.
    • In interactive crop one could want to replace the four dot overlay with something more adapted to interactive mode. The parameter to customize the 4 dots overlays, cornerDotBuilder, don't support that. I managed to synchronize initialAreaBuilder and a custom overlay on top of Crop, but it's not ideal.

    It's less an issue than a feedback, and it surmontable, but thought it was worth reporting.

    opened by gmarizy 0
  • Change of Copyright notice

    Change of Copyright notice

    Hello! According to the Appendix of Apache License 2.0, if you want to license your software under this License you should "attach the boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information". This condition is not met now. Сould you remove the copyright from the text of the license and add a COPYRIGHT NOTICE FILE (like this) in the appropriate form instead (including the year of the software development and your name and surname)? You could also apply the Apache License to your source-code files by attaching the notice to as a comment at the top of each file. Thank you in advance!

    Apache.org says: Include a copy of the Apache License, typically in a file called LICENSE, in your work, and consider also including a NOTICE file. It is also valuable to tag each of your source-code files in case they become detached from the LICENSE file. To apply the Apache License to your source-code files, one approach is to attach the following notice to as a comment at the top of each file. Replace the copyright templates with your own identifying information:

    Copyright [yyyy] [name of copyright owner]

    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

    opened by lubovtorina 0
  • Default value of `initialSize` not working?

    Default value of `initialSize` not working?

    The doc says:

    initialSize is the initial size of cropping area. 1.0 (or null, by default) fits the size of image, which means cropping area extends as much as possible. 0.5 would be the half. This value is also referred when aspectRatio changes via CropController.aspectRatio.

    I tried setting initialSize to 1.0 or null. Neither worked. The default crop size doesn't seem to fill the image.

    image

    opened by mgenware 0
  • Aborting the crop during load leads to an error

    Aborting the crop during load leads to an error

    The cropper does a bit of async work on start up, and if the user / app dismisses the widget during that time, errors will be thrown due to context being accessed after it has been unmounted.

    This happens e.g. in https://github.com/chooyan-eng/crop_your_image/blob/c80794432d2fb5f45d541248c2b6df6adb6078d4/lib/src/crop.dart#L369

    I think all the future.then need to the mounted in the callback before doing anything else.

    E/flutter (14746): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
    E/flutter (14746): Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
    E/flutter (14746): #0      State.context.<anonymous closure> (package:flutter/src/widgets/framework.dart:935:9)
    E/flutter (14746): #1      State.context (package:flutter/src/widgets/framework.dart:941:6)
    E/flutter (14746): #2      _CropEditorState._resetCroppingArea (package:crop_your_image/src/crop.dart:369:38)
    E/flutter (14746): #3      _CropEditorState.didChangeDependencies.<anonymous closure> (package:crop_your_image/src/crop.dart:339:9)
    E/flutter (14746): <asynchronous suspension>
    E/flutter (14746): 
    

    And from Firebase:

    CleanShot 2022-11-17 at 15 24 39@2x
    opened by tp 0
Releases(0.5.1)
Owner
Chooyan
Developing crop_your_image, a Flutter package that provides cropping images functionality. Twitter(Japanese): @chooyan_i18n
Chooyan
📸 Easy to use yet very customizable zoomable image widget for Flutter, Photo View provides a gesture sensitive zoomable widget. Photo View is largely used to show interacive images and other stuff such as SVG.

Flutter Photo View A simple zoomable image/content widget for Flutter. PhotoView enables images to become able to zoom and pan with user gestures such

Fire Slime Games 1.7k Jan 3, 2023
A powerful official extension library of image, which support placeholder(loading)/ failed state, cache network, zoom pan image, photo view, slide out page, editor(crop,rotate,flip), paint custom etc.

extended_image Language: English| 中文简体 A powerful official extension library of image, which support placeholder(loading)/ failed state, cache network

FlutterCandies 1.6k Dec 31, 2022
Crop any widget/image in Android, iOS, Web and Desktop with fancy and customizable UI, in pure Dart code.

crop A Flutter package for cropping any widget, not only images. This package is entirely written in Dart and supports Android, iOS, Web and Desktop.

Mahdi 225 Jan 6, 2023
A simple and easy flutter demo to crop image

flutter_image_crop A simple demo to crop image on flutter easily. A Chinese version of this document can be found here Flutter_image_crop Plugin will

路小飞 3 Jul 8, 2021
An image editor with crop, scribble, mosaic, add-text, flip, rotated functions.

image_editor_dove A high-performance image editor with crop, scribble, mosaic, add-text, flip, rotated functions. Support custom ui style. drawing rot

null 27 Dec 16, 2022
A flutter package which makes it easy to track a series of images.

A flutter package which makes it easy to track a series of images.

Jaehee Kim 2 Oct 7, 2022
Download, cache and show images in a flutter app

Cached network image A flutter library to show images from the internet and keep them in the cache directory. How to use The CachedNetworkImage can be

Baseflow 2.1k Jan 3, 2023
Minimal Unsplash Android App to easily search and download images

Minimal Unsplash Android App to easily search and download images

Yash Garg 18 Dec 7, 2022
Instagram tool to download images, reels, videos and more.

Instagram tool to download images, reels, videos and more.

Yuji 34 Jan 2, 2023
Load GIF images and can set framerate

Load GIF images and can set framerate

Rafael Almeida Barbosa 9 Dec 14, 2022
FMS2 provides Dart implementation of the core design aspects of the UML state diagrams.

FSM2 provides an implementation of the core design aspects of the UML2 state diagrams. FMS2 supports: Nested States Concurrent Regions Guard Condition

Brett Sutton 46 Sep 28, 2022
A flutter carousel widget, support infinite scroll, and custom child widget.

carousel_slider A carousel slider widget. Features Infinite scroll Custom child widgets Auto play Supported platforms Flutter Android Flutter iOS Flut

serenader 1.4k Dec 30, 2022
A scrollable, dismissable by swiping, zoomable, rotatable image gallery on which you can add a dynamic overlay.

Swipe Image Gallery A scrollable, dismissable by swiping, zoomable, rotatable image gallery on which you can add a dynamic overlay. While it is intend

null 20 Dec 7, 2022
Flutter plugin that allows you to display multi image picker on iOS and Android. 👌🔝🎉

IMPORTANT: This repository has been archived and no longer mantained. As I don't have time anymore to work on the package it became very outdated. For

Radoslav Vitanov 898 Apr 29, 2021
This plugin generates thumbnail from video file or URL.

This plugin generates thumbnail from video file or URL. It returns image in memory or writes into a file. It offers rich options to control the image format, resolution and quality. Supports iOS and Android.

John Zhong 156 Jan 3, 2023
A Flutter widget that paints an image and moves it at a slower speed than the main scrolling content.

A Flutter widget that paints an image and moves it at a slower speed than the main scrolling content. Installation Add dependency to your pubspec.yaml

Anatoly Pulyaevskiy 272 Dec 23, 2022
SVG parsing, rendering, and widget library for Flutter

flutter_svg Draw SVG (and some Android VectorDrawable (XML)) files on a Flutter Widget. Getting Started This is a Dart-native rendering library. Issue

Dan Field 1.5k Jan 6, 2023
Flutter package for Image Carousel It is an image carousel widget.

Snapshot Carousel Flutter package for Image Carousel It is an image carousel widget. Supported platforms Flutter Android Flutter iOS Flutter web Flutt

Mrigank Anand 12 Jun 3, 2021
A flutter package to convert any widget to an Image.

Davinci A package to convert any widget to an image which can be saved locally or can be shared to other apps and chats. ?? Preview ℹ️ Usage Prerequis

Sai Gokula Krishnan 37 Dec 20, 2022