Flutter文档扫描插件flutter_twain_scanner的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter文档扫描插件flutter_twain_scanner的使用

插件简介

flutter_twain_scanner 是一个Flutter插件,用于开发跨平台应用程序,可以从TWAIN (32-bit/64-bit)、WIA、SANE、ICA和eSCL扫描仪中数字化文档。该插件提供了可调用的方法,支持开源TWAIN(仅限64位)和Dynamsoft Service REST API。

Flutter TWAIN Dynamsoft Service

Dynamsoft Service REST API

默认情况下,REST API的主机地址设置为 http://127.0.0.1:18622。以下是API的主要方法:

方法 端点 描述 参数 响应
GET /DWTAPI/Scanners 获取扫描仪列表 200 OK 包含扫描仪列表
POST /DWTAPI/ScanJobs 创建扫描任务 license, device, config 201 Created 包含任务ID
GET /DWTAPI/ScanJobs/:id/NextDocument 获取文档图像 id: 任务ID 200 OK 包含图像流
DELETE /DWTAPI/ScanJobs/:id 删除扫描任务 id: 任务ID 200 OK

安装Dynamsoft Service

要使Dynamsoft Service正常工作,请按照以下步骤操作:

  1. 安装Dynamsoft Service

  2. 申请免费试用许可证

Dynamsoft Service配置

安装Dynamsoft Service后,可以通过浏览器访问 http://127.0.0.1:18625/ 来配置主机和端口设置。默认主机IP地址为 127.0.0.1。如果希望在办公室内从桌面、移动和Web应用程序访问服务,可以将主机设置更新为局域网IP地址,例如 192.168.8.72

dynamsoft-service-config

API使用

Open Source TWAIN (Windows 64-bit only)
  • 获取TWAIN兼容扫描仪列表

    List<String> scanners = await _flutterTwainScannerPlugin.getDataSources();
    
  • 从选定扫描仪扫描文档

    int index = _scanners.indexOf(_selectedScanner!);
    List<String> documentPaths = await _flutterTwainScannerPlugin.scanDocument(index);
    
Dynamsoft Service (Windows, macOS, Linux, Android, iOS and Web)
  • 获取TWAIN、WIA和eSCL兼容扫描仪列表

    final DynamsoftService dynamsoftService = DynamsoftService();
    String host = 'http://127.0.0.1:18622';
    final scanners = await dynamsoftService.getDevices(host, ScannerType.TWAINSCANNER | ScannerType.TWAINX64SCANNER);
    
  • 删除扫描任务

    await dynamsoftService.deleteJob(host, jobId);
    
  • 保存扫描任务中的图像到目录

    List<Uint8List> paths = await dynamsoftService.getImageFiles(host, jobId, './');
    
  • 从扫描任务中获取图像流

    List<Uint8List> paths = await dynamsoftService.getImageStreams(host, jobId);
    
  • 创建新的扫描任务

    final Map<String, dynamic> parameters = {
      'license': 'LICENSE-KEY',
      'device': devices[index]['device'],
    };
    
    parameters['config'] = {
      'IfShowUI': false,
      'PixelType': 2,
      'Resolution': 200,
      'IfFeederEnabled': false,
      'IfDuplexEnabled': false,
    };
    
    final String jobId = await dynamsoftService.scanDocument(host, parameters);
    

完整示例Demo

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_twain_scanner/flutter_twain_scanner.dart';
import 'package:flutter_twain_scanner/dynamsoft_service.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _flutterTwainScannerPlugin = FlutterTwainScanner();
  List<String> scannerNames = [];
  String? _selectedScanner;
  String host = 'http://192.168.8.72:18622'; // 替换为您的局域网IP地址
  final DynamsoftService dynamsoftService = DynamsoftService();
  List<dynamic> devices = [];
  List<Uint8List> imagePaths = [];

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
  }

  // 平台消息是异步的,因此我们在异步方法中初始化
  Future<void> initPlatformState() async {
    if (!mounted) return;
  }

  Future<void> _scanDocument(int index) async {
    final Map<String, dynamic> parameters = {
      'license': 'LICENSE-KEY', // 替换为您的许可证密钥
      'device': devices[index]['device'],
    };

    parameters['config'] = {
      'IfShowUI': false,
      'PixelType': 2, // 0: 黑白, 1: 灰度, 2: 彩色
      'Resolution': 200, // 分辨率
      'IfFeederEnabled': false, // 是否启用进纸器
      'IfDuplexEnabled': false, // 是否启用双面扫描
    };

    try {
      final String jobId = await dynamsoftService.scanDocument(host, parameters);

      if (jobId != '') {
        List<Uint8List> paths = await dynamsoftService.getImageStreams(host, jobId);

        await dynamsoftService.deleteJob(host, jobId);

        if (paths.isNotEmpty) {
          setState(() {
            imagePaths.insertAll(0, paths);
          });
        }
      }
    } catch (error) {
      print('An error occurred: $error');
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    Row row = Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        MaterialButton(
          textColor: Colors.white,
          color: Colors.blue,
          onPressed: () async {
            try {
              final scanners = await dynamsoftService.getDevices(host,
                  ScannerType.TWAINSCANNER | ScannerType.TWAINX64SCANNER);
              for (var i = 0; i < scanners.length; i++) {
                devices.add(scanners[i]);
                scannerNames.add(scanners[i]['name']);
              }
              if (devices.isNotEmpty) {
                setState(() {
                  _selectedScanner = devices[0]['name'];
                });
              }
            } catch (error) {
              print('An error occurred: $error');
            }
          },
          child: const Text('List Scanners'),
        ),
        MaterialButton(
          textColor: Colors.white,
          color: Colors.blue,
          onPressed: () async {
            if (_selectedScanner != null) {
              int index = scannerNames.indexOf(_selectedScanner!);
              await _scanDocument(index);
            }
          },
          child: const Text('Scan Document'),
        ),
      ],
    );

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter TWAIN Scanner'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            SizedBox(
              height: 100,
              child: row,
            ),
            DropdownButton(
              hint: const Text('Select a scanner'), // 选项1不需要
              value: _selectedScanner,
              onChanged: (newValue) {
                setState(() {
                  _selectedScanner = newValue;
                });
              },
              items: scannerNames.map((location) {
                return DropdownMenuItem(
                  value: location,
                  child: Text(location),
                );
              }).toList(),
            ),
            Expanded(
              child: imagePaths.isEmpty
                  ? Image.asset('images/default.png')
                  : ListView.builder(
                      itemCount: imagePaths.length,
                      itemBuilder: (context, index) {
                        return Padding(
                          padding: const EdgeInsets.all(10.0),
                          child: Image.memory(
                            imagePaths[index],
                            fit: BoxFit.contain,
                          ), // 对于本地图像,使用 Image.file()
                        );
                      },
                    ),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter文档扫描插件flutter_twain_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文档扫描插件flutter_twain_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 flutter_twain_scanner 插件进行文档扫描的示例代码。需要注意的是,flutter_twain_scanner 插件可能不是广泛知名的 Flutter 插件,因此确保你已经正确添加并配置了这个插件。

首先,确保在你的 pubspec.yaml 文件中添加了依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_twain_scanner: ^最新版本号  # 请替换为实际可用的最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,在你的 Flutter 应用中使用该插件。以下是一个简单的示例,展示如何打开扫描器并进行文档扫描:

import 'package:flutter/material.dart';
import 'package:flutter_twain_scanner/flutter_twain_scanner.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Twain Scanner Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ScanDocumentScreen(),
    );
  }
}

class ScanDocumentScreen extends StatefulWidget {
  @override
  _ScanDocumentScreenState createState() => _ScanDocumentScreenState();
}

class _ScanDocumentScreenState extends State<ScanDocumentScreen> {
  File? _scannedFile;

  Future<void> _scanDocument() async {
    try {
      // 打开扫描器
      var result = await FlutterTwainScanner.scanDocument();
      
      // 检查扫描结果
      if (result != null && result.isNotEmpty) {
        setState(() {
          _scannedFile = File(result.first); // 假设返回的是文件路径列表,取第一个文件
        });
      } else {
        print("No document scanned.");
      }
    } catch (e) {
      print("Error scanning document: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Scan Document'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _scanDocument,
              child: Text('Scan Document'),
            ),
            if (_scannedFile != null)
              Image.file(_scannedFile!),
          ],
        ),
      ),
    );
  }
}

说明:

  1. 依赖添加:确保在 pubspec.yaml 中添加了 flutter_twain_scanner 依赖,并运行 flutter pub get
  2. 扫描功能:在 _scanDocument 方法中,使用 FlutterTwainScanner.scanDocument() 方法打开扫描器。该方法返回一个文件路径列表(假设),我们取第一个文件路径进行处理。
  3. UI 显示:在 UI 上,有一个按钮用于触发扫描操作,如果扫描成功,则显示扫描到的图片。

注意事项:

  • 插件可用性:由于 flutter_twain_scanner 插件可能不是广泛使用的插件,确保你查阅了最新的文档和示例,了解该插件的具体用法和限制。
  • 权限处理:确保你的应用有访问存储和执行扫描操作的权限。这通常在 Android 的 AndroidManifest.xml 和 iOS 的 Info.plist 中配置。
  • 错误处理:在实际应用中,添加更多的错误处理和用户反馈,以提高应用的健壮性和用户体验。

希望这个示例代码能帮助你理解如何使用 flutter_twain_scanner 插件进行文档扫描。如果有任何问题或需要进一步的帮助,请随时提问。

回到顶部