使用C++实现Windows和Linux的Flutter文档扫描插件

本文介绍如何使用Dynamsoft Document Normalizer C++ SDK创建一个Flutter桌面插件,支持Windows和Linux的文档扫描。通过Flutter method channel通信,实现文档边缘检测、剪裁和透视矫正功能。代码可在Windows、Linux和Web上运行。
摘要由CSDN通过智能技术生成

文档扫描应用大都是移动应用。结合手机摄像头可以实现文档拍摄,边缘检测,自动剪裁,透视矫正,滤镜等功能。但是桌面办公也少不了文档处理。这里分享下如何使用Dynamsoft Document Normalizer C++ SDK实现用于桌面文档处理的Flutter插件。

Flutter文档扫描插件下载

需要快速体验可以直接访问
https://pub.dev/packages/flutter_document_scan_sdk

生成配置Flutter桌面插件工程

因为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和C++接口实现

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 <windows.h>

#include <VersionHelpers.h>

#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>

#include <memory>
#include <sstream>

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 <flutter_linux/flutter_linux.h>
#include <gtk/gtk.h>
#include <sys/utsname.h>

#include <cstring>

static void flutter_document_scan_sdk_plugin_handle_method_call(
    FlutterDocumentScanSdkPlugin 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值