Search code examples
imageflutterflutter-layoutcustom-paintingflutter-canvas

How to crop the png image and remove its unused space using Canvas in flutter?


This attachment is from the rendered canvas image which is saved locally via canvas. In image I have drawn the square box which I want to render in canvas and save locally without left and right extra spaces. I just want to save the square box and remove that unnecessary space of PNG-image. So, how to do this?

enter image description here

widget-source-code:

  return CustomPaint(
    painter: PngImageCropper(image: image),
  );

PngImageCropper-code

  class PngImageCropper extends CustomPainter {
    PngImageCropper({
      this.image,
    });

    ui.Image image;

    @override
    void paint(Canvas canvas, Size size) {
      _drawCanvas(size, canvas);
      _saveCanvas(size);
    }

    Canvas _drawCanvas(Size size, Canvas canvas) {
      final center = Offset(image.width / 2, image.height / 2);

      double drawImageWidth = 0;
      double drawImageHeight = 0;

      Rect rect =
          Rect.fromCircle(center: center, radius: _getCircularRadius(image));
      Path path = Path()..addOval(rect);

      canvas.clipPath(path);
      Paint paint = new Paint();

      canvas.drawImage(
        image,
        Offset(drawImageWidth, drawImageHeight),
        paint,
      );

      return canvas;
    }

    _getCircularRadius(ui.Image image) {
      return image.height > image.width
          ? image.width.toDouble() / 2
          : image.height.toDouble() / 2;
    }

    _saveCanvas(Size size) async {
      var pictureRecorder = ui.PictureRecorder();
      var canvas = Canvas(pictureRecorder);
      var paint = Paint();
      paint.isAntiAlias = true;

      _drawCanvas(size, canvas);

      var pic = pictureRecorder.endRecording();
      ui.Image img = await pic.toImage(image.width, image.height);
      var byteData = await img.toByteData(format: ui.ImageByteFormat.png);
      var buffer = byteData.buffer.asUint8List();

      // var response = await get(imgUrl);
      var documentDirectory = await getApplicationDocumentsDirectory();
      File file = File(join(documentDirectory.path,
          '${DateTime.now().toUtc().toIso8601String()}.png'));
      file.writeAsBytesSync(buffer);

      print(file.path);
    }

    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
      return false;
    }
  }

Solution

  • Worked source code! Answer by @pskink.

      Future<List<int>> cropRonded(ui.Image image) async {
        var recorder = ui.PictureRecorder();
        var canvas = Canvas(recorder);
        var imageSize = Size(image.width.toDouble(), image.height.toDouble());
        var boundsToCrop = Rect.fromCenter(
            center: imageSize.center(Offset.zero),
            width: imageSize.shortestSide,
            height: imageSize.shortestSide);
        var matrix = Matrix4.translationValues(
                -boundsToCrop.topLeft.dx, -boundsToCrop.topLeft.dy, 0)
            .storage;
        var paint = Paint()
          ..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, matrix);
        var radius = imageSize.shortestSide / 2;
        canvas.drawCircle(Offset(radius, radius), radius, paint);
    
    
        ui.Image cropped = await recorder
            .endRecording()
            .toImage(imageSize.shortestSide.toInt(), imageSize.shortestSide.toInt());
        var byteData = await cropped.toByteData(format: ui.ImageByteFormat.png);
        return byteData.buffer.asUint8List();
      }