change the font size of headings to 40 and the below information to 26 in all slides
~/
~/attachments/fe357a1c-5b51-4c08-918f-5a6e21862651
mkdir -p "/tmp/workspace/pancreatic-cancer-font-update/output" && python -c "from pptx import Presentation; p=Presentation('/tmp/workspace/attachments/fe357a1c-5b51-4c08-918f-5a6e21862651/pancreatic cancer.pptx'); print('slides',len(p.slides));\nfor i,s in enumerate(p.slides,1):\n print('SLIDE',i);\n for j,sh in enumerate(s.shapes,1):\n if getattr(sh,'has_text_frame',False) and sh.text_frame.text.strip():\n print(j,repr(sh.name),repr(sh.text_frame.text[:100]),'pos',round(sh.top/914400,2),'size',round(sh.height/914400,2))"
python -c "from pptx import Presentation; p=Presentation('/tmp/workspace/attachments/fe357a1c-5b51-4c08-918f-5a6e21862651/pancreatic cancer.pptx'); print('slides',len(p.slides)); [print('S',i,'shape',j,repr(sh.name),repr(sh.text_frame.text[:100]),'top',round(sh.top/914400,2),'h',round(sh.height/914400,2),'placeholder',sh.is_placeholder,('type '+str(sh.placeholder_format.type) if sh.is_placeholder else '')) for i,s in enumerate(p.slides,1) for j,sh in enumerate(s.shapes,1) if getattr(sh,'has_text_frame',False) and sh.text_frame.text.strip()]"
~/pancreatic-cancer-font-update/update_fonts.py
from copy import copy
from pathlib import Path
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.util import Pt
SOURCE = Path('/tmp/workspace/attachments/fe357a1c-5b51-4c08-918f-5a6e21862651/pancreatic cancer.pptx')
OUTPUT = Path('/tmp/workspace/pancreatic-cancer-font-update/output/pancreatic cancer_font-updated.pptx')
TITLE_SIZE = Pt(40)
BODY_SIZE = Pt(26)
def iter_text_shapes(shapes):
for shape in shapes:
if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
yield from iter_text_shapes(shape.shapes)
elif getattr(shape, 'has_text_frame', False) and shape.text_frame.text.strip():
yield shape
def set_text_size(shape, size):
for para in shape.text_frame.paragraphs:
for run in para.runs:
run.font.size = size
# Paragraphs with no runs can still carry default text properties.
para.font.size = size
def is_footer(shape):
text = shape.text_frame.text.strip()
return (
'Pancreatic Cancer | Dept. of General Surgery' in text
or text == 'Original schematic for teaching purposes'
or text.isdigit()
)
prs = Presentation(SOURCE)
changed = []
for slide_number, slide in enumerate(prs.slides, start=1):
text_shapes = list(iter_text_shapes(slide.shapes))
non_footer_shapes = [shape for shape in text_shapes if not is_footer(shape)]
if not non_footer_shapes:
continue
# The uppermost main text box is the slide heading. The title slide is also
# handled correctly: its first two institutional lines are introductory text,
# and the actual presentation title is identified explicitly below.
if slide_number == 1:
title_shape = next(
(shape for shape in non_footer_shapes if shape.text_frame.text.strip() == 'Pancreatic Cancer'),
non_footer_shapes[0],
)
else:
title_shape = min(non_footer_shapes, key=lambda shape: (shape.top, shape.left))
set_text_size(title_shape, TITLE_SIZE)
changed.append((slide_number, title_shape.text_frame.text.strip(), 40))
for shape in non_footer_shapes:
if shape is title_shape:
continue
set_text_size(shape, BODY_SIZE)
changed.append((slide_number, shape.text_frame.text.strip(), 26))
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
prs.save(OUTPUT)
print(f'Saved {OUTPUT}')
print(f'Updated {len(changed)} text boxes across {len(prs.slides)} slides')
python "/tmp/workspace/pancreatic-cancer-font-update/update_fonts.py" && python -c "from pptx import Presentation; from collections import Counter; p=Presentation('/tmp/workspace/pancreatic-cancer-font-update/output/pancreatic cancer_font-updated.pptx'); c=Counter();\nfor s in p.slides:\n for sh in s.shapes:\n if getattr(sh,'has_text_frame',False) and sh.text_frame.text.strip():\n for para in sh.text_frame.paragraphs:\n for r in para.runs:\n if r.font.size: c[round(r.font.size.pt,2)]+=1\nprint('slides',len(p.slides),'font_sizes',sorted(c.items()))"
~/pancreatic-cancer-font-update/verify_fonts.py
from pathlib import Path
from pptx import Presentation
path = Path('/tmp/workspace/pancreatic-cancer-font-update/output/pancreatic cancer_font-updated.pptx')
prs = Presentation(path)
assert len(prs.slides) == 35
# Verify all expected heading and content boxes received their intended sizes.
issues = []
checked = 0
for si, slide in enumerate(prs.slides, 1):
for shape in slide.shapes:
if not getattr(shape, 'has_text_frame', False) or not shape.text_frame.text.strip():
continue
txt = shape.text_frame.text.strip()
if 'Pancreatic Cancer | Dept. of General Surgery' in txt or txt == 'Original schematic for teaching purposes' or txt.isdigit():
continue
expected = 40 if (si != 1 and shape.top == min(s.top for s in slide.shapes if getattr(s, 'has_text_frame', False) and s.text_frame.text.strip() and 'Pancreatic Cancer | Dept. of General Surgery' not in s.text_frame.text and s.text_frame.text.strip() != 'Original schematic for teaching purposes' and not s.text_frame.text.strip().isdigit())) or (si == 1 and txt == 'Pancreatic Cancer') else 26
for para in shape.text_frame.paragraphs:
for run in para.runs:
if run.font.size is None or abs(run.font.size.pt - expected) > 0.01:
issues.append((si, txt[:30], expected, None if run.font.size is None else run.font.size.pt))
checked += 1
print(f'Verified {checked} heading/content text boxes in {len(prs.slides)} slides.')
if issues:
raise RuntimeError(f'Font verification failed: {issues[:10]}')
print('All expected heading boxes are 40 pt and all other main information boxes are 26 pt.')
python "/tmp/workspace/pancreatic-cancer-font-update/verify_fonts.py" && ls -lh "/tmp/workspace/pancreatic-cancer-font-update/output/pancreatic cancer_font-updated.pptx"