mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-09 00:07:49 -06:00
175 lines
3.8 KiB
Dart
175 lines
3.8 KiB
Dart
import 'dart:async';
|
|
import 'dart:developer';
|
|
|
|
import 'package:camera/camera.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:paperless_document_scanner/types/edge_detection_result.dart';
|
|
|
|
import 'camera_view.dart';
|
|
import 'cropping_preview.dart';
|
|
import 'edge_detector.dart';
|
|
import 'image_view.dart';
|
|
|
|
class Scan extends StatefulWidget {
|
|
const Scan({
|
|
super.key,
|
|
required,
|
|
required this.cameras,
|
|
});
|
|
final List<CameraDescription> cameras;
|
|
@override
|
|
State<Scan> createState() => _ScanState();
|
|
}
|
|
|
|
class _ScanState extends State<Scan> {
|
|
late final CameraController controller;
|
|
String? imagePath;
|
|
String? croppedImagePath;
|
|
EdgeDetectionResult? edgeDetectionResult;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
controller = CameraController(
|
|
widget.cameras[0],
|
|
ResolutionPreset.veryHigh,
|
|
imageFormatGroup: ImageFormatGroup.jpeg,
|
|
enableAudio: false,
|
|
);
|
|
() async {
|
|
await controller.initialize();
|
|
log(controller.value.toString());
|
|
}();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Stack(
|
|
children: <Widget>[
|
|
_getMainWidget(),
|
|
_getBottomBar(),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _getMainWidget() {
|
|
if (croppedImagePath != null) {
|
|
return ImageView(imagePath: croppedImagePath!);
|
|
}
|
|
|
|
if (imagePath == null && edgeDetectionResult == null) {
|
|
return CameraView(controller: controller);
|
|
}
|
|
|
|
return ImagePreview(
|
|
imagePath: imagePath!,
|
|
edgeDetectionResult: edgeDetectionResult,
|
|
);
|
|
}
|
|
|
|
Widget _getButtonRow() {
|
|
if (imagePath != null) {
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: FloatingActionButton(
|
|
child: Icon(Icons.check),
|
|
onPressed: () async {
|
|
if (croppedImagePath == null) {
|
|
return _processImage(imagePath!, edgeDetectionResult!);
|
|
}
|
|
|
|
setState(() {
|
|
imagePath = null;
|
|
edgeDetectionResult = null;
|
|
croppedImagePath = null;
|
|
});
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
FloatingActionButton(
|
|
foregroundColor: Colors.white,
|
|
child: Icon(Icons.camera_alt),
|
|
onPressed: onTakePictureButtonPressed,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
|
|
|
|
Future<String> takePicture() async {
|
|
if (!controller.value.isInitialized) {
|
|
throw Exception("Select camera first!");
|
|
}
|
|
|
|
final file = await controller.takePicture();
|
|
|
|
return file.path;
|
|
}
|
|
|
|
Future _detectEdges(String filePath) async {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
imagePath = filePath;
|
|
});
|
|
|
|
EdgeDetectionResult result =
|
|
await EdgeDetector().detectEdgesFromFile(filePath);
|
|
|
|
setState(() {
|
|
edgeDetectionResult = result;
|
|
});
|
|
}
|
|
|
|
Future _processImage(
|
|
String filePath, EdgeDetectionResult edgeDetectionResult) async {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
|
|
bool result = await EdgeDetector()
|
|
.processImageFromFile(filePath, edgeDetectionResult);
|
|
|
|
if (result == false) {
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
imageCache.clearLiveImages();
|
|
imageCache.clear();
|
|
croppedImagePath = imagePath;
|
|
});
|
|
}
|
|
|
|
void onTakePictureButtonPressed() async {
|
|
String filePath = await takePicture();
|
|
|
|
log('Picture saved to $filePath');
|
|
|
|
await _detectEdges(filePath);
|
|
}
|
|
|
|
Padding _getBottomBar() {
|
|
return Padding(
|
|
padding: EdgeInsets.only(bottom: 32),
|
|
child: Align(alignment: Alignment.bottomCenter, child: _getButtonRow()),
|
|
);
|
|
}
|
|
}
|