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 // 創(chuàng)建一個畫筆并配置其屬性
        ..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);
      // 獲得一個圖片區(qū)域中钉凌,指定大小的,居中位置處的 Rect
      Rect headerImageInputRect = Alignment.center.inscribe(
          headerImageFittedSizes.source, Offset.zero & headerImageSize);
      // 獲得一個繪制區(qū)域內捂人,指定大小的御雕,居中位置處的 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);
        // 獲得一個圖片區(qū)域中,指定大小的饮笛,居中位置處的 Rect
        Rect goodsImageInputRect = Alignment.center.inscribe(
            goodsImageFittedSizes.source, Offset.zero & goodsImageSize);
        // 獲得一個繪制區(qū)域內咨察,指定大小的,居中位置處的 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);


有問題歡迎留言

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末福青,一起剝皮案震驚了整個濱河市摄狱,隨后出現的幾起案子,更是在濱河造成了極大的恐慌无午,老刑警劉巖媒役,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異宪迟,居然都是意外死亡酣衷,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門次泽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穿仪,“玉大人,你說我怎么就攤上這事意荤“∑” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵玖像,是天一觀的道長紫谷。 經常有香客問我,道長捐寥,這世上最難降的妖魔是什么笤昨? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮握恳,結果婚禮上瞒窒,老公的妹妹穿的比我還像新娘。我一直安慰自己乡洼,他們只是感情好根竿,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著就珠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪醒颖。 梳的紋絲不亂的頭發(fā)上妻怎,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音泞歉,去河邊找鬼逼侦。 笑死匿辩,一個胖子當著我的面吹牛,可吹牛的內容都是我干的榛丢。 我是一名探鬼主播铲球,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晰赞!你這毒婦竟也來了稼病?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤掖鱼,失蹤者是張志新(化名)和其女友劉穎然走,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體戏挡,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡芍瑞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了褐墅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拆檬。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖妥凳,靈堂內的尸體忽然破棺而出竟贯,到底是詐尸還是另有隱情,我是刑警寧澤猾封,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布澄耍,位于F島的核電站,受9級特大地震影響晌缘,放射性物質發(fā)生泄漏齐莲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一磷箕、第九天 我趴在偏房一處隱蔽的房頂上張望选酗。 院中可真熱鬧,春花似錦岳枷、人聲如沸芒填。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽殿衰。三九已至,卻和暖如春盛泡,著一層夾襖步出監(jiān)牢的瞬間闷祥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工傲诵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凯砍,地道東北人箱硕。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像悟衩,于是被迫代替她去往敵國和親剧罩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355