目录

文档扫描

场景介绍

文档扫描控件提供拍摄文档并转换为高清扫描件的服务。仅需拍摄文档,即可自动裁剪和优化,并支持图片、PDF格式保存和分享;同时支持拍摄或从图库选择图片识别表格,生成表格文档。

可广泛用于教育办公场景,扫描文档、票据、课堂PPT和书籍等输出图片/PDF供用户完成发送、存档等操作。

图1 文档扫描示意图

约束与限制

接口说明

以下仅列出demo中调用的部分主要接口,具体API说明详见API参考。

接口名 描述
DocumentScanner 文档扫描控件
DocumentScannerResultCallback 文档扫描结果回调

开发步骤

  1. 将文档扫描控件相关的类添加至工程。

    import { DocType, DocumentScanner, DocumentScannerConfig, SaveOption, FilterId, ShootingMode, DocumentScannerController } from '@kit.VisionKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
  2. 部分设备不支持文档扫描控件的表格提取功能。在使用该功能前,建议先调用isSheetDetectionSupported接口查询当前设备是否支持。

    let documentScannerController: DocumentScannerController = new DocumentScannerController();
    let isSheetSupported = documentScannerController.isSheetDetectionSupported();
    hilog.info(0x0001, TAG, `isSheetSupported: ${isSheetSupported}`);
  3. 配置布局,根据业务场景配置文档扫描控件的相关属性,获取返回的文档图片uri列表。

    const TAG = 'DocumentScanner';
    
    @Entry
    @Component
    struct Index {
      private docScanConfig = new DocumentScannerConfig();
    
      aboutToAppear() {
        let documentScannerController: DocumentScannerController = new DocumentScannerController();
        let isSheetSupported = documentScannerController.isSheetDetectionSupported();
        if (isSheetSupported) {
          this.docScanConfig.supportType = [DocType.DOC, DocType.SHEET];
        } else {
          this.docScanConfig.supportType = [DocType.DOC];
        }
        this.docScanConfig.isGallerySupported = true;
        this.docScanConfig.editTabs = [];
        this.docScanConfig.maxShotCount = 3;
        this.docScanConfig.defaultFilterId = FilterId.ORIGINAL;
        this.docScanConfig.defaultShootingMode = ShootingMode.MANUAL;
        this.docScanConfig.isShareable = true;
        this.docScanConfig.originalUris = [];
      }
    
      build() {
        Column() {
          DocumentScanner({
            scannerConfig: this.docScanConfig,
            onResult: (code: number, saveType: SaveOption, uris: string[]) => {
              hilog.info(0x0001, TAG, `result code: ${code}, save: ${saveType}`);
              uris.forEach(uriString => {
                hilog.info(0x0001, TAG, `uri: ${uriString}`);
              })
            }
          }).size({ width: '100%', height: '100%' })
        }
        .height('100%')
        .width('100%')
      }
    }

开发实例

[h2]Index.ets

// 开发实例分两页实现,一页为文档扫描入口页,一页为文档扫描实现页
// 文档扫描入口页,需引入文档扫描实现页,以下文实例为例,实现页文件名为DocDemoPage
import { DocDemoPage } from './DocDemoPage';

@Entry
@Component
struct MainPage {
  @Provide('pathStack') pathStack: NavPathStack = new NavPathStack();

  @Builder
  PageMap(name: string) {
    if (name === 'documentScanner') {
      DocDemoPage()
    }
  }

  // 文档扫描入口按钮,可替换为业务入口
  build() {
    Navigation(this.pathStack) {
      Button('DocumentScanner', { stateEffect: true, type: ButtonType.Capsule })
        .width('50%')
        .height(40)
        .onClick(() => {
          this.pathStack.pushPath({ name: 'documentScanner' });
        })
    }.title('文档扫描控件demo').navDestination(this.PageMap)
    .mode(NavigationMode.Stack)
  }
}

[h2]DocDemoPage.ets

// 文档扫描实现页,文件名为DocDemoPage,需被引入至入口页
import {
  DocType,
  DocumentScanner,
  DocumentScannerConfig,
  SaveOption,
  FilterId,
  ShootingMode,
  DocumentScannerController
} from '@kit.VisionKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'DocDemoPage';

// 文档扫描页,用于加载UIExtensionAbility
@Component
export struct DocDemoPage {
  @State docImageUris: string[] = [];
  @Consume('pathStack') pathStack: NavPathStack;
  private docScanConfig = new DocumentScannerConfig();

  aboutToAppear() {
    let documentScannerController: DocumentScannerController = new DocumentScannerController();
    let isSheetSupported = documentScannerController.isSheetDetectionSupported();
    if (isSheetSupported) {
      this.docScanConfig.supportType = [DocType.DOC, DocType.SHEET];
    } else {
      this.docScanConfig.supportType = [DocType.DOC];
    }
    this.docScanConfig.isGallerySupported = true;
    this.docScanConfig.editTabs = [];
    this.docScanConfig.maxShotCount = 3;
    this.docScanConfig.defaultFilterId = FilterId.ORIGINAL;
    this.docScanConfig.defaultShootingMode = ShootingMode.MANUAL;
    this.docScanConfig.isShareable = true;
    this.docScanConfig.originalUris = [];
  }

  build() {
    NavDestination() {
      Stack({ alignContent: Alignment.Top }) {
      // 展示文档扫描结果
        List() {
          ForEach(this.docImageUris, (uri: string) => {
            ListItem() {
              Image(uri)
                .objectFit(ImageFit.Contain)
                .width(100)
                .height(100)
            }
          })
        }
        .listDirection(Axis.Vertical)
        .alignListItem(ListItemAlign.Center)
        .margin({
          top: 50
        })
        .width('80%')
        .height('80%')
        
        // 文档扫描
        DocumentScanner({
          scannerConfig: this.docScanConfig,
          onResult: (code: number, saveType: SaveOption, uris: string[]) => {
            hilog.info(0x0001, TAG, `result code: ${code}, save: ${saveType}`);
            if (code === -1) {
              this.pathStack.pop();
            }
            uris.forEach(uriString => {
              hilog.info(0x0001, TAG, `uri: ${uriString}`);
            })
            this.docImageUris = uris;
          }
        })
          .size({ width: '100%', height: '100%' })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .hideTitleBar(true)
  }
}