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

[iOS] Pixelated svg icons #975

Closed
Primo85 opened this issue Aug 9, 2023 · 43 comments
Closed

[iOS] Pixelated svg icons #975

Primo85 opened this issue Aug 9, 2023 · 43 comments

Comments

@Primo85
Copy link

Primo85 commented Aug 9, 2023

Since we are using 'color' parameter there is a problem with svg rendering on iOS (on android it works fine).
The problem is in tab bar only if there are 2 items there. For 3 and more elements it works fine.
Tested on iPhone 7 iOS 15.7, iPhone 8 iOS 16.3.0 and iPhone 8 iOS 16.3.1.

Expected results/Screenshot

OK

Actual results/Screenshot

NOK2
OK3

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage();

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

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

  void _setIndex(int index) {
    setState(() {
      this.index = index;
    });
  }

  List<BottomNavigationBarItem> getTabs(BuildContext context) {
    return [
      BottomNavigationBarItem(
        icon: Assets.home,
        label: "item 1",
      ),
      BottomNavigationBarItem(
        icon: Assets.homeColor,
        label: "item 2",
      ),
      // BottomNavigationBarItem(
      //   icon: Assets.homeColor,
      //   label: "item 3",
      // ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Some title")),
      body: const Center(
        child: Text("Some screen"),
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        onTap: (int index) {
          _setIndex(index);
        },
        currentIndex: index,
        items: getTabs(context),
      ),
    );
  }
}

class Assets {
  static Color filterColor = Color.fromRGBO(0, 0, 0, 1);

  static Widget home = SvgPicture.asset("assets/home.svg");

  static Widget homeColor = SvgPicture.asset("assets/home.svg",
      color: filterColor);
}
home.svg

home

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[!] Flutter (Channel master, 3.11.0-14.0.pre.6, on macOS 13.1 22C65 darwin-x64, locale en-PL)
    ! Warning: `dart` on your path resolves to /usr/local/Cellar/dart/2.18.7/libexec/bin/dart, which is not inside your current Flutter SDK checkout at /Users/pbiskup/fvm/versions/3.10.1. Consider adding /Users/pbiskup/fvm/versions/3.10.1/bin to the front of your path.
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.
[✓] Xcode - develop for iOS and macOS (Xcode 14.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.1)
[✓] VS Code (version 1.79.2)
[✓] Connected device (3 available)
[✓] Network resources
@Primo85 Primo85 closed this as completed Aug 9, 2023
@Primo85 Primo85 reopened this Aug 10, 2023
@maksym-letiushov
Copy link

Hi,
I was faces with the same issue with flutter_svg: 2.0.7 and would like to add some additional info:

  1. results on real iOS device much worse than on iOS Simulator
  2. results depends on the size of the output image
    My svg has parameters width="24" height="24" and viewBox="0 0 24 24" and I received the worst results for sizes 20, 60, 100.
Results on real iOS Device

Device - iPhone 14 Pro Max

Results on iOS Simulator

Simulator - iPhone 14 Pro Max

Svg file

alert-circle

Demo code

Widget _buildContentForDemo(BuildContext context, String assetName, String package) {
    const List<double> sizes = [16, 20, 24, 30, 40, 50, 60, 80, 100, 120];
    const colorFilter = ColorFilter.mode(Colors.green, BlendMode.srcIn);

    return SafeArea(
      child: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            children: sizes.map((size) {
              return Padding(
                padding: const EdgeInsets.only(bottom: 24),
                child: Row(
                  children: [
                    SizedBox(width: 50, child: Text('$size')),
                    SvgPicture.asset(
                      assetName,
                      package: package,
                      colorFilter: null, // without color
                      width: size,
                      height: size,
                    ),
                    const SizedBox(width: 24),
                    SvgPicture.asset(
                      assetName,
                      package: package,
                      colorFilter: colorFilter, // with color
                      width: size,
                      height: size,
                    ),
                  ],
                ),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }

Flutter doctor

[✓] Flutter (Channel stable, 3.10.6, on macOS 13.3.1 22E772610a darwin-x64, locale en-UA)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.3)

Also I think this issue is very similar to #927

Please take a look

@neronovs
Copy link

Same for me. I use the latest 2.0.7 version.
Android is rendering as expected:
android Screenshot 2023-08-15 at 11 05 31
iOS lags:
ios Screenshot 2023-08-15 at 11 04 52

It would be super to fix this kind of issue!

@dnfield
Copy link
Owner

dnfield commented Aug 15, 2023

CAn you try this on the beta of Flutter?

This is a bug in impeller that I think exists on stable but not beta.

@maksym-letiushov
Copy link

@dnfield thank you for response

I've checked on beta and even on master channel and the problem still exists.

result on beta channel

beta channel

doctor on beta

[✓] Flutter (Channel beta, 3.13.0-0.4.pre, on macOS 13.3.1 22E772610a darwin-x64, locale en-UA)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.3)

result on master channel

master channel

doctor on master

[✓] Flutter (Channel master, 3.14.0-5.0.pre.27, on macOS 13.3.1 22E772610a darwin-x64, locale en-UA)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.3)

@Primo85
Copy link
Author

Primo85 commented Aug 16, 2023

@dnfield thank you for response, sorry for the delay.
I have checked it too, on the master, the problem still occurs.

@aytunch
Copy link

aytunch commented Sep 6, 2023

Hi,
The moment I remove the colorFilter: ColorFilter.mode(color, BlendMode.srcIn) field, this problem goes away.
But of course, when we do this, the SVGs fallback to their natural color rendering the app useless.
The svgs have such jagged lines that the whole app looks really bad.
Is this issue caused by Impeller or this plugin? Should we open up an issue in Flutter/engine repo?

@cliftonlabrum
Copy link

Any progress with this one?

@dnfield
Copy link
Owner

dnfield commented Sep 28, 2023

I don't have a good reproduction case for this. I need one htat I can reproduce locally to be able to work on this.

@cliftonlabrum
Copy link

cliftonlabrum commented Sep 28, 2023

Here is a reproduction of the issue. I am using Xcode 15 with an iPhone 15 Pro simulator on Flutter 3.13.5.

pubspec.yaml

name: flutter_svg_rendering_bug
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
  sdk: '>=3.1.2 <4.0.0'
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  flutter_svg: ^2.0.7
dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0
flutter:
  assets:
    - assets/menu.svg
    - assets/add.svg

main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: SizedBox(
          width: 200,
          height: 200,
          child: Column(
            children: [
              Row(
                children: [
                  SvgPicture.asset(
                    'assets/menu.svg',
                    colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn),
                    width: 20,
                    height: 16,
                  ),
                  const SizedBox(width: 30),
                  SvgPicture.asset(
                    'assets/add.svg',
                    colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn),
                    width: 24,
                    height: 24,
                  ),
                ],
              ),
              const SizedBox(height: 30),
              Row(
                children: [
                  SvgPicture.asset(
                    'assets/menu.svg',
                    //colorFilter: const ColorFilter.mode(Colors.red, BlendMode.srcIn),
                    width: 20,
                    height: 16,
                  ),
                  const SizedBox(width: 30),
                  SvgPicture.asset(
                    'assets/add.svg',
                    //colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn),
                    width: 24,
                    height: 24,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Attached are the two SVG assets to include.

add
menu

The screenshots attached show that the orange icons have a colorFilter property set, and the blue ones do not (the blue color is from the SVG itself).

1 2

3

Hopefully you can see how the edges of the orange icons are jagged and distorted. Let me know you need anything else. Thanks for your help!

@Primo85
Copy link
Author

Primo85 commented Sep 28, 2023

Hi.
Another example of reproduction is in my first post, in the main.dart tab. I'm using Xcode 14.3 and Flutter 3.10.6(and also Channel master, 3.11.0-14.0.pre.6).
Thank you.

@armandsLa
Copy link

armandsLa commented Oct 2, 2023

Having the same issue.

When adding icon to a CupertinoButton and it's pressed down, icon renders correctly. When it's released, it goes back to jagged state.

@simonNEON
Copy link

Are there any updates on this? Im having the same problems and not yet found a solution...

@SivaramSS
Copy link

Facing the same issue with flutter 3.13.9.

@Pomis
Copy link

Pomis commented Oct 27, 2023

Flutter 3.13.8 with Impeller, all color-filtered SVGs look jagged

Using jovial_svg as an alternative for now, it allows coloring by substituting svg file text content

@armandsLa
Copy link

I've found a temporary fix. Wrapping SvgPicture in Opacity and setting the opacity to 0.99 fixes the issue. Opacity reduction of 1% is visually unnoticeable.

Opacity(
  opacity: 0.99,
  child: SvgPicture.asset("asset/img_check.svg",
    colorFilter: ColorFilter.mode(
      Colors.red,
      BlendMode.srcIn,
    ),
  ),
);

@LeonardoRosaa
Copy link

I've found a temporary fix. Wrapping SvgPicture in Opacity and setting the opacity to 0.99 fixes the issue. Opacity reduction of 1% is visually unnoticeable.

Opacity(
  opacity: 0.99,
  child: SvgPicture.asset("asset/img_check.svg",
    colorFilter: ColorFilter.mode(
      Colors.red,
      BlendMode.srcIn,
    ),
  ),
);

Not sure about this solution. After some hours of debugging this issue, I noticed that the issue could be in the colorFilter parameter (the new way to set colors).

Wrapping the icon with the Opacity widget made all icons more "pixelated" in my case.

@RicharC293
Copy link

Same issue here

@felipecastrosales
Copy link

Same issue here using 3.16.2 version, with this fix: flutter/flutter#138598.

@dimazelinskyi
Copy link

Screenshot 2023-12-10 at 12 57 38

It looks like related issue psk907/fluttermoji#35

@HardikKotadiya
Copy link

Facing the same issue with flutter 3.16.5. I had tried lots of solution but not worked, please let me know if anyone get solution.

I had already post issue in stackoverflow too at below link

https://stackoverflow.com/questions/77741764/flutter-svg-icons-get-pixelated-in-bottom-bar-in-flutter

@kienvtqhi
Copy link

I got the same issue

@haomun0731
Copy link

haomun0731 commented Jan 10, 2024

This issue occurs on my iOS simulator. I temporarily fixed it by disabling impeller rendering in iOS debug mode. I added the following lines to Info-Debug.plist:

<key>FLTEnableImpeller</key>
<false />

For more information, please refer to: https://docs.flutter.dev/perf/impeller#ios

@capsulekenny
Copy link

Any updates on this?

@armandsLa
Copy link

This was clearly an issue with Flutter itself. Just run the test with 3.19.0 version and icons look good.

@vase4kin
Copy link

I can confirm. It is gone. The flutter version I tested with is 3.19.1.

@felipecastrosales
Copy link

I can confirm, in latest Flutter versions (3.19.x) this issue isn't present. I think also that this issue can be closed.

This was clearly an issue with Flutter itself. Just run the test with 3.19.0 version and icons look good.

@dnfield dnfield closed this as completed Feb 29, 2024
@ghost
Copy link

ghost commented Mar 25, 2024

And how fix this issue in 2024?

flutter_svg: ^1.1.6

In my case help not use color property:

SvgPicture.asset(
  SvgAssetName.chat,
  // color: AppColors.bottomBarAppIcon,
)

@LeonardoRosaa
Copy link

LeonardoRosaa commented Apr 3, 2024

The issue is back in the Flutter version 3.19.4. Some icons are pixelated in this Flutter version and only when I ran the app in the release mode.

@Kal-Elx
Copy link

Kal-Elx commented Apr 15, 2024

I can also confirm that the issue is back in later Flutter versions.
@dnfield Do you know if this is currently being worked on?

@armandsLa
Copy link

Fortunately, the patch is still working.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';

class SvgIcon extends StatelessWidget {

  final String path;
  final Color color;

  final double? width;
  final double? height;

  SvgIcon({
    required this.path,
    required this.color,
    this.width,
    this.height,
  });

  @override
  Widget build(BuildContext context) {
    if (Platform.isAndroid) {
      return _buildImage();
    }
    return Transform.scale(
      scale: 0.99,
      child: _buildImage(),
    );
  }

  Widget _buildImage() {
    final colorFilter = ColorFilter.mode(
      color,
      BlendMode.srcIn,
    );
    return SvgPicture.asset(path,
      colorFilter: colorFilter,
      width: width,
      height: height,
    );
  }

}

@L1u6
Copy link

L1u6 commented May 22, 2024

Still present with Flutter 3.22.0

@EgorK0rshun
Copy link

Still present with Flutter 3.22.1

@felipecastrosales
Copy link

Hey guys, I see that @dnfield has been inactive on GitHub for a while now. So, I don't think he's seen the latest on this issue.

Another person I see who collaborates on the package and is very close to the Flutter team is @jonahwilliams, who could possibly give us some guidance on what to do here - or check what might have caused the error to happen again.

@Primo85, please reopen the issue so that this can be given some priority.

@johnthiriet
Copy link

Hello, I can also confirm that the issue is present in Flutter 3.22.1
It's not reproduced on the main channel though.
The scale hack still works

@maxAtIppen
Copy link

maxAtIppen commented Jun 28, 2024

I reproduced that issue with flutter_svg 2.0.10+1 and flutter 3.22.2

@maxAtIppen
Copy link

Fortunately, the patch is still working.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';

class SvgIcon extends StatelessWidget {

  final String path;
  final Color color;

  final double? width;
  final double? height;

  SvgIcon({
    required this.path,
    required this.color,
    this.width,
    this.height,
  });

  @override
  Widget build(BuildContext context) {
    if (Platform.isAndroid) {
      return _buildImage();
    }
    return Transform.scale(
      scale: 0.99,
      child: _buildImage(),
    );
  }

  Widget _buildImage() {
    final colorFilter = ColorFilter.mode(
      color,
      BlendMode.srcIn,
    );
    return SvgPicture.asset(path,
      colorFilter: colorFilter,
      width: width,
      height: height,
    );
  }

}

This workaround works for me in debug mode but not in release mode. Does it work for you all in release mode?

@bahadurh
Copy link

Fortunately, the patch is still working.

import 'dart:io';

import 'package:flutter/material.dart';

import 'package:flutter_svg/svg.dart';

class SvgIcon extends StatelessWidget {

final String path;

final Color color;

final double? width;

final double? height;

SvgIcon({

required this.path,
required this.color,
this.width,
this.height,

});

@OverRide

Widget build(BuildContext context) {

if (Platform.isAndroid) {
  return _buildImage();
}
return Transform.scale(
  scale: 0.99,
  child: _buildImage(),
);

}

Widget _buildImage() {

final colorFilter = ColorFilter.mode(
  color,
  BlendMode.srcIn,
);
return SvgPicture.asset(path,
  colorFilter: colorFilter,
  width: width,
  height: height,
);

}

}

This workaround works for me in debug mode but not in release mode. Does it work for you all in release mode?

Play with transform, for me 1.02 scale worked fine 👍🏻👍🏻

@maxAtIppen
Copy link

I tried 0.99, 1.01 and 1.02 but all of them still look pixelated.

@Joan1211
Copy link

Same issue with flutter 3.22.2
Issue only on iOS.

Even values for the size (height:24, width: 24) : issue is not visible
Odd values for the size (height:23, width: 23) : issue is visible

@SimoneScaglia
Copy link

Same issue.

I solved it removing colorFilter parameter and specifying the color directly in svg code.

@emirhankolver
Copy link

emirhankolver commented Jul 28, 2024

I encountered an issue where icons appeared pixelated when using the ColorFilter parameter with the SvgPicture.asset widget. Initially, I tried using Transform.scale, but unfortunately, the icons still looked pixelated. Then, I added the filterQuality: FilterQuality.low parameter, which resolved the issue and the icons started to look great again.

Here's my Flutter details:

Flutter 3.22.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 761747bfc5 (8 weeks ago) • 2024-06-05 22:15:13 +0200
Engine • revision edd8546116
Tools • Dart 3.4.3 • DevTools 2.34.3

Here’s my codebase:

class IconView extends StatelessWidget {
  final IconAssetData? asset;
  final double? size;
  final Color? color;

  const IconView({
    super.key,
    this.asset,
    this.color,
    this.size = 24,
  });

  @override
  Widget build(BuildContext context) {
    if (asset == null) {
      return SizedBox(width: size, height: size);
    }
    final iconColor = color ?? context.theme.colorScheme.onSurface;
    if (Platform.isAndroid) {
      return _renderSVG(iconColor);
    }
    return Transform.scale(
      filterQuality: FilterQuality.low,
      scale: 0.9999,
      child: _renderSVG(iconColor),
    );
  }

  Widget _renderSVG(Color iconColor) {
    return SvgPicture.asset(
      asset!.path,
      width: size,
      height: size,
      colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn),
    );
  }
}

Previews:

  1. filterQuality: FilterQuality.none
    Ekran Resmi 2024-07-28 - 13 18 42

  2. filterQuality: FilterQuality.high
    IMG_DBE3D0063EA2-1

@qwertylolman
Copy link

it's still present in the package :(
I have to replace colorFilter with colorMapper

@beingsalmanshaikh
Copy link

beingsalmanshaikh commented Aug 23, 2024

The issue is still present. Even the workaround is not working for some reason.

Workaround I tried:

return Transform.scale(
      filterQuality: FilterQuality.low,
      scale: 0.9999,
      child:  SvgPicture.asset(
      asset!.path,
      width: size,
      height: size,
      colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn),
    );
    );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests