Im studying first year mbbs in India and for my final exams is anatomy of ear a likely question
first year MBBS anatomy important questions India university exam ear
https://firstranker.com/mbbs/mbbs-1st-year-anatomy-important…
| Question Type | Specific Topic |
|---|---|
| Short note / SAQ | Middle ear cavity - walls, contents, relations |
| Short note | Eustachian tube - structure, function, applied |
| Short note | Fenestra vestibule (oval window) |
| Short note | Bones of middle ear cavity (ossicles) |
| Essay / LAQ | Describe the middle ear with applied aspects |
Create a quick revision PDF on middle ear anatomy with labeled diagrams
mkdir -p /home/daytona/workspace/middle-ear-pdf && ls /home/daytona/workspace/middle-ear-pdf
cd /home/daytona/workspace/middle-ear-pdf && curl -s -o img1_parts.png "https://cdn.orris.care/cdss_images/8d7c405d48086f622cb49511d1c2f3874fe6840f500dada64d7054bd1cc7c1ed.png" && curl -s -o img2_walls.png "https://cdn.orris.care/cdss_images/3f25fcd981595d37ee90bfe520844a48e971e7ca7558712253053105fef6b839.png" && echo "Images downloaded" && ls -lh *.png
~/middle-ear-pdf/build_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib.colors import HexColor, white, black
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Flowable
import os
# ─── Paths ───────────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/middle-ear-pdf/Middle_Ear_Anatomy_Revision.pdf"
IMG1 = "/home/daytona/workspace/middle-ear-pdf/img1_parts.png"
IMG2 = "/home/daytona/workspace/middle-ear-pdf/img2_walls.png"
# ─── Colours ─────────────────────────────────────────────────────────────────
C_DARK_BLUE = HexColor("#1a3a5c")
C_MID_BLUE = HexColor("#2e6da4")
C_LIGHT_BLUE = HexColor("#d6e8f7")
C_ACCENT = HexColor("#e8734a")
C_HIGHLIGHT = HexColor("#fff4cc")
C_GREEN = HexColor("#2e7d32")
C_GREEN_BG = HexColor("#e8f5e9")
C_RED_BG = HexColor("#fce4ec")
C_RED = HexColor("#c62828")
C_GREY_LINE = HexColor("#cccccc")
C_BANNER_BG = HexColor("#1a3a5c")
# ─── Document setup ───────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Middle Ear Anatomy - Quick Revision",
author="Orris Medical"
)
W, H = A4
BODY_W = W - 3.6*cm
styles = getSampleStyleSheet()
# Custom styles
def make_style(name, parent='Normal', **kwargs):
s = ParagraphStyle(name, parent=styles[parent], **kwargs)
return s
TITLE_S = make_style('DocTitle',
fontSize=26, textColor=white, alignment=TA_CENTER,
fontName='Helvetica-Bold', spaceAfter=4, leading=30)
SUBTITLE_S = make_style('DocSubtitle',
fontSize=13, textColor=HexColor("#d6e8f7"), alignment=TA_CENTER,
fontName='Helvetica', spaceAfter=2)
H1 = make_style('H1',
fontSize=14, textColor=white, fontName='Helvetica-Bold',
spaceBefore=14, spaceAfter=4, leading=18,
backColor=C_MID_BLUE, leftIndent=-6, rightIndent=-6,
borderPad=5)
H2 = make_style('H2',
fontSize=12, textColor=C_DARK_BLUE, fontName='Helvetica-Bold',
spaceBefore=10, spaceAfter=3, leading=16,
borderPad=0)
H3 = make_style('H3',
fontSize=10.5, textColor=C_MID_BLUE, fontName='Helvetica-Bold',
spaceBefore=6, spaceAfter=2, leading=14)
BODY = make_style('Body',
fontSize=9.5, textColor=HexColor("#222222"), fontName='Helvetica',
spaceBefore=2, spaceAfter=2, leading=14, alignment=TA_JUSTIFY)
BULLET = make_style('Bullet',
fontSize=9.5, textColor=HexColor("#222222"), fontName='Helvetica',
spaceBefore=1, spaceAfter=1, leading=13,
leftIndent=14, bulletIndent=4, bulletFontName='Helvetica',
bulletFontSize=10)
CAPTION = make_style('Caption',
fontSize=8.5, textColor=HexColor("#555555"), fontName='Helvetica-Oblique',
alignment=TA_CENTER, spaceBefore=3, spaceAfter=6)
MEMONIC = make_style('Mnemonic',
fontSize=10, textColor=C_GREEN, fontName='Helvetica-Bold',
alignment=TA_CENTER, spaceBefore=4, spaceAfter=4, leading=14)
CLINICAL = make_style('Clinical',
fontSize=9.5, textColor=C_RED, fontName='Helvetica',
spaceBefore=1, spaceAfter=1, leading=13, leftIndent=10)
# ─── Custom Flowables ────────────────────────────────────────────────────────
class ColorBox(Flowable):
"""Coloured banner with title text."""
def __init__(self, text, bg=C_DARK_BLUE, fg=white, height=60, font_size=22):
super().__init__()
self.text = text
self.bg = bg
self.fg = fg
self._h = height
self._fs = font_size
def wrap(self, aW, aH):
self._w = aW
return (aW, self._h)
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.rect(0, 0, self._w, self._h, fill=1, stroke=0)
c.setFillColor(self.fg)
c.setFont('Helvetica-Bold', self._fs)
c.drawCentredString(self._w / 2, self._h / 2 - self._fs / 3 + 2, self.text)
class SectionHeader(Flowable):
def __init__(self, text, color=C_MID_BLUE, width=None):
super().__init__()
self.text = text
self.color = color
self._req_w = width
def wrap(self, aW, aH):
self._w = self._req_w or aW
return (self._w, 22)
def draw(self):
c = self.canv
c.setFillColor(self.color)
c.rect(0, 0, self._w, 20, fill=1, stroke=0)
c.setFillColor(white)
c.setFont('Helvetica-Bold', 11)
c.drawString(8, 5, self.text)
class HighlightBox(Flowable):
"""Coloured info box."""
def __init__(self, paragraphs, bg=C_HIGHLIGHT, border=C_ACCENT, pad=8):
super().__init__()
self.paragraphs = paragraphs
self.bg = bg
self.border = border
self.pad = pad
def wrap(self, aW, aH):
self._w = aW
total_h = self.pad * 2
for p in self.paragraphs:
w, h = p.wrap(aW - self.pad*2, aH)
total_h += h + 3
self._h = total_h
return (aW, total_h)
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.setStrokeColor(self.border)
c.setLineWidth(1.5)
c.roundRect(0, 0, self._w, self._h, 5, fill=1, stroke=1)
y = self._h - self.pad
for p in self.paragraphs:
pw, ph = p.wrap(self._w - self.pad*2, 9999)
y -= ph
p.drawOn(c, self.pad, y)
y -= 3
def bp(text):
return Paragraph(f"<bullet>•</bullet> {text}", BULLET)
def bold(text, color=C_DARK_BLUE):
return f'<font color="{color.hexval() if hasattr(color,"hexval") else color}" name="Helvetica-Bold">{text}</font>'
# ─── Build story ─────────────────────────────────────────────────────────────
story = []
# ══════════════════════════════════════════════════════════════
# COVER / TITLE BANNER
# ══════════════════════════════════════════════════════════════
story.append(ColorBox("MIDDLE EAR ANATOMY", bg=C_DARK_BLUE, fg=white, height=80, font_size=26))
story.append(Spacer(1, 0.2*cm))
story.append(ColorBox("Quick Revision Notes | 1st Year MBBS", bg=C_MID_BLUE, fg=white, height=30, font_size=12))
story.append(Spacer(1, 0.5*cm))
# Exam focus box
ef_style = make_style('EF', fontSize=9.5, textColor=C_DARK_BLUE,
fontName='Helvetica', leading=14, spaceAfter=2)
story.append(HighlightBox([
Paragraph("<b>EXAM HIGH-YIELD TOPICS:</b> Middle ear cavity (6 walls, contents) | "
"Tympanic membrane | Ossicles | Eustachian tube | Facial nerve course | "
"Blood & nerve supply | Applied anatomy", ef_style)
], bg=C_LIGHT_BLUE, border=C_MID_BLUE))
story.append(Spacer(1, 0.3*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 1 – OVERVIEW
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("1. OVERVIEW OF THE MIDDLE EAR"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The <b>middle ear (tympanic cavity)</b> is an air-filled, mucous membrane-lined space "
"within the petrous part of the temporal bone. It lies between the tympanic membrane "
"laterally and the lateral wall of the internal ear medially.",
BODY))
story.append(Paragraph("<b>Two parts:</b>", H3))
data = [
[bold("Part"), bold("Location"), bold("Contents")],
["Tympanic cavity proper\n(Mesotympanum)", "Adjacent to tympanic\nmembrane", "Ossicles, chorda tympani"],
["Epitympanic recess\n(Attic / Epitympanum)", "Superior to tympanic\nmembrane", "Head of malleus, body of\nincus, aditus to mastoid"],
]
t = Table(data, colWidths=[5*cm, 5*cm, 5*cm])
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('BACKGROUND', (0,1), (-1,1), C_LIGHT_BLUE),
('BACKGROUND', (0,2), (-1,2), white),
('GRID', (0,0), (-1,-1), 0.5, C_GREY_LINE),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(t)
story.append(Spacer(1, 0.3*cm))
# Communications
story.append(Paragraph("<b>Communications of the middle ear:</b>", H3))
comms = [
("Anteriorly", "Eustachian (pharyngotympanic) tube → nasopharynx"),
("Posteriorly", "Aditus → mastoid antrum → mastoid air cells"),
("Laterally", "Tympanic membrane → external auditory meatus"),
("Medially", "Internal ear (oval window, round window)"),
]
for loc, desc in comms:
story.append(bp(f"<b>{loc}:</b> {desc}"))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# DIAGRAM 1
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("2. LABELED DIAGRAM — Parts of the Middle Ear (Gray's Anatomy for Students)"))
story.append(Spacer(1, 0.2*cm))
img1 = Image(IMG1, width=9*cm, height=11*cm, kind='proportional')
img1.hAlign = 'CENTER'
story.append(img1)
story.append(Paragraph(
"Fig. 1 Coronal section showing the parts of the middle ear — external acoustic meatus, "
"tympanic membrane, ossicular chain (malleus, incus, stapes), oval window, "
"internal ear, epitympanic recess, and pharyngotympanic tube.",
CAPTION))
story.append(Spacer(1, 0.3*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 3 – SIX WALLS
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("3. THE SIX WALLS OF THE TYMPANIC CAVITY"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
'Remember with: <font color="#2e6da4" name="Helvetica-Bold">T-J-M-A-L-M</font> '
'(Tegmental · Jugular · Membranous · Anterior (Carotid) · Labyrinthine · Mastoid)',
BODY))
walls_data = [
[bold("Wall"), bold("Also Called"), bold("Structure / Contents"), bold("Clinical Note")],
["ROOF\n(Superior)", "Tegmental wall", "Tegmen tympani — thin plate of\npetrous temporal bone;\nseparates middle ear from\nmiddle cranial fossa",
"Infection → meningitis;\nEpidural abscess"],
["FLOOR\n(Inferior)", "Jugular wall", "Thin bone over internal\njugular vein bulb.\nOpening for tympanic branch\nof CN IX (Jacobson's nerve)",
"High jugular bulb may\nbulge into middle ear"],
["LATERAL\nWALL", "Membranous wall", "Tympanic membrane (most);\nbony lateral wall of\nepitympanic recess superiorly",
"Otoscopy, myringotomy"],
["MEDIAL\nWALL", "Labyrinthine wall", "Promontory (basal cochlear turn);\nOval window (fenestra vestibuli);\nRound window (fenestra cochleae);\nFacial canal prominence;\nLateral semicircular canal prominence;\nTympanic plexus on promontory",
"Fenestration surgery;\nFacial nerve at risk"],
["ANTERIOR\nWALL", "Carotid wall", "Thin bone over internal\ncarotid artery.\nOpening: Eustachian tube (lower);\nCanal for tensor tympani (upper);\nChorda tympani exits here",
"ICA related to ET;\nOtitis media"],
["POSTERIOR\nWALL", "Mastoid wall", "Aditus to mastoid antrum;\nPyramidal eminence (stapedius);\nChorda tympani enters here;\nFacial nerve descends here",
"Mastoiditis;\nCholesteatoma"],
]
tw = Table(walls_data, colWidths=[2*cm, 2.5*cm, 6*cm, 4*cm])
tw.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('TEXTCOLOR', (3,1), (3,-1), C_RED),
]))
story.append(tw)
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# DIAGRAM 2
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("4. LABELED DIAGRAM — Medial Wall & Contents (Gray's Anatomy for Students)"))
story.append(Spacer(1, 0.2*cm))
img2 = Image(IMG2, width=13*cm, height=9.5*cm, kind='proportional')
img2.hAlign = 'CENTER'
story.append(img2)
story.append(Paragraph(
"Fig. 2 Schematic 'box' showing the medial wall of the tympanic cavity: promontory, "
"oval & round windows, facial canal, tympanic plexus, chorda tympani, "
"pyramidal eminence, tensor tympani, and pharyngotympanic tube.",
CAPTION))
story.append(Spacer(1, 0.3*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 5 – TYMPANIC MEMBRANE
# ══════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(SectionHeader("5. TYMPANIC MEMBRANE (TM)"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"A pearly-grey, semi-transparent, oval membrane (~10 mm × 8.5 mm). "
"Set obliquely (55° to floor of EAM). Separates external from middle ear.",
BODY))
story.append(Paragraph("<b>Structure — 3 Layers:</b>", H3))
layers = [
("Outer (lateral)", "Thin squamous epithelium (continuous with skin of EAM)"),
("Middle (fibrous)", "Radial + circular collagen fibres — gives TM its strength"),
("Inner (medial)", "Mucous membrane (continuous with middle ear lining)"),
]
for name, desc in layers:
story.append(bp(f"<b>{name}:</b> {desc}"))
story.append(Paragraph("<b>Parts:</b>", H3))
parts = [
("Pars tensa", "Lower 4/5ths; tense, supported by fibrous annulus. Shows Cone of Light (anteroinferior quadrant)."),
("Pars flaccida (Shrapnell's membrane)", "Upper 1/5th; flaccid, no fibrous layer; attached to notch of Rivinus. Site of attic cholesteatoma."),
("Umbo", "Central most depressed point; tip of handle of malleus."),
("Cone of Light", "Anteroinferior quadrant. Seen at 5 o'clock (right ear) / 7 o'clock (left ear). Absent in otitis media."),
]
for name, desc in parts:
story.append(bp(f"<b>{name}:</b> {desc}"))
story.append(Paragraph("<b>Nerve supply of TM:</b>", H3))
ns_data = [
[bold("Surface"), bold("Nerve"), bold("From")],
["Outer (upper)", "Auriculotemporal n.", "CN V3 (mandibular)"],
["Outer (lower)", "Auricular branch", "CN X (vagus) — Arnold's nerve"],
["Inner", "Tympanic branch", "CN IX (glossopharyngeal) — Jacobson's nerve"],
]
tns = Table(ns_data, colWidths=[4.5*cm, 5*cm, 5*cm])
tns.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_MID_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(tns)
story.append(Spacer(1, 0.2*cm))
story.append(HighlightBox([
Paragraph("<b>Clinical Pearl:</b> Vagal (CN X) innervation of the TM → stimulation (e.g. syringing) "
"can cause reflex bradycardia, cough, or syncope. This is 'Arnold's ear-cough reflex'.",
make_style('CP', fontSize=9.5, textColor=C_RED, fontName='Helvetica', leading=13))
], bg=C_RED_BG, border=C_RED))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 6 – OSSICLES
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("6. OSSICLES — The 3 Ear Bones"))
story.append(Spacer(1, 0.2*cm))
story.append(HighlightBox([
Paragraph("<b>Mnemonic:</b> MIS — <b>M</b>alleus · <b>I</b>ncus · <b>S</b>tapes (lateral → medial)",
MEMONIC)
], bg=C_GREEN_BG, border=C_GREEN))
story.append(Spacer(1, 0.2*cm))
odata = [
[bold("Ossicle"), bold("Parts"), bold("Attachments"), bold("Muscle"), bold("Joint")],
["MALLEUS\n(hammer)", "Head, neck,\nhandle (manubrium),\nlateral & anterior process",
"Handle → TM (umbo)\nHead → body of incus",
"Tensor tympani\n(from lesser horn\nof sphenoid)",
"Incudomallear\n(synovial)"],
["INCUS\n(anvil)", "Body, short process\n(posterior), long process\n(descends medially)",
"Body ↔ malleus head\nLenticular process ↔ stapes head",
"None",
"Incudostapedial\n(synovial)"],
["STAPES\n(stirrup)", "Head, neck, anterior\n& posterior crura, footplate",
"Footplate → oval window\n(annular ligament)",
"Stapedius\n(from facial n.)",
"Oval window\n(syndesmosis)"],
]
tos = Table(odata, colWidths=[2.5*cm, 3.5*cm, 3.5*cm, 3*cm, 2*cm])
tos.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
]))
story.append(tos)
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>Movements:</b>", H3))
story.append(bp("TM vibrations → malleus handle → incus → stapes footplate → oval window → perilymph"))
story.append(bp("Stapes footplate (3 mm²) amplifies pressure ~17× vs. TM area (55 mm²) — hydraulic action"))
story.append(bp("Lever action of ossicular chain provides additional ~1.3× amplification"))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 7 – MUSCLES
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("7. MUSCLES OF THE MIDDLE EAR"))
story.append(Spacer(1, 0.2*cm))
mdata = [
[bold("Muscle"), bold("Origin"), bold("Insertion"), bold("Nerve Supply"), bold("Action"), bold("Clinical")],
["Tensor tympani\n(largest ME muscle)",
"Cartilage of\nEustachian tube,\nlesser wing of\nsphenoid",
"Handle of\nmalleus (via\ncochleariform\nprocess hook)",
"Medial pterygoid n.\n(branch of CN V3)",
"Pulls malleus medially;\ntenses TM;\nattenuates loud sounds",
"Stapedius reflex\ntest — CN V3"],
["Stapedius\n(smallest skeletal\nmuscle in body)",
"Pyramidal\neminence\n(posterior wall)",
"Neck of stapes",
"Facial nerve\n(CN VII)",
"Pulls stapes\nposteriorly;\nstiffens ossicular\nchain; protective",
"CN VII palsy →\nhyperacusis\n(stapedius reflex\nabsent)"],
]
tm = Table(mdata, colWidths=[2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm, 3*cm, 1.5*cm])
tm.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 4),
]))
story.append(tm)
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 8 – EUSTACHIAN TUBE
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("8. EUSTACHIAN TUBE (Pharyngotympanic / Auditory Tube)"))
story.append(Spacer(1, 0.2*cm))
et_points = [
"<b>Length:</b> ~36–40 mm (1.5 inches)",
"<b>Direction:</b> passes anteromedially and inferiorly at ~45° from middle ear to nasopharynx",
"<b>Two parts:</b> Bony (lateral 1/3, in petrous bone) + Fibrocartilaginous (medial 2/3, collapsed at rest)",
"<b>Isthmus:</b> narrowest point at bony–cartilaginous junction",
"<b>Nasopharyngeal opening:</b> at torus tubarius (visible on posterior rhinoscopy)",
"<b>Function:</b> (1) Equalises pressure — opens during swallowing, yawning; (2) Drainage of middle ear; (3) Protection from nasopharyngeal secretions",
"<b>Opens by:</b> Tensor veli palatini (CN V3) and Levator veli palatini (CN X) — contraction during swallowing",
]
for p in et_points:
story.append(bp(p))
story.append(Spacer(1, 0.2*cm))
story.append(HighlightBox([
Paragraph("<b>Why children get otitis media more often:</b> In children, the ET is shorter "
"(~18 mm), more horizontal, and wider → easier passage of nasopharyngeal bacteria → "
"higher incidence of acute otitis media. In adults it is longer, more oblique (45°), "
"and the lumen is narrower.",
make_style('ET', fontSize=9.5, textColor=C_DARK_BLUE, fontName='Helvetica', leading=13))
], bg=C_LIGHT_BLUE, border=C_MID_BLUE))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 9 – FACIAL NERVE
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("9. FACIAL NERVE (CN VII) IN THE MIDDLE EAR"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The facial nerve traverses the temporal bone in the <b>facial canal (Fallopian canal)</b> and "
"gives critical branches within or related to the middle ear. Its course has 3 segments in the temporal bone:",
BODY))
fn_data = [
[bold("Segment"), bold("Course"), bold("Branch given off")],
["Labyrinthine\n(shortest, 3–5 mm)", "Enters internal auditory meatus → above cochlea",
"Greater superficial petrosal nerve\n(from geniculate ganglion) → lacrimal gland"],
["Tympanic\n(horizontal, 10–12 mm)", "Runs along medial wall of middle ear\nabove oval window; most commonly\ndehiscent here",
"Nerve to stapedius"],
["Mastoid\n(vertical, 15–20 mm)", "Descends in posterior wall (mastoid);\nexits stylomastoid foramen",
"Chorda tympani nerve\n(taste anterior 2/3 tongue;\nsubmandibular & sublingual glands)"],
]
tfn = Table(fn_data, colWidths=[3.5*cm, 7*cm, 4*cm])
tfn.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
]))
story.append(tfn)
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>Chorda tympani nerve — key facts:</b>", H3))
ct = [
"Branch of CN VII from mastoid segment",
"Enters middle ear through posterior wall → runs between pars flaccida and handle of malleus",
"Exits through anterior wall (petrotympanic fissure / iter chordae anterius)",
"Joins lingual nerve (CN V3) in infratemporal fossa",
"Function: taste from anterior 2/3 tongue + secretomotor to submandibular and sublingual glands",
]
for c in ct:
story.append(bp(c))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 10 – BLOOD SUPPLY & NERVE SUPPLY
# ══════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(SectionHeader("10. BLOOD SUPPLY OF THE MIDDLE EAR"))
story.append(Spacer(1, 0.2*cm))
bs_data = [
[bold("Artery"), bold("Branch of"), bold("Supply")],
["Anterior tympanic a.", "Maxillary a. (from ECA)", "TM, middle ear"],
["Posterior tympanic a.", "Stylomastoid a. (from post. auricular/occipital)", "Posterior ME"],
["Inferior tympanic a.", "Ascending pharyngeal a. (from ECA)", "Floor, medial wall"],
["Superior tympanic a.", "Middle meningeal a. (from maxillary)", "Roof (tegmental wall)"],
["Caroticotympanic a.", "Internal carotid artery", "Anterior wall, medial wall"],
["Petrosal branch", "Middle meningeal a.", "Geniculate ganglion area"],
]
tbs = Table(bs_data, colWidths=[4.5*cm, 5.5*cm, 4.5*cm])
tbs.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_LIGHT_BLUE, white]),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (0,0), (-1,-1), 6),
]))
story.append(tbs)
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("<b>Venous drainage:</b> Superior petrosal sinus, pterygoid venous plexus.", BODY))
story.append(Spacer(1, 0.3*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 11 – NERVE SUPPLY / TYMPANIC PLEXUS
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("11. NERVE SUPPLY — TYMPANIC PLEXUS"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The <b>tympanic plexus</b> lies on the promontory (medial wall) and is formed by:",
BODY))
plexus = [
"<b>Tympanic branch of CN IX (Jacobson's nerve)</b> — main contributor; enters floor via inferior tympanic canaliculus",
"<b>Caroticotympanic nerves</b> — from sympathetic plexus on ICA (T1 preganglionic → superior cervical ganglion → postganglionic)",
]
for p in plexus:
story.append(bp(p))
story.append(Paragraph("<b>Tympanic plexus supplies:</b> mucosa of middle ear, mastoid air cells, and Eustachian tube.", BODY))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"<b>Lesser petrosal nerve</b> — terminal branch of tympanic plexus; carries parasympathetic "
"fibres (GVE) for parotid gland (via otic ganglion → auriculotemporal nerve → parotid).",
BODY))
story.append(Spacer(1, 0.4*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 12 – APPLIED ANATOMY
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("12. APPLIED ANATOMY (Exam Favourite!)"))
story.append(Spacer(1, 0.2*cm))
applied = [
("Acute Otitis Media (AOM)",
"ET dysfunction → bacterial colonisation (S. pneumoniae, H. influenzae). "
"More common in children (horizontal ET). Presents with otalgia, fever, bulging red TM."),
("Glue Ear (Otitis Media with Effusion)",
"Chronic ET dysfunction → non-purulent middle ear effusion → conductive hearing loss. "
"Common in children, often needs grommets."),
("Cholesteatoma",
"Abnormal keratinising squamous epithelium in middle ear. Usually starts at pars flaccida. "
"Erodes ossicles and bone. Dangerous — can erode tegmen (meningitis), facial canal (CN VII palsy), "
"lateral semicircular canal."),
("Mastoiditis",
"Infection spreads via aditus from middle ear to mastoid antrum and air cells. "
"Post-auricular swelling, tenderness, displaced pinna. Emergency."),
("Facial Nerve Palsy",
"Herpes zoster oticus (Ramsay Hunt syndrome) — VZV reactivation at geniculate ganglion. "
"Bell's palsy — demyelination. Surgery risk at dehiscent tympanic segment."),
("Otosclerosis",
"Abnormal bone remodelling at oval window → fixation of stapes footplate → "
"conductive hearing loss. Treated by stapedectomy/stapedotomy."),
("Referred Otalgia",
"No pathology in ear but pain felt there. CN V3 (dental), CN IX (tonsil/tongue base), "
"CN X (larynx), CN VII — all share auricular branches. "
"Always examine throat/neck in otalgia with normal ear."),
]
for title, desc in applied:
story.append(KeepTogether([
Paragraph(f"<b>{title}</b>", H3),
Paragraph(desc, BODY),
Spacer(1, 0.1*cm),
]))
story.append(Spacer(1, 0.3*cm))
# ══════════════════════════════════════════════════════════════
# SECTION 13 – MNEMONICS SUMMARY
# ══════════════════════════════════════════════════════════════
story.append(SectionHeader("13. QUICK MNEMONICS & EXAM TIPS"))
story.append(Spacer(1, 0.2*cm))
mnems = [
("Ossicles (lateral → medial)", "MIS — Malleus, Incus, Stapes"),
("Walls of middle ear", "T-J-M-A-L-M — Tegmental, Jugular, Membranous, Anterior, Labyrinthine, Mastoid"),
("Nerve to tensor tympani", "V3 — 'Tensor Tympani = Two / Trigeminal'"),
("Nerve to stapedius", "7 (VII) — 'S-Seven-tapedius'"),
("Chorda tympani runs between", "Pars flaccida above + handle of malleus below ('chord between strings')"),
("Eustachian tube opens by", "TVP — Tensor Veli Palatini (+ levator veli palatini)"),
("Tympanic plexus main nerve", "IX (Jacobson's nerve) — on prOmontory = prOmontory plexus"),
("Lesser petrosal nerve → parotid", "Otic ganglion → auriculotemporal nerve → parotid"),
]
mnem_data = [[bold("Topic"), bold("Mnemonic / Key Fact")]] + [[a, b] for a, b in mnems]
tmn = Table(mnem_data, colWidths=[5.5*cm, 9*cm])
tmn.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.4, C_GREY_LINE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_HIGHLIGHT, white]),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]))
story.append(tmn)
story.append(Spacer(1, 0.5*cm))
# ══════════════════════════════════════════════════════════════
# FOOTER NOTE
# ══════════════════════════════════════════════════════════════
story.append(HRFlowable(width="100%", thickness=1, color=C_GREY_LINE))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Sources: Gray's Anatomy for Students (10e) | Cummings Otolaryngology | "
"Orris Medical AI. For exam use only.",
make_style('Footer', fontSize=8, textColor=HexColor("#888888"),
alignment=TA_CENTER, fontName='Helvetica-Oblique')))
# ─── Build ─────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /home/daytona/workspace/middle-ear-pdf && python build_pdf.py 2>&1
ls -lh /home/daytona/workspace/middle-ear-pdf/Middle_Ear_Anatomy_Revision.pdf
Middle Ear Anatomy Revision
PDF Document · PDF
| Section | What's covered |
|---|---|
| Cover + Exam Focus | High-yield topic list at a glance |
| Overview | Two parts of middle ear, communications table |
| Diagram 1 (Gray's Anatomy) | Labeled coronal section - malleus, incus, stapes, oval window, ET, TM, EAM, epitympanic recess |
| Six Walls table | All 6 walls with alternate names, contents, and clinical notes in colour |
| Diagram 2 (Gray's Anatomy) | Labeled "box" diagram of medial wall - promontory, oval/round windows, tympanic plexus, chorda tympani, pyramidal eminence, tensor tympani, facial canal |
| Tympanic Membrane | Layers, parts (pars tensa/flaccida), cone of light, nerve supply table, Arnold's ear-cough reflex box |
| Ossicles | MIS mnemonic, full table with parts/attachments/muscles/joints, sound amplification mechanism |
| Muscles | Tensor tympani vs. stapedius - full comparison + clinical (hyperacusis, CN VII palsy) |
| Eustachian Tube | Length, parts, isthmus, why children get AOM more (highlighted box) |
| Facial Nerve (CN VII) | All 3 temporal bone segments, branches, chorda tympani course step-by-step |
| Blood & Nerve Supply | Complete arterial supply table + tympanic plexus + lesser petrosal nerve |
| Applied Anatomy | AOM, glue ear, cholesteatoma, mastoiditis, Bell's/Ramsay Hunt, otosclerosis, referred otalgia |
| Mnemonics | 8 mnemonics covering all major exam questions |
This seems a little extra can you simplify it a little bit and do the same for internals and external ear
cd /home/daytona/workspace/middle-ear-pdf && curl -s -o img_auricle.png "https://cdn.orris.care/cdss_images/00a54eb5a4673a333c5346b5d2ed1344301c1f3a390bad198477f6ab68cea6ee.png" && curl -s -o img_eam.png "https://cdn.orris.care/cdss_images/23e43b321fe82bfb9817eab135210f931cce601355caead38a2162b3be83d6d2.png" && curl -s -o img_inner_loc.png "https://cdn.orris.care/cdss_images/9cb4f2340095f42dbc54a4ec4b9d4c114a910b2e6c596f6ece0f051fee29bc0a.png" && curl -s -o img_bony_lab.png "https://cdn.orris.care/cdss_images/4f907594a809bd9f9420cc86ce43c1e98fb1567f4df18727965d88a9ea6675db.png" && curl -s -o img_cochlea.png "https://cdn.orris.care/cdss_images/f9e42054e9c6f74cdbef16b45acd31f0e433a3eed8fd5a22572fbc860b74fb62.png" && echo "Done" && ls -lh *.png
~/middle-ear-pdf/build_all.py
"""
Build 3 simplified ear anatomy revision PDFs.
Clean, concise, student-friendly — one topic per page where possible.
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.lib.colors import HexColor, white, black
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Flowable
DIR = "/home/daytona/workspace/middle-ear-pdf/"
# ── Colours ──────────────────────────────────────────────────────────
BLUE = HexColor("#1f4e79")
LBLUE = HexColor("#d0e4f7")
MBLUE = HexColor("#2e75b6")
RED = HexColor("#c00000")
LRED = HexColor("#fce4ec")
GREEN = HexColor("#1e6b24")
LGREEN = HexColor("#e8f5e9")
GOLD = HexColor("#7f6000")
LGOLD = HexColor("#fff9c4")
GREY = HexColor("#cccccc")
DGREY = HexColor("#444444")
# ── Shared styles ────────────────────────────────────────────────────
def make_styles():
s = {}
base = getSampleStyleSheet()
def st(name, parent='Normal', **kw):
p = ParagraphStyle(name, parent=base[parent], **kw)
s[name] = p
return p
st('body', fontSize=9.5, leading=14, textColor=DGREY,
spaceAfter=3, spaceBefore=2, alignment=TA_JUSTIFY)
st('bullet', fontSize=9.5, leading=13, textColor=DGREY,
leftIndent=14, bulletIndent=4, spaceAfter=2)
st('h2', fontSize=12, leading=16, fontName='Helvetica-Bold',
textColor=BLUE, spaceBefore=10, spaceAfter=3)
st('h3', fontSize=10, leading=14, fontName='Helvetica-Bold',
textColor=MBLUE, spaceBefore=6, spaceAfter=2)
st('caption', fontSize=8, leading=11, textColor=HexColor("#666666"),
alignment=TA_CENTER, spaceAfter=8, fontName='Helvetica-Oblique')
st('mnem', fontSize=9.5, leading=13, fontName='Helvetica-Bold',
textColor=GREEN, alignment=TA_CENTER, spaceBefore=3, spaceAfter=3)
st('clinical', fontSize=9, leading=13, textColor=RED,
leftIndent=8, spaceAfter=2)
st('footer', fontSize=7.5, leading=10, textColor=HexColor("#888888"),
alignment=TA_CENTER, fontName='Helvetica-Oblique')
return s
S = make_styles()
# ── Helpers ──────────────────────────────────────────────────────────
def bp(txt):
return Paragraph(f"<bullet>•</bullet> {txt}", S['bullet'])
def section(title, color=BLUE):
"""Coloured section header bar."""
class _Bar(Flowable):
def wrap(self, aW, aH):
self._w = aW; return (aW, 22)
def draw(self):
c = self.canv
c.setFillColor(color)
c.rect(0, 0, self._w, 20, fill=1, stroke=0)
c.setFillColor(white)
c.setFont('Helvetica-Bold', 10.5)
c.drawString(7, 5, title)
return _Bar()
def infobox(paras, bg=LBLUE, border=MBLUE):
class _Box(Flowable):
def wrap(self, aW, aH):
self._w = aW
self._h = 10
for p in paras:
_, ph = p.wrap(aW - 16, 9999)
self._h += ph + 4
return (aW, self._h)
def draw(self):
c = self.canv
c.setFillColor(bg); c.setStrokeColor(border); c.setLineWidth(1.2)
c.roundRect(0, 0, self._w, self._h, 4, fill=1, stroke=1)
y = self._h - 7
for p in paras:
pw, ph = p.wrap(self._w - 16, 9999)
y -= ph
p.drawOn(c, 8, y)
y -= 4
return _Box()
def table(data, col_widths, header_color=BLUE, row_colors=(LBLUE, white)):
t = Table(data, colWidths=col_widths)
t.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), header_color),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8.5),
('GRID', (0,0), (-1,-1), 0.4, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), list(row_colors)),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('RIGHTPADDING', (0,0), (-1,-1), 4),
]))
return t
def cover_bar(text, sub, bg=BLUE):
class _Cover(Flowable):
def wrap(self, aW, aH):
self._w = aW; return (aW, 70)
def draw(self):
c = self.canv
c.setFillColor(bg)
c.rect(0, 0, self._w, 70, fill=1, stroke=0)
c.setFillColor(white); c.setFont('Helvetica-Bold', 22)
c.drawCentredString(self._w/2, 42, text)
c.setFont('Helvetica', 11)
c.drawCentredString(self._w/2, 22, sub)
return _Cover()
def make_doc(path, title_str):
return SimpleDocTemplate(
path, pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm,
title=title_str)
BODY_W = A4[0] - 3.6*cm
def footer_note():
return [
Spacer(1, 0.3*cm),
HRFlowable(width="100%", thickness=0.5, color=GREY),
Spacer(1, 0.1*cm),
Paragraph("Source: Gray's Anatomy for Students | Orris Medical. Quick revision notes — 1st Year MBBS.", S['footer']),
]
# ═══════════════════════════════════════════════════════════════════
# PDF 1 — EXTERNAL EAR
# ═══════════════════════════════════════════════════════════════════
def build_external():
story = []
story.append(cover_bar("EXTERNAL EAR ANATOMY", "Quick Revision | 1st Year MBBS", bg=BLUE))
story.append(Spacer(1, 0.4*cm))
# Overview
story.append(section("OVERVIEW"))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph("The external ear has two parts: the <b>auricle (pinna)</b> and the <b>external acoustic meatus (EAM)</b>.", S['body']))
story.append(Spacer(1, 0.3*cm))
# Auricle diagram
story.append(section("1. AURICLE (PINNA) — Labeled Diagram"))
story.append(Spacer(1, 0.15*cm))
img = Image(DIR+"img_auricle.png", width=7*cm, height=8*cm, kind='proportional')
img.hAlign = 'CENTER'
story.append(img)
story.append(Paragraph("Fig. 1 Auricle — Gray's Anatomy for Students", S['caption']))
story.append(Paragraph("<b>Parts of the auricle:</b>", S['h3']))
auricle_data = [
["Part", "Description"],
["Helix", "Large outer curved rim"],
["Antihelix", "Inner curved ridge, parallel to helix; splits into 2 crura superiorly"],
["Concha", "Deep central hollow; EAM opens from its depth"],
["Tragus", "Projection anterior to EAM opening"],
["Antitragus", "Projection opposite the tragus, above lobule"],
["Lobule", "Fleshy inferior part; only part WITHOUT cartilage"],
["Scaphoid fossa", "Groove between helix and antihelix"],
["Triangular fossa", "Depression between the two crura of antihelix"],
]
story.append(table(auricle_data, [3.5*cm, 10.5*cm]))
story.append(Spacer(1, 0.3*cm))
# Nerve supply auricle
story.append(section("2. NERVE SUPPLY OF AURICLE"))
story.append(Spacer(1, 0.15*cm))
ns_data = [
["Nerve", "Area Supplied"],
["Great auricular n. (C2,C3)", "Anterior + posterior inferior surface"],
["Lesser occipital n. (C2)", "Posterosuperior surface"],
["Auriculotemporal n. (CN V3)", "Anterosuperior surface + tragus"],
["Auricular branch of vagus (CN X) — Arnold's nerve", "Posterior concha + floor of EAM"],
["Facial nerve (CN VII)", "Small area near concha (motor to auricular muscles)"],
]
story.append(table(ns_data, [6.5*cm, 7.5*cm]))
story.append(Spacer(1, 0.15*cm))
story.append(infobox([
Paragraph("<b>Clinical:</b> Arnold's ear-cough reflex — stimulating posterior EAM (e.g. syringing) via CN X → reflex cough or bradycardia.", S['clinical'])
], bg=LRED, border=RED))
story.append(Spacer(1, 0.3*cm))
# Blood supply
story.append(section("3. BLOOD & LYMPH SUPPLY OF AURICLE"))
story.append(Spacer(1, 0.15*cm))
story.append(bp("<b>Arterial:</b> Posterior auricular a. (ECA) + anterior auricular branches of superficial temporal a. (ECA) + occipital a. branch"))
story.append(bp("<b>Venous:</b> Superficial temporal v. + posterior auricular v. → external jugular v."))
story.append(bp("<b>Lymph:</b> Anterior → parotid nodes; Posterior → mastoid nodes; Lobule → upper deep cervical nodes"))
story.append(Spacer(1, 0.3*cm))
# EAM
story.append(section("4. EXTERNAL ACOUSTIC MEATUS (EAM) — Labeled Diagram"))
story.append(Spacer(1, 0.15*cm))
img2 = Image(DIR+"img_eam.png", width=9*cm, height=6.5*cm, kind='proportional')
img2.hAlign = 'CENTER'
story.append(img2)
story.append(Paragraph("Fig. 2 EAM — cartilaginous outer 1/3, bony inner 2/3", S['caption']))
eam_data = [
["Feature", "Detail"],
["Length", "~2.5 cm (1 inch)"],
["Direction", "S-shaped curve: initially upward + forward, then backward, then forward + downward"],
["Outer 1/3", "Cartilaginous (fibrocartilage) — contains hair follicles, sebaceous glands, ceruminous glands"],
["Inner 2/3", "Bony (tympanic part of temporal bone) — thin skin, no hairs or glands"],
["Isthmus", "Narrowest part at bony-cartilaginous junction"],
["Relations", "Parotid gland anteriorly (clinically important), temporomandibular joint anteriorly"],
]
story.append(table(eam_data, [3*cm, 11*cm]))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>Nerve supply of EAM:</b>", S['h3']))
eam_ns = [
["Surface", "Nerve"],
["Anterior + superior walls", "Auriculotemporal nerve (CN V3)"],
["Posterior + inferior walls", "Auricular branch of vagus (CN X)"],
["Minor contribution", "Branch of facial nerve (CN VII)"],
]
story.append(table(eam_ns, [5*cm, 9*cm]))
story.append(Spacer(1, 0.2*cm))
story.append(infobox([
Paragraph("<b>Exam tip:</b> To straighten the EAM for otoscopy → pull pinna <b>upward, backward, and laterally</b> in adults. In infants → pull <b>downward and backward</b> (EAM more horizontal).", S['body'])
], bg=LGOLD, border=GOLD))
story.append(Spacer(1, 0.3*cm))
# Applied
story.append(section("5. APPLIED ANATOMY"))
story.append(Spacer(1, 0.15*cm))
applied = [
("<b>Otitis externa</b> (Swimmer's ear)", "Infection of EAM skin; pain worsened by pulling pinna (distinguishes from otitis media)"),
("<b>Furunculosis</b>", "Boil in outer 1/3 (cartilaginous part); intensely painful due to tight skin adherent to cartilage"),
("<b>Referred otalgia</b>", "Dental pain (CN V3), tonsil pain (CN IX), laryngeal pain (CN X) all felt in ear via shared nerve supply"),
("<b>Parotid tumour</b>", "Can impinge on EAM due to close relation anteriorly"),
]
for t_str, d in applied:
story.append(bp(f"{t_str} — {d}"))
story.append(Spacer(1, 0.2*cm))
story.append(infobox([
Paragraph("<b>Mnemonic — EAM nerve supply:</b> <b>V-X-VII</b> (Anterior/Superior = V3 | Posterior/Inferior = X | Minor = VII)", S['mnem'])
], bg=LGREEN, border=GREEN))
story += footer_note()
doc = make_doc(DIR+"External_Ear_Anatomy.pdf", "External Ear Anatomy - Quick Revision")
doc.build(story)
print("External ear PDF done.")
# ═══════════════════════════════════════════════════════════════════
# PDF 2 — MIDDLE EAR (simplified)
# ═══════════════════════════════════════════════════════════════════
def build_middle():
story = []
story.append(cover_bar("MIDDLE EAR ANATOMY", "Quick Revision | 1st Year MBBS", bg=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.4*cm))
# Overview + diagram 1
story.append(section("OVERVIEW & DIAGRAM", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"Air-filled space in petrous temporal bone. Two parts: "
"<b>tympanic cavity proper</b> (mesotympanum) + <b>epitympanic recess</b> (attic, above TM).",
S['body']))
story.append(Spacer(1, 0.1*cm))
img1 = Image(DIR+"img1_parts.png", width=7*cm, height=8.5*cm, kind='proportional')
img1.hAlign = 'CENTER'
story.append(img1)
story.append(Paragraph("Fig. 1 Parts of middle ear (Gray's Anatomy for Students)", S['caption']))
# Six walls
story.append(section("1. SIX WALLS (Mnemonic: T-J-M-A-L-M)", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
walls = [
["Wall (Alt. name)", "Key contents / relations", "Clinical"],
["ROOF — Tegmental\n(Tegmen tympani)", "Thin bone; separates from middle cranial fossa", "Meningitis, epidural abscess"],
["FLOOR — Jugular\n(Jugular wall)", "Thin bone over int. jugular vein bulb;\nopening for Jacobson's nerve (CN IX br.)", "High jugular bulb"],
["LATERAL — Membranous\n(Tympanic membrane)", "TM (most); bony wall of epitympanic recess superiorly", "Otoscopy, myringotomy"],
["MEDIAL — Labyrinthine\n(Lateral wall of inner ear)", "Promontory (basal cochlear turn);\nOval window (sup.); Round window (inf.);\nFacial canal; tympanic plexus", "Fenestration surgery;\nFacial nerve risk"],
["ANTERIOR — Carotid\n(Carotid wall)", "Thin bone over ICA;\nEustachian tube opening (lower);\nCanal for tensor tympani (upper);\nChorda tympani exits", "ICA injury; otitis media"],
["POSTERIOR — Mastoid\n(Mastoid wall)", "Aditus → mastoid antrum;\nPyramidal eminence (stapedius);\nChorda tympani enters;\nFacial nerve descends", "Mastoiditis;\nCholesteatoma"],
]
t1 = Table(walls, colWidths=[3.5*cm, 6.5*cm, 4*cm])
t1.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor("#1a3a5c")),
('TEXTCOLOR', (0,0), (-1,0), white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.4, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [LBLUE, white]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('TEXTCOLOR', (2,1), (2,-1), RED),
]))
story.append(t1)
story.append(Spacer(1, 0.3*cm))
# Diagram 2 medial wall
story.append(section("2. MEDIAL WALL DIAGRAM", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
img2 = Image(DIR+"img2_walls.png", width=12*cm, height=8.5*cm, kind='proportional')
img2.hAlign = 'CENTER'
story.append(img2)
story.append(Paragraph("Fig. 2 Medial wall of tympanic cavity showing promontory, oval/round windows, tympanic plexus, chorda tympani, facial nerve", S['caption']))
story.append(Spacer(1, 0.3*cm))
# Ossicles + muscles
story.append(section("3. OSSICLES & MUSCLES", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
story.append(infobox([
Paragraph("<b>Mnemonic:</b> MIS (lateral → medial): Malleus · Incus · Stapes", S['mnem'])
], bg=LGREEN, border=GREEN))
story.append(Spacer(1, 0.1*cm))
oss = [
["Ossicle", "Parts", "Muscle attached", "Nerve to muscle"],
["Malleus (hammer)", "Handle attached to TM (umbo);\nHead, neck, ant. & lat. process", "Tensor tympani", "CN V3 (medial pterygoid n.)"],
["Incus (anvil)", "Body + short process (posterior)\n+ long process + lenticular process", "None", "—"],
["Stapes (stirrup)", "Head, neck, 2 crura, footplate\n(footplate in oval window)", "Stapedius", "CN VII (facial n.)"],
]
story.append(table(oss, [3*cm, 5*cm, 3.5*cm, 2.5*cm]))
story.append(Spacer(1, 0.15*cm))
story.append(infobox([
Paragraph("<b>CN VII palsy</b> → stapedius paralysed → <b>hyperacusis</b> (sounds painfully loud). Tested by stapedius reflex on audiometry.", S['clinical'])
], bg=LRED, border=RED))
story.append(Spacer(1, 0.3*cm))
# Eustachian tube
story.append(section("4. EUSTACHIAN TUBE", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
et = [
["Feature", "Detail"],
["Length", "~36–40 mm"],
["Direction","Anteromedially + inferiorly at ~45°"],
["Parts", "Bony (lateral 1/3, in petrous bone) + Fibrocartilaginous (medial 2/3, collapsed at rest)"],
["Isthmus", "Narrowest point at bony-cartilaginous junction"],
["Opens by", "Tensor veli palatini (CN V3) during swallowing / yawning"],
["Functions","(1) Equalise pressure; (2) Drain middle ear; (3) Protect from nasopharyngeal secretions"],
]
story.append(table(et, [3.5*cm, 10.5*cm]))
story.append(Spacer(1, 0.15*cm))
story.append(infobox([
Paragraph("<b>Why children get AOM more:</b> ET in children is shorter (~18 mm), more horizontal, wider lumen → bacteria enter easily from nasopharynx.", S['body'])
], bg=LGOLD, border=GOLD))
story.append(Spacer(1, 0.3*cm))
# Facial nerve + applied
story.append(section("5. FACIAL NERVE THROUGH MIDDLE EAR", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
fn = [
["Segment", "Course", "Branch in this segment"],
["Labyrinthine\n(3–5 mm)", "Internal acoustic meatus → above cochlea → geniculate ganglion", "Greater petrosal nerve\n(lacrimal gland)"],
["Tympanic\n(horizontal, ~11 mm)", "Medial wall above oval window\n(often dehiscent — most vulnerable)", "Nerve to stapedius"],
["Mastoid\n(vertical, ~15 mm)", "Descends in posterior wall → stylomastoid foramen", "Chorda tympani\n(taste + submandibular/sublingual glands)"],
]
story.append(table(fn, [2.5*cm, 5.5*cm, 6*cm]))
story.append(Spacer(1, 0.15*cm))
story.append(bp("<b>Chorda tympani path:</b> From posterior wall → crosses middle ear (between pars flaccida and malleus handle) → exits anterior wall → joins lingual nerve (CN V3) in infratemporal fossa"))
story.append(Spacer(1, 0.3*cm))
# Applied
story.append(section("6. APPLIED ANATOMY", color=HexColor("#1a3a5c")))
story.append(Spacer(1, 0.15*cm))
app = [
("<b>Otitis media</b>", "ET dysfunction → bacterial infection of middle ear; bulging red TM, otalgia, conductive hearing loss"),
("<b>Cholesteatoma</b>", "Keratinising squamous epithelium invades middle ear (usually from pars flaccida) → erodes ossicles and bone"),
("<b>Otosclerosis</b>", "Abnormal bone at oval window → stapes fixation → conductive hearing loss; treated by stapedectomy"),
("<b>Mastoiditis</b>", "Infection spreads via aditus → post-auricular swelling, pinna displaced forward"),
("<b>Glue ear</b>", "Chronic ET dysfunction → mucoid effusion → conductive hearing loss in children"),
]
for t_str, d in app:
story.append(bp(f"{t_str} — {d}"))
story += footer_note()
doc = make_doc(DIR+"Middle_Ear_Anatomy_Simplified.pdf", "Middle Ear Anatomy - Quick Revision")
doc.build(story)
print("Middle ear PDF done.")
# ═══════════════════════════════════════════════════════════════════
# PDF 3 — INTERNAL EAR
# ═══════════════════════════════════════════════════════════════════
def build_internal():
story = []
story.append(cover_bar("INTERNAL EAR ANATOMY", "Quick Revision | 1st Year MBBS", bg=HexColor("#1b5e20")))
story.append(Spacer(1, 0.4*cm))
# Overview
story.append(section("OVERVIEW", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"The internal ear (labyrinth) sits in the <b>petrous part of temporal bone</b>, between the middle ear "
"laterally and the internal acoustic meatus medially. It has two components:",
S['body']))
ov = [
["Component", "Contains", "Fluid", "Function"],
["Bony labyrinth", "Vestibule + 3 semicircular canals + cochlea", "Perilymph\n(similar to CSF)", "Houses membranous labyrinth"],
["Membranous labyrinth", "Utricle + saccule + 3 semicircular ducts + cochlear duct", "Endolymph\n(high K⁺)", "Hearing + Balance"],
]
story.append(table(ov, [3.5*cm, 5*cm, 3*cm, 3*cm], header_color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.3*cm))
# Location diagram
story.append(section("1. LOCATION DIAGRAM", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
img1 = Image(DIR+"img_inner_loc.png", width=8*cm, height=7*cm, kind='proportional')
img1.hAlign = 'CENTER'
story.append(img1)
story.append(Paragraph("Fig. 1 Internal ear in petrous temporal bone — cochlea, semicircular canals (ant./post./lateral), vestibulocochlear nerve CN VIII", S['caption']))
# Bony labyrinth
story.append(section("2. BONY LABYRINTH", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
bl = [
["Part", "Location", "Key features"],
["Vestibule", "Central part of bony labyrinth", "Contains oval window (lateral wall);\ncommunicates with cochlea (ant.) + semicircular canals (posterosuperiorly);\nvesibular aqueduct"],
["3 Semicircular\ncanals", "Posterosuperior to vestibule", "Anterior (superior), Posterior, Lateral;\neach forms 2/3 of a circle; one end dilated = ampulla;\nmutually perpendicular (3D)"],
["Cochlea", "Anterior to vestibule", "2.5 turns around modiolus (central bony axis);\nbase faces internal acoustic meatus;\nscala vestibuli + scala tympani (meet at helicotrema at apex);\nscala media (cochlear duct) between them"],
]
story.append(table(bl, [2.5*cm, 3.5*cm, 8*cm], header_color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.3*cm))
# Cochlea diagram
story.append(section("3. COCHLEA DIAGRAM", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
img_coch = Image(DIR+"img_cochlea.png", width=8*cm, height=6*cm, kind='proportional')
img_coch.hAlign = 'CENTER'
story.append(img_coch)
story.append(Paragraph("Fig. 2 Cochlea cross-section — modiolus, scala vestibuli, scala tympani, helicotrema (Gray's Anatomy for Students)", S['caption']))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>Cochlea scalae:</b>", S['h3']))
scalae = [
["Scala", "Contains", "Communication"],
["Scala vestibuli (upper)", "Perilymph", "Continuous with vestibule (via oval window)"],
["Scala media (middle)\n= cochlear duct", "Endolymph", "Part of membranous labyrinth;\ncontains organ of Corti"],
["Scala tympani (lower)", "Perilymph", "Ends at round window (secondary TM)"],
]
story.append(table(scalae, [3.5*cm, 3.5*cm, 7*cm], header_color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.1*cm))
story.append(bp("Scala vestibuli and scala tympani communicate at the apex through the <b>helicotrema</b>"))
story.append(bp("<b>Reissner's membrane</b> separates scala vestibuli from scala media"))
story.append(bp("<b>Basilar membrane</b> separates scala media from scala tympani; bears the Organ of Corti"))
story.append(Spacer(1, 0.3*cm))
# Membranous labyrinth
story.append(section("4. MEMBRANOUS LABYRINTH & BALANCE", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
ml = [
["Structure", "Location", "Sensory receptor", "Detects"],
["Utricle", "Vestibule (superior)", "Macula utriculi\n(otoliths)", "Linear acceleration\n(horizontal); head tilt"],
["Saccule", "Vestibule (inferior)", "Macula sacculi\n(otoliths)", "Linear acceleration\n(vertical); gravity"],
["3 Semicircular ducts", "Within bony canals", "Crista ampullaris\n(each ampulla)", "Angular/rotational\nacceleration"],
["Cochlear duct\n(scala media)", "Within cochlea", "Organ of Corti\n(hair cells on basilar m.)", "Sound (hearing)"],
]
story.append(table(ml, [3*cm, 3*cm, 3.5*cm, 4.5*cm], header_color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.3*cm))
# Bony labyrinth diagram
story.append(section("5. BONY LABYRINTH DIAGRAM", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
img_bl = Image(DIR+"img_bony_lab.png", width=10*cm, height=7*cm, kind='proportional')
img_bl.hAlign = 'CENTER'
story.append(img_bl)
story.append(Paragraph("Fig. 3 Bony labyrinth — vestibule, semicircular canals, cochlea, modiolus, spiral lamina", S['caption']))
story.append(Spacer(1, 0.3*cm))
# Nerve supply
story.append(section("6. NERVE SUPPLY — CN VIII", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"The <b>vestibulocochlear nerve (CN VIII)</b> enters the internal acoustic meatus and divides into:",
S['body']))
cn8 = [
["Division", "Ganglion", "Supplies", "Function"],
["Cochlear nerve", "Spiral (cochlear) ganglion\n(in modiolus)", "Organ of Corti\n(hair cells)", "Hearing"],
["Vestibular nerve", "Scarpa's (vestibular) ganglion\n(in IAM)", "Maculae + cristae ampullaris", "Balance"],
]
story.append(table(cn8, [3*cm, 4*cm, 4*cm, 3*cm], header_color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.2*cm))
story.append(infobox([
Paragraph("<b>Blood supply:</b> Labyrinthine artery (= internal auditory artery) — branch of <b>AICA</b> (anterior inferior cerebellar artery) from basilar artery. End artery — no collaterals → infarction causes sudden sensorineural deafness.", S['body'])
], bg=LGOLD, border=GOLD))
story.append(Spacer(1, 0.3*cm))
# Applied
story.append(section("7. APPLIED ANATOMY", color=HexColor("#1b5e20")))
story.append(Spacer(1, 0.15*cm))
app = [
("<b>Labyrinthitis</b>", "Viral infection of membranous labyrinth → vertigo + sensorineural hearing loss"),
("<b>Meniere's disease</b>", "Endolymphatic hydrops (excess endolymph) → episodes of vertigo + fluctuating SNHL + tinnitus + aural fullness"),
("<b>BPPV</b>", "Otoconia (calcium crystals) displaced into semicircular canal → positional vertigo; treated by Epley manoeuvre"),
("<b>Acoustic neuroma</b>", "Schwannoma of CN VIII in internal acoustic meatus → progressive SNHL + tinnitus + vertigo"),
("<b>Presbycusis</b>", "Age-related degeneration of basal turn of cochlea (high-frequency loss first)"),
]
for t_str, d in app:
story.append(bp(f"{t_str} — {d}"))
story.append(Spacer(1, 0.2*cm))
story.append(infobox([
Paragraph("<b>Key fact:</b> Perilymph composition ≈ extracellular fluid (high Na⁺, low K⁺). "
"Endolymph composition ≈ intracellular fluid (high K⁺, low Na⁺) — unique in the body. "
"Endolymph produced by stria vascularis.", S['body'])
], bg=LGOLD, border=GOLD))
story += footer_note()
doc = make_doc(DIR+"Internal_Ear_Anatomy.pdf", "Internal Ear Anatomy - Quick Revision")
doc.build(story)
print("Internal ear PDF done.")
# ── Run all ──────────────────────────────────────────────────────────
build_external()
build_middle()
build_internal()
print("All 3 PDFs built successfully.")
cd /home/daytona/workspace/middle-ear-pdf && python build_all.py 2>&1
ls -lh /home/daytona/workspace/middle-ear-pdf/*.pdf
External Ear Anatomy
PDF Document · PDF
Middle Ear Anatomy Simplified
PDF Document · PDF
Internal Ear Anatomy
PDF Document · PDF
| External Ear | Middle Ear | Internal Ear | |
|---|---|---|---|
| Diagram(s) | Auricle + EAM cross-section | Middle ear parts + medial wall box | Location in temporal bone + cochlea + bony labyrinth |
| Main tables | Parts of auricle, nerve supply, EAM features | 6 walls, ossicles, Eustachian tube, facial nerve segments | Bony vs membranous labyrinth, cochlear scalae, CN VIII |
| Applied | Otitis externa, referred otalgia, parotid | Otitis media, cholesteatoma, mastoiditis, otosclerosis | Labyrinthitis, Meniere's, BPPV, acoustic neuroma |
| Mnemonics | V-X-VII (EAM nerve supply) | MIS (ossicles), T-J-M-A-L-M (walls) | Perilymph vs endolymph composition |