hm21 / pro_image_editor

The pro_image_editor is a Flutter widget designed for image editing within your application. It provides a flexible and convenient way to integrate image editing capabilities into your Flutter project.
https://hm21.github.io/pro_image_editor/
BSD 3-Clause "New" or "Revised" License
140 stars 75 forks source link

[Bug]: If you open and close the editor like CropRotateEditor many times it will eventually bug out and the next times you open it it will always bug #236

Open joaopinacio opened 1 month ago

joaopinacio commented 1 month ago

Package Version

5.1.1

Flutter Version

3.24.3

Platforms

Web

How to reproduce?

create the CropRotateEditor like:

 await showDialog<void>(
        context: context,
         builder: (_) {
          return CropRotateEditor.network(
            image,
            initConfigs: CropRotateEditorInitConfigs(
              theme: ThemeData.dark(),
              convertToUint8List: true,
              onImageEditingComplete: (bytes) async {
                final blob = html.Blob([bytes], 'image/png');
                final croppedPath = html.Url.createObjectUrlFromBlob(blob);
               /// use croppedPath todo whatever you want with croppedImage here 

                Navigator.pop(context);
              },
              configs: ProImageEditorConfigs(
                designMode: platformDesignMode,
                imageEditorTheme: ImageEditorTheme(
                  cropRotateEditor: CropRotateEditorTheme(
                    cropCornerLength: 40,
                    cropCornerColor: Colors.blue,
                  ),
                ),
                imageGenerationConfigs: const ImageGenerationConfigs(
                  outputFormat: OutputFormat.png,
                ),
                customWidgets: ImageEditorCustomWidgets(
                  cropRotateEditor: CustomWidgetsCropRotateEditor(
                    appBar: (state, stream) => ReactiveCustomAppbar(
                      stream: stream,
                      builder: (context) {
                        return AppBar(
                          automaticallyImplyLeading: false,
                          title: Text(
                            'Edit',
                          ),
                        );
                      },
                    ),
                    bottomBar: (editor, stream) => ReactiveCustomWidget(
                      stream: stream,
                      builder: (context) {
                        return Padding(
                          padding: const EdgeInsets.only(right: 24, left: 24, bottom: 24),
                          child: Row(
                            mainAxisSize: MainAxisSize.min,
                            children: [
                              InkWell(
                                onTap: editor.close,
                                child: Padding(
                                  padding: const EdgeInsets.all(20),
                                  child: Text(
                                    'Cancel',
                                  ),
                                ),
                              ),
                              const Spacer(),
                              const Spacer(),
                              InkWell(
                                onTap: () => editor.done(),
                                child: Padding(
                                  padding: const EdgeInsets.all(20),
                                  child: Text(
                                    'Choose',
                                  ),
                                ),
                              ),
                            ],
                          ),
                        );
                      },
                    ),
                  ),
                ),
                cropRotateEditorConfigs: const CropRotateEditorConfigs(
                  desktopCornerDragArea: 20,
                  initAspectRatio: 0,
                ),
              ),
            ),
          );
        },
    );

I know that this bug happened in another Issue that has already been "resolved", but I'm on the Web platform and it happened to me, I've tried to resolve it in several ways but I don't know what's happening.

The first time it never bugs, but if you keep closing and opening fast you will throw exceptions.

I have test with memory and network constructors all give me exceptions eventually.

If you test in --release version, the exception happens faster.

Logs (optional)

Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart:200:12
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════

Example code (optional)

No response

Device Model (optional)

Chrome

hm21 commented 1 month ago

Could you try using the latest version of the package, 5.4.1, to see if it resolves the issue? Version 5.1.1 is outdated, and a fix for this problem was introduced in version 5.1.3.

joaopinacio commented 1 month ago

Thanks for fast response.

I will try now to update and test but, other user opened one issue about the same problem and he is at the latest version.

237

joaopinacio commented 1 month ago

Same error with version: 5.4.1

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart:200:12
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart:200:12
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart:200:12
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart:200:12
!_debugDuringDeviceUpdate
is not true
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════
Assertion failed: file:///Users/joao/Desktop/dev/flutter/packages/flutter/lib/src/gestures/hit_test.dart:214:7
_debugVectorMoreOrLessEquals(transform.getRow(2), Vector4(0, 0, 1, 0)) &&
      _debugVectorMoreOrLessEquals(transform.getColumn(2), Vector4(0, 0, 1, 0))
"The third row and third column of a transform matrix for pointer events must be Vector4(0, 0, 1, 0) to ensure that a transformed point is directly under the pointing device. Did you forget to run the paint matrix through PointerEvent.removePerspectiveTransform? The provided matrix is:\n[0] NaN,NaN,NaN,NaN\n[1] NaN,NaN,NaN,NaN\n[2] NaN,NaN,NaN,NaN\n[3] NaN,NaN,NaN,NaN\n"
════════════════════════════════════════════════════════════════════════════════

Exception caught by rendering library ═════════════════════════════════
Assertion failed: org-dartlang-sdk:///lib/_engine/engine/validators.dart:10:7
!(rect.left.isNaN ||
          rect.right.isNaN ||
          rect.top.isNaN ||
          rect.bottom.isNaN)
"Rect argument contained a NaN value."
PedroFaria99 commented 1 month ago

237 This is probably related.

hm21 commented 1 month ago

Thank you for sharing that information.

When you try the web demo under "Standalone Sub-Editor => Crop-Rotate-Editor", do you experience the same issue? I am currently unable to reproduce the problem, even when using your code. If the issue does occur for you in the demo, could you let me know your browser version? Additionally, have you noticed this behavior across multiple browser versions or different browsers?

To clarify, are you using the canvas renderer for the web? Also, do you bootstrap Flutter in the same way shown in the web example? If you are using a different method for bootstrapping, could you share your approach?

Finally, do you also precache the image before opening the editor?

joaopinacio commented 1 month ago

About the web demo, yes it work normal but i dont know what flutter version you are using, i thought that was a problem with .network or .memory constructor but the same error occurs with asset testing in my Flutter Version

About the bootstrap, yes its the same as your example.

I tried using precache but the problem continues.

joaopinacio commented 1 month ago

I just created a blank project, just to test this and the problem still continue.

main.dart

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await showDialog(
            context: context,
            builder: (c) {
              return CropRotateEditor.network(
                'https://cdn.pixabay.com/photo/2024/03/07/10/38/simba-8618301_1280.jpg',
                initConfigs: CropRotateEditorInitConfigs(
                  theme: ThemeData.dark(),
                  convertToUint8List: true,
                  configs: ProImageEditorConfigs(
                    designMode: platformDesignMode,
                  ),
                  onImageEditingComplete: (bytes) async {
                    Navigator.pop(context);
                  },
                ),
              );
            },
          );
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

pubspec.yaml

name: web_poc_tests
description: "A new Flutter project."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ^3.5.3

dependencies:
  flutter:
    sdk: flutter

  pro_image_editor: ^5.4.1

  cupertino_icons: ^1.0.8

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^4.0.0

flutter:
  uses-material-design: true
hm21 commented 1 month ago

About the web demo, yes it work normal but i dont know what flutter version you are using, i thought that was a problem with .network or .memory constructor but the same error occurs with asset testing in my Flutter Version

The network, assets, and file constructors each convert the image in the background directly to a Uint8List, just as the memory constructor does, to allow the editor to access key information about the image. This conversion process is invisible to the user, as the editor initially displays the image using the default image constructor such as Image.network, and then switches to Image.memory once the conversion is complete.

This means that if the memory constructor does not function as expected, the other constructors will also fail to work properly. However, the crop-rotate editor is more complex to initialize from a raw image. In my opinion, the issue will be in the method calcCropRect, where a calculation may be failing, particularly in the section responsible for setting the imgConstraints.

Additionally, we know that when the crop-rotate editor is accessed from the main editor, there is no issue. The problem only arises when the standalone editor is opened. The key difference with the standalone version lies within the initConfigs parameter, specifically in the mainBodySize and mainImageSize values, which are left undefined.

Our next steps will be to confirm whether the issue is inside the calcCropRect method and to determine if the initConfigs values for mainBodySize and mainImageSize are necessary to ensure all calculations function correctly.

initConfigs: CropRotateEditorInitConfigs(
  mainImageSize: sizesManager.decodedImageSize,
  mainBodySize: sizesManager.bodySize,

FYI: The Flutter version used for the demo can be seen in the workflow here.