~/pathology-notes/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
OUTPUT_PATH = "/home/daytona/workspace/pathology-notes/General_Pathology_Study_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1a3a5c")
MID_BLUE = colors.HexColor("#2563a8")
LIGHT_BLUE = colors.HexColor("#dbeafe")
ACCENT_RED = colors.HexColor("#b91c1c")
ACCENT_GOLD = colors.HexColor("#b45309")
LIGHT_GOLD = colors.HexColor("#fef3c7")
LIGHT_GREEN = colors.HexColor("#dcfce7")
LIGHT_RED = colors.HexColor("#fee2e2")
LIGHT_GREY = colors.HexColor("#f3f4f6")
MED_GREY = colors.HexColor("#6b7280")
WHITE = colors.white
BLACK = colors.black
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def style(name, parent="Normal", **kw):
s = ParagraphStyle(name, parent=base[parent], **kw)
return s
COVER_TITLE = style("CoverTitle", fontSize=32, leading=40,
textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica-Bold")
COVER_SUB = style("CoverSub", fontSize=14, leading=20,
textColor=colors.HexColor("#bfdbfe"), alignment=TA_CENTER)
COVER_BOOK = style("CoverBook", fontSize=9, leading=14,
textColor=colors.HexColor("#93c5fd"), alignment=TA_CENTER)
PART_TITLE = style("PartTitle", fontSize=18, leading=24,
textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER,
spaceAfter=4)
H1 = style("H1", fontSize=14, leading=18,
textColor=WHITE, fontName="Helvetica-Bold",
spaceBefore=10, spaceAfter=4)
H2 = style("H2", fontSize=11, leading=15,
textColor=DARK_BLUE, fontName="Helvetica-Bold",
spaceBefore=8, spaceAfter=3)
H3 = style("H3", fontSize=10, leading=13,
textColor=MID_BLUE, fontName="Helvetica-Bold",
spaceBefore=5, spaceAfter=2)
BODY = style("Body", fontSize=9, leading=13,
textColor=BLACK, spaceAfter=3, alignment=TA_JUSTIFY)
BULLET = style("Bullet", fontSize=9, leading=13,
textColor=BLACK, leftIndent=14, firstLineIndent=-10,
spaceAfter=2)
SUB_BULLET = style("SubBullet", fontSize=8.5, leading=12,
textColor=colors.HexColor("#374151"), leftIndent=26,
firstLineIndent=-10, spaceAfter=1)
TIP_STYLE = style("Tip", fontSize=8.5, leading=12,
textColor=colors.HexColor("#92400e"), leftIndent=6,
rightIndent=6, spaceBefore=4, spaceAfter=4,
backColor=LIGHT_GOLD)
FOOTER_S = style("Footer", fontSize=7, leading=9,
textColor=MED_GREY, alignment=TA_CENTER)
# ── Helper builders ──────────────────────────────────────────────────────────
def part_banner(title):
"""Full-width dark blue banner for part headings."""
data = [[Paragraph(title, PART_TITLE)]]
t = Table(data, colWidths=[17*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [4]),
]))
return t
def section_banner(title):
"""Medium blue banner for section headings."""
data = [[Paragraph(title, H1)]]
t = Table(data, colWidths=[17*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), MID_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return t
def tip_box(text):
return Paragraph(f"<b>▶ KEY TIP:</b> {text}", TIP_STYLE)
def bullet(text, indent=0):
s = SUB_BULLET if indent else BULLET
return Paragraph(f"• {text}", s)
def body(text):
return Paragraph(text, BODY)
def sp(h=4):
return Spacer(1, h)
def make_table(headers, rows, col_widths=None, stripe=True):
data = [headers] + rows
if col_widths is None:
col_widths = [17*cm / len(headers)] * len(headers)
header_style = ParagraphStyle("TH", fontSize=8.5, leading=11,
textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER)
cell_style = ParagraphStyle("TD", fontSize=8, leading=11,
textColor=BLACK, alignment=TA_LEFT)
fmt_data = []
for r_i, row in enumerate(data):
fmt_row = []
for cell in row:
s = header_style if r_i == 0 else cell_style
fmt_row.append(Paragraph(str(cell), s))
fmt_data.append(fmt_row)
t = Table(fmt_data, colWidths=col_widths, repeatRows=1)
cmd = [
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_BLUE] if stripe else [WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cbd5e1")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
t.setStyle(TableStyle(cmd))
return t
def highlight_table(data_rows, col_widths=None):
"""Two-column key-value highlight table (gold bg header)."""
if col_widths is None:
col_widths = [8*cm, 9*cm]
hdr_s = ParagraphStyle("HTH", fontSize=8.5, leading=11,
textColor=WHITE, fontName="Helvetica-Bold")
cell_s = ParagraphStyle("HTC", fontSize=8, leading=11, textColor=BLACK)
fmt = []
for i, row in enumerate(data_rows):
if i == 0:
fmt.append([Paragraph(c, hdr_s) for c in row])
else:
fmt.append([Paragraph(c, cell_s) for c in row])
t = Table(fmt, colWidths=col_widths, repeatRows=1)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), ACCENT_GOLD),
("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#d97706")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
# ── Page template with header/footer ─────────────────────────────────────────
def add_page_decorations(canvas, doc):
canvas.saveState()
w, h = A4
# top bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, h - 18*mm, w, 18*mm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 9)
canvas.drawString(15*mm, h - 11*mm, "General Pathology — Exam Study Guide")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(w - 15*mm, h - 11*mm, "Based on Robbins Pathology")
# bottom bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, 0, w, 10*mm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica", 7)
canvas.drawCentredString(w/2, 3.5*mm, f"Page {doc.page}")
canvas.restoreState()
# ── Cover page ────────────────────────────────────────────────────────────────
def cover_page():
elems = []
# big blue block
cover_data = [[
Paragraph("GENERAL<br/>PATHOLOGY", COVER_TITLE),
]]
ct = Table(cover_data, colWidths=[17*cm])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_BLUE),
("TOPPADDING", (0,0), (-1,-1), 40),
("BOTTOMPADDING", (0,0), (-1,-1), 40),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
]))
elems.append(Spacer(1, 2*cm))
elems.append(ct)
elems.append(sp(10))
elems.append(Paragraph("EXAM STUDY GUIDE", style("CS2", fontSize=16,
textColor=MID_BLUE, alignment=TA_CENTER, fontName="Helvetica-Bold")))
elems.append(sp(6))
elems.append(HRFlowable(width="80%", thickness=2, color=MID_BLUE, hAlign="CENTER"))
elems.append(sp(10))
topics = [
("PART 1", "Cell Injury, Cell Death & Adaptations"),
("PART 2", "Inflammation & Repair"),
("PART 3", "Neoplasia"),
]
for part, topic in topics:
row_data = [[
Paragraph(part, style(f"P_{part}", fontSize=9, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(topic, style(f"T_{part}", fontSize=10, textColor=DARK_BLUE,
fontName="Helvetica-Bold")),
]]
rt = Table(row_data, colWidths=[3*cm, 14*cm])
rt.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), MID_BLUE),
("BACKGROUND", (1,0), (1,-1), LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("LINEBELOW", (0,0), (-1,-1), 1, WHITE),
]))
elems.append(rt)
elems.append(sp(3))
elems.append(sp(20))
elems.append(HRFlowable(width="60%", thickness=1, color=MED_GREY, hAlign="CENTER"))
elems.append(sp(6))
elems.append(Paragraph(
"Source: Robbins Basic Pathology & Robbins, Cotran & Kumar Pathologic Basis of Disease",
style("Src", fontSize=8, textColor=MED_GREY, alignment=TA_CENTER)))
elems.append(PageBreak())
return elems
# ── Content ───────────────────────────────────────────────────────────────────
def part1():
e = []
e.append(part_banner("PART 1 — CELL INJURY, CELL DEATH & ADAPTATIONS"))
e.append(sp(6))
# Key definitions
e.append(KeepTogether([
section_banner("KEY DEFINITIONS"),
sp(4),
bullet("<b>Etiology</b> — the cause/origin of a disease (the <i>why</i>)"),
bullet("<b>Pathogenesis</b> — the steps/mechanisms by which disease develops (the <i>how</i>)"),
bullet("<b>Morphology</b> — structural changes in cells/tissues that characterise a disease"),
bullet("<b>Homeostasis</b> — the steady state that cells maintain by adapting to their environment"),
]))
e.append(sp(8))
# Cellular response spectrum
e.append(section_banner("CELLULAR RESPONSES TO STRESS"))
e.append(sp(4))
e.append(make_table(
["Stress Level", "Cell Response", "Outcome"],
[
["Mild / reversible", "Adaptation (hypertrophy, hyperplasia, atrophy, metaplasia)", "New steady state"],
["Moderate", "Reversible cell injury", "Cell swelling, fatty change"],
["Severe / prolonged", "Irreversible injury → Cell Death", "Necrosis or Apoptosis"],
],
col_widths=[4*cm, 8*cm, 5*cm]
))
e.append(sp(8))
# Causes of cell injury
e.append(section_banner("CAUSES OF CELL INJURY"))
e.append(sp(4))
causes = [
("<b>Hypoxia & Ischemia</b>", "Most common cause; ATP depletion is the key event"),
("<b>Physical agents</b>", "Trauma, extreme temperature, radiation, electric shock"),
("<b>Chemical agents & drugs</b>", "Poisons, pollutants, therapeutic drugs"),
("<b>Infectious agents</b>", "Viruses, bacteria, fungi, parasites"),
("<b>Immunologic reactions</b>", "Autoimmune disease, hypersensitivity"),
("<b>Genetic defects</b>", "Mutations causing protein dysfunction"),
("<b>Nutritional imbalances</b>", "Deficiencies or excess"),
]
e.append(make_table(
["Cause", "Notes"],
causes,
col_widths=[5.5*cm, 11.5*cm]
))
e.append(sp(8))
# Reversible vs Irreversible
e.append(section_banner("REVERSIBLE vs IRREVERSIBLE INJURY"))
e.append(sp(4))
e.append(make_table(
["Feature", "Reversible", "Irreversible"],
[
["Hallmark", "Cell swelling, fatty change", "Membrane damage, lysosomal rupture"],
["Mitochondria", "Swollen, amorphous densities", "Flocculent densities"],
["Key event", "ATP depletion", "Ca²⁺ influx + membrane destruction"],
["Outcome", "Cell recovers", "Necrosis or apoptosis"],
],
col_widths=[4*cm, 6.5*cm, 6.5*cm]
))
e.append(sp(8))
# Mechanisms of injury
e.append(section_banner("MECHANISMS OF CELL INJURY — THE BIG 5"))
e.append(sp(4))
mechs = [
("1. Mitochondrial dysfunction", "ATP depletion → Na⁺/K⁺ pump fails → cell swelling"),
("2. Oxidative stress (ROS)", "Damage DNA, lipids, proteins; generated by reperfusion, drugs, radiation"),
("3. Membrane damage", "Lysosomal leakage, mitochondrial permeability, plasma membrane damage"),
("4. Calcium influx", "Activates destructive enzymes: phospholipases, proteases, endonucleases, ATPases"),
("5. DNA damage / ER stress", "Misfolded proteins → unfolded protein response → cell death"),
]
e.append(make_table(
["Mechanism", "Consequence"],
mechs,
col_widths=[5.5*cm, 11.5*cm]
))
e.append(sp(8))
# Necrosis vs Apoptosis
e.append(section_banner("NECROSIS vs APOPTOSIS"))
e.append(sp(4))
e.append(make_table(
["Feature", "Necrosis", "Apoptosis"],
[
["Cause", "Hypoxia, toxins, severe injury", "Physiologic or pathologic signals"],
["Cell size", "Swells (oncosis)", "Shrinks"],
["Nucleus", "Karyolysis / karyorrhexis / pyknosis", "Fragmentation (ladder on gel)"],
["Membrane", "Disrupted", "Intact (forms blebs)"],
["Inflammation", "YES — contents spill out", "NO — phagocytosed cleanly"],
["Energy needed", "No (passive)", "Yes (active, caspase-mediated)"],
],
col_widths=[4*cm, 6.5*cm, 6.5*cm]
))
e.append(sp(6))
e.append(Paragraph("<b>Types of Necrosis:</b>", H2))
types = [
("<b>Coagulative</b>", "Most organs (heart, kidney); ghost cells, structure preserved", "Ischemic infarct"),
("<b>Liquefactive</b>", "Brain infarct; bacterial abscesses; enzymes dissolve tissue", "Brain stroke, abscess"),
("<b>Caseous</b>", "Soft cheese-like; surrounded by granuloma; AFB positive", "Tuberculosis"),
("<b>Fat</b>", "Saponification, chalky deposits (Ca²⁺ + fatty acids)", "Acute pancreatitis, breast"),
("<b>Fibrinoid</b>", "Immune complexes in vessel walls", "Malignant HTN, vasculitis"),
("<b>Gangrenous</b>", "Dry (coagulative) or wet (liquefactive + infection)", "Diabetic foot, limb ischemia"),
]
e.append(make_table(
["Type", "Features", "Example"],
types,
col_widths=[3.5*cm, 9*cm, 4.5*cm]
))
e.append(sp(6))
e.append(Paragraph("<b>Apoptosis Pathways:</b>", H2))
e.append(bullet("<b>Intrinsic (mitochondrial):</b> DNA damage / growth factor withdrawal → Bcl-2 family regulation → cytochrome c release → caspase-9 → caspase-3 (executioner)"))
e.append(bullet("<b>Extrinsic (death receptor):</b> FasL or TNF binds receptor → DISC → caspase-8 → caspase-3"))
e.append(bullet("<b>Bcl-2</b> is anti-apoptotic — overexpressed in <b>follicular lymphoma t(14;18)</b>"))
e.append(bullet("<b>p53</b> triggers apoptosis in response to DNA damage via intrinsic pathway"))
e.append(sp(8))
# Cellular adaptations
e.append(section_banner("CELLULAR ADAPTATIONS TO STRESS"))
e.append(sp(4))
e.append(make_table(
["Adaptation", "Definition", "Physiologic Example", "Pathologic Example"],
[
["Hypertrophy", "↑ cell size", "Uterus in pregnancy; skeletal muscle with exercise", "Cardiac hypertrophy in HTN"],
["Hyperplasia", "↑ cell number", "Endometrium in menstrual cycle", "Endometrial hyperplasia (excess estrogen)"],
["Atrophy", "↓ cell size + number", "Muscle in weightlessness", "Disuse atrophy, denervation atrophy"],
["Metaplasia", "One cell type → another", "None (usually pathologic)", "Barrett esophagus; smoker's bronchi (columnar → squamous)"],
],
col_widths=[3*cm, 3.5*cm, 5.5*cm, 5*cm]
))
e.append(sp(4))
e.append(tip_box("Metaplasia is REVERSIBLE, but predisposes to dysplasia and cancer if the stimulus persists."))
e.append(sp(8))
# Intracellular depositions
e.append(section_banner("INTRACELLULAR ACCUMULATIONS & CALCIFICATION"))
e.append(sp(4))
e.append(Paragraph("<b>Common Accumulations:</b>", H2))
e.append(bullet("<b>Fatty change (steatosis)</b> — liver, heart; in alcoholism, obesity, DM"))
e.append(bullet("<b>Protein bodies</b> — Mallory bodies (alcoholic liver disease), Russell bodies (plasma cells)"))
e.append(bullet("<b>Glycogen</b> — DM, glycogen storage diseases"))
e.append(Paragraph("<b>Pigments:</b>", H3))
pigments = [
["Lipofuscin", "'Wear-and-tear' pigment", "Brown granules in aging/atrophied cells"],
["Hemosiderin", "Iron from degraded hemoglobin", "Hemosiderosis (local) vs Hemochromatosis (systemic)"],
["Melanin", "Normal skin pigment", "Excess in Addison disease"],
["Carbon (anthracite)", "Inhaled carbon particles", "Anthracosis — coal miners' lung"],
]
e.append(make_table(["Pigment", "Origin", "Significance"], pigments,
col_widths=[4*cm, 6*cm, 7*cm]))
e.append(sp(5))
e.append(Paragraph("<b>Pathologic Calcification:</b>", H2))
e.append(make_table(
["Type", "Serum Ca²⁺", "Site", "Examples"],
[
["Dystrophic", "NORMAL", "Dead / necrotic tissue", "TB foci, atherosclerosis, dead parasites, fat necrosis"],
["Metastatic", "HIGH (hypercalcemia)", "Normal tissue", "Hyperparathyroidism, sarcoidosis, hypervitaminosis D"],
],
col_widths=[3.5*cm, 3*cm, 4*cm, 6.5*cm]
))
e.append(PageBreak())
return e
def part2():
e = []
e.append(part_banner("PART 2 — INFLAMMATION & REPAIR"))
e.append(sp(6))
e.append(section_banner("OVERVIEW OF INFLAMMATION"))
e.append(sp(4))
e.append(body("Inflammation is a protective vascular-connective tissue response that eliminates the cause of injury, removes damaged tissue, and initiates repair. It can be harmful when excessive (e.g., sepsis, autoimmunity, atherosclerosis)."))
e.append(sp(4))
e.append(Paragraph("<b>Cardinal Signs (Celsus + Virchow):</b>", H2))
signs = [
["<b>Rubor</b>", "Redness", "Vasodilation → ↑ blood flow"],
["<b>Calor</b>", "Heat", "↑ Blood flow to affected area"],
["<b>Tumor</b>", "Swelling", "↑ Vascular permeability → oedema"],
["<b>Dolor</b>", "Pain", "Bradykinin, PGE2, serotonin"],
["<b>Functio laesa</b>", "Loss of function", "Combination of all above"],
]
e.append(make_table(["Sign", "Meaning", "Mechanism"], signs,
col_widths=[3*cm, 4*cm, 10*cm]))
e.append(sp(8))
e.append(section_banner("RECOGNITION — PATTERN RECOGNITION RECEPTORS (PRRs)"))
e.append(sp(4))
e.append(bullet("<b>Toll-like receptors (TLRs)</b> — on cell surface & endosomes; recognise PAMPs and DAMPs"))
e.append(bullet("<b>NOD-like receptors (NLRs)</b> — cytosolic; form the <b>Inflammasome</b> → activates IL-1β"))
e.append(bullet("<b>PAMPs</b> = pathogen-associated molecular patterns (e.g., LPS, bacterial DNA)"))
e.append(bullet("<b>DAMPs</b> = damage-associated molecular patterns (e.g., leaked DNA, ATP, uric acid)"))
e.append(sp(8))
e.append(section_banner("ACUTE INFLAMMATION"))
e.append(sp(4))
e.append(body("Three major components: (1) vasodilation, (2) ↑ vascular permeability, (3) leukocyte emigration — primarily in <b>postcapillary venules</b>."))
e.append(sp(4))
e.append(Paragraph("<b>Leukocyte Recruitment — Step by Step:</b>", H2))
steps = [
["1. Margination", "Stasis → leukocytes move to vessel periphery"],
["2. Rolling", "Selectins (E/P-selectin on endothelium; L-selectin on leukocyte)"],
["3. Adhesion", "ICAM-1 (endothelium) + Integrins LFA-1/Mac-1 (leukocyte)"],
["4. Transmigration", "PECAM-1 (CD31) — diapedesis through vessel wall"],
["5. Chemotaxis", "C5a, LTB4, IL-8, bacterial fMLP — directional migration"],
["6. Phagocytosis", "Recognition (opsonins: IgG, C3b) → engulfment → killing"],
]
e.append(make_table(["Step", "Key Molecules / Details"], steps,
col_widths=[4*cm, 13*cm]))
e.append(sp(5))
e.append(Paragraph("<b>Phagocytosis & Killing:</b>", H2))
e.append(bullet("<b>Opsonins:</b> IgG (Fc receptor) and C3b (CR1/CR3) coat the target"))
e.append(bullet("<b>Oxidative killing:</b> NADPH oxidase → O₂⁻ → H₂O₂; myeloperoxidase + H₂O₂ + Cl⁻ → HOCl (most potent)"))
e.append(bullet("<b>Non-oxidative killing:</b> defensins, lysozyme, lactoferrin, BPI"))
e.append(sp(5))
e.append(Paragraph("<b>Leukocyte Defects (HIGH YIELD):</b>", H2))
defects = [
["Chronic Granulomatous Disease (CGD)", "Defective NADPH oxidase", "Catalase-positive organisms (S. aureus, Aspergillus, Pseudomonas)"],
["Chediak-Higashi Syndrome", "Defective lysosomal fusion (LYST gene)", "Recurrent pyogenic infections; giant granules in neutrophils"],
["LAD (Leukocyte Adhesion Deficiency)", "Absent CD18 (β2-integrin)", "Delayed umbilical cord separation; no pus formation"],
["MPO deficiency", "Absent myeloperoxidase", "Usually asymptomatic; ↑ Candida infections in DM"],
]
e.append(make_table(["Disorder", "Defect", "Clinical Feature"],
defects, col_widths=[5*cm, 5*cm, 7*cm]))
e.append(sp(8))
e.append(section_banner("CHEMICAL MEDIATORS OF INFLAMMATION"))
e.append(sp(4))
mediators = [
["<b>Histamine</b>", "Mast cells, platelets", "Vasodilation, ↑ permeability (early, fast)"],
["<b>Serotonin</b>", "Platelets", "↑ Permeability"],
["<b>PGE2 / PGI2</b> (COX)", "Arachidonic acid → COX", "Vasodilation, fever, pain sensitisation"],
["<b>LTB4</b> (LOX)", "Arachidonic acid → LOX", "Neutrophil chemotaxis"],
["<b>LTC4/D4/E4</b> (LOX)", "Mast cells, eosinophils", "Bronchoconstriction, ↑ permeability (slow-reacting SRS-A)"],
["<b>TNF & IL-1</b>", "Macrophages", "Fever, acute-phase response, endothelial activation"],
["<b>IL-6</b>", "Macrophages, T cells", "Induces acute-phase proteins (CRP, fibrinogen) from liver"],
["<b>IL-8 (CXCL8)</b>", "Macrophages, endothelium", "Neutrophil chemotaxis"],
["<b>C3a / C5a</b>", "Complement (liver)", "Anaphylatoxins; C5a = chemotaxis + opsonin; MAC = lysis"],
["<b>Bradykinin</b>", "Kinin system", "Pain, vasodilation, ↑ permeability"],
["<b>NO</b>", "Endothelium, macrophages", "Vasodilation; kills microbes"],
]
e.append(make_table(["Mediator", "Source", "Action"],
mediators, col_widths=[4*cm, 5.5*cm, 7.5*cm]))
e.append(sp(4))
e.append(tip_box("Drug targets: Aspirin/NSAIDs → block COX → ↓ PGs. Corticosteroids → block phospholipase A2 → ↓ ALL AA metabolites. Montelukast → blocks LT receptors (asthma)."))
e.append(sp(8))
e.append(section_banner("MORPHOLOGIC PATTERNS OF ACUTE INFLAMMATION"))
e.append(sp(4))
patterns = [
["<b>Serous</b>", "Watery, protein-poor fluid leaks into body cavities", "Viral pleuritis, skin blister"],
["<b>Fibrinous</b>", "Fibrin exudate; 'bread-and-butter' appearance", "Fibrinous pericarditis, lobar pneumonia"],
["<b>Suppurative / Purulent</b>", "Pus = neutrophils + liquefied debris; abscess = walled-off", "Bacterial meningitis, empyema, liver abscess"],
["<b>Ulcer</b>", "Epithelial defect exposing underlying tissue", "Peptic ulcer, aphthous stomatitis"],
]
e.append(make_table(["Pattern", "Features", "Examples"],
patterns, col_widths=[3.5*cm, 8.5*cm, 5*cm]))
e.append(sp(8))
e.append(section_banner("OUTCOMES OF ACUTE INFLAMMATION"))
e.append(sp(4))
e.append(bullet("<b>Resolution</b> — complete restoration; most viral infections"))
e.append(bullet("<b>Abscess formation</b> — walling off of infection with pus"))
e.append(bullet("<b>Fibrosis / Scarring</b> — if tissue cannot regenerate"))
e.append(bullet("<b>Progression to chronic inflammation</b> — persistent stimulus"))
e.append(sp(8))
e.append(section_banner("CHRONIC INFLAMMATION"))
e.append(sp(4))
e.append(body("Duration: weeks to months. Mononuclear cells predominate. Caused by persistent infection, autoimmune disease, or prolonged exposure to toxic agents."))
e.append(sp(4))
e.append(Paragraph("<b>Key Cells:</b>", H2))
cells = [
["Macrophages", "Most important; activated by IFN-γ from T cells; produce TNF, IL-12, ROS, lysosomal enzymes"],
["Lymphocytes (CD4⁺ T)", "Activate macrophages via IFN-γ; crosstalk amplifies response"],
["Plasma cells", "Secrete antibodies; Russell bodies visible"],
["Eosinophils", "Parasitic infections; allergic reactions; contain major basic protein"],
["Mast cells", "IgE-mediated; release histamine, heparin, cytokines"],
]
e.append(make_table(["Cell", "Role"], cells, col_widths=[4.5*cm, 12.5*cm]))
e.append(sp(6))
e.append(Paragraph("<b>Granulomatous Inflammation:</b>", H2))
e.append(body("Special form of chronic inflammation with <b>epithelioid macrophages</b> (activated, eosinophilic cytoplasm), <b>Langhans giant cells</b> (horseshoe-shaped nuclei), surrounded by CD4⁺ T lymphocytes."))
e.append(sp(4))
granulomas = [
["<b>Tuberculosis</b>", "Caseating (central cheese-like necrosis)", "AFB positive (Ziehl-Neelsen stain)"],
["<b>Sarcoidosis</b>", "'Naked' non-caseating granuloma", "↑ ACE; bilateral hilar adenopathy"],
["<b>Leprosy</b>", "Lepromatous (foamy macrophages) or tuberculoid", "AFB + in lepromatous type"],
["<b>Crohn disease</b>", "Non-caseating; skip lesions in GI tract", "Transmural inflammation"],
["<b>Berylliosis</b>", "Non-caseating; exposure to beryllium", "Mimics sarcoidosis clinically"],
["<b>Foreign body</b>", "Giant cells around foreign material", "Sutures, silica, talc"],
["<b>Cat-scratch disease</b>", "Stellate granuloma with necrosis", "Bartonella henselae"],
]
e.append(make_table(["Disease", "Type", "Key Feature"],
granulomas, col_widths=[4*cm, 7*cm, 6*cm]))
e.append(tip_box("Naked granuloma = Sarcoidosis (no caseation). Caseating granuloma = TB. Always AFB stain for TB!"))
e.append(sp(8))
e.append(section_banner("SYSTEMIC EFFECTS — ACUTE PHASE RESPONSE"))
e.append(sp(4))
e.append(bullet("<b>Fever:</b> IL-1, TNF, IL-6 → COX in hypothalamus → ↑ PGE2 → ↑ set point"))
e.append(bullet("<b>Acute-phase proteins</b> (from liver, induced by IL-6): CRP ↑, fibrinogen ↑, haptoglobin ↑, ferritin ↑; albumin ↓, transferrin ↓"))
e.append(bullet("<b>Leukocytosis:</b> Bacterial = neutrophilia; Viral = lymphocytosis; Parasites/allergy = eosinophilia; Left shift = ↑ bands (immature neutrophils)"))
e.append(bullet("<b>Septic shock:</b> Systemic TNF + IL-1 → ↓ BP, DIC, multi-organ failure"))
e.append(sp(8))
e.append(section_banner("TISSUE REPAIR"))
e.append(sp(4))
e.append(make_table(
["Cell Type", "Examples", "Regenerative Capacity"],
[
["<b>Labile</b> (always dividing)", "GI epithelium, skin, bone marrow, oral mucosa", "Excellent — replace themselves continuously"],
["<b>Stable</b> (quiescent, re-enter cycle)", "Liver, kidney, fibroblasts, osteoblasts", "Good — regenerate on demand"],
["<b>Permanent</b> (cannot divide)", "Neurons, cardiac muscle, skeletal muscle", "Poor — replaced by scar tissue"],
],
col_widths=[4*cm, 7*cm, 6*cm]
))
e.append(sp(5))
e.append(Paragraph("<b>Steps in Scar Formation:</b>", H2))
e.append(bullet("Granulation tissue forms: fibroblasts + new capillaries (angiogenesis via VEGF, FGF)"))
e.append(bullet("Fibroblast activation and collagen deposition — <b>TGF-β is the master regulator</b>"))
e.append(bullet("Remodeling: MMPs (matrix metalloproteinases) balance collagen synthesis vs. degradation"))
e.append(sp(5))
e.append(Paragraph("<b>Factors Impairing Wound Healing:</b>", H2))
e.append(make_table(
["Factor", "Mechanism"],
[
["Infection", "Prolongs inflammation, delays repair"],
["Malnutrition (Vit C deficiency)", "Impairs collagen synthesis (prolyl/lysyl hydroxylase needs Vit C)"],
["Poor blood supply / ischemia", "Lack of O₂ and nutrients"],
["Diabetes mellitus", "↑ Infection, glycosylation of collagen, neuropathy"],
["Corticosteroids", "Inhibit fibroblast proliferation, ↓ TGF-β"],
["Mechanical stress / movement", "Disrupts scar tissue formation"],
],
col_widths=[6*cm, 11*cm]
))
e.append(PageBreak())
return e
def part3():
e = []
e.append(part_banner("PART 3 — NEOPLASIA"))
e.append(sp(6))
e.append(section_banner("DEFINITIONS"))
e.append(sp(4))
e.append(bullet("<b>Neoplasia:</b> abnormal, uncontrolled, purposeless cell proliferation that persists after the initiating stimulus is removed"))
e.append(bullet("<b>Benign tumor:</b> grows locally, does NOT invade or metastasise; well-differentiated"))
e.append(bullet("<b>Malignant tumor:</b> can invade locally AND metastasise; variable differentiation"))
e.append(bullet("<b>Dysplasia:</b> disordered growth — pre-malignant; may regress or progress to carcinoma in situ"))
e.append(bullet("<b>Carcinoma in situ (CIS):</b> full-thickness dysplasia with intact basement membrane"))
e.append(sp(8))
e.append(section_banner("NOMENCLATURE"))
e.append(sp(4))
e.append(make_table(
["Cell Origin", "Benign", "Malignant"],
[
["Squamous epithelium", "Squamous papilloma", "Squamous cell carcinoma"],
["Glandular epithelium", "Adenoma", "Adenocarcinoma"],
["Fibrous tissue", "Fibroma", "Fibrosarcoma"],
["Smooth muscle", "Leiomyoma", "Leiomyosarcoma"],
["Skeletal muscle", "Rhabdomyoma", "Rhabdomyosarcoma"],
["Cartilage", "Chondroma", "Chondrosarcoma"],
["Bone", "Osteoma", "Osteosarcoma"],
["Melanocytes", "Melanocytic nevus (mole)", "Melanoma"],
["Lymphoid tissue", "—", "Lymphoma"],
["Hematopoietic cells", "—", "Leukemia"],
],
col_widths=[5.5*cm, 5.5*cm, 6*cm]
))
e.append(sp(5))
e.append(Paragraph("<b>Special Terms:</b>", H2))
e.append(bullet("<b>Hamartoma:</b> disorganised mass of native tissue (e.g., pulmonary hamartoma — cartilage, glands, fat)"))
e.append(bullet("<b>Choristoma:</b> normal tissue in the wrong location (e.g., gastric mucosa in Meckel's diverticulum)"))
e.append(bullet("<b>Teratoma:</b> all 3 germ layers; mature (benign, cystic) vs. immature (malignant)"))
e.append(sp(8))
e.append(section_banner("BENIGN vs MALIGNANT TUMORS"))
e.append(sp(4))
e.append(make_table(
["Feature", "Benign", "Malignant"],
[
["Differentiation", "Well-differentiated", "Variable; may be anaplastic"],
["Mitoses", "Rare, normal", "Frequent, abnormal (tripolar, multipolar)"],
["Nuclear changes", "Normal", "Pleomorphism, ↑ N:C ratio, prominent nucleoli, hyperchromatism"],
["Growth rate", "Slow", "Fast"],
["Local invasion", "Expansile, encapsulated", "Infiltrative, NOT encapsulated"],
["Metastasis", "NO", "YES — hallmark of malignancy"],
["Necrosis", "Rare", "Common (outgrows blood supply)"],
],
col_widths=[4*cm, 6.5*cm, 6.5*cm]
))
e.append(sp(4))
e.append(tip_box("Anaplasia features: Pleomorphism, hyperchromatism, giant tumor cells, ABNORMAL mitoses, prominent nucleoli, loss of polarity."))
e.append(sp(8))
e.append(section_banner("HALLMARKS OF CANCER (Hanahan & Weinberg)"))
e.append(sp(4))
hallmarks = [
["1. Self-sufficiency in growth signals", "Oncogenes mimic growth factor signalling (RAS, MYC, EGFR)"],
["2. Insensitivity to growth inhibitory signals", "Loss of tumour suppressors (RB, TP53, APC)"],
["3. Evasion of apoptosis", "Overexpression of Bcl-2; loss of p53; survival signals"],
["4. Limitless replicative potential", "Telomerase activation — bypasses Hayflick limit"],
["5. Sustained angiogenesis", "VEGF, FGF secretion; 'angiogenic switch' at ~1mm³ tumour size"],
["6. Invasion and metastasis", "↓ E-cadherin, ↑ MMPs, epithelial-mesenchymal transition (EMT)"],
["7. Evasion of immune surveillance", "PD-L1/PD-1 axis, ↓ MHC-I, CTLA-4, TGF-β secretion"],
["8. Altered metabolism (Warburg effect)", "Aerobic glycolysis even in O₂; ↑ glucose uptake (PET imaging)"],
["9. Tumour-promoting inflammation", "Tumour-associated macrophages supply growth factors"],
["10. Genome instability", "↑ mutation rate; microsatellite instability; chromosomal instability"],
]
e.append(make_table(["Hallmark", "Mechanism / Key Points"],
hallmarks, col_widths=[6*cm, 11*cm]))
e.append(sp(8))
e.append(section_banner("KEY CANCER GENES"))
e.append(sp(4))
e.append(Paragraph("<b>Oncogenes (gain-of-function mutations):</b>", H2))
oncogenes = [
["<b>RAS</b>", "Point mutation → GTPase stays 'on'", "Colon, pancreas, lung"],
["<b>MYC</b>", "Amplification / translocation t(8;14)", "Burkitt lymphoma"],
["<b>HER2/NEU</b>", "Amplification", "Breast cancer (trastuzumab target)"],
["<b>BCR-ABL</b>", "t(9;22) Philadelphia chromosome", "CML (imatinib target)"],
["<b>RET</b>", "Point mutation (germline)", "MEN2, medullary thyroid CA"],
["<b>EGFR</b>", "Mutation / amplification", "Lung adenocarcinoma, CRC"],
["<b>BRAF V600E</b>", "Point mutation", "Melanoma, papillary thyroid CA, hairy cell leukemia"],
]
e.append(make_table(["Oncogene", "Mechanism", "Associated Cancer"],
oncogenes, col_widths=[3.5*cm, 7*cm, 6.5*cm]))
e.append(sp(6))
e.append(Paragraph("<b>Tumour Suppressor Genes (loss-of-function — Knudson Two-Hit):</b>", H2))
tsgs = [
["<b>RB (Rb)</b>", "Cell cycle brake at G1→S checkpoint", "Retinoblastoma, osteosarcoma"],
["<b>TP53</b>", "'Guardian of genome' — DNA repair, apoptosis, cell cycle arrest", "Li-Fraumeni; most human cancers (>50%)"],
["<b>APC</b>", "WNT/β-catenin signalling suppressor", "FAP, sporadic colon cancer"],
["<b>BRCA1/2</b>", "DNA repair (homologous recombination)", "Breast, ovarian cancer"],
["<b>CDKN2A (p16)</b>", "CDK4 inhibitor; halts G1 progression", "Melanoma, pancreatic cancer"],
["<b>VHL</b>", "Regulates HIF-1α stability", "Clear cell renal cell carcinoma"],
["<b>WT1</b>", "Transcription factor in renal development", "Wilms tumor (nephroblastoma)"],
["<b>NF1/NF2</b>", "RAS-GAP / Merlin (cytoskeletal)", "Neurofibromatosis type 1/2"],
]
e.append(make_table(["Gene", "Function", "Associated Cancer"],
tsgs, col_widths=[3.5*cm, 8*cm, 5.5*cm]))
e.append(tip_box("Knudson Two-Hit Hypothesis: Both alleles of a TSG must be inactivated. In hereditary cancers, one hit is inherited (germline) and the second is somatic."))
e.append(sp(8))
e.append(section_banner("INVASION & METASTASIS"))
e.append(sp(4))
e.append(Paragraph("<b>Steps in Metastasis:</b>", H2))
msteps = ["Local invasion (↓ E-cadherin, ↑ MMPs, EMT)",
"Intravasation into blood vessels or lymphatics",
"Survival in circulation (immune evasion, platelet clumping)",
"Extravasation at distant site",
"Colonisation (organ-specific — 'seed and soil' hypothesis, Paget 1889)"]
for i, s in enumerate(msteps, 1):
e.append(bullet(f"<b>{i}.</b> {s}"))
e.append(sp(5))
e.append(make_table(
["Route", "Common Tumors", "Typical Sites"],
[
["Hematogenous", "Sarcomas, choriocarcinoma, thyroid, renal", "Liver, lung, bone, brain"],
["Lymphatic", "Carcinomas (most common route)", "Regional lymph nodes first"],
["Seeding of body cavities", "Colon, ovary, gastric", "Peritoneum; Krukenberg tumor (gastric → both ovaries)"],
["Transcoelomic / CSF spread", "Medulloblastoma, ependymoma", "Spinal cord (drop metastases)"],
],
col_widths=[4*cm, 6*cm, 7*cm]
))
e.append(sp(8))
e.append(section_banner("CARCINOGENIC AGENTS"))
e.append(sp(4))
carcinogens = [
["<b>Polycyclic hydrocarbons</b> (tobacco smoke)", "Chemical", "Lung, bladder, oropharynx"],
["<b>Aflatoxin B1</b> (Aspergillus flavus)", "Chemical / dietary", "Hepatocellular carcinoma"],
["<b>Benzene</b>", "Chemical", "AML / leukemia"],
["<b>Vinyl chloride</b>", "Chemical", "Angiosarcoma of liver"],
["<b>Arsenic</b>", "Chemical", "Skin, lung, bladder"],
["<b>Nitrosamines</b> (smoked/pickled food)", "Chemical / dietary", "Gastric, esophageal"],
["<b>UV light</b> (pyrimidine dimers → XPC)", "Radiation", "Melanoma, BCC, SCC of skin"],
["<b>Ionising radiation</b>", "Radiation", "Leukemia, thyroid CA, breast CA"],
["<b>HPV 16/18</b> (E6→p53↓, E7→RB↓)", "Viral", "Cervical, oropharyngeal"],
["<b>EBV</b>", "Viral", "Burkitt lymphoma, Hodgkin lymphoma, NPC, PTLD"],
["<b>HBV / HCV</b>", "Viral", "Hepatocellular carcinoma"],
["<b>HTLV-1</b>", "Viral", "Adult T-cell leukemia/lymphoma"],
["<b>HHV-8 (KSHV)</b>", "Viral", "Kaposi sarcoma"],
["<b>H. pylori</b>", "Bacterial", "Gastric adenocarcinoma, MALT lymphoma"],
]
e.append(make_table(["Agent", "Category", "Associated Cancer"],
carcinogens, col_widths=[5.5*cm, 4*cm, 7.5*cm]))
e.append(sp(8))
e.append(section_banner("PARANEOPLASTIC SYNDROMES"))
e.append(sp(4))
para = [
["Hypercalcemia", "PTHrP secretion", "Squamous cell CA (lung), breast, renal"],
["SIADH (↓ Na⁺)", "ADH-like peptide secretion", "Small cell lung cancer (SCLC)"],
["Cushing syndrome", "ACTH-like peptide secretion", "SCLC, carcinoid"],
["Polycythemia (↑ RBC)", "Ectopic EPO production", "Renal cell CA, hepatocellular CA"],
["Migratory thrombophlebitis (Trousseau sign)", "Mucin activates clotting cascade", "Pancreatic CA, GI cancers"],
["Eaton-Lambert syndrome", "Anti-VGCC antibodies", "SCLC"],
["Acanthosis nigricans", "TGF-α / other growth factors", "Gastric, lung, GI cancers"],
["Cerebellar degeneration", "Anti-Yo (anti-Purkinje cell)", "Ovarian, breast cancer"],
]
e.append(make_table(["Syndrome", "Mechanism", "Tumor Type"],
para, col_widths=[5.5*cm, 5.5*cm, 6*cm]))
e.append(sp(8))
e.append(section_banner("RAPID REVIEW — HIGH-YIELD BUZZWORD TABLE"))
e.append(sp(4))
buzz = [
["High-Yield Fact", "Answer"],
["Most common cause of cell injury", "Hypoxia / Ischemia"],
["'Guardian of the genome'", "p53 (TP53)"],
["Anti-apoptotic gene in follicular lymphoma", "Bcl-2 — t(14;18)"],
["Caseous necrosis + granuloma", "Tuberculosis"],
["Non-caseating granuloma", "Sarcoidosis"],
["'Bread-and-butter' pericarditis", "Fibrinous inflammation"],
["Defective NADPH oxidase", "Chronic Granulomatous Disease (CGD)"],
["Philadelphia chromosome t(9;22)", "CML — BCR-ABL (imatinib)"],
["t(8;14) MYC translocation", "Burkitt lymphoma"],
["Knudson Two-Hit Hypothesis", "Both alleles of TSG must be hit — e.g., RB"],
["Seed and soil hypothesis", "Paget — organ tropism in metastasis"],
["Hallmark of malignancy", "Metastasis"],
["Warburg effect", "Aerobic glycolysis in tumours (PET uses this)"],
["HPV E6 protein", "Degrades / inactivates p53"],
["HPV E7 protein", "Inactivates RB (pRb)"],
["Wear-and-tear pigment", "Lipofuscin"],
["Dystrophic vs metastatic calcification", "Dystrophic = normal Ca²⁺; Metastatic = high Ca²⁺"],
["Labile vs permanent cells", "Labile regenerate; permanent replaced by scar"],
["Master cytokine in scar formation", "TGF-β"],
["Angiogenesis growth factor", "VEGF (also FGF)"],
["Macrophage activating cytokine", "IFN-γ (from T cells)"],
["Acute-phase protein inducer", "IL-6"],
]
e.append(highlight_table(buzz, col_widths=[8*cm, 9*cm]))
e.append(sp(8))
e.append(HRFlowable(width="100%", thickness=1.5, color=DARK_BLUE))
e.append(sp(6))
e.append(Paragraph(
"<i>Source: Robbins Basic Pathology (Kumar, Abbas, Aster) & Robbins and Cotran Pathologic Basis of Disease. "
"All content is for educational/exam preparation purposes.</i>",
style("Src2", fontSize=7.5, textColor=MED_GREY, alignment=TA_CENTER)
))
return e
# ── Build PDF ─────────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
leftMargin=2*cm,
rightMargin=2*cm,
topMargin=3*cm,
bottomMargin=2*cm,
title="General Pathology Exam Study Guide",
author="Orris AI",
subject="Robbins Pathology — Cell Injury, Inflammation, Neoplasia",
)
story = []
story += cover_page()
story += part1()
story += part2()
story += part3()
doc.build(story, onFirstPage=add_page_decorations,
onLaterPages=add_page_decorations)
print(f"PDF saved to: {OUTPUT_PATH}")
if __name__ == "__main__":
build()