Flutter 利用 canvans绘制海报

公司有个需求是需要生成二维码的,查询了很多资料,一开始打算用切图的形式来完成图片的拼接,然后再利用RepaintBoundary生成图片,但是这样每个手机生成的图片大小是不一样的,所以就需要利用canvans来实现了,效果如下图

991617678483_.pic.jpg

下面是代码

     String bgImageS = 'lib/images/product_bg.png';

      UI.Image bgImage = await Tools.byteToImage(bgImageS, false, bgImageS);
      UI.Image headerImage = await Tools.byteToImage(
          Tools.getImgUrl(personInfoProvider.headImage),
          true,
          'lib/images/defaultHead.png');

      Paint paint = Paint()
        ..filterQuality = FilterQuality.high // 创建一个画笔并配置其属性
        ..strokeWidth = 1 // 画笔的宽度
        ..isAntiAlias = true // 是否抗锯齿
        ..color = Colors.white; // 画笔颜色

      UI.PictureRecorder pictureRecorder = new UI.PictureRecorder(); // 图片记录仪
      Canvas canvas = new Canvas(pictureRecorder); //canvas接受一个图片记录仪
      double pixelRatio = 2.5; //ScreenUtil.pixelRatio;
      // 绘制图片
      canvas.drawImageRect(
          bgImage,
          Rect.fromLTWH(
              0, 0, bgImage.width.toDouble(), bgImage.height.toDouble()),
          Rect.fromLTWH(
              0, 0, bgImage.width * pixelRatio, bgImage.height * pixelRatio),
          paint); // 直接画图
      //第二个 ui.Image对象 由pictureRecorder结束记录后返回  toImage裁剪图片

      //头像
      canvas.save();
      canvas.clipRRect(RRect.fromRectAndRadius(
          Rect.fromLTWH(259 * pixelRatio, 62 * pixelRatio, 102 * pixelRatio,
              102 * pixelRatio),
          Radius.circular(51*pixelRatio)));
      Size headerImageSize =
          Size(headerImage.width.toDouble(), headerImage.height.toDouble());
      Rect headerImageDstRect = Rect.fromLTWH(259 * pixelRatio, 62 * pixelRatio,
          102 * pixelRatio, 102 * pixelRatio);
      // 根据适配模式,计算适合的缩放尺寸8
      FittedSizes headerImageFittedSizes =
          applyBoxFit(BoxFit.contain, headerImageSize, headerImageDstRect.size);
      // 获得一个图片区域中,指定大小的,居中位置处的 Rect
      Rect headerImageInputRect = Alignment.center.inscribe(
          headerImageFittedSizes.source, Offset.zero & headerImageSize);
      // 获得一个绘制区域内,指定大小的,居中位置处的 Rect
      Rect headerImageOutputRect = Alignment.center
          .inscribe(headerImageFittedSizes.destination, headerImageDstRect);
      canvas.drawImageRect(
          headerImage,
          headerImageInputRect,
          Rect.fromLTWH(258 * pixelRatio, 60 * pixelRatio, 105 * pixelRatio,
              105 * pixelRatio),
          paint);
      canvas.restore();

      //店铺文字
      UI.ParagraphBuilder shopNameBuilder = UI.ParagraphBuilder(
        UI.ParagraphStyle(
          textAlign: TextAlign.center,
          fontSize: 30.0 * pixelRatio,
          textDirection: TextDirection.ltr,
          maxLines: 1,
        ),
      )
        ..pushStyle(
          UI.TextStyle(
              fontWeight: FontWeight.bold,
              color: Colors.black,
              textBaseline: UI.TextBaseline.alphabetic),
        )
        ..addText(personInfoProvider.shopName);
      UI.Paragraph shopNameParagraph = shopNameBuilder.build()
        ..layout(UI.ParagraphConstraints(
            width: 620.0 * pixelRatio - 35 * 2 * pixelRatio));
      canvas.drawParagraph(
          shopNameParagraph, Offset(35 * pixelRatio, 190.0 * pixelRatio));

       double goodsImageTop;
        double priceTop;
        String goodsName = goodsNames[I];
        TextPainter goodsNameTextPainter;
        double goodsNameTop;
        double qrTop;
          goodsImageTop = 255 * pixelRatio;
          priceTop = 800 * pixelRatio;
          goodsName = goodsNames[I];
          goodsNameTextPainter = Tools.calculateTextSize(
              context,
              goodsName,
              30.0 * pixelRatio,
              FontWeight.normal,
              (620.0 - 60 * 2) / 2 * pixelRatio,
              2);
          goodsNameTop =
              goodsNameTextPainter.width < ((620.0 - 60 * 2) / 2) * pixelRatio
                  ? 800 * pixelRatio
                  : 785 * pixelRatio;
          qrTop = 908 * pixelRatio;

        //主图

        String goodsImageName = goodsImageNames[I];
        UI.Image goodsImage = await Tools.byteToImage(
            Tools.getImgUrl(goodsImageName), true, 'lib/images/account_bg.png');

        Size goodsImageSize =
            Size(goodsImage.width.toDouble(), goodsImage.height.toDouble());
        Rect goodsImageDstRect = Rect.fromLTWH(
            35 * pixelRatio, goodsImageTop, 550 * pixelRatio, 500 * pixelRatio);
        // 根据适配模式,计算适合的缩放尺寸
        FittedSizes goodsImageFittedSizes =
            applyBoxFit(BoxFit.contain, goodsImageSize, goodsImageDstRect.size);
        // 获得一个图片区域中,指定大小的,居中位置处的 Rect
        Rect goodsImageInputRect = Alignment.center.inscribe(
            goodsImageFittedSizes.source, Offset.zero & goodsImageSize);
        // 获得一个绘制区域内,指定大小的,居中位置处的 Rect
        Rect goodsImageOutputRect = Alignment.center
            .inscribe(goodsImageFittedSizes.destination, goodsImageDstRect);
        canvas.drawImageRect(
            goodsImage, goodsImageInputRect, goodsImageOutputRect, paint);

        //商品名称

        UI.ParagraphBuilder goodsNameParagraphBuilder = UI.ParagraphBuilder(
          UI.ParagraphStyle(
            textAlign: TextAlign.left,
            fontSize: 30.0 * pixelRatio,
            textDirection: TextDirection.ltr,
            maxLines: 2,
          ),
        )
          ..pushStyle(UI.TextStyle(
              color: Colors.black, textBaseline: TextBaseline.alphabetic))
          ..addText(goodsName);
        UI.Paragraph goodsNameParagraph = goodsNameParagraphBuilder.build()
          ..layout(UI.ParagraphConstraints(
              width: (620.0 - 60 * 2) / 2 * pixelRatio));

        canvas.drawParagraph(
            goodsNameParagraph, Offset(60 * pixelRatio, goodsNameTop));
        String disprice = disprices[I];
        //价格图标
        UI.ParagraphBuilder priceIconParagraphBuilder = UI.ParagraphBuilder(
          UI.ParagraphStyle(
            textAlign: TextAlign.right,
            fontSize: 30.0 * pixelRatio,
            textDirection: TextDirection.ltr,
            maxLines: 1,
            fontWeight: FontWeight.bold,
          ),
        )
          ..pushStyle(
            UI.TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
                textBaseline: TextBaseline.alphabetic),
          )
          ..addText('¥');
        TextPainter priceTextPainter = Tools.calculateTextSize(
            context,
            disprice,
            40.0 * pixelRatio,
            FontWeight.bold,
            (620.0 - 60 * 2) / 2 * pixelRatio - 30 * pixelRatio,
            1);
        UI.Paragraph priceIconParagraph = priceIconParagraphBuilder.build()
          ..layout(UI.ParagraphConstraints(
              width:
                  (620.0 - 60 * 2) / 2 * pixelRatio - priceTextPainter.width));
        canvas.drawParagraph(priceIconParagraph,
            Offset((620.0 / 2) * pixelRatio, priceTop + 8 * pixelRatio));

        //价格

        UI.ParagraphBuilder priceParagraphBuilder = UI.ParagraphBuilder(
          UI.ParagraphStyle(
            textAlign: TextAlign.right,
            fontSize: 40.0 * pixelRatio,
            fontWeight: FontWeight.bold,
            textDirection: TextDirection.ltr,
            maxLines: 1,
          ),
        )
          ..pushStyle(
            UI.TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
                textBaseline: TextBaseline.alphabetic),
          )
          ..addText(disprice);
        UI.Paragraph priceParagraph = priceParagraphBuilder.build()
          ..layout(UI.ParagraphConstraints(
              width: (620.0 - 60 * 2) / 2 * pixelRatio - 30 * pixelRatio));
        canvas.drawParagraph(priceParagraph,
            Offset((620.0 / 2) * pixelRatio + 30 * pixelRatio, priceTop));
        //二维码
        UI.Image qrImage = await Tools.toQrImageData(shareUrl);
        canvas.drawImageRect(
            qrImage,
            Rect.fromLTWH(
                0, 0, qrImage.width.toDouble(), qrImage.height.toDouble()),
            Rect.fromLTWH(
                60 * pixelRatio, qrTop, 100 * pixelRatio, 100 * pixelRatio),
            paint);
      }

      double bgImageH;
      bgImageH = 1069 * pixelRatio;

      UI.Image picture = await pictureRecorder
          .endRecording()
          .toImage((620 * pixelRatio).toInt(), bgImageH.toInt()); //设置生成图片的宽和高
      //ByteData对象 转成 Uint8List对象 给 Image.memory() 使用来显示
      ByteData pngImageBytes =
          await picture.toByteData(format: UI.ImageByteFormat.png);


有问题欢迎留言

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。