~/pathology-revision/build_compressed.py
#!/usr/bin/env python3
"""
Builds a compact, dense revision PDF from the raw extracted text.
Strategy:
- Small font sizes (body 7.2pt, headings 8.5-10pt)
- Tight leading
- Two-column layout for body text
- Compact tables with small fonts
- Minimal whitespace
- Color-coded section headings for quick navigation
"""
import re
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import (
BaseDocTemplate, Frame, PageTemplate, Paragraph, Spacer,
Table, TableStyle, HRFlowable, KeepTogether, NextPageTemplate,
PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus.flowables import BalancedColumns
# ── Colours ──────────────────────────────────────────────────────────────────
C_DARK_BLUE = colors.HexColor('#1a237e')
C_MED_BLUE = colors.HexColor('#1565c0')
C_TEAL = colors.HexColor('#00695c')
C_RED = colors.HexColor('#b71c1c')
C_ORANGE = colors.HexColor('#e65100')
C_GREY_BG = colors.HexColor('#f5f5f5')
C_HEADER_BG = colors.HexColor('#e3f2fd')
C_TABLE_HEAD = colors.HexColor('#1565c0')
C_TABLE_ALT = colors.HexColor('#f1f8ff')
C_WHITE = colors.white
C_BLACK = colors.black
C_DIVIDER = colors.HexColor('#90caf9')
W, H = A4
MARGIN = 8 * mm
COL_GAP = 5 * mm
COL_W = (W - 2 * MARGIN - COL_GAP) / 2
# ── Styles ────────────────────────────────────────────────────────────────────
def make_styles():
s = {}
s['cover_title'] = ParagraphStyle('cover_title',
fontName='Helvetica-Bold', fontSize=22, textColor=C_DARK_BLUE,
alignment=TA_CENTER, spaceAfter=4)
s['cover_sub'] = ParagraphStyle('cover_sub',
fontName='Helvetica', fontSize=11, textColor=C_MED_BLUE,
alignment=TA_CENTER, spaceAfter=2)
s['cover_note'] = ParagraphStyle('cover_note',
fontName='Helvetica-Oblique', fontSize=9, textColor=colors.grey,
alignment=TA_CENTER, spaceAfter=2)
s['section'] = ParagraphStyle('section',
fontName='Helvetica-Bold', fontSize=10, textColor=C_WHITE,
backColor=C_DARK_BLUE, spaceBefore=5, spaceAfter=2,
leftIndent=3, borderPad=2, leading=14)
s['subsection'] = ParagraphStyle('subsection',
fontName='Helvetica-Bold', fontSize=8.5, textColor=C_MED_BLUE,
spaceBefore=4, spaceAfter=1, leading=11, borderPad=1)
s['question'] = ParagraphStyle('question',
fontName='Helvetica-Bold', fontSize=8, textColor=C_TEAL,
backColor=C_HEADER_BG, spaceBefore=3, spaceAfter=1,
leftIndent=2, leading=10, borderPad=2)
s['body'] = ParagraphStyle('body',
fontName='Helvetica', fontSize=7.2, textColor=C_BLACK,
spaceBefore=1, spaceAfter=1, leading=9.5, alignment=TA_JUSTIFY)
s['body_bold'] = ParagraphStyle('body_bold',
fontName='Helvetica-Bold', fontSize=7.2, textColor=C_BLACK,
spaceBefore=1, spaceAfter=1, leading=9.5)
s['bullet'] = ParagraphStyle('bullet',
fontName='Helvetica', fontSize=7, textColor=C_BLACK,
spaceBefore=0, spaceAfter=0, leading=9, leftIndent=8,
firstLineIndent=-5)
s['bullet2'] = ParagraphStyle('bullet2',
fontName='Helvetica', fontSize=6.8, textColor=colors.HexColor('#333333'),
spaceBefore=0, spaceAfter=0, leading=8.5, leftIndent=14,
firstLineIndent=-5)
s['label'] = ParagraphStyle('label',
fontName='Helvetica-Bold', fontSize=7, textColor=C_ORANGE,
spaceBefore=2, spaceAfter=0, leading=9)
s['note'] = ParagraphStyle('note',
fontName='Helvetica-Oblique', fontSize=6.5, textColor=colors.HexColor('#555555'),
spaceBefore=0, spaceAfter=1, leading=8)
s['tbl_hdr'] = ParagraphStyle('tbl_hdr',
fontName='Helvetica-Bold', fontSize=6.5, textColor=C_WHITE,
alignment=TA_CENTER, leading=8)
s['tbl_body'] = ParagraphStyle('tbl_body',
fontName='Helvetica', fontSize=6.3, textColor=C_BLACK,
leading=7.5, alignment=TA_LEFT)
s['tbl_body_b'] = ParagraphStyle('tbl_body_b',
fontName='Helvetica-Bold', fontSize=6.3, textColor=C_DARK_BLUE,
leading=7.5, alignment=TA_LEFT)
s['key_point'] = ParagraphStyle('key_point',
fontName='Helvetica-Bold', fontSize=7, textColor=C_RED,
spaceBefore=1, spaceAfter=1, leading=9, leftIndent=4,
backColor=colors.HexColor('#fff3e0'), borderPad=2)
s['footer'] = ParagraphStyle('footer',
fontName='Helvetica', fontSize=6, textColor=colors.grey,
alignment=TA_CENTER)
return s
ST = make_styles()
# ── Table helpers ─────────────────────────────────────────────────────────────
def make_table(headers, rows, col_widths=None, span_full=False):
"""Build a compact styled table."""
usable = W - 2 * MARGIN if span_full else COL_W
if col_widths is None:
n = len(headers)
col_widths = [usable / n] * n
tbl_headers = [Paragraph(h, ST['tbl_hdr']) for h in headers]
data = [tbl_headers]
for i, row in enumerate(rows):
cells = [Paragraph(str(c), ST['tbl_body']) for c in row]
data.append(cells)
tbl = Table(data, colWidths=col_widths, repeatRows=1)
row_count = len(data)
style = [
('BACKGROUND', (0,0), (-1,0), C_TABLE_HEAD),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 6.3),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_WHITE, C_TABLE_ALT]),
('GRID', (0,0), (-1,-1), 0.25, colors.HexColor('#bbdefb')),
('LEFTPADDING', (0,0), (-1,-1), 2),
('RIGHTPADDING', (0,0), (-1,-1), 2),
('TOPPADDING', (0,0), (-1,-1), 1.5),
('BOTTOMPADDING',(0,0), (-1,-1), 1.5),
('VALIGN', (0,0), (-1,-1), 'TOP'),
]
tbl.setStyle(TableStyle(style))
return tbl
def hr():
return HRFlowable(width='100%', thickness=0.5, color=C_DIVIDER,
spaceAfter=2, spaceBefore=2)
def sp(n=2):
return Spacer(1, n)
# ── Content builder ────────────────────────────────────────────────────────────
def build_story():
story = []
# ── COVER PAGE ──────────────────────────────────────────────────────────
story.append(Spacer(1, 30*mm))
story.append(Paragraph("PATHOLOGY PAPER 2", ST['cover_title']))
story.append(Paragraph("Quick Revision Notes", ST['cover_sub']))
story.append(Spacer(1, 3*mm))
story.append(Paragraph("Harsh Mohan | Exam Prep Edition", ST['cover_note']))
story.append(Paragraph("Compressed · High-Yield · All Topics Covered", ST['cover_note']))
story.append(Spacer(1, 6*mm))
# Contents box
toc = [
["1. Oral Cavity & Salivary Glands", "2. Gastrointestinal Tract"],
["3. Liver, Biliary & Pancreas", "4. Kidney & Lower Urinary Tract"],
["5. Male Reproductive System", "6. High-Yield Summary Tables"],
]
toc_tbl = Table(toc, colWidths=[(W-2*MARGIN)/2]*2)
toc_tbl.setStyle(TableStyle([
('FONTNAME', (0,0), (-1,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8),
('TEXTCOLOR', (0,0), (-1,-1), C_MED_BLUE),
('BACKGROUND',(0,0), (-1,-1), C_HEADER_BG),
('GRID', (0,0), (-1,-1), 0.5, C_DIVIDER),
('LEFTPADDING',(0,0),(-1,-1), 6),
('TOPPADDING',(0,0),(-1,-1), 4),
('BOTTOMPADDING',(0,0),(-1,-1), 4),
]))
story.append(toc_tbl)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 1: ORAL CAVITY
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("1. ORAL CAVITY AND SALIVARY GLANDS", ST['section']))
story.append(Paragraph("SN: Pleomorphic Adenoma of Salivary Gland (Pg.516)", ST['question']))
cols1 = [
Paragraph("<b>Definition:</b> Most common benign salivary gland tumor (~60%). Also called <b>mixed tumor</b>. Site: Parotid (70%), submandibular, minor salivary glands.", ST['body']),
Paragraph("<b>Gross:</b> Encapsulated, lobulated, rubbery, grey-white; mucoid/chondroid areas; 2-6 cm.", ST['body']),
Paragraph("<b>Microscopy:</b> (1) Epithelial – ductal/acinar cells forming ducts, tubules; (2) Myoepithelial – spindle/stellate cells; (3) Stroma – myxoid, chondroid, hyaline (cartilage-like). <b>Capsule incomplete</b> – pseudopod projections → recurrence if incompletely excised.", ST['body']),
Paragraph("<b>Behaviour:</b> Benign but locally recurrent. 2-10% risk malignant transformation (carcinoma ex pleomorphic adenoma) after 15+ yrs.", ST['body']),
Paragraph("<b>Treatment:</b> Superficial parotidectomy preserving facial nerve.", ST['body']),
]
for p in cols1:
story.append(p)
story.append(hr())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 2: GI TRACT
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("2. GASTROINTESTINAL TRACT", ST['section']))
# Gastritis
story.append(Paragraph("SN1: Gastritis – Classification & Etiologic Agents", ST['question']))
gastritis_rows = [
["Acute gastritis", "Neutrophilic infiltration"],
["Chronic – H.pylori", "Antral, lymphoplasmacytic"],
["Autoimmune (Type A)", "Fundal, anti-parietal cell Ab"],
["Chemical/Reactive (Type C)", "Bile reflux, NSAIDs"],
["Special forms", "Granulomatous, eosinophilic, lymphocytic"],
]
story.append(make_table(["Type", "Key Features"], gastritis_rows))
story.append(Paragraph("<b>Acute etiologic agents:</b> NSAIDs, Alcohol, Stress (Curling's ulcer-burns; Cushing's-brain injury), Uremia, Corticosteroids, Ischemia, Chemotherapy/radiation, Smoking, Infections (CMV, HSV rare).", ST['body']))
story.append(Paragraph("<b>Morphology:</b> Mucosal edema, hyperemia, neutrophilic infiltration, erosions, mucosal hemorrhage (acute erosive hemorrhagic gastritis).", ST['body']))
story.append(Paragraph("SN2/LAQ4: Gastric Carcinoma (Pg.538)", ST['question']))
story.append(Paragraph("<b>Risk factors:</b> H.pylori (WHO type I carcinogen), high-salt/nitrate diet, atrophic gastritis with intestinal metaplasia, pernicious anemia, partial gastrectomy, CDH1 mutations (hereditary diffuse type), EBV infection (~10%).", ST['body']))
story.append(Paragraph("<b>Correa cascade (intestinal type):</b> Normal → Chronic gastritis → Atrophy → Intestinal metaplasia → Dysplasia → Carcinoma.", ST['key_point']))
gc_rows = [
["Intestinal type", "Gland-forming, expansile", "Antrum/lesser curvature", "Hematogenous (liver)", "CDH1 WT, IM precursor"],
["Diffuse type", "Signet-ring cells, infiltrative", "Fundus/whole stomach", "Peritoneal/lymphatic", "CDH1 mutation, linitis plastica"],
]
story.append(make_table(["Type","Morphology","Location","Spread","Notes"], gc_rows))
story.append(Paragraph("<b>Gross patterns:</b> (1) Polypoid/fungating, (2) Ulcerative (heaped-up everted edges), (3) Diffuse infiltrative – linitis plastica (leather-bottle stomach), (4) Superficial spreading (early).", ST['body']))
story.append(Paragraph("<b>Microscopy:</b> Intestinal – well-formed mucus-secreting glands back-to-back. Diffuse – signet-ring cells (nucleus pushed to periphery by mucin); desmoplastic stroma.", ST['body']))
story.append(Paragraph("<b>Spread:</b> Direct (esophagus, pancreas, colon); Lymphatic (perigastric→celiac→para-aortic, Virchow's node); Hematogenous (liver, lungs); Peritoneal (Krukenberg tumor-ovaries, Sister Mary Joseph nodule-umbilicus, Blumer's shelf).", ST['body']))
story.append(Paragraph("SN3: H. pylori Gastritis (Pg.530-531)", ST['question']))
story.append(Paragraph("<b>H.pylori:</b> Gram-negative spiral rod, microaerophilic, urease-positive.", ST['body']))
story.append(Paragraph("<b>Virulence factors:</b> (1) <b>Urease</b>-generates NH3, neutralizes acid; (2) <b>Flagella</b>-motility; (3) <b>Adhesins</b>-bind foveolar cells; (4) <b>CagA</b>-injected into cells, ↑IL-8, neutrophil chemotaxis, ulcer+cancer risk; (5) <b>VacA</b>-vacuolating cytotoxin.", ST['body']))
story.append(Paragraph("<b>Morphology:</b> Organisms in mucus layer (Giemsa/Warthin-Starry stain); neutrophilic infiltration (active); lymphoplasmacytic infiltrate; lymphoid follicles (MALT→MALT lymphoma); intestinal metaplasia in chronic cases.", ST['body']))
story.append(Paragraph("SN5/SN9: Chronic Peptic Ulcer & Role of H.pylori (Pg.533)", ST['question']))
story.append(Paragraph("<b>Risk factors:</b> H.pylori (90% DU, 70% GU), NSAIDs, smoking, alcohol, stress, ZE syndrome, blood group O.", ST['body']))
story.append(Paragraph("<b>Pathogenesis:</b> Imbalance – aggressive (acid, pepsin, H.pylori, NSAIDs, bile) vs. defensive (mucus, HCO3, PGs, blood flow, epithelial renewal).", ST['body']))
story.append(Paragraph("<b>H.pylori role:</b> Damages mucosa (NH3+toxins), ↑gastrin→↑acid, impairs mucus, promotes chronic inflammation. Eradication heals ulcer & prevents recurrence.", ST['key_point']))
story.append(Paragraph("<b>Gross:</b> Sharply punched-out, round/oval ulcer; flat overhanging edges; clean base; mucosal folds radiating toward ulcer. Site: 1st part duodenum (anterior wall, 95%) > lesser curvature stomach.", ST['body']))
story.append(Paragraph("<b>Microscopy – 4 zones (surface→depth):</b> (1) Necrotic slough (fibrin+WBCs); (2) Fibrinoid necrosis; (3) Granulation tissue; (4) Fibrous scar (collagen).", ST['body']))
story.append(Paragraph("SN6/LAQ1: Ulcerative Colitis vs Crohn's Disease (Pg.552)", ST['question']))
uc_cd_rows = [
["Site", "Colon only (rectum ALWAYS)", "Any GI (mouth to anus)"],
["Distribution", "Continuous, diffuse", "Skip lesions"],
["Depth", "Mucosa/submucosa ONLY", "Transmural (all layers)"],
["Crypt abscesses", "Yes (pathognomonic)", "Occasional"],
["Granulomas", "Absent", "Yes (non-caseating, 60%)"],
["Fistulae", "Rare", "Common"],
["Stricture", "Rare", "Common (fibrosis)"],
["Cobblestone", "No", "Yes"],
["Cancer risk", "HIGH", "Lower"],
["Serology", "p-ANCA +ve", "ASCA +ve"],
["Smoking", "Protective", "Risk factor"],
["Pseudopolyps", "Yes", "No"],
]
story.append(make_table(["Feature", "Ulcerative Colitis", "Crohn's Disease"], uc_cd_rows, span_full=True))
story.append(Paragraph("SN7: Typhoid vs Tubercular Intestinal Ulcers (Pg.553-554)", ST['question']))
tt_rows = [
["Agent", "Salmonella typhi", "Mycobacterium tuberculosis"],
["Site", "Terminal ileum (Peyer's patches)", "Ileocecal region"],
["Orientation", "Transverse (⊥ long axis)", "Circumferential"],
["Edges", "Undermined, overhanging", "Undermined, ragged, caseous"],
["Complications", "Perforation (common)", "Stricture (fibrosis)"],
["Microscopy", "Typhoid nodules, macrophages", "Caseating granulomas, Langerhans GC"],
]
story.append(make_table(["Feature","Typhoid","Tubercular"], tt_rows, span_full=True))
story.append(Paragraph("SN8: Benign vs Malignant Gastric Ulcer (Pg.543)", ST['question']))
bm_rows = [
["Shape", "Round/oval, regular", "Irregular"],
["Size", "<2 cm usually", ">2 cm usually"],
["Edges", "Flat, punched-out; folds radiate TO edge", "Heaped-up, everted, nodular; folds STOP before edge"],
["Base", "Clean, smooth, grey-white slough", "Dirty, necrotic, hemorrhagic"],
["Location", "Lesser curvature, antrum", "Anywhere; especially greater curvature"],
["Biopsy", "No malignant cells", "Malignant glands/signet-ring cells"],
]
story.append(make_table(["Feature","Benign Ulcer","Malignant Ulcer"], bm_rows, span_full=True))
story.append(Paragraph("LAQ2-3: Carcinoma Colon & Rectum (Pg.570)", ST['question']))
story.append(Paragraph("<b>Risk factors:</b> High-fat low-fiber diet, obesity, IBD (UC>Crohn's), FAP (APC gene), HNPCC/Lynch (MLH1,MSH2,MSH6,PMS2), adenomatous polyps (villous>tubular), age>50.", ST['body']))
story.append(Paragraph("<b>Molecular paths:</b> (1) APC/WNT-chromosomal instability (85%): APC→KRAS→SMAD4→TP53→carcinoma; (2) MSI pathway – mismatch repair genes (HNPCC, 15%).", ST['body']))
story.append(Paragraph("<b>Gross:</b> Right colon – polypoid/fungating (presents with anemia). Left colon/rectum – annular napkin-ring → obstruction.", ST['body']))
story.append(Paragraph("<b>Dukes' Staging:</b> A=wall confined; B1=into muscularis (no nodes); B2=through wall (no nodes); C1/C2=node+ve; D=distant mets (liver via portal vein→most common).", ST['body']))
story.append(hr())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 3: LIVER
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("3. LIVER, BILIARY TRACT & EXOCRINE PANCREAS", ST['section']))
story.append(Paragraph("SN1/LAQ2: Alcoholic Liver Disease (Pg.603,606)", ST['question']))
ald_rows = [
["Fatty Liver\n(Steatosis)", "Enlarged, yellow, greasy, soft (up to 4-6 kg)", "Macrovesicular steatosis (zone 3→panlobular); nucleus peripherally pushed. Reversible with abstinence.", "↑NADH→↑FA synthesis, ↓β-oxidation"],
["Alcoholic\nHepatitis", "Enlarged, mottled, red-green", "Hepatocyte ballooning+necrosis (zone3); Mallory-Denk bodies (eosinophilic tangles of IF); neutrophilic infiltrate; megamitochondria; cholestasis", "Acetaldehyde toxicity; CYP2E1 oxidative stress"],
["Cirrhosis", "Micronodular (<3mm), thin fibrous bands", "Fibrous bands, regenerative nodules, loss of lobular architecture. Irreversible.", "Fibrosis from stellate cell activation"],
]
story.append(make_table(["Stage","Gross","Microscopy","Pathogenesis"], ald_rows, span_full=True,
col_widths=[25*mm, 40*mm, 70*mm, 42*mm]))
story.append(Paragraph("<b>Mallory-Denk bodies</b> = eosinophilic intracytoplasmic inclusions (cytokeratin intermediate filament tangles). Neutrophilic infiltrate distinguishes from viral hepatitis (lymphocytic).", ST['key_point']))
story.append(Paragraph("Cirrhosis – Define & Classify", ST['question']))
story.append(Paragraph("<b>Definition:</b> Diffuse fibrosis + conversion of normal architecture into regenerative nodules.", ST['body']))
circ_rows = [
["Micronodular (Laennec's)", "<3 mm", "Alcohol, biliary, hemochromatosis"],
["Macronodular", ">3 mm (variable)", "Viral hepatitis (HBV/HCV), Wilson's, α1AT deficiency"],
["Mixed", "Both", "Various"],
]
story.append(make_table(["Type","Nodule Size","Causes"], circ_rows))
story.append(Paragraph("<b>Complications:</b> Portal HTN (varices, splenomegaly, ascites, caput medusae); hepatic encephalopathy; hepatorenal syndrome; SBP; HCC; coagulopathy; hypoalbuminemia.", ST['body']))
story.append(Paragraph("LAQ3: Post-Necrotic Cirrhosis – Etiopathogenesis & Morphology (Pg.609)", ST['question']))
story.append(Paragraph("<b>Etiology:</b> Chronic HBV/HCV (most common), drug-induced hepatitis (INH, methyldopa, halothane), autoimmune hepatitis, fulminant hepatic failure.", ST['body']))
story.append(Paragraph("<b>Pathogenesis:</b> Bridging necrosis (portal-portal/portal-central) → fibrosis → collapse of reticulin → regeneration of survivors → LARGE nodules.", ST['body']))
story.append(Paragraph("<b>Gross:</b> Shrunken, deformed liver; large irregular nodules (>3mm–several cm) macronodular; deep fibrous scars.", ST['body']))
story.append(Paragraph("<b>Micro:</b> Broad fibrous bands; large regenerative nodules; no normal lobular architecture; cholangiolar proliferation; lymphocytic infiltrate; etiology-specific features (ground-glass cells in HBV).", ST['body']))
story.append(Paragraph("SN2: Acute Viral Hepatitis – Morphologic Features (Pg.595)", ST['question']))
story.append(Paragraph("<b>Gross:</b> Enlarged, congested, yellow-green liver.", ST['body']))
story.append(Paragraph("<b>Microscopy:</b> (1) Hepatocyte ballooning degeneration; (2) <b>Acidophilic (Councilman/apoptotic) bodies</b>-shrunken eosinophilic hepatocytes, pyknotic nucleus; (3) Lobular disarray; (4) Lymphocytes+macrophages (portal+lobular); (5) Kupffer cell hyperplasia+ceroid; (6) Cholestasis (bile plugs); (7) Regenerative activity-mitoses, binucleate cells; (8) Bridging necrosis in severe cases.", ST['body']))
story.append(Paragraph("<b>Zone of injury:</b> HAV/HCV–panlobular; HBV–periportal; Yellow fever–midzonal (zone 2).", ST['key_point']))
story.append(Paragraph("SN3: LFT Differences – Hemolytic vs Hepatocellular vs Obstructive Jaundice", ST['question']))
lft_rows = [
["Serum bilirubin", "↑Unconjugated", "↑Both", "↑Conjugated"],
["Urine bilirubin", "Absent", "Present", "Present (dark urine)"],
["Urine urobilinogen", "↑↑", "↑ or ↓", "Absent"],
["Stool colour", "Dark", "Pale", "Pale/clay-coloured"],
["Alk. phosphatase", "Normal", "Mild ↑", "Marked ↑↑↑"],
["ALT/AST", "Normal", "Marked ↑↑↑", "Mild ↑"],
["PT/INR", "Normal", "Prolonged (no Vit K correction)", "Prolonged (corrects with Vit K)"],
["Serum albumin", "Normal", "Decreased", "Normal (early)"],
]
story.append(make_table(["Parameter","Hemolytic","Hepatocellular","Obstructive"], lft_rows, span_full=True))
story.append(Paragraph("LAQ1: Jaundice – Define, Classify, Causes", ST['question']))
story.append(Paragraph("<b>Definition:</b> Yellow discolouration of skin/sclerae/mucosae due to serum bilirubin >2 mg/dL (sclerae visible >3 mg/dL).", ST['body']))
jaundice_rows = [
["Pre-hepatic (hemolytic)", "Excess unconjugated bilirubin", "Hemolytic anaemia, G6PD deficiency, sickle cell"],
["Hepatocellular", "↓Uptake/conjugation/excretion", "Viral hepatitis, cirrhosis, drugs, Wilson's"],
["Post-hepatic (obstructive)", "Impaired bile flow", "Choledocholithiasis, Ca head pancreas, cholangiocarcinoma"],
["Neonatal physiological", "Low UGT1A1, short RBC life", "Resolves 2 weeks"],
["Hereditary", "Enzyme defects", "Gilbert's, Crigler-Najjar, Dubin-Johnson, Rotor's"],
]
story.append(make_table(["Type","Mechanism","Examples"], jaundice_rows, span_full=True))
story.append(Paragraph("SN7: Hepatitis B – Sequence of Serologic Markers in Acute Infection (Pg.592)", ST['question']))
hbv_rows = [
["HBsAg", "4-8 wks post exposure", "First marker; disappears at recovery; if >6 months = chronic HBV"],
["HBeAg", "Shortly after HBsAg", "Active viral replication; high infectivity"],
["HBV DNA", "With HBsAg", "Best marker of replication"],
["Anti-HBc IgM", "Symptom onset", "Acute infection; ONLY marker in WINDOW PERIOD"],
["Anti-HBc IgG", "Persists lifelong", "Past or current infection marker"],
["Anti-HBe", "After HBeAg clears", "Low infectivity"],
["Anti-HBs", "Last to appear", "Recovery + immunity; vaccination ONLY marker"],
]
story.append(make_table(["Marker","Timing","Significance"], hbv_rows, span_full=True))
story.append(Paragraph("<b>Window period:</b> HBsAg gone, Anti-HBs not yet detectable → ONLY Anti-HBc IgM positive.", ST['key_point']))
story.append(Paragraph("SN8: Amoebic Liver Abscess (Pg.600)", ST['question']))
story.append(Paragraph("<b>Agent:</b> Entamoeba histolytica trophozoites. <b>Path:</b> Colonic ulcers → portal vein → liver → liquefaction.", ST['body']))
story.append(Paragraph("<b>Clinical:</b> RUQ pain, fever, hepatomegaly; may have no bowel symptoms; can rupture into pleura/pericardium.", ST['body']))
story.append(Paragraph("<b>Gross:</b> Single, right lobe; <b>'Anchovy sauce'/'chocolate-brown'</b> material (liquefied necrosis+blood); NO pus; fibrous rim.", ST['body']))
story.append(Paragraph("<b>Micro:</b> Eosinophilic necrotic debris; thin fibrous wall; <b>PAS+ trophozoites at wall-debris junction</b> (contain phagocytosed RBCs); minimal inflammation (unlike pyogenic).", ST['body']))
story.append(Paragraph("<b>Dx:</b> ELISA anti-amoebic antibodies (>95% sensitive).", ST['body']))
story.append(Paragraph("SN4/LAQ: Primary Carcinoma of Liver – HCC (Pg.618)", ST['question']))
story.append(Paragraph("<b>Pathogenesis:</b> Chronic HBV/HCV (HBV integrates→activates oncogenes; HCV via cirrhosis), Aflatoxin B1 (TP53 codon 249 mutation), alcohol, NAFLD/NASH, hereditary hemochromatosis, Wilson's, α1AT def.", ST['body']))
story.append(Paragraph("<b>Gross:</b> Unifocal large/multifocal/diffuse; green (bile), soft; vascular invasion (portal/hepatic veins) – characteristic; pale-grey to yellow-green cut surface.", ST['body']))
hcc_rows = [
["Trabecular (most common)", "Plates 2+ cells thick, sinusoidal vessels"],
["Pseudoglandular (acinar)", "Gland-like structures with bile"],
["Scirrhous", "Abundant fibrous stroma"],
["Fibrolamellar", "Young patients, no cirrhosis, eosinophilic cells+fibrous lamellae, BETTER prognosis"],
]
story.append(make_table(["HCC Pattern","Features"], hcc_rows))
story.append(Paragraph("<b>Markers:</b> AFP elevated ~70%. <b>Spread:</b> Portal vein thrombosis (characteristic), hilar LN, lungs, adrenals.", ST['body']))
story.append(hr())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 4: KIDNEY
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("4. KIDNEY AND LOWER URINARY TRACT", ST['section']))
story.append(Paragraph("SN2/LAQ1: Classification of Glomerular Diseases (Pg.647)", ST['question']))
glom_rows = [
["Post-streptococcal GN", "Nephritic", "Immune complex subepithelial 'humps'", "↓C3, ↑ASO", "Children, post-strep"],
["IgA nephropathy", "Nephritic (recurrent hematuria)", "IgA mesangial deposits", "Normal C3", "Most common GN worldwide"],
["Membranous GN", "Nephrotic", "Subepithelial deposits, GBM spikes", "Normal C3", "Anti-PLA2R Ab; most common adult NS"],
["Minimal Change Disease", "Nephrotic", "Normal LM; foot process effacement EM", "Normal", "Most common in children (80%)"],
["FSGS", "Nephrotic", "Segmental scarring, podocyte injury", "Normal", "HIV, obesity, heroin"],
["RPGN (Crescentic)", "Rapidly progressive", "Crescents >50% glomeruli", "Var.", "Type I/II/III"],
["Membranoproliferative", "Mixed nephritic+nephrotic", "Tram-track GBM, mesangial interposition", "↓C3", "HCV, cryoglobulin"],
]
story.append(make_table(["Type","Syndrome","Morphology","Complement","Notes"], glom_rows, span_full=True,
col_widths=[32*mm,28*mm,48*mm,20*mm,35*mm]))
story.append(Paragraph("Membranous Glomerulopathy – Morphology (Pg.656)", ST['question']))
story.append(Paragraph("<b>LM:</b> Diffuse GBM thickening; spike formation on silver stain.", ST['body']))
story.append(Paragraph("<b>IF:</b> Granular IgG+C3 along capillary walls (subepithelial).", ST['body']))
story.append(Paragraph("<b>EM:</b> Subepithelial electron-dense deposits; podocyte foot process effacement.", ST['body']))
mg_stages = [
["I","Small subepithelial deposits, no GBM thickening"],
["II","Spikes of GBM between deposits (Jones silver stain)"],
["III","Deposits incorporated into GBM (intramembranous)"],
["IV","Lucent zones within thick GBM (scarred stage)"],
]
story.append(make_table(["Stage","Appearance"], mg_stages))
story.append(Paragraph("SN6/LAQ2-3: Post-Streptococcal GN (Pg.652)", ST['question']))
story.append(Paragraph("<b>Etiology:</b> Group A β-hemolytic Strep (nephritogenic strains). Latent period: pharyngitis 1-3 wks; impetigo 3-6 wks.", ST['body']))
story.append(Paragraph("<b>Pathogenesis:</b> Immune complex-mediated (SPEB/NAPlr antigens); complement activation (classical+alternative); neutrophil/macrophage injury.", ST['body']))
story.append(Paragraph("<b>Gross:</b> Bilateral enlarged <b>'flea-bitten'</b> kidneys (petechial hemorrhages).", ST['body']))
story.append(Paragraph("<b>LM:</b> Diffuse endocapillary proliferative GN; hypercellular glomeruli; neutrophilic infiltrate; capillary lumen narrowing.", ST['body']))
story.append(Paragraph("<b>IF:</b> Granular ('lumpy-bumpy') IgG+C3 capillary loops+mesangium – 'starry sky'.", ST['body']))
story.append(Paragraph("<b>EM:</b> Large subepithelial <b>hump-shaped deposits</b> – PATHOGNOMONIC.", ST['key_point']))
story.append(Paragraph("<b>Lab:</b> RBC casts, proteinuria; ↓C3 (C4 normal-alt pathway); ↑ASO titer (throat) or anti-DNase B (skin).", ST['body']))
story.append(Paragraph("<b>Prognosis:</b> 95% children recover completely; adults worse; small % → RPGN/chronic GN.", ST['body']))
story.append(Paragraph("SN4/LAQ1: Rapidly Progressive GN (RPGN) (Pg.654)", ST['question']))
story.append(Paragraph("<b>Definition:</b> Nephritic syndrome with rapid renal failure in weeks-months; >50% glomeruli show crescents.", ST['body']))
rpgn_rows = [
["Type I (anti-GBM)", "Linear IgG along GBM", "Goodpasture syndrome (lungs+kidneys)"],
["Type II (immune complex)", "Granular deposits", "Post-strep, SLE, IgA, MPGN"],
["Type III (pauci-immune)", "No/minimal Ig (ANCA+)", "Wegener's/GPA, microscopic polyangiitis"],
]
story.append(make_table(["Type","IF Pattern","Disease"], rpgn_rows))
story.append(Paragraph("<b>Crescent formation:</b> GBM injury → fibrin in Bowman's space → parietal epithelial cell proliferation + monocyte migration → crescent → compresses tuft → cellular→fibrocellular→fibrous.", ST['body']))
story.append(Paragraph("LAQ2: Glomerular Syndromes / Acute Proliferative GN (Pg.647)", ST['question']))
story.append(Paragraph("<b>Syndromes:</b> (1) Nephritic; (2) Nephrotic; (3) RPGN; (4) Chronic GN; (5) Asymptomatic proteinuria/hematuria.", ST['body']))
story.append(Paragraph("<b>Acute Proliferative GN = Post-Streptococcal GN</b> – see above.", ST['body']))
story.append(Paragraph("SN5: Nephrotic Syndrome – Features (Pg.648)", ST['question']))
story.append(Paragraph("<b>Definition:</b> (1) Massive proteinuria >3.5 g/day; (2) Hypoalbuminemia <3 g/dL; (3) Generalised oedema; (4) Hyperlipidaemia; (5) Lipiduria (oval fat bodies, Maltese cross polarised light).", ST['body']))
story.append(Paragraph("<b>Complications:</b> Infections (↓IgG, complement loss); Thrombosis (↓antithrombin III, protein C/S → renal vein thrombosis especially membranous); Vit D deficiency; Iron-resistant anaemia; Drug toxicity.", ST['body']))
story.append(Paragraph("<b>Causes by age:</b> Children – Minimal Change Disease (80%); Adults – Membranous GN (primary), Diabetic nephropathy (secondary), FSGS.", ST['key_point']))
story.append(Paragraph("SN3: Chronic Pyelonephritis (Pg.669)", ST['question']))
story.append(Paragraph("<b>Pathogenesis:</b> Recurrent UTI + vesicoureteral reflux (reflux nephropathy) or obstruction.", ST['body']))
story.append(Paragraph("<b>Gross (Characteristic):</b> Irregular corticomedullary <b>U-shaped</b> depressed scars (broad-based – vs V-shaped ischaemic); dilated blunted calyces beneath scars; if bilateral → small scarred kidneys.", ST['body']))
story.append(Paragraph("<b>Micro:</b> <b>Thyroidisation</b> (tubules filled with eosinophilic casts resembling thyroid follicles); tubular atrophy; interstitial fibrosis; lymphoplasmacytic infiltrate; periglomerular fibrosis; vascular intimal thickening.", ST['key_point']))
story.append(Paragraph("SN1: Renal Cell Carcinoma (Pg.681)", ST['question']))
rcc_rows = [
["Clear cell (70-80%)", "VHL (3p deletion)", "Golden yellow, haemorrhage, necrosis", "Clear cells (lipid/glycogen), sinusoidal vasculature"],
["Papillary (10-15%)", "MET gene", "Bilateral, multiple", "Papillary fronds with fibrovascular cores"],
["Chromophobe (5%)", "Multiple chromosome losses", "Tan/brown, no necrosis", "Large pale cells, perinuclear halos, Hale colloidal iron+"],
["Collecting duct (<2%)", "Complex", "Infiltrative", "Tubular/tubulopapillary, high grade, poor prognosis"],
]
story.append(make_table(["Type","Genetics","Gross","Micro"], rcc_rows, span_full=True,
col_widths=[30*mm,28*mm,35*mm,60*mm]))
story.append(Paragraph("<b>Clinical triad (only 10% complete):</b> Hematuria + flank pain + palpable mass.", ST['body']))
story.append(Paragraph("<b>Paraneoplastic:</b> Polycythemia (EPO), hypercalcaemia (PTHrP), HTN (renin), Cushing's (ACTH), Stauffer syndrome (hepatic dysfunction).", ST['body']))
story.append(Paragraph("<b>Spread:</b> Renal vein invasion (tumour thrombus→IVC→right heart) – characteristic; hematogenous → lungs (cannonball mets), bones, adrenals, liver.", ST['body']))
story.append(hr())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 5: MALE REPRODUCTIVE
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("5. MALE REPRODUCTIVE SYSTEM", ST['section']))
story.append(Paragraph("SN3: Classify Testicular Tumors (Pg.695)", ST['question']))
story.append(Paragraph("<b>A. Germ Cell Tumors (GCTs) – 95% of testicular tumors:</b>", ST['label']))
story.append(Paragraph("Related to GCNIS: Seminoma (classical); Non-seminomatous – Embryonal carcinoma, Yolk sac tumor, Choriocarcinoma, Teratoma (post-pubertal), Mixed GCT.", ST['body']))
story.append(Paragraph("Unrelated to GCNIS: Spermatocytic tumor (elderly, does NOT metastasize), Pre-pubertal yolk sac tumor, Pre-pubertal teratoma (benign).", ST['body']))
story.append(Paragraph("<b>B. Sex Cord-Stromal Tumors:</b> Leydig cell tumor (most common, androgens/estrogens), Sertoli cell, Granulosa cell.", ST['label']))
story.append(Paragraph("<b>C. Lymphoma:</b> Most common testicular tumor in men >60 yrs (bilateral).", ST['label']))
story.append(Paragraph("<b>D. Metastatic:</b> Prostate (most common), lung, kidney.", ST['label']))
tm_rows = [
["Seminoma", "−", "+ (10%)", "+", "Radiosensitive; >95% cure"],
["Embryonal Ca.", "+", "+", "+", "Most aggressive GCT"],
["Yolk sac tumor", "↑↑↑", "−", "+", "Children; Schiller-Duval bodies"],
["Choriocarcinoma", "−", "↑↑↑", "+", "Hematogenous spread early; worst prognosis"],
["Teratoma", "+ (usu.)", "−", "−", "Post-pubertal = malignant regardless of histology"],
]
story.append(make_table(["Tumor","AFP","β-hCG","LDH","Notes"], tm_rows, span_full=True))
story.append(Paragraph("SN2/LAQ: Seminoma – Gross, Microscopy, Spread (Pg.697)", ST['question']))
story.append(Paragraph("<b>Most common testicular GCT (~50%).</b> Peak: 3rd-4th decade. Types: Classical (95%), Spermatocytic (elderly, NO mets), Anaplastic (rare).", ST['body']))
story.append(Paragraph("<b>Gross:</b> Enlarged testis; <b>homogeneous, lobulated, grey-white</b> tumor; NO hemorrhage/necrosis (unlike non-seminomatous); replaces parenchyma; tunica albuginea intact.", ST['body']))
story.append(Paragraph("<b>Microscopy:</b> (1) Large uniform cells with <b>clear cytoplasm (PAS+ glycogen)</b>, large central nuclei, prominent nucleoli, in lobules/sheets; (2) Fibrous septa with <b>lymphocytic infiltrate (T cells)</b> – characteristic; (3) <b>Granulomatous reaction</b> (giant cells) – common; (4) Syncytiotrophoblasts may be present (mild ↑β-hCG).", ST['body']))
story.append(Paragraph("<b>Spread:</b> (1) <b>Lymphatic (primary route)</b>: para-aortic LN (L1-L2) → mediastinal → supraclavicular – NOT inguinal initially; (2) Haematogenous (late): lungs, liver, brain, bone; (3) Retrograde to inguinal nodes only if tunica/scrotum involved.", ST['body']))
story.append(Paragraph("<b>Treatment:</b> Orchiectomy + radiotherapy (highly radiosensitive); BEP chemo for advanced. <b>Prognosis:</b> >95% cure.", ST['key_point']))
story.append(Paragraph("SN1/LAQ4: Teratoma – Define, Classify, Extragonadal Sites (Pg.699)", ST['question']))
story.append(Paragraph("<b>Definition:</b> Germ cell tumor containing elements from >1 germ layer (ecto, meso, endoderm) in abnormal arrangement.", ST['body']))
ter_rows = [
["Mature (benign)", "Well-differentiated: skin, hair, teeth, sebaceous glands, neural tissue, cartilage, respiratory epithelium"],
["Immature (malignant)", "Primitive/embryonic tissue – neuroepithelium (grade 1-3 by amount of immature neural tissue)"],
["With malignant transformation", "Somatic-type malignancy (e.g. SCC) arising within teratoma"],
]
story.append(make_table(["Type","Features"], ter_rows))
story.append(Paragraph("<b>Gross:</b> Well-demarcated, lobulated; heterogeneous – cystic areas (mucoid/serous), cartilage, bone, hair.", ST['body']))
story.append(Paragraph("<b>Extragonadal sites:</b> Sacrococcygeal (most common in infants – anterior to sacrum), Anterior mediastinum, Retroperitoneum, Pineal gland/brain, Cervical.", ST['key_point']))
story.append(Paragraph("<b>Important:</b> Post-pubertal testicular teratomas behave MALIGNANTLY regardless of histologic appearance; Pre-pubertal are BENIGN.", ST['key_point']))
story.append(Paragraph("SN5/LAQ: Testicular GCTs – Enumerate & Describe Embryonal Carcinoma", ST['question']))
story.append(Paragraph("<b>Enumerate:</b> See classification above (Section 5).", ST['body']))
story.append(Paragraph("<b>Embryonal Carcinoma:</b> Most aggressive GCT. <b>Gross:</b> Smaller than seminoma, heterogeneous, hemorrhage+necrosis common. <b>Micro:</b> Large anaplastic cells with prominent nucleoli in sheets/glands/tubules; frequent mitoses; NO lymphocytic infiltrate. <b>Markers:</b> AFP+, β-hCG+. Spreads early (lymphatic+haematogenous).", ST['body']))
story.append(hr())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 6: HIGH-YIELD SUMMARY TABLE
# ═══════════════════════════════════════════════════════════════════════════
story.append(Paragraph("6. HIGH-YIELD EXAM SUMMARY", ST['section']))
hy_rows = [
["Seminoma", "Homogeneous grey-white", "Clear cells + lymphocytic septae + granulomas", "β-hCG (10%), LDH; AFP neg"],
["Yolk sac tumor", "Mucinous, grey-white", "Schiller-Duval bodies (perivascular pseudorosettes)", "AFP ↑↑↑"],
["Choriocarcinoma", "Hemorrhagic, necrotic", "Cytotrophoblasts + syncytiotrophoblasts", "β-hCG ↑↑↑"],
["Membranous GN", "Pale kidneys", "GBM spikes/domes (Jones silver stain)", "Anti-PLA2R Ab"],
["PSGN", "Flea-bitten kidneys", "Subepithelial HUMPS (EM); lumpy IgG/C3 (IF)", "↓C3, ↑ASO"],
["Alcoholic hepatitis", "Mottled liver", "Mallory-Denk bodies, neutrophils (zone 3)", "AST:ALT >2:1"],
["HCC", "Variegated; vascular invasion", "Trabecular pattern; bile production", "AFP ↑"],
["Gastric Ca (diffuse)", "Linitis plastica", "Signet ring cells, desmoplastic stroma", "CDH1 mutation"],
["Crohn's disease", "Skip lesions, cobblestone", "Transmural, non-caseating granulomas", "ASCA +ve"],
["Ulcerative Colitis", "Continuous; pseudopolyps", "Crypt abscesses, mucosa only", "p-ANCA +ve"],
["Amoebic liver abscess", "Anchovy sauce material", "PAS+ trophozoites at wall-debris junction", "Anti-amoebic ELISA"],
["Chronic pyelonephritis", "Broad U-shaped scars; calyceal dilation", "Thyroidisation, periglomerular fibrosis", "Reflux nephropathy"],
["RCC (clear cell)", "Golden yellow; variegated", "Clear cells, sinusoidal vessels, Fuhrman grade", "VHL mutation; AFP neg"],
["H.pylori gastritis", "Active gastritis, erosions", "Neutrophils, pit abscesses, MALT follicles", "CLO test, UBT"],
["Post-necrotic cirrhosis", "Macronodular, shrunken liver", "Broad fibrous bands, large nodules", "HBV/HCV markers"],
["Pleomorphic adenoma", "Encapsulated, lobulated", "Epithelial + myoepithelial + myxochondroid stroma", "Incomplete capsule → recurrence"],
]
story.append(make_table(
["Condition","Key Gross","Key Microscopy","Key Marker/Fact"],
hy_rows, span_full=True,
col_widths=[35*mm,38*mm,60*mm,44*mm]
))
story.append(Spacer(1, 4*mm))
story.append(Paragraph("Prepared from Harsh Mohan Textbook of Pathology | Robbins & Kumar | Quick Revision Edition", ST['note']))
return story
# ── Document setup ──────────────────────────────────────────────────────────
def build_pdf(output_path):
doc = BaseDocTemplate(
output_path,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=10*mm, bottomMargin=10*mm,
title="Pathology Paper 2 - Quick Revision",
author="Orris AI",
subject="Harsh Mohan Pathology Exam Prep",
)
def on_page(canvas, doc):
canvas.saveState()
# Header bar
canvas.setFillColor(C_DARK_BLUE)
canvas.rect(0, H - 7*mm, W, 7*mm, fill=1, stroke=0)
canvas.setFont('Helvetica-Bold', 6.5)
canvas.setFillColor(C_WHITE)
canvas.drawString(MARGIN, H - 5*mm, "PATHOLOGY PAPER 2 | QUICK REVISION")
canvas.drawRightString(W - MARGIN, H - 5*mm, f"Page {doc.page}")
# Footer
canvas.setFillColor(colors.grey)
canvas.setFont('Helvetica', 5.5)
canvas.drawCentredString(W/2, 5*mm, "Harsh Mohan Pathology · Exam Prep Edition · All rights of original author reserved")
canvas.restoreState()
full_frame = Frame(
MARGIN, 10*mm,
W - 2*MARGIN, H - 17*mm,
id='full', leftPadding=0, rightPadding=0, topPadding=0, bottomPadding=0
)
doc.addPageTemplates([
PageTemplate(id='main', frames=[full_frame], onPage=on_page)
])
story = build_story()
doc.build(story)
print(f"PDF built: {output_path}")
if __name__ == '__main__':
build_pdf('/home/daytona/workspace/pathology-revision/Pathology_Paper2_Revision_Compressed.pdf')