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

Flutter web: The Image.memory makes the web page freeze for a period of time when uploading/downloading an image that has a big size #102828

Open
SittiphanSittisak opened this issue Apr 29, 2022 · 11 comments
Labels
a: images Loading, displaying, rendering images c: performance Relates to speed or footprint issues (see "perf:" labels) e: web_canvaskit CanvasKit (a.k.a. Skia-on-WebGL) rendering backend for Web found in release: 2.10 Found to occur in 2.10 found in release: 2.13 Found to occur in 2.13 P3 Issues that are less important to the Flutter project platform-web Web applications specifically team-web Owned by Web platform team triaged-web Triaged by Web platform team

Comments

@SittiphanSittisak
Copy link

When a user uploads an image that has a big size, the application will freeze at the moment(Is the app calculating?).

How to fix it to smooth. The Image.network has a leadingBuilder property but the Image.memory doesn't have this property.

And another similar problem. When the Image.memory is assigned in the x parameter and another widget is y. When I use setState for swapping the widget x and y in the Card widget. The web always freezes for a while that the widget swap from y to x(From another widget to Image.memory widget that contains the image with big size).

For the example:

Screen.Recording.29-4-2565.23-11-18.mp4

How to fix this?
I want to make the app work smooth.
If the image has a big size, the app shows an indicator that when the app is processing.
And the app shouldn't reload the image widget every time that the widget was toggled by setState.

@SittiphanSittisak
Copy link
Author

SittiphanSittisak commented Apr 30, 2022

I tried precacheImage. The web still freezes for a while when I assigned the Image widget in the x parameter before using precacheImage(x.image, context).

The precacheImage help to make the web smooth when swapping the widget from another widget to Image.memory.

I think the problem is Image.memory.
Have any widgets instead of the Image.memory?

@maheshmnj maheshmnj added the in triage Presently being triaged by the triage team label May 2, 2022
@maheshmnj
Copy link
Member

Hi @SittiphanSittisak, Thanks for filing the issue. Please share a minimal and complete reproducible code along with the output of flutter doctor -v to investigate this issue further. Also, what is the size of the image that's taking longer to load?

@maheshmnj maheshmnj added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 2, 2022
@SittiphanSittisak
Copy link
Author

SittiphanSittisak commented May 8, 2022

Thank you for your response.
My images are Medium 1920 x 1458, Large 2400 x 1823 and Titan 4096 x 3112.
You can see this problem in the video. The freezing was detected by watching the CircularProgressIndicator when opening the Large and the Titan image size. How to make this smooth?
https://user-images.githubusercontent.com/59549741/167283280-94829a04-3a7f-4610-896a-95ba6e405348.mp4

test link:
https://flutter-test-exam-bug.web.app/#/github_102828

In this case, I can use the precacheImage. But in my project, the image that was used in the Image.memory() comes from an upload or API(unknown image size). Converting an image to byte or putting the image bytes in the Image.memory() doesn't make the app freeze, The app will be freezing when showing the Image.memory().

flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.10.5, on Microsoft Windows [Version 10.0.19044.1645], locale th-TH)
[√] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.1.5)
[√] Android Studio (version 2021.1)
[√] VS Code (version 1.67.0)
[√] Connected device (3 available)
[√] HTTP Host Availability

• No issues found!

minimal code:

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Page102828 extends StatefulWidget {
  const Page102828({Key? key}) : super(key: key);

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

class _Page102828State extends State<Page102828> {
  bool mediumToggle = true,
      largeToggle = true,
      titanToggle = true,
      putImgInWidgetToggle = false;
  List<int> imgMedium = [], imgLarge = [], imgTitan = [];
  Widget? putImgInWidget;

  Future getImg() async {
    imgMedium =
        (await rootBundle.load('asset/102828/medium.jpg')).buffer.asUint8List();
    imgLarge =
        (await rootBundle.load('asset/102828/large.jpg')).buffer.asUint8List();
    imgTitan =
        (await rootBundle.load('asset/102828/titan.jpg')).buffer.asUint8List();
  }

  void testPutImgInWidget(img) {
    putImgInWidgetToggle = false;
    putImgInWidget = null;
    putImgInWidget = SizedBox(
        width: 100,
        height: 100,
        child: Image.memory(Uint8List.fromList(img),
            width: double.infinity,
            height: double.infinity,
            fit: BoxFit.scaleDown));
  }

  @override
  void initState() {
    getImg();
    super.initState();
  }

  Widget showImg(
      {required bool isTxt, required String txt, required List<int> img}) {
    return Container(
      margin: const EdgeInsets.all(20),
      height: 100,
      width: 100,
      color: Colors.brown,
      child: Center(
          child: isTxt
              ? Text(txt)
              : Image.memory(Uint8List.fromList(img),
                  width: double.infinity,
                  height: double.infinity,
                  fit: BoxFit.scaleDown,
                  errorBuilder: (context, error, stackTrace) => const Center(
                      child: Icon(Icons.error, color: Colors.red, size: 20)))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Container(
        alignment: Alignment.center,
        color: Colors.grey,
        child: SingleChildScrollView(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              const SizedBox(
                  width: 100,
                  height: 800,
                  child: CircularProgressIndicator(
                      color: Colors.red, strokeWidth: 20)),
              Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  InkWell(
                      onTap: () => setState(() {
                            largeToggle = true;
                            titanToggle = true;
                            mediumToggle = !mediumToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded,
                          size: 20)),
                  InkWell(
                      onTap: () => testPutImgInWidget(imgMedium),
                      child: const Text("Put imgMedium to testWidget")),
                  showImg(
                      isTxt: mediumToggle,
                      txt: "Medium 1920 x 1458",
                      img: imgMedium),
                  InkWell(
                      onTap: () => setState(() {
                            mediumToggle = true;
                            titanToggle = true;
                            largeToggle = !largeToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded,
                          size: 20)),
                  InkWell(
                      onTap: () => testPutImgInWidget(imgLarge),
                      child: const Text("Put imgLarge to testWidget")),
                  showImg(
                      isTxt: largeToggle,
                      txt: "Large 2400 x 1823",
                      img: imgLarge),
                  InkWell(
                      onTap: () => setState(() {
                            mediumToggle = true;
                            largeToggle = true;
                            titanToggle = !titanToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded,
                          size: 20)),
                  InkWell(
                      onTap: () => testPutImgInWidget(imgTitan),
                      child: const Text("Put imgTitan to testWidget")),
                  showImg(
                      isTxt: titanToggle,
                      txt: "Titan 4096 x 3112",
                      img: imgTitan),
                  InkWell(
                      onTap: () => setState(() => putImgInWidgetToggle = true),
                      child: const Text("show testWidget")),
                  putImgInWidgetToggle
                      ? putImgInWidget ??
                          Container(
                              height: 100, width: 100, color: Colors.brown)
                      : Container(height: 100, width: 100, color: Colors.brown),
                ],
              ),
            ],
          ),
        ),
      )),
    );
  }
}

Adding the folder asset/102828 with 3 images and add

  assets:
    - asset/102828/

images from https://unsplash.com/photos/CdAmQAko9As:

asset/102828/medium.jpg
asset/102828/large.jpg
asset/102828/titan.jpg

in pubspec.yml look like:

flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - asset/102828/
  # To add assets to your application, add an assets section, like this:
  # assets:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 8, 2022
@huycozy
Copy link
Member

huycozy commented May 9, 2022

Hi @SittiphanSittisak, let's break down your question as below:

  1. "When a user uploads an image that has a big size, the application will freeze at the moment(Is the app calculating?)."

There are some tips that may help you:

  • Using chunked upload for large files.
  • Separate a big widget into smaller widgets.
  • Using state management
  1. "The Image.network has a leadingBuilder property but the Image.memory doesn't have this property."

    Image.memory supports frameBuilder that you can use it as a loadingBuilder:

Sample code:
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const Page102828(),
    );
  }
}

class Page102828 extends StatefulWidget {
  const Page102828({Key? key}) : super(key: key);

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

class _Page102828State extends State<Page102828> {
  bool mediumToggle = true, largeToggle = true, titanToggle = true, putImgInWidgetToggle = false;
  List<int> imgMedium = [], imgLarge = [], imgTitan = [];
  Widget? putImgInWidget;

  Future getImg() async {
    imgMedium = (await rootBundle.load('asset/102828/medium.jpg')).buffer.asUint8List();
    imgLarge = (await rootBundle.load('asset/102828/large.jpg')).buffer.asUint8List();
    imgTitan = (await rootBundle.load('asset/102828/titan.jpg')).buffer.asUint8List();
  }

  void testPutImgInWidget(img) {
    putImgInWidgetToggle = false;
    putImgInWidget = null;
    putImgInWidget = SizedBox(
        width: 100,
        height: 100,
        child: Image.memory(Uint8List.fromList(img),
            width: double.infinity, height: double.infinity, fit: BoxFit.scaleDown));
  }

  @override
  void initState() {
    getImg();
    super.initState();
  }

  Widget showImg({required bool isTxt, required String txt, required List<int> img}) {
    return Container(
      margin: const EdgeInsets.all(20),
      height: 100,
      width: 100,
      color: Colors.brown,
      child: Center(
          child: isTxt
              ? Text(txt)
              : Image.memory(Uint8List.fromList(img),
                  width: double.infinity,
                  height: double.infinity,
                  fit: BoxFit.scaleDown,
                  frameBuilder: (
                    BuildContext context,
                    Widget child,
                    int? frame,
                    bool wasSynchronouslyLoaded,
                  ) {
                    if (wasSynchronouslyLoaded) return child;
                    return AnimatedSwitcher(
                      duration: const Duration(milliseconds: 500),
                      child: frame != null
                          ? child
                          : const SizedBox(
                              height: 60,
                              width: 60,
                              child: CircularProgressIndicator(strokeWidth: 6),
                            ),
                    );
                  },
                  errorBuilder: (context, error, stackTrace) =>
                      const Center(child: Icon(Icons.error, color: Colors.red, size: 20)))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Container(
        alignment: Alignment.center,
        child: SingleChildScrollView(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              const SizedBox(
                  width: 100, height: 100, child: CircularProgressIndicator(color: Colors.red, strokeWidth: 4)),
              Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  InkWell(
                      onTap: () => setState(() {
                            largeToggle = true;
                            titanToggle = true;
                            mediumToggle = !mediumToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
                  InkWell(onTap: () => testPutImgInWidget(imgMedium), child: const Text("Put imgMedium to testWidget")),
                  showImg(isTxt: mediumToggle, txt: "Medium 1920 x 1458", img: imgMedium),
                  InkWell(
                      onTap: () => setState(() {
                            mediumToggle = true;
                            titanToggle = true;
                            largeToggle = !largeToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
                  InkWell(onTap: () => testPutImgInWidget(imgLarge), child: const Text("Put imgLarge to testWidget")),
                  showImg(isTxt: largeToggle, txt: "Large 2400 x 1823", img: imgLarge),
                  InkWell(
                      onTap: () => setState(() {
                            mediumToggle = true;
                            largeToggle = true;
                            titanToggle = !titanToggle;
                          }),
                      child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
                  InkWell(onTap: () => testPutImgInWidget(imgTitan), child: const Text("Put imgTitan to testWidget")),
                  showImg(isTxt: titanToggle, txt: "Titan 4096 x 3112", img: imgTitan),
                  InkWell(
                      onTap: () => setState(() => putImgInWidgetToggle = true), child: const Text("show testWidget")),
                  putImgInWidgetToggle
                      ? putImgInWidget ?? Container(height: 100, width: 100, color: Colors.brown)
                      : Container(height: 100, width: 100, color: Colors.brown),
                ],
              ),
            ],
          ),
        ),
      )),
    );
  }
}
  1. "And another similar problem. When the Image.memory is assigned in the x parameter and another widget is y. When I use setState for swapping the widget x and y in the Card widget. The web always freezes for a while that the widget swap from y to x(From another widget to Image.memory widget that contains the image with big size)."

I tried to run your sample code and found that it's an issue by canvas renderer on web. This is result when running on latest channels (--web-renderer canvaskit):

Stable Master Beta
Can reproduce Can not reproduce Can not reproduce
Demo - freeze
102828.mov
Demo - no freeze
102828_html.mov
flutter doctor -v
[✓] Flutter (Channel stable, 2.10.5, on macOS 12.2.1 21D62 darwin-x64, locale en-VN)
    • Flutter version 2.10.5 at /Users/huynq/Documents/GitHub/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 5464c5bac7 (3 weeks ago), 2022-04-18 09:55:37 -0700
    • Engine revision 57d3bac3dd
    • Dart version 2.16.2
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2020.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)

[✓] Android Studio (version 4.1)
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] Android Studio
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/203.7185775/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174)

[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.66.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.40.0

[✓] Connected device (4 available)
    • MI 8 Lite (mobile) • 4f54c54e                             • android-arm64  • Android 10 (API 29)
    • iPhone 13 (mobile) • 5F5D609C-3B0B-4C48-872C-961928157361 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
    • macOS (desktop)    • macos                                • darwin-x64     • macOS 12.2.1 21D62 darwin-x64
    • Chrome (web)       • chrome                               • web-javascript • Google Chrome 101.0.4951.54

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

[✓] Flutter (Channel master, 2.13.0-0.0.pre.987, on macOS 12.2.1 21D62 darwin-x64, locale en-VN)
    • Flutter version 2.13.0-0.0.pre.987 at /Users/huynq/Documents/GitHub/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 0656a5c033 (4 hours ago), 2022-05-08 18:24:04 -0400
    • Engine revision c930e64a13
    • Dart version 2.18.0 (build 2.18.0-98.0.dev)
    • DevTools version 2.13.1

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2020.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)

[✓] Android Studio (version 4.1)
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[!] Android Studio
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/203.7185775/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.66.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.40.0

[✓] Connected device (4 available)
    • MI 8 Lite (mobile) • 4f54c54e                             • android-arm64  • Android 10 (API 29)
    • iPhone 13 (mobile) • 5F5D609C-3B0B-4C48-872C-961928157361 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
    • macOS (desktop)    • macos                                • darwin-x64     • macOS 12.2.1 21D62 darwin-x64
    • Chrome (web)       • chrome                               • web-javascript • Google Chrome 101.0.4951.54

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.
[✓] Flutter (Channel beta, 2.13.0-0.4.pre, on macOS 12.2.1 21D62 darwin-x64, locale en-VN)
    • Flutter version 2.13.0-0.4.pre at /Users/huynq/Documents/GitHub/flutter_beta
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 25caf1461b (4 days ago), 2022-05-05 14:23:09 -0700
    • Engine revision c5caf749fe
    • Dart version 2.17.0 (build 2.17.0-266.8.beta)
    • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2020.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)

[✓] Android Studio (version 4.1)
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] Android Studio
    • Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/203.7185775/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174)

[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.67.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.40.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-x64     • macOS 12.2.1 21D62 darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 101.0.4951.54

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@huycozy huycozy added c: performance Relates to speed or footprint issues (see "perf:" labels) platform-web Web applications specifically a: images Loading, displaying, rendering images e: web_canvaskit CanvasKit (a.k.a. Skia-on-WebGL) rendering backend for Web found in release: 2.10 Found to occur in 2.10 found in release: 2.13 Found to occur in 2.13 and removed in triage Presently being triaged by the triage team labels May 9, 2022
@yjbanov
Copy link
Contributor

yjbanov commented May 12, 2022

Can you please try this on a newer Flutter version? We recently introduced WebCodecs-based image decoding. I profiled the sample app and noticed that it still uses the WASM codecs. If the WebCodecs-based decoder still janks we'll take a look. Otherwise, our recommendation is to use WebCodecs. While not all browsers support them, we expect as browser support matures this problem will gradually go away. As a workaround, you could try decoding images in a WebWorker.

@yjbanov yjbanov added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 12, 2022
@SittiphanSittisak
Copy link
Author

I'm sorry for replying so late.
Hi @huycozy, thank you for your tips. I ran the project in the Stable channel and used the canvas renderer when I built the web.
I have some questions to clarify my understanding.

  1. "When a user uploads an image that has a big size, the application will freeze at the moment(Is the app calculating?)."
  • chunked upload
    Is it mean "Create the method that receives the information in small increments and combines it after all the information has been received."?
    (Or the flutter already has some function that can upload large images by dividing the information into smaller parts.)
  • Separate a big widget into smaller widgets.
    Is it mean "changing the width and height of the widget to a smaller value"?
  • Using [state management]
    Is it mean "refresh only target widget, not all widget like using setState"?
    (In the main project, I am already using GetX)
  1. OMG, thank you for the nice tip!

  2. Yes, I am using the stable channel and building with flutter build web --web-renderer canvaskit because I need the toImage function.

@SittiphanSittisak
Copy link
Author

SittiphanSittisak commented May 17, 2022

I'm sorry for replying so late.
Hi @yjbanov, thank you for your response.
My flutter version:

Flutter 3.0.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ee4e09cce0 (7 days ago) • 2022-05-09 16:45:18 -0700
Engine • revision d1b9a6938a
Tools • Dart 2.17.0 • DevTools 2.12.2

I don't know about "decoding images in a WebWorker".
Is its new function to decode images? Please, give the example.

After I updated the flutter version, I tried to rebuild the project and It's smooth like this (after 34sec is the new flutter version):
https://user-images.githubusercontent.com/59549741/168757042-c8b74d94-30e2-42fc-aace-76a7d9292240.mp4
This still has some mini freeze (at 1:22), but overall, it's greatly improved!

You can test by following this link:
https://flutter-test-exam-bug.web.app/#/github_102828

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 17, 2022
@SittiphanSittisak
Copy link
Author

SittiphanSittisak commented May 18, 2022

After using frameBuilder.
More example:

  1. image small size + convert to byte + create the Image.memory widget + show
    https://user-images.githubusercontent.com/59549741/168989186-b727f057-59dd-4923-b6df-cc63d5f863a5.mp4
    (not freeze)
  2. image big size + convert to byte + create the Image.memory widget + show
    https://user-images.githubusercontent.com/59549741/168989455-15d8639c-8695-4015-ad3b-10b7a33a1f1d.mp4
    (freeze)
  3. image big size + convert to byte + create the Image.memory widget
    https://user-images.githubusercontent.com/59549741/168990075-ea2d063c-73f3-4ad7-bf6e-4efdae577f00.mp4
    (freeze)
  4. image big size + convert to byte
    https://user-images.githubusercontent.com/59549741/168990677-ee7cf93d-f710-4d3c-9fa5-78915c6f48e9.mp4
    (not freeze, Is freeze because create the Image.memory widget?)
  5. multi-image big size + convert to byte + create a list of the Image.memory widget + show
    https://user-images.githubusercontent.com/59549741/168991210-7cc85f0f-98d7-4f56-83b6-beeee6cbf10b.mp4
    (not freeze but why?)

@yjbanov
Copy link
Contributor

yjbanov commented May 26, 2022

@SittiphanSittisak yes, the new version of Flutter will try to use the ImageDecoder API if the browser supports it. As of today, Chrome, Edge, and other Chromium-based browsers support this new API. It should be much faster and it's non-blocking.

I am going to keep this issue open as a feature request for processing large images after decoding. I don't have a solution though. At some point the image has to make it into the WebGL context, and I'm not aware of a non-blocking way to do this. Maybe WebGPU will have something. So this may take a while to fully fix.

@yjbanov yjbanov added the P3 Issues that are less important to the Flutter project label May 26, 2022
@ShanibhanushaInfosoft
Copy link

how to final imageMemory = MemoryImage(Uint8List.fromList(imageData)); to convert image link in flutter

@SittiphanSittisak
Copy link
Author

SittiphanSittisak commented Jul 5, 2023

@ShanibhanushaInfosoft If you mean how to convert an image from the URL path to byte, this is how:

import 'dart:typed_data';
import 'package:http/http.dart' as http;

Future<Uint8List?> convertImageToBytes(String imageUrl) async {
  try {
    final response = await http.get(Uri.parse(imageUrl));
    if (response.statusCode == 200) return response.bodyBytes;
    return null;
  } catch (_) {
    return null;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: images Loading, displaying, rendering images c: performance Relates to speed or footprint issues (see "perf:" labels) e: web_canvaskit CanvasKit (a.k.a. Skia-on-WebGL) rendering backend for Web found in release: 2.10 Found to occur in 2.10 found in release: 2.13 Found to occur in 2.13 P3 Issues that are less important to the Flutter project platform-web Web applications specifically team-web Owned by Web platform team triaged-web Triaged by Web platform team
Projects
None yet
Development

No branches or pull requests

5 participants