Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Web: Image shrinks when editted #37

Closed
sgehrman opened this issue May 6, 2024 · 8 comments
Closed

[Bug]: Web: Image shrinks when editted #37

sgehrman opened this issue May 6, 2024 · 8 comments
Labels
bug Something isn't working

Comments

@sgehrman
Copy link

sgehrman commented May 6, 2024

Package Version

2.7.3

Flutter Version

3.19

Platforms

Web

How to reproduce?

I edit an image and the result is smaller
Screenshot-20240506155433-809x995

Logs (optional)

See the image size on right, every save the image gets smaller and smaller

Example code (optional)

No response

Device Model (optional)

linux

@sgehrman sgehrman added the bug Something isn't working label May 6, 2024
@sgehrman
Copy link
Author

sgehrman commented May 6, 2024

This could be because I have this image inside a Widget with a FittedBox and it's scaled to fit.

I scanned your code and I don't understand how it works, but I see you are taking screenshots?

Maybe you should use the PictureRecorder() and draw to a canvas? Screenshots seems like a weird thing to do, but I know nothing about how the code works.

  static PictureAndSize _drawImageToCanvas( ) {
    final ui.PictureRecorder recorder = ui.PictureRecorder();
    final ui.Canvas canvas = ui.Canvas(recorder);

    canvas.save();
   

    canvas.drawStuff(xxxx);

    canvas.restore();

    return PictureAndSize(
      picture: recorder.endRecording(),
      height: (image.height).round(),
      width: (image.width).round(),
    );
  }

@hm21
Copy link
Owner

hm21 commented May 7, 2024

Hi Steve

Don't worry, I know the screenshot package gives us a “weird” feeling. To be honest, the first time I saw it in another package I also thought something like “what the heck” but when we look at the code it's very simple. The package also allows us to set the “pixelRatio” of the image for the best quality. In the end of this post you can see the code how the package takes a screenshot.

Anyway, I just tested it and everything works fine for me without scaling down the image. So now my questions:

  • Do you also resize the image or just “paint” stuff on it?
  • You marked “Web” as your platform, so what web browser are you using (Chrome, Edge, Opera…)?
  • Web doesn't support “File” by default, so which package or which way do you download the file?
  • Are you using the regular editor or the editor that has a “movable background image”?
  • Do you set some special configurations on the editor (i18n and theme doesn't matter)? If yes, can you post the widget ProImageEditor how you configure it?

Code screenshot package:

 Future<Uint8List?> capture({
    double? pixelRatio,
    Duration delay = const Duration(milliseconds: 20),
  }) {
    //Delay is required. See Issue https://github.com/flutter/flutter/issues/22308
    return new Future.delayed(delay, () async {
      ui.Image? image = await captureAsUiImage(
        delay: Duration.zero,
        pixelRatio: pixelRatio,
      );
      ByteData? byteData =
          await image?.toByteData(format: ui.ImageByteFormat.png);
      image?.dispose();

      Uint8List? pngBytes = byteData?.buffer.asUint8List();

      return pngBytes;
    });
  }

  Future<ui.Image?> captureAsUiImage(
      {double? pixelRatio = 1,
      Duration delay = const Duration(milliseconds: 20)}) {
    //Delay is required. See Issue https://github.com/flutter/flutter/issues/22308
    return new Future.delayed(delay, () async {
      try {
        var findRenderObject =
            this._containerKey.currentContext?.findRenderObject();
        if (findRenderObject == null) {
          return null;
        }
        RenderRepaintBoundary boundary =
            findRenderObject as RenderRepaintBoundary;
        BuildContext? context = _containerKey.currentContext;
        if (pixelRatio == null) {
          if (context != null)
            pixelRatio = pixelRatio ?? MediaQuery.of(context).devicePixelRatio;
        }
        ui.Image image = await boundary.toImage(pixelRatio: pixelRatio ?? 1);
        return image;
      } catch (e) {
        throw e;
      }
    });
  }

@sgehrman
Copy link
Author

sgehrman commented May 7, 2024

  • Do you also resize the image or just “paint” stuff on it?

I just opened an image i painted on and saved it again and it shrank

  • You marked “Web” as your platform, so what web browser are you using (Chrome, Edge, Opera…)?

Chrome

  • Web doesn't support “File” by default, so which package or which way do you download the file?

I use a file picker package for web that lets me pick a file on disk and it gives me the file bytes

  • Are you using the regular editor or the editor that has a “movable background image”?

regular

  • Do you set some special configurations on the editor (i18n and theme doesn't matter)? If yes, can you post the widget ProImageEditor how you configure it?

ProImageEditor.memory(
widget.sourceController.sourceImage!.bytes,
configs: const ProImageEditorConfigs(
blurEditorConfigs: BlurEditorConfigs(maxBlur: 40),
),

I do some experiments and see what I find.

@sgehrman
Copy link
Author

sgehrman commented May 7, 2024

I think I figured it out.

The size of the dialog matters. I think when you create the image you are looking at the context of the dialog that is not as wide or tall as the main window and some calculation is wrong?

@sgehrman
Copy link
Author

sgehrman commented May 7, 2024

Yeah, I confirmed it in the example app. replace the MaterialPageRoute with this new dialog route to see it happen.

  Navigator.pop(context);
                    Navigator.of(context).push(
                      BaseDialogRoute(_buildAssetEditor()),
                    );

class BaseDialogRoute<T> extends ModalRoute<T> {
  BaseDialogRoute(this.child) : super();

  Widget child;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 200);

  @override
  bool get opaque => false;

  @override
  bool get barrierDismissible => true;

  @override
  Color get barrierColor => Colors.black.withOpacity(0.5);

  @override
  String get barrierLabel => '';

  @override
  bool get maintainState => true;

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    final screenSize = MediaQuery.of(context).size;

    return Center(
      child: Container(
        constraints: BoxConstraints(
          maxHeight: screenSize.height * 0.95,
          maxWidth: screenSize.width * 0.9,
        ),
        width: screenSize.width * 0.9,
        decoration: BoxDecoration(
          color: Theme.of(context).scaffoldBackgroundColor,
          borderRadius: const BorderRadius.all(Radius.circular(22)),
        ),
        child: Material(
          type: MaterialType.transparency,
          child: child,
        ),
      ),
    );
  }
}


@sgehrman
Copy link
Author

sgehrman commented May 8, 2024

I'm assuming a bug in TransformHelper?

I would get rid of that screenshot stuff and just draw everything in a canvas. Seems much simpler. Not sure how the pixel ratio stuff works, but is that just drawing the image in a larger or smaller canvas and stretching or shrinking it? I'm sure you can do everything in Canvas. drawImage, drawImageRect, drawPicture, paths etc.

dragging and dropping text and emojis also has some math problems when inside a dialog. Maybe the same issue.

@hm21
Copy link
Owner

hm21 commented May 8, 2024

Thanks Steve, for this detailed answer which helped me a lot.

I reproduced it and found out that the problem before was that for all calculations I checked the full-screen size “MediaQuery.of(context).size” which of course will make problems when the “ProImageEditor” is rendered in smaller sizes. So every time you saved your changes, the pixel Ratio was calculated for a full-screen size, which scaled it down. However, I made some changes in version 2.7.5 that should fix this. Please tell me if the issue still exists by you after you update to the new version. For the case the issue still exists, please share with me the screen size and your image size (width and height in pixels).

To the part about Canvas:
Actually, it's correct to do it with canvas will also work, but we still need to respect the pixel ratio. You can imagine that your screen has a pixel ratio of 1 and a width of 500 pixels. If you now render an image with a width of 1000 pixels, it will be “scaled down” (pixels removed) and displayed as 500 pixels. When we export it, of course, we still want our image to have the large width of 1000 pixels. This is important so that on other screens like mobile screens, which have a higher pixel ratio, the image will be drawn in good quality. For this case, we need to multiply everything with the “pixel ratio” factor of the image.
When I draw it on the canvas, I have to recalculate each position and size from every layer with the active pixel ratio first and then add it. Although it's possible, I prefer to create an image from the rendered image. As you can see in the code I posted above, it is Flutter native code that does this part and returns it.
I didn't compare both options about performance, so maybe it's still possible that in the future I will change to the solution where I export it as canvas. After I release the new crop-rotate-editor, I will optimize this export part, but currently I can't say which solution it will be. The import is that it is fast and supported on all platforms.
To be honest, I still dream about a way to run a separate thread “isolated” that directly creates the image after every change we do. This will allow it that in most cases when the user presses the done button there will be no loading screen anymore especially on mobile devices.

hm21 added a commit that referenced this issue May 8, 2024
…r screens

Ensure accurate pixel ratio and layer interaction handling in ProImageEditor when rendered in reduced screen areas, addressing [GitHub issue #37](#37).
@sgehrman
Copy link
Author

sgehrman commented May 8, 2024

seems to work. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants