Flutter中CustomPaint与PictureRecorder绘制尺寸不一导致水印变小如何解决
问题原因
你遇到的尺寸差异核心是单位不统一:
- 你在
CustomPaint预览时用的fontSize是Flutter默认的逻辑像素单位,适配的是屏幕显示尺寸(比如预览区域宽度只有300逻辑像素,20号字体看起来大小合适) - 导出时
PictureRecorder的画布尺寸是原图的物理像素尺寸(比如原图是4000px宽),同样的20单位字体放到4000px的画布上,占比只有预览时的1/13左右,自然看起来变小。
修复方案
有两种常用的实现方案,你可以根据需求选:
方案1:按原图比例动态计算水印尺寸(推荐,不需要依赖预览控件尺寸)
直接把所有水印相关的尺寸(字体大小、logo大小、位置偏移)改成按原图尺寸的比例计算,保证不管原图多大,水印的视觉占比一致。
比如设置字体大小为原图宽度的1/50,logo宽度为原图宽度的1/10:
// 导出代码修改示例 ui.PictureRecorder recorder = ui.PictureRecorder(); Canvas canvas = Canvas(recorder); ui.Image image = await _retrieveImage(); // 动态计算缩放后的字体大小 double scaledFontSize = image.width / 50; // 可根据需求调整比例分母 // 如果logo需要缩放也同理计算,logoAspectRatio为你原始logo的宽高比 Size scaledLogoSize = Size(image.width / 10, image.width /10 * logoAspectRatio); Watermark.draw( canvas, image, text, TextStyle( fontSize: scaledFontSize, // 替换成动态计算的尺寸 color: Color.fromRGBO(255, 255, 255, fontOpacity)), Size(image.width.roundToDouble(), image.height.roundToDouble()), _logo, scaledLogoSize: scaledLogoSize // 把缩放后的logo尺寸传入绘制方法 ); ui.Image pic = await recorder.endRecording().toImage(image.width, image.height); ByteData data = await pic.toByteData(format: ui.ImageByteFormat.png);
对应的CustomPaint预览代码也同步修改,用预览的图片显示宽度作为基准计算尺寸,保证预览和导出效果一致:
// 用LayoutBuilder获取CustomPaint的实际显示宽度 LayoutBuilder( builder: (context, constraints) { double previewWidth = constraints.maxWidth; double previewFontSize = previewWidth /50; // 和导出的比例保持一致 return CustomPaint( painter: painter.ImagePainter( image: snapshot.data, text: text, style: TextStyle( fontSize: previewFontSize, color: Color.fromRGBO(255, 255, 255, fontOpacity), ), logo: _logo, // 同样按预览宽度计算logo显示尺寸 previewLogoSize: Size(previewWidth/10, previewWidth/10 * logoAspectRatio), ), willChange: true, ); } )
方案2:用固定缩放系数换算
如果你需要保持字体大小的设置值和预览效果完全一致,可以先获取预览时CustomPaint的实际渲染宽度,计算导出时的缩放系数:
// 缩放系数 = 原图宽度 / 预览区域宽度 double exportScale = image.width / previewCustomPaintWidth; // 所有尺寸乘以缩放系数 double scaledFontSize = fontSize * exportScale;
额外注意点
- 水印的位置偏移也要同步乘以对应的缩放系数,不然会出现水印位置和预览不一致的问题
- 如果需要支持横竖图不同的缩放逻辑,可以取原图宽高中较小的值作为比例计算的基准,避免竖图水印过大或者横图水印过小
内容的提问来源于stack exchange,提问作者Burak Mete Erdoğan
相关产品推荐
相关产品推荐

