【发布时间】:2021-01-29 11:39:50
【问题描述】:
我正在尝试在 Flutter 中实现一个条形码扫描仪应用程序,其中相机可以作为小部件嵌入,而不是使其全屏显示。
所以我选择了flutter_qr_mobile_vision 包,因为我们可以使用原生相机功能并限制相机预览大小。
但是上面的包只给出了 MLKit 检测到的条形码字符串,而不是条形码的详细信息,如边界框、条形码类型和其他信息,所以我把上面的包的源代码做了一些修改,以便我得到了边界框,可用于在检测到的条形码上覆盖图形。
我想要做的事情的代码可以在here找到
现在我在使用这些更改时面临两个问题(目前仅 Android 实现)
- 当我尝试将边界框覆盖在条形码顶部时,多个设备的结果不一致。
例如:
在oneplus上全屏运行良好
在 Redmi 5 上输出相同的代码
默认情况下,我将所有设备的相机分辨率保持为 (1280 x 720),并在叠加之前缩放输出
我正在尝试了解不同设备上出现这种情况的原因
- 现在如果我尝试调整相机预览的小部件高度,结果在 oneplus 上也不一致
我觉得这与缩放部分有关,但我不确定。
以下代码用于相机预览和叠加图形
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:qr_mobile_vision/qr_camera.dart';
import 'package:qr_mobile_vision/qr_barcode.dart';
import 'package:vision_demo/barcode_detctor_painter.dart';
import 'package:vision_demo/overlay.dart';
void main() {
debugPaintSizeEnabled = false;
runApp(new HomePage());
}
class HomePage extends StatefulWidget {
@override
HomeState createState() => new HomeState();
}
class HomeState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return new MaterialApp(home: new MyApp());
}
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool camState = false;
List<Barcode> barcode = List<Barcode>();
@override
initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Demo app'),
),
body: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
camState
? new SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 300 - AppBar().preferredSize.height,
child: Stack(
children: [
new QrCamera(
onError: (context, error) => Text(
error.toString(),
style: TextStyle(color: Colors.red),
),
qrCodeCallback: (code) {
setState(() {
barcode = code;
});
},
child: new Container(
decoration: new BoxDecoration(
color: Colors.transparent,
),
),
),
Container(
constraints: const BoxConstraints.expand(),
decoration: ShapeDecoration(
shape: QrScannerOverlayShape(cutOutSize: MediaQuery.of(context).size.width - 160, borderColor: Colors.white),
)),
LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
return _buildResults(constraints);
})
],
),
)
: Expanded(child: new Center(child: new Text("Camera inactive"))),
],
),
),
floatingActionButton: new FloatingActionButton(
child: new Text(
"press me",
textAlign: TextAlign.center,
),
onPressed: () {
setState(() {
camState = !camState;
});
}),
);
}
Widget _buildResults(BoxConstraints constraints) {
const Text noResultsText = Text('No results!');
if (barcode == null) {
return noResultsText;
}
CustomPainter painter;
final Size imageSize = Size(720.0, 1280.0);
if (barcode is! List<Barcode>) return noResultsText;
painter = BarcodeDetectorPainter(imageSize, barcode);
return CustomPaint(
size: Size(double.maxFinite, double.maxFinite),
painter: painter,
);
}
}
下面是我用来调整大小以覆盖图形的代码。
import 'package:flutter/material.dart';
import 'package:qr_mobile_vision/qr_barcode.dart';
class BarcodeDetectorPainter extends CustomPainter {
BarcodeDetectorPainter(this.absoluteImageSize, this.barcodeLocations); // absoluteImageSize will always be (1280 x 720)
final List<Barcode> barcodeLocations;
final Size absoluteImageSize;
@override
void paint(Canvas canvas, Size size) {
final double scaleX = size.width / absoluteImageSize.width;
final double scaleY = size.height / absoluteImageSize.height;
Rect scaleRect(Barcode barcode) {
return Rect.fromLTRB(
barcode.boundingBox.left * scaleX,
barcode.boundingBox.top * scaleY,
barcode.boundingBox.right * scaleX,
barcode.boundingBox.bottom * scaleY,
);
}
final Paint paint = Paint()
..style = PaintingStyle.fill
..strokeWidth = 2.0;
for (Barcode barcode in barcodeLocations) {
paint.color = Colors.green;
canvas.drawRect(scaleRect(barcode), paint);
}
}
@override
bool shouldRepaint(BarcodeDetectorPainter oldDelegate) {
return oldDelegate.absoluteImageSize != absoluteImageSize || oldDelegate.barcodeLocations != barcodeLocations;
}
}
解决这两个问题很重要,因为在此之后我想限制扫描区域,以便我只能捕获与我添加的切口大小对齐的条形码。
感谢任何形式的帮助。
【问题讨论】:
-
可能跟底部的系统导航栏有关(注意一加没有,红米5有)。尝试弄乱
MediaQuery.of(context).padding.bottom属性。 -
谢谢,但我正在画布上的可用空间上绘制图形,所以我想这没关系,据说我已经尝试混合和匹配屏幕的不同高度,而且缩放可用空间的边界框
-
使用定位填充而不是容器,如果您确定图像大小,那么问题可能出在设备大小和相机纵横比上,而不是您的代码可能需要特殊处理跨度>
-
您可以通过以下方式轻松调试:(1)当条形码位于相机预览顶部时记录数据(2)在底部时记录。然后你就有了所有这些原始数据,你可以轻松地复制和调整你的代码。
标签: android flutter barcode-scanner firebase-mlkit