美文网首页
flutter canvas 如何获取clip后的图片

flutter canvas 如何获取clip后的图片

作者: 金_大_大 | 来源:发表于2019-04-13 18:57 被阅读0次

    原文地址

    Step.1 Canvas转换为图片

    首先,你要了解flutter如何将canvas转换成图片,这里有一个非常好的例子分享给大家flutter_canvas_to_image,这里简单讲解一下思路:

    1.首先创建一个 ui.PictureRecorder(记录仪), 然后作为载体创建一个canvas对象

    // 创建一个记录仪
    final recorder = new ui.PictureRecorder();
    final canvas = new Canvas(
        recorder,
        new Rect.fromPoints(
            new Offset(0.0, 0.0), new Offset(200.0, 200.0)));
    

    2.在canvas上进行绘制

    final stroke = new Paint()
      ..color = Colors.grey
      ..style = PaintingStyle.stroke;
    
    canvas.drawRect(
        new Rect.fromLTWH(0.0, 0.0, 200.0, 200.0), stroke);
    
    final paint = new Paint()
      ..color = color
      ..style = PaintingStyle.fill;
    
    canvas.drawCircle(
        new Offset(
          widget.rd.nextDouble() * 200.0,
          widget.rd.nextDouble() * 200.0,
        ),
        20.0,
        paint);
    
    1. 转换和显示
    // 关闭记录仪
    final picture = recorder.endRecording();
    final img = picture.toImage(200, 200);
    final pngBytes = await img.toByteData(format: new ui.EncodingFormat.png());
    // 显示图片
    new Image.memory(new Uint8List.view(imgBytes.buffer));
    

    Step.2 Canvas截取

    当我们懂得如何将canvas转为图片之后,我们简单看下canvas clip的代码(这并不是本文主要讲述的内容,所以不做详细说明),我们以canvas.clipPath截取图片为例

    // 绘制一个三角形的path
    Path _path = Path()
          ..moveTo(100, 50)
          ..lineTo(50, 150)
          ..lineTo(150, 150)
          ..lineTo(100, 50);
    
    canvas.clipPath(_path);
    
    canvasClip.drawImageRect(
          _image, // ui.Image
          Rect.fromLTWH(0, 0, _image.width.toDouble(), _image.height.toDouble()),, 
          Rect.fromLTWH(0, 0, 200, 200), // 画布Rect
          Paint()
        );
    
    image

    Step.3 获取截取之后的图形

    我们已经将图片截取了,这个时候获取的图片大小是200*200的,但是我们只想要那个三角形怎么办那?思路如下:

    1. 获取path围成的矩形
    2. 将这个矩形移到画布的左上角
    3. 转成目标大小的图片

    思路有了,我们看实际解决办法,首先针对第一点,flutter Path 为我们提供了一个现成的方法 getBounds(), 看下官网的描述

    getBounds() → Rect
    Computes the bounding rectangle for this path. 
    

    然后看下第二点,我们可以将之前生成的图片通过位移画在一个新的canvas的左上角,第三步在Step.1 已经充分get了,看下代码:

    // 获取Path围成的矩形
    Rect _bounds = _path.getBounds();
    // 上一步生成的图片
    ui.Image img = await picture.toImage(200, 200);
    // 新建一个新的记录仪和canvas
    final recorder2 = ui.PictureRecorder();
    final canvasClip = Canvas(recorder2, Rect.fromLTWH(0, 0, size.width, size.height));
    
    canvasClip.drawImageRect(
          img,
          _bound, // _bound 中已经包含左上角的offset,可以直接拿过来用
          Rect.fromLTWH(0, 0, _bound.width, _bound.height),
          Paint()
     );
    // 停止录制 生成image
    final picture2 = recorder2.endRecording();
    ui.Image img2 = await picture2.toImage(size.width.toInt(), size.height.toInt());
    
    final pngBytes = await img2.toByteData(format: ui.ImageByteFormat.png);
    
    image

    看起来没什么变化?我们可以打印下输出


    image

    very nice,大佬们如果有更好的方法麻烦告诉下,非常感谢

    Step.4 献上完整代码

    import 'dart:typed_data';
    import 'dart:ui' as ui;
    import 'package:myapp/utils/image.dart';
    import 'package:flutter/material.dart';
    
    void main() => runApp(App());
    
    const kCanvasSize = 200.0;
    
    class App extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: ImageGenerator(),
          ),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class ImageGenerator extends StatefulWidget {
      @override
      _ImageGeneratorState createState() => _ImageGeneratorState();
    }
    
    class _ImageGeneratorState extends State<ImageGenerator> {
      ByteData imgBytes;
      ui.Image _image;
    
      @override
      void initState() {
        super.initState();
        loadImage('assets/images/face.jpg').then((image) {
          setState(() {
            _image = image;
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Column(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(12.0),
                child: RaisedButton(
                    child: Text('Generate image'), onPressed: generateImage),
              ),
              imgBytes != null
                  ? Container(
                      child: Image.memory(
                      Uint8List.view(imgBytes.buffer),
                      width: kCanvasSize,
                      height: kCanvasSize,
                    ))
                  : Container()
            ],
          ),
        );
      }
    
      void generateImage() async {
        final recorder = ui.PictureRecorder();
        final canvas = Canvas(recorder,
            Rect.fromPoints(Offset(0.0, 0.0), Offset(kCanvasSize, kCanvasSize)));
    
        final stroke = new Paint()
          ..color = Colors.grey
          ..style = PaintingStyle.stroke;
    
        canvas.drawRect(Rect.fromLTWH(0.0, 0.0, kCanvasSize, kCanvasSize), stroke);
    
        Path _path = Path()
          ..moveTo(100, 50)
          ..lineTo(50, 150)
          ..lineTo(150, 150)
          ..lineTo(100, 50);
    
        canvas.clipPath(_path);
        Rect _bound = _path.getBounds();
    
        canvas.drawImageRect(
            _image,
            Rect.fromLTWH(0, 0, _image.width.toDouble(), _image.height.toDouble()),
            Rect.fromLTWH(0, 0, 200, 200),
            Paint());
    
        final picture = recorder.endRecording();
        ui.Image img = await picture.toImage(200, 200);
    
        print('img的尺寸: $img');
    
        final recorder2 = ui.PictureRecorder();
        final canvasClip =
            Canvas(recorder2, Rect.fromLTWH(0, 0, _bound.width, _bound.height));
    
        canvasClip.drawImageRect(
            img, _bound, Rect.fromLTWH(0, 0, _bound.width, _bound.height), Paint());
    
        final picture2 = recorder2.endRecording();
        ui.Image img2 =
            await picture2.toImage(_bound.width.toInt(), _bound.height.toInt());
    
        print('img2的尺寸: $img2');
    
        final pngBytes = await img2.toByteData(format: ui.ImageByteFormat.png);
    
        setState(() {
          imgBytes = pngBytes;
        });
      }
    }
    

    相关文章

      网友评论

          本文标题:flutter canvas 如何获取clip后的图片

          本文链接:https://www.haomeiwen.com/subject/doprwqtx.html