我正在尝试从用户那里收集签名并将其保存到图像中。我已经做得足够远,我可以在屏幕上绘图,但现在我想点击一个按钮保存到图像并存储在我的数据库中。
这是我到目前为止所做的:
import 'package:flutter/material.dart';
class SignaturePadPage extends StatefulWidget {
SignaturePadPage({Key key}) : super(key: key);
@override
_SignaturePadPage createState() => new _SignaturePadPage();
}
class _SignaturePadPage extends State<SignaturePadPage> {
List<Offset> _points = <Offset>[];
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
_points = new List.from(_points)..add(localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),
child: new CustomPaint(painter: new SignaturePainter(_points)),
),
);
}
}
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset> points;
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null)
canvas.drawLine(points[i], points[i + 1], paint);
}
}
bool shouldRepaint(SignaturePainter other) => other.points != points;
}
不确定从哪里开始...
答案 0 :(得分:6)
您可以使用CustomPainter
捕获PictureRecorder
的输出。将您的PictureRecorder
实例传递给Canvas
的构造函数。 Picture
返回的PictureRecorder.endRecording
可以转换为Image
Picture.toImage
。最后,使用Image.toByteData
提取图像字节。
答案 1 :(得分:2)
在小部件中添加渲染的方法
ui.Image get rendered {
// [CustomPainter] has its own @canvas to pass our
// [ui.PictureRecorder] object must be passed to [Canvas]#contructor
// to capture the Image. This way we can pass @recorder to [Canvas]#contructor
// using @painter[SignaturePainter] we can call [SignaturePainter]#paint
// with the our newly created @canvas
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas canvas = Canvas(recorder);
SignaturePainter painter = SignaturePainter(points: _points);
var size = context.size;
painter.paint(canvas, size);
return recorder.endRecording()
.toImage(size.width.floor(), size.height.floor());
}
然后使用状态获取渲染的图像
var image = signatureKey.currentState.rendered
现在,您可以使用toByteData(format: ui.ImageByteFormat.png)
生成png图片并使用asInt8List()
var pngBytes = await image.toByteData(format: ui.ImageByteFormat.png)
File('your-path/filename.png')
.writeAsBytesSync(pngBytes.buffer.asInt8List())
有关完整示例,关于如何将画布导出为png,请查看此示例 https://github.com/vemarav/signature
答案 2 :(得分:0)
现有的解决方案对我有用,但是与在屏幕上渲染的图像相比,我用PictureRecorder
捕获的图像总是模糊的。我最终意识到我可以使用一些基本的Canvas技巧来实现这一目标。基本上,在创建PictureRecorder
的{{1}}之后,将其大小设置为所需比例的倍数(此处将其设置为4x)。然后Canvas
就可以了。繁荣-与具有现代分辨率的屏幕上显示的图像相比,您生成的图像不再模糊!
您可能希望将canvas.scale
的值提高一些,以提高打印或图像的爆炸/扩展效果;如果使用此功能,则希望降低_overSampleScale
值,并希望提高图像预览的加载性能。与其他解决方案一样,您需要在屏幕上使用它,将Image.memory
小部件约束为 actual 宽度和高度的Container
。理想情况下,该数字应为Flutter假“像素”中的DPI(即PictureRecorder
捕获的图像)与屏幕的实际DPI之比。
static const double _overSampleScale = 4;
Future<ui.Image> get renderedScoreImage async {
final recorder = ui.PictureRecorder();
Canvas canvas = Canvas(recorder);
final size = Size(widget.width * _overSampleScale, widget.height * _overSampleScale);
final painter = SignaturePainter(points: _points);
canvas.save();
canvas.scale(_overSampleScale);
painter.paint(canvas, size);
canvas.restore();
final data = recorder.endRecording()
.toImage(size.width.floor(), size.height.floor());
return data;
}