0

I would like to draw an image 200x200 pixels on the canvas, and then do some other things to it. The image I have is 900x690, so ideally I would like to "center crop" the image to use an Android term. This video for some reason tells us to use a FittedBox and then a SizedBox. I have also tried putting both of those in to a Container. I have tried setting the container size, the sized box size, and the customer painter Size to 200x200 and everything results in a full screen image. Who knows what I am doing wrong :)

Here is the code:

import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ui.Image image;

  @override
  void initState() {
    super.initState();
    load('images/noodlejpg.jpg').then((i) {
      setState(() {
        image = i;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Colors.blue, title: Text('I am a title')),
      backgroundColor: Colors.teal,
      body: SafeArea(
        child: FittedBox(
          child: SizedBox(
            width: 200.0,
            height: 200.0,
            child: CustomPaint(
              painter: MyPainter(image),
            ),
          ),
        ),
      ),
    );
  }

  Future<ui.Image> load(String asset) async {
    ByteData data = await rootBundle.load(asset);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }
}

class MyPainter extends CustomPainter {
  ui.Image image;

  MyPainter(this.image);

  @override
  void paint(Canvas canvas, Size size) {
    var paint = new Paint();
    paint.blendMode = BlendMode.srcIn;
    paint.isAntiAlias = true;

    if (image != null) canvas.drawImage(image, Offset.zero, paint);
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) {
    return image != oldDelegate.image;
  }
}
Daniel Wilson
  • 18,838
  • 12
  • 85
  • 135

3 Answers3

3

Ok I figured out the answer to this. There is a built in paint function called paintImage. I don't know why the video doesn't mention this, maybe it's new.

So in the paint function itself, all that is needed is this:

  @override
  void paint(Canvas canvas, Size size) {
    paintImage(
        canvas: canvas,
        rect: Rect.fromLTRB(0, 0, 200, 200),
        image: image,
        fit: BoxFit.cover);
  }

BoxFit.cover is analogous to "center-cropping" an image I believe. In the source code you can see it does a load of scale / source / dest rect stuff but the key to it is the drawImageRect function.

Daniel Wilson
  • 18,838
  • 12
  • 85
  • 135
1

Try this way

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Colors.blue, title: Text('I am a title')),
      backgroundColor: Colors.teal,
      body: SafeArea(
        child: Container(
          height: 200.0,
          width: 200.0,
          child: FittedBox(
            child: SizedBox(
              height: image.height.toDouble(),
              width: image.width.toDouble(),
              child: CustomPaint(
                painter: MyPainter(image),
              ),
            ),
          ),
        ),
      ),
    );
  }
0

Set image codec size: instantiateImageCodec function

Future<Codec> instantiateImageCodec (
       Uint8List list,
       {int targetWidth,
       int targetHeight}
)
Kahou
  • 3,200
  • 1
  • 14
  • 21