TextIn OCR Frontend前端开源组件库发布!

为什么开源 TextIn OCR Frontend 前端组件库?

在 TextIn 社群中,我们时常接到用户反馈,调取 API 进行票据等文件批量识别后,需要另行完成前端工程,实现比对环节。为助力用户节省工程成本,TextIn 团队正式开源 OCR Frontend 前端组件库,便于用户搭建前端界面,完成识别结果审核,提升使用体验。

此外,对于有翻译、校对等需求的开发者,也可灵活应用开源组件库,进行二次开发。

TextIn OCR Frontend 是一个用于展示 Textin 识别结果的 React 组件库,支持文件预览、坐标回显和结果展示。

组件库适配票据类解析结果(key-value)的展示,前端界面案例见下图。

特性

  • 📄 支持图片和 PDF 文件预览

  • 🎯 支持文本区域坐标回显和高亮

  • 🔄 预览区域和识别结果双向联动

  • 📊 支持 JSON 格式结果展示

  • 🎨 TODO:可自定义样式和主题

安装与使用

拉取项目

复制代码
git clone https://github.com/intsig-textin/textin-ocr-frontend.git

npm install textin-ocr-frontend
# 或
yarn add textin-ocr-frontend

快速开始

复制代码
import { FilePreview, ResultView, JsonView } from "textin-ocr-frontend";

functionApp() {
return (
    <div style={{ display: "flex" }}>
      <div style={{ flex: 1 }}>
        <FilePreview src="path/to/image.jpg" rects={rects} pages={pages} />
      </div>
      <div style={{ flex: 1 }}>
        <ResultView resultList={resultList} />
      </div>
    </div>
  );
}

组件说明

1. FilePreview 文件预览组件

文件预览组件,支持 PDF 和图片预览,支持缩放、旋转、分页等功能。

Props

2. ResultView 结果展示组件

结果展示组件,支持表格和列表两种展示方式。

Props

3. MarkLayer 标注层组件

标注层组件,用于在图片显示标注框。

Props

4. JsonView JSON 展示组件

JSON 数据展示组件,用于格式化展示 JSON 数据。 本项目 JSON 数据采用react-json-view库渲染,API 保持一致,详细属性可参考其官方文档。

Props

API Interface 定义

PDFSrc

PDF 文件源配置

复制代码
interface DocumentInitParameters {
  [key: string]: any;
  url?: string | URL;
  data?: TypedArray | ArrayBuffer | Array<number> | string;
  httpHeaders?: Object;
  withCredentials?: boolean;
  password?: string;
  length?: boolean;
}

type PDFSrc = DocumentInitParameters;
IRectItem

标注框数据

复制代码
interface IRectItem {
  [key: string]: any;
  key?: string;
  type?: string;
  rect_type?: string;
  uid: string;
  parent_uid?: string;
  content_id: string;
  parent_id?: string;
  position: number[];
  angle?: number;
  render_text?: string;
}
IPageItem

页面数据

复制代码
interface IPageItem {
  page_number: number;
  duration: number;
  ppi: number;
  width: number;
  height: number;
  angle?: number;
}
IResultListItem

结果列表项

复制代码
interface IResultListItem extends IRectItem {
  type: string;
  description: string;
  no: number;
  list: IFieldItem[];
  flightList: IFieldItem[][];
  page_id?: number;
}
IFieldItem

字段项

复制代码
interface IFieldItem extends IOriginFieldItem {
  uid: string;
  parent_uid?: string;
}

interface IOriginFieldItem {
  key: string;
  type?: string;
  value: string;
  description: string;
  position: number[];
}
ToolbarOptions

工具栏配置

复制代码
interface ToolbarOptions {
  tools: PreviewToolItem[];
}

interface PreviewToolItem {
  Icon: React.ComponentType<any>;
  onClick: () => void;
  type: string;
  disabled?: boolean;
}
PreviewToolItem

工具栏配置项

复制代码
interface PreviewToolItem {
  Icon: React.ComponentType<any>;  // 工具栏图标组件
  onClick: () => void;            // 点击事件处理函数
  type: string;                   // 工具类型
  disabled?: boolean;             // 是否禁用
}

Hooks

useContentLinkage

用于实现预览区域和识别结果的双向联动。

复制代码
const { activeContentId, activeParentContentId, registerLinkage } =
  useContentLinkage({
    viewContainerRef,
    resultContainerRef,
  });

参数

返回值

usePDFMarkLayer

用于在 PDF 文档上实现标注层功能。

复制代码
const { run } = usePDFMarkLayer({
  containerRef,
  pdfViewerRef,
  rects,
  pages,
  dpi,
  activeContentId,
  showMark,
});

参数

返回值

usePreviewTool

用于实现预览工具栏功能,包括缩放、旋转和 1:1 还原。

复制代码
const { tools, scale, rotate, position, onMouseDown, onWheel, resizeScale } =
  usePreviewTool({
    viewContainerRef,
    viewRef,
    toolbarOptions,
  });

参数

返回值

示例

图片示例
复制代码
import { useLayoutEffect, useRef, useState } from "react";
import FilePreview from "../components/FilePreview";
import { RadioGroup } from "../components/RadioGroup";
import ResultView from "../components/ResultView";
import { imageExample } from "./data";
import JsonView from "../components/JsonView";
import { useContentLinkage } from "../hooks/useContentLinkage";

export default functionImageExample() {
  const [resultTab, setResultTab] = useState("text");
  const viewContainerRef = useRef<HTMLElement | null>(null);
  const resultContainerRef = useRef<HTMLElement | null>(null);

  const { activeParentContentId, activeContentId, registerLinkage } =
    useContentLinkage({
      viewContainerRef,
      resultContainerRef,
    });

  useLayoutEffect(() => {
    registerLinkage();
  }, []);

return (
    <div
      style={{
        display: "flex",
        width: "100%",
        height: "calc(100% - 80px)",
        padding: 16,
        textAlign: "center",
        columnGap: 32,
      }}
    >
      <div style={{ flex: 4, minWidth: "40%", maxWidth: "60%" }}>
        <div style={{ margin: 16 }}>预览</div>
        <div
          style={{
            position: "relative",
            overflow: "hidden",
            maxWidth: "100%",
            maxHeight: "calc(100% - 80px)",
            height: "calc(100% - 80px)",
          }}
        >
          <FilePreview
            src={imageExample.src}
            rects={imageExample.rects}
            pages={imageExample.pages}
            getContainerRef={viewContainerRef}
            activeContentId={activeContentId}
          />
        </div>
      </div>
      <div style={{ flex: 6, minWidth: "40%", maxWidth: "60%" }}>
        <RadioGroup
          style={{ margin: 16 }}
          optionStyle={{ flex: 1 }}
          type="line"
          options={[
            { label: "识别结果", value: "text" },
            { label: "JSON结果", value: "json" },
          ]}
          value={resultTab}
          onChange={setResultTab}
        />
        {resultTab === "text" && (
          <ResultView
            style={{
              position: "relative",
              overflow: "auto",
              maxWidth: "100%",
              maxHeight: "calc(100% - 80px)",
              height: "calc(100% - 80px)",
            }}
            // resultList={example2.result}
            resultList={imageExample.result}
            getContainerRef={resultContainerRef}
            activeContentId={activeContentId}
            activeParentContentId={activeParentContentId}
          />
        )}
        {resultTab === "json" && (
          <JsonView
            style={{
              padding: "0 16px",
              height: "calc(100% - 80px)",
              overflow: "auto",
            }}
            src={imageExample.json}
          />
        )}
      </div>
    </div>
  );
}
PDF 示例
复制代码
import { useLayoutEffect, useRef, useState } from "react";
import FilePreview from "../components/FilePreview";
import { RadioGroup } from "../components/RadioGroup";
import ResultView from "../components/ResultView";
import { pdfExample } from "./data";
import JsonView from "../components/JsonView";
import { useContentLinkage } from "../hooks/useContentLinkage";

export default functionPDFExample() {
  const [resultTab, setResultTab] = useState("text");
  const viewContainerRef = useRef<HTMLElement | null>(null);
  const resultContainerRef = useRef<HTMLElement | null>(null);

  const { activeParentContentId, activeContentId, registerLinkage } =
    useContentLinkage({
      viewContainerRef,
      resultContainerRef,
    });

  useLayoutEffect(() => {
    registerLinkage();
  }, []);

return (
    <div
      style={{
        display: "flex",
        width: "100%",
        height: "calc(100vh - 100px)",
        padding: 16,
        textAlign: "center",
        columnGap: 32,
      }}
    >
      <div style={{ flex: 4, minWidth: "40%", maxWidth: "60%" }}>
        <div style={{ margin: 16 }}>预览</div>
        <div
          style={{
            position: "relative",
            overflow: "hidden",
            maxWidth: "100%",
            maxHeight: "calc(100% - 80px)",
            height: "calc(100% - 80px)",
          }}
        >
          <FilePreview
            src={{
              url: pdfExample.src,
            }}
            rects={pdfExample.rects}
            pages={pdfExample.pages}
            getContainerRef={viewContainerRef}
            activeContentId={activeContentId}
          />
        </div>
      </div>
      <div style={{ flex: 6, minWidth: "40%", maxWidth: "60%" }}>
        <RadioGroup
          style={{ margin: 16 }}
          optionStyle={{ flex: 1 }}
          type="line"
          options={[
            { label: "识别结果", value: "text" },
            { label: "JSON结果", value: "json" },
          ]}
          value={resultTab}
          onChange={setResultTab}
        />
        {resultTab === "text" && (
          <ResultView
            style={{
              position: "relative",
              overflow: "auto",
              maxWidth: "100%",
              maxHeight: "calc(100% - 80px)",
              height: "calc(100% - 80px)",
            }}
            resultList={pdfExample.result}
            getContainerRef={resultContainerRef}
            activeContentId={activeContentId}
            activeParentContentId={activeParentContentId}
          />
        )}
        {resultTab === "json" && (
          <JsonView
            style={{
              padding: "0 16px",
              height: "calc(100% - 80px)",
              overflow: "auto",
            }}
            src={pdfExample.json}
          />
        )}
      </div>
    </div>
  );
}

二次开发

项目基于 vite 和 react 构建,您可将该项目 fork 到本地自主扩展:

拉取项目

复制代码
git clone https://github.com/intsig-textin/textin-ocr-frontend.git

安装依赖

复制代码
npm install

启动项目

复制代码
npm run dev

浏览器访问 http://localhost:5173/

在线预览前端界面:https://cc.co/16YSTY

以上为 TextIn OCR Frontend 开源组件库当前版本介绍。根据规划,组件库将持续迭代,实现:

  • 组件支持更多自定义配置、样式覆盖等特性

  • 支持可编辑、复制、导出结果

  • 支持更多复杂类型识别结果展示

在线体验https://cc.co/16YSTY

相关推荐
。。,……~12 分钟前
Opencv实用操作5 图像腐蚀膨胀
深度学习·神经网络·计算机视觉
江沉晚呤时13 分钟前
深入了解 C# 异步编程库 AsyncEx
java·前端·数据库·c#·.netcore
有很多梦想要实现15 分钟前
Nest全栈到失业(四):半小时图书管理系统-Book
开发语言·前端·javascript·数据库·typescript·webstorm
点云SLAM25 分钟前
PyTorch中 torch.utils.data.DataLoader 的详细解析和读取点云数据示例
人工智能·pytorch·python·算法·计算机视觉·dataloader·3d深度学习
百锦再42 分钟前
AI 眼镜新纪元:贴片式TF卡与 SOC 芯片的黄金组合破局智能穿戴
人工智能·内存·芯片·sd·moc·mk
疯狂的沙粒1 小时前
uniapp开发企业微信小程序时 wx.qy.login 在uniapp中使用的时候,需要导包吗?
前端·javascript·微信小程序·小程序·uni-app
丁值心1 小时前
5.29打卡
开发语言·人工智能·python·机器学习·支持向量机
Allen Bright1 小时前
【HTML-15】HTML表单:构建交互式网页的基石
前端·html
思绪漂移1 小时前
同源“平滑思想”的问题解法:正则化与拉普拉斯平滑
人工智能·算法
小张快跑。1 小时前
<el-date-picker>配置禁用指定日期之前的时间选择(Vue2+Vue3)
前端·javascript·vue.js