问题描述
项目中,需要将PDF文档转为图像,使用Imagick扩展组件进行转换。结果在转换时,因为PDF文档没有嵌入字体,导致一部份文字无法显示出来。如下图片,下划线部份,下划线上面是有文字的,但是转换后,模糊部份的文字正常显示,下划线上面的文字是空白的。
然后就是各种百度、问AI,无论使用何种方法,比如加入字体文档、修复PDF文档、安装第三方组件等等。
最终解决就是用python写一个api服务,因为服务器是centos的,系统python版本是python2,要使用yum所以再加个docker,最终解决问题。
下面是具体的步骤:
- 项目新建一个docker目录,用于存放api服务。
- 创建一个Dockerfile,内容如下:
# 使用CentOS 7作为基础镜像
FROM centos:7# 将当前目录下的Centos-7.repo复制到镜像内的/etc/yum.repos.d/目录下并覆盖原有的CentOS-Base.repo文件
COPY Centos-7.repo /etc/yum.repos.d/CentOS-Base.repo# 将当前目录下的AdobeSongStd-Light.otf复制到镜像目录/usr/share/fonts/目录下
COPY AdobeSongStd-Light.otf /usr/share/fonts/AdobeSongStd-Light.otf# 设置工作目录
WORKDIR /home/convert# 添加端口映射
EXPOSE 30581# 添加目录挂载 /www/wwwroot/dockerdemo.com/docker
# 这个目录放置的是转换PDF服务的源码文件
VOLUME ["/home/convert", "/www/wwwroot/dockerdemo.com/docker"]# 使用yum安装相关依赖包
RUN yum install -y openssl-devel bzip2-devel libffi-devel zlib-devel poppler-utils gcc gcc-c++ make# 下载Python 3.8.17的源码包并解压
RUN curl -O https://mirrors.huaweicloud.com/python/3.8.17/Python-3.8.17.tgz && \tar -zxvf Python-3.8.17.tgz && \cd Python-3.8.17 && \# 编译安装Python 3.8./configure --prefix=/usr/local/python3.8 && \make && \make install && \# 备注系统自带的python2.7mv /usr/bin/python /usr/bin/python.bak && \# 创建软链接将系统默认的python指向python3.8(此操作需谨慎,可能影响依赖Python 2的系统命令)ln -s /usr/local/python3.8/bin/python3.8 /usr/bin/python && \# 创建软链接将pip3.8映射到系统目录便于使用ln -s /usr/local/python3.8/bin/pip3.8 /usr/bin/pip# 使用pip安装指定版本的Pillow以及其他依赖库
RUN pip install Pillow==8.4 flask pdf2image PyPDF2 websockets redis# 设置容器启动时执行的命令为运行autorun.sh文件(需确保该文件存在于挂载的/home/convert目录下)
CMD ["./autorun.sh"]
- 创建autorun.sh文件,内容如下:
#!/bin/bash
# 切换到.py文件所在目录(假设.py文件在/app目录下,根据实际情况修改)
cd /home/convert
# 运行.py文件(假设文件名为main.py,根据实际情况修改)
python main.py
- 创建main.py文件,内容如下:
#!/usr/bin/env python3
from flask import Flask, request, jsonify, send_from_directory
import os
from pdf2image import convert_from_bytes
from PIL import Image
import uuid
from werkzeug.utils import secure_filenameapp = Flask(__name__)# 配置上传和输出目录
UPLOAD_FOLDER = 'upload'
OUTPUT_FOLDER = 'output'
ALLOWED_EXTENSIONS = {'pdf'}# 确保目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)def allowed_file(filename):return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONSdef process_pdf(pdf_bytes):try:# 转换PDF为图片,提高DPI到300images = convert_from_bytes(pdf_bytes,dpi=300,fmt='png',first_page=1,last_page=7 # 修改为7页以包含第7页)# 调整图片宽度为800,高度按比例缩放target_width = 800first_images = []total_height = 0for img in images:# 计算缩放比例ratio = target_width / img.widthnew_height = int(img.height * ratio)# 调整图片大小,使用 ANTIALIAS 替代 Resampling.LANCZOSresized_img = img.resize((target_width, new_height), Image.ANTIALIAS)first_images.append(resized_img)total_height += new_height# 创建新图片用于拼接result = Image.new('RGB', (target_width, total_height), 'white')# 拼接图片current_height = 0for img in first_images:result.paste(img, (0, current_height))current_height += img.height# 生成唯一文件名output_filename = f"{uuid.uuid4()}.png"output_path = os.path.join(OUTPUT_FOLDER, output_filename)# 保存结果result.save(output_path, 'PNG')# 返回文件的URLreturn (f"/download/{output_filename}",None)except Exception as e:return None, str(e)@app.route('/convert', methods=['POST'])
def convert_pdf():# 添加调试信息print("files:", request.files)print("form:", request.form)print("Content-Type:", request.headers.get('Content-Type'))if 'file' not in request.files:return jsonify({'code': -1,'message': '没有文件上传'}), 400file = request.files['file']if file.filename == '':return jsonify({'code': -1,'message': '没有选择文件'}), 400if not allowed_file(file.filename):return jsonify({'code': -1,'message': '不支持的文件格式'}), 400try:# 读取PDF文件内容pdf_bytes = file.read()# 处理PDFfile_url, error = process_pdf(pdf_bytes)if error:return jsonify({'code': -1,'message': error}), 400return jsonify({'code': 0,'message': 'SUCCESS','data': {'fileUrl': file_url}})except Exception as e:return jsonify({'code': -1,'message': str(e)}), 500@app.route('/download/<filename>')
def download_file(filename):return send_from_directory(OUTPUT_FOLDER, filename)if __name__ == '__main__':app.run(host='0.0.0.0', port=30581, debug=True)
- 构建镜像:
docker build -t convertPdf:latest .
- 运行容器:
docker run -d --name convertPdf -p 30581:30581 \-v /www/wwwroot/dockerdemo.com/docker:/home/convert \convertPdf
- 测试编写PHP上传文件代码,调用API接口:
<?php
$client = new Client(['verify' => false]);
$response = $client->request('POST', 'http://127.0.0.1:30581/convert', ['multipart' => [['name' => 'file','contents' => fopen('/path/to/file.pdf', 'r') // 上传文件路径]],'headers' => ['Accept' =>'application/json']
]);
$status_code = $response->getStatusCode();
$body = $response->getBody();
$data = json_decode($body, true);echo $data['data']['fileUrl']; // 图片URL
-
测试上传文件,查看结果。
-
注意:如果遇到问题,可以先尝试删除容器、镜像、挂载目录,然后重新构建、运行。