[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import filedialog
from docx import Document
from docx.shared import Inches, Cm
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.shared import OxmlElement, qn
import os
def get_folder_path():
folder_selected = filedialog.askdirectory()
folder_path.set(folder_selected)
selected_files.set("")
def get_output_file_path():
output_file_selected = filedialog.asksaveasfilename(
defaultextension=".docx",
filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")],
title="选择输出文件的位置和名称"
)
output_filename.set(output_file_selected)
def select_files():
files_selected = filedialog.askopenfilenames(
title="选择图片文件",
filetypes=[("图片文件", "*.jpg *.jpeg *.png *.JPG *.JPEG *.PNG"), ("所有文件", "*.*")]
)
if files_selected:
selected_files.set(";".join(files_selected))
folder_path.set("")
def set_cell_margins(cell, **kwargs):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcMar = OxmlElement('w:tcMar')
for marge, value in kwargs.items():
node = OxmlElement("w:{}".format(marge))
node.set(qn('w:w'), str(value))
node.set(qn('w:type'), 'dxa')
tcMar.append(node)
tcPr.append(tcMar)
def set_row_height(row, height_cm):
tr = row._tr
trPr = tr.get_or_add_trPr()
height_element = OxmlElement('w:trHeight')
height_element.set(qn('w:val'), str(int(height_cm * 567)))
height_element.set(qn('w:hRule'), 'exact')
trPr.append(height_element)
def replace_paragraph_marks(doc):
paragraphs_to_remove = []
for paragraph in doc.paragraphs:
if not paragraph.text.strip() and len(paragraph.runs) == 0:
paragraphs_to_remove.append(paragraph)
for paragraph in reversed(paragraphs_to_remove):
p = paragraph._element
p.getparent().remove(p)
def create_document():
img_folder = folder_path.get()
files_list = selected_files.get()
output_file = output_filename.get()
show_filename = show_filename_var.get()
include_extension = include_extension_var.get()
orientation = orientation_var.get()
images_per_page = images_per_page_var.get()
image_paths = []
if img_folder:
image_paths = [os.path.join(img_folder, f) for f in os.listdir(img_folder) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
elif files_list:
image_paths = files_list.split(";")
image_paths = [f for f in image_paths if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
else:
status_label.config(text='请先选择图片文件夹或选择图片文件。')
return
if not output_file:
status_label.config(text='请先选择输出文件的位置和名称。')
return
if not image_paths:
status_label.config(text='没有找到支持的图片格式。')
return
status_label.config(text='正在创建文档...')
window.update()
doc = Document()
if orientation == "横向":
section = doc.sections[0]
section.orientation = 1
new_width = section.page_height
new_height = section.page_width
section.page_width = new_width
section.page_height = new_height
vertical_rules = {
1: {"rows": 1, "cols": 1, "row_height": 22.0, "max_width": Cm(15.0)},
2: {"rows": 2, "cols": 1, "row_height": 11.0, "max_width": Cm(15.0)},
4: {"rows": 2, "cols": 2, "row_height": 11.0, "max_width": Cm(7.0)},
6: {"rows": 3, "cols": 2, "row_height": 7.3, "max_width": Cm(7.0)},
8: {"rows": 4, "cols": 2, "row_height": 5.3, "max_width": Cm(7.0)}
}
horizontal_rules = {
1: {"rows": 1, "cols": 1, "row_height": 16.0, "max_width": Cm(20.0)},
2: {"rows": 2, "cols": 1, "row_height": 8.0, "max_width": Cm(20.0)},
4: {"rows": 2, "cols": 2, "row_height": 8.0, "max_width": Cm(10.0)},
6: {"rows": 3, "cols": 2, "row_height": 5.3, "max_width": Cm(10.0)},
8: {"rows": 4, "cols": 2, "row_height": 4.0, "max_width": Cm(10.0)}
}
if orientation == "纵向":
rules = vertical_rules
else:
rules = horizontal_rules
if images_per_page not in rules:
status_label.config(text='无效的每页图片数量选择。')
return
current_rule = rules[images_per_page]
rows_per_page = current_rule["rows"]
cols_per_page = current_rule["cols"]
row_height = current_rule["row_height"]
max_width = current_rule["max_width"]
for page_start in range(0, len(image_paths), images_per_page):
table = doc.add_table(rows=rows_per_page, cols=cols_per_page)
table.alignment = WD_TABLE_ALIGNMENT.CENTER
for row in table.rows:
set_row_height(row, row_height)
for cell in row.cells:
cell.vertical_alignment = 1
set_cell_margins(cell, top=50, bottom=50, left=50, right=50)
page_images = image_paths[page_start:page_start + images_per_page]
for i, img_path in enumerate(page_images):
row_idx = i // cols_per_page
col_idx = i % cols_per_page
if row_idx < rows_per_page and col_idx < cols_per_page:
cell = table.cell(row_idx, col_idx)
for paragraph in cell.paragraphs:
paragraph.clear()
try:
img_para = cell.add_paragraph()
img_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
img_run = img_para.add_run()
img_para.paragraph_format.space_before = 0
img_para.paragraph_format.space_after = 0
img_para.paragraph_format.line_spacing = 1
pic = img_run.add_picture(img_path, width=max_width)
available_height = row_height - 1.5
if pic.height.cm > available_height:
scale_ratio = available_height / pic.height.cm
new_width = pic.width.cm * scale_ratio
pic.width = Cm(new_width)
pic.height = Cm(available_height)
if show_filename:
filename = os.path.basename(img_path)
if not include_extension:
filename = os.path.splitext(filename)[0]
filename_para = cell.add_paragraph()
filename_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
filename_run = filename_para.add_run(filename)
filename_run.font.name = 'Times New Roman'
filename_run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
from docx.shared import Pt
filename_run.font.size = Pt(10.5)
status_label.config(text=f'{os.path.basename(img_path)} 已插入到 word 文档中...')
window.update()
except Exception as e:
status_label.config(text=f'无法插入 {os.path.basename(img_path)},原因:{e}')
window.update()
if page_start + images_per_page < len(image_paths):
doc.add_page_break()
try:
replace_paragraph_marks(doc)
doc.save(output_file)
status_label.config(text=f'所有图片已全部插入,文档保存为 "{os.path.basename(output_file)}"。')
window.update()
open_document(output_file)
except Exception as e:
status_label.config(text=f'无法保存文档,原因:{e}')
def open_document(file_path):
try:
if os.path.isfile(file_path):
if os.name == 'nt':
os.startfile(file_path)
elif os.name == 'posix':
os.system(f'open "{file_path}"')
else:
status_label.config(text='不支持的操作系统,无法自动打开文档。')
except Exception as e:
status_label.config(text=f'无法打开文档,原因:{e}')
window = tk.Tk()
window.title('图片插入Word文档工具')
folder_path = tk.StringVar()
output_filename = tk.StringVar()
selected_files = tk.StringVar()
show_filename_var = tk.IntVar(value=1)
include_extension_var = tk.IntVar(value=1)
orientation_var = tk.StringVar(value="纵向")
images_per_page_var = tk.IntVar(value=6)
tk.Label(window, text='图片文件夹路径:').grid(row=0, column=0, sticky='w')
entry_folder_path = tk.Entry(window, textvariable=folder_path, width=40).grid(row=0, column=1)
browse_button_folder = tk.Button(window, text='浏览', command=get_folder_path).grid(row=0, column=2)
tk.Label(window, text='或选择图片文件:').grid(row=1, column=0, sticky='w')
select_files_button = tk.Button(window, text='选择文件', command=select_files).grid(row=1, column=1, sticky='w')
selected_files_label = tk.Label(window, textvariable=selected_files, fg='blue', wraplength=300).grid(row=2, column=1, sticky='w')
tk.Label(window, text='输出文件路径:').grid(row=3, column=0, sticky='w')
entry_output_filename = tk.Entry(window, textvariable=output_filename, width=40).grid(row=3, column=1)
browse_button_output = tk.Button(window, text='浏览', command=get_output_file_path).grid(row=3, column=2)
tk.Label(window, text='页面方向:').grid(row=4, column=0, sticky='w')
tk.Radiobutton(window, text='纵向', variable=orientation_var, value="纵向").grid(row=4, column=1, sticky='w')
tk.Radiobutton(window, text='横向', variable=orientation_var, value="横向").grid(row=4, column=2, sticky='w')
tk.Label(window, text='是否显示文件名:').grid(row=5, column=0, sticky='w')
tk.Radiobutton(window, text='显示文件名', variable=show_filename_var, value=1).grid(row=5, column=1, sticky='w')
tk.Radiobutton(window, text='不显示文件名', variable=show_filename_var, value=0).grid(row=5, column=2, sticky='w')
tk.Label(window, text='是否包含后缀:').grid(row=6, column=0, sticky='w')
tk.Radiobutton(window, text='包含后缀', variable=include_extension_var, value=1).grid(row=6, column=1, sticky='w')
tk.Radiobutton(window, text='不包含后缀', variable=include_extension_var, value=0).grid(row=6, column=2, sticky='w')
tk.Label(window, text='每页图片数量:').grid(row=7, column=0, sticky='w')
tk.Radiobutton(window, text='每页1张', variable=images_per_page_var, value=1).grid(row=7, column=1, sticky='w')
tk.Radiobutton(window, text='每页2张', variable=images_per_page_var, value=2).grid(row=8, column=1, sticky='w')
tk.Radiobutton(window, text='每页4张', variable=images_per_page_var, value=4).grid(row=7, column=2, sticky='w')
tk.Radiobutton(window, text='每页6张', variable=images_per_page_var, value=6).grid(row=8, column=2, sticky='w')
tk.Radiobutton(window, text='每页8张', variable=images_per_page_var, value=8).grid(row=9, column=1, sticky='w')
start_button = tk.Button(window, text='开始', command=create_document, width=20, height=2)
start_button.grid(row=10, column=1, pady=10)
status_label = tk.Label(window, text='', fg='blue')
status_label.grid(row=11, column=1)
window.mainloop()