鸿蒙HarmonyOS应用开发:扫描仪文件扫描

news2024/11/15 21:43:14

华为鸿蒙HarmonyOS已经发展到4.0,使用ArkTS作为开发语言。这篇文章结合Dynamsoft Service开发一个简单的鸿蒙应用,用来获取办公室里连接PC的扫描仪(惠普,富士通,爱普生,等),把文档扫描到手机里。

准备工作

  • Dynamsoft Service

    1. 在连接着扫描仪的电脑上安装Dynamsoft Service。安装包可以满足各种国产操作系统,比如统信UOS麒麟Kylin OS等。支持的架构有:x86x64arm64mips64el。支持的扫描仪协议包括TWAINWIASANEICAeSCL(AirPrint)。下载地址:

      • Windows: Dynamsoft-Service-Setup.msi
      • macOS: Dynamsoft-Service-Setup.pkg
      • Linux:
        • Dynamsoft-Service-Setup.deb
        • Dynamsoft-Service-Setup-arm64.deb
        • Dynamsoft-Service-Setup-mips64el.deb
        • Dynamsoft-Service-Setup.rpm

      然后访问http://127.0.0.1:18622/DWTAPI/Scanners。正常安装可以获取到扫描仪列表。

      dynamsoft-service-scanners

    2. 在浏览器中打开http://127.0.0.1:18625/,把host127.0.0.1改成PC的局域网IP地址。比如192.168.8.72,修改成功可以通过局域网IP地址访问192.168.8.72:18622/DWTAPI/Scanners获取到扫描仪列表。

      dynamsoft-service-config

    3. 申请一个免费试用序列号,扫描文件的时候需要用。

  • DevEco Studio

    下载地址:https://developer.harmonyos.com/cn/develop/deveco-studio/#download。安装前先安装Node.js,路径中不要带空格,否则安装DevEco Studio, 下载HarmonyOS SDK可能会失败。

鸿蒙程序开发

在DevEco Studio中新建工程。

鸿蒙应用工程

entry/src/main/module.json5中添加网络权限:

{
  "module": {
    ...
    "abilities": [
      ...
    ],
    "requestPermissions": [{"name": "ohos.permission.INTERNET"}]
  }
}

打开entry/src/main/etc/pages/Index.ets,导入网络和图像模块:

import http from '@ohos.net.http';
import image from '@ohos.multimedia.image';

声明UI组件,包含两个按钮,一个下拉按钮和一个图片控件:

@Entry
@Component
struct Index {
  @State deviceNames: SelectOption[] = [{value: ''}]
  @State displayImage: PixelMap = undefined
  licenseKey: string = "LICENSE-KEY"; // https://www.dynamsoft.com/customer/license/trialLicense?product=dwt
  host: string = 'http://192.168.8.72:18622'
  devices = []
  index: number = 0
  build() {
    Column() {
      Row() {
        Button('Get Devices')
          .onClick(() => {
            
            }
            );
          }).width('30%')
        Column() {
          Select(this.deviceNames)
            .selected(this.index)
            .value(this.deviceNames[this.index].value.toString())
            .font({size: 14, family: 'serif', style: FontStyle.Normal })
            .onSelect((index:number)=>{
              this.index = index;
            })
        }.width('40%').alignItems(HorizontalAlign.Center)

        Button('Scan')
          .onClick(() => {
            
            }
            );

          }).width('30%')
      }.backgroundColor(0xFFFFFF).padding({ left: 12 }).width('100%').margin({bottom: 5})
      Divider()
      Image(this.displayImage).height('100%').width('100%')
    }.justifyContent(FlexAlign.Start).width('100%').height('100%').padding({left: 5, top: 5, right: 5, bottom: 5})
  }
}

这里的licenseKeyhost需要替换成自己的。

当点击Get Devices按钮的时候,我们通过HTTP GET来获取扫描仪列表:

Button('Get Devices')
    .onClick(() => {
    let url = this.host + '/DWTAPI/Scanners'

    let httpRequest = http.createHttp();
    httpRequest.on('headersReceive', (header) => {
        console.info('header: ' + JSON.stringify(header));
    })

    httpRequest.request(
        url,
        {
        method: http.RequestMethod.GET,
        header: {
            'Content-Type': 'application/json'
        }
        }, (err, data) => {
        if (!err) {
        try {
            const jsonArray = JSON.parse(data.result.toString())
            this.devices = []
            let tmp: SelectOption[] = []
            for (const obj of jsonArray) {
            tmp.push({value: obj.name})
            this.devices.push(obj)
            }

            if (tmp.length > 0) {
            this.index = 0
            this.deviceNames = tmp
            }

        } catch (error) {
            console.error("Error parsing JSON:", error);
        }

        console.info('code:' + JSON.stringify(data.responseCode));

        } else {
        console.info('error:' + JSON.stringify(err));
        httpRequest.off('headersReceive');
        httpRequest.destroy();
        }
    }
    );
    }).width('30%')

当点击Scan按钮的时候,我们通过HTTP POST来触发扫描仪扫描文档. 字段extraData用于传输内容,等同于HTTP请求中的body。传输的参数可以自定义,具体可以参考在线文档。

Button('Scan')
    .onClick(() => {
    if (this.devices.length == 0) {
        return;
    }
    let parameters = {
        license: this.licenseKey,
        device: this.devices[this.index].device,
        config: {
        IfShowUI: false,
        PixelType: 2,
        //XferCount: 1,
        //PageSize: 1,
        Resolution: 200,
        IfFeederEnabled: false,
        IfDuplexEnabled: false,
        }
    };

    let url = this.host + '/DWTAPI/ScanJobs';
    let httpRequest = http.createHttp();
    httpRequest.on('headersReceive', (header) => {
        console.info('header: ' + JSON.stringify(header));
    })
    httpRequest.request(
        url,
        {
        method: http.RequestMethod.POST,
        header: {
            'Content-Type': 'application/json'
        },
        extraData: JSON.stringify(parameters),
        }, (err, data) => {
        if (!err) {
        if (data.responseCode == 201) {
            let jobId = data.result;
            let url = this.host + '/DWTAPI/ScanJobs/' + jobId + '/NextDocument';
            let httpRequest = http.createHttp();
            httpRequest.request(
            url,
            {
                method: http.RequestMethod.GET,
                expectDataType: http.HttpDataType.ARRAY_BUFFER
            }, (err, data) => {
            if (!err) {
                if (data.responseCode == 200) {
                    // show image
                }
            } else {
                console.info('error:' + JSON.stringify(err));
                httpRequest.destroy();
            }
            }
            );
        }
        } else {
        console.info('error:' + JSON.stringify(err));
        httpRequest.off('headersReceive');
        httpRequest.destroy();
        }
    }
    );

    }).width('30%')

获取到的图像是一个ArrayBuffer,我们通过image.createImageSource来创建一个PixelMap对象,然后把它赋值给displayImage,就可以在UI上显示出来了。

let imageData = data.result as ArrayBuffer;
const imageSource = image.createImageSource(imageData);
imageSource.createPixelMap().then(pixelmap => {
    this.displayImage = pixelmap;
});

在华为手机或者鸿蒙模拟器中运行文档扫描程序:
鸿蒙文档扫描

源代码

https://gitee.com/yushulx/harmonyos-document-scanner

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1113920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 3.12.0 Release 版本

本心、输入输出、结果 文章目录 Python 3.12.0 Release 版本前言与 Python 3.11 相比,Python 3.12 系列主要更新了哪些新的功能更灵活的 f 字符串解析,允许许多以前不允许的事情 (PEP 701)。支持 Python 代码中的缓冲区协议 &…

Unity实现方圆X范围随机生成怪物

using System.Collections; using System.Collections.Generic; using UnityEngine;public class CreatMonster : MonoBehaviour {// S这个脚本间隔一点时间生成怪物/*1.程序逻辑* 1. 设计一个计时器* 2.间隔一段时间3s执行一下 * */float SaveTime 0f;public GameObject …

【215. 数组中的第K个最大元素】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 class Solution { public:int getRandom(int left,int right,vector<int>& nums){return nums[rand()%(right-left1)left];}int qsort(int l,int r,vector<int>& nums…

已经有多人中招,不要被AI换脸技术骗了!

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

LinkedList 源码解析(JDK1.8)

目录 一. 前言 二. 常用方法 三. 源码解析 3.1. 属性和内部类 3.2. 构造函数 3.3. 添加元素 3.4. 获取元素 3.5. 删除元素 3.6. 迭代器 3.6.1. 头到尾方向的迭代 3.6.2. 尾到头方向的迭代 3.6.3. add() 插入元素 3.6.4. remove() 移除元素 一. 前言 LinkedList同时…

ATA-8202射频功率放大器参数指标及应用介绍

ATA-8202射频功率放大器简介 ATA-8202是一款射频功率放大器。其P1dB输出功率100W&#xff0c;饱和输出功率200W。增益数控可调&#xff0c;一键保存设置&#xff0c;提供了方便简洁的操作选择&#xff0c;可与主流的信号发生器配套使用&#xff0c;实现射频信号的完美放大。宽…

JavaScript 中的Hoisting是什么?

在JavaScript中,Hoisting(变量提升)是指在代码执行之前,JavaScript引擎将变量和函数的声明提升到当前作用域的顶部的行为。 具体来说,JavaScript引擎在执行代码之前会进行两个步骤:编译阶段和执行阶段。在编译阶段,JavaScript引擎会将变量声明和函数声明提升到当前作用…

智能井盖监测系统,增加城市管理便捷性

看起来小小的井盖&#xff0c;实际上折射的是一个城市&#xff0c;一个地区的发展状况。每一个城市的道路网络&#xff0c;决定了一个城市发展的缓慢程度&#xff0c;哪怕是其中的井盖&#xff0c;有着自己的职责&#xff0c;是城市生命线的不可缺少的组成部分。但是现如今传统…

Qt10-19

第一个界面的头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QMovie>//动态图片所用的类 #include<QMessageBox>//消息对话框类QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget …

国产主控应用案例:汉王电子血压计-君正开发板

2023春季新品发布会上汉王科技发布柯氏音法电子血压计产品—汉王电子血压计&#xff0c;继嗅觉检测盒之后再次深度布局大健康领域。 不同于当前市面上使用示波法原理的电子血压计&#xff0c;汉王电子血压计采用血压测量金标准中的柯氏音法&#xff0c;由此引领一场电子血压计领…

出东方利中国!长城五星牵手国家宝藏,共谱丝路艺术华章

执笔 | 尼 奥 编辑 | 古利特 当中国葡萄酒与国家宝藏、非遗工艺灵魂碰撞&#xff0c;又将产生怎样的大国之美&#xff1f;长城五星艺术干红给出答案。 10月19日&#xff0c;长城五星艺术干红上市发布会在成都召开。会上&#xff0c;长城葡萄酒正式发布文化战略新品——“五…

“达观杯”智能文档版面分析赛题baseline已上线,欢迎下载报名!

由国内领先智能文本处理企业达观数据与上海市计算机学会联合举办的智能文档版面分析多模态数据处理算法竞赛正在火热报名阶段。开赛一周内&#xff0c;第七届“达观杯”已有来自国内外的近200名企业和高校算法精英参与到比赛中。作为本次赛题的出题方&#xff0c;为助力各位打榜…

taro使用defineConstants定义全局变量eslint报错该变量不存在

问题描述 在taro项目中使用defineConstants定义一些全局变量供业务代码中进行使用&#xff0c;全局变量声明config/index.js代码如下&#xff1a; module.exports {defineConstants: {LOGIN_URL: JSON.stringify(/baidu/login), },全局变量使用代码如下&#xff1a; /*** 跳…

高速DSP系统设计参考指南(四)DSP电源设计

&#xff08;四&#xff09;DSP电源设计 1.电源设计的重要性2.DSP电源架构考虑3.电源去耦技术3.1 一般经验法则解耦法3.2 解耦分析方法3.3 分析案例3.4 计算去耦电容值3.5 高频噪声隔离 1.电源设计的重要性 电源设计可能是高速 DSP 设计中控制噪声和辐射的整个过程中最具挑战性…

Affinity Photofor Mac/Windows:专业级图片编辑的终极选择

在今天的内容中&#xff0c;我们将要介绍一款备受赞誉的图片编辑软件——Affinity Photo。无论你是业余的摄影爱好者&#xff0c;还是专业的设计师&#xff0c;Affinity Photo都能为你提供丰富的编辑功能和出色的使用体验。 首先&#xff0c;让我们来简单了解一下Affinity Pho…

哪些重生奇迹mu地图适合刷玛雅宝石?

作为一款非常经典的打斗游戏&#xff0c;重生奇迹mu设计非常复杂&#xff0c;游戏玩法以及地图设计非常完善&#xff0c;而且游戏推出了最新版本&#xff0c;各方面表现更加的优秀&#xff0c;值得游戏玩家去尝试。 重生奇迹mu游戏拥有非常完善的商城系统&#xff0c;其中最重…

金融机器学习方法:决策树与随机森林

目录 1.决策树 1.1 什么是决策树&#xff1f; 1.2 决策树的优点与缺点 2.随机森林 2.1 什么是随机森林&#xff1f; 2.2 随机森林的优点与缺点 3.决策树与随机森林的联系与区别 4.案例分析 4.1 使用决策树和随机森林预测 4.2绘制ROC曲线 决策树和随机森林都是监督学…

聊聊Android线程优化这件事

一、背景 在日常开发APP的过程中&#xff0c;难免需要使用第二方库和第三方库来帮助开发者快速实现一些功能&#xff0c;提高开发效率。但是&#xff0c;这些库也可能会给线程带来一定的压力&#xff0c;主要表现在以下几个方面&#xff1a; 线程数量增多&#xff1a;一些库可…

uniapp——自定义组件插槽及使用

案例样式 自定义组件pageBox.vue <template><view><view class"bgColor" :style"{ height: bgHeight rpx }"></view><view class"main"><!-- 主要内容放这里 --><slot></slot></view>&…

虚拟/物理机备份中深度有效数据提取应用原理

当前针对虚拟机的磁盘映像备份的通用技术&#xff0c;主要通过识别虚拟机磁盘文件的元数据&#xff0c;或是借助虚拟化API&#xff08;如CBT接口&#xff09;或分区结构提取位图来进行。然而&#xff0c;由于虚拟化环境底层的限制&#xff0c;无法洞悉文件系统的内部运作&#…