PPT转图片拼贴工具 v4.3

news2025/7/27 20:48:23

软件介绍

这个软件就是将PPT文件转换为图片并且拼接起来。
效果展示在这里插入图片描述

支持导入文件和支持导入文件夹,也支持手动输入文件/文件夹路径

软件界面
在这里插入图片描述

这一次提供了源码和开箱即用版本,exe就是直接用就可以了。

软件源码

import os
import re
import sys
import win32com.client
from PIL import Image
from typing import List, Union
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QFileDialog, QProgressBar, QTextEdit, QScrollBar, QFrame, QStyleFactory
from PyQt5.QtGui import QFont, QIcon
from PyQt5.QtCore import Qt, QThread, pyqtSignal
import pythoncom
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices


class PPTtoImageConverter:
    """PPT转图片拼贴的核心功能类"""

    def __init__(self):
        pass

    def convert_ppt_to_png(self, ppt_path: str, output_folder: str) -> None:
        """将单个PPT文件转换为PNG图片"""
        pythoncom.CoInitialize()
        try:
            ppt_app = win32com.client.Dispatch("PowerPoint.Application")
        except Exception as e:
            pythoncom.CoUninitialize()
            raise RuntimeError(f"无法启动 PowerPoint 应用程序: {e}")

        if not os.path.exists(ppt_path):
            pythoncom.CoUninitialize()
            raise FileNotFoundError(f"PPT 文件不存在: {ppt_path}")

        try:
            presentation = ppt_app.Presentations.Open(ppt_path, WithWindow=False)
            presentation.SaveAs(output_folder, 18)  # 18 代表 PNG 格式
            presentation.Close()
        finally:
            ppt_app.Quit()
            pythoncom.CoUninitialize()

    def create_collage(self, input_folder: str, output_folder: str, ppt_name: str,
                       row_size: int = 3, col_gap: int = 10, row_gap: int = 10) -> None:
        """从PNG图片创建拼贴画"""
        files = os.listdir(input_folder)
        slide_files = [f for f in files if re.match(r"幻灯片\d+\.png", f, re.IGNORECASE)]

        if not slide_files:
            raise RuntimeError(f"未找到幻灯片图片文件")

        slide_files.sort(key=lambda x: int(re.search(r'\d+', x).group()))

        try:
            images = [Image.open(os.path.join(input_folder, f)) for f in slide_files]
        except Exception as e:
            raise RuntimeError(f"加载图片时出错: {e}")

        if not images:
            raise RuntimeError("没有可处理的图片")

        width, height = images[0].size

        first_img = images[0].resize(
            (width * row_size + col_gap * (row_size - 1),
             height * row_size + int(col_gap * (row_size - 1) * height / width)),
            Image.LANCZOS
        )

        remaining_images = images[1:]

        rows = (len(remaining_images) + row_size - 1) // row_size
        canvas_width = first_img.width
        canvas_height = first_img.height + rows * (height + row_gap)

        collage_image = Image.new("RGB", (canvas_width, canvas_height), (255, 255, 255))

        collage_image.paste(first_img, (0, 0))

        for i, img in enumerate(remaining_images):
            row = i // row_size
            col = i % row_size
            x = col * (width + col_gap)
            y = first_img.height + row * (height + row_gap)
            collage_image.paste(img, (x, y))

        collage_path = os.path.join(output_folder, f"{ppt_name}.png")
        collage_image.save(collage_path)

        for f in slide_files:
            os.remove(os.path.join(input_folder, f))

    def process_ppt_item(self, item_path: str, output_folder: str,
                         row_size: int = 3, col_gap: int = 10, row_gap: int = 10,
                         progress_callback=None) -> None:
        """处理单个PPT文件或文件夹"""
        processed_count = 0
        total_files = 0

        if os.path.isfile(item_path):
            if item_path.lower().endswith(('.ppt', '.pptx')):
                total_files = 1
                try:
                    ppt_filename = os.path.basename(item_path)
                    ppt_name = os.path.splitext(ppt_filename)[0]

                    # 为每个PPT创建单独的临时文件夹
                    temp_folder = os.path.join(output_folder, f"temp_{ppt_name}")
                    os.makedirs(temp_folder, exist_ok=True)

                    self.convert_ppt_to_png(item_path, temp_folder)

                    self.create_collage(temp_folder, output_folder, ppt_name, row_size, col_gap, row_gap)

                    # 清理临时文件夹
                    for f in os.listdir(temp_folder):
                        os.remove(os.path.join(temp_folder, f))
                    os.rmdir(temp_folder)

                    message = f"✓ 处理完成: {ppt_name}.png"
                    if progress_callback:
                        progress_callback(message, 100)
                    processed_count = 1
                except Exception as e:
                    message = f"⚠️ 处理失败: {os.path.basename(item_path)} - {str(e)}"
                    if progress_callback:
                        progress_callback(message, 100)
            else:
                message = f"⚠️ 跳过非PPT文件: {os.path.basename(item_path)}"
                if progress_callback:
                    progress_callback(message, 100)
        elif os.path.isdir(item_path):
            message = f"处理文件夹: {item_path}"
            if progress_callback:
                progress_callback(message, 0)

            ppt_files = [f for f in os.listdir(item_path)
                         if f.lower().endswith(('.ppt', '.pptx'))]
            total_files = len(ppt_files)

            for i, filename in enumerate(ppt_files):
                file_path = os.path.join(item_path, filename)
                try:
                    ppt_name = os.path.splitext(filename)[0]

                    # 为每个PPT创建单独的临时文件夹
                    temp_folder = os.path.join(output_folder, f"temp_{ppt_name}")
                    os.makedirs(temp_folder, exist_ok=True)

                    self.convert_ppt_to_png(file_path, temp_folder)

                    self.create_collage(temp_folder, output_folder, ppt_name, row_size, col_gap, row_gap)

                    # 清理临时文件夹
                    for f in os.listdir(temp_folder):
                        os.remove(os.path.join(temp_folder, f))
                    os.rmdir(temp_folder)

                    message = f"✓ 处理完成 ({i + 1}/{total_files}): {ppt_name}.png"
                    progress = int((i + 1) / total_files * 100)
                    if progress_callback:
                        progress_callback(message, progress)
                    processed_count += 1
                except Exception as e:
                    message = f"⚠️ 处理失败 ({i + 1}/{total_files}): {filename} - {str(e)}"
                    if progress_callback:
                        progress_callback(message, int(i / total_files * 100))
        else:
            message = f"⚠️ 路径不存在或无法访问: {item_path}"
            if progress_callback:
                progress_callback(message, 100)

        return processed_count, total_files


class ProcessingThread(QThread):
    progress_signal = pyqtSignal(str, int)

    def __init__(self, converter, input_path, output_path, row_size, col_gap, row_gap):
        super().__init__()
        self.converter = converter
        self.input_path = input_path
        self.output_path = output_path
        self.row_size = row_size
        self.col_gap = col_gap
        self.row_gap = row_gap

    def run(self):
        try:
            self.converter.process_ppt_item(
                self.input_path,
                self.output_path,
                self.row_size,
                self.col_gap,
                self.row_gap,
                self.update_progress
            )
            self.progress_signal.emit("✅ 所有文件处理完成!", 100)
        except Exception as e:
            self.progress_signal.emit(f"❌ 处理过程中发生错误: {str(e)}", 100)

    def update_progress(self, message, progress):
        self.progress_signal.emit(message, progress)


class PPTtoImageGUI(QWidget):
    """PPT转图片拼贴的图形界面类"""

    def __init__(self):
        super().__init__()
        self.initUI()
        self.converter = PPTtoImageConverter()
        self.processing = False
        self.process_thread = None

    def initUI(self):
        self.setWindowTitle("PPT转图片拼贴工具@阿幸")
        self.setGeometry(100, 100, 700, 550)
        
        # 设置应用程序图标
        self.setWindowIcon(QIcon("PTT.ico"))  # 请确保app.ico文件存在于程序运行目录下

        main_layout = QVBoxLayout()

        # 输入路径选择
        input_layout = QHBoxLayout()
        input_label = QLabel("输入路径:")
        input_label.setFont(QFont("Microsoft YaHei", 10))
        self.input_path_edit = QLineEdit()
        self.input_path_edit.setFont(QFont("Microsoft YaHei", 10))
        
        # 浏览按钮 - 文件选择
        browse_file_button = QPushButton("选择文件")
        browse_file_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        browse_file_button.setFixedWidth(150)
        browse_file_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        browse_file_button.clicked.connect(self.browse_file)
        
        # 浏览按钮 - 文件夹选择
        browse_folder_button = QPushButton("选择文件夹")
        browse_folder_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        browse_folder_button.setFixedWidth(150)
        browse_folder_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        browse_folder_button.clicked.connect(self.browse_folder)
        
        input_layout.addWidget(input_label)
        input_layout.addWidget(self.input_path_edit)
        input_layout.addWidget(browse_file_button)
        input_layout.addWidget(browse_folder_button)
        main_layout.addLayout(input_layout)

        # 输出路径选择
        output_layout = QHBoxLayout()
        output_label = QLabel("输出路径:")
        output_label.setFont(QFont("Microsoft YaHei", 10))
        self.output_path_edit = QLineEdit()
        self.output_path_edit.setFont(QFont("Microsoft YaHei", 10))
        browse_output_button = QPushButton("浏览")
        browse_output_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        browse_output_button.setFixedWidth(150)
        browse_output_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        browse_output_button.clicked.connect(self.browse_output_path)
        output_layout.addWidget(output_label)
        output_layout.addWidget(self.output_path_edit)
        output_layout.addWidget(browse_output_button)
        main_layout.addLayout(output_layout)

        # 设置参数
        params_frame = QFrame()
        params_frame.setFrameShape(QFrame.StyledPanel)
        params_layout = QVBoxLayout(params_frame)
        params_label = QLabel("拼贴设置")
        params_label.setFont(QFont("Microsoft YaHei", 10))
        params_layout.addWidget(params_label)

        # 每行图片数量
        row_size_layout = QHBoxLayout()
        row_size_label = QLabel("每行图片数量:")
        row_size_label.setFont(QFont("Microsoft YaHei", 10))
        self.row_size_edit = QLineEdit()
        self.row_size_edit.setFont(QFont("Microsoft YaHei", 10))
        self.row_size_edit.setText("3")
        row_size_minus_button = QPushButton("-")
        row_size_minus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        row_size_minus_button.setFixedWidth(50)
        row_size_minus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        row_size_minus_button.clicked.connect(lambda: self.decrement_var(self.row_size_edit, 1, 10))
        row_size_plus_button = QPushButton("+")
        row_size_plus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        row_size_plus_button.setFixedWidth(50)
        row_size_plus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        row_size_plus_button.clicked.connect(lambda: self.increment_var(self.row_size_edit, 1, 10))
        row_size_layout.addWidget(row_size_label)
        row_size_layout.addWidget(self.row_size_edit)
        row_size_layout.addWidget(row_size_minus_button)
        row_size_layout.addWidget(row_size_plus_button)
        params_layout.addLayout(row_size_layout)

        # 列间距
        col_gap_layout = QHBoxLayout()
        col_gap_label = QLabel("列间距(像素):")
        col_gap_label.setFont(QFont("Microsoft YaHei", 10))
        self.col_gap_edit = QLineEdit()
        self.col_gap_edit.setFont(QFont("Microsoft YaHei", 10))
        self.col_gap_edit.setText("10")
        col_gap_minus_button = QPushButton("-")
        col_gap_minus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        col_gap_minus_button.setFixedWidth(50)
        col_gap_minus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        col_gap_minus_button.clicked.connect(lambda: self.decrement_var(self.col_gap_edit, 0, 50))
        col_gap_plus_button = QPushButton("+")
        col_gap_plus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        col_gap_plus_button.setFixedWidth(50)
        col_gap_plus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        col_gap_plus_button.clicked.connect(lambda: self.increment_var(self.col_gap_edit, 0, 50))
        col_gap_layout.addWidget(col_gap_label)
        col_gap_layout.addWidget(self.col_gap_edit)
        col_gap_layout.addWidget(col_gap_minus_button)
        col_gap_layout.addWidget(col_gap_plus_button)
        params_layout.addLayout(col_gap_layout)

        # 行间距
        row_gap_layout = QHBoxLayout()
        row_gap_label = QLabel("行间距(像素):")
        row_gap_label.setFont(QFont("Microsoft YaHei", 10))
        self.row_gap_edit = QLineEdit()
        self.row_gap_edit.setFont(QFont("Microsoft YaHei", 10))
        self.row_gap_edit.setText("10")
        row_gap_minus_button = QPushButton("-")
        row_gap_minus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        row_gap_minus_button.setFixedWidth(50)
        row_gap_minus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        row_gap_minus_button.clicked.connect(lambda: self.decrement_var(self.row_gap_edit, 0, 50))
        row_gap_plus_button = QPushButton("+")
        row_gap_plus_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        row_gap_plus_button.setFixedWidth(50)
        row_gap_plus_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        row_gap_plus_button.clicked.connect(lambda: self.increment_var(self.row_gap_edit, 0, 50))
        row_gap_layout.addWidget(row_gap_label)
        row_gap_layout.addWidget(self.row_gap_edit)
        row_gap_layout.addWidget(row_gap_minus_button)
        row_gap_layout.addWidget(row_gap_plus_button)
        params_layout.addLayout(row_gap_layout)

        main_layout.addWidget(params_frame)

        # 处理按钮 - 使用水平布局放置两个按钮
        button_layout = QHBoxLayout()

        self.process_button = QPushButton("开始处理")
        self.process_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        self.process_button.setFixedWidth(120)
        self.process_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
        """)
        self.process_button.clicked.connect(self.start_processing)
        button_layout.addWidget(self.process_button, alignment=Qt.AlignCenter)

        # 添加"关于阿幸"按钮
        self.about_button = QPushButton("关于阿幸")
        self.about_button.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
        self.about_button.setFixedWidth(120)
        self.about_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #388E3C;
            }
        """)
        self.about_button.clicked.connect(self.open_axing_website)
        button_layout.addWidget(self.about_button, alignment=Qt.AlignCenter)

        main_layout.addLayout(button_layout)

        # 进度条
        progress_layout = QHBoxLayout()
        progress_label = QLabel("处理进度:")
        progress_label.setFont(QFont("Microsoft YaHei", 10))
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        progress_layout.addWidget(progress_label)
        progress_layout.addWidget(self.progress_bar)
        main_layout.addLayout(progress_layout)

        # 日志区域
        log_layout = QHBoxLayout()
        log_label = QLabel("处理日志:")
        log_label.setFont(QFont("Microsoft YaHei", 10))
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        log_scrollbar = QScrollBar(Qt.Vertical)
        self.log_text.setVerticalScrollBar(log_scrollbar)
        log_layout.addWidget(log_label)
        log_layout.addWidget(self.log_text)
        main_layout.addLayout(log_layout)

        self.setLayout(main_layout)

        # 设置默认路径
        self.input_path_edit.setText(r"D:\Desktop\文件存储\1")
        self.output_path_edit.setText(r"D:\Desktop\文件存储\1")

    def browse_file(self):
        """浏览并选择单个PPT文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择PPT文件", "", "PowerPoint 文件 (*.ppt *.pptx)"
        )
        if file_path:
            self.input_path_edit.setText(file_path)

    def browse_folder(self):
        """浏览并选择文件夹"""
        folder_path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if folder_path:
            self.input_path_edit.setText(folder_path)

    def browse_output_path(self):
        """浏览并选择输出路径"""
        path = QFileDialog.getExistingDirectory(self, "选择输出文件夹")
        if path:
            self.output_path_edit.setText(path)

    def start_processing(self):
        """开始处理PPT文件"""
        if self.processing:
            return

        input_path = self.input_path_edit.text()
        output_path = self.output_path_edit.text()

        if not input_path or not output_path:
            print("请设置输入路径和输出路径")
            return

        if not os.path.exists(input_path):
            print(f"输入路径不存在: {input_path}")
            return

        os.makedirs(output_path, exist_ok=True)

        self.log_text.clear()
        self.progress_bar.setValue(0)

        row_size = int(self.row_size_edit.text())
        col_gap = int(self.col_gap_edit.text())
        row_gap = int(self.row_gap_edit.text())

        self.processing = True
        self.process_button.setText("处理中...")
        self.process_button.setEnabled(False)

        self.process_thread = ProcessingThread(self.converter, input_path, output_path, row_size, col_gap, row_gap)
        self.process_thread.progress_signal.connect(self.update_progress)
        self.process_thread.finished.connect(self.process_finished)
        self.process_thread.start()

    def update_progress(self, message, progress):
        self.log_text.append(message)
        self.progress_bar.setValue(progress)

    def process_finished(self):
        self.processing = False
        self.process_button.setText("开始处理")
        self.process_button.setEnabled(True)

    def increment_var(self, edit, min_val, max_val):
        """增加变量值,不超过最大值"""
        current = int(edit.text())
        if current < max_val:
            edit.setText(str(current + 1))

    def decrement_var(self, edit, min_val, max_val):
        """减少变量值,不小于最小值"""
        current = int(edit.text())
        if current > min_val:
            edit.setText(str(current - 1))

    def open_axing_website(self):
        """打开关于阿幸的网站"""
        url = QUrl("https://a-xing.top/")
        QDesktopServices.openUrl(url)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create('Fusion'))
    gui = PPTtoImageGUI()
    gui.show()
    sys.exit(app.exec_())

源码下载

https://pan.quark.cn/s/f8bf2904e8c3

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chrome安装代理插件ZeroOmega(保姆级别)

目录 本文直接讲解一下怎么本地安装ZeroOmega一、下载文件在GitHub直接下ZeroOmega 的文件&#xff08;下最新版即可&#xff09; 二、安装插件打开 Chrome 浏览器&#xff0c;访问 chrome://extensions/ 页面&#xff08;扩展程序管理页面&#xff09;&#xff0c;并打开开发者…

Transformer-BiGRU多变量时序预测(Matlab完整源码和数据)

Transformer-BiGRU多变量时序预测&#xff08;Matlab完整源码和数据&#xff09; 目录 Transformer-BiGRU多变量时序预测&#xff08;Matlab完整源码和数据&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现Transformer-BiGRU多变量时间序列预测&…

新华三H3CNE网络工程师认证—Easy IP

Easy IP 就是“用路由器自己的公网IP&#xff0c;给全家所有设备当共享门牌号”的技术&#xff01;&#xff08;省掉额外公网IP&#xff0c;省钱又省配置&#xff01;&#xff09; 生活场景对比&#xff0c;想象你住在一个小区&#xff1a;普通动态NAT&#xff1a;物业申请了 …

Excel 模拟分析之单变量求解简单应用

正向求解 利用公式根据贷款总额、还款期限、贷款利率&#xff0c;求每月还款金额 反向求解 根据每月还款能力&#xff0c;求最大能承受贷款金额 参数&#xff1a; 目标单元格&#xff1a;求的值所在的单元格 目标值&#xff1a;想要达到的预期值 可变单元格&#xff1a;变…

装备制造项目管理具备什么特征?如何选择适配的项目管理软件系统进行项目管控?

国内某大型半导体装备制造企业与奥博思软件达成战略合作&#xff0c;全面引入奥博思 PowerProject 打造企业专属项目管理平台&#xff0c;进一步提升智能制造领域的项目管理效率与协同能力。 该项目管理平台聚焦半导体装备研发与制造的业务特性&#xff0c;实现了从项目立项、…

FPGA 动态重构配置流程

触发FPGA 进行配置的方式有两种&#xff0c;一种是断电后上电&#xff0c;另一种是在FPGA运行过程中&#xff0c;将PROGRAM 管脚拉低。将PROGRAM 管脚拉低500ns 以上就可以触发FPGA 进行重构。 FPGA 的配置过程大致可以分为&#xff1a;配置的触发和建立阶段、加载配置文件和建…

网络安全逆向分析之rust逆向技巧

rust逆向技巧 rust逆向三板斧&#xff1a; 快速定位关键函数 (真正的main函数)&#xff1a;观察输出、输入&#xff0c;字符串搜索&#xff0c;断点等方法。定位关键 加密区 &#xff1a;根据输入的flag&#xff0c;打硬件断点&#xff0c;快速捕获程序中对flag访问的位置&am…

Leetcode 2494. 合并在同一个大厅重叠的活动

1.题目基本信息 1.1.题目描述 表: HallEvents ----------------- | Column Name | Type | ----------------- | hall_id | int | | start_day | date | | end_day | date | ----------------- 该表可能包含重复字段。 该表的每一行表示活动的开始日期和结束日期&…

vue+elementui 网站首页顶部菜单上下布局

菜单集合后台接口动态获取&#xff0c;保存到store vuex状态管理器 <template><div id"app"><el-menu:default-active"activeIndex2"class"el-menu-demo"mode"horizontal"select"handleSelect"background-…

网络安全-等级保护(等保) 3-3-1 GB/T 36627-2018 附录A (资料性附录) 测评后活动、附 录 B (资料性附录)渗透测试的有关概念说明

################################################################################ GB/T 36627-2018 《信息安全技术 网络安全等级保护测试评估技术指南》对网络安全等级保护测评中的相关测评技术进行明确的分类和定义,系统地归纳并阐述测评的技术方法,概述技术性安全测试和…

pytorch3d+pytorch1.10+MinkowskiEngine安装

1、配置pytorch1.10cuda11.0 pip install torch1.10.1cu111 torchvision0.11.2cu111 torchaudio0.10.1 -f https://download.pytorch.org/whl/cu111/torch_stable.html 2、配置 MinkowskiEngine库 不按下面步骤&#xff0c;出现错误 1、下载MinkowskiEngine0.5.4到本地 2、查看…

AI Infra运维实践:DeepSeek部署运维中的软硬结合

发布会资料 《AI Infra运维实践&#xff1a;DeepSeek部署运维中的软硬结合》 袋鼠云运维服务 1、行业痛点 随着数字化转型的深入&#xff0c;企业面临的运维挑战日益复杂&#xff0c;所依托的平台在长期使用的过程中积累了各式各样的问题或者难点。这些问题不仅影响效率&…

MySQL体系架构解析(二):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…

K8s基础一

Kubernetes 架构 Kubernetes 背后的架构概念。 Kubernetes 集群由一个控制平面和一组用于运行容器化应用的工作机器组成&#xff0c; 这些工作机器称作节点&#xff08;Node&#xff09;。每个集群至少需要一个工作节点来运行 Pod。 工作节点托管着组成应用负载的 Pod。控制平…

2025五大免费变声器推荐!

在游戏开黑时想靠声音搞怪活跃气氛&#xff0c;或是在直播中用独特声线吸引观众&#xff0c;又或者给视频配音时想尝试不同角色 —— 但市面上的变声软件要么收费高昂&#xff0c;要么效果生硬、操作复杂&#xff0c;难道找到一款好用又免费的变声器真的这么难&#xff1f; 今…

SDC命令详解:使用set_min_capacitance命令进行约束

相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 目录 指定最小需驱动电容值 指定对象列表/集合 简单使用 写在最后 set_min_capacitance命令用于设置输入端口的最小需驱动电容&#xff08;设置了输入端口的min_c…

几何引擎对比:OpenCasCade、ACIS、Parasolid和CGM

概述 从技术架构与行业实践来看&#xff0c;OpenCasCade 凭借开源生态与轻量化设计形成差异化竞争力&#xff0c;尤其适合预算敏感、需定制开发或依赖开源工具链的场景&#xff1b;而 ACIS、Parasolid 等商业内核则通过工业级精度优化与主流 CAD 深度绑定占据大型企业市场&…

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战

汽车安全&#xff1a;功能安全&#xff08;FuSa&#xff09;、预期功能安全&#xff08;SOTIF&#xff09;与网络安全(Cybersecurity) 从理论到实战的安全体系 引言&#xff1a;自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进&#xff0c;汽车安全正从“机械可靠…

Excel-vlookup -多条件匹配,返回指定列处的值

前提&#xff1a;先了解vlookup 的简单使用&#xff0c; 参照&#xff1a;https://blog.csdn.net/yanweijie0317/article/details/144886106?spm1011.2124.3001.6209 要求&#xff1a;按照Sheet0的B列和I列&#xff0c;在Sheet1中查找H列。 函数&#xff1a; VLOOKUP(B509&a…

Python异步爬虫与代理完美结合

为了编写一个高性能的异步爬虫&#xff0c;并使用代理IP&#xff0c;我们可以使用以下技术栈&#xff1a;aiohttp &#xff08;用于异步HTTP请求&#xff09;、asyncio &#xff08;用于异步编程&#xff09;、代理IP可以使用一个代理池&#xff0c;我们从文件中读取或者从API获…