dnfield / flutter_svg

SVG parsing, rendering, and widget library for Flutter
MIT License
1.67k stars 459 forks source link

Images pixelated (CanvasKit) #668

Open KevMCarp opened 2 years ago

KevMCarp commented 2 years ago

When running on web using the canvaskit renderer images are pixelated. canvaskit canvaskit html html

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: SvgPicture.asset(
            'tick.svg',
            height: 100,
          ),
        ),
      ),
    );
  }
}

tick

philqc commented 2 years ago

I also get the same issue using Flutter Web with canvaskit. Here is how the SVG is rendered: qd_web_rendering

And here is the SVG file: Qd

Code:

SizedBox(
  child: Align(
    alignment: Alignment.center,
    child: SvgPicture.asset(
      "assets/svgs/playing-cards/Qd.svg",
      width: 96,
    ),
  ),
),
jonbhanson commented 2 years ago

I'm seeing the same thing in my app: slightly aliasing when rendered in canvaskit.

doppio commented 2 years ago

Same issue here with my brand logo. Unfortunately, I'll need to use a PNG instead since the loss of quality isn't worth the file size reduction.

Could this be related to https://github.com/flutter/flutter/issues/77485?

MarcAnProv commented 2 years ago

Same thing is happening for me.

dom3lek commented 2 years ago

Any progress of this problem?

LeonardoRosaa commented 1 year ago

Same problem here 😢

curt-weber commented 1 year ago

For CanvasKit - we use a supersampling technique that improves quality:

   Transform.scale(
      filterQuality: FilterQuality.medium,
      scale: 0.5,
      child: Transform.scale(
         scale: 2,
         child: SvgPicture(...),
      ),
   )

Keep in mind this is rendering the icon at 2X, so probably only suitable for smaller icons...

RobertApikyan commented 1 year ago

For CanvasKit - we use a supersampling technique that improves quality:

   Transform.scale(
      filterQuality: FilterQuality.medium,
      scale: 0.5,
      child: Transform.scale(
         scale: 2,
         child: SvgPicture(...),
      ),
   )

Keep in mind this is rendering the icon at 2X, so probably only suitable for smaller icons...

Fixed for iOS, I had the same pixelated image for iOS devices, Flutter 3.12.0, now it is fixed, thanks a lot!

aytunch commented 1 year ago

@RobertApikyan I am confused. Is this issue fixed with the latest Flutter & flutter_svg or with the above workaround?

RobertApikyan commented 1 year ago

@RobertApikyan I am confused. Is this issue fixed with the latest Flutter & flutter_svg or with the above workaround?

@aytunch the issue is fixed with the workaround.

blingkonnerth commented 1 year ago

any updates on this? Still experiencing this issue on iOS. @curt-weber fix is working for some icons, however it is cutting of images, unless I specifically set height and width together Boxfit.contain.

curt-weber commented 1 year ago

If the clipping is only happening on iOS, it could very likely be a bug related to Impeller. You should probably open a flutter issue showing a difference between skia/impeller. It's usually best to set a specific height and/or width so the icon has size (before it's fully loaded, or use placeholder). We found that was the cause of test flakes, attempting to tap an icon that has yet to be encountered (random test order) and thus having no size. cc @dnfield

Adam-Langley commented 1 year ago

@curt-weber thanks for the super-sampling suggestion. In cases where the upscale causes partial rendering off-screen, the upscaled image is clipped before it's downscaled again resulting in effects like this:

(note the bottom grey icon is clipped because the pre-scaled (2x) version would bleed off-screen. I've put a red square behind the svg to demonstrate the region where the SVG should be)

image

Is there a way to force flutter to render the entire widget even when the pixels aren't visible? Or another way to resolve this issue with super sampling?

curt-weber commented 1 year ago

There is likely an ancestor widget that is adding clipping (such as a scrollview). You can't pop that clip using OverflowBox, but you could perform this same supersampling strategy using CustomPaint (or a custom RenderObject) since it doesn't add clipping until you ask it to. You could use PictureInfo to obtain a picture for drawing.

hunterwilhelm commented 1 year ago

I am running into the clipping issue too when using the transform on iOS. I will have to resort to using png's until this issue is fixed.

curt-weber commented 1 year ago

Does this only reproduce on iOS(Impeller)? Testing with a parent clip (scrollview) doesn't reproduce on web (canvaskit) for me. FWIW this technique isn't needed for iOS and you could create a wrapper widget that performs the supersampling just on web, but passes through to the regular SvgPicture elsewhere. There is also a parameter clipViewbox that is available to the lower-level VectorGraphic but not exposed to SvgPicture - all you would have to do to test is switch to using VectorGraphic (clipViewbox=false) and report back your findings.

gabrielginter commented 8 months ago

Supersampling workaround doesn't seem to be working anymore on the new Flutter version (issue https://github.com/dnfield/flutter_svg/issues/1013).

Is there another way to solve this?

curt-weber commented 8 months ago

This is captured within the flutter repo and you can follow for updates here: #139028

lilran14 commented 2 months ago

has anyone been successful in resolving this issue? 🤔