吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]
查看: 2352|回复: 33
上一主题 下一主题
收起左侧

[Python 原创] 图片插入word(支持wps)

  [复制链接]
跳转到指定楼层
楼主
deepxia 发表于 2025-8-13 20:49 回帖奖励
本帖最后由 deepxia 于 2025-8-14 11:13 编辑

帮一个监理弄的,他们插入图片挺多的.看见我在Python弄压力容器排版图生成插件,叫我帮着弄个这个,就按照他的需求弄了一个这个,目前使用没啥问题.
成品下载地址:https://wwej.lanzouu.com/iuP4m33ia6de密码:52pj

[Asm] 纯文本查看 复制代码
import sys
import os
import win32com.client as win32
import pythoncom
import threading
import time
import shutil
import tempfile
import logging
import traceback
import re  # 新增:导入正则表达式模块
from PIL import Image
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QLabel, QLineEdit, QPushButton, QListWidget, QProgressBar,
    QGroupBox, QGridLayout, QHBoxLayout, QCheckBox, QFileDialog, QMessageBox,
    QColorDialog, QFontDialog, QFrame
)
from PySide6.QtCore import Qt, QThread, Signal
from PySide6.QtGui import QPixmap, QDragEnterEvent, QDropEvent, QFont, QColor, QPalette

# 确保 win32com 能找到类型库
if getattr(sys, 'frozen', False):
    # 打包后模式 - 使用更安全的访问方式
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(sys.executable)))

    gen_py_path = os.path.join(base_path, "gen_py")
    if not os.path.exists(gen_py_path):
        os.makedirs(gen_py_path)
    os.environ["GENPY_PATH"] = gen_py_path

# 添加全局线程锁
com_lock = threading.Lock()


class WorkerThread(QThread):
    progress_updated = Signal(int, str)
    task_completed = Signal()
    error_occurred = Signal(str)
    compress_completed = Signal(list)

    def __init__(self, target, args=None):
        super().__init__()
        self.target = target
        self.args = args if args else []

    def run(self):
        try:
            self.target(*self.args)
            self.task_completed.emit()
        except (OSError, IOError, pythoncom.com_error) as e:
            self.error_occurred.emit(str(e))
            logging.error(f"Worker thread error: {str(e)}\n{traceback.format_exc()}")
        except Exception as e:
            self.error_occurred.emit(f"Unexpected error: {str(e)}")
            logging.error(f"Unexpected worker thread error: {str(e)}\n{traceback.format_exc()}")


class WordImageInserter(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Word表格图片插入工具")
        self.resize(600, 300)  # 增加高度以适应新控件

        # 设置中文字体支持
        self.font_family = "Microsoft YaHei"
        self.small_font = QFont(self.font_family, 9)
        self.normal_font = QFont(self.font_family, 10)
        self.title_font = QFont(self.font_family, 10, QFont.Weight.Bold)

        # 创建主部件
        main_widget = QWidget()
        self.setCentralWidget(main_widget)

        # 主布局
        main_layout = QHBoxLayout(main_widget)
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(15)

        # 左侧:图片插入设置
        left_frame = QGroupBox("图片插入设置")
        left_frame.setFont(self.title_font)
        left_frame.setStyleSheet("""
            QGroupBox {
                background-color: #ffffff;
                border: 1px solid #cccccc;
                border-radius: 5px;
                margin-top: 1.5ex;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                subcontrol-position: top center;
                padding: 0 5px;
                color: #2c3e50;
            }
        """)
        left_layout = QGridLayout(left_frame)
        left_layout.setSpacing(10)

        # 图片宽度(插入时)
        width_label = QLabel("宽度(厘米):")
        width_label.setFont(self.small_font)
        self.insert_width = QLineEdit("8.0")
        self.insert_width.setFont(self.small_font)
        self.insert_width.setFixedWidth(100)
        left_layout.addWidget(width_label, 0, 0)
        left_layout.addWidget(self.insert_width, 0, 1)

        # 图片高度(插入时)
        height_label = QLabel("高度(厘米):")
        height_label.setFont(self.small_font)
        self.insert_height = QLineEdit("6.0")
        self.insert_height.setFont(self.small_font)
        self.insert_height.setFixedWidth(100)
        left_layout.addWidget(height_label, 1, 0)
        left_layout.addWidget(self.insert_height, 1, 1)

        # 行间距
        spacing_label = QLabel("行间距:")
        spacing_label.setFont(self.small_font)
        self.line_spacing = QLineEdit("8")
        self.line_spacing.setFont(self.small_font)
        self.line_spacing.setFixedWidth(100)
        left_layout.addWidget(spacing_label, 3, 0)
        left_layout.addWidget(self.line_spacing, 3, 1)

        # 每行显示图片数(固定为2列)
        per_row_label = QLabel("每行数量:")
        per_row_label.setFont(self.small_font)
        self.images_per_row = QLineEdit("2")
        self.images_per_row.setFont(self.small_font)
        self.images_per_row.setFixedWidth(100)
        self.images_per_row.setReadOnly(True)
        left_layout.addWidget(per_row_label, 4, 0)
        left_layout.addWidget(self.images_per_row, 4, 1)

        # 字体设置区域
        font_frame = QFrame()
        font_frame.setFrameShape(QFrame.Shape.NoFrame)
        font_layout = QHBoxLayout(font_frame)
        font_layout.setContentsMargins(0, 0, 0, 0)
        font_layout.setSpacing(5)

        # 字体选择按钮
        self.font_btn = QPushButton("选择字体")
        self.font_btn.setFont(self.small_font)
        self.font_btn.setStyleSheet("padding: 5px;")
        self.font_btn.clicked.connect(self.select_font)
        font_layout.addWidget(self.font_btn)

        # 字体颜色选择按钮
        self.color_btn = QPushButton("选择颜色")
        self.color_btn.setFont(self.small_font)
        self.color_btn.setStyleSheet("padding: 5px;")
        self.color_btn.clicked.connect(self.select_color)
        font_layout.addWidget(self.color_btn)

        # 当前字体预览
        self.font_preview = QLabel("字体预览")
        self.font_preview.setStyleSheet("border: 1px solid #cccccc; padding: 3px;")
        font_layout.addWidget(self.font_preview)

        left_layout.addWidget(font_frame, 5, 0, 1, 2)

        # 功能按钮区
        btn_frame = QWidget()
        btn_layout = QHBoxLayout(btn_frame)
        btn_layout.setContentsMargins(0, 0, 0, 0)
        btn_layout.setSpacing(5)

        # 图片选择按钮
        self.select_btn = QPushButton("选择图片")
        self.select_btn.setFont(self.small_font)
        self.select_btn.setStyleSheet("background-color: #28a745; color: white; padding: 5px;")
        self.select_btn.clicked.connect(self.select_images)
        btn_layout.addWidget(self.select_btn)

        # 插入按钮
        self.insert_btn = QPushButton("插入到Word")
        self.insert_btn.setFont(self.small_font)
        self.insert_btn.setStyleSheet("background-color: #007bff; color: white; padding: 5px;")
        self.insert_btn.clicked.connect(self.start_insert_thread)
        self.insert_btn.setEnabled(False)
        btn_layout.addWidget(self.insert_btn)

        left_layout.addWidget(btn_frame, 6, 0, 1, 2)

        # 图片压缩功能区
        compress_frame = QWidget()
        compress_layout = QHBoxLayout(compress_frame)
        compress_layout.setContentsMargins(0, 0, 0, 0)
        compress_layout.setSpacing(5)

        compress_label = QLabel("压缩至(K):")
        compress_label.setFont(self.small_font)
        self.compression_quality = QLineEdit("200")
        self.compression_quality.setFont(self.small_font)
        compress_layout.addWidget(compress_label)
        compress_layout.addWidget(self.compression_quality)

        self.compress_btn = QPushButton("图片压缩")
        self.compress_btn.setFont(self.small_font)
        self.compress_btn.setStyleSheet("background-color: #17a2b8; color: white; padding: 5px;")
        self.compress_btn.clicked.connect(self.start_compress_thread)
        self.compress_btn.setEnabled(False)
        compress_layout.addWidget(self.compress_btn)

        left_layout.addWidget(compress_frame, 7, 0, 1, 2)

        # 批量改名功能区
        rename_frame = QWidget()
        rename_layout = QHBoxLayout(rename_frame)
        rename_layout.setContentsMargins(0, 0, 0, 0)
        rename_layout.setSpacing(5)

        rename_label = QLabel("头文件名:")
        rename_label.setFont(self.small_font)
        self.rename_prefix = QLineEdit("图片")
        self.rename_prefix.setFont(self.small_font)
        rename_layout.addWidget(rename_label)
        rename_layout.addWidget(self.rename_prefix)

        self.rename_btn = QPushButton("批量改名")
        self.rename_btn.setFont(self.small_font)
        self.rename_btn.setStyleSheet("background-color: #6610f2; color: white; padding: 5px;")
        self.rename_btn.clicked.connect(self.batch_rename_images)
        self.rename_btn.setEnabled(False)
        rename_layout.addWidget(self.rename_btn)

        left_layout.addWidget(rename_frame, 8, 0, 1, 2)

        # 图片列表标题
        list_label = QLabel("已选图片列表 (支持拖放图片到此处)")
        list_label.setFont(self.small_font)
        left_layout.addWidget(list_label, 9, 0, 1, 2)

        # 图片列表框
        self.image_list = QListWidget()
        self.image_list.setFont(QFont("Consolas", 9))
        self.image_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection)
        self.image_list.itemSelectionChanged.connect(self.update_preview)
        self.image_list.setAcceptDrops(True)
        self.image_list.setStyleSheet("""
            QListWidget {
                border: 1px solid #cccccc;
                background-color: white;
            }
        """)
        left_layout.addWidget(self.image_list, 10, 0, 1, 2)

        # 进度条
        self.progress = QProgressBar()
        self.progress.setRange(0, 100)
        left_layout.addWidget(self.progress, 11, 0, 1, 2)

        # 状态标签
        self.status_label = QLabel("就绪")
        self.status_label.setFont(QFont(self.font_family, 8))
        self.status_label.setStyleSheet("color: #666666;")
        left_layout.addWidget(self.status_label, 12, 0, 1, 2)

        # 设置左侧布局权重
        left_layout.setRowStretch(10, 1)

        # 右侧:批量调整区域
        right_frame = QGroupBox("批量调整图片")
        right_frame.setFont(self.title_font)
        right_frame.setStyleSheet("""
            QGroupBox {
                background-color: #ffffff;
                border: 1px solid #cccccc;
                border-radius: 5px;
                margin-top: 1.5ex;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                subcontrol-position: top center;
                padding: 0 5px;
                color: #2c3e50;
            }
        """)
        right_layout = QGridLayout(right_frame)
        right_layout.setSpacing(10)

        # 调整宽度
        resize_width_label = QLabel("新宽度(cm):")
        resize_width_label.setFont(self.small_font)
        self.resize_width = QLineEdit("8.0")
        self.resize_width.setFont(self.small_font)
        self.resize_width.setFixedWidth(100)
        right_layout.addWidget(resize_width_label, 0, 0)
        right_layout.addWidget(self.resize_width, 0, 1)

        # 调整高度
        resize_height_label = QLabel("新高度(cm):")
        resize_height_label.setFont(self.small_font)
        self.resize_height = QLineEdit("6.0")
        self.resize_height.setFont(self.small_font)
        self.resize_height.setFixedWidth(100)
        right_layout.addWidget(resize_height_label, 1, 0)
        right_layout.addWidget(self.resize_height, 1, 1)

        # 保持纵横比
        self.lock_aspect = QCheckBox("保持纵横比")
        self.lock_aspect.setFont(self.small_font)
        self.lock_aspect.setChecked(True)
        right_layout.addWidget(self.lock_aspect, 2, 0, 1, 2)

        # 应用按钮
        self.resize_btn = QPushButton("应用到所有图片")
        self.resize_btn.setFont(self.small_font)
        self.resize_btn.setStyleSheet("background-color: #ff9800; color: white; padding: 5px;")
        self.resize_btn.clicked.connect(self.start_resize_thread)
        right_layout.addWidget(self.resize_btn, 3, 0, 1, 2)

        # 一键清除所有图片按钮
        self.clear_btn = QPushButton("清除文档中所有图片")
        self.clear_btn.setFont(self.small_font)
        self.clear_btn.setStyleSheet("background-color: #dc3545; color: white; padding: 5px;")
        self.clear_btn.clicked.connect(self.start_clear_thread)
        right_layout.addWidget(self.clear_btn, 4, 0, 1, 2)

        # 复制设置按钮
        copy_btn = QPushButton("从插入设置复制尺寸")
        copy_btn.setFont(QFont(self.font_family, 8))
        copy_btn.setStyleSheet("background-color: #f5f5f5; color: #555555; padding: 3px; border: 1px solid #cccccc;")
        copy_btn.clicked.connect(self.copy_insert_settings)
        right_layout.addWidget(copy_btn, 5, 0, 1, 2)

        # 图片预览区域
        preview_label = QLabel("图片预览")
        preview_label.setFont(QFont(self.font_family, 9, QFont.Weight.Bold))
        right_layout.addWidget(preview_label, 6, 0, 1, 2)

        # 图片预览 - 增大预览区域
        self.preview_label = QLabel()
        self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.preview_label.setStyleSheet("""
            QLabel {
                background-color: #f0f0f0;
                border: 1px solid #cccccc;
            }
        """)
        self.preview_label.setMinimumSize(200, 200)  # 增大预览区域
        self.preview_label.setText("请选择图片预览")
        self.preview_label.setFont(QFont("Arial", 10))
        self.preview_label.setStyleSheet("color: #999999;")
        right_layout.addWidget(self.preview_label, 7, 0, 1, 2)

        # 图片信息标签
        self.info_label = QLabel()
        self.info_label.setFont(QFont("Arial", 8))
        self.info_label.setStyleSheet("color: #666666;")
        self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        right_layout.addWidget(self.info_label, 8, 0, 1, 2)

        # 图片列表操作按钮
        list_btn_frame = QFrame()
        list_btn_layout = QHBoxLayout(list_btn_frame)
        list_btn_layout.setContentsMargins(0, 0, 0, 0)
        list_btn_layout.setSpacing(5)

        # 删除选中图片按钮
        self.delete_btn = QPushButton("删除选中图片")
        self.delete_btn.setFont(self.small_font)
        self.delete_btn.setStyleSheet("background-color: #dc3545; color: white; padding: 5px;")
        self.delete_btn.clicked.connect(self.delete_selected_images)
        self.delete_btn.setEnabled(False)
        list_btn_layout.addWidget(self.delete_btn)

        # 清空图片列表按钮
        self.clear_list_btn = QPushButton("清空图片列表")
        self.clear_list_btn.setFont(self.small_font)
        self.clear_list_btn.setStyleSheet("background-color: #6c757d; color: white; padding: 5px;")
        self.clear_list_btn.clicked.connect(self.clear_all_list_images)
        self.clear_list_btn.setEnabled(False)
        list_btn_layout.addWidget(self.clear_list_btn)

        right_layout.addWidget(list_btn_frame, 9, 0, 1, 2)

        # 设置右侧布局权重
        right_layout.setRowStretch(7, 1)

        # 添加左右框架到主布局
        main_layout.addWidget(left_frame, 1)
        main_layout.addWidget(right_frame, 1)

        # 存储图片路径
        self.image_paths = []
        # 存储压缩后的图片路径
        self.compressed_paths = []

        # 字体设置
        self.font_name = "宋体"  # 使用界面默认字体
        self.font_size = 9  # 使用正常字体大小
        self.font_color = QColor(0, 0, 0)  # 默认黑色

        # 设置日志记录
        logging.basicConfig(filename='word_image_inserter.log', level=logging.DEBUG,
                            format='%(asctime)s - %(levelname)s - %(message)s')

        # 启用拖放功能
        self.setAcceptDrops(True)
        self.image_list.setAcceptDrops(True)

        # 在创建完所有控件后调用 update_font_preview
        self.update_font_preview()

        # 初始化 worker_thread 属性
        self.worker_thread = None

    def select_font(self):
        """选择字体和大小"""
        # 创建初始字体对象
        initial_font = QFont(self.font_name, self.font_size)

        # 打开字体对话框
        dialog = QFontDialog(initial_font, self)
        dialog.setWindowTitle("选择字体")

        if dialog.exec() == QFontDialog.DialogCode.Accepted:
            selected_font = dialog.selectedFont()
            if selected_font:
                # 更新字体属性
                self.font_name = selected_font.family()
                self.font_size = selected_font.pointSize()

                # 更新预览
                self.update_font_preview()

    def select_color(self):
        """选择字体颜色"""
        color = QColorDialog.getColor()
        if color.isValid():
            self.font_color = color
            # 更新预览
            self.update_font_preview()

    def update_font_preview(self):
        """更新字体预览显示"""
        # 设置预览文本
        preview_text = f"{self.font_name} {self.font_size}pt"
        self.font_preview.setText(preview_text)

        # 使用选择的字体和大小设置预览标签
        preview_font = QFont(self.font_name, self.font_size)
        self.font_preview.setFont(preview_font)

        # 设置文本颜色
        palette = self.font_preview.palette()
        palette.setColor(QPalette.ColorRole.WindowText, self.font_color)
        self.font_preview.setPalette(palette)

        # 强制重绘确保更新
        self.font_preview.update()

    def select_images(self):
        """选择图片文件 - 追加模式"""
        file_dialog = QFileDialog()
        file_dialog.setNameFilter("图片文件 (*.jpg *.jpeg *.png *.bmp *.gif)")
        file_dialog.setFileMode(QFileDialog.FileMode.ExistingFiles)

        if file_dialog.exec():
            selected_files = file_dialog.selectedFiles()
            if selected_files:
                # 追加图片而不是覆盖
                self.image_paths.extend(selected_files)
                for path in selected_files:
                    self.image_list.addItem(os.path.basename(path))

                # 启用相关按钮
                self.insert_btn.setEnabled(True)
                self.compress_btn.setEnabled(True)
                self.rename_btn.setEnabled(True)
                self.delete_btn.setEnabled(True)
                self.clear_list_btn.setEnabled(True)

                self.status_label.setText(f"已添加 {len(selected_files)} 张图片,共 {len(self.image_paths)} 张")

                # 更新预览
                self.update_preview()

    def dragEnterEvent(self, event: QDragEnterEvent):
        """处理拖入事件"""
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        """处理拖放事件 - 追加图片而不是覆盖"""
        urls = event.mimeData().urls()
        if not urls:
            return

        new_paths = []
        for url in urls:
            path = url.toLocalFile()
            if os.path.isfile(path) and self.is_image_file(path):
                new_paths.append(path)

        if new_paths:
            # 追加图片而不是覆盖
            self.image_paths.extend(new_paths)
            for path in new_paths:
                self.image_list.addItem(os.path.basename(path))

            # 启用相关按钮
            self.insert_btn.setEnabled(True)
            self.compress_btn.setEnabled(True)
            self.rename_btn.setEnabled(True)
            self.delete_btn.setEnabled(True)
            self.clear_list_btn.setEnabled(True)

            self.status_label.setText(f"已添加 {len(new_paths)} 张图片,共 {len(self.image_paths)} 张")

            # 更新预览
            self.update_preview()

    @staticmethod
    def is_image_file(path):
        """检查文件是否为支持的图片格式(静态方法)"""
        image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']
        return os.path.splitext(path)[1].lower() in image_extensions

    def delete_selected_images(self):
        """删除选中的图片"""
        selected_items = self.image_list.selectedItems()
        if not selected_items:
            return

        confirm = QMessageBox.question(
            self,
            "确认删除",
            f"确定要删除选中的 {len(selected_items)} 张图片吗?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )

        if confirm != QMessageBox.StandardButton.Yes:
            return

        # 获取选中的索引(从后往前删除,避免索引变化)
        selected_indices = [self.image_list.row(item) for item in selected_items]
        selected_indices.sort(reverse=True)

        for index in selected_indices:
            self.image_list.takeItem(index)
            self.image_paths.pop(index)

        # 更新状态
        self.status_label.setText(f"已删除 {len(selected_indices)} 张图片")

        # 如果没有图片了,禁用相关按钮
        if not self.image_paths:
            self.insert_btn.setEnabled(False)
            self.compress_btn.setEnabled(False)
            self.rename_btn.setEnabled(False)
            self.delete_btn.setEnabled(False)
            self.clear_list_btn.setEnabled(False)
            self.preview_label.setText("无图片预览")
            self.preview_label.setStyleSheet("color: #999999;")
            self.info_label.setText("")
        else:
            # 更新预览
            self.update_preview()

    def clear_all_list_images(self):
        """清空图片列表中的所有图片"""
        if not self.image_paths:
            return

        confirm = QMessageBox.question(
            self,
            "确认清空",
            "确定要清空所有图片吗?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )

        if confirm != QMessageBox.StandardButton.Yes:
            return

        self.image_list.clear()
        self.image_paths = []
        self.compressed_paths = []

        # 禁用相关按钮
        self.insert_btn.setEnabled(False)
        self.compress_btn.setEnabled(False)
        self.rename_btn.setEnabled(False)
        self.delete_btn.setEnabled(False)
        self.clear_list_btn.setEnabled(False)

        self.preview_label.setText("无图片预览")
        self.preview_label.setStyleSheet("color: #999999;")
        self.info_label.setText("")
        self.status_label.setText("已清空所有图片")

    def update_preview(self):
        """更新图片预览 - 增大预览区域"""
        selected_items = self.image_list.selectedItems()
        if not selected_items:
            self.delete_btn.setEnabled(False)
            self.preview_label.setText("请选择图片预览")
            self.preview_label.setStyleSheet("color: #999999;")
            self.info_label.setText("")
            return

        # 启用删除按钮
        self.delete_btn.setEnabled(True)

        # 只显示第一张选中的图片
        index = self.image_list.row(selected_items[0])
        img_path = self.image_paths[index]

        try:
            # 使用Pillow获取图片信息
            with Image.open(img_path) as img:
                img_width, img_height = img.size
            file_size = os.path.getsize(img_path) // 1024  # KB

            # 创建QPixmap对象
            pixmap = QPixmap(img_path)
            if pixmap.isNull():
                raise IOError("无法加载图片")

            # 调整图片大小以适应预览区域
            max_size = 450
            if pixmap.width() > max_size or pixmap.height() > max_size:
                pixmap = pixmap.scaled(max_size, max_size,
                                       Qt.AspectRatioMode.KeepAspectRatio,
                                       Qt.TransformationMode.SmoothTransformation)

            # 显示图片
            self.preview_label.setPixmap(pixmap)
            self.preview_label.setStyleSheet("")

            # 显示图片信息
            self.info_label.setText(
                f"文件名: {os.path.basename(img_path)}\n"
                f"尺寸: {img_width}×{img_height}像素 | 大小: {file_size}KB"
            )

        except (IOError, OSError) as e:
            self.preview_label.setText("无法预览图片")
            self.preview_label.setStyleSheet("color: #cc0000;")
            self.info_label.setText(f"错误: {str(e)}")
            logging.error(f"预览图片时出错: {str(e)}")
        except Exception as e:
            self.preview_label.setText("无法预览图片")
            self.preview_label.setStyleSheet("color: #cc0000;")
            self.info_label.setText("未知错误")
            logging.error(f"预览图片时发生未知错误: {str(e)}")

    def copy_insert_settings(self):
        """将插入图片的尺寸设置复制到批量调整区域"""
        self.resize_width.setText(self.insert_width.text())
        self.resize_height.setText(self.insert_height.text())
        self.status_label.setText("已复制插入图片的尺寸设置")

    def start_compress_thread(self):
        """启动图片压缩线程"""
        # 验证输入
        try:
            target_size_kb = int(self.compression_quality.text())
            if target_size_kb <= 0 or target_size_kb > 10240:  # 限制在1-10240KB之间
                QMessageBox.warning(self, "输入无效", "请输入1-10240之间的数值")
                return
        except ValueError:
            QMessageBox.warning(self, "输入无效", "请输入有效的数值")
            return

        # 启动线程
        self.set_buttons_enabled(False)
        self.status_label.setText("正在压缩图片...")
        self.progress.setValue(0)

        self.worker_thread = WorkerThread(self.compress_images, (target_size_kb,))
        self.worker_thread.progress_updated.connect(self.update_compress_progress)
        self.worker_thread.task_completed.connect(self.compress_completed)
        self.worker_thread.error_occurred.connect(self.handle_error)
        self.worker_thread.start()

    def compress_images(self, target_size_kb):
        """执行图片压缩操作"""
        try:
            total_images = len(self.image_paths)
            target_size = target_size_kb * 1024  # 转换为字节
            self.compressed_paths = []

            # 创建压缩图片保存目录
            compress_dir = os.path.join(os.path.dirname(self.image_paths[0]), "压缩图片")
            os.makedirs(compress_dir, exist_ok=True)

            for i, img_path in enumerate(self.image_paths):
                try:
                    # 打开图片
                    with Image.open(img_path) as img:
                        # 获取原图片格式
                        img_format = img.format if img.format else "JPEG"
                        if img_format.upper() == "PNG" and img.mode in ('RGBA', 'LA'):
                            # 处理透明背景
                            background = Image.new(img.mode[:-1], img.size, (255, 255, 255))
                            background.paste(img, img.split()[-1])
                            img = background

                        # 生成保存路径
                        filename = os.path.basename(img_path)
                        name, ext = os.path.splitext(filename)
                        save_path = os.path.join(compress_dir, f"{name}_compressed{ext}")

                        # 初始质量
                        quality = 95
                        step = 5

                        # 循环调整质量直到达到目标大小
                        while quality > 0:
                            # 保存临时图片
                            with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as temp_file:
                                img.save(temp_file, format=img_format, quality=quality, optimize=True)
                                temp_path = temp_file.name

                            # 检查文件大小
                            file_size = os.path.getsize(temp_path)

                            if file_size <= target_size or quality <= 5:
                                # 达到目标大小或质量已很低,保存最终版本
                                shutil.copy2(temp_path, save_path)
                                os.unlink(temp_path)  # 删除临时文件
                                self.compressed_paths.append(save_path)
                                break

                            # 未达到目标,降低质量
                            quality -= step
                            os.unlink(temp_path)  # 删除临时文件

                        # 更新进度
                        progress = (i + 1) / total_images * 100
                        self.worker_thread.progress_updated.emit(progress, f"正在压缩第{i + 1}/{total_images}张图片")

                        time.sleep(0.1)  # 短暂延迟

                except (IOError, OSError) as e:
                    error_msg = f"压缩图片 {os.path.basename(img_path)} 时出错: {str(e)}"
                    self.worker_thread.error_occurred.emit(error_msg)
                    logging.error(f"压缩第{i + 1}张图片时出错: {error_msg}\n{traceback.format_exc()}")
                    # 添加原图路径作为备选
                    self.compressed_paths.append(img_path)
                except Exception as e:
                    error_msg = f"压缩图片 {os.path.basename(img_path)} 时发生未知错误: {str(e)}"
                    self.worker_thread.error_occurred.emit(error_msg)
                    logging.error(f"压缩第{i + 1}张图片时发生未知错误: {error_msg}\n{traceback.format_exc()}")
                    self.compressed_paths.append(img_path)

            # 完成压缩
            self.compressed_paths = self.compressed_paths  # 确保列表完整

        except (OSError, IOError) as e:
            error_msg = f"图片压缩时出错: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)
        except Exception as e:
            error_msg = f"图片压缩时发生未知错误: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)

    def update_compress_progress(self, progress, message):
        """更新压缩进度"""
        self.progress.setValue(int(progress))
        self.status_label.setText(message)

    def compress_completed(self):
        """压缩完成处理"""
        # 更新列表
        self.image_list.clear()
        for path in self.compressed_paths:
            self.image_list.addItem(os.path.basename(path))

        # 更新图片路径为压缩后的路径
        self.image_paths = self.compressed_paths.copy()

        # 完成提示
        self.progress.setValue(100)
        self.status_label.setText(f"已完成!共压缩了 {len(self.compressed_paths)} 张图片")
        QMessageBox.information(
            self,
            "完成",
            f"成功压缩了图片,保存路径:\n{os.path.dirname(self.compressed_paths[0])}"
        )

        # 重新启用按钮
        self.set_buttons_enabled(True)

    def batch_rename_images(self):
        """批量重命名选中的图片 - 增加了头文件名规则检查"""
        if not self.image_paths:
            return

        prefix = self.rename_prefix.text().strip()
        if not prefix:
            QMessageBox.warning(self, "输入无效", "请输入头文件名")
            return
        """"
        # 新增:头文件名规则检查,只允许字母、数字和下划线
        if not re.fullmatch(r'^[a-zA-Z0-9_]+$', prefix):
            QMessageBox.warning(
                self,
                "输入无效",
                "头文件名只能包含字母、数字和下划线(如:Image_2023)"
            )
            return
        """
        # 确认操作
        confirm = QMessageBox.question(
            self,
            "确认重命名",
            f"确定要将选中的{len(self.image_paths)}张图片重命名为\n'{prefix}-1', '{prefix}-2'...吗?\n此操作会直接修改原文件!",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )

        if confirm != QMessageBox.StandardButton.Yes:
            return

        try:
            # 按原顺序重命名
            for i, img_path in enumerate(self.image_paths):
                # 获取文件目录和扩展名
                dir_path = os.path.dirname(img_path)
                ext = os.path.splitext(img_path)[1]

                # 生成新文件名
                new_name = f"{prefix}-{i + 1}{ext}"
                new_path = os.path.join(dir_path, new_name)

                # 检查文件是否存在
                counter = 1
                while os.path.exists(new_path):
                    new_name = f"{prefix}-{i + 1}_{counter}{ext}"
                    new_path = os.path.join(dir_path, new_name)
                    counter += 1

                # 重命名文件
                os.rename(img_path, new_path)

                # 更新路径列表
                self.image_paths[i] = new_path

                # 更新列表显示
                self.image_list.item(i).setText(new_name)

                # 更新状态
                self.status_label.setText(f"正在重命名第{i + 1}/{len(self.image_paths)}张图片")
                time.sleep(0.1)

            self.status_label.setText(f"已完成!共重命名了 {len(self.image_paths)} 张图片")
            QMessageBox.information(self, "完成", f"成功重命名了 {len(self.image_paths)} 张图片")

        except (OSError, IOError) as e:
            error_msg = f"重命名图片时出错: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.status_label.setText(f"错误: {error_msg}")
            QMessageBox.critical(self, "错误", error_msg)
        except Exception as e:
            error_msg = f"重命名图片时发生未知错误: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.status_label.setText(f"错误: {error_msg}")
            QMessageBox.critical(self, "错误", error_msg)

    def start_insert_thread(self):
        """启动新线程执行插入操作"""
        # 获取参数(固定为2列)
        try:
            params = {
                "width": max(1.0, float(self.insert_width.text())),
                "height": max(1.0, float(self.insert_height.text())),
                "line_spacing": max(0.5, float(self.line_spacing.text())),
                "images_per_row": 2,  # 固定为2列
                "font_name": self.font_name,
                "font_size": self.font_size,
                "font_color": self.font_color
            }
        except ValueError:
            QMessageBox.warning(self, "输入无效", "请输入有效的数值")
            return

        # 启动线程
        self.set_buttons_enabled(False)
        self.status_label.setText("正在准备插入图片...")
        self.progress.setValue(0)

        self.worker_thread = WorkerThread(self.insert_to_existing_table, (params,))
        self.worker_thread.progress_updated.connect(self.update_insert_progress)
        self.worker_thread.task_completed.connect(self.insert_completed)
        self.worker_thread.error_occurred.connect(self.handle_error)
        self.worker_thread.start()

    def insert_to_existing_table(self, params):
        """在现有Word表格中插入图片,按照单个单元格陆续插入"""
        try:
            # 初始化COM
            with com_lock:
                pythoncom.CoInitialize()

            # 连接到Word应用程序
            self.worker_thread.progress_updated.emit(0, "正在连接到Word...")
            try:
                word_app = win32.gencache.EnsureDispatch("Word.Application")
                word_app.Visible = True
            except (pythoncom.com_error, AttributeError) as e:
                error_message = "无法启动Word应用程序。请确保已安装Microsoft Word。"
                raise Exception(error_message) from e

            # 获取活动文档
            try:
                if word_app.Documents.Count == 0:
                    error_message = "没有打开的Word文档。请先打开或创建一个文档。"
                    raise Exception(error_message)

                doc = word_app.ActiveDocument
                self.worker_thread.progress_updated.emit(0, f"使用当前文档: {doc.Name}")
            except (pythoncom.com_error, AttributeError) as e:
                error_message = "无法获取活动文档。请确保已打开一个Word文档。"
                raise Exception(error_message) from e

            # 获取当前选中的表格
            try:
                selection = word_app.Selection
                table = None

                # 尝试获取当前选择的表格
                try:
                    if selection.InRange(selection.Tables(1).Range):
                        table = selection.Tables(1)
                except pythoncom.com_error:
                    # 查找包含光标的表格
                    found = False
                    for i in range(1, doc.Tables.Count + 1):
                        tbl = doc.Tables(i)
                        if tbl.Range.Start <= selection.Start <= tbl.Range.End:
                            table = tbl
                            tbl.Select()
                            selection = word_app.Selection
                            found = True
                            break

                    if not found:
                        error_message = "未找到表格。请先在文档中创建一个表格并将光标置于表格内。"
                        raise Exception(error_message)

                if table is None:
                    error_message = "未选中任何表格。请将光标置于表格内。"
                    raise Exception(error_message)

                initial_rows = table.Rows.Count
                initial_cols = table.Columns.Count
                # 确保表格至少有2列
                if initial_cols < 2:
                    # 扩展表格到2列
                    while table.Columns.Count < 2:
                        table.Columns.Add()
                    initial_cols = 2
                    self.worker_thread.progress_updated.emit(0, "表格已扩展为2列布局")

                self.worker_thread.progress_updated.emit(0, f"使用选中的表格({initial_rows}行x{initial_cols}列)")
            except (pythoncom.com_error, AttributeError) as e:
                error_message = str(e) or "无法获取表格。请确保光标在表格内。"
                raise Exception(error_message) from e

            # 获取当前光标位置(初始行列)
            try:
                if not selection.InRange(table.Range):
                    table.Cell(1, 1).Select()
                    selection = word_app.Selection

                current_cell = selection.Cells(1)
                start_row = current_cell.RowIndex
                start_col = current_cell.ColumnIndex
                # 确保起始列在有效范围内
                if start_col > 2:
                    start_col = 1
                self.worker_thread.progress_updated.emit(0, f"从表格位置: 行{start_row}, 列{start_col}开始插入")
            except (pythoncom.com_error, AttributeError) as e:
                start_row = 1
                start_col = 1
                try:
                    table.Cell(start_row, start_col).Select()
                    selection = word_app.Selection
                    self.worker_thread.progress_updated.emit(0, "从表格左上角开始插入")
                except:
                    error_message = "无法定位表格起始位置。"
                    raise Exception(error_message) from e

            # 插入图片和文件名(按照单个单元格陆续插入)
            total_images = len(self.image_paths)

            # 设置当前插入位置
            current_row = start_row
            current_col = start_col

            for i, img_path in enumerate(self.image_paths):
                # 更新进度
                progress = (i + 1) / total_images * 100
                self.worker_thread.progress_updated.emit(progress,
                                                         f"插入图片: {os.path.basename(img_path)} ({i + 1}/{total_images})")

                try:
                    # 检查是否需要添加新行
                    if current_row > table.Rows.Count:
                        table.Rows.Add()
                        self.worker_thread.progress_updated.emit(progress, f"添加新行: 共{table.Rows.Count}行")

                    # 检查是否需要添加新列
                    if current_col > table.Columns.Count:
                        table.Columns.Add()
                        self.worker_thread.progress_updated.emit(progress, f"添加新列: 共{table.Columns.Count}列")

                    # 获取图片单元格
                    img_cell = table.Cell(current_row, current_col)

                    # 添加图片
                    success = self.add_image_to_cell(img_cell, img_path, params)

                    # 获取名称单元格(图片行的下一行)
                    name_row = current_row + 1
                    if name_row > table.Rows.Count:
                        table.Rows.Add()
                        self.worker_thread.progress_updated.emit(progress, f"补充名称行: 共{table.Rows.Count}行")

                    name_cell = table.Cell(name_row, current_col)
                    self.add_filename(name_cell, img_path, params, success)

                    # 移动到下一个位置
                    current_col += 1
                    if current_col > 2:  # 如果超过2列(即一行最多2张图)
                        current_col = 1  # 回到第一列
                        current_row += 2  # 向下移动两行(图片行+文件名行)

                except (OSError, IOError, pythoncom.com_error) as e:
                    error_msg = f"处理图片 {os.path.basename(img_path)} 时出错: {str(e)}"
                    self.worker_thread.progress_updated.emit(progress, error_msg)
                    logging.error(f"处理第{i + 1}张图片时出错: {error_msg}\n{traceback.format_exc()}")
                except Exception as e:
                    error_msg = f"处理图片 {os.path.basename(img_path)} 时发生未知错误: {str(e)}"
                    self.worker_thread.progress_updated.emit(progress, error_msg)
                    logging.error(f"处理第{i + 1}张图片时发生未知错误: {error_msg}\n{traceback.format_exc()}")

            # 完成
            self.worker_thread.progress_updated.emit(100, f"成功插入 {total_images} 张图片到表格")
            word_app.Activate()

        except (pythoncom.com_error, OSError, IOError) as e:
            error_message = str(e) or "发生错误"
            self.worker_thread.error_occurred.emit(error_message)
            logging.error(f"插入图片时出错: {error_message}\n{traceback.format_exc()}")
        except Exception as e:
            error_message = f"发生未知错误: {str(e)}"
            self.worker_thread.error_occurred.emit(error_message)
            logging.error(f"插入图片时发生未知错误: {error_message}\n{traceback.format_exc()}")
        finally:
            # 清理COM
            with com_lock:
                try:
                    pythoncom.CoUninitialize()
                except:
                    pass

    def update_insert_progress(self, progress, message):
        """更新插入进度"""
        self.progress.setValue(int(progress))
        self.status_label.setText(message)

    def insert_completed(self):
        """插入完成处理"""
        self.status_label.setText("图片插入操作完成")
        self.progress.setValue(100)
        self.set_buttons_enabled(True)
        QMessageBox.information(self, "完成", "图片已成功插入到Word文档")

    def start_resize_thread(self):
        """启动调整图片大小的线程"""
        # 验证输入
        try:
            new_width = float(self.resize_width.text())
            new_height = float(self.resize_height.text())

            if new_width < 1.0 or new_width > 30.0:
                QMessageBox.warning(self, "输入无效", "图片宽度应在1-30厘米之间")
                return

            if new_height < 1.0 or new_height > 30.0:
                QMessageBox.warning(self, "输入无效", "图片高度应在1-30厘米之间")
                return
        except ValueError:
            QMessageBox.warning(self, "输入无效", "请输入有效的数值")
            return

        # 启动线程
        self.set_buttons_enabled(False)
        self.status_label.setText("正在修改所有图片大小...")
        self.progress.setValue(0)

        lock_aspect = self.lock_aspect.isChecked()

        self.worker_thread = WorkerThread(self.resize_all_images, (new_width, new_height, lock_aspect))
        self.worker_thread.progress_updated.connect(self.update_resize_progress)
        self.worker_thread.task_completed.connect(self.resize_completed)
        self.worker_thread.error_occurred.connect(self.handle_error)
        self.worker_thread.start()

    def resize_all_images(self, new_width, new_height, lock_aspect):
        """实际执行修改所有图片大小的操作"""
        try:
            # 使用线程锁保护COM初始化
            with com_lock:
                pythoncom.CoInitialize()

            # 连接到Word
            try:
                word_app = win32.gencache.EnsureDispatch("Word.Application")
                word_app.Visible = True
            except (pythoncom.com_error, AttributeError) as e:
                error_msg = "无法连接到Word应用程序"
                raise Exception(error_msg) from e

            # 检查是否有打开的文档
            if word_app.Documents.Count == 0:
                error_msg = "没有打开的Word文档"
                raise Exception(error_msg)

            doc = word_app.ActiveDocument
            self.worker_thread.progress_updated.emit(0, f"正在处理文档: {doc.Name}")

            # 转换厘米到磅
            cm_to_points = 28.3465
            target_width = new_width * cm_to_points
            target_height = new_height * cm_to_points

            # 统计图片数量
            total_images = doc.InlineShapes.Count
            if total_images == 0:
                self.worker_thread.progress_updated.emit(100, "文档中没有图片")
                return

            # 遍历所有图片并修改大小
            for i in range(1, total_images + 1):
                try:
                    shape = doc.InlineShapes(i)

                    if lock_aspect:
                        # 保持纵横比,按宽度计算高度
                        original_ratio = shape.Height / shape.Width
                        shape.Width = target_width
                        shape.Height = target_width * original_ratio
                    else:
                        # 不锁定纵横比,按指定尺寸调整
                        shape.LockAspectRatio = 0
                        shape.Width = target_width
                        shape.Height = target_height

                    # 更新进度
                    progress = (i / total_images) * 100
                    self.worker_thread.progress_updated.emit(progress, f"正在修改第{i}/{total_images}张图片")

                    time.sleep(0.1)  # 短暂延迟
                except (pythoncom.com_error, AttributeError) as e:
                    logging.error(f"修改第{i}张图片时出错: {str(e)}")
                    continue
                except Exception as e:
                    logging.error(f"修改第{i}张图片时发生未知错误: {str(e)}")
                    continue

            # 完成
            self.worker_thread.progress_updated.emit(100, f"已完成!共修改了 {total_images} 张图片的大小")

        except (pythoncom.com_error, OSError, IOError) as e:
            error_msg = f"修改图片大小时出错: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)
        except Exception as e:
            error_msg = f"修改图片大小时发生未知错误: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)
        finally:
            # 清理
            with com_lock:
                try:
                    pythoncom.CoUninitialize()
                except:
                    pass

    def update_resize_progress(self, progress, message):
        """更新调整大小进度"""
        self.progress.setValue(int(progress))
        self.status_label.setText(message)

    def resize_completed(self):
        """调整大小完成处理"""
        self.status_label.setText("图片大小调整操作完成")
        self.set_buttons_enabled(True)
        QMessageBox.information(self, "完成", "图片大小调整操作完成")

    def start_clear_thread(self):
        """启动清除所有图片的线程"""
        # 确认操作
        confirm = QMessageBox.question(
            self,
            "确认清除",
            "确定要删除文档中所有图片吗?此操作不可恢复!",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )

        if confirm != QMessageBox.StandardButton.Yes:
            return

        # 启动线程
        self.set_buttons_enabled(False)
        self.status_label.setText("正在清除所有图片...")
        self.progress.setValue(0)

        self.worker_thread = WorkerThread(self.clear_all_images)
        self.worker_thread.progress_updated.connect(self.update_clear_progress)
        self.worker_thread.task_completed.connect(self.clear_completed)
        self.worker_thread.error_occurred.connect(self.handle_error)
        self.worker_thread.start()

    def clear_all_images(self):
        """实际执行清除所有图片的操作"""
        try:
            # 使用线程锁保护COM初始化
            with com_lock:
                pythoncom.CoInitialize()

            # 连接到Word
            try:
                word_app = win32.gencache.EnsureDispatch("Word.Application")
                word_app.Visible = True
            except (pythoncom.com_error, AttributeError) as e:
                error_msg = "无法连接到Word应用程序"
                raise Exception(error_msg) from e

            # 检查是否有打开的文档
            if word_app.Documents.Count == 0:
                error_msg = "没有打开的Word文档"
                raise Exception(error_msg)

            doc = word_app.ActiveDocument
            self.worker_thread.progress_updated.emit(0, f"正在处理文档: {doc.Name}")

            # 统计图片数量
            total_images = doc.InlineShapes.Count
            if total_images == 0:
                self.worker_thread.progress_updated.emit(100, "文档中没有图片")
                return

            # 从后往前删除图片(避免索引变化问题)
            removed = 0
            for i in range(total_images, 0, -1):
                try:
                    # 删除图片
                    doc.InlineShapes(i).Delete()
                    removed += 1

                    # 更新进度
                    progress = (removed / total_images) * 100
                    self.worker_thread.progress_updated.emit(progress, f"已清除 {removed}/{total_images} 张图片")

                    time.sleep(0.1)  # 短暂延迟
                except (pythoncom.com_error, AttributeError) as e:
                    logging.error(f"清除第{i}张图片时出错: {str(e)}")
                    continue
                except Exception as e:
                    logging.error(f"清除第{i}张图片时发生未知错误: {str(e)}")
                    continue

            # 完成
            self.worker_thread.progress_updated.emit(100, f"已完成!共清除了 {removed} 张图片")

        except (pythoncom.com_error, OSError, IOError) as e:
            error_msg = f"清除图片时出错: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)
        except Exception as e:
            error_msg = f"清除图片时发生未知错误: {str(e)}"
            logging.error(error_msg, exc_info=True)
            self.worker_thread.error_occurred.emit(error_msg)
        finally:
            # 清理
            with com_lock:
                try:
                    pythoncom.CoUninitialize()
                except:
                    pass

    def update_clear_progress(self, progress, message):
        """更新清除进度"""
        self.progress.setValue(int(progress))
        self.status_label.setText(message)

    def clear_completed(self):
        """清除图片完成处理"""
        self.status_label.setText("图片清除操作完成")
        self.set_buttons_enabled(True)
        QMessageBox.information(self, "完成", "图片清除操作完成")

    def handle_error(self, error_message):
        """处理错误"""
        self.status_label.setText(f"错误: {error_message}")
        self.progress.setValue(0)
        self.set_buttons_enabled(True)
        QMessageBox.critical(self, "错误", error_message)

    def set_buttons_enabled(self, enabled):
        """设置按钮启用状态"""
        self.insert_btn.setEnabled(enabled and bool(self.image_paths))
        self.select_btn.setEnabled(enabled)
        self.resize_btn.setEnabled(enabled)
        self.clear_btn.setEnabled(enabled)
        self.compress_btn.setEnabled(enabled and bool(self.image_paths))
        self.rename_btn.setEnabled(enabled and bool(self.image_paths))
        self.delete_btn.setEnabled(enabled and bool(self.image_list.selectedItems()))
        self.clear_list_btn.setEnabled(enabled and bool(self.image_paths))

    def add_image_to_cell(self, cell, img_path, params):
        """在Word表格单元格中添加图片并调整大小"""
        temp_dir = None
        try:
            if not os.path.exists(img_path):
                raise FileNotFoundError(f"图片文件不存在: {img_path}")

            # 创建临时副本(解决特殊字符问题)
            temp_dir = tempfile.mkdtemp()
            safe_filename = f"img_{os.urandom(4).hex()}{os.path.splitext(img_path)[1]}"
            temp_path = os.path.join(temp_dir, safe_filename)
            shutil.copy2(img_path, temp_path)

            # 计算目标尺寸(厘米转磅)
            cm_to_points = 28.3465
            target_width = params["width"] * cm_to_points
            target_height = params["height"] * cm_to_points

            # 清除单元格原有内容
            cell.Range.Delete()

            # 添加图片
            inline_shape = cell.Range.InlineShapes.AddPicture(
                FileName=temp_path,
                LinkToFile=False,
                SaveWithDocument=True
            )

            # 调整图片大小
            inline_shape.LockAspectRatio = 0  # 不锁定纵横比
            inline_shape.Width = target_width
            inline_shape.Height = target_height

            # 图片居中
            cell.Range.Paragraphs.Alignment = 1  # 居中

            return True

        except (OSError, IOError, pythoncom.com_error) as e:
            error_msg = f"无法处理图片 {os.path.basename(img_path)}: {str(e)}"
            self.worker_thread.progress_updated.emit(0, error_msg)
            return False
        except Exception as e:
            error_msg = f"无法处理图片 {os.path.basename(img_path)}: 未知错误 {str(e)}"
            self.worker_thread.progress_updated.emit(0, error_msg)
            return False
        finally:
            # 清理临时文件
            if temp_dir and os.path.exists(temp_dir):
                try:
                    shutil.rmtree(temp_dir)
                except Exception as e:
                    logging.error(f"清理临时文件失败: {str(e)}", exc_info=True)

    def add_filename(self, cell, img_path, params, success):
        """在图片下方的单元格中添加文件名 - 应用字体设置"""
        try:
            # 获取文件名(不含扩展名)
            filename = os.path.splitext(os.path.basename(img_path))[0]

            # 清除单元格原有内容
            cell.Range.Delete()

            # 添加文件名文本
            if not success:
                filename = f"[失败] {filename}"

            # 先设置文本内容
            cell.Range.Text = filename

            # 获取文本范围
            text_range = cell.Range

            # 设置中文字体名称(重要!)
            text_range.Font.NameFarEast = params["font_name"]

            # 设置英文字体名称
            text_range.Font.Name = params["font_name"]

            # 设置字体大小(使用原始字体大小,不需要转换)
            text_range.Font.Size = params["font_size"]

            # 设置段落对齐
            text_range.Paragraphs.Alignment = 1  # 居中

            # 设置行间距
            text_range.Paragraphs.LineSpacing = params["line_spacing"]

            # 设置字体颜色
            if not success:
                text_range.Font.Color = win32.constants.wdColorRed
            else:
                # 将QColor转换为Word颜色常量
                red = params["font_color"].red()
                green = params["font_color"].green()
                blue = params["font_color"].blue()
                color_val = blue * 65536 + green * 256 + red
                text_range.Font.Color = color_val

        except (pythoncom.com_error, AttributeError) as e:
            error_msg = f"添加文件名失败: {os.path.basename(img_path)}: {str(e)}"
            self.worker_thread.progress_updated.emit(0, error_msg)
        except Exception as e:
            error_msg = f"添加文件名失败: {os.path.basename(img_path)}: 未知错误 {str(e)}"
            self.worker_thread.progress_updated.emit(0, error_msg)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = WordImageInserter()
    window.show()
    sys.exit(app.exec())

界面.png (54.21 KB, 下载次数: 5)

界面.png

免费评分

参与人数 8吾爱币 +13 热心值 +8 收起 理由
wangxb2555 + 1 我很赞同!
bamboowalker + 1 + 1 我很赞同!
loine5 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
GXW1693 + 1 + 1 谢谢@Thanks!
牧尘凉凉 + 1 + 1 我很赞同!
hrh123 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
xlln + 1 + 1 我很赞同!
王者之剑0 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
sxsllgq 发表于 2025-8-22 04:33
2025-08-22 04:31:52,553 - ERROR - 插入图片时发生未知错误: 发生未知错误: 无法启动Word应用程序。请确保已安装Microsoft Word。
Traceback (most recent call last):
  File "5.0.py", line 903, in insert_to_existing_table
  File "win32com\client\gencache.py", line 654, in EnsureDispatch
  File "win32com\client\gencache.py", line 481, in EnsureModule
  File "win32com\client\gencache.py", line 312, in GetModuleForTypelib
  File "win32com\client\gencache.py", line 687, in AddModuleToCache
AttributeError: module 'win32com.gen_py.00020905-0000-0000-C000-000000000046x0x8x7' has no attribute 'CLSIDToClassMap'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "5.0.py", line 907, in insert_to_existing_table
Exception: 无法启动Word应用程序。请确保已安装Microsoft Word。
推荐
 楼主| deepxia 发表于 2025-8-22 08:04 |楼主
sxsllgq 发表于 2025-8-22 04:33
2025-08-22 04:31:52,553 - ERROR - 插入图片时发生未知错误: 发生未知错误: 无法启动Word应用程序。请确保 ...

win32com.gen_py.00020905-0000-0000-C000-000000000046x0x8x7' has no attribute 'CLSIDToClassMap' 临时简单解决办法,删除C:\Users\[用户名]\AppData\Local\Temp\gen_py文件夹,重新打开软件,应该就能用了。想一劳永逸的解决办法,只有改源代码了或者看看Office版本兼容性问题(就是64位的电脑装了32位的office之类的)
沙发
王者之剑0 发表于 2025-8-14 09:17
3#
qqxx 发表于 2025-8-14 09:21
请给个软件下载链接呀,谢谢
4#
KusicFack 发表于 2025-8-14 09:36
支持开源,感谢楼主分享
5#
 楼主| deepxia 发表于 2025-8-14 09:39 |楼主
王者之剑0 发表于 2025-8-14 09:17
老哥,有没有成品呀,看不懂

https://wwej.lanzouu.com/iuP4m33ia6de密码:52pj
6#
 楼主| deepxia 发表于 2025-8-14 09:40 |楼主
qqxx 发表于 2025-8-14 09:21
请给个软件下载链接呀,谢谢

https://wwej.lanzouu.com/iuP4m33ia6de密码:52pj
7#
hrh123 发表于 2025-8-14 09:57
【公告】发帖代码插入以及添加链接教程(有福利)
https://www.52pojie.cn/thread-713042-1-1.html
(出处: 吾爱破解论坛)
8#
jacktong85 发表于 2025-8-14 10:19
如何使用?
9#
 楼主| deepxia 发表于 2025-8-14 10:44 |楼主

其实就是图片批量压缩,批量改名,在word中批量插入图片,读取图片名。看图片界面也能明白个80-90%
10#
wwmusic 发表于 2025-8-14 11:04
WPS能用吗?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-21 17:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表