analyse_media
Reading File
Here is a detailed analysis of this brain MRI:

Brain MRI Analysis

Sequences Displayed

This is a printed MRI film (from a MEDVISION/Medicare Diagnostics system) showing axial (horizontal) cross-sections arranged in a grid, with two main sequences:
Rows 1-3: FLAIR (Fluid-Attenuated Inversion Recovery)
  • CSF appears dark (suppressed), making pathology stand out as bright white
  • Slices progress from the posterior fossa (brainstem + cerebellum) at the top left through the basal ganglia, lateral ventricles, and up to the cerebral vertex
  • Highly sensitive for detecting edema, demyelination, and ischemic change
Rows 4-6: DWI (Diffusion-Weighted Imaging)
  • Grainier appearance with a darker background
  • Detects acute cytotoxic edema (as in acute ischemic stroke), where restricted diffusion appears bright white

Anatomical Structures

  • Brainstem & cerebellum - visible in the lower-cut slices (top-left); appear intact
  • Basal ganglia & thalami - visible bilaterally in mid-brain slices, symmetric
  • Lateral ventricles - symmetric, normal caliber; no hydrocephalus or midline shift
  • Cerebral cortex - cortical sulci and gyri patterns are visible across all lobes (frontal, temporal, parietal, occipital)

Findings

FLAIR (top 3 rows):
  • Small, scattered areas of mild white matter hyperintensity in the periventricular and deep white matter regions
  • These represent leukoaraiosis - chronic microvascular ischemic changes consistent with small vessel disease (often associated with aging, hypertension, or diabetes)
  • No large mass lesion, no significant surrounding edema, no midline shift
  • Mild age-appropriate cortical sulcal prominence (mild generalized atrophy)
DWI (bottom 3 rows):
  • No obvious focal areas of restricted diffusion - no bright lesions to suggest an acute ischemic stroke
  • Brainstem and cerebellum appear clear on DWI

Overall Impression

FindingAssessment
Acute ischemic strokeNo evidence on DWI
Mass lesion / tumorNot identified
HemorrhageNot visible (T2*/GRE sequence not shown)
White matter changesMild periventricular hyperintensities (small vessel disease)
Ventricular systemNormal size and symmetry
Midline shiftNone
Summary: The MRI shows mild chronic small vessel ischemic disease (leukoaraiosis) on FLAIR without evidence of an acute infarct on DWI. This is a common finding in older adults with vascular risk factors. No space-occupying lesion or acute stroke is identified on these sequences.

Important disclaimer: This is an AI interpretation of a photograph of a printed MRI film - not a formal radiological report. A definitive diagnosis requires a qualified radiologist reviewing original DICOM images alongside the patient's clinical history. Sequences like T1, T2, and post-contrast (gadolinium) images are not shown here and may provide additional information.

Explain changes where and where with pictures

Finding Sources
Finding Sources
Searching the Web

periventricular white matter hyperintensities FLAIR MRI leukoaraiosis location diagram small vessel disease

Loading Image
Loading Image
Loading Image
Finding Sources
Here is a detailed, picture-supported breakdown of the changes found in this MRI and exactly where they are located:

What Changed, and Where

1. White Matter Hyperintensities (WMH) / Leukoaraiosis

What they are: Patches of brain tissue that appear brighter than normal on FLAIR sequences. They represent tiny areas of damage to the white matter - the "wiring" of the brain - caused by chronic reduced blood flow through small arteries.
Where in this MRI: Visible as small bright spots in rows 2 and 3 of the FLAIR sequences, specifically:
  • Around the edges of the lateral ventricles (periventricular region)
  • In the deep white matter of the frontal and parietal lobes
This diagram shows exactly where WMH (pale yellow areas) and related small vessel disease changes sit in a brain cross-section:
Small Vessel Disease brain diagram showing WMH location
  • WMH = the bright white patches seen on FLAIR, located in deep white matter next to the ventricles
  • Lacunes = small old infarcts (not seen in this scan - absent here is reassuring)
  • Perivascular spaces = enlarged fluid-filled spaces around small vessels (may be mildly prominent)

2. How WMH Evolve Over Time

This NIH/PMC diagram explains the dynamic process - how small vessel damage leads to white matter changes, cortical thinning, and downstream effects:
Dynamic mechanisms of WMH and small vessel disease progression
Key takeaway: the periventricular and deep WMH (pale yellow, shown left side of diagram) seen in this MRI can:
  • Remain stable
  • Slowly grow over time with continued vascular risk factors
  • In advanced stages, cause thinning of overlying cortex

3. What the Two Sequences Show Side by Side

Location in BrainFLAIR (rows 1-3)DWI (rows 4-6)
Periventricular white matterSmall bright patches = chronic WMHNo bright signal = NOT an acute stroke
Deep white matterMild scattered hyperintensitiesNormal/dark = no restriction
Brainstem / cerebellumStructurally normalNormal
Lateral ventriclesMildly prominent; dark CSF = normal suppressionNormal
CortexMild sulcal widening (mild atrophy)Normal

4. What Causes These Changes

The small bright patches appear because of chronic hypoperfusion (reduced blood flow) to the white matter from:
Risk FactorEffect
HypertensionThickens/stiffens small arterial walls
DiabetesDamages endothelial lining of small vessels
AgeArteries naturally stiffen over time
SmokingPromotes atherosclerosis in small vessels
The white matter is particularly vulnerable because it sits in a "watershed zone" - at the furthest reach of small penetrating arteries with no collateral blood supply backup.

Summary of Findings in Plain Language

  • The FLAIR rows show small white spots near the ventricles and in the deep brain white matter - these are old, chronic, non-emergency changes
  • The DWI rows are essentially normal - no bright spots means no fresh stroke
  • The changes are consistent with mild small vessel disease, likely from cardiovascular risk factors
  • No tumor, no active stroke, no bleed visible on these sequences
This MRI analysis is educational. A formal radiological report from a qualified radiologist reviewing the original DICOM files remains essential for clinical decisions.

Create a summary PDF with labeled MRI diagrams explaining WMH locations

Reading File
Running Command

mkdir -p /tmp/workspace/wmh-pdf/images && cd /tmp/workspace/wmh-pdf/images && curl -s -o svd_diagram.jpg "https://prod-images-static.radiopaedia.org/images/65745315/082337e05e6ac11db3fe272cdf455711bcca4a12f65bae8eef3336a6156c4b9f_gallery.jpeg" && curl -s -o wmh_progression.jpg "https://cdn.ncbi.nlm.nih.gov/pmc/blobs/cb49/4599520/9722c1d7f2db/jah30004-e001140-f3.jpg" && curl -s -o patient_mri.jpg "https://d361swluvexzqs.cloudfront.net/chats-attachments/photo-1784127210054-1784127210698-04ouvh.jpg" && ls -lh

Writing File

~/wmh-pdf/build_pdf.py


import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
    HRFlowable, PageBreak, KeepTogether
)
from reportlab.graphics.shapes import Drawing, Rect, String, Circle, Line, Ellipse, Arrow
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Group
from PIL import Image as PILImage
import io

BASE = "/tmp/workspace/wmh-pdf"
OUT  = os.path.join(BASE, "WMH_Brain_MRI_Summary.pdf")

# ── Colour palette ─────────────────────────────────────────────────────────
NAVY      = colors.HexColor("#1a2a4a")
BLUE      = colors.HexColor("#2e5fa3")
LIGHTBLUE = colors.HexColor("#d6e4f7")
TEAL      = colors.HexColor("#1d7874")
ORANGE    = colors.HexColor("#e07b39")
YELLOW    = colors.HexColor("#f5c842")
RED       = colors.HexColor("#c0392b")
WHITE     = colors.white
GRAY      = colors.HexColor("#666666")
LIGHTGRAY = colors.HexColor("#f2f4f7")
DARKGRAY  = colors.HexColor("#333333")

W, H = A4   # 595.27 x 841.89

# ── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def style(name, **kw):
    s = ParagraphStyle(name, **kw)
    return s

H1 = style("H1", fontSize=26, fontName="Helvetica-Bold", textColor=NAVY,
           spaceAfter=6, spaceBefore=4, alignment=TA_CENTER)
H2 = style("H2", fontSize=16, fontName="Helvetica-Bold", textColor=BLUE,
           spaceAfter=4, spaceBefore=12)
H3 = style("H3", fontSize=12, fontName="Helvetica-Bold", textColor=NAVY,
           spaceAfter=3, spaceBefore=8)
BODY = style("BODY", fontSize=10, fontName="Helvetica", textColor=DARKGRAY,
             spaceAfter=4, leading=15, alignment=TA_JUSTIFY)
CAPTION = style("CAPTION", fontSize=8.5, fontName="Helvetica-Oblique",
                textColor=GRAY, spaceAfter=6, alignment=TA_CENTER)
BULLET = style("BULLET", fontSize=10, fontName="Helvetica", textColor=DARKGRAY,
               spaceAfter=3, leading=15, leftIndent=14, bulletIndent=4)
LABEL_ST = style("LABEL", fontSize=8, fontName="Helvetica-Bold",
                 textColor=WHITE, alignment=TA_CENTER)
DISCLAIMER = style("DISCLAIMER", fontSize=8, fontName="Helvetica-Oblique",
                   textColor=GRAY, alignment=TA_CENTER, spaceAfter=4)
SUBTITLE = style("SUBTITLE", fontSize=12, fontName="Helvetica",
                 textColor=BLUE, alignment=TA_CENTER, spaceAfter=6)
FINDING_TITLE = style("FT", fontSize=11, fontName="Helvetica-Bold",
                      textColor=NAVY, spaceAfter=2)

# ── Helper: fit image keeping aspect ratio ──────────────────────────────────
def fit_image(path, max_w, max_h):
    with PILImage.open(path) as im:
        iw, ih = im.size
    ratio = min(max_w / iw, max_h / ih)
    return Image(path, width=iw * ratio, height=ih * ratio)

# ── Helper: coloured badge ──────────────────────────────────────────────────
def badge(text, bg=BLUE, fg=WHITE, w=120, h=18):
    d = Drawing(w, h)
    d.add(Rect(0, 0, w, h, rx=4, ry=4, fillColor=bg, strokeColor=None))
    d.add(String(w/2, 4, text, fontName="Helvetica-Bold", fontSize=9,
                 fillColor=fg, textAnchor="middle"))
    return d

# ── Annotated brain cross-section drawing ───────────────────────────────────
def brain_cross_section_drawing(dw=480, dh=320):
    """Draw a schematic axial brain cross-section with WMH labels."""
    d = Drawing(dw, dh)
    cx, cy = dw / 2, dh / 2 + 10

    # skull outline
    d.add(Ellipse(cx, cy, 200, 160,
                  fillColor=colors.HexColor("#e8e0d0"),
                  strokeColor=colors.HexColor("#9e8c70"), strokeWidth=3))

    # brain parenchyma
    d.add(Ellipse(cx, cy, 185, 148,
                  fillColor=colors.HexColor("#d8cfc0"),
                  strokeColor=colors.HexColor("#b0a090"), strokeWidth=1.5))

    # gray matter rim
    d.add(Ellipse(cx, cy, 185, 148,
                  fillColor=None,
                  strokeColor=colors.HexColor("#c0a080"), strokeWidth=8))

    # white matter zone (inner)
    d.add(Ellipse(cx, cy, 148, 118,
                  fillColor=colors.HexColor("#ede8df"),
                  strokeColor=colors.HexColor("#c8bfb0"), strokeWidth=1))

    # lateral ventricles (left)
    d.add(Ellipse(cx - 42, cy + 8, 28, 14,
                  fillColor=colors.HexColor("#7fb8d4"),
                  strokeColor=colors.HexColor("#5a9ab8"), strokeWidth=1.5))
    # lateral ventricles (right)
    d.add(Ellipse(cx + 42, cy + 8, 28, 14,
                  fillColor=colors.HexColor("#7fb8d4"),
                  strokeColor=colors.HexColor("#5a9ab8"), strokeWidth=1.5))
    # third ventricle
    d.add(Rect(cx - 5, cy - 5, 10, 22,
               fillColor=colors.HexColor("#7fb8d4"),
               strokeColor=colors.HexColor("#5a9ab8"), strokeWidth=1))

    # ── WMH patches (periventricular) ──────────────────────────────────────
    wmh_positions = [
        (cx - 70, cy + 18, 18, 10),  # left periventricular anterior
        (cx - 72, cy - 10, 14, 9),   # left periventricular posterior
        (cx + 52, cy + 18, 18, 10),  # right periventricular anterior
        (cx + 55, cy - 8, 14, 9),    # right periventricular posterior
    ]
    for (ex, ey, ew, eh) in wmh_positions:
        d.add(Ellipse(ex, ey, ew, eh,
                      fillColor=colors.HexColor("#fffacd"),
                      strokeColor=YELLOW, strokeWidth=1.5))

    # ── Deep white matter WMH ─────────────────────────────────────────────
    deep_wmh = [
        (cx - 110, cy + 25, 12, 7),
        (cx + 100, cy - 20, 10, 6),
        (cx - 90,  cy - 30, 10, 6),
    ]
    for (ex, ey, ew, eh) in deep_wmh:
        d.add(Ellipse(ex, ey, ew, eh,
                      fillColor=colors.HexColor("#fff0a0"),
                      strokeColor=ORANGE, strokeWidth=1.2))

    # ── Basal ganglia ────────────────────────────────────────────────────
    d.add(Ellipse(cx - 28, cy - 5, 18, 12,
                  fillColor=colors.HexColor("#b8a898"),
                  strokeColor=colors.HexColor("#908070"), strokeWidth=1))
    d.add(Ellipse(cx + 28, cy - 5, 18, 12,
                  fillColor=colors.HexColor("#b8a898"),
                  strokeColor=colors.HexColor("#908070"), strokeWidth=1))

    # ── Annotations with lines ──────────────────────────────────────────
    anno_font = "Helvetica-Bold"
    anno_small = "Helvetica"

    def annotate(x1, y1, x2, y2, text, sub="", col=NAVY):
        d.add(Line(x1, y1, x2, y2, strokeColor=col, strokeWidth=1.2))
        d.add(Circle(x1, y1, 3, fillColor=col, strokeColor=None))
        d.add(String(x2 + 4, y2 - 2, text, fontName=anno_font,
                     fontSize=8.5, fillColor=col))
        if sub:
            d.add(String(x2 + 4, y2 - 13, sub, fontName=anno_small,
                         fontSize=7.5, fillColor=GRAY))

    # Ventricles label
    annotate(cx - 42, cy + 8, cx - 42, cy + 68, "Lateral Ventricle", "(CSF - dark on FLAIR)", col=colors.HexColor("#2a7aac"))

    # Periventricular WMH label
    annotate(cx - 72, cy + 18, cx - 165, cy + 55,
             "Periventricular WMH", "(bright spots on FLAIR)", col=colors.HexColor("#b8860b"))

    # Deep WMH label
    annotate(cx - 110, cy + 25, cx - 195, cy - 5,
             "Deep White Matter WMH", "(scattered bright foci)", col=ORANGE)

    # White matter label
    annotate(cx, cy - 85, cx + 60, cy - 105,
             "White Matter", "(myelinated axons)", col=GRAY)

    # Cortex label
    annotate(cx + 155, cy + 20, cx + 200, cy + 60,
             "Cortex / Gray Matter", "(normal)", col=colors.HexColor("#6b8e23"))

    # Basal ganglia
    annotate(cx + 28, cy - 5, cx + 160, cy - 35,
             "Basal Ganglia", "(normal)", col=GRAY)

    # Legend boxes at bottom
    lx, ly = 30, 12
    # WMH periventricular
    d.add(Rect(lx, ly, 14, 10, fillColor=colors.HexColor("#fffacd"),
               strokeColor=YELLOW, strokeWidth=1.5))
    d.add(String(lx + 18, ly + 2, "Periventricular WMH",
                 fontName="Helvetica", fontSize=7.5, fillColor=DARKGRAY))
    # WMH deep
    d.add(Rect(lx + 145, ly, 14, 10, fillColor=colors.HexColor("#fff0a0"),
               strokeColor=ORANGE, strokeWidth=1.2))
    d.add(String(lx + 163, ly + 2, "Deep White Matter WMH",
                 fontName="Helvetica", fontSize=7.5, fillColor=DARKGRAY))
    # Ventricle
    d.add(Rect(lx + 320, ly, 14, 10, fillColor=colors.HexColor("#7fb8d4"),
               strokeColor=colors.HexColor("#5a9ab8"), strokeWidth=1.5))
    d.add(String(lx + 338, ly + 2, "CSF / Ventricle",
                 fontName="Helvetica", fontSize=7.5, fillColor=DARKGRAY))

    return d

# ── Fazekas scale drawing ────────────────────────────────────────────────────
def fazekas_drawing(dw=480, dh=110):
    """Illustrate the 3-grade Fazekas scale for WMH severity."""
    d = Drawing(dw, dh)
    labels = ["Grade 0\nNo WMH", "Grade 1\nPunctate\n(Mild)", "Grade 2\nBeginning\nConfluence\n(Moderate)", "Grade 3\nLarge\nConfluent\n(Severe)"]
    wmh_counts = [0, 1, 3, 6]
    wmh_large  = [False, False, True, True]
    box_w = 100
    gap = 20
    start_x = (dw - (4 * box_w + 3 * gap)) / 2

    for i, (label, wcount, wlarge) in enumerate(zip(labels, wmh_counts, wmh_large)):
        bx = start_x + i * (box_w + gap)
        by = 28
        # brain oval
        d.add(Ellipse(bx + box_w/2, by + 36, 40, 32,
                      fillColor=colors.HexColor("#d8cfc0"),
                      strokeColor=colors.HexColor("#b0a090"), strokeWidth=1.5))
        # ventricle
        d.add(Ellipse(bx + box_w/2 - 10, by + 38, 10, 6,
                      fillColor=colors.HexColor("#7fb8d4"),
                      strokeColor=None))
        d.add(Ellipse(bx + box_w/2 + 10, by + 38, 10, 6,
                      fillColor=colors.HexColor("#7fb8d4"),
                      strokeColor=None))
        # draw WMH patches
        wmh_locs = [
            (bx + box_w/2 - 22, by + 42),
            (bx + box_w/2 + 18, by + 42),
            (bx + box_w/2 - 30, by + 28),
            (bx + box_w/2 + 24, by + 28),
            (bx + box_w/2 - 20, by + 28),
            (bx + box_w/2 + 12, by + 55),
        ]
        size = 9 if wlarge else 5
        for j in range(wcount):
            lx2, ly2 = wmh_locs[j]
            d.add(Ellipse(lx2, ly2, size, size * 0.6,
                          fillColor=YELLOW,
                          strokeColor=ORANGE, strokeWidth=0.8))
        # label
        col = [GRAY, colors.HexColor("#8B7000"), ORANGE, RED][i]
        d.add(Rect(bx + 5, 4, box_w - 10, 18, rx=3, ry=3,
                   fillColor=col, strokeColor=None))
        for li, lline in enumerate(label.split("\n")):
            d.add(String(bx + box_w/2, 79 - li * 9, lline,
                         fontName="Helvetica-Bold", fontSize=7.5,
                         fillColor=WHITE, textAnchor="middle"))

    return d

# ── FLAIR vs DWI comparison drawing ─────────────────────────────────────────
def flair_dwi_drawing(dw=480, dh=170):
    d = Drawing(dw, dh)
    cx1 = 120
    cx2 = 360
    cy = 100

    for cx, label, bg, wmh_col, wmh_bright, csf_col, title_col, title in [
        (cx1, "FLAIR", colors.HexColor("#0a1a3a"), colors.HexColor("#fffacd"),
         True, colors.HexColor("#0a1a3a"), colors.HexColor("#5599dd"), "FLAIR Sequence"),
        (cx2, "DWI",   colors.HexColor("#050e1f"), colors.HexColor("#050e1f"),
         False, colors.HexColor("#101828"), colors.HexColor("#44aacc"), "DWI Sequence"),
    ]:
        # background circle (MRI dark background)
        d.add(Ellipse(cx, cy, 88, 72,
                      fillColor=bg, strokeColor=colors.HexColor("#222244"),
                      strokeWidth=2))
        # brain parenchyma
        d.add(Ellipse(cx, cy, 76, 62,
                      fillColor=colors.HexColor("#1e3a5a") if label == "FLAIR" else colors.HexColor("#0d2035"),
                      strokeColor=None))
        # gray matter rim brighter
        d.add(Ellipse(cx, cy, 76, 62,
                      fillColor=None,
                      strokeColor=colors.HexColor("#4a7ab8") if label == "FLAIR" else colors.HexColor("#2a4a6a"),
                      strokeWidth=6))
        # ventricles - dark on FLAIR, dark on DWI
        d.add(Ellipse(cx - 18, cy + 4, 12, 7,
                      fillColor=colors.HexColor("#050e1f"),
                      strokeColor=None))
        d.add(Ellipse(cx + 18, cy + 4, 12, 7,
                      fillColor=colors.HexColor("#050e1f"),
                      strokeColor=None))
        # WMH patches - bright on FLAIR, dark/absent on DWI
        wmh_spots = [(cx - 30, cy + 8), (cx + 22, cy + 8),
                     (cx - 38, cy - 8), (cx + 32, cy - 6)]
        spot_col = colors.HexColor("#fffacd") if wmh_bright else colors.HexColor("#1a2a3a")
        spot_stroke = ORANGE if wmh_bright else colors.HexColor("#1a2a3a")
        for (sx, sy) in wmh_spots:
            d.add(Ellipse(sx, sy, 8, 5,
                          fillColor=spot_col,
                          strokeColor=spot_stroke, strokeWidth=0.8))

        # title bar
        d.add(Rect(cx - 80, cy + 82, 160, 20, rx=4, ry=4,
                   fillColor=title_col, strokeColor=None))
        d.add(String(cx, cy + 88, title,
                     fontName="Helvetica-Bold", fontSize=10,
                     fillColor=WHITE, textAnchor="middle"))

    # Arrow between them
    d.add(Line(210, cy, 270, cy, strokeColor=BLUE, strokeWidth=2))
    d.add(String(240, cy + 6, "compare", fontName="Helvetica", fontSize=8,
                 fillColor=BLUE, textAnchor="middle"))

    # Labels below FLAIR
    d.add(String(cx1, cy - 90, "WMH = BRIGHT (chronic)",
                 fontName="Helvetica-Bold", fontSize=8.5,
                 fillColor=colors.HexColor("#c8a800"), textAnchor="middle"))
    d.add(String(cx1, cy - 102, "Ventricles = DARK (suppressed)",
                 fontName="Helvetica", fontSize=7.5,
                 fillColor=colors.HexColor("#8899aa"), textAnchor="middle"))

    # Labels below DWI
    d.add(String(cx2, cy - 90, "No acute infarct (no bright spots)",
                 fontName="Helvetica-Bold", fontSize=8.5,
                 fillColor=colors.HexColor("#44cc88"), textAnchor="middle"))
    d.add(String(cx2, cy - 102, "Normal = all dark/uniform",
                 fontName="Helvetica", fontSize=7.5,
                 fillColor=colors.HexColor("#8899aa"), textAnchor="middle"))

    return d


# ── Build document ───────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUT,
    pagesize=A4,
    leftMargin=2*cm, rightMargin=2*cm,
    topMargin=2.2*cm, bottomMargin=2*cm,
    title="Brain MRI – White Matter Hyperintensities Summary",
    author="Orris Medical AI"
)

story = []

# ═══════════════════════════════════════════════════════════════════════
# PAGE 1 – COVER
# ═══════════════════════════════════════════════════════════════════════

# Top colour bar
story.append(HRFlowable(width="100%", thickness=8, color=NAVY, spaceAfter=10))

story.append(Paragraph("Brain MRI Analysis Report", H1))
story.append(Paragraph("White Matter Hyperintensities (WMH) – Location & Clinical Significance", SUBTITLE))
story.append(HRFlowable(width="100%", thickness=2, color=BLUE, spaceAfter=16))

# Key info box
info_data = [
    [Paragraph("<b>Imaging Modality</b>", BODY), Paragraph("MRI Brain – FLAIR + DWI sequences", BODY)],
    [Paragraph("<b>Primary Finding</b>", BODY), Paragraph("Mild periventricular & deep white matter hyperintensities", BODY)],
    [Paragraph("<b>Clinical Significance</b>", BODY), Paragraph("Chronic small vessel ischemic disease (leukoaraiosis)", BODY)],
    [Paragraph("<b>Acute Finding</b>", BODY), Paragraph("None – No restricted diffusion on DWI (no acute stroke)", BODY)],
    [Paragraph("<b>Report Date</b>", BODY), Paragraph("July 15, 2026", BODY)],
]
info_table = Table(info_data, colWidths=[5*cm, 11*cm])
info_table.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (0, -1), LIGHTBLUE),
    ("BACKGROUND", (1, 0), (1, -1), colors.HexColor("#f8faff")),
    ("TEXTCOLOR", (0, 0), (-1, -1), DARKGRAY),
    ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
    ("FONTSIZE", (0, 0), (-1, -1), 10),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#c0ccdd")),
    ("ROWBACKGROUNDS", (0, 0), (-1, -1), [LIGHTBLUE, colors.HexColor("#f8faff")]),
    ("TOPPADDING", (0, 0), (-1, -1), 7),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
    ("LEFTPADDING", (0, 0), (-1, -1), 10),
    ("ROUNDEDCORNERS", [4]),
]))
story.append(info_table)
story.append(Spacer(1, 0.5*cm))

# Patient MRI thumbnail on cover
story.append(Paragraph("Patient MRI Film", H3))
story.append(fit_image("/tmp/workspace/wmh-pdf/images/patient_mri.jpg", 14*cm, 11*cm))
story.append(Paragraph(
    "Figure 1. Original patient MRI film (MEDVISION). Top three rows: FLAIR sequence showing "
    "white matter hyperintensities. Bottom three rows: DWI sequence with no evidence of acute infarction.",
    CAPTION
))

story.append(HRFlowable(width="100%", thickness=1, color=LIGHTBLUE, spaceBefore=8, spaceAfter=6))
story.append(Paragraph(
    "DISCLAIMER: This report is generated by Orris AI for educational purposes only. It does not constitute "
    "a formal radiological diagnosis. All clinical decisions must be made by a qualified physician reviewing "
    "original DICOM images alongside patient history.",
    DISCLAIMER
))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════════
# PAGE 2 – WHAT ARE WMH? + LABELED DIAGRAM
# ═══════════════════════════════════════════════════════════════════════

story.append(HRFlowable(width="100%", thickness=5, color=NAVY, spaceAfter=8))
story.append(Paragraph("1. What Are White Matter Hyperintensities?", H2))

story.append(Paragraph(
    "White Matter Hyperintensities (WMH), also called <b>leukoaraiosis</b>, are areas of the brain "
    "that appear abnormally bright (hyperintense) on FLAIR and T2-weighted MRI sequences. They represent "
    "damage to the white matter – the deep brain tissue made up of myelinated nerve fibers (axons) that "
    "connect different brain regions.", BODY))

story.append(Paragraph(
    "WMH are extremely common in older adults and in patients with cardiovascular risk factors. "
    "They are a hallmark of <b>cerebral small vessel disease (SVD)</b> – chronic damage to the "
    "tiny arteries (arterioles) that supply the deep brain white matter.", BODY))

# Two-column bullet table
bullet_data = [
    [Paragraph("<b>Location in the Brain</b>", H3), Paragraph("<b>What They Represent</b>", H3)],
    [
        Paragraph(
            "• <b>Periventricular</b> – immediately surrounding the lateral ventricles<br/>"
            "• <b>Deep white matter</b> – frontal, parietal, temporal lobes<br/>"
            "• <b>Subcortical</b> – just beneath the cortex<br/>"
            "• <b>Infratentorial</b> – brainstem, cerebellum (less common)", BULLET),
        Paragraph(
            "• Demyelination (loss of myelin sheath around axons)<br/>"
            "• Axonal loss and gliosis (scar tissue formation)<br/>"
            "• Enlarged perivascular spaces<br/>"
            "• Chronic ischemia from small artery thickening", BULLET)
    ],
]
btable = Table(bullet_data, colWidths=[8*cm, 8*cm])
btable.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, 0), NAVY),
    ("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
    ("BACKGROUND", (0, 1), (0, 1), colors.HexColor("#eef4ff")),
    ("BACKGROUND", (1, 1), (1, 1), colors.HexColor("#fff8ee")),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#c0ccdd")),
    ("TOPPADDING", (0, 0), (-1, -1), 8),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 8),
    ("LEFTPADDING", (0, 0), (-1, -1), 8),
    ("VALIGN", (0, 0), (-1, -1), "TOP"),
]))
story.append(btable)
story.append(Spacer(1, 0.4*cm))

story.append(Paragraph("Labeled Brain Cross-Section – WMH Locations", H3))
story.append(brain_cross_section_drawing(480, 320))
story.append(Paragraph(
    "Figure 2. Schematic axial cross-section of the brain showing the two main locations of WMH: "
    "periventricular (immediately adjacent to the lateral ventricles, shown in pale yellow) and "
    "deep white matter (scattered foci, shown in orange-yellow). The lateral ventricles appear "
    "blue (CSF). Basal ganglia are shown in gray.",
    CAPTION
))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════════
# PAGE 3 – FLAIR vs DWI + FAZEKAS SCALE
# ═══════════════════════════════════════════════════════════════════════

story.append(HRFlowable(width="100%", thickness=5, color=NAVY, spaceAfter=8))
story.append(Paragraph("2. How WMH Look on MRI – FLAIR vs DWI", H2))

story.append(Paragraph(
    "Two key sequences are used to characterise WMH and distinguish them from acute pathology:", BODY))

story.append(flair_dwi_drawing(480, 170))
story.append(Paragraph(
    "Figure 3. Schematic comparison of FLAIR (left) and DWI (right) appearances. "
    "On FLAIR, WMH appear as bright (hyperintense) foci; ventricles are dark. "
    "On DWI, the same WMH are dark – absence of bright signal confirms no acute stroke.",
    CAPTION
))
story.append(Spacer(1, 0.3*cm))

seq_data = [
    [Paragraph("<b>Sequence</b>", LABEL_ST), Paragraph("<b>WMH Appearance</b>", LABEL_ST),
     Paragraph("<b>Why It Matters</b>", LABEL_ST)],
    [Paragraph("FLAIR", BODY), Paragraph("Bright / hyperintense", BODY),
     Paragraph("Best for detecting WMH, periventricular halos, subcortical lesions", BODY)],
    [Paragraph("DWI", BODY), Paragraph("Dark / isointense", BODY),
     Paragraph("Normal DWI confirms lesions are CHRONIC, not an acute stroke", BODY)],
    [Paragraph("T1", BODY), Paragraph("Dark / hypointense", BODY),
     Paragraph("Old lacunar infarcts appear as black holes on T1", BODY)],
    [Paragraph("T2", BODY), Paragraph("Bright / hyperintense", BODY),
     Paragraph("Shows same changes as FLAIR but with CSF also bright (less contrast)", BODY)],
]
seq_table = Table(seq_data, colWidths=[3*cm, 4.5*cm, 8.5*cm])
seq_table.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, 0), NAVY),
    ("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
    ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.HexColor("#f8faff"), WHITE]),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#c0ccdd")),
    ("TOPPADDING", (0, 0), (-1, -1), 7),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
    ("LEFTPADDING", (0, 0), (-1, -1), 8),
    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
    ("FONTSIZE", (0, 0), (-1, -1), 9.5),
    ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(seq_table)
story.append(Spacer(1, 0.5*cm))

story.append(Paragraph("3. Grading WMH Severity – Fazekas Scale", H2))
story.append(Paragraph(
    "The <b>Fazekas scale</b> is the most widely used system to grade WMH severity on MRI. "
    "This patient's scan shows Grade 1-2 changes (mild-to-moderate punctate/beginning confluence).", BODY))

story.append(fazekas_drawing(480, 110))
story.append(Paragraph(
    "Figure 4. Schematic Fazekas grading scale for WMH severity. Yellow foci = WMH patches. "
    "Grade 0 = normal; Grade 1 = punctate foci (mild); Grade 2 = beginning confluence (moderate); "
    "Grade 3 = large confluent areas (severe). This patient's scan corresponds to Grade 1-2.",
    CAPTION
))

story.append(Spacer(1, 0.4*cm))

# Reference diagram from Radiopaedia
story.append(Paragraph("Reference: Small Vessel Disease Brain Anatomy", H3))
story.append(fit_image("/tmp/workspace/wmh-pdf/images/svd_diagram.jpg", 10*cm, 8*cm))
story.append(Paragraph(
    "Figure 5. Anatomical diagram (Radiopaedia) illustrating features of cerebral small vessel disease "
    "including WMH location, lacunes, microbleeds, and perivascular spaces in an axial brain cross-section. "
    "This patient's scan shows WMH only (no lacunes, no microbleeds identified on available sequences).",
    CAPTION
))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════════
# PAGE 4 – CAUSES, CLINICAL SIGNIFICANCE, MANAGEMENT
# ═══════════════════════════════════════════════════════════════════════

story.append(HRFlowable(width="100%", thickness=5, color=NAVY, spaceAfter=8))
story.append(Paragraph("4. Causes and Risk Factors", H2))

causes_data = [
    [Paragraph("<b>Risk Factor</b>", LABEL_ST),
     Paragraph("<b>Mechanism</b>", LABEL_ST),
     Paragraph("<b>Effect on White Matter</b>", LABEL_ST)],
    [Paragraph("Hypertension", BODY),
     Paragraph("Arteriolosclerosis – thickening/stiffening of small artery walls", BODY),
     Paragraph("Reduced perfusion to deep white matter watershed zones", BODY)],
    [Paragraph("Diabetes mellitus", BODY),
     Paragraph("Endothelial dysfunction; glycation of vessel walls", BODY),
     Paragraph("Microangiopathy; accelerated small vessel damage", BODY)],
    [Paragraph("Age (>60 years)", BODY),
     Paragraph("Natural stiffening of arteries (arteriosclerosis)", BODY),
     Paragraph("Progressive ischemic white matter rarefaction", BODY)],
    [Paragraph("Hyperlipidaemia", BODY),
     Paragraph("Lipid deposits in arterial walls", BODY),
     Paragraph("Promotes atheromatous change in small vessels", BODY)],
    [Paragraph("Smoking", BODY),
     Paragraph("Oxidative stress; vasospasm; accelerated atherosclerosis", BODY),
     Paragraph("Worsens all above mechanisms", BODY)],
    [Paragraph("Atrial fibrillation", BODY),
     Paragraph("Microemboli from cardiac source", BODY),
     Paragraph("Small embolic infarcts appear as WMH", BODY)],
]
causes_table = Table(causes_data, colWidths=[3.5*cm, 6.5*cm, 6*cm])
causes_table.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, 0), TEAL),
    ("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
    ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.HexColor("#f0faf8"), WHITE]),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#aacccc")),
    ("TOPPADDING", (0, 0), (-1, -1), 7),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
    ("LEFTPADDING", (0, 0), (-1, -1), 8),
    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
    ("FONTSIZE", (0, 0), (-1, -1), 9),
    ("VALIGN", (0, 0), (-1, -1), "TOP"),
]))
story.append(causes_table)
story.append(Spacer(1, 0.5*cm))

story.append(Paragraph("5. Clinical Significance", H2))
story.append(Paragraph(
    "WMH are not merely incidental findings – they carry important clinical implications, "
    "especially when moderate to severe:", BODY))

sig_items = [
    ("<b>Cognitive impairment:</b>", "WMH disrupt white matter tracts connecting frontal-subcortical circuits. "
     "Moderate-severe WMH are associated with slowed processing speed, executive dysfunction, and vascular dementia."),
    ("<b>Stroke risk:</b>", "WMH independently increase future stroke risk (both ischemic and hemorrhagic). "
     "Presence of WMH roughly doubles stroke risk."),
    ("<b>Gait disturbance:</b>", "Periventricular WMH affecting motor tracts can cause small-stepped gait and falls."),
    ("<b>Mood disorders:</b>", "Deep white matter lesions are associated with late-onset depression ('vascular depression')."),
    ("<b>Bladder dysfunction:</b>", "Frontal WMH can cause urinary urgency/incontinence by interrupting inhibitory pathways."),
]
for title_text, body_text in sig_items:
    story.append(Paragraph(f"{title_text} {body_text}", BULLET))

story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("6. Management Recommendations", H2))

mgmt_data = [
    [Paragraph("<b>Goal</b>", LABEL_ST), Paragraph("<b>Action</b>", LABEL_ST)],
    [Paragraph("Control hypertension", BODY),
     Paragraph("Target BP <130/80 mmHg; first-line agents: ACE inhibitor or ARB", BODY)],
    [Paragraph("Manage diabetes", BODY),
     Paragraph("HbA1c <7%; GLP-1 agonists have additional vascular benefit", BODY)],
    [Paragraph("Statin therapy", BODY),
     Paragraph("If dyslipidaemia present; LDL-C <1.8 mmol/L in high-risk patients", BODY)],
    [Paragraph("Antiplatelet therapy", BODY),
     Paragraph("Aspirin 75-100 mg/day if cerebrovascular disease confirmed", BODY)],
    [Paragraph("Lifestyle modification", BODY),
     Paragraph("Smoking cessation, aerobic exercise, Mediterranean diet", BODY)],
    [Paragraph("Cognitive monitoring", BODY),
     Paragraph("Annual cognitive screening (MoCA); neuropsychology if symptomatic", BODY)],
    [Paragraph("Follow-up MRI", BODY),
     Paragraph("Repeat MRI in 2-3 years to monitor WMH progression", BODY)],
]
mgmt_table = Table(mgmt_data, colWidths=[4.5*cm, 11.5*cm])
mgmt_table.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, 0), NAVY),
    ("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
    ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.HexColor("#f8faff"), WHITE]),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#c0ccdd")),
    ("TOPPADDING", (0, 0), (-1, -1), 7),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
    ("LEFTPADDING", (0, 0), (-1, -1), 8),
    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
    ("FONTSIZE", (0, 0), (-1, -1), 9.5),
    ("VALIGN", (0, 0), (-1, -1), "TOP"),
]))
story.append(mgmt_table)

story.append(Spacer(1, 0.5*cm))
story.append(HRFlowable(width="100%", thickness=1, color=LIGHTBLUE, spaceAfter=6))

# WMH progression diagram
story.append(Paragraph("7. How WMH Progress Over Time", H2))
story.append(fit_image("/tmp/workspace/wmh-pdf/images/wmh_progression.jpg", 13*cm, 9*cm))
story.append(Paragraph(
    "Figure 6. Dynamic progression model of WMH and small vessel disease (Wardlaw et al., JAH 2015). "
    "Periventricular and deep WMH (pale yellow) can increase, occasionally shrink, and lead to atrophy "
    "of overlying cortex (blue). Acute small subcortical infarcts (white) may cavitate, persist as WMH caps, "
    "or cause downstream white matter tract damage.",
    CAPTION
))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════════
# PAGE 5 – SUMMARY FINDINGS TABLE + KEY MESSAGES
# ═══════════════════════════════════════════════════════════════════════

story.append(HRFlowable(width="100%", thickness=5, color=NAVY, spaceAfter=8))
story.append(Paragraph("8. Summary of MRI Findings – This Patient", H2))

summary_data = [
    [Paragraph("<b>Brain Region</b>", LABEL_ST),
     Paragraph("<b>Sequence</b>", LABEL_ST),
     Paragraph("<b>Finding</b>", LABEL_ST),
     Paragraph("<b>Significance</b>", LABEL_ST)],
    [Paragraph("Periventricular white matter", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("Small bright hyperintensities adjacent to lateral ventricles", BODY),
     Paragraph("Chronic small vessel disease", BODY)],
    [Paragraph("Deep white matter\n(frontal/parietal)", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("Scattered mild hyperintense foci", BODY),
     Paragraph("Chronic microvascular ischemia", BODY)],
    [Paragraph("Lateral ventricles", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("Normal size, symmetric; CSF correctly dark", BODY),
     Paragraph("No hydrocephalus", BODY)],
    [Paragraph("Cerebral hemispheres", BODY),
     Paragraph("DWI", BODY),
     Paragraph("No restricted diffusion (no bright areas)", BODY),
     Paragraph("No acute ischemic stroke", BODY)],
    [Paragraph("Brainstem/cerebellum", BODY),
     Paragraph("FLAIR + DWI", BODY),
     Paragraph("Structurally intact; no focal lesion", BODY),
     Paragraph("Normal posterior fossa", BODY)],
    [Paragraph("Cortex / sulci", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("Mild sulcal widening (age-appropriate)", BODY),
     Paragraph("Mild diffuse cortical atrophy", BODY)],
    [Paragraph("Basal ganglia / thalami", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("No focal signal change", BODY),
     Paragraph("Normal deep grey matter", BODY)],
    [Paragraph("Midline structures", BODY),
     Paragraph("FLAIR", BODY),
     Paragraph("No shift; corpus callosum intact", BODY),
     Paragraph("No mass effect", BODY)],
]
summary_table = Table(summary_data, colWidths=[4*cm, 2.5*cm, 6*cm, 3.5*cm])
summary_table.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, 0), NAVY),
    ("TEXTCOLOR", (0, 0), (-1, 0), WHITE),
    ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.HexColor("#fff9e6"), WHITE]),
    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#c0ccdd")),
    ("TOPPADDING", (0, 0), (-1, -1), 6),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
    ("LEFTPADDING", (0, 0), (-1, -1), 6),
    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
    ("FONTSIZE", (0, 0), (-1, -1), 8.5),
    ("VALIGN", (0, 0), (-1, -1), "TOP"),
]))
story.append(summary_table)
story.append(Spacer(1, 0.5*cm))

story.append(Paragraph("Key Clinical Messages", H2))
key_msgs = [
    ("No emergency finding.", "There is no acute stroke, hemorrhage, tumor, or midline shift on this scan."),
    ("Chronic vascular change.", "The WMH represent cumulative damage from long-standing small vessel disease – "
     "not a new event."),
    ("Modifiable risk factors.", "Most causes of WMH (hypertension, diabetes, smoking) are treatable. "
     "Aggressive risk factor control can slow progression."),
    ("Cognitive vigilance.", "Even mild WMH warrant monitoring for early cognitive or gait changes."),
    ("Follow-up imaging.", "A repeat MRI in 2-3 years is recommended to track WMH evolution "
     "and ensure no new lesions develop."),
]
for num, (msg_title, msg_body) in enumerate(key_msgs, 1):
    d = Drawing(480, 38)
    d.add(Rect(0, 4, 480, 32, rx=5, ry=5,
               fillColor=LIGHTBLUE if num % 2 == 0 else colors.HexColor("#fff8e8"),
               strokeColor=BLUE, strokeWidth=0.5))
    d.add(Rect(0, 4, 8, 32, rx=0, ry=0,
               fillColor=BLUE if num % 2 == 0 else ORANGE, strokeColor=None))
    d.add(String(20, 24, f"{num}. {msg_title}", fontName="Helvetica-Bold",
                 fontSize=9.5, fillColor=NAVY))
    d.add(String(20, 11, msg_body, fontName="Helvetica",
                 fontSize=8.5, fillColor=DARKGRAY))
    story.append(d)
    story.append(Spacer(1, 2))

story.append(Spacer(1, 0.6*cm))
story.append(HRFlowable(width="100%", thickness=2, color=NAVY, spaceAfter=8))
story.append(Paragraph(
    "References: Wardlaw JM et al. (2013) Neuroimaging standards for research into small vessel disease. "
    "Lancet Neurol 12(8):822-38. | Fazekas F et al. (1987) CT and MRI rating of white matter lesions. "
    "AJNR 8(2):421-6. | Hachinski V et al. (1987) Leukoaraiosis. Arch Neurol 44(1):21-3.",
    DISCLAIMER
))
story.append(Paragraph(
    "DISCLAIMER: This document is generated by Orris AI for educational/informational purposes only. "
    "It is NOT a substitute for formal radiological reporting by a qualified radiologist. "
    "Clinical decisions must be based on complete clinical assessment.",
    DISCLAIMER
))

doc.build(story)
print(f"PDF saved to: {OUT}")
Running Command

cd /tmp/workspace/wmh-pdf && python build_pdf.py 2>&1

Editing File

~/wmh-pdf/build_pdf.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/wmh-pdf/build_pdf.py'
Running Command

cd /tmp/workspace/wmh-pdf && python build_pdf.py 2>&1

Running Command

ls -lh /tmp/workspace/wmh-pdf/WMH_Brain_MRI_Summary.pdf

Your PDF is ready (945 KB, 5 pages):

WMH Brain MRI Summary

PDF Document · PDF


Here's what's inside the 5-page report:
PageContent
1 – CoverSummary info table + your original patient MRI film
2 – What are WMH?Custom labeled brain cross-section diagram showing periventricular vs. deep white matter WMH locations, with annotated anatomy
3 – FLAIR vs DWI + Fazekas ScaleSchematic comparison of how WMH appear on each sequence; Fazekas grading illustrations (Grade 0-3); reference SVD anatomy diagram
4 – Causes & ManagementDetailed tables covering risk factors (hypertension, diabetes, etc.), clinical significance (cognition, stroke risk, gait), and management recommendations
5 – Findings Table + Key MessagesComplete findings by brain region; 5 highlighted key clinical takeaway panels
This is a shared conversation. Sign in to Orris to start your own chat.