Skip to content

Instantly share code, notes, and snippets.

@KumaTea
Created January 24, 2026 10:01
Show Gist options
  • Select an option

  • Save KumaTea/1468a433aaff9077e4c4011b4baaccd4 to your computer and use it in GitHub Desktop.

Select an option

Save KumaTea/1468a433aaff9077e4c4011b4baaccd4 to your computer and use it in GitHub Desktop.
Shrink PowerPoint Slides (.pptx file) by reducing images size inside
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