Created
January 24, 2026 10:01
-
-
Save KumaTea/1468a433aaff9077e4c4011b4baaccd4 to your computer and use it in GitHub Desktop.
Shrink PowerPoint Slides (.pptx file) by reducing images size inside
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import io | |
| import zipfile | |
| from PIL import Image | |
| from tqdm import tqdm | |
| QUALITY = 50 # Adjust as needed: 1–95 | |
| def shrink_image(data, filename, prt=print): | |
| """Shrink JPEG/PNG binary data using Pillow.""" | |
| try: | |
| img = Image.open(io.BytesIO(data)) | |
| out = io.BytesIO() | |
| if filename.lower().endswith(".png"): | |
| # Convert PNG to PNG with lower quality by reducing dimensions OR using optimize | |
| # Pillow has no 'quality' for PNG, so we use optimize=True | |
| img.save(out, format="PNG", optimize=True) | |
| elif filename.lower().endswith(".jpeg") or filename.lower().endswith(".jpg"): | |
| # JPEG quality reduction | |
| img.save(out, format="JPEG", quality=QUALITY, optimize=True) | |
| else: | |
| raise RuntimeError | |
| out_bytes = out.getvalue() | |
| shrink_pct = 100 - len(out_bytes)/len(data)*100 | |
| shrink_size_kb = (len(data) - len(out_bytes)) / 1000 | |
| to_shrink = (shrink_pct > 10) or (shrink_size_kb > 100) | |
| if to_shrink: | |
| prt(f"{filename}: shrunk {len(data)/1000:.2f} → {len(out_bytes)/1000:.2f} KB ({100 - len(out_bytes)/len(data)*100:.1f}%)") | |
| return out_bytes | |
| else: | |
| prt(f"{filename}: shrunk {len(data)/1000:.2f} → {len(out_bytes)/1000:.2f} KB ({100 - len(out_bytes)/len(data)*100:.1f}%), using original...") | |
| return data | |
| except Exception as e: | |
| prt(f"Skipping {filename}: {e}") | |
| return data | |
| def slim_pptx(input_pptx): | |
| """Create a slimmed version of a PPTX with resized images.""" | |
| output_pptx = input_pptx.replace(".pptx", "_slim.pptx") | |
| pbar = None | |
| with zipfile.ZipFile(input_pptx, 'r') as zin, \ | |
| zipfile.ZipFile(output_pptx, 'w', zipfile.ZIP_DEFLATED) as zout: | |
| items = zin.infolist() | |
| shrinkable = [item for item in items if (item.filename.startswith("ppt/media/") and item.filename.lower().endswith((".jpg", ".jpeg", ".png")))] | |
| if not shrinkable: | |
| exit('Nothing to shrink!') | |
| pbar = tqdm(shrinkable) | |
| for item in zin.infolist(): | |
| filedata = zin.read(item.filename) | |
| # Only target ppt/media/*.jpg / .jpeg / .png | |
| if item.filename.startswith("ppt/media/") and \ | |
| item.filename.lower().endswith((".jpg", ".jpeg", ".png")): | |
| pbar.set_description(f"Shrinking: {item.filename}") | |
| filedata = shrink_image(filedata, item.filename, pbar.write) | |
| pbar.update(1) | |
| zout.writestr(item, filedata) | |
| # if pbar: | |
| # prt = pbar.write | |
| # else: | |
| # prt = print | |
| prt = pbar.write # guaranteed | |
| prt(f"\nDone! Slim PPTX saved as: {output_pptx}") | |
| if __name__ == "__main__": | |
| import sys | |
| if len(sys.argv) < 2: | |
| print("Usage: python shrink.py input.pptx") | |
| exit(1) | |
| slim_pptx(sys.argv[1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment