PHP转换PDF时,因为PDF文档没有嵌入字体

news/2025/1/7 17:04:11/文章来源:https://www.cnblogs.com/quaki/p/18654836

问题描述

项目中,需要将PDF文档转为图像,使用Imagick扩展组件进行转换。结果在转换时,因为PDF文档没有嵌入字体,导致一部份文字无法显示出来。如下图片,下划线部份,下划线上面是有文字的,但是转换后,模糊部份的文字正常显示,下划线上面的文字是空白的。

然后就是各种百度、问AI,无论使用何种方法,比如加入字体文档、修复PDF文档、安装第三方组件等等。
最终解决就是用python写一个api服务,因为服务器是centos的,系统python版本是python2,要使用yum所以再加个docker,最终解决问题。

下面是具体的步骤:

  1. 项目新建一个docker目录,用于存放api服务。
  2. 创建一个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"]
  1. 创建autorun.sh文件,内容如下:
#!/bin/bash
# 切换到.py文件所在目录(假设.py文件在/app目录下,根据实际情况修改)
cd /home/convert
# 运行.py文件(假设文件名为main.py,根据实际情况修改)
python main.py
  1. 创建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) 
  1. 构建镜像:
docker build -t convertPdf:latest .
  1. 运行容器:
docker run -d --name convertPdf -p 30581:30581 \-v /www/wwwroot/dockerdemo.com/docker:/home/convert \convertPdf
  1. 测试编写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
  1. 测试上传文件,查看结果。

  2. 注意:如果遇到问题,可以先尝试删除容器、镜像、挂载目录,然后重新构建、运行。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#+ WPF 实现蓝牙转WIFI计步上位机

前言 一个WIFI上位机,接收底层MPU6050数据,途中转蓝牙从机透传,到蓝牙主机直连WIFI,PC端UDP通信,实现三轴加速度数据传送和计步功能。 项目介绍 本项目基于.NET平台,使用WPF开发了一个应用程序,用于实现MPU6050传感器数据从蓝牙模块传输到主机,并通过WiFi以UDP协议接收…

水位监测识别报警摄像机

智能水位监测识别报警摄像机是保障水域安全的重要利器。其高效准确的监测能力和及时有效的报警功能,将为城市水域管理和安全防范提供重要支持,有助于减少因水灾而造成的损失。摄像头通过实时捕捉水面画面,并将数据传输至中央处理器进行分析。一旦系统检测到水位异常,如水位…

SQL Server Profiler的trc文件生成阻止.240108

很奇葩,sqlserver自动生成trc文件,每分钟一个,重启服务器也没用。解决思路:查询现在正在跑的trace进程select * from sys.fn_trace_getinfo(0);关闭C2审计功能EXEC sp_configure c2 audit mode, 0;重启数据库服务 再次查看,已经没了。然后删除数据盘所有的trc文件。EXEC s…

cas5配置redis.240108

​POM文件加载redis依赖,重新maven clean package<dependency><groupId>org.apereo.cas</groupId><artifactId>cas-server-support-redis-ticket-registry</artifactId><version>${cas.version}</version></dependency><d…

dockerfile实现tomcat以及java的war包自动部署.240108

1. 下载jdk和tomcat wget https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.93/bin/apache-tomcat-8.5.93.tar.gz wget https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz 2. vim Dockerfile FROM centos:latest MAINTAINER Amadeus # now add…

Centos中keytool不起作用的解决方法.240109

​keytool是Java开发中用于管理密钥和证书的工具,可以用于生成密钥、创建证书请求、导入和导出证书等操作。你可以在Oracle官网上下载和安装JDK,然后在JDK的 bin目录下找到 keytool 工具。 因此,我们首先要给centos装jdk yum -y install java-1.8.0-openjdk* 然后在执行keyt…

【npm】npm warn ERESOLVE overriding peer dependency——版本冲突,降级

这里警告的远远是由于 @eslint 和 eslint-loader@2.2.1 之间版本冲突。eslint-loader支持的eslint版本在`>=1.6.0 <7.0.0`。可用输入 npm list eslint 查看当前依赖的具体问题。 所有,我们可以给wsint降级,选择1.6.0~7.0.0(不包含7.0.0)之间的版本。输入 npm view es…

群晖 MariaDB10 开启远程登录.240109

​情况:MariaDB设置了TCP/IP的端口,但是还是无法进行远程访问。解决方法: 一、使用ssh登录群晖,并进入MariaDB安装目录 cd /volume1/@appstore/MariaDB10/usr/local/mariadb10/bin 二、使用root登录 MariaDB,然后进行修改 mysql -u root -p MariaDB [(none)]> use mysq…

软件最难的不是开发程序,而是需求.240109

最近几个月,关于人工智能的惊人文章在互联网泛滥。这也引发了很多人的担心——软件开发人员可能很快就会失业,被人工智能取代。他们想象所有的企业高管和产品研究人员将绕过大多数或所有的软件开发人员,直接要求人工智能构建他们想要或需要的东西。但作为一个拥有15年一线开…

项目管理不再是难题:一揽子解决方案助你轻松前行

项目管理中的痛点涉及多个方面,但通过优化资源分配、建立有效的沟通机制、加强时间管理、完善风险控制、简化变更管理以及加强利益相关者期望管理等措施,可以有效地解决这些痛点,确保项目的顺利进行和成功完成。一、项目管理的核心要素 ● 范围管理:明确项目的范围和目标,…

如何修改网站的模板?

修改网站的模板是提升网站外观和用户体验的重要步骤。以下是详细的步骤和建议:备份原始模板:在进行任何修改之前,确保备份原始模板文件。 使用版本控制系统(如Git)来管理文件变更。选择合适的工具:根据网站的技术栈选择合适的工具。常见的工具包括文本编辑器(如Notepad+…

如何使用Dreamweaver修改网站模板?

Dreamweaver(DW)是一款功能强大的网页设计工具,可以帮助您轻松修改网站模板。以下是详细的步骤和建议:安装和启动Dreamweaver:确保已安装Dreamweaver软件。 启动Dreamweaver并打开您的网站项目。定位模板文件:在Dreamweaver的“文件”面板中,找到并打开需要修改的模板文…