mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-11 06:08:04 -06:00
feat: Add document scanner package
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:paperless_document_scanner/types/edge_detection_result.dart';
|
||||
|
||||
final DynamicLibrary _nativeInteropLib = Platform.isAndroid
|
||||
? DynamicLibrary.open("libnative_edge_detection.so")
|
||||
: DynamicLibrary.process();
|
||||
|
||||
class EdgeDetection {
|
||||
static Future<EdgeDetectionResult> detectEdgesFromFile(String path) async {
|
||||
final detectEdges = _nativeInteropLib
|
||||
.lookup<NativeFunction<_c_detect_edges_from_file>>(
|
||||
"detect_edges_from_file")
|
||||
.asFunction<_dart_detect_edges_from_file>();
|
||||
|
||||
NativeEdgeDetectionResult detectionResult =
|
||||
detectEdges(path.toNativeUtf8()).ref;
|
||||
|
||||
return EdgeDetectionResult(
|
||||
topLeft: Offset(
|
||||
detectionResult.topLeft.ref.x, detectionResult.topLeft.ref.y),
|
||||
topRight: Offset(
|
||||
detectionResult.topRight.ref.x, detectionResult.topRight.ref.y),
|
||||
bottomLeft: Offset(
|
||||
detectionResult.bottomLeft.ref.x, detectionResult.bottomLeft.ref.y),
|
||||
bottomRight: Offset(detectionResult.bottomRight.ref.x,
|
||||
detectionResult.bottomRight.ref.y));
|
||||
}
|
||||
|
||||
static Future<EdgeDetectionResult> detectEdges(Uint8List bytes) async {
|
||||
final detectEdges = _nativeInteropLib
|
||||
.lookup<NativeFunction<_c_detect_edges>>("detect_edges")
|
||||
.asFunction<_dart_detect_edges>();
|
||||
|
||||
Pointer<Uint8> imgBuffer = malloc.allocate<Uint8>(bytes.lengthInBytes);
|
||||
Uint8List buffer = imgBuffer.asTypedList(bytes.lengthInBytes);
|
||||
buffer.setAll(0, bytes);
|
||||
|
||||
NativeEdgeDetectionResult detectionResult = detectEdges(
|
||||
imgBuffer,
|
||||
buffer.lengthInBytes,
|
||||
).ref;
|
||||
|
||||
final result = EdgeDetectionResult(
|
||||
topLeft: Offset(
|
||||
detectionResult.topLeft.ref.x,
|
||||
detectionResult.topLeft.ref.y,
|
||||
),
|
||||
topRight: Offset(
|
||||
detectionResult.topRight.ref.x,
|
||||
detectionResult.topRight.ref.y,
|
||||
),
|
||||
bottomLeft: Offset(
|
||||
detectionResult.bottomLeft.ref.x,
|
||||
detectionResult.bottomLeft.ref.y,
|
||||
),
|
||||
bottomRight: Offset(
|
||||
detectionResult.bottomRight.ref.x,
|
||||
detectionResult.bottomRight.ref.y,
|
||||
),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
typedef _c_detect_edges_from_file = Pointer<NativeEdgeDetectionResult> Function(
|
||||
Pointer<Utf8> imagePath,
|
||||
);
|
||||
|
||||
typedef _c_detect_edges = Pointer<NativeEdgeDetectionResult> Function(
|
||||
Pointer<Uint8> bytes,
|
||||
Int32 byteSize,
|
||||
);
|
||||
|
||||
typedef _dart_detect_edges_from_file = Pointer<NativeEdgeDetectionResult>
|
||||
Function(
|
||||
Pointer<Utf8> imagePath,
|
||||
);
|
||||
|
||||
typedef _dart_detect_edges = Pointer<NativeEdgeDetectionResult> Function(
|
||||
Pointer<Uint8> bytes,
|
||||
int byteSize,
|
||||
);
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:paperless_document_scanner/types/edge_detection_result.dart';
|
||||
|
||||
final DynamicLibrary _nativeInteropLib = Platform.isAndroid
|
||||
? DynamicLibrary.open("libnative_edge_detection.so")
|
||||
: DynamicLibrary.process();
|
||||
|
||||
class ImageProcessing {
|
||||
static Future<bool> processImageFromFile(
|
||||
String path,
|
||||
EdgeDetectionResult result,
|
||||
) async {
|
||||
final processImage = _nativeInteropLib
|
||||
.lookup<NativeFunction<_c_process_image_from_file>>(
|
||||
"process_image_from_file")
|
||||
.asFunction<_dart_process_image_from_file>();
|
||||
|
||||
return processImage(
|
||||
path.toNativeUtf8(),
|
||||
result.topLeft.dx,
|
||||
result.topLeft.dy,
|
||||
result.topRight.dx,
|
||||
result.topRight.dy,
|
||||
result.bottomLeft.dx,
|
||||
result.bottomLeft.dy,
|
||||
result.bottomRight.dx,
|
||||
result.bottomRight.dy,
|
||||
) ==
|
||||
1;
|
||||
}
|
||||
|
||||
static Future<bool> processImage(
|
||||
Uint8List bytes,
|
||||
EdgeDetectionResult result,
|
||||
) async {
|
||||
final processImage = _nativeInteropLib
|
||||
.lookup<NativeFunction<_c_process_image>>("process_image")
|
||||
.asFunction<_dart_process_image>();
|
||||
|
||||
final imgBuffer = malloc.allocate<Uint8>(bytes.lengthInBytes);
|
||||
Uint8List buffer = imgBuffer.asTypedList(bytes.lengthInBytes);
|
||||
buffer.setAll(0, bytes);
|
||||
|
||||
return processImage(
|
||||
imgBuffer,
|
||||
bytes.lengthInBytes,
|
||||
result.topLeft.dx,
|
||||
result.topLeft.dy,
|
||||
result.topRight.dx,
|
||||
result.topRight.dy,
|
||||
result.bottomLeft.dx,
|
||||
result.bottomLeft.dy,
|
||||
result.bottomRight.dx,
|
||||
result.bottomRight.dy,
|
||||
) ==
|
||||
1;
|
||||
}
|
||||
}
|
||||
|
||||
typedef _c_process_image_from_file = Int8 Function(
|
||||
Pointer<Utf8> imagePath,
|
||||
Double topLeftX,
|
||||
Double topLeftY,
|
||||
Double topRightX,
|
||||
Double topRightY,
|
||||
Double bottomLeftX,
|
||||
Double bottomLeftY,
|
||||
Double bottomRightX,
|
||||
Double bottomRightY,
|
||||
);
|
||||
|
||||
typedef _c_process_image = Int8 Function(
|
||||
Pointer<Uint8> imagePath,
|
||||
Int32 byteSize,
|
||||
Double topLeftX,
|
||||
Double topLeftY,
|
||||
Double topRightX,
|
||||
Double topRightY,
|
||||
Double bottomLeftX,
|
||||
Double bottomLeftY,
|
||||
Double bottomRightX,
|
||||
Double bottomRightY,
|
||||
);
|
||||
|
||||
typedef _dart_process_image_from_file = int Function(
|
||||
Pointer<Utf8> imagePath,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY,
|
||||
);
|
||||
|
||||
typedef _dart_process_image = int Function(
|
||||
Pointer<Uint8> imagePath,
|
||||
int byteSize,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY,
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
export 'modules/edge_detection.dart';
|
||||
export 'modules/image_processing.dart';
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'dart:ffi';
|
||||
|
||||
class Coordinate extends Struct {
|
||||
@Double()
|
||||
external double x;
|
||||
|
||||
@Double()
|
||||
external double y;
|
||||
|
||||
factory Coordinate.allocate(double x, double y) => malloc<Coordinate>().ref
|
||||
..x = x
|
||||
..y = y;
|
||||
}
|
||||
|
||||
class NativeEdgeDetectionResult extends Struct {
|
||||
external Pointer<Coordinate> topLeft;
|
||||
external Pointer<Coordinate> topRight;
|
||||
external Pointer<Coordinate> bottomLeft;
|
||||
external Pointer<Coordinate> bottomRight;
|
||||
|
||||
factory NativeEdgeDetectionResult.allocate(
|
||||
Pointer<Coordinate> topLeft,
|
||||
Pointer<Coordinate> topRight,
|
||||
Pointer<Coordinate> bottomLeft,
|
||||
Pointer<Coordinate> bottomRight,
|
||||
) =>
|
||||
malloc<NativeEdgeDetectionResult>().ref
|
||||
..topLeft = topLeft
|
||||
..topRight = topRight
|
||||
..bottomLeft = bottomLeft
|
||||
..bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
class EdgeDetectionResult {
|
||||
final Offset topLeft;
|
||||
final Offset topRight;
|
||||
final Offset bottomLeft;
|
||||
final Offset bottomRight;
|
||||
|
||||
EdgeDetectionResult({
|
||||
required this.topLeft,
|
||||
required this.topRight,
|
||||
required this.bottomLeft,
|
||||
required this.bottomRight,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user