matteoh
matteoh

Reputation: 3590

Flutter Canvas.drawImage() draws a pixelated image

In my Flutter project, I use a CustomPainter to draw a custom shape. In that CustomPainter, I need to draw a png image, which is available in my assets folder in multiple sizes, so I can get the right image for the right screen density:

assets
   \1.5x
      image.png   // 54 x 54 pixels
   \2.0x
      image.png   // 72 x 72 pixels
   \3.0x
      image.png   // 108 x 108 pixels
   \4.0x
      image.png   // 144 x 144 pixels
   image.png      // 36 x 36 pixels

Here is how I load my image, to get an Image file:

import 'dart:ui' as ui;

Future<ui.Image> getImage() async {
   AssetImage assetImage = AssetImage("assets/image.png");
   ImageStream stream = assetImage.resolve(createLocalImageConfiguration(context));
   Completer<ui.Image> completer = Completer();
   stream.addListener(ImageStreamListener((Imageinfo image, _) {
      return completer.complete(image.image);
   }
   return completer.future;
}

And in my CustomPainter.paint() function, here is how I draw the Image, once loaded:

@override
void paint(Canvas canvas, Size size) {
   // ...
   canvas.drawImage(
      myImage, // <- the loaded image
      Offset(20, 20),
      Paint()
   );
}

I have two problems:

So what should I do to draw on my canvas the right image for the right screen density, so it's drawn properly?

Thanks.

Upvotes: 6

Views: 9415

Answers (1)

matteoh
matteoh

Reputation: 3590

Here is how I finally got it to work (thanks @pskink):

Step 1: return the whole ImageInfo object, and not only the image:

Future<ImageInfo> getImageInfo(BuildContext context) async {
   AssetImage assetImage = AssetImage("assets/image.png");
   ImageStream stream = assetImage.resolve(createLocalImageConfiguration(context));
   Completer<ImageInfo> completer = Completer();
   stream.addListener(ImageStreamListener((Imageinfo imageInfo, _) {
      return completer.complete(imageInfo);
   }
   return completer.future;
}

Step 2: use the ImageInfo.scale property, and some filtering, to draw the image:

@override
void paint(Canvas canvas, Size size) {
   // ...
   paintImage(
      canvas: canvas,
      rect: Rect.fromLTWH(
         20, 20,
         myImageInfo.width / myImageInfo.scale,
         myImageInfo.height / myImageInfo.scale),
      image: myImageInfo.image,                // <- the loaded image
      filterQuality: FilterQuality.low,
   );
}

Upvotes: 5

Related Questions