Read QR Code from file in Flutter

前端 未结 2 741
臣服心动
臣服心动 2021-02-06 15:06

I\'m developing a mobile app using the Flutter framework.

I need to read QR Codes, and I have successfully implemented the Barcode Scan library, based on ZXing to decode

相关标签:
2条回答
  • 2021-02-06 15:10

    As I suggested you in my comment you could try using firebase_ml_visionpackage.

    Always remember:

    You must also configure Firebase for each platform project: Android and iOS (see the example folder or https://codelabs.developers.google.com/codelabs/flutter-firebase/#4 for step by step details).

    In this example (taken from the official one, but with a specific plugin version - not the latest one) we use image_picker plugin to get the image from device and then we decode the QRCode.

    pubspec.yaml

    firebase_ml_vision: 0.2.1
    image_picker: 0.4.12+1
    

    detector_painters.dart

    // Copyright 2018 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    
    import 'dart:ui' as ui;
    
    import 'package:firebase_ml_vision/firebase_ml_vision.dart';
    import 'package:flutter/material.dart';
    
    enum Detector { barcode, face, label, cloudLabel, text }
    
    class BarcodeDetectorPainter extends CustomPainter {
      BarcodeDetectorPainter(this.absoluteImageSize, this.barcodeLocations);
    
      final Size absoluteImageSize;
      final List<Barcode> barcodeLocations;
    
      @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.stroke
          ..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;
      }
    }
    
    class FaceDetectorPainter extends CustomPainter {
      FaceDetectorPainter(this.absoluteImageSize, this.faces);
    
      final Size absoluteImageSize;
      final List<Face> faces;
    
      @override
      void paint(Canvas canvas, Size size) {
        final double scaleX = size.width / absoluteImageSize.width;
        final double scaleY = size.height / absoluteImageSize.height;
    
        final Paint paint = Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0
          ..color = Colors.red;
    
        for (Face face in faces) {
          canvas.drawRect(
            Rect.fromLTRB(
              face.boundingBox.left * scaleX,
              face.boundingBox.top * scaleY,
              face.boundingBox.right * scaleX,
              face.boundingBox.bottom * scaleY,
            ),
            paint,
          );
        }
      }
    
      @override
      bool shouldRepaint(FaceDetectorPainter oldDelegate) {
        return oldDelegate.absoluteImageSize != absoluteImageSize ||
            oldDelegate.faces != faces;
      }
    }
    
    class LabelDetectorPainter extends CustomPainter {
      LabelDetectorPainter(this.absoluteImageSize, this.labels);
    
      final Size absoluteImageSize;
      final List<Label> labels;
    
      @override
      void paint(Canvas canvas, Size size) {
        final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
          ui.ParagraphStyle(
              textAlign: TextAlign.left,
              fontSize: 23.0,
              textDirection: TextDirection.ltr),
        );
    
        builder.pushStyle(ui.TextStyle(color: Colors.green));
        for (Label label in labels) {
          builder.addText('Label: ${label.label}, '
              'Confidence: ${label.confidence.toStringAsFixed(2)}\n');
        }
        builder.pop();
    
        canvas.drawParagraph(
          builder.build()
            ..layout(ui.ParagraphConstraints(
              width: size.width,
            )),
          const Offset(0.0, 0.0),
        );
      }
    
      @override
      bool shouldRepaint(LabelDetectorPainter oldDelegate) {
        return oldDelegate.absoluteImageSize != absoluteImageSize ||
            oldDelegate.labels != labels;
      }
    }
    
    // Paints rectangles around all the text in the image.
    class TextDetectorPainter extends CustomPainter {
      TextDetectorPainter(this.absoluteImageSize, this.visionText);
    
      final Size absoluteImageSize;
      final VisionText visionText;
    
      @override
      void paint(Canvas canvas, Size size) {
        final double scaleX = size.width / absoluteImageSize.width;
        final double scaleY = size.height / absoluteImageSize.height;
    
        Rect scaleRect(TextContainer container) {
          return Rect.fromLTRB(
            container.boundingBox.left * scaleX,
            container.boundingBox.top * scaleY,
            container.boundingBox.right * scaleX,
            container.boundingBox.bottom * scaleY,
          );
        }
    
        final Paint paint = Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0;
    
        for (TextBlock block in visionText.blocks) {
          for (TextLine line in block.lines) {
            for (TextElement element in line.elements) {
              paint.color = Colors.green;
              canvas.drawRect(scaleRect(element), paint);
            }
    
            paint.color = Colors.yellow;
            canvas.drawRect(scaleRect(line), paint);
          }
    
          paint.color = Colors.red;
          canvas.drawRect(scaleRect(block), paint);
        }
      }
    
      @override
      bool shouldRepaint(TextDetectorPainter oldDelegate) {
        return oldDelegate.absoluteImageSize != absoluteImageSize ||
            oldDelegate.visionText != visionText;
      }
    }
    

    main.dart

    // Copyright 2018 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    
    import 'dart:async';
    import 'dart:io';
    
    import 'package:firebase_ml_vision/firebase_ml_vision.dart';
    import 'package:flutter/material.dart';
    import 'package:image_picker/image_picker.dart';
    
    import 'detector_painters.dart';
    
    void main() => runApp(MaterialApp(home: _MyHomePage()));
    
    class _MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<_MyHomePage> {
      File _imageFile;
      Size _imageSize;
      dynamic _scanResults;
      String _title = 'ML Vision Example';
      Detector _currentDetector = Detector.text;
    
      Future<void> _getAndScanImage() async {
        setState(() {
          _imageFile = null;
          _imageSize = null;
        });
    
        final File imageFile =
        await ImagePicker.pickImage(source: ImageSource.gallery);
    
        if (imageFile != null) {
          _getImageSize(imageFile);
          _scanImage(imageFile);
        }
    
        setState(() {
          _imageFile = imageFile;
        });
      }
    
      Future<void> _getImageSize(File imageFile) async {
        final Completer<Size> completer = Completer<Size>();
    
        final Image image = Image.file(imageFile);
        image.image.resolve(const ImageConfiguration()).addListener(
              (ImageInfo info, bool _) {
            completer.complete(Size(
              info.image.width.toDouble(),
              info.image.height.toDouble(),
            ));
          },
        );
    
        final Size imageSize = await completer.future;
        setState(() {
          _imageSize = imageSize;
        });
      }
    
      Future<void> _scanImage(File imageFile) async {
        setState(() {
          _scanResults = null;
        });
    
        final FirebaseVisionImage visionImage =
        FirebaseVisionImage.fromFile(imageFile);
    
        FirebaseVisionDetector detector;
        switch (_currentDetector) {
          case Detector.barcode:
            detector = FirebaseVision.instance.barcodeDetector();
            break;
          case Detector.face:
            detector = FirebaseVision.instance.faceDetector();
            break;
          case Detector.label:
            detector = FirebaseVision.instance.labelDetector();
            break;
          case Detector.cloudLabel:
            detector = FirebaseVision.instance.cloudLabelDetector();
            break;
          case Detector.text:
            detector = FirebaseVision.instance.textRecognizer();
            break;
          default:
            return;
        }
    
        final dynamic results =
            await detector.detectInImage(visionImage) ?? <dynamic>[];
    
        setState(() {
          _scanResults = results;
          if (results is List<Barcode>
              && results[0] is Barcode) {
            Barcode res = results[0];
            _title = res.displayValue;
          }
        });
      }
    
      CustomPaint _buildResults(Size imageSize, dynamic results) {
        CustomPainter painter;
    
        switch (_currentDetector) {
          case Detector.barcode:
            painter = BarcodeDetectorPainter(_imageSize, results);
            break;
          case Detector.face:
            painter = FaceDetectorPainter(_imageSize, results);
            break;
          case Detector.label:
            painter = LabelDetectorPainter(_imageSize, results);
            break;
          case Detector.cloudLabel:
            painter = LabelDetectorPainter(_imageSize, results);
            break;
          case Detector.text:
            painter = TextDetectorPainter(_imageSize, results);
            break;
          default:
            break;
        }
    
        return CustomPaint(
          painter: painter,
        );
      }
    
      Widget _buildImage() {
        return Container(
          constraints: const BoxConstraints.expand(),
          decoration: BoxDecoration(
            image: DecorationImage(
              image: Image.file(_imageFile).image,
              fit: BoxFit.fill,
            ),
          ),
          child: _imageSize == null || _scanResults == null
              ? const Center(
            child: Text(
              'Scanning...',
              style: TextStyle(
                color: Colors.green,
                fontSize: 30.0,
              ),
            ),
          )
              : _buildResults(_imageSize, _scanResults),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(_title),
            actions: <Widget>[
              PopupMenuButton<Detector>(
                onSelected: (Detector result) {
                  _currentDetector = result;
                  if (_imageFile != null) _scanImage(_imageFile);
                },
                itemBuilder: (BuildContext context) => <PopupMenuEntry<Detector>>[
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Barcode'),
                    value: Detector.barcode,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Face'),
                    value: Detector.face,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Label'),
                    value: Detector.label,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Cloud Label'),
                    value: Detector.cloudLabel,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Text'),
                    value: Detector.text,
                  ),
                ],
              ),
            ],
          ),
          body: _imageFile == null
              ? const Center(child: Text('No image selected.'))
              : _buildImage(),
          floatingActionButton: FloatingActionButton(
            onPressed: _getAndScanImage,
            tooltip: 'Pick Image',
            child: const Icon(Icons.add_a_photo),
          ),
        );
      }
    }
    

    UPDATE for iOS and Android

    to address a successful build on iOS I've got to use an even lower version of firebase_ml_vision plugin otherwise you have this error.

    pubspec.yaml

    # https://github.com/firebase/firebase-ios-sdk/issues/2151
    firebase_ml_vision: 0.1.2
    image_picker: 0.4.12+1
    

    And I get the error you have so I've got to modify also my classes.

    main.dart

    // Copyright 2018 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    
    import 'dart:async';
    import 'dart:io';
    
    import 'package:firebase_ml_vision/firebase_ml_vision.dart';
    import 'package:flutter/material.dart';
    import 'package:image_picker/image_picker.dart';
    
    import 'detector_painters.dart';
    
    void main() => runApp(MaterialApp(home: _MyHomePage()));
    
    class _MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<_MyHomePage> {
      File _imageFile;
      Size _imageSize;
      dynamic _scanResults;
      String _title = 'ML Vision Example';
      Detector _currentDetector = Detector.barcode;
    
      Future<void> _getAndScanImage() async {
        setState(() {
          _imageFile = null;
          _imageSize = null;
        });
    
        final File imageFile =
        await ImagePicker.pickImage(source: ImageSource.gallery);
    
        if (imageFile != null) {
          _getImageSize(imageFile);
          _scanImage(imageFile);
        }
    
        setState(() {
          _imageFile = imageFile;
        });
      }
    
      Future<void> _getImageSize(File imageFile) async {
        final Completer<Size> completer = Completer<Size>();
    
        final Image image = Image.file(imageFile);
        image.image.resolve(const ImageConfiguration()).addListener(
              (ImageInfo info, bool _) {
            completer.complete(Size(
              info.image.width.toDouble(),
              info.image.height.toDouble(),
            ));
          },
        );
    
        final Size imageSize = await completer.future;
        setState(() {
          _imageSize = imageSize;
        });
      }
    
      Future<void> _scanImage(File imageFile) async {
        setState(() {
          _scanResults = null;
        });
    
        final FirebaseVisionImage visionImage =
        FirebaseVisionImage.fromFile(imageFile);
    
        FirebaseVisionDetector detector;
        switch (_currentDetector) {
          case Detector.barcode:
            detector = FirebaseVision.instance.barcodeDetector();
            break;
          case Detector.face:
            detector = FirebaseVision.instance.faceDetector();
            break;
          case Detector.label:
            detector = FirebaseVision.instance.labelDetector();
            break;
          default:
            return;
        }
    
        final dynamic results =
            await detector.detectInImage(visionImage) ?? <dynamic>[];
    
        setState(() {
          _scanResults = results;
          if (results is List<Barcode>
              && results[0] is Barcode) {
            Barcode res = results[0];
            _title = res.displayValue;
          }
        });
      }
    
      CustomPaint _buildResults(Size imageSize, dynamic results) {
        CustomPainter painter;
    
        switch (_currentDetector) {
          case Detector.barcode:
            painter = BarcodeDetectorPainter(_imageSize, results);
            break;
          case Detector.face:
            painter = FaceDetectorPainter(_imageSize, results);
            break;
          case Detector.label:
            painter = LabelDetectorPainter(_imageSize, results);
            break;
          case Detector.cloudLabel:
            painter = LabelDetectorPainter(_imageSize, results);
            break;
          default:
            break;
        }
    
        return CustomPaint(
          painter: painter,
        );
      }
    
      Widget _buildImage() {
        return Container(
          constraints: const BoxConstraints.expand(),
          decoration: BoxDecoration(
            image: DecorationImage(
              image: Image.file(_imageFile).image,
              fit: BoxFit.fill,
            ),
          ),
          child: _imageSize == null || _scanResults == null
              ? const Center(
            child: Text(
              'Scanning...',
              style: TextStyle(
                color: Colors.green,
                fontSize: 30.0,
              ),
            ),
          )
              : _buildResults(_imageSize, _scanResults),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(_title),
            actions: <Widget>[
              PopupMenuButton<Detector>(
                onSelected: (Detector result) {
                  _currentDetector = result;
                  if (_imageFile != null) _scanImage(_imageFile);
                },
                itemBuilder: (BuildContext context) => <PopupMenuEntry<Detector>>[
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Barcode'),
                    value: Detector.barcode,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Face'),
                    value: Detector.face,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Label'),
                    value: Detector.label,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Cloud Label'),
                    value: Detector.cloudLabel,
                  ),
                  const PopupMenuItem<Detector>(
                    child: Text('Detect Text'),
                    value: Detector.text,
                  ),
                ],
              ),
            ],
          ),
          body: _imageFile == null
              ? const Center(child: Text('No image selected.'))
              : _buildImage(),
          floatingActionButton: FloatingActionButton(
            onPressed: _getAndScanImage,
            tooltip: 'Pick Image',
            child: const Icon(Icons.add_a_photo),
          ),
        );
      }
    }
    

    detector_painters.dart

    // Copyright 2018 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    
    import 'dart:ui' as ui;
    
    import 'package:firebase_ml_vision/firebase_ml_vision.dart';
    import 'package:flutter/material.dart';
    
    enum Detector { barcode, face, label, cloudLabel, text }
    
    class BarcodeDetectorPainter extends CustomPainter {
      BarcodeDetectorPainter(this.absoluteImageSize, this.barcodeLocations);
    
      final Size absoluteImageSize;
      final List<Barcode> barcodeLocations;
    
      @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.stroke
          ..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;
      }
    }
    
    class FaceDetectorPainter extends CustomPainter {
      FaceDetectorPainter(this.absoluteImageSize, this.faces);
    
      final Size absoluteImageSize;
      final List<Face> faces;
    
      @override
      void paint(Canvas canvas, Size size) {
        final double scaleX = size.width / absoluteImageSize.width;
        final double scaleY = size.height / absoluteImageSize.height;
    
        final Paint paint = Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0
          ..color = Colors.red;
    
        for (Face face in faces) {
          canvas.drawRect(
            Rect.fromLTRB(
              face.boundingBox.left * scaleX,
              face.boundingBox.top * scaleY,
              face.boundingBox.right * scaleX,
              face.boundingBox.bottom * scaleY,
            ),
            paint,
          );
        }
      }
    
      @override
      bool shouldRepaint(FaceDetectorPainter oldDelegate) {
        return oldDelegate.absoluteImageSize != absoluteImageSize ||
            oldDelegate.faces != faces;
      }
    }
    
    class LabelDetectorPainter extends CustomPainter {
      LabelDetectorPainter(this.absoluteImageSize, this.labels);
    
      final Size absoluteImageSize;
      final List<Label> labels;
    
      @override
      void paint(Canvas canvas, Size size) {
        final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
          ui.ParagraphStyle(
              textAlign: TextAlign.left,
              fontSize: 23.0,
              textDirection: TextDirection.ltr),
        );
    
        builder.pushStyle(ui.TextStyle(color: Colors.green));
        for (Label label in labels) {
          builder.addText('Label: ${label.label}, '
              'Confidence: ${label.confidence.toStringAsFixed(2)}\n');
        }
        builder.pop();
    
        canvas.drawParagraph(
          builder.build()
            ..layout(ui.ParagraphConstraints(
              width: size.width,
            )),
          const Offset(0.0, 0.0),
        );
      }
    
      @override
      bool shouldRepaint(LabelDetectorPainter oldDelegate) {
        return oldDelegate.absoluteImageSize != absoluteImageSize ||
            oldDelegate.labels != labels;
      }
    }
    

    0 讨论(0)
  • 2021-02-06 15:16

    You can try this:

    flutter plugin: qr_code_tools

    Pub Link - https://pub.dev/packages/qr_code_tools

    Home Page - https://github.com/AifeiI/qr_code_tools

    0 讨论(0)
提交回复
热议问题