AI帮我解决工作生活中的1件小事,教你如何利用AI工具来解决你实际遇到的问题,并产生价值

一、背景:AI 爆火,它到底能为我们做什么?​

AI 领域可谓是热闹非凡,ChatGPT、DeepSeek 等各种 AI 工具如雨后春笋般涌现,朋友圈里到处都是大家用 AI 生成的文案、图片,仿佛一夜之间,AI 就渗透到了我们生活的方方面面。然而,在这股热潮之下,很多人心里都有这样的疑问:AI 到底能做什么?我能用它来做什么呢?看着别人用 AI 做出各种酷炫的东西,自己却不知道从何下手,仿佛 AI 离我们很近,又很远。

二、生活中的一件小事:打印PDF太大,打印机无法支持超过20MB的PDF打印。

就在今天,我就遇到了一个让人头疼的小问题。孩子学校需要打印一份 PDF学习材料,可当我把文件发送到打印机时,却收到提示:文件超过 20 MB,无法直接打印,需要去电脑端。但是电脑端也试过,根本也不好用。孩子今天放学后就要用到,我试了市面上的很多工具,尝试进行PDF压缩,很遗憾,大部分压缩功能都需要收费。之前也遇到过这种太大无法打印的问题,当时我是采取的最笨的办法,一张张截图,然后一张张打印图片,费时又费力。不知道大家遇没遇到过这种情况,虽然我也是搞软件的,但是遇到这个问题也很头疼,网上也有很多在线压缩的,要么就收费、要么就是做推广需要验证码加好友什么的。

然后就突然想起最近一直在关注的 AI 编程,说不定它能帮我解决这个难题。抱着试试看的心态,我决定向 AI 求助。

三、具体如何做:豆包 AI 助力,生成 Python 程序

因为最近一直在使用豆包,其编程能力很不错。利用豆包AI工具,将需求描述给AI,让其帮我用Python写一个合并DPF的程序。对话如下“我是一个C#开发人员,对.net很熟悉,现在想学习python,请帮我用python写一个可以合并PDF的程序,要求可以自定义上传文件,然后进行合并,同时支持多页合并。”

四、一步步让AI帮你调试:在尝试中找到正确的方法

豆包很快就给出了回应,它为我提供了一段基于 PyMuPDF 库的 Python 代码,这个代码直接复制后拿到Visual Studio Code中

进行运行调试,输出界面如下

但是第一次运行报错了

将报错信息直接反馈豆包,让其进行修改,豆包很快进行了反馈

但是运行后还是报错,继续将错误反馈豆包,进行反复修改

经过多次调试、更换其他思路后最终可以了,但是输出的结果不太对,将结果反馈豆包后,它可以继续帮你修改

最终经过多次的问题修复反馈,成功完成了PDF压缩程序。压缩后的PDF大小大幅降低。同时PDF质量没有受到影响。

以下为PDF压缩前后对比图,压缩前23MB,压缩后9MB

下面是最终完成代码,拿去后直接保存为"合并PDF.py"文件,如果你有Python环境,即可直接运行;后续我会将这个py打包为exe程序,可直接双击运行。

创作不易,欢迎点赞和关注,你的支持是最好的动力~

import os
import fitz  # PyMuPDF
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter import font
import sys
from typing import Optional, Tuple
import tempfile
import traceback
from PIL import Image  # 用于图片处理

class PDFImageCompressorApp:
    def __init__(self, root: tk.Tk):
        self.root = root
        self.root.title("PDF图片压缩工具")
        self.root.geometry("600x400")
        self.root.minsize(500, 350)
        
        # 设置中文字体支持
        self.default_font = font.nametofont("TkDefaultFont")
        self.default_font.configure(family="SimHei", size=10)
        self.root.option_add("*Font", self.default_font)
        
        # 初始化变量
        self.input_file = ""
        self.output_file = ""
        self.quality = tk.IntVar(value=50)  # 默认质量为50%
        self.is_processing = False  # 标记是否正在处理
        
        self._create_widgets()
        self._setup_layout()
        
    def _create_widgets(self) -> None:
        # 创建菜单栏
        self.menu_bar = tk.Menu(self.root)
        self.file_menu = tk.Menu(self.menu_bar, tearoff=0)
        self.file_menu.add_command(label="打开", command=self._select_input_file, accelerator="Ctrl+O")
        self.file_menu.add_separator()
        self.file_menu.add_command(label="退出", command=self.root.quit)
        self.menu_bar.add_cascade(label="文件", menu=self.file_menu)
        
        self.help_menu = tk.Menu(self.menu_bar, tearoff=0)
        self.help_menu.add_command(label="使用说明", command=self._show_help)
        self.help_menu.add_separator()
        self.help_menu.add_command(label="关于", command=self._show_about)
        self.menu_bar.add_cascade(label="帮助", menu=self.help_menu)
        
        self.root.config(menu=self.menu_bar)
        
        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="20")
        
        # 文件选择区域
        self.file_frame = ttk.LabelFrame(self.main_frame, text="文件选择", padding="10")
        self.file_path_label = ttk.Label(self.file_frame, text="未选择文件", width=40)
        self.browse_button = ttk.Button(self.file_frame, text="浏览...", command=self._select_input_file)
        
        # 质量设置区域
        self.quality_frame = ttk.LabelFrame(self.main_frame, text="压缩质量", padding="10")
        self.quality_scale = ttk.Scale(self.quality_frame, from_=10, to=100, orient=tk.HORIZONTAL,
                                      variable=self.quality, length=300)
        self.quality_value_label = ttk.Label(self.quality_frame, text="50%")
        self.quality_scale.bind("<Motion>", self._update_quality_label)
        self.quality_scale.bind("<ButtonRelease-1>", self._update_quality_label)
        
        # 压缩说明
        self.info_label = ttk.Label(self.quality_frame, 
                                  text="较低的质量会产生更小的文件,但可能降低可读性",
                                  foreground="blue")
        
        # 预设按钮
        self.preset_frame = ttk.Frame(self.quality_frame)
        self.low_quality_button = ttk.Button(self.preset_frame, text="低质量 (小文件)", 
                                           command=lambda: self.quality.set(30))
        self.medium_quality_button = ttk.Button(self.preset_frame, text="中等质量", 
                                             command=lambda: self.quality.set(50))
        self.high_quality_button = ttk.Button(self.preset_frame, text="高质量 (大文件)", 
                                            command=lambda: self.quality.set(80))
        
        # 压缩按钮
        self.compress_button = ttk.Button(self.main_frame, text="开始压缩", 
                                        command=self._compress_pdf,
                                        style='Accent.TButton')
        
        # 状态栏
        self.status_bar = ttk.Label(self.root, text="就绪", anchor=tk.W, padding="5")
        
    def _setup_layout(self) -> None:
        self.menu_bar.add_cascade(label="文件", menu=self.file_menu)
        self.menu_bar.add_cascade(label="帮助", menu=self.help_menu)
        
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        self.file_frame.pack(fill=tk.X, pady=10)
        self.file_path_label.pack(side=tk.LEFT, padx=5)
        self.browse_button.pack(side=tk.RIGHT)
        
        self.quality_frame.pack(fill=tk.X, pady=10)
        self.quality_scale.pack(side=tk.LEFT, padx=5)
        self.quality_value_label.pack(side=tk.LEFT, padx=5)
        self.info_label.pack(anchor=tk.W, pady=5)
        
        self.preset_frame.pack(fill=tk.X, pady=5)
        self.low_quality_button.pack(side=tk.LEFT, padx=5)
        self.medium_quality_button.pack(side=tk.LEFT, padx=5)
        self.high_quality_button.pack(side=tk.LEFT, padx=5)
        
        self.compress_button.pack(pady=20)
        self.status_bar.pack(fill=tk.X, side=tk.BOTTOM)
        
        # 绑定快捷键
        self.root.bind("<Control-o>", lambda event: self._select_input_file())
        
        # 设置样式
        style = ttk.Style()
        style.configure('Accent.TButton', font=('SimHei', 12, 'bold'))
        
    def _update_quality_label(self, event=None) -> None:
        """更新质量标签显示"""
        value = self.quality.get()
        self.quality_value_label.config(text=f"{value}%")
        
    def _select_input_file(self, event=None) -> None:
        """选择输入PDF文件"""
        file_path = filedialog.askopenfilename(
            title="选择PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.input_file = file_path
            self.file_path_label.config(text=os.path.basename(file_path))
            self._update_status(f"已选择文件: {os.path.basename(file_path)}")
    
    def _update_status(self, message: str) -> None:
        """更新状态栏消息"""
        self.status_bar.config(text=message)
        self.root.update_idletasks()
    
    def _show_help(self) -> None:
        """显示帮助信息"""
        help_text = """PDF图片压缩工具使用说明:

1. 选择文件:点击"浏览..."按钮选择要压缩的PDF文件
2. 设置质量:使用滑块或预设按钮设置压缩质量
3. 开始压缩:点击"开始压缩"按钮开始处理
4. 保存文件:选择压缩后PDF的保存位置

注意:
- 此工具通过将PDF转换为图片再重新组合来压缩文件
- 压缩质量越低,生成的文件越小,但可能会降低PDF的可读性
- 处理大型PDF文件可能需要较长时间"""
        
        messagebox.showinfo("使用说明", help_text)
    
    def _show_about(self) -> None:
        """显示关于信息"""
        about_text = "PDF图片压缩工具 v1.0\n\n使用Python、PyMuPDF和PIL库开发的PDF压缩应用程序"
        messagebox.showinfo("关于", about_text)
    
    def _get_output_file_path(self) -> Optional[str]:
        """获取输出文件路径"""
        if not self.input_file:
            messagebox.showerror("错误", "请先选择要压缩的PDF文件")
            return None
            
        default_output = os.path.splitext(self.input_file)[0] + "_compressed.pdf"
        output_file = filedialog.asksaveasfilename(
            title="保存压缩后的PDF文件",
            defaultextension=".pdf",
            initialfile=os.path.basename(default_output),
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        
        return output_file if output_file else None
    
    def _get_file_size(self, file_path: str) -> str:
        """获取文件大小的友好显示"""
        size = os.path.getsize(file_path)
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024.0:
                return f"{size:.2f} {unit}"
            size /= 1024.0
        return f"{size:.2f} TB"
    
    def _try_repair_pdf(self, input_path: str) -> Optional[str]:
        """尝试修复损坏的PDF文件"""
        try:
            # 创建临时修复文件
            temp_path = os.path.splitext(input_path)[0] + "_repaired.pdf"
            
            # 尝试打开并保存文件以修复
            with fitz.open(input_path) as doc:
                doc.save(temp_path, garbage=4, deflate=True)
            
            return temp_path
        except Exception as e:
            self._show_detailed_error("修复PDF文件时出错", e)
            return None
    
    def _show_detailed_error(self, title: str, error: Exception) -> None:
        """显示详细的错误信息,包括错误类型和代码行号"""
        # 获取堆栈跟踪信息
        exc_type, exc_value, exc_traceback = sys.exc_info()
        stack_summary = traceback.extract_tb(exc_traceback)
        
        # 提取最相关的错误行信息
        error_line = None
        for frame in reversed(stack_summary):
            if frame.filename.endswith("pdf_image_compressor.py"):
                error_line = frame
                break
        
        # 构建错误消息
        error_message = f"错误类型: {type(error).__name__}\n\n"
        error_message += f"错误信息: {str(error)}\n\n"
        
        if error_line:
            error_message += f"错误位置: 第 {error_line.lineno} 行\n"
            error_message += f"代码: {error_line.line.strip()}\n\n"
            
            # 添加建议的修复方法或相关信息
            if "PIL" in str(error):
                error_message += "提示: 此错误与图像处理有关。请确保已安装Pillow库: pip install pillow"
            elif "PyMuPDF" in str(error):
                error_message += "提示: 此错误与PDF处理有关。请确保已安装PyMuPDF库: pip install pymupdf"
        
        error_message += "\n请复制此错误信息并提供给开发者以获取进一步帮助。"
        
        # 显示错误对话框
        messagebox.showerror(title, error_message)
    
    def _pdf_to_images(self, pdf_path: str, quality: int) -> Tuple[Optional[str], int]:
        """将PDF转换为图片并返回临时文件夹路径"""
        try:
            # 创建临时文件夹
            temp_dir = tempfile.mkdtemp(prefix="pdf_compress_")
            
            # 打开PDF文件
            doc = fitz.open(pdf_path)
            total_pages = len(doc)
            
            # 计算缩放因子
            if quality < 40:  # 低质量
                zoom_x = 1.0  # 水平缩放因子
                zoom_y = 1.0  # 垂直缩放因子
            elif quality < 70:  # 中等质量
                zoom_x = 1.5  # 水平缩放因子
                zoom_y = 1.5  # 垂直缩放因子
            else:  # 高质量
                zoom_x = 2.0  # 水平缩放因子
                zoom_y = 2.0  # 垂直缩放因子
            
            mat = fitz.Matrix(zoom_x, zoom_y)  # 缩放矩阵
            
            # 逐页转换为图片
            for page_num in range(total_pages):
                page = doc.load_page(page_num)
                pix = page.get_pixmap(matrix=mat)
                
                # 构建图片路径
                img_path = os.path.join(temp_dir, f"page_{page_num+1}.jpg")
                
                # 保存图片
                pix.save(img_path)
                
                # 释放资源
                del pix
                
                # 更新状态
                self._update_status(f"正在转换第 {page_num+1}/{total_pages} 页为图片...")
            
            doc.close()
            
            return temp_dir, total_pages
        except Exception as e:
            self._show_detailed_error("将PDF转换为图片时出错", e)
            return None, 0
    
    def _compress_images(self, img_dir: str, total_pages: int, quality: int) -> None:
        """压缩指定目录中的图片"""
        try:
            # 获取所有图片文件
            img_files = sorted(
                [f for f in os.listdir(img_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))],
                key=lambda x: int(x.split('_')[1].split('.')[0])
            )
            
            # 压缩每张图片
            for i, img_file in enumerate(img_files):
                img_path = os.path.join(img_dir, img_file)
                
                # 打开图片
                img = Image.open(img_path)
                
                # 转换为RGB模式(如果不是)
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                
                # 计算目标尺寸
                width, height = img.size
                
                # 根据质量调整尺寸
                if quality < 40:  # 低质量:大幅缩小
                    scale = 0.5
                elif quality < 70:  # 中等质量:适度缩小
                    scale = 0.8
                else:  # 高质量:轻微缩小或不缩小
                    scale = 0.95
                
                new_width = max(100, int(width * scale))
                new_height = max(100, int(height * scale))
                
                # 调整图片尺寸
                img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
                
                # 保存压缩后的图片
                img.save(img_path, quality=quality, optimize=True)
                
                # 释放资源
                img.close()
                
                # 更新状态
                self._update_status(f"正在压缩第 {i+1}/{total_pages} 页图片...")
        
        except Exception as e:
            self._show_detailed_error("压缩图片时出错", e)
            raise
    
    def _images_to_pdf(self, img_dir: str, output_path: str, total_pages: int) -> None:
        """将图片合并为PDF"""
        try:
            # 创建新的PDF文档
            doc = fitz.open()
            
            # 获取所有图片文件
            img_files = sorted(
                [f for f in os.listdir(img_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))],
                key=lambda x: int(x.split('_')[1].split('.')[0])
            )
            
            # 将每张图片添加到PDF
            for i, img_file in enumerate(img_files):
                img_path = os.path.join(img_dir, img_file)
                
                # 获取图片尺寸
                img = Image.open(img_path)
                width, height = img.size
                img.close()
                
                # 添加新页面
                page = doc.new_page(width=width, height=height)
                
                # 在页面上插入图片
                page.insert_image(fitz.Rect(0, 0, width, height), filename=img_path)
                
                # 更新状态
                self._update_status(f"正在合并第 {i+1}/{total_pages} 页到PDF...")
            
            # 保存PDF
            doc.save(output_path)
            doc.close()
        
        except Exception as e:
            self._show_detailed_error("将图片合并为PDF时出错", e)
            raise
    
    def _compress_pdf(self) -> None:
        """压缩PDF文件"""
        # 防止重复处理
        if self.is_processing:
            return
            
        output_file = self._get_output_file_path()
        if not output_file:
            return
            
        try:
            if not self.input_file:
                messagebox.showerror("错误", "请先选择要压缩的PDF文件")
                return
                
            self.is_processing = True
            self.compress_button.config(state=tk.DISABLED)
            self._update_status("正在检查PDF文件...")
            
            # 尝试打开PDF文件,检查是否有错误
            pdf_to_process = self.input_file
            repair_attempted = False
            
            try:
                # 先尝试普通打开
                with fitz.open(self.input_file) as doc:
                    pass
            except Exception as e:
                # 尝试修复PDF
                self._update_status("检测到PDF文件可能损坏,正在尝试修复...")
                pdf_to_process = self._try_repair_pdf(self.input_file)
                repair_attempted = True
                
                if not pdf_to_process:
                    messagebox.showerror("错误", f"无法打开PDF文件: {str(e)}\n\n可能是文件已损坏。")
                    self.is_processing = False
                    self.compress_button.config(state=tk.NORMAL)
                    return
                else:
                    messagebox.showinfo("提示", "已尝试修复PDF文件。将继续处理修复后的版本。")
            
            self._update_status("正在准备压缩PDF文件...")
            
            # 获取原始文件大小
            original_size = self._get_file_size(self.input_file)
            
            # 质量设置
            quality = self.quality.get()
            
            # 1. 将PDF转换为图片
            self._update_status("开始将PDF转换为图片...")
            img_dir, total_pages = self._pdf_to_images(pdf_to_process, quality)
            
            if not img_dir:
                raise Exception("无法创建临时图片文件夹")
            
            # 2. 压缩图片
            self._update_status("开始压缩图片...")
            self._compress_images(img_dir, total_pages, quality)
            
            # 3. 将图片合并为PDF
            self._update_status("开始将图片合并为PDF...")
            self._images_to_pdf(img_dir, output_file, total_pages)
            
            # 删除临时文件夹
            for file_name in os.listdir(img_dir):
                file_path = os.path.join(img_dir, file_name)
                os.remove(file_path)
            os.rmdir(img_dir)
            
            # 删除临时修复文件(如果有)
            if repair_attempted and pdf_to_process != self.input_file:
                os.remove(pdf_to_process)
            
            # 获取压缩后文件大小
            compressed_size = self._get_file_size(output_file)
            
            # 计算压缩比例
            original_bytes = os.path.getsize(self.input_file)
            compressed_bytes = os.path.getsize(output_file)
            reduction_percentage = (1 - compressed_bytes / original_bytes) * 100
            
            result_message = (f"PDF处理完成!\n\n"
                             f"原始大小: {original_size}\n"
                             f"处理后大小: {compressed_size}\n"
                             f"大小变化: {reduction_percentage:.2f}%\n\n"
                             f"文件已保存到: {output_file}")
            
            # 检查是否有实际压缩
            if reduction_percentage < 5:
                result_message += "\n\n注意: 文件大小变化较小,可能是因为PDF中主要是文本内容。"
            
            self._update_status(f"PDF处理完成,文件已保存到: {output_file}")
            messagebox.showinfo("成功", result_message)
            
        except Exception as e:
            # 显示详细的全局错误
            self._show_detailed_error("处理PDF时发生错误", e)
            self._update_status(f"错误: 处理PDF时发生错误: {str(e)}")
        finally:
            # 重置处理状态
            self.is_processing = False
            self.compress_button.config(state=tk.NORMAL)

def main() -> None:
    """主函数"""
    try:
        # 尝试导入必要的库
        import fitz
        from PIL import Image
    except ImportError:
        print("错误: 缺少必要的库。请安装PyMuPDF和Pillow库: pip install pymupdf pillow")
        return
    
    root = tk.Tk()
    app = PDFImageCompressorApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()

五、总结

AI 可以帮助我们做任何事情,只要你能想到。它就像一个无所不能的助手,等待着我们去挖掘它的潜力。这次用 AI 解决打印问题只是一个开始,未来我还会继续探索 AI 在工作和生活中的更多应用。

如果你也有类似的问题,或者想了解更多 AI 的实战经历,欢迎在下方留言关注。让我们一起探索 AI 的世界,利用 AI 工具创造更多的价值,期待与你一起进步!后面我会把PDF压缩的源码放到下载资源里,有需要的可以去下载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI、少年郎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值