Git Product home page Git Product logo

crop_your_image's People

Contributors

airy-swift avatar chooyan-eng avatar noahbanderson avatar ravikant-paudel avatar tolotrasamuel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

crop_your_image's Issues

Set initial Rect of cropping area based on the Rect of actual image data.

The goal of API should be

Crop(
  image: _imageData,
  controller: _controller,
  initialArea: _rectBasedOnImageData, // <- ADD new property here.
  onCrop: (croppedData) {}, 
),

As initial area based on actual screen is up to users device, initialArea must be based on actual image size.

initialArea is converted into the initial rect based on the size of users' screen and set as initial cropping area.

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.

Assertion _targetImage!=null

Situation: After cropping, onCropped and onStatusChanged with status= ready were called. At this time the crop widget still shows the progress indicator for a while loading the cropped image
Following Exception when I start a new crop before the progress indicator has gone:

E/flutter (17760): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:crop_your_image/src/crop.dart': Failed assertion: line 412 pos 12: '_targetImage != null': is not true.
E/flutter (17760): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
E/flutter (17760): #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
E/flutter (17760): #2 _CropEditorState._crop (package:crop_your_image/src/crop.dart:412:12)
E/flutter (17760): #3 CropController.crop (package:crop_your_image/src/controller.dart:11:34)
E/flutter (17760): #4 _BildausschnittRouteState._cropImage (package:xyz/route/BildausschnittRoute.dart:242:16)
E/flutter (17760): #5 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1072:21)
E/flutter (17760): #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24)
E/flutter (17760): #7 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11)
E/flutter (17760): #8 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:306:5)
E/flutter (17760): #9 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:239:7)
E/flutter (17760): #10 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:615:9)
E/flutter (17760): #11 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12)
E/flutter (17760): #12 PointerRouter._dispatchEventToRoutes. (package:flutter/src/gestures/pointer_router.dart:143:9)
E/flutter (17760): #13 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:617:13)
E/flutter (17760): #14 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18)
E/flutter (17760): #15 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7)
E/flutter (17760): #16 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:460:19)
E/flutter (17760): #17 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:440:22)
E/flutter (17760): #18 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:337:11)
E/flutter (17760): #19 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:395:7)
E/flutter (17760): #20 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:357:5)
E/flutter (17760): #21 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:314:7)
E/flutter (17760): #22 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:295:7)
E/flutter (17760): #23 _invoke1 (dart:ui/hooks.dart:167:13)
E/flutter (17760): #24 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:341:7)
E/flutter (17760): #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)
E/flutter (17760):

Is there a way to be informed when _target image is set, so I can block possibility for start new crop till this point?

Can not able to flip, rotate image

Thank you for making such a good thing in flutter. it's really helpful.

I can not able to rotate and flip(vertically + horizontally) image in Your Crop method.

My code:

                   Crop(
                          controller: _controller,
                          image: widget.imageFile.readAsBytesSync(),  
                          onCropped: (cropped) {
                            croppedData = cropped;
                            isProcessing = false;
                          },
                          initialSize: 0.7,
                          baseColor: Colors.grey.shade700,
                          cornerDotBuilder: (size, cornerIndex) {
                            return _isPreviewing ? const SizedBox.shrink() : const DotControl();
                          },
                          maskColor: _isPreviewing ? Colors.white : null)

Third line in code: image: widget.imageFile.readAsBytesSync(), NEED THIS IMAGE TO ROTATE AND FLIP

Please help me with this.
Thank you.

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.

The picture cannot be displayed, it keeps loading

Use wechat_assets_picker: ^7.0.5 to pick pictures, and the photo[0].originBytes method is converted to Uint8List.
ios, Android, some pictures can be selected, and some pictures will always be loaded.
`

util.requestPhotosPermission().then((value) {
if(!value) return;
});
final List? photo = await AssetPicker.pickAssets(context,
pickerConfig: const AssetPickerConfig(
maxAssets: 1,
gridCount: 3,
pageSize: 15,
requestType: RequestType.image,
gridThumbnailSize: ThumbnailSize.square(100)
));
if(photo != null){
Uint8List? filePath = await photo[0].originBytes;
if(filePath == null){
MyView.showToast('Image selection failed');
return;
}
Navigator.push(context, MaterialPageRoute(builder: (context)=>CropImage(
fileimage: filePath,
result: (value) {
processImage(value);
},
)));
}
q
`

@override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Stack( children: [ Column( children: [ Container(height: ScreenService.topSafeHeight), Expanded( child: Crop( image: widget.fileimage, controller: controller, onCropped: (image) { Navigator.pop(context); widget.result(image); }, aspectRatio: 1, initialSize: 0.8, withCircleUi: true, baseColor: Colors.black, maskColor: Colors.black.withAlpha(150), cornerDotBuilder: (size, edgeAlignment) => const DotControl(color: Colors.white54), )), GestureDetector( onTap: (){ controller.crop(); }, child: Container( height: 50, width: ScreenService.width, color: MyView.mainColor, child: const Center( child: Text( 'Crop Avatar', style: TextStyle( color: Colors.white, fontFamily: 'bold', fontSize: 18 ), ), ) ), ) ], ), Positioned( top: 40,right: 20, child: GestureDetector( onTap: (){ Navigator.pop(context); }, child: const Icon(Icons.clear,size: 35,color: Colors.white,), ), ) ], ), ); }

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!

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 :

20210328_171641.mp4

Configure CropEditor's base color

Colors.blue.shade50 is set to Container.color now.
The goal is to accept configuration by app and apply here with default Colors.white.

First load is slowly & Loading widget should customizable

I don't know what this function that to do but it need too much time to done.

@override
  void didChangeDependencies() {
    final future = compute(_fromByteData, widget.image);
    _lastComputed = future;
    future.then((converted) {
      if (_lastComputed == future) {
        _targetImage = converted;
        _withCircleUi = widget.withCircleUi;
        _resetCroppingArea();

        setState(() {
          _lastComputed = null;
        });
        widget.onStatusChanged?.call(CropStatus.ready);
      }
    });
    super.didChangeDependencies();
  }

And I suggest for you that CircleProgressLoading should be customizable.

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")),
                                    ))
                              ],
                            )
                          ],
                        ),
                      );
              },
            ),

Image has tripled in size after being cropped

I have tested these on several images and when cropping it multiplies its size up to x3. Why is that? Am I doing something wrong?

flutter: Bytes before cropping 1930990 (1.9 MB)
flutter: Bytes after cropping 4916747 (4.9 MB)
Dart file
class PictureCroppingPage extends StatefulWidget {
  const PictureCroppingPage({
    Key? key,
    required this.picture,
    required this.onCropped,
    this.isCircular = false,
    this.aspectRatio,
  }) : super(key: key);

  final Uint8List picture;
  final Function(Uint8List) onCropped;
  final bool isCircular;
  final double? aspectRatio;

  @override
  _PictureCroppingPageState createState() => _PictureCroppingPageState();
}

class _PictureCroppingPageState extends State<PictureCroppingPage> {
  final _controller = CropController();
  bool isCropping = false;

  @override
  Widget build(BuildContext context) {
    print('Bytes before cropping ${widget.picture.lengthInBytes}');
    return Scaffold(
      appBar: AppBar(
        leading: const CloseButton(),
        title: Text(context.l10n.cropPicturePageTitle),
        elevation: 1.0,
      ),
      body: Crop(
        controller: _controller,
        image: widget.picture,
        onCropped: (picture) {
          widget.onCropped(picture);
          print('Bytes after cropping ${picture.lengthInBytes}');
          context.navigator.pop();
        },
        aspectRatio: widget.aspectRatio,
        withCircleUi: widget.isCircular,
        baseColor: context.theme.backgroundColor,
      ),
      bottomNavigationBar: BottomBarAction(
        builder: (context) {
          return DivenElevatedButton(
            isLoading: isCropping,
            isDisabled: isCropping,
            onPressed: () {
              _controller.crop();

              setState(() {
                isCropping = true;
              });
            },
            label: Text(
              context.l10n.cropPicturePageCroppingButton,
            ),
          );
        },
      ),
    );
  }
}
Images attached

IMG_0003

IMG_0002

[ISSUE] Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).

When closing page with CropEditor there is error in the console.

It happens in the method _resetCroppingArea when getting screenSize from context:

void _resetCroppingArea() {
    final screenSize = MediaQuery.of(context).size;

    final imageRatio = _targetImage!.width / _targetImage!.height;
    _isFitVertically = imageRatio < screenSize.aspectRatio;

    _imageRect = calculator.imageRect(screenSize, imageRatio);

    _resizeWith(widget.aspectRatio, widget.initialArea);
  }

image

[Feature] Pan & Zoom the Image Itself into a Fixed Frame Instead of Positioning the Cropping Box

The general way of cropping with this package is to change the rectangular box's dimensions and position. It's very good indeed.

I would like you to provide an opposite way of that. Let us change the position and scale of the underlying image by panning & zooming while keeping the cropper box at the center with a selected aspect ratio.

So instead of us moving the cropping rectangle, we would be dragging the image itself until it is positioned in a stationary cropping frame.

It will be like the cropper of the Instagram's post sharing screen. This is very intuitive for users to adapt.

There is another package on pub.dev for cropping as I said; however, I think your package is better at the moment and if you can implement what I say in this issue, it will be superior.

Thanks a lot!

make it easier to use initialArea

Currently the initialArea expects values based on the image size and not on the screen size.

This is cumbersome, because using the lib the developer does provide byte data and not image data. Hence, the actual image data is not available outside the lib. The developer then needs to build her own version of _fromByteData (see https://github.com/chooyan-eng/crop_your_image/blob/main/lib/src/crop.dart#L537 ) to get the _targetImage.

It would be much more convenient to provide a way that is based on the screen size. The lib then should transform this to actual image sizes by taking into account the ratio between screen size and the actual image data.

This could be an implementation:

// given a screen based area
final initialScreenBasedArea = Rect(...)

// calculate the initalArea based on the image

final img = _fromByteData(byteData);
final screen = MediaQuery.of(context).size;

final imageScreenRatioHorizontal = img.width / screen.width;
final imageScreenRatioVertical = img.height / screen.height;

initialArea = Rect.fromCenter(
  width: initialScreenBasedArea.width * imageScreenRatioHorizontal,
  height: initialScreenBasedArea.height * imageScreenRatioVertical,
  center: Offset(
    initialScreenBasedArea.center.dx * imageScreenRatioHorizontal,
    initialScreenBasedArea.center.dy * imageScreenRatioVertical,
  ),
);

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.

Version solving failed due to flutter_driver

I am getting error in running flutter pub get because version solving fails.

Because every version of flutter_driver from sdk depends on webdriver 2.1.2 which depends on archive >=1.0.0 <3.0.0, every version of flutter_driver from sdk requires archive >=1.0.0 <3.0.0. And because every version of crop_your_image depends on image ^3.0.1 which depends on archive ^3.0.0, flutter_driver from sdk is incompatible with crop_your_image. So, because project depends on both crop_your_image ^0.5.3 and flutter_driver any from sdk, version solving failed. Running "flutter pub get" in project... pub get failed (1; So, because project depends on both crop_your_image ^0.5.3 and flutter_driver any from sdk, version solving failed.)

As the version is clashing with flutter sdk I cannot understand how to fix. Let me know if I need to add any more required information to help me fix it.

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

final screenSize = MediaQuery.of(context).size;

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

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

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.