Open popeyelau opened 3 years ago
poster_painter.dart
import 'dart:async'; import 'dart:typed_data'; import 'dart:ui'; import 'dart:math' as math show max; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart' as cache; import 'utils.dart'; class PosterPainter { /// 商品海报 /// [coverUrl] 商品图 /// [miniCodeUrl] 小程序码 /// [title] 商品名称 /// [price] 价格 /// [mktPrice] 市场价 /// [saleDate] 预售日期 /// [store] 门店 static Future<ByteData> drawPoster( {String coverUrl, String miniCodeUrl, String title, double price, double mktPrice, String saleDate, String store}) async { final imageUrls = <String>[ "https://front-xps-cdn.xsyx.xyz/2020/01/10/1468273837.png", //background coverUrl, //cover miniCodeUrl, //miniCode ]; final downloadManager = cache.DefaultCacheManager(); bool hasError = false; final files = await Future.wait<cache.FileInfo>( imageUrls.map(downloadManager.downloadFile).toList()) .catchError((e, s) { hasError = true; debugPrint(e); }); if (hasError || files.length != imageUrls.length) return null; final background = await Utils.loadImage(files[0].file.readAsBytesSync()); final cover = await Utils.loadImage(files[1].file.readAsBytesSync()); final miniCode = await Utils.loadImage(files[2].file.readAsBytesSync()); final canvasSize = Size(background.width.toDouble(), background.height.toDouble()); final coverSize = Size(cover.width.toDouble(), cover.height.toDouble()); final miniCodeSize = Size(miniCode.width.toDouble(), miniCode.height.toDouble()); final recorder = PictureRecorder(); final canvas = Canvas(recorder); final painter = Paint() ..style = PaintingStyle.fill ..color = Colors.white; canvas.drawImage(background, Offset.zero, painter); double scaledSize = math.max(coverSize.width, coverSize.height) * 0.75; double x = (canvasSize.width - scaledSize) * 0.5; double y = 100.0; canvas.drawImageRect( cover, Rect.fromLTRB(0, 0, coverSize.width, coverSize.height), Rect.fromLTWH(x, y, scaledSize, scaledSize), painter); canvas.drawImageRect( miniCode, Rect.fromLTRB(0, 0, miniCodeSize.width, miniCodeSize.height), Rect.fromLTWH(x, canvasSize.height - 160, 150, 150), painter); final style = TextStyle( fontSize: 32, color: Colors.black, fontWeight: FontWeight.normal); final textWidth = canvasSize.width - x * 2; TextPainter( textAlign: TextAlign.left, text: TextSpan(children: [ TextSpan( text: "$title\n", style: style.copyWith(height: 2, fontWeight: FontWeight.w500)), TextSpan( text: "¥$price ", style: style.copyWith( fontSize: 40, color: Colors.red, fontWeight: FontWeight.w600)), TextSpan( text: "¥$mktPrice", style: style.copyWith( decoration: TextDecoration.lineThrough, color: Colors.grey)), TextSpan( text: " 预售时间: $saleDate\n", style: style.copyWith(color: Colors.grey.shade400)), TextSpan( text: "提货门店: $store", style: style.copyWith(height: 2, color: Colors.orange)) ]), textDirection: TextDirection.ltr, ) ..layout(maxWidth: textWidth, minWidth: textWidth) ..paint(canvas, Offset(x, y + scaledSize)); final picture = recorder.endRecording(); final img = await picture.toImage( canvasSize.width.toInt(), canvasSize.height.toInt()); return img.toByteData(format: ImageByteFormat.png); } }
utils.dart
import 'dart:async'; import 'dart:ui'; class Utils { static Future<Image> loadImage(List<int> img) async { final Completer<Image> completer = Completer(); decodeImageFromList(img, (Image img) { return completer.complete(img); }); return completer.future; } }
home_page.dart
import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_draw_poster/poster_painter.dart'; class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { ByteData posterByteData; @override void initState() { super.initState(); drawing(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0xffcccccc), appBar: AppBar( title: Text('Drawing'), ), body: Container( padding: EdgeInsets.all(20), alignment: Alignment.center, child: poster), floatingActionButton: FloatingActionButton( child: Icon(Icons.insert_photo), onPressed: drawing, ), ); } Widget get poster { if (posterByteData == null) return null; return Image.memory(Uint8List.view(posterByteData.buffer)); } Future<void> drawing() async { final bytes = await PosterPainter.drawPoster( coverUrl: "https://front-xps-cdn.xsyx.xyz/2020/12/04/241721671.jpg", miniCodeUrl: "https://front-xps-cdn.xsyx.xyz/2020/12/04/1348955141.jpg", title: "精卫 精品红提 230g/盒 正负 20g", price: 2.99, mktPrice: 5.99, saleDate: "12月12日", store: "麓谷总部店"); setState(() { posterByteData = bytes; }); } }
poster_painter.dart
utils.dart
home_page.dart