吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 155|回复: 13
收起左侧

[经验求助] PPT文件太大,求免费瘦身大法

[复制链接]
jeanshmily 发表于 2026-6-5 09:34
25吾爱币
本帖最后由 jeanshmily 于 2026-6-5 09:54 编辑

企业简介宣传文件,一百多兆的文件,求大神指导免费的文件瘦身!
穷打工牛马,冲不起VIP
感激不尽!在线等
PS:因为文件随时会编辑更改变动,格式最好能保留PPT原本文件格式

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

shanxue2021 发表于 2026-6-5 09:51
可以采取转成图、降低图片分辨率,再合并的方法。
 楼主| jeanshmily 发表于 2026-6-5 09:53
shanxue2021 发表于 2026-6-5 09:51
可以采取转成图、降低图片分辨率,再合并的方法。

因为文件随时会编辑更改变动,格式最好能保留PPT原本文件格式
shzjz123 发表于 2026-6-5 09:59
shzjz123 发表于 2026-6-5 10:07
AI编写了个程序,500多M压缩到20多M
shzjz123 发表于 2026-6-5 10:19
[Python] 纯文本查看 复制代码
#!/usr/bin/env python3
"""
PPT 瘦身 GUI 工具
可调节 JPEG 压缩质量 (1-100),限制图片最大边长(分辨率),
并选择性删除音视频,显著减小文件体积。
"""

import os
import sys
import shutil
import tempfile
import zipfile
import threading
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

try:
    from PIL import Image
except ImportError:
    # 如果缺少 Pillow,给出友好提示并退出
    root = tk.Tk()
    root.withdraw()
    messagebox.showerror("缺少依赖", "请先安装 Pillow 库:\npip install Pillow")
    sys.exit(1)


# 支持的图片类型
IMAGE_EXT = {'.jpg', '.jpeg', '.png'}
MEDIA_EXT = {'.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.mp3', '.wav', '.m4a', '.aac'}


def compress_image(img_path, quality=85, max_dimension=None):
    """
    压缩单张图片,若新图片更小则替换原文件。
    返回 (是否成功, 原大小, 新大小)
    """
    orig_size = os.path.getsize(img_path)
    try:
        with Image.open(img_path) as img:
            # 缩放
            if max_dimension and (img.width > max_dimension or img.height > max_dimension):
                ratio = max_dimension / max(img.width, img.height)
                new_w = int(img.width * ratio)
                new_h = int(img.height * ratio)
                img.thumbnail((new_w, new_h), Image.Resampling.LANCZOS)

            ext = os.path.splitext(img_path)[1].lower()
            save_kwargs = {}
            fmt = None
            if ext in ('.jpg', '.jpeg'):
                if img.mode in ('RGBA', 'P'):
                    img = img.convert('RGB')
                save_kwargs = {'quality': quality, 'optimize': True, 'subsampling': 2}
                fmt = 'JPEG'
            elif ext == '.png':
                save_kwargs = {'optimize': True, 'compress_level': 6}
                fmt = 'PNG'
            else:
                return False, orig_size, orig_size

            # 临时保存
            with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as tmp:
                img.save(tmp, format=fmt, **save_kwargs)
                tmp_path = tmp.name
            new_size = os.path.getsize(tmp_path)
            if new_size < orig_size:
                shutil.move(tmp_path, img_path)
                return True, orig_size, new_size
            else:
                os.unlink(tmp_path)
                return False, orig_size, orig_size
    except Exception as e:
        print(f"压缩失败 {img_path}: {e}")
        return False, orig_size, orig_size


def slim_pptx(input_path, output_path, quality, max_dim, remove_media, progress_callback=None):
    """
    执行 PPTX 瘦身,支持进度回调 progress_callback(percent, message)
    """
    if not os.path.isfile(input_path):
        raise FileNotFoundError(f"文件不存在: {input_path}")

    with tempfile.TemporaryDirectory() as tmpdir:
        # 解压
        if progress_callback:
            progress_callback(5, "正在解压 PPTX...")
        with zipfile.ZipFile(input_path, 'r') as zf:
            zf.extractall(tmpdir)

        # 收集 media 文件
        media_files = []
        for root, _, files in os.walk(tmpdir):
            if os.path.basename(root) == 'media':
                for f in files:
                    media_files.append(os.path.join(root, f))

        images = [p for p in media_files if os.path.splitext(p)[1].lower() in IMAGE_EXT]
        total_images = len(images)

        # 压缩图片
        saved_bytes = 0
        for idx, img_path in enumerate(images):
            if progress_callback:
                percent = 10 + int(80 * idx / total_images) if total_images > 0 else 90
                progress_callback(percent, f"压缩图片 {idx+1}/{total_images}")
            success, old_sz, new_sz = compress_image(img_path, quality, max_dim)
            if success:
                saved_bytes += (old_sz - new_sz)

        # 删除媒体
        if remove_media:
            to_remove = [p for p in media_files if os.path.splitext(p)[1].lower() in MEDIA_EXT]
            for r in to_remove:
                os.unlink(r)
            if progress_callback:
                progress_callback(90, f"已删除 {len(to_remove)} 个音视频文件")

        # 重新打包
        if progress_callback:
            progress_callback(95, "正在重新打包 PPTX...")
        with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as new_zip:
            # mimetype 必须未压缩且为第一项
            mt = os.path.join(tmpdir, 'mimetype')
            if os.path.exists(mt):
                new_zip.write(mt, 'mimetype', compress_type=zipfile.ZIP_STORED)
            for root, _, files in os.walk(tmpdir):
                for f in files:
                    full = os.path.join(root, f)
                    arc = os.path.relpath(full, tmpdir)
                    if arc == 'mimetype':
                        continue
                    new_zip.write(full, arc, compress_type=zipfile.ZIP_DEFLATED)

        if progress_callback:
            progress_callback(100, "瘦身完成!")
        return saved_bytes


class PPTXCompressorApp:
    def __init__(self, root):
        self.root = root
        root.title("PPT 瘦身工具 - 可调压缩/分辨率")
        root.geometry("500x450")
        root.resizable(False, False)

        # 变量
        self.input_file = tk.StringVar()
        self.output_file = tk.StringVar()
        self.quality = tk.IntVar(value=75)
        self.max_dim = tk.IntVar(value=1920)
        self.remove_media = tk.BooleanVar(value=False)

        # 界面布局
        # 输入文件
        tk.Label(root, text="原始 PPTX 文件:").grid(row=0, column=0, padx=10, pady=10, sticky='e')
        tk.Entry(root, textvariable=self.input_file, width=40).grid(row=0, column=1, padx=5)
        tk.Button(root, text="浏览...", command=self.browse_input).grid(row=0, column=2, padx=5)

        # 输出文件
        tk.Label(root, text="输出 PPTX 文件:").grid(row=1, column=0, padx=10, pady=5, sticky='e')
        tk.Entry(root, textvariable=self.output_file, width=40).grid(row=1, column=1, padx=5)
        tk.Button(root, text="另存为...", command=self.browse_output).grid(row=1, column=2, padx=5)

        # 压缩质量滑块
        tk.Label(root, text="JPEG 压缩质量 (1~100):").grid(row=2, column=0, padx=10, pady=5, sticky='e')
        quality_scale = tk.Scale(root, from_=1, to=100, orient=tk.HORIZONTAL,
                                 variable=self.quality, length=200)
        quality_scale.grid(row=2, column=1, padx=5, pady=5, sticky='w')
        self.quality_label = tk.Label(root, text="75")
        self.quality_label.grid(row=2, column=2, padx=5, sticky='w')
        quality_scale.configure(command=lambda v: self.quality_label.config(text=str(int(float(v)))))

        # 最大边长(分辨率限制)
        tk.Label(root, text="图片最大边长(像素):").grid(row=3, column=0, padx=10, pady=5, sticky='e')
        dim_spin = tk.Spinbox(root, from_=100, to=10000, increment=100,
                              textvariable=self.max_dim, width=8)
        dim_spin.grid(row=3, column=1, padx=5, pady=5, sticky='w')
        tk.Label(root, text="(0 表示不限制)").grid(row=3, column=2, padx=5, sticky='w')
        # 限制0表示不限制
        # 删除媒体选项
        tk.Checkbutton(root, text="删除所有音视频文件(注意:将无法播放)",
                       variable=self.remove_media).grid(row=4, column=0, columnspan=3, pady=10, sticky='w', padx=20)

        # 开始按钮
        self.start_btn = tk.Button(root, text="开始瘦身", command=self.start_slim,
                                   bg="#4CAF50", fg="white", font=("", 12, "bold"))
        self.start_btn.grid(row=5, column=0, columnspan=3, pady=20)

        # 进度条
        self.progress = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=400, mode='determinate')
        self.progress.grid(row=6, column=0, columnspan=3, pady=10, padx=20)

        # 状态信息
        self.status_var = tk.StringVar(value="就绪")
        tk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor='w').grid(
            row=7, column=0, columnspan=3, sticky='ew', padx=10, pady=10)

        # 帮助提示
        tk.Label(root, text="提示:降低质量或限制最大边长可大幅减小体积,缩放对高分辨率照片效果最明显。",
                 fg="gray", font=("", 9)).grid(row=8, column=0, columnspan=3, pady=5)

    def browse_input(self):
        filename = filedialog.askopenfilename(filetypes=[("PowerPoint 文件", "*.pptx")])
        if filename:
            self.input_file.set(filename)
            # 自动生成输出文件名
            base, ext = os.path.splitext(filename)
            self.output_file.set(f"{base}_瘦身后{ext}")

    def browse_output(self):
        filename = filedialog.asksaveasfilename(defaultextension=".pptx", filetypes=[("PowerPoint 文件", "*.pptx")])
        if filename:
            self.output_file.set(filename)

    def start_slim(self):
        input_path = self.input_file.get().strip()
        out_path = self.output_file.get().strip()
        if not input_path or not os.path.isfile(input_path):
            messagebox.showerror("错误", "请选择有效的 PPTX 文件")
            return
        if not out_path:
            messagebox.showerror("错误", "请指定输出文件路径")
            return
        if input_path == out_path:
            messagebox.showerror("错误", "输入和输出文件不能相同,请另存为新文件")
            return

        quality = self.quality.get()
        max_dim = self.max_dim.get()
        if max_dim == 0:
            max_dim = None
        remove = self.remove_media.get()

        # 禁止重复点击
        self.start_btn.config(state=tk.DISABLED)
        self.progress['value'] = 0
        self.status_var.set("正在处理...")

        # 在新线程中执行瘦身,避免界面卡死
        def task():
            try:
                saved = slim_pptx(
                    input_path, out_path, quality, max_dim, remove,
                    progress_callback=self.update_progress
                )
                self.root.after(0, lambda: self.on_finish(True, saved, out_path))
            except Exception as e:
                self.root.after(0, lambda: self.on_finish(False, 0, str(e)))

        thread = threading.Thread(target=task)
        thread.daemon = True
        thread.start()

    def update_progress(self, percent, message):
        self.root.after(0, lambda: self._update_gui(percent, message))

    def _update_gui(self, percent, message):
        self.progress['value'] = percent
        self.status_var.set(message)

    def on_finish(self, success, saved_bytes, extra):
        self.start_btn.config(state=tk.NORMAL)
        if success:
            # 计算节省的 MB
            saved_mb = saved_bytes / (1024 * 1024)
            msg = f"瘦身完成!\n总共节省 {saved_mb:.2f} MB\n输出文件:{extra}"
            messagebox.showinfo("完成", msg)
            self.status_var.set(f"完成,节省 {saved_mb:.2f} MB")
        else:
            messagebox.showerror("错误", f"瘦身失败:\n{extra}")
            self.status_var.set("失败")


if __name__ == "__main__":
    root = tk.Tk()
    app = PPTXCompressorApp(root)
    root.mainloop()

安装依赖pip install Pillow 可调图片分辨率
 楼主| jeanshmily 发表于 2026-6-5 10:29
shzjz123 发表于 2026-6-5 10:19
[mw_shl_code=python,true]#!/usr/bin/env python3
"""
PPT 瘦身 GUI 工具

大佬!如何使用
readboys 发表于 2026-6-5 11:11
图片尺寸太大了, 根据需要,不求人的方法用魔术手吧图片尺寸控制在1024x786.或者800x600,同时降低下分辨率,在保证画质的前提下适当裁剪
acepilot 发表于 2026-6-5 11:53
首先要知道根源,文件体积通常是嵌入视频、音频、图片、字体而增大的
所以,压缩体积的思路就是压缩源文件
例如图片,嵌入照片的话原始分辨率可能是4608*3466(或更大)
编辑的时候也是要更改尺寸的,那就用photoshop等编辑软件先更改到ppt实际需要的尺寸(例如800*600)再插入
视频、音频等也同样的思路
nue12138 发表于 2026-6-5 11:54
你的这个PPT,是图片多吗。有视频吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-6-6 09:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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