Flutterでカメラ撮影から矩形選択からOCRのAndroid、iPhone動作確認
Flutter で、カメラ撮影から、画像の切り抜き し、Cloud Vision API で OCR の結果を表示する。
/lib/main.dart
import 'dart:io'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image_cropper/image_cropper.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { final message = "Initial Message."; @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Sample', home: MyPage(message:this.message), ); } } class MyPageState extends State<MyPage>{ String _time; File _image; final _stateController = TextEditingController(); final _visionTextController = TextEditingController(); //final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer(); final TextRecognizer textRecognizer = FirebaseVision.instance.cloudTextRecognizer(); @override void initState() { super.initState(); this._time = "Tap Floating Action Button"; } @override void dispose() { this._stateController.dispose(); this._visionTextController.dispose(); super.dispose(); } Future getImage() async { var image = await ImagePicker.pickImage(source: ImageSource.camera); setState(() { this._image = image; }); } Future cropImage() async { var croppedImage = await ImageCropper.cropImage(sourcePath: this._image.path, aspectRatioPresets: [ CropAspectRatioPreset.square, CropAspectRatioPreset.ratio3x2, CropAspectRatioPreset.original, CropAspectRatioPreset.ratio4x3, CropAspectRatioPreset.ratio16x9 ], androidUiSettings: AndroidUiSettings( toolbarTitle: 'Cropper', toolbarColor: Colors.deepOrange, toolbarWidgetColor: Colors.white, initAspectRatio: CropAspectRatioPreset.original, lockAspectRatio: false), iosUiSettings: IOSUiSettings( minimumAspectRatio: 1.0, ) ); setState(() { this._image = croppedImage; }); } void vision() async { if (this._image != null) { FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(this._image); VisionText visionText = await textRecognizer.processImage(visionImage); String text = visionText.text; print(text); var buf = new StringBuffer(); for (TextBlock block in visionText.blocks) { final Rect boundingBox = block.boundingBox; final List<Offset> cornerPoints = block.cornerPoints; final String text = block.text; final List<RecognizedLanguage> languages = block.recognizedLanguages; print(languages); buf.write("=====================\n"); for (TextLine line in block.lines) { // Same getters as TextBlock buf.write("${line.text}\n"); for (TextElement element in line.elements) { // Same getters as TextBlock } } } setState(() { this._visionTextController.text = buf.toString(); }); } } void showTime(){ setState(() { this._time = DateTime.now().toString(); }); } void loadOnPressed() { Firestore.instance.document("sample/sandwichData") .get().then((DocumentSnapshot ds){ setState(() { this._stateController.text = ds["hotDogStatus"]; }); print("status=$this.status"); }); } void saveOnPressed() { Firestore.instance.document("sample/sandwichData") .updateData({"hotDogStatus":_stateController.text}) .then((value) => print("success")) .catchError((value) => print("error $value")); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Firebase Sample'), ), body: LayoutBuilder( builder: (BuildContext context, BoxConstraints viewportConstraints) { return SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints( minHeight: viewportConstraints.maxHeight, ), child: IntrinsicHeight( child: Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( this._time, style: TextStyle(fontSize: 16.0), ), Row( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Flexible( child: TextField( controller: _stateController, ), ), Padding( padding: EdgeInsets.all(2.0), child: RaisedButton( onPressed: saveOnPressed, child: Text("Save")), ), Padding( padding: EdgeInsets.all(2.0), child: RaisedButton( onPressed: loadOnPressed, child: Text("Load")) ) ], ), Column( children: <Widget>[ Row( children: <Widget>[ Padding( padding: EdgeInsets.all(2.0), child: RaisedButton( onPressed: getImage, child: Text("Pick Image"), ), ), Padding( padding: EdgeInsets.all(2.0), child: RaisedButton( onPressed: cropImage, child: Text("Crop Image"), ), ), Padding( padding: EdgeInsets.all(2.0), child: RaisedButton( onPressed: vision, child: Text("Vision Api"), ), ), ], ), TextField( controller: _visionTextController, minLines: 6, maxLines: 15, decoration: InputDecoration( border: OutlineInputBorder(), ), ), Container( //width: MediaQuery.of(context).size.width, //height: 300, child: FittedBox( fit: BoxFit.fitHeight, child: _image == null ? Text('No image selected.') : Image.file(_image), ), ), ], ), ], ), ), ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: showTime, child: Icon(Icons.timer), ), ); } } class MyPage extends StatefulWidget { final String message; MyPage({this.message}):super() {} @override State<StatefulWidget> createState() => new MyPageState(); }
pubspec.yaml
dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.2 cloud_firestore: 0.13.4+2 firebase_ml_vision: 0.9.3+8 image_picker: 0.6.5 image_cropper: 1.2.
android/app/src/main/AndroidManifest.xml
<activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
ios/Runner/Info.plist
以下を追記
<key>NSPhotoLibraryUsageDescription</key> <string>What purpose to use</string> <key>NSCameraUsageDescription</key> <string>What purpose to use</string> <key>NSMicrophoneUsageDescription</key> <string>What purpose to use</string>