文档扫描应用大都是移动应用。结合手机摄像头可以实现文档拍摄,边缘检测,自动剪裁,透视矫正,滤镜等功能。但是桌面办公也少不了文档处理。这里分享下如何使用Dynamsoft Document Normalizer C++ SDK实现用于桌面文档处理的Flutter插件。
需要快速体验可以直接访问
https://pub.dev/packages/flutter_document_scan_sdk
因为C++ SDK只提供了Windows和Linux的库,所以我们创建一个支持Windows和Linux的Flutter插件工程:
flutter create --org com.dynamsoft --template=plugin --platforms=windows,linux .
我们看到Windows和Linux插件代码都是通过CMake编译的。所以需要打开CMakeLists.txt
文件配置下编译环境。
Windows
link_directories("${PROJECT_SOURCE_DIR}/lib/")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin "DynamsoftCorex64" "DynamsoftDocumentNormalizerx64")
set(flutter_document_scan_sdk_bundled_libraries
"${PROJECT_SOURCE_DIR}/bin/"
PARENT_SCOPE
)
Linux
link_directories("${PROJECT_SOURCE_DIR}/lib/")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter "DynamsoftCore" "DynamsoftDocumentNormalizer")
set(flutter_document_scan_sdk_bundled_libraries
PARENT_SCOPE
)
两个平台有一些差异。用于Windows和Linux的库名字有一些不同。Windows上因为链接的是*.lib
文件,最后还需要指定*.dll
文件的路径用于打包。
Flutter和底层代码是通过method channel通信的。
首先在flutter_document_scan_sdk_method_channel.dart
中定义上层接口:
class MethodChannelFlutterDocumentScanSdk
extends FlutterDocumentScanSdkPlatform {
final methodChannel = const MethodChannel('flutter_document_scan_sdk');
Future<String?> getPlatformVersion() async {
final version =
await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
Future<int?> init(String path, String key) async {
return await methodChannel
.invokeMethod<int>('init', {
'path': path, 'key': key});
}
Future<int?> setParameters(String params) async {
return await methodChannel
.invokeMethod<int>('setParameters', {
'params': params});
}
Future<String?> getParameters() async {
return await methodChannel.invokeMethod<String>('getParameters');
}
Future<List<DocumentResult>> detect(String file) async {
List? results = await methodChannel.invokeListMethod<dynamic>(
'detect',
{
'file': file},
);
return _resultWrapper(results);
}
List<DocumentResult> _resultWrapper(List<dynamic>? results) {
List<DocumentResult> output = [];
if (results != null) {
for (var result in results) {
int confidence = result['confidence'];
List<Offset> offsets = [];
int x1 = result['x1'];
int y1 = result['y1'];
int x2 = result['x2'];
int y2 = result['y2'];
int x3 = result['x3'];
int y3 = result['y3'];
int x4 = result['x4'];
int y4 = result['y4'];
offsets.add(Offset(x1.toDouble(), y1.toDouble()));
offsets.add(Offset(x2.toDouble(), y2.toDouble()));
offsets.add(Offset(x3.toDouble(), y3.toDouble()));
offsets.add(Offset(x4.toDouble(), y4.toDouble()));
DocumentResult documentResult = DocumentResult(confidence, offsets, []);
output.add(documentResult);
}
}
return output;
}
Future<NormalizedImage?> normalize(String file, dynamic points) async {
Offset offset = points[0];
int x1 = offset.dx.toInt();
int y1 = offset.dy.toInt();
offset = points[1];
int x2 = offset.dx.toInt();
int y2 = offset.dy.toInt();
offset = points[2];
int x3 = offset.dx.toInt();
int y3 = offset.dy.toInt();
offset = points[3];
int x4 = offset.dx.toInt();
int y4 = offset.dy.toInt();
Map? result = await methodChannel.invokeMapMethod<String, dynamic>(
'normalize',
{
'file': file,
'x1': x1,
'y1': y1,
'x2': x2,
'y2': y2,
'x3': x3,
'y3': y3,
'x4': x4,
'y4': y4
},
);
if (result != null) {
return NormalizedImage(
result['data'],
result['width'],
result['height'],
);
}
return null;
}
Future<int?> save(String filename) async {
return await methodChannel
.invokeMethod<int>('save', {
'filename': filename});
}
}
然后在C++中解析接口名和参数名。Windows上C++的入口函数是FlutterDocumentScanSdkPlugin::HandleMethodCall
,而Linux上是flutter_document_scan_sdk_plugin_handle_method_call
。
Windows
#include "flutter_document_scan_sdk_plugin.h"
#include
#include
#include
#include
#include
#include
#include
void FlutterDocumentScanSdkPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result){
}
Linux
#include "include/flutter_document_scan_sdk/flutter_document_scan_sdk_plugin.h"
#include
#include
#include
#include
static void flutter_document_scan_sdk_plugin_handle_method_call(
FlutterDocumentScanSdkPlugin