欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > python语言写的一款pdf转word、word转pdf的免费工具

python语言写的一款pdf转word、word转pdf的免费工具

2025/3/14 22:46:52 来源:https://blog.csdn.net/2302_79560683/article/details/146230228  浏览:    关键词:python语言写的一款pdf转word、word转pdf的免费工具

Word 与 PDF 文件转换工具

这是一个简单的 Web 应用程序,允许用户将 Word 文档转换为 PDF 文件,或将 PDF 文件转换为 Word 文档。

功能特点

- Word (.docx) 转换为 PDF

- PDF 转换为 Word (.docx)

- 简单易用的 Web 界面

- 即时转换和下载

- 详细的错误处理和日志记录

安装要求

- Python 3.7 或更高版本

- 依赖库(见 requirements.txt)

- 对于 Word 到 PDF 的转换,建议安装 LibreOffice 或 OpenOffice(可选但推荐)

安装 LibreOffice(推荐)

为了确保 Word 到 PDF 的转换更加可靠,建议安装 LibreOffice:

- **Windows**: 从 [LibreOffice 官网](https://www.libreoffice.org/download/download/) 下载并安装

- **macOS**: 从 [LibreOffice 官网](https://www.libreoffice.org/download/download/) 下载并安装,或使用 Homebrew 安装:`brew install --cask libreoffice`

- **Linux**: 使用包管理器安装,例如 Ubuntu:`sudo apt-get install libreoffice`

3. 安装依赖:

```

pip install -r requirements.txt

```

4. 运行应用:

```

python app.py

```

5. 在浏览器中访问:

```

http://127.0.0.1:5000

```

## 使用说明

1. 在 Web 界面上选择转换类型(Word 转 PDF 或 PDF 转 Word)

2. 点击"选择文件"按钮并上传您的文件

3. 点击"开始转换"按钮

4. 转换完成后,文件将自动下载

效果演示

import os
import tempfile
import logging
import subprocess
import platform
import time
import shutil
from flask import Flask, render_template, request, redirect, url_for, flash, send_file, jsonify
from werkzeug.utils import secure_filename
from docx2pdf import convert as docx_to_pdf
from pdf2docx import Converter as pdf_to_docx
import check_libreoffice# 创建日志目录
log_dir = os.path.join(os.getcwd(), 'logs')
os.makedirs(log_dir, exist_ok=True)# 配置日志
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler(os.path.join(log_dir, 'app.log'), encoding='utf-8'),logging.StreamHandler()]
)
logger = logging.getLogger(__name__)# 检查是否安装了LibreOffice
libreoffice_installed, libreoffice_path = check_libreoffice.check_libreoffice()
if libreoffice_installed:logger.info(f"LibreOffice 已安装: {libreoffice_path}")
else:logger.warning("LibreOffice 未安装,Word 到 PDF 转换可能不可靠")app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['UPLOAD_FOLDER'] = os.path.join(os.getcwd(), 'uploads')
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max upload size# 确保上传目录存在
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
logger.info(f"上传目录: {app.config['UPLOAD_FOLDER']}")# 确保上传目录有正确的权限
try:os.chmod(app.config['UPLOAD_FOLDER'], 0o777)logger.info("已设置上传目录权限")
except Exception as e:logger.warning(f"无法设置上传目录权限: {str(e)}")ALLOWED_EXTENSIONS = {'docx', 'pdf'}def allowed_file(filename):return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS# 使用LibreOffice/OpenOffice转换Word到PDF
def convert_word_to_pdf_with_libreoffice(input_file, output_file):"""使用LibreOffice/OpenOffice转换Word到PDF"""system = platform.system()try:if system == 'Darwin':  # macOS# 检查是否安装了LibreOfficelibreoffice_paths = ['/Applications/LibreOffice.app/Contents/MacOS/soffice','/Applications/OpenOffice.app/Contents/MacOS/soffice']soffice_path = Nonefor path in libreoffice_paths:if os.path.exists(path):soffice_path = pathbreakif soffice_path is None:logger.error("在macOS上未找到LibreOffice或OpenOffice")return False# 添加字体嵌入和编码参数cmd = [soffice_path,'--headless','--convert-to', 'pdf:writer_pdf_Export:EmbedStandardFonts=true','--outdir', os.path.dirname(output_file),input_file]elif system == 'Windows':# Windows上的LibreOffice路径libreoffice_paths = [r'C:\Program Files\LibreOffice\program\soffice.exe',r'C:\Program Files (x86)\LibreOffice\program\soffice.exe',]soffice_path = Nonefor path in libreoffice_paths:if os.path.exists(path):soffice_path = pathbreakif soffice_path is None:logger.error("在Windows上未找到LibreOffice")return False# 添加字体嵌入和编码参数cmd = [soffice_path,'--headless','--convert-to', 'pdf:writer_pdf_Export:EmbedStandardFonts=true','--outdir', os.path.dirname(output_file),input_file]else:  # Linux# 添加字体嵌入和编码参数cmd = ['libreoffice','--headless','--convert-to', 'pdf:writer_pdf_Export:EmbedStandardFonts=true','--outdir', os.path.dirname(output_file),input_file]logger.info(f"执行命令: {' '.join(cmd)}")process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)stdout, stderr = process.communicate()if process.returncode != 0:logger.error(f"LibreOffice转换失败: {stderr.decode('utf-8', errors='ignore')}")return False# LibreOffice生成的PDF文件名可能与我们期望的不同# 它通常使用输入文件名,但扩展名改为.pdfinput_filename = os.path.basename(input_file)expected_output_filename = os.path.splitext(input_filename)[0] + '.pdf'expected_output_path = os.path.join(os.path.dirname(output_file), expected_output_filename)# 如果生成的文件名与期望的不同,重命名它if expected_output_path != output_file and os.path.exists(expected_output_path):os.rename(expected_output_path, output_file)return os.path.exists(output_file)except Exception as e:logger.exception(f"使用LibreOffice转换时出错: {str(e)}")return False# 使用pdf2docx转换PDF到Word,添加更好的字体处理
def convert_pdf_to_word(input_file, output_file):"""使用pdf2docx转换PDF到Word,添加更好的字体处理"""try:logger.info(f"开始转换PDF到Word: {input_file} -> {output_file}")# 使用pdf2docx库进行转换converter = pdf_to_docx(input_file)# 设置转换参数,提高字体处理能力converter.convert(output_file, start=0, end=None, pages=None, kwargs={'debug': False,'min_section_height': 20,'connected_border': False,'line_overlap_threshold': 0.9,'line_break_width_threshold': 2.0,'line_break_free_space_ratio': 0.3,'line_separate_threshold': 5.0,'new_paragraph_free_space_ratio': 0.85,'float_image_ignorable_gap': 5.0,'page_margin_factor': 0.1})converter.close()# 检查输出文件是否存在if not os.path.exists(output_file) or os.path.getsize(output_file) == 0:logger.error(f"转换后的文件不存在或为空: {output_file}")return Falselogger.info(f"PDF到Word转换成功: {output_file}, 大小: {os.path.getsize(output_file)} 字节")return Trueexcept Exception as e:logger.exception(f"PDF到Word转换失败: {str(e)}")return False@app.route('/')
def index():return render_template('index.html', libreoffice_installed=libreoffice_installed)@app.route('/convert', methods=['POST'])
def convert_file():# 检查是否有文件上传if 'file' not in request.files:flash('没有文件部分')logger.error('没有文件部分')return redirect(url_for('index'))file = request.files['file']# 如果用户没有选择文件,浏览器也会# 提交一个没有文件名的空部分if file.filename == '':flash('没有选择文件')logger.error('没有选择文件')return redirect(url_for('index'))if file and allowed_file(file.filename):# 安全地处理文件名original_filename = file.filenamefilename = secure_filename(original_filename)logger.info(f"原始文件名: {original_filename}, 安全文件名: {filename}")# 确保文件名不包含可能导致问题的字符filename = filename.replace('__', '_')# 创建完整的文件路径file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)logger.info(f"保存文件到: {file_path}")try:# 保存上传的文件file.save(file_path)# 检查文件是否成功保存if not os.path.exists(file_path):raise FileNotFoundError(f"文件保存失败: {file_path}")logger.info(f"文件成功保存: {file_path}, 大小: {os.path.getsize(file_path)} 字节")conversion_type = request.form.get('conversion_type')logger.info(f"转换类型: {conversion_type}")if conversion_type == 'word_to_pdf' and filename.lower().endswith('.docx'):# 转换 Word 到 PDFoutput_filename = filename.rsplit('.', 1)[0] + '.pdf'output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename)logger.info(f"开始转换 Word 到 PDF: {file_path} -> {output_path}")# 确保输出路径可写output_dir = os.path.dirname(output_path)if not os.access(output_dir, os.W_OK):logger.warning(f"输出目录不可写: {output_dir}")try:os.chmod(output_dir, 0o777)logger.info(f"已修改输出目录权限: {output_dir}")except Exception as e:logger.error(f"无法修改输出目录权限: {str(e)}")# 尝试使用多种方法转换conversion_success = False# 如果安装了LibreOffice,优先使用它if libreoffice_installed:logger.info("尝试使用LibreOffice转换...")conversion_success = convert_word_to_pdf_with_libreoffice(file_path, output_path)if conversion_success:logger.info("使用LibreOffice转换成功")# 如果LibreOffice转换失败或未安装,尝试使用docx2pdfif not conversion_success:try:logger.info("尝试使用docx2pdf转换...")docx_to_pdf(file_path, output_path)# 等待一段时间,确保文件已经写入time.sleep(2)if os.path.exists(output_path) and os.path.getsize(output_path) > 0:conversion_success = Truelogger.info("使用docx2pdf转换成功")except Exception as e:logger.warning(f"使用docx2pdf转换失败: {str(e)}")# 检查转换是否成功if not conversion_success or not os.path.exists(output_path) or os.path.getsize(output_path) == 0:# 尝试列出目录内容,看看文件是否在其他位置logger.info(f"列出目录 {output_dir} 的内容:")for f in os.listdir(output_dir):logger.info(f"  - {f} ({os.path.getsize(os.path.join(output_dir, f))} 字节)")if not libreoffice_installed:error_msg = "转换失败: 建议安装 LibreOffice 以获得更可靠的转换"flash(error_msg)logger.error(error_msg)else:error_msg = f"转换后的文件不存在或为空: {output_path}"flash(error_msg)logger.error(error_msg)return redirect(url_for('index'))logger.info(f"转换成功: {output_path}, 大小: {os.path.getsize(output_path)} 字节")# 使用临时文件复制一份,以防send_file后被删除with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as temp_file:temp_path = temp_file.namewith open(output_path, 'rb') as f:temp_file.write(f.read())logger.info(f"已创建临时文件: {temp_path}")# 设置响应头,确保浏览器知道这是一个下载response = send_file(temp_path,as_attachment=True,download_name=output_filename,mimetype='application/pdf')# 添加自定义头,防止缓存response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"response.headers["Pragma"] = "no-cache"response.headers["Expires"] = "0"response.headers["X-Conversion-Success"] = "true"return responseelif conversion_type == 'pdf_to_word' and filename.lower().endswith('.pdf'):# 转换 PDF 到 Wordoutput_filename = filename.rsplit('.', 1)[0] + '.docx'output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename)logger.info(f"开始转换 PDF 到 Word: {file_path} -> {output_path}")# 确保输出路径可写output_dir = os.path.dirname(output_path)if not os.access(output_dir, os.W_OK):logger.warning(f"输出目录不可写: {output_dir}")try:os.chmod(output_dir, 0o777)logger.info(f"已修改输出目录权限: {output_dir}")except Exception as e:logger.error(f"无法修改输出目录权限: {str(e)}")# 使用改进的PDF到Word转换函数conversion_success = convert_pdf_to_word(file_path, output_path)# 检查转换是否成功if not conversion_success or not os.path.exists(output_path) or os.path.getsize(output_path) == 0:# 尝试列出目录内容,看看文件是否在其他位置logger.info(f"列出目录 {output_dir} 的内容:")for f in os.listdir(output_dir):logger.info(f"  - {f} ({os.path.getsize(os.path.join(output_dir, f))} 字节)")error_msg = f"转换后的文件不存在或为空: {output_path}"flash(error_msg)logger.error(error_msg)return redirect(url_for('index'))logger.info(f"转换成功: {output_path}, 大小: {os.path.getsize(output_path)} 字节")# 使用临时文件复制一份,以防send_file后被删除with tempfile.NamedTemporaryFile(delete=False, suffix='.docx') as temp_file:temp_path = temp_file.namewith open(output_path, 'rb') as f:temp_file.write(f.read())logger.info(f"已创建临时文件: {temp_path}")# 设置响应头,确保浏览器知道这是一个下载response = send_file(temp_path,as_attachment=True,download_name=output_filename,mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document')# 添加自定义头,防止缓存response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"response.headers["Pragma"] = "no-cache"response.headers["Expires"] = "0"response.headers["X-Conversion-Success"] = "true"return responseelse:flash('无效的转换类型或文件格式')logger.error(f"无效的转换类型或文件格式: {conversion_type}, 文件名: {filename}")return redirect(url_for('index'))except Exception as e:error_msg = f'转换过程中出错: {str(e)}'flash(error_msg)logger.exception(error_msg)return redirect(url_for('index'))finally:# 清理上传的文件try:if os.path.exists(file_path):os.remove(file_path)logger.info(f"已删除上传的文件: {file_path}")# 清理输出文件(如果存在)output_filename = filename.rsplit('.', 1)[0]pdf_output = os.path.join(app.config['UPLOAD_FOLDER'], output_filename + '.pdf')docx_output = os.path.join(app.config['UPLOAD_FOLDER'], output_filename + '.docx')if os.path.exists(pdf_output):os.remove(pdf_output)logger.info(f"已删除输出文件: {pdf_output}")if os.path.exists(docx_output):os.remove(docx_output)logger.info(f"已删除输出文件: {docx_output}")except Exception as e:logger.error(f"清理文件时出错: {str(e)}")flash('无效的文件类型。请上传 DOCX 或 PDF 文件。')logger.error(f"无效的文件类型: {file.filename if file else 'None'}")return redirect(url_for('index'))# 添加一个路由来检查转换状态
@app.route('/check_conversion_status')
def check_conversion_status():return jsonify({"status": "success"})if __name__ == '__main__':# 在启动应用程序之前检查LibreOfficecheck_libreoffice.main()app.run(debug=True) 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词