标签: code

  • 【Python】按照关键词查找相应PPT

    今天巧了,好几个同事问我要PPT,但是他们只能记得起来一些关键词,而我恰好也没有很足的印象,毕竟那是两三年前,还可能不是我做的东西!

    WPS只能按照云文档进行查找关键词,那么电脑中几千个PPT要怎么找呢?(没错我电脑里真有2000个PPT (((φ(◎ロ◎;)φ))))

    我们可以根据他们截取的画面关键词,来对PPT进行索引,这样可以节约一些查找文件的时间,然后采用olefile库,查找对应PPT即可。

    import os
    from pptx import Presentation
    import olefile
    
    def is_powerpoint_file(file_path):
        """检查文件是否为PPT或PPTX格式"""
        valid_extensions = ['.ppt', '.pptx']
        return any(file_path.lower().endswith(ext) for ext in valid_extensions)
    
    def index_powerpoint_files(search_dir):
        """索引指定目录中的所有PPT和PPTX文件"""
        ppt_files = []
        total_files = 0
    
        for root, _, files in os.walk(search_dir):
            total_files += len(files)
            for file in files:
                if file.startswith("~$"):  # 跳过临时文件
                    continue
                file_path = os.path.join(root, file)
                if is_powerpoint_file(file_path):
                    ppt_files.append(file_path)
        
        print(f"[信息] 已索引文件总数:{total_files},PPT文件总数:{len(ppt_files)}")
        return ppt_files
    
    def search_text_in_pptx(file_path, target_text):
        """在PPTX文件中搜索目标文字"""
        try:
            presentation = Presentation(file_path)
            for slide in presentation.slides:
                for shape in slide.shapes:
                    if shape.has_text_frame and target_text in shape.text:
                        return True
        except Exception as e:
            print(f"[错误] 无法处理文件:{file_path},错误信息:{e}")
        return False
    
    def search_text_in_ppt(file_path, target_text):
        """在PPT文件中搜索目标文字"""
        try:
            if olefile.isOleFile(file_path):
                with olefile.OleFileIO(file_path) as ole:
                    if "PowerPoint Document" in ole.listdir():
                        stream = ole.openstream("PowerPoint Document")
                        content = stream.read().decode(errors="ignore")
                        if target_text in content:
                            return True
        except Exception as e:
            print(f"[错误] 无法处理文件:{file_path},错误信息:{e}")
        return False
    
    def search_text_in_powerpoint_files(ppt_files, target_text):
        """在索引的PPT文件中搜索目标文字"""
        result_files = []
        total_files = len(ppt_files)
    
        print(f"[信息] 开始内容搜索,共需处理 {total_files} 个文件")
        for idx, file_path in enumerate(ppt_files, start=1):
            print(f"[处理中] {idx}/{total_files} - 正在处理文件:{file_path}")
            if file_path.lower().endswith(".pptx") and search_text_in_pptx(file_path, target_text):
                result_files.append(file_path)
            elif file_path.lower().endswith(".ppt") and search_text_in_ppt(file_path, target_text):
                result_files.append(file_path)
    
        return result_files
    
    if __name__ == "__main__":
        search_dir = "D:\\"
        target_text = input("请输入要查找的文字(支持中文):")
        
        print(f"[信息] 正在索引盘中的PPT文件,请稍候...\n")
        ppt_files = index_powerpoint_files(search_dir)
        
        if ppt_files:
            print(f"\n[信息] 索引完成,开始搜索包含 '{target_text}' 的文件...\n")
            matching_files = search_text_in_powerpoint_files(ppt_files, target_text)
            if matching_files:
                print("\n[结果] 找到包含目标文字的PPT文件:")
                for file in matching_files:
                    print(file)
            else:
                print("\n[结果] 未找到包含该文字的PPT文件。")
        else:
            print("\n[信息] 未在指定目录中找到任何PPT文件。")
    
  • 【Python】对彩色LOGO进行批量反白处理

    为了制作一些高大上的风格化 PPT,有时我们需要很多客户的反白色LOGO,以符合当下的一些设计潮流。

    目前常用的做法是在 PPT中对图片本身进行亮度调整,可以理解为一键过曝,但是这对于一些本身就含有白色的图片不适用,也无法处理JPG的图片,更没法快速将反白的图片进行批量保存,以便存储成库,在其他场景继续使用。

    因此使用脚本可以防止原来的白色部分混成一团,预先对原LOGO白色区域进行透明化,然后对其他颜色区域反白。

    这个脚本目前适用于我的工作环境,包含一些问题,例如如果原来的图标包含白色文字,这样会将其透明化,因此还需按照使用情况进行调整。

    后续考虑加入对JPG进行处理的过程,原理上是对白色部分预先透明度处理,然后后续步骤基本一致,不过使用JPG作为LOGO的客户较少,该功能并不急迫。若要实现该功能,可能需要使用OCR对文字部分预先识别处理,流程上麻烦不少,不过由于wechat-ocr的强大功能,应该也可以稳定呈现,wechat-ocr此前有过一些实践,效果出众,推荐大家使用。

    此外脚本尚未测试灰色部分是否会有问题,目前感觉应该会有问题,若使用中有其他问题会随时更新。

    import tkinter as tk
    from tkinter import filedialog
    from PIL import Image, ImageTk
    import random
    import string
    class ImageProcessor(tk.Tk):
        def __init__(self):
            super().__init__()
            self.title("Logo Image Processor")
            self.geometry("600x600")
            self.image_path = None
            self.images = []  # 用于存储多个图像
            self.image_label = tk.Label(self)
            self.image_label.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
            
            # 设置拖放区域
            self.drop_area = tk.Label(self, text="拖动PNG图片到此区域", relief="solid", width=30, height=4)
            self.drop_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
            self.drop_area.bind("<Enter>", self.on_drag_enter)
            self.drop_area.bind("<Leave>", self.on_drag_leave)
            self.drop_area.bind("<ButtonRelease-1>", self.on_drop)
            # 添加处理按钮
            self.process_button = tk.Button(self, text="处理图片并保存", command=self.process_images)
            self.process_button.pack(pady=10)
        def on_drag_enter(self, event):
            self.drop_area.config(bg="lightblue")
        def on_drag_leave(self, event):
            self.drop_area.config(bg="white")
        def on_drop(self, event):
            file_paths = filedialog.askopenfilenames(filetypes=[("PNG files", "*.png")])
            if file_paths:
                self.load_images(file_paths)
        def load_images(self, paths):
            self.images = []  # 清空当前图像列表
            for path in paths:
                image = Image.open(path).convert("RGBA")  # 确保加载为RGBA格式以处理透明度
                self.images.append((path, image))  # 存储图像及其路径
            if self.images:
                self.display_image(self.images[0][1])  # 显示第一张图片
        def display_image(self, image):
            image_tk = ImageTk.PhotoImage(image)
            self.image_label.config(image=image_tk)
            self.image_label.image = image_tk
        def process_images(self):
            if self.images:
                for original_path, image in self.images:
                    # 获取图像的每个像素
                    pixels = image.load()
                    width, height = image.size
                    
                    for x in range(width):
                        for y in range(height):
                            r, g, b, a = pixels[x, y]
                            
                            # 将白色部分透明化
                            if r == 255 and g == 255 and b == 255:
                                pixels[x, y] = (255, 255, 255, 0)  # 将白色变为透明
                            elif a != 0:  # 如果是非透明区域
                                # 将所有非透明区域变为纯白色
                                pixels[x, y] = (255, 255, 255, a)  # 变为白色,保持原透明度
                    
                    # 生成随机字符并保存处理后的图像
                    random_suffix = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
                    output_path = f"processed_logo_{random_suffix}.png"
                    image.save(output_path)
                    print(f"处理后的LOGO图片已保存为 {output_path}")
                    
                # 更新显示处理后的图片(显示第一张图像)
                self.display_image(self.images[0][1])
    if __name__ == "__main__":
        app = ImageProcessor()
        app.mainloop()
    

    此外,还可以对JPG进行处理:

    注意保证输入图片的分辨率,其平滑操作对分辨率会有一定的损失。

    import tkinter as tk
    from tkinter import filedialog, messagebox
    from PIL import Image, ImageFilter
    import random
    import string
    import os
    class ImageProcessor(tk.Tk):
        def __init__(self):
            super().__init__()
            self.title("Logo Image Processor")
            self.geometry("400x200")  # 设置主窗口大小
            self.image_path = None
            self.images = []  # 用于存储多个图像
            self.processed_images = []  # 用于存储处理后图像路径
            # 设置拖放区域
            self.drop_area = tk.Label(self, text="拖动PNG或JPG图片到此区域", relief="solid", width=30, height=4)
            self.drop_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
            self.drop_area.bind("<Enter>", self.on_drag_enter)
            self.drop_area.bind("<Leave>", self.on_drag_leave)
            self.drop_area.bind("<ButtonRelease-1>", self.on_drop)
            # 添加处理按钮
            self.process_button = tk.Button(self, text="处理图片并保存", command=self.process_images)
            self.process_button.pack(pady=10)
            # 添加选择输出路径按钮
            self.output_dir = None
            self.select_output_button = tk.Button(self, text="选择保存路径", command=self.select_output_dir)
            self.select_output_button.pack(pady=5)
        def on_drag_enter(self, event):
            self.drop_area.config(bg="lightblue")
        def on_drag_leave(self, event):
            self.drop_area.config(bg="white")
        def on_drop(self, event):
            file_paths = filedialog.askopenfilenames(filetypes=[("Image files", "*.png *.jpg *.jpeg")])
            if file_paths:
                self.load_images(file_paths)
        def load_images(self, paths):
            self.images = []  # 清空当前图像列表
            for path in paths:
                try:
                    image = Image.open(path)
                    # 将JPG图像转换为支持透明度的RGBA格式
                    if image.mode != "RGBA":
                        image = image.convert("RGBA")
                    self.images.append((path, image))  # 存储图像及其路径
                except Exception as e:
                    print(f"无法加载图像 {path}: {e}")
                    messagebox.showerror("错误", f"无法加载图像 {path}")
                    
        def select_output_dir(self):
            self.output_dir = filedialog.askdirectory()
            if self.output_dir:
                print(f"选择的输出目录是: {self.output_dir}")
            
        def process_images(self):
            if not self.images:
                messagebox.showwarning("警告", "请先加载图片")
                return
            
            if not self.output_dir:
                messagebox.showwarning("警告", "请先选择保存路径")
                return
            for original_path, image in self.images:
                pixels = image.load()
                width, height = image.size
                
                for x in range(width):
                    for y in range(height):
                        r, g, b, a = pixels[x, y]
                        
                        # 将接近白色的区域透明化,设置阈值范围 (240, 240, 240) 到 (255, 255, 255)
                        if r >= 240 and g >= 240 and b >= 240:
                            pixels[x, y] = (255, 255, 255, 0)  # 将接近白色的部分变为透明
                        elif a != 0:  # 如果是非透明区域
                            # 将所有非透明区域变为纯白色
                            pixels[x, y] = (255, 255, 255, a)  # 变为白色,保持原透明度
                # 对图像进行边缘平滑处理,减少杂色
                image = image.filter(ImageFilter.GaussianBlur(radius=2))
                
                # 生成随机字符并保存处理后的图像
                random_suffix = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
                output_path = os.path.join(self.output_dir, f"processed_logo_{random_suffix}.png")
                image.save(output_path)
                print(f"处理后的LOGO图片已保存为 {output_path}")
                self.processed_images.append(output_path)
    if __name__ == "__main__":
        app = ImageProcessor()
        app.mainloop()
    

  • 【设计】一种菱形平面的火焰表现形式

    来自索契冬奥会转播画面,应该是俄罗斯国家电视一频道+圣火的标志。

    用HTML粗糙实现类似效果,如果要精准复刻,还是需要位置和动画的精细调整。

    <style>
            /* 创建父容器来承载菱形,并设置其为 relative 定位 */
            .container {
                position: relative;
                width: 500px; /* 缩小容器的大小 */
                height: 500px; /* 缩小容器的大小 */
                display: flex;
                justify-content: center;
                align-items: center;
                overflow: visible; /* 防止容器遮挡菱形动画 */
            }
    
            /* 菱形样式 */
            .diamond {
                position: absolute; /* 使用绝对定位来控制每个菱形的具体位置 */
                width: 60px; /* 缩小菱形的宽度 */
                height: 90px; /* 缩小菱形的高度 */
                background-color: yellow; /* 初始颜色为黄色 */
                clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); /* 菱形形状 */
                animation: growDiamond 0.5s ease-in-out forwards, 
                          riseAndShrinkDiamond 1.5s ease-in infinite; /* 循环动画 */
                transform-origin: bottom center;
            }
    
            /* 菱形扩展动画 */
            @keyframes growDiamond {
                0% {
                    transform: scaleY(0);
                    opacity: 0;
                }
                100% {
                    transform: scaleY(1);
                    opacity: 1;
                }
            }
    
            /* 上升并缩小动画 */
            @keyframes riseAndShrinkDiamond {
                0% {
                    transform: translateY(0) scale(1);
                    opacity: 1;
                    background-color: yellow;
                }
                100% {
                    transform: translateY(-150px) scale(0.05); /* 缩小菱形的移动范围 */
                    opacity: 0;
                    background-color: red;
                }
            }
    
            /* 为每个菱形设置不同的初始位置、大小、延迟和动画 */
            .diamond:nth-child(1) {
                animation-delay: 0.2s;
                left: 50px; /* 自定义位置 */
                top: 50px;  /* 自定义位置 */
                transform: scale(1.2); /* 初始大小为1.2倍 */
            }
    
            .diamond:nth-child(2) {
                animation-delay: 0.4s;
                left: 60px;
                top: 70px;
                transform: scale(0.8); /* 初始大小为0.8倍 */
            }
    
            .diamond:nth-child(3) {
                animation-delay: 0.6s;
                left: 30px;
                top: 15px;
                transform: scale(1.5); /* 初始大小为1.5倍 */
            }
    
            .diamond:nth-child(4) {
                animation-delay: 0.8s;
                left: 40px;
                top: 20px;
                transform: scale(1);
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="diamond"></div> <!-- 第一个菱形 -->
            <div class="diamond"></div> <!-- 第二个菱形 -->
            <div class="diamond"></div> <!-- 第三个菱形 -->
            <div class="diamond"></div> <!-- 第四个菱形 -->
        </div>
    </body>