I want in this format
mkdir -p /tmp/workspace/case-report-poster && ls /tmp/workspace/case-report-poster/
~/case-report-poster/build_poster.py
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from pptx.util import Cm
# A0 landscape poster: 118.9 cm x 84.1 cm
# We'll use a standard wide poster: 33.1" x 23.4" (A1 landscape) — good for medical posters
# Let's use A0 landscape in inches: 46.8" x 33.1"
# Actually let's use a common conference poster: 36" x 48" portrait or 48" x 36" landscape
# The sketch shows PORTRAIT orientation with a top header bar
# Portrait poster: 33.1" wide x 46.8" tall (A0)
W = Inches(33.11)
H = Inches(46.81)
prs = Presentation()
prs.slide_width = W
prs.slide_height = H
slide_layout = prs.slide_layouts[6] # blank
slide = prs.slides.add_slide(slide_layout)
# ── Colors ──────────────────────────────────────────────────────────────────
HEADER_BG = RGBColor(0x2E, 0x4A, 0x7A) # deep navy
COL_BG = RGBColor(0xF4, 0xF7, 0xFF) # very light blue tint
BORDER = RGBColor(0x2E, 0x4A, 0x7A)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
BLACK = RGBColor(0x10, 0x10, 0x10)
HEADING_CLR = RGBColor(0x2E, 0x4A, 0x7A)
SUBHEAD_CLR = RGBColor(0x1A, 0x6A, 0x3A) # dark green for image list
RED_CLR = RGBColor(0xCC, 0x00, 0x00)
LIGHT_GRAY = RGBColor(0xE8, 0xEC, 0xF5)
# ── Layout constants ─────────────────────────────────────────────────────────
margin = Inches(0.5)
gap = Inches(0.25)
# Total usable width
usable_w = W - 2 * margin
# Header height
header_h = Inches(3.0)
# Remaining height for columns
col_top = margin + header_h + gap
col_h = H - col_top - margin
# 3 columns (left | middle | right)
# Left = 35%, Middle = 38%, Right = 27%
col_left_w = usable_w * 0.33
col_mid_w = usable_w * 0.38
col_right_w = usable_w - col_left_w - col_mid_w - 2*gap
col_left_x = margin
col_mid_x = col_left_x + col_left_w + gap
col_right_x = col_mid_x + col_mid_w + gap
# Left column sub-sections
intro_h = col_h * 0.28
case_h = col_h * 0.30
images_h = col_h - intro_h - case_h - 2*gap
# Right column sub-sections
conc_h = col_h * 0.55
ref_h = col_h - conc_h - gap
# ── Helper: add filled rounded rectangle with border ─────────────────────────
from pptx.util import Pt
from pptx.oxml.ns import qn
from lxml import etree
def add_box(slide, x, y, w, h, fill_rgb, border_rgb=None, border_pt=2):
shape = slide.shapes.add_shape(
1, # MSO_SHAPE_TYPE.RECTANGLE = 1
x, y, w, h
)
shape.fill.solid()
shape.fill.fore_color.rgb = fill_rgb
if border_rgb:
shape.line.color.rgb = border_rgb
shape.line.width = Pt(border_pt)
else:
shape.line.fill.background()
return shape
def add_textbox(slide, x, y, w, h, text, font_size=18, bold=False,
color=None, align=PP_ALIGN.LEFT, wrap=True, italic=False):
txb = slide.shapes.add_textbox(x, y, w, h)
tf = txb.text_frame
tf.word_wrap = wrap
p = tf.paragraphs[0]
p.alignment = align
run = p.add_run()
run.text = text
run.font.size = Pt(font_size)
run.font.bold = bold
run.font.italic = italic
if color:
run.font.color.rgb = color
return txb
def add_section_heading(slide, x, y, w, label, font_size=28, bg=HEADER_BG,
text_color=WHITE):
"""Add a filled heading bar."""
bar_h = Inches(0.55)
add_box(slide, x, y, w, bar_h, bg, None)
add_textbox(slide, x + Inches(0.15), y + Inches(0.07),
w - Inches(0.3), bar_h - Inches(0.1),
label, font_size=font_size, bold=True,
color=text_color, align=PP_ALIGN.LEFT)
return bar_h
# ═══════════════════════════════════════════════════════════════════════════════
# 1. HEADER BAR
# ═══════════════════════════════════════════════════════════════════════════════
add_box(slide, margin, margin, usable_w, header_h, HEADER_BG, None)
# Title placeholder
add_textbox(
slide,
margin + Inches(0.4), margin + Inches(0.25),
usable_w - Inches(0.8), Inches(1.6),
"Title of the Case Report",
font_size=54, bold=True, color=WHITE, align=PP_ALIGN.CENTER
)
# Authors placeholder
add_textbox(
slide,
margin + Inches(0.4), margin + Inches(1.9),
usable_w - Inches(0.8), Inches(0.9),
"Author 1¹, Author 2², Author 3³",
font_size=30, bold=False, color=RGBColor(0xCC, 0xDD, 0xFF),
align=PP_ALIGN.CENTER
)
# Institution line (small)
add_textbox(
slide,
margin + Inches(0.4), margin + Inches(2.55),
usable_w - Inches(0.8), Inches(0.35),
"¹Department, Institution | ²Department, Institution | ³Department, Institution",
font_size=18, bold=False, color=RGBColor(0xAA, 0xBB, 0xDD),
align=PP_ALIGN.CENTER
)
# ═══════════════════════════════════════════════════════════════════════════════
# 2. LEFT COLUMN
# ═══════════════════════════════════════════════════════════════════════════════
lx = col_left_x
# 2a INTRODUCTION
add_box(slide, lx, col_top, col_left_w, intro_h, COL_BG, BORDER, 1.5)
bar_h = add_section_heading(slide, lx, col_top, col_left_w, "Introduction")
add_textbox(
slide,
lx + Inches(0.2),
col_top + bar_h + Inches(0.15),
col_left_w - Inches(0.4),
intro_h - bar_h - Inches(0.25),
"Background and context of the case. Briefly state why this case is noteworthy, "
"any relevant epidemiology, and the purpose of this report.",
font_size=20, color=BLACK
)
# 2b CASE PRESENTATION
case_top = col_top + intro_h + gap
add_box(slide, lx, case_top, col_left_w, case_h, COL_BG, BORDER, 1.5)
bar_h2 = add_section_heading(slide, lx, case_top, col_left_w, "Case Presentation")
add_textbox(
slide,
lx + Inches(0.2),
case_top + bar_h2 + Inches(0.15),
col_left_w - Inches(0.4),
case_h - bar_h2 - Inches(0.25),
"Patient demographics, presenting complaint, relevant history, examination findings, "
"investigations, and clinical course. Include key lab values and timeline.",
font_size=20, color=BLACK
)
# 2c IMAGES
img_top = case_top + case_h + gap
add_box(slide, lx, img_top, col_left_w, images_h, LIGHT_GRAY, BORDER, 1.5)
bar_h3 = add_section_heading(slide, lx, img_top, col_left_w, "Images")
# Image list in green
img_items = [
("①", "CXR (Pre-op)"),
("②", "HRCT: compressed trachea slide"),
("③", "Mass"),
("④", "Intubated patient image", "optional"),
("⑤", "Fiberoptic image while intubating patient", "optional"),
]
item_y = img_top + bar_h3 + Inches(0.2)
for item in img_items:
num, label = item[0], item[1]
opt = len(item) == 3
add_textbox(
slide,
lx + Inches(0.2), item_y,
col_left_w - Inches(0.4), Inches(0.6),
f"{num} {label}" + (" [optional]" if opt else ""),
font_size=20, bold=False,
color=SUBHEAD_CLR if not opt else RED_CLR
)
item_y += Inches(0.65)
# placeholder box for each image
if item_y + Inches(2.5) < img_top + images_h - Inches(0.1):
img_box_h = min(Inches(2.2), (img_top + images_h - item_y - Inches(0.15)))
if img_box_h > Inches(0.5):
add_box(
slide,
lx + Inches(0.2), item_y,
col_left_w - Inches(0.4), img_box_h,
WHITE, RGBColor(0xAA, 0xBB, 0xCC), 1
)
add_textbox(
slide,
lx + Inches(0.3), item_y + Inches(0.1),
col_left_w - Inches(0.6), img_box_h - Inches(0.2),
"[ Insert image here ]",
font_size=16, color=RGBColor(0x99, 0x99, 0xAA),
align=PP_ALIGN.CENTER, italic=True
)
item_y += img_box_h + Inches(0.2)
# ═══════════════════════════════════════════════════════════════════════════════
# 3. MIDDLE COLUMN — DISCUSSION
# ═══════════════════════════════════════════════════════════════════════════════
mx = col_mid_x
add_box(slide, mx, col_top, col_mid_w, col_h, COL_BG, BORDER, 1.5)
bar_hm = add_section_heading(slide, mx, col_top, col_mid_w, "Discussion", font_size=32)
add_textbox(
slide,
mx + Inches(0.2),
col_top + bar_hm + Inches(0.2),
col_mid_w - Inches(0.4),
col_h - bar_hm - Inches(0.4),
"Discuss the clinical significance of this case. Compare findings with existing literature. "
"Analyze the diagnostic challenges, management decisions, and outcomes.\n\n"
"Include:\n"
"• Pathophysiology relevant to the case\n"
"• Comparison with published similar cases\n"
"• Rationale for management choices\n"
"• Unusual or educational aspects\n\n"
"[Continue discussion text here...]",
font_size=22, color=BLACK
)
# ═══════════════════════════════════════════════════════════════════════════════
# 4. RIGHT COLUMN
# ═══════════════════════════════════════════════════════════════════════════════
rx = col_right_x
# 4a CONCLUSION
add_box(slide, rx, col_top, col_right_w, conc_h, COL_BG, BORDER, 1.5)
bar_hc = add_section_heading(slide, rx, col_top, col_right_w, "Conclusion", font_size=28)
add_textbox(
slide,
rx + Inches(0.2),
col_top + bar_hc + Inches(0.2),
col_right_w - Inches(0.4),
conc_h - bar_hc - Inches(0.4),
"Summarize the key learning points from this case.\n\n"
"• Main diagnosis and its significance\n"
"• Key management takeaways\n"
"• Contribution to clinical practice\n\n"
"[Conclusion text here...]",
font_size=22, color=BLACK
)
# 4b REFERENCES
ref_top = col_top + conc_h + gap
add_box(slide, rx, ref_top, col_right_w, ref_h, COL_BG, BORDER, 1.5)
bar_hr = add_section_heading(slide, rx, ref_top, col_right_w, "References", font_size=28)
add_textbox(
slide,
rx + Inches(0.2),
ref_top + bar_hr + Inches(0.2),
col_right_w - Inches(0.4),
ref_h - bar_hr - Inches(0.4),
"1. Author A, Author B. Title of article. Journal. Year;Vol(Issue):Pages.\n\n"
"2. Author C, Author D. Title of article. Journal. Year;Vol(Issue):Pages.\n\n"
"3. Author E et al. Title. Journal. Year.\n\n"
"[Add references here...]",
font_size=18, color=BLACK
)
# ── Save ──────────────────────────────────────────────────────────────────────
out = "/tmp/workspace/case-report-poster/CaseReport_Poster.pptx"
prs.save(out)
print(f"Saved: {out}")
python /tmp/workspace/case-report-poster/build_poster.py
CaseReport Poster
Presentation · PPTX