<Project-7 ipdf2tx> Python flask应用 在浏览器中提交 PDF图片 转换 文本PDF,同时保留图像 多进程 OCR 详细的安装准备环境

原因

上一个项目,性能太差。如果把翻译的算力交给插件,比如:Chrome/Edge extension: Immersive Translate , 只需要图转文字就行

目标

采用多线程来提升性能,支持多种语言的图片PDF文件去转换成文字。

安装与配置

环境准备

  • 安装 python:3.12.3-slim
  • 安装必要的库和工具:
    • Flask(Web 框架)
    • pytesseract(OCR 库)
    • pdf2image(将 PDF 页面转换为图像)
    • reportlab(生成 PDF)
    • PyPDF2(处理 PDF)
    • tesseract-ocr(需要系统安装)
    • ocrmypdf (对 PDF 文件进行 OCR)

先在Windows 11上实现,再实现Linux Docker,以下是在Windows 11上的操作。

因为涉及多个安装包,要从不同地方下载,在代码执行时总缺少工具,这一文章用流水方式记录这段过程,

pytesseract(OCR 库)

项目:https://github.com/UB-Mannheim/tesseract/wiki  
Windows 11有安装包下载(我写这篇时的最新版本):https://github.com/UB-Mannheim/tesseract/releases/download/v5.4.0.20240606/tesseract-ocr-w64-setup-5.4.0.20240606.exe

如果想得到更准确识别,还有训练过的语言包下载:GitHub - tesseract-ocr/tessdata: Trained models with fast variant of the "best" LSTM models + legacy models

我下载了简体中文包:chi_sim.traineddata,这个比安装文件自带的大多了41MB,我又下载了english 包。

下载后,文件放到:C:\Program Files\Tesseract-OCR\tessdata   
                               (如果你安装它在上面目录)

Linux可以用sudo来安装,如:

sudo apt-get update
sudo apt-get install tesseract-ocr
sudo apt-get install tesseract-ocr-chi-sim
添加路径

        

pngquant

在执行时有报错:”ocrmypdf.exceptions.MissingDependencyError: Could not find program 'pngquant' on the PATH
“,发现 ocrmypdf 库,会调用 pngquant (pngquant is a command-line utility and a library for lossy compression of PNG images. pngquant — lossy PNG compressor

网上找到,还要摸索...   pngquant 是一个用于压缩 PNG 图像的工具,ocrmypdf 在执行优化步骤时需要使用它。 下载bin文件,并放到有PATH覆盖的地方。我就把它放到,上面提及的安装文件的目录:C:\Program Files\Tesseract-OCR\

Ghostscript

在执行时有报错:ocrmypdf.exceptions.MissingDependencyError: Could not find program 'gswin64c' on the PATH

我也不知道它是什么,以下是查到的内容:

gswin64c 是什么?gswin64c 是 Ghostscript 的一个命令行版本的可执行文件。Ghostscript 是一个解释器,用于 PostScript 和 PDF 文件。它广泛用于 PDF 文件的查看、转换和打印等操作。

官网:GhostscriptGhostscript is the #1 PDL conversion and interpreter tool available, offering native rendering of PDF, PostScript, PCL, XPS, raster and vector files, as well as ASCII text.icon-default.png?t=O83Ahttps://www.ghostscript.com/

下载安装包:Ghostscript : ReleasesThe latest Ghostscript releases.icon-default.png?t=O83Ahttps://www.ghostscript.com/releases/index.html

非商用这个:Postscript and PDF interpreter/renderer: GNU license for win64

Ghostscripticon-default.png?t=O83Ahttps://www.ghostscript.com/releases/gsdnld.html

当前下载安装文件:

https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10040/gs10040w64.exe

验证命令
Microsoft Windows [Version 10.0.22631.4249]
(c) Microsoft Corporation. All rights reserved.

C:\Users\dave>gswin64c --version
10.04.0

C:\Users\dave>
gs.bat

这个很重要!!! 因为gswin64c.exe 替代了9.0的gs.exe需要手动制作一个执行文件

编辑gs.bat在 gswin64c.exe的目录(我的pc上默认安装在:”C:\Program Files\gs\gs10.04.0\bin“),并加入以下两行:

@echo off
"C:\Program Files\gs\gs10.04.0\bin\gswin64c.exe" %*

这样ocrmypdf在Windows上寻找的是gs命令,而实际上Ghostscript的可执行文件是gswin64c.exe,通过一个批处理实现映射。

将来要放Docker里,Dockerfile也要同时更新依赖

# 基础镜像
FROM python:3.12.3-slim

# 安装必要的系统依赖
RUN apt-get update && apt-get install -y \
    tesseract-ocr \
    tesseract-ocr-chi-sim \
    ghostscript \
    pngquant \
    libglib2.0-0 \
    libsm6 \
    libxrender1 \
    libxext6 \
    poppler-utils \
    && rm -rf /var/lib/apt/lists/*

小结:

对于Pngquant与Ghostscript 另一个解决办法是:禁用 ocrmypdf 的优化功能,只是文件大点。

目录结构

ipdf2tx/
│
├── app.py             # Flask 应用程序主文件
├── ocr_util.py        # OCR 功能模块
├── requirements.txt   # Python 依赖列表
├── Dockerfile         # Docker 配置文件
├── templates/
│   └── upload.html    # 上传页面模板
├── uploads/           # 上传的 PDF 文件(自动创建)
└── outputs/           # 输出的 PDF 文件(自动创建)
  • app.py:主 Flask 应用程序,负责处理 HTTP 请求、管理任务和与前端交互。
  • ocr_util.py:负责 PDF 文件的 OCR 转换,包括分页、文本识别和 PDF 合并。
  • templates/upload.html:前端上传界面,提供文件上传和语言选择功能。
  • uploads/:用于存储用户上传的 PDF 文件。
  • outputs/:用于存储转换后的可搜索 PDF 文件。

功能说明

ipdf2tx 用Python开发的跨平台Web应用程序,将基于图像的PDF文件(如扫描书籍)转换为带有可搜索文本层的PDF,同时保留原始图像,通过OCR功能实现。

主要功能

  • PDF上传:用户可通过简洁友好的网页界面上传图像PDF文件。
  • 多语言OCR支持:支持英语、简体中文、繁体中文、日文
  • 多语言同时选择:用户可以在一次转换中选择多种语言,适用于包含多语言内容的PDF文件。
  • 高效多进程处理:利用多核CPU的优势,加快大文件或多文件的转换速度。
  • OCR转换:利用OCR技术,为每一页PDF添加文本层,实现文字的搜索和复制。
  • 实时进度显示:转换过程中,前端界面动态显示转换进度,提升用户体验。
  • PDF预览:转换完成后,用户可直接在浏览器中打开并阅读生成的可搜索PDF。
  • 多平台支持:兼容Windows和Linux操作系统,满足不同用户的需求。
  • Docker化部署:提供Docker容器化方案,简化部署流程,确保环境一致性。
  • 端口:9005

技术使用

  • Python 3.12.3 + Flask
  • ocrmypdf:用于在PDF中添加OCR文本层的工具。
  • PyPDF2:用于读取和操作PDF文件的Python库。
  • 多进程处理:利用Python的multiprocessing模块,实现多页并行处理,大副提升转换速度。
  • Docker:提供容器化部署方案,确保跨平台一致性和简化部署流程。
  • 依赖工具
    • Tesseract OCR:开源OCR引擎,负责文本识别。
    • Ghostscript:用于处理PDF文件的解释器。
    • pngquant:用于PNG图像优化,减小PDF文件大小。 (测试PDF 2.63MB,转换后 0.97MB)

安装与配置

Windows 部署

        参考上面的环境准备

Docker化部署

Dockerfile

# 使用官方的Python 3.12轻量级镜像作为基础镜像
FROM python:3.12.3-slim

# 设置环境变量,避免生成.pyc文件,并确保输出实时刷新
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    tesseract-ocr \
    tesseract-ocr-chi-sim \
    ghostscript \
    pngquant \
    poppler-utils \
    && rm -rf /var/lib/apt/lists/*

# 设置工作目录为/app
WORKDIR /app

# 复制并安装Python依赖
COPY requirements.txt /app/
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用程序代码到容器中
COPY . /app/

# 创建必要的目录
RUN mkdir -p uploads outputs

# 暴露应用程序运行的端口
EXPOSE 9005

# 设置环境变量以指定Flask运行的主机和端口
ENV FLASK_RUN_HOST=0.0.0.0
ENV FLASK_RUN_PORT=9005

# 启动应用程序
CMD ["python", "app.py"]

requirements.txt

Flask
ocrmypdf
PyPDF2

创建与运行Docker镜像

创建Docker镜像
#在项目文件目录下:
docker build -t ipdf2tx .
运行Docker容器
docker run -d -p 9005:9005 --name ipdf2tx_container ipdf2tx
#如Docker所在主机支持多线程
docker run -d -p 9005:9005 --name ipdf2tx_container --cpus="4" ipdf2tx
打开浏览器,访问:
http://Docker-Container-IP:9005

完整代码

主程序 app.py

# app.py

from flask import Flask, request, send_file, render_template, Response, jsonify
import os
import uuid
from threading import Thread
from werkzeug.utils import secure_filename
from ocr_util import ocr_pdf
from collections import defaultdict

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'

# 确保上传文件夹存在
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# 确保输出文件夹存在
os.makedirs('outputs', exist_ok=True)

# 存储进度的全局变量
progress = defaultdict(int)  # 使用defaultdict初始化为0

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files.get('file')
        # 获取用户选择的语言,默认为英语
        selected_langs = request.form.getlist('language')  # 使用getlist以获取多选
        if not selected_langs:
            selected_langs = ['eng']  # 默认语言
        lang = '+'.join(selected_langs)  # 例如 'eng+chi_sim'

        if file and file.filename.lower().endswith('.pdf'):
            filename = secure_filename(file.filename)
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filepath)

            # 使用 UUID 生成唯一的任务 ID
            task_id = str(uuid.uuid4())
            progress[task_id] = 0  # 初始化进度为 0

            # 定义进度回调函数
            def progress_callback(p):
                progress[task_id] = p

            # 开始转换
            def convert():
                ocr_pdf(filepath, task_id, progress_callback, lang=lang)

            # 启动一个新线程来进行转换
            t = Thread(target=convert)
            t.start()

            return jsonify({'task_id': task_id}), 202  # 返回任务 ID
        else:
            return "请上传 PDF 文件。", 400
    return render_template('upload.html')

@app.route('/progress/<task_id>')
def progress_stream(task_id):
    def generate():
        while True:
            status = progress.get(task_id, 0)
            yield f"data: {status}\n\n"
            if status >= 100 or status == -1:
                break
    return Response(generate(), mimetype='text/event-stream')

@app.route('/view/<task_id>')
def view_pdf(task_id):
    merged_pdf_path = os.path.join('outputs', f'{task_id}.pdf')
    if os.path.exists(merged_pdf_path):
        return send_file(merged_pdf_path)
    else:
        return "转换后的PDF不存在。", 404

if __name__ == '__main__':
#    app.run(debug=True, port=9005)   如果不指定host, 默认是127.0.0.1这是个loop 0,不能与外面通信 modified at 1231am on 7oct.2024
app.run(host='0.0.0.0',debug=True, port=9005)

必要库

  • os:与操作系统有关的,文件路径之类
  • uuid:生成唯一的任务 ID。
  • Thread:创建新线程,异步处理 OCR 任务。
  • secure_filename:确保上传文件名的安全性
  • ocr_pdf:从 ocr_util.py 导入的函数,负责 PDF 的 OCR 转换。
  • defaultdict:用于存储任务进度,默认值为 0,进度条使用。

代码解释:

文件上传路由 (/)
  • GET 请求
    • 渲染上传页面 upload.html,展示文件上传表单。
  • POST 请求
    • 文件获取:通过 request.files.get('file') 获取上传的文件。
    • 语言获取:使用 request.form.getlist('language') 获取用户选择的所有语言复选框的值,返回一个列表。如果未选择任何语言,则默认使用英语 (['eng'])。
    • 语言参数格式:将选中的语言列表用 + 连接,如 eng+chi_sim,符合 ocrmypdf 的多语言参数格式。
    • 文件验证:检查上传的文件是否存在且为 PDF 格式。
    • 文件保存:使用 secure_filename 确保文件名安全,然后保存到 uploads/ 目录。
    • 任务 ID 生成:使用 uuid.uuid4() 生成唯一的 task_id,并初始化进度为 0。
    • 进度回调函数:定义一个回调函数 progress_callback(p),用于更新当前任务的进度。
    • 转换任务启动:定义一个函数 convert(),调用 ocr_pdf 进行 OCR 转换,并在新线程中启动该函数,避免阻塞主线程。
    • 返回响应:通过 jsonify 返回任务 ID,并设置 HTTP 状态码为 202 Accepted,表示请求已被接受并正在处理中。
    • 错误处理:如果上传的文件不符合要求,返回 400 Bad Request 错误。
进度查询路由 (/progress/<task_id>)
  • 定义一个生成器函数 generate(),不断检查当前任务的进度,并通过 yield 将进度值发送给前端。
  • 当进度达到 100% 或转换失败(进度为 -1)时,停止推送。
查看转换后 PDF 路由 (/view/<task_id>)
  • 根据 task_id 查找并返回转换后的 PDF 文件。
  • 如果对应的 PDF 文件存在,则通过 send_file 发送给客户端。
  • 如果文件不存在,返回4 04 错误.
  • 当前端接收到转换进度达到 100% ,用户点击“打开转换后的 PDF”按钮,前端会通过 /view/<task_id> 找到文件。

OCR 调ocr_util.py

负责 PDF 文件的 OCR 转换,包括分页、文本识别和 PDF 合并

# ocr_util.py

import os
import io
import PyPDF2
import ocrmypdf
from concurrent.futures import ProcessPoolExecutor, as_completed
from threading import Lock
import logging
import shutil

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 创建一个全局锁,用于同步进度更新
progress_lock = Lock()

def process_page(args):
    """
    处理单页PDF,进行OCR转换。
    Args:
        args: Tuple containing (page_num, pdf_bytes, output_dir, lang)
    Returns:
        Tuple (page_num, success, error_message)
    """
    page_num, pdf_bytes, output_dir, lang = args
    try:
        logging.info(f"开始处理第 {page_num + 1} 页")
        page_input = os.path.join(output_dir, f'page_{page_num}.pdf')
        page_output = os.path.join(output_dir, f'page_{page_num}_ocr.pdf')

        # 提取单页 PDF
        pdf_reader = PyPDF2.PdfReader(io.BytesIO(pdf_bytes))
        pdf_writer = PyPDF2.PdfWriter()
        pdf_writer.add_page(pdf_reader.pages[0])
        with open(page_input, 'wb') as f_out:
            pdf_writer.write(f_out)

        # 对单页 PDF 进行 OCR 处理
        ocrmypdf.ocr(
            page_input,
            page_output,
            lang=lang,  # 使用指定语言包
            deskew=True,
            force_ocr=True,
            optimize=0,
            progress_bar=False
        )
        logging.info(f"完成处理第 {page_num + 1} 页")
        return (page_num, True, None)
    except Exception as e:
        logging.error(f"处理第 {page_num + 1} 页时出错: {e}")
        return (page_num, False, str(e))

def ocr_pdf(filepath, task_id, progress_callback, lang='eng'):
    """
    OCR处理PDF文件,添加进度回调。
    Args:
        filepath: Path to the input PDF
        task_id: Unique task ID
        progress_callback: Function to call with progress updates
        lang: Language code(s) for OCR (e.g., 'eng', 'chi_sim', 'jpn')
    """
    output_dir = os.path.join('outputs', task_id)
    os.makedirs(output_dir, exist_ok=True)

    try:
        logging.info(f"开始处理任务 {task_id}")
        # 读取PDF文件
        with open(filepath, 'rb') as f:
            pdf_reader = PyPDF2.PdfReader(f)
            total_pages = len(pdf_reader.pages)
            logging.info(f"总页数: {total_pages}")

            # 准备所有页面的任务
            tasks = []
            for page_num in range(total_pages):
                pdf_writer = PyPDF2.PdfWriter()
                pdf_writer.add_page(pdf_reader.pages[page_num])
                pdf_bytes_io = io.BytesIO()
                pdf_writer.write(pdf_bytes_io)
                pdf_bytes = pdf_bytes_io.getvalue()
                tasks.append((page_num, pdf_bytes, output_dir, lang))

        # 使用ProcessPoolExecutor进行多进程处理
        with ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
            future_to_page = {executor.submit(process_page, task): task[0] for task in tasks}

            processed_pages = 0
            for future in as_completed(future_to_page):
                page_num = future_to_page[future]
                try:
                    _, success, error = future.result()
                    if success:
                        with progress_lock:
                            processed_pages += 1
                            progress = int((processed_pages / total_pages) * 100)
                            progress_callback(progress)
                        logging.info(f"页面 {page_num + 1} 处理成功,当前进度: {progress}%")
                    else:
                        with progress_lock:
                            progress_callback(-1)
                        logging.error(f"页面 {page_num + 1} 处理失败,错误: {error}")
                except Exception as exc:
                    with progress_lock:
                        progress_callback(-1)
                    logging.error(f"页面 {page_num + 1} 处理时发生异常: {exc}")

        # 检查是否所有页面都成功处理
        if processed_pages != total_pages:
            raise Exception("部分页面处理失败,请检查日志。")

        # 合并所有处理后的单页 PDF
        logging.info(f"开始合并PDF文件为 {task_id}.pdf")
        merged_pdf_path = os.path.join('outputs', f'{task_id}.pdf')
        pdf_merger = PyPDF2.PdfWriter()
        for page_num in range(total_pages):
            page_output = os.path.join(output_dir, f'page_{page_num}_ocr.pdf')
            with open(page_output, 'rb') as f_in:
                page_reader = PyPDF2.PdfReader(f_in)
                pdf_merger.add_page(page_reader.pages[0])
        with open(merged_pdf_path, 'wb') as f_out:
            pdf_merger.write(f_out)
        logging.info(f"成功合并PDF文件为 {merged_pdf_path}")
        progress_callback(100)

    except Exception as e:
        # 更新进度为-1表示失败
        progress_callback(-1)
        logging.error(f"任务 {task_id} 处理出错: {e}")
    finally:
        # 清理临时文件
        logging.info(f"清理临时文件夹 {output_dir}")
        shutil.rmtree(output_dir, ignore_errors=True)
        logging.info(f"任务 {task_id} 完成")

必要库

  • PyPDF2:用于读取和写入 PDF 文件。

  • ocrmypdf:集成 Tesseract OCR 和 Ghostscript,实现 PDF 的 OCR 转换。

  • ProcessPoolExecutoras_completed:用于多进程并行处理。

  • Lock:线程锁,确保进度更新的线程安全。

代码解释

日志使用“全局锁”,在多进程环境下避免竞争

处理单页 PDF 的函数 (process_page)
提取单页 PDF
  • 使用 PyPDF2.PdfReader 读取页面内容。
  • 使用 PyPDF2.PdfWriter 创建一个新的 PDF,仅包含当前页面。
  • 将单页内容写入 page_input 文件。
OCR 处理

使用 ocrmypdf.ocr 对单页 PDF 进行 OCR 转换。

返回结果,包含:页编号、是否成功等

OCR 转换主函数 (ocr_pdf)

参数
  • filepath:PDF 文件路径。
  • task_id:唯一的任务 ID,用于标识和跟踪。
  • progress_callback:回调函数,用于更新任务进度。
  • lang:OCR 识别的语言代码,支持多语言(如 eng, chi_sim, jpn)。
    C:\Program Files\Tesseract-OCR\tessdata 用来存放“语言训练数据文件“, 可以在github上找到训练丰富的数据文件。 上面在pytenseract有提到。因为pdf可能含有多种语言文字,程序与支持多选,所在 lang = '+'.join(selected_langs) 可以多选语言。
  • 使用 ProcessPoolExecutor 并行处理每一页的 OCR 转换,利用CPU 多核提升效率。
    我的NAS CPU:Intel(R) Celeron(R) J4125 CPU @ 2.00GHz 4物理核,没有超线程技术,即:4个物理核 = 4个逻辑cores 
    “ProcessPoolExecutor(max_workers=os.cpu_count())” 代码里没有限定CPU core数量,默认为全部。如果想保留2个,定义变量 reserved_cores=2, 让一个变量存系统的cpu个数:cpu_count = os.cpu_count(), 再让 max_worker=cpu_count-reserved_cores 。如果保留超出实际CPU数量,要有判断代码。
  • 使用 PyPDF2.PdfWriter 将所有经过 OCR 转换的单页 PDF 文件合并为一个完整的可搜索 PDF 文件。

上传页面 upload.html

<!-- templates/upload.html -->

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>ipdf2tx - 上传 PDF 文件</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 40px;
        }
        #progress, #result, #error {
            margin-top: 20px;
        }
        #progressValue {
            font-weight: bold;
        }
        #viewButton {
            padding: 10px 20px;
            font-size: 16px;
        }
        .error {
            color: red;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <h1>ipdf2tx - 上传 PDF 文件</h1>
    <form method="post" enctype="multipart/form-data" id="uploadForm">
        <label for="fileInput">选择 PDF 文件:</label>
        <input type="file" name="file" accept=".pdf" id="fileInput" required>
        <br><br>
        <label for="languageSelect">选择语言:</label>
        <br>
        <input type="checkbox" name="language" value="eng" id="lang_eng" checked>
        <label for="lang_eng">英语 (English)</label><br>
        <input type="checkbox" name="language" value="chi_sim" id="lang_chi_sim">
        <label for="lang_chi_sim">简体中文 (Simplified Chinese)</label><br>
        <input type="checkbox" name="language" value="chi_tra" id="lang_chi_tra">
        <label for="lang_chi_tra">繁体中文 (Traditional Chinese)</label><br>
        <input type="checkbox" name="language" value="jpn" id="lang_jpn">
        <label for="lang_jpn">日语 (Japanese)</label><br>
        <!-- 如果需要支持更多语言,可以继续添加复选框 -->
        <br>
        <input type="submit" value="上传并转换">
    </form>

    <div id="progress" style="display:none;">
        <p>转换进度:<span id="progressValue">0%</span></p>
    </div>

    <div id="result" style="display:none;">
        <button id="viewButton">打开转换后的 PDF</button>
    </div>

    <div id="error" class="error" style="display:none;">
        转换失败,请重试。
    </div>

    <script>
        const form = document.getElementById('uploadForm');
        const progressDiv = document.getElementById('progress');
        const progressValue = document.getElementById('progressValue');
        const resultDiv = document.getElementById('result');
        const viewButton = document.getElementById('viewButton');
        const errorDiv = document.getElementById('error');

        form.addEventListener('submit', function(e) {
            e.preventDefault();
            const fileInput = document.getElementById('fileInput');
            const file = fileInput.files[0];
            const languageCheckboxes = document.querySelectorAll('input[name="language"]:checked');
            const selectedLangs = Array.from(languageCheckboxes).map(cb => cb.value);
            let selectedLang = 'eng'; // 默认语言

            if (selectedLangs.length > 0) {
                selectedLang = selectedLangs.join('+');  // 例如 'eng+chi_sim'
            }

            if (!file) {
                alert('请选择一个 PDF 文件。');
                return;
            }

            const formData = new FormData();
            formData.append('file', file);
            formData.append('language', selectedLang);  // 添加语言参数

            // 发送上传请求
            fetch('/', {
                method: 'POST',
                body: formData
            })
            .then(response => {
                if (response.status === 202) {
                    return response.json();
                } else {
                    throw new Error('上传失败');
                }
            })
            .then(data => {
                const taskId = data.task_id;

                // 显示进度条
                progressDiv.style.display = 'block';
                errorDiv.style.display = 'none';
                resultDiv.style.display = 'none';
                progressValue.innerText = '0%';

                // 开始监听进度
                const progressSource = new EventSource(`/progress/${taskId}`);
                progressSource.onmessage = function(event) {
                    const status = event.data;
                    if (status === '-1') {
                        progressValue.innerText = '转换失败,请重试。';
                        progressSource.close();
                        progressDiv.style.display = 'none';
                        errorDiv.style.display = 'block';
                    } else {
                        progressValue.innerText = `${status}%`;
                        if (status >= 100) {
                            progressSource.close();
                            resultDiv.style.display = 'block';
                        }
                    }
                };

                // 设置查看按钮的链接
                viewButton.onclick = function() {
                    window.open(`/view/${taskId}`, '_blank');
                };
            })
            .catch(error => {
                console.error('发生错误:', error);
                alert('上传或转换过程中发生错误,请重试。');
            });
        });
    </script>
</body>
</html>
  • 使用多个 <input type="checkbox"> 元素,允许用户选择多种语言进行 OCR 处理。
  • 默认选中英语 (checked)。
  • 上传文件只接受pdf  accept=".pdf

运行实例

1. 浏览器:  http://127.0.0.1:9005

2. 选择pdf

3.点击"上传按钮"

因为上面还有一个VM在占用系统,乎略8cores是满的。 这里只是显示是多任务。

4.任务结束,可以点击"打开转换后的 PDF" 查看

5. 结果与对比

上图为转换后,文字是可以选择的。

下图是转换前,每页是图片形式

由于使用多进程,对系统的内存与cpu要求多一些。

当pdf内容是以文字排版,就可以用浏览器插件直接翻译。 或修改<Project-6>来实现同样功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值