Anatomy of thyroid gland


| Artery | Origin | Supplies |
|---|---|---|
| Superior thyroid artery | First branch of external carotid artery | Upper pole - divides into anterior and posterior branches |
| Inferior thyroid artery | Thyrocervical trunk (from subclavian artery) | Lower and posterior portions; also primary supply to both parathyroids |
| Thyroidea ima artery | Brachiocephalic artery or aortic arch | Present in 1-10% of individuals; enters the isthmus |
| Vein | Drainage |
|---|---|
| Superior thyroid vein | Runs with superior thyroid artery → internal jugular vein |
| Middle thyroid vein | From lateral border of gland → internal jugular vein (variable, often multiple) |
| Inferior thyroid vein | Forms a plexus from the lower pole → brachiocephalic veins (present in ~50%) |

| Direction | Structures |
|---|---|
| Anterior | Skin, superficial fascia, platysma, deep fascia, strap muscles, SCM |
| Posterior (medial) | Trachea, esophagus, inferior constrictor of pharynx |
| Posterior (lateral) | Carotid sheath (common carotid a., internal jugular v., vagus n.) |
| Posterior | Parathyroid glands (on posterior surface), RLN in tracheoesophageal groove |
| Superior | Larynx (thyroid cartilage, cricoid) |
Convert it into hand written format
ls /home/daytona/workspace/ && python3 -c "from reportlab.pdfgen import canvas; …
fc-list | grep -i "caveat\|indie\|rock\|patrick\|handlee\|dancing\|shadows\|arch…
mkdir -p /home/daytona/workspace/thyroid-notes && cd /home/daytona/workspace/thy…
cd /home/daytona/workspace/thyroid-notes && curl -L "https://github.com/google/f…
~/thyroid-notes/generate_pdf.py
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.colors import HexColor, white, black
import math, random
# ── Register handwriting font ─────────────────────────────────────────────────
pdfmetrics.registerFont(TTFont("Caveat", "/home/daytona/workspace/thyroid-notes/caveat.ttf"))
# ── Colour palette ────────────────────────────────────────────────────────────
PAGE_BG = HexColor("#FFFDF4") # warm paper
LINE_COLOR = HexColor("#C8D8E8") # faint ruled lines
HEADING1 = HexColor("#1A3C6E") # deep navy (main titles)
HEADING2 = HexColor("#2E6DA4") # medium blue (section heads)
HEADING3 = HexColor("#C0392B") # red (sub-heads, labels)
BODY = HexColor("#1C1C1C") # near-black body text
BULLET_DOT = HexColor("#E67E22") # orange bullet
TABLE_HEAD = HexColor("#2E6DA4")
TABLE_ROW1 = HexColor("#EAF2FB")
TABLE_ROW2 = HexColor("#FDFEFE")
BORDER = HexColor("#AED6F1")
BOX_BG = HexColor("#EBF5FB")
BOX_BORDER = HexColor("#2980B9")
NOTE_BG = HexColor("#FEF9E7")
NOTE_BORDER = HexColor("#F39C12")
W, H = A4 # 595 x 842 pt
MARGIN_L = 55
MARGIN_R = W - 50
CONTENT_W = MARGIN_R - MARGIN_L
random.seed(42)
# ── Helper: draw ruled lines on a page ───────────────────────────────────────
def draw_ruled(c):
c.setStrokeColor(LINE_COLOR)
c.setLineWidth(0.4)
for y in range(int(H - 95), 30, -22):
c.line(MARGIN_L - 10, y, MARGIN_R + 5, y)
# red margin line
c.setStrokeColor(HexColor("#FFAAAA"))
c.setLineWidth(0.7)
c.line(MARGIN_L - 2, H - 60, MARGIN_L - 2, 30)
def draw_page_bg(c):
c.setFillColor(PAGE_BG)
c.rect(0, 0, W, H, fill=1, stroke=0)
draw_ruled(c)
# ── Page header ───────────────────────────────────────────────────────────────
def page_header(c, page_num, title="Anatomy of the Thyroid Gland"):
c.setFillColor(HexColor("#1A3C6E"))
c.rect(0, H - 42, W, 42, fill=1, stroke=0)
c.setFillColor(white)
c.setFont("Caveat", 17)
c.drawString(MARGIN_L, H - 28, title)
c.setFont("Caveat", 12)
c.drawRightString(W - 40, H - 28, f"Page {page_num}")
# bottom strip
c.setFillColor(HexColor("#1A3C6E"))
c.rect(0, 0, W, 22, fill=1, stroke=0)
c.setFillColor(white)
c.setFont("Caveat", 9)
c.drawCentredString(W / 2, 7, "Orris Medical Notes • Thyroid Gland Anatomy")
# ── Text wrapper ──────────────────────────────────────────────────────────────
def wrap_text(text, font, size, max_width):
"""Return list of lines fitting max_width."""
words = text.split()
lines, cur = [], ""
for w in words:
test = (cur + " " + w).strip()
if pdfmetrics.stringWidth(test, font, size) <= max_width:
cur = test
else:
if cur:
lines.append(cur)
cur = w
if cur:
lines.append(cur)
return lines if lines else [""]
# ── Renderer class ────────────────────────────────────────────────────────────
class DocWriter:
def __init__(self, path):
self.c = canvas.Canvas(path, pagesize=A4)
self.y = H - 65
self.page = 1
draw_page_bg(self.c)
page_header(self.c, self.page)
def new_page(self):
self.c.showPage()
self.page += 1
draw_page_bg(self.c)
page_header(self.c, self.page)
self.y = H - 65
def need(self, pts):
if self.y - pts < 32:
self.new_page()
def gap(self, pts=6):
self.y -= pts
if self.y < 32:
self.new_page()
# ── Heading 1 ─────────────────────────────────────────────────────────────
def h1(self, text):
self.need(38)
self.gap(8)
# underline band
tw = pdfmetrics.stringWidth(text, "Caveat", 22)
self.c.setFillColor(HexColor("#D6EAF8"))
self.c.roundRect(MARGIN_L - 6, self.y - 6, min(tw + 20, CONTENT_W + 6), 28, 4, fill=1, stroke=0)
self.c.setFillColor(HEADING1)
self.c.setFont("Caveat", 22)
self.c.drawString(MARGIN_L, self.y + 4, text)
self.y -= 28
self.gap(4)
# ── Heading 2 ─────────────────────────────────────────────────────────────
def h2(self, text):
self.need(28)
self.gap(6)
self.c.setStrokeColor(HEADING2)
self.c.setLineWidth(1.5)
self.c.line(MARGIN_L - 4, self.y - 2, MARGIN_L - 4, self.y + 16)
self.c.setFillColor(HEADING2)
self.c.setFont("Caveat", 17)
self.c.drawString(MARGIN_L + 4, self.y, text)
self.y -= 22
self.gap(2)
# ── Heading 3 ─────────────────────────────────────────────────────────────
def h3(self, text):
self.need(22)
self.gap(4)
self.c.setFillColor(HEADING3)
self.c.setFont("Caveat", 14)
self.c.drawString(MARGIN_L, self.y, "▸ " + text)
self.y -= 18
self.gap(2)
# ── Body paragraph ────────────────────────────────────────────────────────
def para(self, text, indent=0, size=12.5, color=BODY):
lines = wrap_text(text, "Caveat", size, CONTENT_W - indent)
for line in lines:
self.need(16)
self.c.setFillColor(color)
self.c.setFont("Caveat", size)
self.c.drawString(MARGIN_L + indent, self.y, line)
self.y -= 17
self.gap(2)
# ── Bullet ────────────────────────────────────────────────────────────────
def bullet(self, text, indent=10, size=12.5):
lines = wrap_text(text, "Caveat", size, CONTENT_W - indent - 14)
for i, line in enumerate(lines):
self.need(16)
if i == 0:
self.c.setFillColor(BULLET_DOT)
self.c.circle(MARGIN_L + indent + 4, self.y + 4, 3, fill=1, stroke=0)
self.c.setFillColor(BODY)
self.c.setFont("Caveat", size)
self.c.drawString(MARGIN_L + indent + 14, self.y, line)
self.y -= 17
self.gap(1)
# ── Sub-bullet ────────────────────────────────────────────────────────────
def sub_bullet(self, text, indent=28, size=12):
lines = wrap_text(text, "Caveat", size, CONTENT_W - indent - 12)
for i, line in enumerate(lines):
self.need(16)
if i == 0:
self.c.setFillColor(HexColor("#2980B9"))
self.c.setFont("Caveat", 10)
self.c.drawString(MARGIN_L + indent, self.y + 1, "–")
self.c.setFillColor(BODY)
self.c.setFont("Caveat", size)
self.c.drawString(MARGIN_L + indent + 12, self.y, line)
self.y -= 16
self.gap(1)
# ── Callout / note box ────────────────────────────────────────────────────
def note(self, label, text, bg=NOTE_BG, border=NOTE_BORDER, label_color=HexColor("#E67E22")):
lines = wrap_text(text, "Caveat", 12, CONTENT_W - 22)
box_h = len(lines) * 16 + 18
self.need(box_h + 10)
self.gap(4)
self.c.setFillColor(bg)
self.c.setStrokeColor(border)
self.c.setLineWidth(1.2)
self.c.roundRect(MARGIN_L, self.y - box_h + 14, CONTENT_W, box_h, 5, fill=1, stroke=1)
self.c.setFillColor(label_color)
self.c.setFont("Caveat", 12)
self.c.drawString(MARGIN_L + 8, self.y + 4, label)
self.y -= 16
for line in lines:
self.c.setFillColor(BODY)
self.c.setFont("Caveat", 12)
self.c.drawString(MARGIN_L + 8, self.y, line)
self.y -= 16
self.gap(6)
# ── 2-column table ────────────────────────────────────────────────────────
def table2(self, headers, rows, col1_w=None):
c1 = col1_w or int(CONTENT_W * 0.38)
c2 = CONTENT_W - c1 - 4
def row_height(r):
l1 = len(wrap_text(r[0], "Caveat", 11.5, c1 - 8))
l2 = len(wrap_text(r[1], "Caveat", 11.5, c2 - 8))
return max(l1, l2) * 15 + 8
def draw_row(y, r, bg, is_header=False):
h = row_height(r) if not is_header else 22
self.need(h + 4)
self.c.setFillColor(bg)
self.c.setStrokeColor(BORDER)
self.c.setLineWidth(0.5)
self.c.rect(MARGIN_L, y - h + 4, c1, h, fill=1, stroke=1)
self.c.rect(MARGIN_L + c1, y - h + 4, c2, h, fill=1, stroke=1)
fc = white if is_header else BODY
fn = "Caveat"
fs = 12 if is_header else 11.5
self.c.setFillColor(fc)
self.c.setFont(fn, fs)
# col1
lines1 = wrap_text(r[0], fn, fs, c1 - 8)
for i, ln in enumerate(lines1):
self.c.drawString(MARGIN_L + 5, y - i * 15 - 2, ln)
# col2
lines2 = wrap_text(r[1], fn, fs, c2 - 8)
for i, ln in enumerate(lines2):
self.c.drawString(MARGIN_L + c1 + 5, y - i * 15 - 2, ln)
return h
self.gap(4)
self.need(30)
h = draw_row(self.y, headers, TABLE_HEAD, is_header=True)
self.y -= h
for i, row in enumerate(rows):
bg = TABLE_ROW1 if i % 2 == 0 else TABLE_ROW2
h = row_height(row)
self.need(h + 4)
draw_row(self.y, row, bg)
self.y -= h
self.gap(8)
# ── 3-column table ────────────────────────────────────────────────────────
def table3(self, headers, rows, widths=None):
if not widths:
widths = [int(CONTENT_W * 0.28), int(CONTENT_W * 0.38), int(CONTENT_W * 0.34)]
w1, w2, w3 = widths
def rh(r):
lines = [len(wrap_text(r[i], "Caveat", 11, widths[i] - 8)) for i in range(3)]
return max(lines) * 14 + 8
def draw_row(y, r, bg, is_header=False):
h = rh(r) if not is_header else 22
self.need(h + 4)
fc = white if is_header else BODY
fs = 11.5 if is_header else 11
xs = [MARGIN_L, MARGIN_L + w1, MARGIN_L + w1 + w2]
ws = [w1, w2, w3]
for ci in range(3):
self.c.setFillColor(bg)
self.c.setStrokeColor(BORDER)
self.c.setLineWidth(0.5)
self.c.rect(xs[ci], y - h + 4, ws[ci], h, fill=1, stroke=1)
self.c.setFillColor(fc)
self.c.setFont("Caveat", fs)
lines = wrap_text(r[ci], "Caveat", fs, ws[ci] - 8)
for i, ln in enumerate(lines):
self.c.drawString(xs[ci] + 5, y - i * 14 - 2, ln)
return h
self.gap(4)
self.need(30)
h = draw_row(self.y, headers, TABLE_HEAD, is_header=True)
self.y -= h
for i, row in enumerate(rows):
bg = TABLE_ROW1 if i % 2 == 0 else TABLE_ROW2
h = rh(row)
self.need(h + 4)
draw_row(self.y, row, bg)
self.y -= h
self.gap(8)
def save(self):
self.c.save()
# ══════════════════════════════════════════════════════════════════════════════
# BUILD THE DOCUMENT
# ══════════════════════════════════════════════════════════════════════════════
doc = DocWriter("/home/daytona/workspace/thyroid-notes/Thyroid_Anatomy_Handwritten.pdf")
d = doc # alias
# ─── COVER AREA ───────────────────────────────────────────────────────────────
d.c.setFillColor(HexColor("#1A3C6E"))
d.c.roundRect(MARGIN_L - 10, d.y - 80, CONTENT_W + 20, 90, 8, fill=1, stroke=0)
d.c.setFillColor(white)
d.c.setFont("Caveat", 28)
d.c.drawCentredString(W / 2, d.y + 2, "Anatomy of the Thyroid Gland")
d.c.setFont("Caveat", 14)
d.c.drawCentredString(W / 2, d.y - 22, "Comprehensive Medical Notes")
d.c.setFont("Caveat", 11)
d.c.drawCentredString(W / 2, d.y - 44, "Sources: Guyton & Hall • Schwartz's Surgery • Bailey & Love • Fischer's Surgery")
d.y -= 95
d.gap(14)
# ─── 1. OVERVIEW ─────────────────────────────────────────────────────────────
d.h1("1. Overview & Position")
d.para("The thyroid is the largest endocrine gland in the body — brown, firm, and weighing 20-25 g in adults.")
d.bullet("Located anterior to the trachea, posterior to the strap muscles, inferior to the larynx")
d.bullet("Two lateral lobes connected by the isthmus (overlies 2nd-4th tracheal rings)")
d.bullet("Pyramidal lobe present in ~50% of individuals — projects superiorly from isthmus; remnant of thyroglossal duct")
d.bullet("Enclosed by a pretracheal (deep cervical) fascia")
d.gap(6)
# ─── 2. EMBRYOLOGY ────────────────────────────────────────────────────────────
d.h1("2. Embryology")
d.para("Understanding development is key to anatomical variations and surgical complications.")
d.bullet("Arises from a median pharyngeal bud at the foramen caecum (tongue base)")
d.bullet("Foramen caecum = junction of anterior 2/3 and posterior 1/3 of tongue (vestigial remnant)")
d.bullet("Descends caudally via the thyroglossal duct, passing near/through the hyoid bone")
d.bullet("C cells (parafollicular) arrive via the ultimobranchial body from neural crest cells")
d.bullet("Parathyroids: superior from 4th pouch; inferior from 3rd pouch (descends with thymus)")
d.note("Clinical", "Thyroglossal duct cysts can occur anywhere along descent path. Lingual thyroid = failed descent. Pyramidal lobe = incomplete obliteration of duct.")
d.gap(4)
# ─── 3. HISTOLOGY ─────────────────────────────────────────────────────────────
d.h1("3. Microscopic Anatomy (Histology)")
d.h2("Follicles")
d.bullet("100-300 micrometers in diameter; the basic structural and functional units")
d.bullet("Lined by cuboidal follicular epithelial cells (thyrocytes) — height varies with activity")
d.bullet("Lumen filled with colloid — mostly thyroglobulin (large glycoprotein storing T3/T4)")
d.bullet("Functioning lobule = 24-40 follicles supplied by a single arteriole")
d.h2("Cell Types")
d.table2(
["Cell Type", "Function"],
[
["Follicular cells (thyrocytes)", "Synthesise and secrete T3 and T4; cuboidal epithelium lining follicles"],
["Parafollicular C cells", "Secrete calcitonin; neuroendocrine origin; located between follicles"],
]
)
d.note("Guyton & Hall", "Blood flow = ~5x gland weight per minute — among highest in the body (comparable only to adrenal cortex).")
d.gap(4)
# ─── 4. CAPSULE & FASCIA ──────────────────────────────────────────────────────
d.h1("4. Capsule, Fascia & Berry's Ligament")
d.bullet("Thyroid enclosed by a thin fibrous capsule, further invested by pretracheal fascia")
d.bullet("Fibrous septa project inward from capsule, dividing gland into lobules")
d.bullet("Berry's ligament = condensation of pretracheal fascia binding posteromedial thyroid to cricoid cartilage and upper tracheal rings")
d.note("Surgical Significance", "Berry's ligament is the point of greatest proximity of the RLN to the thyroid — highest risk zone during thyroidectomy. The RLN enters the larynx at the cricothyroid joint at this level.")
d.gap(6)
# ─── 5. BLOOD SUPPLY ─────────────────────────────────────────────────────────
d.h1("5. Blood Supply")
d.h2("Arterial Supply")
d.table3(
["Artery", "Origin", "Supply / Notes"],
[
["Superior thyroid a.", "External carotid a. (1st branch)", "Upper pole; divides into anterior & posterior branches"],
["Inferior thyroid a.", "Thyrocervical trunk → subclavian a.", "Lower/posterior gland; primary supply to BOTH parathyroids; crosses RLN"],
["Thyroidea ima a.", "Brachiocephalic / aortic arch", "Present in 1-10%; enters isthmus; variable"],
]
)
d.h3("Key Note on Inferior Thyroid Artery")
d.para("Courses superiorly over scalenus anterior → crosses posterior to carotid sheath → approaches gland where it crosses the RLN. Its branches may pass anterior, posterior, or interdigitate around the nerve.", indent=10)
d.gap(4)
d.h2("Venous Drainage")
d.table3(
["Vein", "Drainage", "Notes"],
[
["Superior thyroid v.", "Internal jugular vein", "Runs with superior thyroid artery"],
["Middle thyroid v.", "Internal jugular vein", "Variable; may be multiple; Division allows gland mobilisation"],
["Inferior thyroid v.", "Brachiocephalic veins", "Forms a plexus; present in ~50%; drains lower pole"],
]
)
d.note("Surgery Tip", "Dividing the middle thyroid vein is the key step that allows medial mobilisation of the thyroid lobe, exposing the inferior thyroid artery, RLN, and parathyroid glands behind it.")
# ─── 6. NERVES ────────────────────────────────────────────────────────────────
d.h1("6. Nerve Supply")
d.h2("Recurrent Laryngeal Nerve (RLN) — Most Important")
d.table2(
["Side", "Course / Notes"],
[
["Left RLN", "Loops around aortic arch at ligamentum arteriosum → ascends vertically in tracheoesophageal groove"],
["Right RLN", "Loops around right subclavian artery → ascends more obliquely to tracheoesophageal groove"],
["Both", "Enter larynx at cricothyroid joint at level of Berry's ligament"],
["Non-recurrent RLN", "Right side: 0.5-1% (aberrant right subclavian a.); Left: extremely rare (situs inversus)"],
]
)
d.h3("Locating the RLN — Surgical Landmarks")
d.bullet("Tubercle of Zuckerkandl — most posterolateral part of thyroid lobe; nerve found beneath it")
d.bullet("Beahr's Triangle — bounded by common carotid artery, inferior thyroid artery, tracheoesophageal groove")
d.bullet("RLN may branch in its course; finding a small nerve should raise suspicion of branching")
d.gap(4)
d.h2("Superior Laryngeal Nerve (SLN)")
d.table2(
["Branch", "Course & Function"],
[
["External branch", "Runs with superior thyroid artery; supplies cricothyroid muscle (voice pitch); injury → loss of projection"],
["Internal branch", "Sensory; pierces thyrohyoid membrane with laryngeal branch of superior thyroid artery"],
]
)
d.h2("Autonomic Supply")
d.bullet("Sympathetic: superior & middle cervical ganglia — via perivascular plexuses")
d.bullet("Parasympathetic: vagus nerve — via perivascular plexuses")
d.para("Function: primarily regulate gland blood flow rather than hormone secretion.", indent=10, color=HexColor("#555555"))
d.gap(6)
# ─── 7. LYMPHATICS ────────────────────────────────────────────────────────────
d.h1("7. Lymphatic Drainage")
d.para("The thyroid has an extensive intraglandular and periglandular lymphatic network draining in a predictable nodal sequence:")
d.bullet("Step 1 — Subcapsular plexus → Central compartment (Level VI): Delphian node (prelaryngeal), paratracheal nodes, nodes on superior/inferior thyroid veins")
d.bullet("Step 2 — Level VI → Lateral deep cervical nodes (Levels II, III, IV, V)")
d.bullet("Step 3 — Level VI → Mediastinal nodes (Level VII)")
d.note("Oncology", "Papillary thyroid carcinoma (most common) metastasises first to central compartment (Level VI) nodes. This is why prophylactic central neck dissection is debated in high-risk cases.")
d.gap(4)
# ─── 8. ANATOMICAL RELATIONS ──────────────────────────────────────────────────
d.h1("8. Anatomical Relations")
d.table2(
["Direction", "Structures"],
[
["Anterior", "Skin, superficial fascia, platysma, investing fascia, strap muscles (sternohyoid, sternothyroid), sternocleidomastoid"],
["Posterior (medial)", "Trachea, esophagus, inferior constrictor of pharynx, larynx"],
["Posterior (lateral)", "Carotid sheath contents: common carotid artery, internal jugular vein, vagus nerve"],
["Posterior (surface)", "Parathyroid glands (x4), recurrent laryngeal nerve in tracheoesophageal groove"],
["Superior", "Larynx (thyroid cartilage, cricoid cartilage)"],
["Inferior", "Trachea, great vessels of superior mediastinum"],
],
col1_w=130
)
d.gap(6)
# ─── 9. PARATHYROIDS ──────────────────────────────────────────────────────────
d.h1("9. Parathyroid Glands (Relation to Thyroid)")
d.bullet("Normally 4 glands: 2 superior + 2 inferior, on the posterior surface of the thyroid")
d.bullet("Superior parathyroid (from 4th pouch) — more constant position, dorsal to plane of RLN")
d.bullet("Inferior parathyroid (from 3rd pouch, descends with thymus) — more variable position, ventral to RLN")
d.bullet("Blood supply: primarily inferior thyroid artery for BOTH superior and inferior glands")
d.bullet("Identified by slightly different color (yellow-tan) and texture compared to thyroid/fat")
d.note("Surgical Note", "Inferior parathyroid may lie anywhere along the line of thymic descent — from just below the thyroid down to the anterior mediastinum. Superior parathyroid is more predictable in position.")
# ─── 10. QUICK SUMMARY ────────────────────────────────────────────────────────
d.h1("10. Quick Summary Table")
d.table2(
["Feature", "Key Detail"],
[
["Weight", "20-25 g (normal adult)"],
["Position", "C5-T1 vertebral level; anterior neck"],
["Lobes", "2 lateral lobes + isthmus + pyramidal lobe (50%)"],
["Main arterial supply", "Superior thyroid a. (ext. carotid) + Inferior thyroid a. (thyrocervical trunk)"],
["Main venous drainage", "Superior, middle, inferior thyroid veins"],
["Key nerve", "RLN — at risk at Berry's ligament & inferior thyroid artery crossing"],
["Lymph drainage", "Level VI → Levels II-V and VII"],
["Capsule landmark", "Berry's ligament — binds to cricoid/trachea"],
["Histology unit", "Follicle (100-300 μm) with cuboidal cells + colloid"],
["Calcitonin cells", "Parafollicular C cells (neural crest origin)"],
["Embryological origin", "Foramen caecum → thyroglossal duct descent"],
],
col1_w=155
)
doc.save()
print("PDF saved!")
cd /home/daytona/workspace/thyroid-notes && python3 generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/thyroid-notes/Thyroid_Anatomy_Handwritten.pdf
Thyroid Anatomy Handwritten
PDF Document · PDF
Add reference images to make visualization easy
cd /home/daytona/workspace/thyroid-notes && \ curl -sL "https://cdn.orris.care/c…
cd /home/daytona/workspace/thyroid-notes && python3 -c " from PIL import Image i…
~/thyroid-notes/generate_pdf_v2.py
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.colors import HexColor, white, black
from reportlab.lib.utils import ImageReader
from PIL import Image as PILImage
import os
BASE = "/home/daytona/workspace/thyroid-notes/"
# ── Register handwriting font ──────────────────────────────────────────────
pdfmetrics.registerFont(TTFont("Caveat", BASE + "caveat.ttf"))
# ── Colours ────────────────────────────────────────────────────────────────
PAGE_BG = HexColor("#FFFDF4")
LINE_COLOR = HexColor("#C8D8E8")
HEADING1 = HexColor("#1A3C6E")
HEADING2 = HexColor("#2E6DA4")
HEADING3 = HexColor("#C0392B")
BODY = HexColor("#1C1C1C")
BULLET_DOT = HexColor("#E67E22")
TABLE_HEAD = HexColor("#2E6DA4")
TABLE_ROW1 = HexColor("#EAF2FB")
TABLE_ROW2 = HexColor("#FDFEFE")
BORDER = HexColor("#AED6F1")
NOTE_BG = HexColor("#FEF9E7")
NOTE_BORDER= HexColor("#F39C12")
IMG_BORDER = HexColor("#2E6DA4")
IMG_CAP_BG = HexColor("#EAF2FB")
IMG_CAP = HexColor("#1A3C6E")
W, H = A4
MARGIN_L = 55
MARGIN_R = W - 50
CONTENT_W = MARGIN_R - MARGIN_L
# ── Ruled paper background ─────────────────────────────────────────────────
def draw_ruled(c):
c.setStrokeColor(LINE_COLOR)
c.setLineWidth(0.4)
for y in range(int(H - 95), 30, -22):
c.line(MARGIN_L - 10, y, MARGIN_R + 5, y)
c.setStrokeColor(HexColor("#FFAAAA"))
c.setLineWidth(0.7)
c.line(MARGIN_L - 2, H - 60, MARGIN_L - 2, 30)
def draw_page_bg(c):
c.setFillColor(PAGE_BG)
c.rect(0, 0, W, H, fill=1, stroke=0)
draw_ruled(c)
def page_header(c, page_num):
c.setFillColor(HEADING1)
c.rect(0, H - 42, W, 42, fill=1, stroke=0)
c.setFillColor(white)
c.setFont("Caveat", 17)
c.drawString(MARGIN_L, H - 28, "Anatomy of the Thyroid Gland")
c.setFont("Caveat", 12)
c.drawRightString(W - 40, H - 28, f"Page {page_num}")
c.setFillColor(HEADING1)
c.rect(0, 0, W, 22, fill=1, stroke=0)
c.setFillColor(white)
c.setFont("Caveat", 9)
c.drawCentredString(W / 2, 7, "Orris Medical Notes • Thyroid Gland Anatomy")
def wrap_text(text, font, size, max_width):
words = text.split()
lines, cur = [], ""
for w in words:
test = (cur + " " + w).strip()
if pdfmetrics.stringWidth(test, font, size) <= max_width:
cur = test
else:
if cur:
lines.append(cur)
cur = w
if cur:
lines.append(cur)
return lines if lines else [""]
# ── DocWriter ──────────────────────────────────────────────────────────────
class DocWriter:
def __init__(self, path):
self.c = canvas.Canvas(path, pagesize=A4)
self.y = H - 65
self.page = 1
draw_page_bg(self.c)
page_header(self.c, self.page)
def new_page(self):
self.c.showPage()
self.page += 1
draw_page_bg(self.c)
page_header(self.c, self.page)
self.y = H - 65
def need(self, pts):
if self.y - pts < 32:
self.new_page()
def gap(self, pts=6):
self.y -= pts
if self.y < 32:
self.new_page()
# ── Heading 1 ──────────────────────────────────────────────────────────
def h1(self, text):
self.need(38)
self.gap(8)
tw = pdfmetrics.stringWidth(text, "Caveat", 22)
self.c.setFillColor(HexColor("#D6EAF8"))
self.c.roundRect(MARGIN_L - 6, self.y - 6, min(tw + 20, CONTENT_W + 6), 28, 4, fill=1, stroke=0)
self.c.setFillColor(HEADING1)
self.c.setFont("Caveat", 22)
self.c.drawString(MARGIN_L, self.y + 4, text)
self.y -= 28
self.gap(4)
# ── Heading 2 ──────────────────────────────────────────────────────────
def h2(self, text):
self.need(28)
self.gap(6)
self.c.setStrokeColor(HEADING2)
self.c.setLineWidth(1.5)
self.c.line(MARGIN_L - 4, self.y - 2, MARGIN_L - 4, self.y + 16)
self.c.setFillColor(HEADING2)
self.c.setFont("Caveat", 17)
self.c.drawString(MARGIN_L + 4, self.y, text)
self.y -= 22
self.gap(2)
# ── Heading 3 ──────────────────────────────────────────────────────────
def h3(self, text):
self.need(22)
self.gap(4)
self.c.setFillColor(HEADING3)
self.c.setFont("Caveat", 14)
self.c.drawString(MARGIN_L, self.y, "▸ " + text)
self.y -= 18
self.gap(2)
# ── Body paragraph ─────────────────────────────────────────────────────
def para(self, text, indent=0, size=12.5, color=BODY):
lines = wrap_text(text, "Caveat", size, CONTENT_W - indent)
for line in lines:
self.need(16)
self.c.setFillColor(color)
self.c.setFont("Caveat", size)
self.c.drawString(MARGIN_L + indent, self.y, line)
self.y -= 17
self.gap(2)
# ── Bullet ─────────────────────────────────────────────────────────────
def bullet(self, text, indent=10, size=12.5):
lines = wrap_text(text, "Caveat", size, CONTENT_W - indent - 14)
for i, line in enumerate(lines):
self.need(16)
if i == 0:
self.c.setFillColor(BULLET_DOT)
self.c.circle(MARGIN_L + indent + 4, self.y + 4, 3, fill=1, stroke=0)
self.c.setFillColor(BODY)
self.c.setFont("Caveat", size)
self.c.drawString(MARGIN_L + indent + 14, self.y, line)
self.y -= 17
self.gap(1)
# ── Note box ───────────────────────────────────────────────────────────
def note(self, label, text, bg=NOTE_BG, border=NOTE_BORDER, label_color=HexColor("#E67E22")):
lines = wrap_text(text, "Caveat", 12, CONTENT_W - 22)
box_h = len(lines) * 16 + 18
self.need(box_h + 10)
self.gap(4)
self.c.setFillColor(bg)
self.c.setStrokeColor(border)
self.c.setLineWidth(1.2)
self.c.roundRect(MARGIN_L, self.y - box_h + 14, CONTENT_W, box_h, 5, fill=1, stroke=1)
self.c.setFillColor(label_color)
self.c.setFont("Caveat", 12)
self.c.drawString(MARGIN_L + 8, self.y + 4, label)
self.y -= 16
for line in lines:
self.c.setFillColor(BODY)
self.c.setFont("Caveat", 12)
self.c.drawString(MARGIN_L + 8, self.y, line)
self.y -= 16
self.gap(6)
# ── 2-column table ─────────────────────────────────────────────────────
def table2(self, headers, rows, col1_w=None):
c1 = col1_w or int(CONTENT_W * 0.38)
c2 = CONTENT_W - c1 - 4
def row_height(r):
l1 = len(wrap_text(r[0], "Caveat", 11.5, c1 - 8))
l2 = len(wrap_text(r[1], "Caveat", 11.5, c2 - 8))
return max(l1, l2) * 15 + 8
def draw_row(y, r, bg, is_header=False):
h = row_height(r) if not is_header else 22
self.need(h + 4)
self.c.setFillColor(bg)
self.c.setStrokeColor(BORDER)
self.c.setLineWidth(0.5)
self.c.rect(MARGIN_L, y - h + 4, c1, h, fill=1, stroke=1)
self.c.rect(MARGIN_L + c1, y - h + 4, c2, h, fill=1, stroke=1)
fc = white if is_header else BODY
fn, fs = "Caveat", 12 if is_header else 11.5
self.c.setFillColor(fc)
self.c.setFont(fn, fs)
for i, ln in enumerate(wrap_text(r[0], fn, fs, c1 - 8)):
self.c.drawString(MARGIN_L + 5, y - i * 15 - 2, ln)
for i, ln in enumerate(wrap_text(r[1], fn, fs, c2 - 8)):
self.c.drawString(MARGIN_L + c1 + 5, y - i * 15 - 2, ln)
return h
self.gap(4)
self.need(30)
h = draw_row(self.y, headers, TABLE_HEAD, is_header=True)
self.y -= h
for i, row in enumerate(rows):
bg = TABLE_ROW1 if i % 2 == 0 else TABLE_ROW2
h = row_height(row)
self.need(h + 4)
draw_row(self.y, row, bg)
self.y -= h
self.gap(8)
# ── 3-column table ─────────────────────────────────────────────────────
def table3(self, headers, rows, widths=None):
if not widths:
widths = [int(CONTENT_W * 0.28), int(CONTENT_W * 0.38), int(CONTENT_W * 0.34)]
w1, w2, w3 = widths
def rh(r):
return max(len(wrap_text(r[i], "Caveat", 11, widths[i] - 8)) for i in range(3)) * 14 + 8
def draw_row(y, r, bg, is_header=False):
h = rh(r) if not is_header else 22
self.need(h + 4)
fc = white if is_header else BODY
fs = 11.5 if is_header else 11
xs = [MARGIN_L, MARGIN_L + w1, MARGIN_L + w1 + w2]
ws = [w1, w2, w3]
for ci in range(3):
self.c.setFillColor(bg)
self.c.setStrokeColor(BORDER)
self.c.setLineWidth(0.5)
self.c.rect(xs[ci], y - h + 4, ws[ci], h, fill=1, stroke=1)
self.c.setFillColor(fc)
self.c.setFont("Caveat", fs)
for i, ln in enumerate(wrap_text(r[ci], "Caveat", fs, ws[ci] - 8)):
self.c.drawString(xs[ci] + 5, y - i * 14 - 2, ln)
return h
self.gap(4)
self.need(30)
h = draw_row(self.y, headers, TABLE_HEAD, is_header=True)
self.y -= h
for i, row in enumerate(rows):
bg = TABLE_ROW1 if i % 2 == 0 else TABLE_ROW2
h = rh(row)
self.need(h + 4)
draw_row(self.y, row, bg)
self.y -= h
self.gap(8)
# ── IMAGE EMBED ────────────────────────────────────────────────────────
def image(self, img_path, caption, max_w=None, max_h=None, center=True):
"""Embed an image with a styled caption box. Fits within max_w x max_h."""
if not os.path.exists(img_path):
return
max_w = max_w or CONTENT_W
max_h = max_h or 260
# Get natural size
pil = PILImage.open(img_path)
iw, ih = pil.size
aspect = iw / ih
# Scale to fit
dw = min(max_w, iw)
dh = dw / aspect
if dh > max_h:
dh = max_h
dw = dh * aspect
cap_lines = wrap_text(caption, "Caveat", 11, CONTENT_W - 20)
cap_h = len(cap_lines) * 14 + 10
total = dh + cap_h + 20
self.need(total + 14)
self.gap(6)
# Image frame (shadow effect)
x = MARGIN_L + (CONTENT_W - dw) / 2 if center else MARGIN_L
y_top = self.y
y_img = y_top - dh
# Drop shadow
self.c.setFillColor(HexColor("#CCCCCC"))
self.c.roundRect(x + 3, y_img - cap_h - 5, dw, dh + cap_h + 4, 4, fill=1, stroke=0)
# Caption background
self.c.setFillColor(IMG_CAP_BG)
self.c.setStrokeColor(IMG_BORDER)
self.c.setLineWidth(1.0)
self.c.roundRect(x, y_img - cap_h - 2, dw, dh + cap_h, 4, fill=1, stroke=1)
# Draw image
ir = ImageReader(img_path)
self.c.drawImage(ir, x, y_img, width=dw, height=dh, preserveAspectRatio=True, mask='auto')
# Caption area separator
self.c.setStrokeColor(IMG_BORDER)
self.c.setLineWidth(0.6)
self.c.line(x + 4, y_img - 2, x + dw - 4, y_img - 2)
# Caption text
self.c.setFillColor(IMG_CAP)
self.c.setFont("Caveat", 11)
for i, ln in enumerate(cap_lines):
self.c.drawCentredString(x + dw / 2, y_img - 14 - i * 14, ln)
self.y = y_img - cap_h - 10
self.gap(8)
def save(self):
self.c.save()
# ══════════════════════════════════════════════════════════════════════════════
# BUILD DOCUMENT
# ══════════════════════════════════════════════════════════════════════════════
doc = DocWriter(BASE + "Thyroid_Anatomy_With_Images.pdf")
d = doc
# ─── COVER BANNER ─────────────────────────────────────────────────────────────
d.c.setFillColor(HEADING1)
d.c.roundRect(MARGIN_L - 10, d.y - 80, CONTENT_W + 20, 90, 8, fill=1, stroke=0)
d.c.setFillColor(white)
d.c.setFont("Caveat", 28)
d.c.drawCentredString(W / 2, d.y + 2, "Anatomy of the Thyroid Gland")
d.c.setFont("Caveat", 14)
d.c.drawCentredString(W / 2, d.y - 22, "Comprehensive Medical Notes with Reference Images")
d.c.setFont("Caveat", 11)
d.c.drawCentredString(W / 2, d.y - 44, "Sources: Guyton & Hall • Schwartz's Surgery • Bailey & Love • Fischer's Surgery")
d.y -= 95
d.gap(14)
# ─── 1. OVERVIEW ──────────────────────────────────────────────────────────────
d.h1("1. Overview & Position")
d.para("The thyroid is the largest endocrine gland in the body — brown, firm, and weighing 20-25 g in adults.")
d.bullet("Located anterior to the trachea, posterior to the strap muscles, inferior to the larynx")
d.bullet("Two lateral lobes connected by the isthmus (overlies 2nd-4th tracheal rings)")
d.bullet("Pyramidal lobe present in ~50% — projects superiorly from isthmus; remnant of thyroglossal duct")
d.bullet("Enclosed by a pretracheal (deep cervical) fascia")
d.gap(6)
# ─── 2. EMBRYOLOGY ────────────────────────────────────────────────────────────
d.h1("2. Embryology")
d.bullet("Arises from a median pharyngeal bud at the foramen caecum (tongue base)")
d.bullet("Foramen caecum = junction of anterior 2/3 and posterior 1/3 of tongue (vestigial remnant)")
d.bullet("Descends caudally via the thyroglossal duct, passing near/through the hyoid bone")
d.bullet("C cells (parafollicular) arrive via the ultimobranchial body from neural crest cells")
d.bullet("Parathyroids: superior from 4th pouch; inferior from 3rd pouch (descends with thymus)")
d.note("Clinical", "Thyroglossal duct cysts can occur anywhere along descent path. Lingual thyroid = failed descent. Pyramidal lobe = incomplete obliteration of duct.")
d.gap(4)
# ─── 3. HISTOLOGY ─────────────────────────────────────────────────────────────
d.h1("3. Microscopic Anatomy (Histology)")
d.h2("Follicles")
d.bullet("100-300 micrometers in diameter; the basic structural and functional units")
d.bullet("Lined by cuboidal follicular epithelial cells (thyrocytes)")
d.bullet("Lumen filled with colloid — mostly thyroglobulin (large glycoprotein storing T3/T4)")
d.bullet("Functioning lobule = 24-40 follicles supplied by a single arteriole")
d.h2("Cell Types")
d.table2(
["Cell Type", "Function"],
[
["Follicular cells (thyrocytes)", "Synthesise and secrete T3 and T4; cuboidal epithelium lining follicles"],
["Parafollicular C cells", "Secrete calcitonin; neuroendocrine origin; located between follicles"],
]
)
d.note("Guyton & Hall", "Blood flow = ~5x gland weight per minute — among highest in the body.")
# IMAGE: Histology diagram (Guyton)
d.image(
BASE + "img_histology.png",
"Fig 1. Anatomy & microscopic structure of the thyroid gland — follicles, cuboidal epithelial cells, C cells and colloid. (Guyton & Hall, Medical Physiology)",
max_w=220, max_h=290
)
# IMAGE: Histo2 (Bailey & Love histology)
d.image(
BASE + "img_histo2.png",
"Fig 2. Histology of the normal thyroid gland showing follicles filled with colloid, lined by cuboidal epithelium. (Bailey & Love, 28th Ed.)",
max_w=CONTENT_W - 20, max_h=180
)
# ─── 4. CAPSULE & BERRY'S LIGAMENT ────────────────────────────────────────────
d.h1("4. Capsule, Fascia & Berry's Ligament")
d.bullet("Thyroid enclosed by a thin fibrous capsule, further invested by pretracheal fascia")
d.bullet("Fibrous septa project inward, dividing gland into lobules")
d.bullet("Berry's ligament = condensation of pretracheal fascia binding posteromedial thyroid to cricoid cartilage and upper tracheal rings")
d.note("Surgical Significance", "Berry's ligament is the zone of greatest proximity of the RLN to the thyroid — highest risk zone during thyroidectomy. RLN enters larynx at the cricothyroid joint at this level.")
d.gap(6)
# ─── 5. BLOOD SUPPLY ──────────────────────────────────────────────────────────
d.h1("5. Blood Supply")
d.h2("Arterial Supply")
d.table3(
["Artery", "Origin", "Supply / Notes"],
[
["Superior thyroid a.", "External carotid a. (1st branch)", "Upper pole; divides into anterior & posterior branches"],
["Inferior thyroid a.", "Thyrocervical trunk → subclavian a.", "Lower/posterior gland; primary supply to BOTH parathyroids; crosses RLN"],
["Thyroidea ima a.", "Brachiocephalic / aortic arch", "Present in 1-10%; enters isthmus; variable"],
]
)
d.h3("Key Note on Inferior Thyroid Artery")
d.para("Courses over scalenus anterior → crosses posterior to carotid sheath → crosses RLN (branches may pass anterior, posterior, or around the nerve).", indent=10)
d.gap(4)
d.h2("Venous Drainage")
d.table3(
["Vein", "Drainage", "Notes"],
[
["Superior thyroid v.", "Internal jugular vein", "Runs with superior thyroid artery"],
["Middle thyroid v.", "Internal jugular vein", "Variable; division allows gland mobilisation"],
["Inferior thyroid v.", "Brachiocephalic veins", "Forms a plexus; present in ~50%; drains lower pole"],
]
)
d.note("Surgery Tip", "Dividing the middle thyroid vein allows medial mobilisation, exposing the inferior thyroid artery, RLN, and parathyroids.")
# IMAGE: Anterior anatomy (Schwartz) — full-width
d.image(
BASE + "img_anterior.png",
"Fig 3. Thyroid gland and surrounding structures — anterior view (A) showing arteries, veins and nerves; and cross-section (B) showing relations. (Schwartz's Surgery, 11th Ed.)",
max_w=CONTENT_W, max_h=330
)
# ─── 6. NERVES ────────────────────────────────────────────────────────────────
d.h1("6. Nerve Supply")
d.h2("Recurrent Laryngeal Nerve (RLN) — Most Important")
d.table2(
["Side", "Course / Notes"],
[
["Left RLN", "Loops around aortic arch at ligamentum arteriosum → ascends vertically in tracheoesophageal groove"],
["Right RLN", "Loops around right subclavian artery → ascends more obliquely to tracheoesophageal groove"],
["Both", "Enter larynx at cricothyroid joint at level of Berry's ligament"],
["Non-recurrent RLN", "Right: 0.5-1% (aberrant rt. subclavian a.); Left: extremely rare (situs inversus)"],
]
)
d.h3("Surgical Landmarks for RLN")
d.bullet("Tubercle of Zuckerkandl — most posterolateral part of thyroid; nerve found beneath it")
d.bullet("Beahr's Triangle — bounded by common carotid artery, inferior thyroid artery, tracheoesophageal groove")
d.bullet("RLN may branch; finding a small nerve should alert surgeon to branching")
d.gap(4)
d.h2("Superior Laryngeal Nerve (SLN)")
d.table2(
["Branch", "Function / Notes"],
[
["External branch", "Runs with superior thyroid artery; supplies cricothyroid (voice pitch); injury = loss of projection"],
["Internal branch", "Sensory; pierces thyrohyoid membrane with laryngeal branch of superior thyroid artery"],
]
)
# IMAGE: RLN diagram (Schwartz)
d.image(
BASE + "img_rln.png",
"Fig 4. Relationship of the Recurrent Laryngeal Nerve (RLN) to the inferior thyroid artery. Note: superior parathyroid is dorsal to the nerve; inferior parathyroid is ventral. (Schwartz's Surgery, 11th Ed.)",
max_w=CONTENT_W - 10, max_h=220
)
# IMAGE: Posterior view (Bailey & Love)
d.image(
BASE + "img_posterior.png",
"Fig 5. Thyroid gland from behind — showing both RLNs, inferior thyroid arteries, inferior thyroid veins, and superior/inferior parathyroid glands. (Bailey & Love, 28th Ed.)",
max_w=CONTENT_W, max_h=280
)
# ─── 7. LYMPHATICS ────────────────────────────────────────────────────────────
d.h1("7. Lymphatic Drainage")
d.para("Extensive intra- and periglandular network draining in a predictable nodal sequence:")
d.bullet("Step 1 — Subcapsular plexus → Central compartment (Level VI): Delphian node (prelaryngeal), paratracheal nodes, nodes on superior/inferior thyroid veins")
d.bullet("Step 2 — Level VI → Lateral deep cervical nodes (Levels II, III, IV, V)")
d.bullet("Step 3 — Level VI → Mediastinal nodes (Level VII)")
d.note("Oncology", "Papillary thyroid carcinoma first metastasises to central compartment (Level VI) nodes. This is why central neck dissection is performed/considered in high-risk cases.")
# IMAGE: Lymph node levels
d.image(
BASE + "img_lymph.png",
"Fig 6. Cervical lymph node levels (I-VII). Thyroid lymphatics drain primarily to Level VI (central compartment), then to Levels II-V and VII. (Bailey & Love, 28th Ed.)",
max_w=CONTENT_W - 40, max_h=260
)
# ─── 8. ANATOMICAL RELATIONS ──────────────────────────────────────────────────
d.h1("8. Anatomical Relations")
d.table2(
["Direction", "Structures"],
[
["Anterior", "Skin, superficial fascia, platysma, investing fascia, strap muscles (sternohyoid, sternothyroid), SCM"],
["Posterior (medial)", "Trachea, esophagus, inferior constrictor of pharynx, larynx"],
["Posterior (lateral)", "Carotid sheath: common carotid artery, internal jugular vein, vagus nerve"],
["Posterior (surface)", "Parathyroid glands (x4), RLN in tracheoesophageal groove"],
["Superior", "Larynx (thyroid cartilage, cricoid cartilage)"],
["Inferior", "Trachea, great vessels of superior mediastinum"],
],
col1_w=130
)
d.gap(6)
# ─── 9. PARATHYROIDS ──────────────────────────────────────────────────────────
d.h1("9. Parathyroid Glands (Relations to Thyroid)")
d.bullet("Normally 4 glands: 2 superior + 2 inferior, on the posterior surface of the thyroid")
d.bullet("Superior parathyroid (4th pouch) — more constant, dorsal to plane of RLN")
d.bullet("Inferior parathyroid (3rd pouch, descends with thymus) — variable, ventral to RLN")
d.bullet("Blood supply: inferior thyroid artery is the primary supply to BOTH superior and inferior glands")
d.bullet("Identified by slightly different color (yellow-tan) and texture vs thyroid/fat")
d.note("Surgical Note", "Inferior parathyroid may lie anywhere from just below the thyroid to the anterior mediastinum. Superior parathyroid is more predictably located.")
# ─── 10. QUICK SUMMARY ────────────────────────────────────────────────────────
d.h1("10. Quick Summary Table")
d.table2(
["Feature", "Key Detail"],
[
["Weight", "20-25 g (normal adult)"],
["Position", "C5-T1 vertebral level; anterior neck"],
["Lobes", "2 lateral lobes + isthmus + pyramidal lobe (50%)"],
["Main arterial supply", "Superior thyroid a. (ext. carotid) + Inferior thyroid a. (thyrocervical trunk)"],
["Main venous drainage", "Superior, middle, inferior thyroid veins"],
["Key nerve at risk", "RLN — at Berry's ligament & inferior thyroid artery crossing"],
["Lymph drainage", "Level VI → Levels II-V and VII"],
["Capsule landmark", "Berry's ligament — binds to cricoid/trachea"],
["Histology unit", "Follicle (100-300 um) with cuboidal cells + colloid"],
["Calcitonin cells", "Parafollicular C cells (neural crest origin)"],
["Embryological origin", "Foramen caecum → thyroglossal duct descent"],
],
col1_w=155
)
doc.save()
print(f"Done! Pages: {doc.page}")
cd /home/daytona/workspace/thyroid-notes && python3 generate_pdf_v2.py 2>&1
ls -lh /home/daytona/workspace/thyroid-notes/Thyroid_Anatomy_With_Images.pdf
Thyroid Anatomy With Images
PDF Document · PDF
| Figure | Placed After | Source |
|---|---|---|
| Fig 1. Microscopic anatomy diagram | Section 3 - Histology | Guyton & Hall |
| Fig 2. Normal thyroid histology (H&E) | Section 3 - Histology | Bailey & Love |
| Fig 3. Anterior view + cross-section | Section 5 - Blood Supply | Schwartz's Surgery |
| Fig 4. RLN & inferior thyroid artery relationship | Section 6 - Nerves | Schwartz's Surgery |
| Fig 5. Thyroid from behind (RLN + parathyroids) | Section 6 - Nerves | Bailey & Love |
| Fig 6. Cervical lymph node levels I-VII | Section 7 - Lymphatics | Bailey & Love |