~/rhtc-pocket-guide/generate_pdf.py
from reportlab.lib.pagesizes import A5
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer,
HRFlowable, KeepTogether
)
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/rhtc-pocket-guide/RHTC_Pocket_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY = HexColor("#1a3a5c") # header background
C_TEAL = HexColor("#0d7377") # section title background
C_MINT = HexColor("#e8f5f5") # table alt row
C_AMBER = HexColor("#fff3cd") # warning / note row
C_RED = HexColor("#c0392b") # red-flag text
C_WHITE = colors.white
C_BLACK = colors.black
C_LGRAY = HexColor("#f5f5f5")
C_DGRAY = HexColor("#555555")
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A5,
leftMargin=8*mm, rightMargin=8*mm,
topMargin=8*mm, bottomMargin=8*mm,
)
W = A5[0] - 16*mm # usable width
styles = getSampleStyleSheet()
def style(name, parent="Normal", **kwargs):
return ParagraphStyle(name, parent=styles[parent], **kwargs)
S_TITLE = style("Title2", fontSize=13, textColor=C_WHITE, alignment=TA_CENTER, leading=16, fontName="Helvetica-Bold")
S_HEAD = style("Head2", fontSize=8, textColor=C_WHITE, alignment=TA_CENTER, leading=10, fontName="Helvetica-Bold")
S_CELL = style("Cell2", fontSize=7, textColor=C_BLACK, alignment=TA_LEFT, leading=9, fontName="Helvetica")
S_CELLB = style("CellB2", fontSize=7, textColor=C_BLACK, alignment=TA_LEFT, leading=9, fontName="Helvetica-Bold")
S_NOTE = style("Note2", fontSize=6.5,textColor=C_DGRAY, alignment=TA_LEFT, leading=8, fontName="Helvetica-Oblique")
S_RED = style("Red2", fontSize=6.5,textColor=C_RED, alignment=TA_LEFT, leading=8, fontName="Helvetica-Bold")
S_SEC = style("Sec2", fontSize=8, textColor=C_WHITE, alignment=TA_LEFT, leading=10, fontName="Helvetica-Bold")
S_FOOTER = style("Footer2", fontSize=5.5,textColor=C_DGRAY, alignment=TA_CENTER, leading=7, fontName="Helvetica-Oblique")
# ── Helper: section header bar ───────────────────────────────────────────────
def sec_header(text, color=C_TEAL):
data = [[Paragraph(f"▶ {text}", S_SEC)]]
t = Table(data, colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0), (-1,-1), 5),
]))
return t
# ── Helper: plain table ──────────────────────────────────────────────────────
def make_table(headers, rows, col_widths, alt=True, note=None):
"""Build a styled table with optional note row."""
head_row = [Paragraph(h, S_HEAD) for h in headers]
body = [head_row]
for i, row in enumerate(rows):
styled = [Paragraph(str(c), S_CELLB if i == 0 and False else S_CELL) for c in row]
body.append(styled)
style_cmds = [
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_MINT] if alt else [C_WHITE]),
("GRID", (0,0), (-1,-1), 0.3, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 3),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("FONTSIZE", (0,0), (-1,0), 7),
]
t = Table(body, colWidths=col_widths)
t.setStyle(TableStyle(style_cmds))
elems = [t]
if note:
elems.append(Paragraph(note, S_NOTE))
return elems
# ── Helper: note/warning box ─────────────────────────────────────────────────
def note_box(text, bg=C_AMBER, text_style=None):
s = text_style or S_NOTE
data = [[Paragraph(text, s)]]
t = Table(data, colWidths=[W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 0.5, C_TEAL),
]))
return t
# ════════════════════════════════════════════════════════════════════════════
# Build story
# ════════════════════════════════════════════════════════════════════════════
story = []
SP = lambda n=2: Spacer(1, n*mm)
HR = lambda: HRFlowable(width=W, thickness=0.4, color=HexColor("#cccccc"), spaceAfter=1*mm, spaceBefore=1*mm)
# ── Cover banner ─────────────────────────────────────────────────────────────
banner_data = [[Paragraph("RHTC INTERN POCKET GUIDE", S_TITLE)],
[Paragraph("Quick Reference · Dosing Tables · Red Flags", style("sub", fontSize=7, textColor=C_WHITE, alignment=TA_CENTER, fontName="Helvetica"))]]
banner = Table(banner_data, colWidths=[W])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 4),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story += [banner, SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 1. ACUTE DIARRHEA
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("1. ACUTE DIARRHEA / GASTROENTERITIS"), SP()]
story += make_table(
["Age", "ORS per loose stool", "Zinc (14 days)"],
[
["< 6 months", "50–100 mL", "10 mg/day"],
["6 months – 2 yrs", "100–200 mL", "20 mg/day"],
["2 – 10 yrs", "100–200 mL", "20 mg/day"],
["> 10 yrs / Adults", "200–400 mL", "Not needed"],
],
[30*mm, 60*mm, W-90*mm]
)
story += [SP(), note_box(
"Antibiotics ONLY if: cholera-suspect → Doxycycline 300mg single dose (adults) / Cotrimoxazole in children | "
"Bloody diarrhea/dysentery → Ciprofloxacin 500mg BD×3d (adults); Nalidixic acid in children | "
"Amoebiasis/Giardiasis → Metronidazole 400mg TDS×5–7d"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 2. FEVER / ARI
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("2. FEVER & UPPER RESPIRATORY INFECTION (URTI)"), SP()]
story += make_table(
["Age", "Paracetamol", "Antihistamine"],
[
["< 2 yrs", "10–15 mg/kg/dose Q6H", "Saline nasal drops only"],
["2–12 yrs", "10–15 mg/kg/dose Q6H", "CPM 0.1 mg/kg/dose BD"],
["Adults", "500 mg–1 g Q6H (max 4g/d)","Cetirizine 10mg OD or CPM 4mg TDS"],
],
[25*mm, 60*mm, W-85*mm]
)
story += [SP(), note_box(
"Antibiotics if bacterial (fever>3d, purulent exudate, ear pain): Amoxicillin 500mg TDS (adults) / 25–40mg/kg/day ÷3 (children) ×7d | "
"Pneumonia (tachypnea+fever+chest signs): same dose; REFER if chest indrawing, cyanosis or SpO₂ <94%"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 3. MALARIA
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("3. MALARIA (Confirm with RDT / smear first)"), SP()]
story.append(Paragraph("<b>P. vivax</b> — Chloroquine (CQ 150mg base tab) + Primaquine (PQ 2.5mg tab)", S_CELLB))
story += [SP(1)]
story += make_table(
["Age", "CQ Day1", "CQ Day2", "CQ Day3", "PQ Days 1–14"],
[
["<1 yr", "½", "½", "¼", "Contraindicated"],
["1–4 yrs", "1", "1", "½", "1 tab/day"],
["5–8 yrs", "2", "2", "1", "2 tabs/day"],
["9–14 yrs", "3", "3", "1½", "4 tabs/day"],
["≥15 yrs/Adult","4", "4", "2", "6 tabs/day"],
["Pregnancy", "4", "4", "2", "⚠ OMIT PQ"],
],
[32*mm, 18*mm, 18*mm, 18*mm, W-86*mm]
)
story += [SP(2)]
story.append(Paragraph("<b>P. falciparum</b> — ACT-SP (non-NE India)", S_CELLB))
story += [SP(1)]
story += make_table(
["Age", "Artesunate (50mg) Days 1–3", "SP Day 1", "PQ (large) Day 2"],
[
["<1 yr", "¼ tab/day", "¼", "Contraindicated"],
["1–4 yrs", "½ tab/day", "½", "½ tab"],
["5–8 yrs", "1 tab/day", "1", "¾ tab"],
["9–14 yrs", "2 tabs/day", "1½", "1½ tabs"],
["≥15 yrs/Adult", "4 tabs/day", "3", "2 tabs (45mg)"],
["Pregnancy", "4 tabs/day", "3", "⚠ OMIT PQ (1st tri: avoid ACT)"],
],
[24*mm, 52*mm, 18*mm, W-94*mm]
)
story += [SP(), note_box(
"⚠ PQ contraindicated: infants, pregnancy, G6PD deficiency | "
"Severe malaria → IV Artesunate: REFER immediately | "
"Always give paracetamol for fever control"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 4. ENTERIC FEVER
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("4. ENTERIC FEVER (TYPHOID)"), SP()]
story += make_table(
["Group", "Drug & Dose", "Duration"],
[
["Adults", "Ciprofloxacin 500mg BD OR Azithromycin 1g Day1 then 500mg OD", "14d / 7d"],
["Children", "Azithromycin 20mg/kg/day OD OR Cefixime 20mg/kg/day BD", "7d / 14d"],
["Pregnancy", "Ceftriaxone 2g IV OD — REFER", "14d"],
],
[25*mm, 100*mm, W-125*mm]
)
story += [SP(), note_box(
"Symptomatic: Paracetamol for fever; soft diet; ORS | Avoid NSAIDs (GI bleed/perforation risk)"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 5. ANEMIA (Iron Deficiency)
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("5. IRON DEFICIENCY ANEMIA"), SP()]
story += make_table(
["Group", "Elemental Iron + Folic Acid", "Duration"],
[
["Children 6m–5yr", "Ferrous sulfate 3mg/kg/day ÷2 doses", "3–6 months"],
["5–12 yrs", "60mg Fe + 0.5mg FA once daily", "3 months"],
["Adolescent girls (WIFS)","100mg Fe + 0.5mg FA once weekly (school)", "Ongoing"],
["Pregnant women (IFA)", "100mg Fe + 0.5mg FA twice daily", "Pregnancy + 3m PP"],
["Adults (general)", "100–200mg Fe daily (divided doses)", "3–6 months"],
],
[40*mm, 88*mm, W-128*mm]
)
story += [SP(), note_box(
"Give iron between meals for better absorption; take with lemon juice (Vit C) | "
"Deworming at start: Albendazole 400mg single dose (children >2yr & adults)"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 6. WORM INFESTATION
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("6. INTESTINAL WORMS (Deworming)"), SP()]
story += make_table(
["Age", "Drug", "Dose"],
[
["1–2 yrs", "Albendazole", "200mg single dose"],
[">2 yrs & Adults", "Albendazole", "400mg single dose"],
["Alternative (all)", "Mebendazole", "500mg single dose OR 100mg BD × 3d"],
],
[38*mm, 42*mm, W-80*mm]
)
story += [SP(), note_box("Repeat every 6 months (National Deworming Day) | Always pair with iron supplementation if anemia"), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 7. SCABIES
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("7. SCABIES"), SP()]
story += make_table(
["Age", "Treatment"],
[
["<2 months", "5–10% Sulfur ointment — all over body (below neck) × 3 nights"],
["2m – 2 yrs", "5% Permethrin cream — apply neck to toe, wash off after 8–12h; repeat in 1 week"],
[">2 yrs & Adults", "5% Permethrin OR Benzyl Benzoate 25% (dilute to 12.5% for children)"],
["Adults alt.", "Ivermectin 200 mcg/kg single dose (not in pregnancy / weight <15kg)"],
],
[35*mm, W-35*mm]
)
story += [SP(), note_box(
"TREAT ALL FAMILY MEMBERS SIMULTANEOUSLY | "
"Wash + hot-press all clothing & bedding | CPM for itch | Amoxicillin/Cloxacillin if secondary infection"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 8. SKIN FUNGAL (TINEA)
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("8. FUNGAL SKIN INFECTION (TINEA)"), SP()]
story += make_table(
["Type", "Treatment"],
[
["Localised (tinea corporis/cruris/pedis)", "Clotrimazole 1% cream BD × 2–4 weeks (topical)"],
["Extensive / scalp (tinea capitis)", "Griseofulvin 10–20mg/kg/day (children) OR Fluconazole 150mg weekly × 4wk (adults)"],
["Nail (onychomycosis)", "Itraconazole 200mg OD × 3m OR pulse therapy"],
],
[55*mm, W-55*mm]
)
story += [SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 9. HYPERTENSION
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("9. HYPERTENSION"), SP()]
story += make_table(
["Group", "First-line Drug"],
[
["Adults <60yr", "Amlodipine 2.5–5mg OD; if uncontrolled add Enalapril 5–10mg BD"],
["Elderly >60yr", "Amlodipine 2.5mg OD (start low); avoid ACEI if dry cough"],
["With Diabetes", "ACEI — Enalapril 5–10mg BD (or ARB: Losartan 50mg OD)"],
["Pregnancy", "Methyldopa 250mg BD–TDS OR Labetalol 100mg BD"],
["Hypertensive urgency", "Amlodipine 5–10mg; Enalapril; oral Nifedipine 10mg if needed"],
],
[42*mm, W-42*mm]
)
story += [SP(), note_box(
"Lifestyle: salt <5g/day; reduce alcohol; weight loss; walking 30min/day | "
"BP >180/120 with symptoms → same-day treatment + close monitoring / refer"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 10. DIABETES MELLITUS TYPE 2
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("10. DIABETES MELLITUS TYPE 2"), SP()]
story += make_table(
["Group", "Drug & Dose"],
[
["Adults (non-obese)", "Metformin 500mg OD with meals → titrate to 500mg TDS over weeks"],
["Adults (obese)", "Metformin 500mg–1g BD (start low to avoid GI upset)"],
["Elderly", "Metformin with caution (hold if eGFR <30); Glipizide 5mg OD"],
["Children (Type 1)", "REFER — requires insulin"],
],
[38*mm, W-38*mm]
)
story += [SP(), note_box(
"Targets: FBS <126mg/dL; HbA1c <7% | "
"Diet: avoid white rice excess, sugary drinks, processed foods | Screen: eyes, feet, BP, urine protein at every visit"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 11. UTI
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("11. URINARY TRACT INFECTION (UTI)"), SP()]
story += make_table(
["Group", "Drug & Dose", "Duration"],
[
["Non-pregnant women", "Nitrofurantoin 100mg BD OR Cotrimoxazole DS BD", "5d / 3d"],
["Pregnant women", "Nitrofurantoin 100mg BD (avoid near term) OR Cephalexin 500mg QID", "7d"],
["Men / complicated", "Ciprofloxacin 500mg BD", "7–14d"],
["Elderly", "Ciprofloxacin 500mg BD + ensure adequate hydration", "7d"],
],
[38*mm, 90*mm, W-128*mm]
)
story += [SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 12. EYE — ACUTE CONJUNCTIVITIS
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("12. ACUTE CONJUNCTIVITIS"), SP()]
story += make_table(
["Type", "Treatment"],
[
["Bacterial (all ages)", "Ciprofloxacin 0.3% eye drops 1–2 drops Q2–4H × 7d"],
["Allergic", "Sodium cromoglycate drops + Cetirizine 10mg OD (adults) / CPM (children)"],
["Neonatal (<28 days)", "REFER IMMEDIATELY — Erythromycin/tetracycline ointment + systemic antibiotics"],
],
[42*mm, W-42*mm]
)
story += [SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 13. MUSCULOSKELETAL PAIN
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("13. MUSCULOSKELETAL / JOINT PAIN"), SP()]
story += make_table(
["Condition", "Treatment"],
[
["Osteoarthritis", "Paracetamol 500mg–1g TDS (safer than NSAIDs in elderly) + topical Diclofenac gel"],
["Acute sprains", "RICE + Ibuprofen 400mg TDS × 5d with food; Paracetamol if gastric issues"],
["Mechanical backache","Paracetamol + physiotherapy counseling; avoid prolonged bed rest"],
],
[38*mm, W-38*mm]
)
story += [SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# 14. MALNUTRITION (Children)
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("14. MALNUTRITION (Children <5 years)"), SP()]
story += make_table(
["MUAC", "Grade", "Action"],
[
[">12.5 cm", "Normal", "Dietary counseling, routine care"],
["11.5–12.5 cm", "MAM", "High-energy diet counseling; micronutrients; deworming"],
["<11.5 cm", "SAM", "REFER to NRC; F75→F100 feeds; treat infection"],
],
[22*mm, 22*mm, W-44*mm]
)
story += [SP(), note_box(
"Vitamin A supplementation: 1,00,000 IU (6–11m) / 2,00,000 IU (1–5yr) every 6 months | "
"Zinc 20mg/day × 14d for every diarrheal episode | Deworming every 6 months"
), SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# RED FLAGS
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("🚨 RED FLAGS — WHEN TO REFER", color=C_RED)]
story += [SP()]
story += make_table(
["Condition", "Refer if..."],
[
["Diarrhea", "Unable to drink, sunken eyes, no urine output, altered sensorium"],
["Malaria / Fever", "Altered consciousness, convulsions, severe anemia, jaundice, hyperparasitemia"],
["ARI / Pneumonia", "Chest indrawing, stridor, cyanosis, SpO₂ <92%, unable to feed"],
["Malnutrition", "SAM + complications (infection, edema, hypoglycemia)"],
["Hypertension", "BP >180/120 with headache / visual changes / confusion"],
["Pregnancy", "Heavy bleeding, eclampsia, obstructed labor, fetal distress"],
["Eye", "Neonatal conjunctivitis, corneal ulcer, sudden vision loss"],
],
[38*mm, W-38*mm]
)
story += [SP(3)]
# ════════════════════════════════════════════════════════════════════════════
# QUICK TIPS
# ════════════════════════════════════════════════════════════════════════════
story += [sec_header("INTERN QUICK TIPS"), SP()]
tips = [
"Always confirm malaria with RDT before prescribing antimalarials",
"ORS first in every diarrhea — antibiotics rarely needed",
"Zinc 14 days after every diarrheal episode in children <5yr",
"Deworming every 6 months — combine with iron supplementation",
"PQ contraindicated: infants, pregnancy, G6PD deficiency",
"Scabies: treat ALL family members on the SAME day",
"Metformin: start low (500mg OD) and titrate slowly",
"WIFS scheme: weekly IFA for adolescent girls — record in register",
"MUAC tape at every under-5 visit for malnutrition screening",
"Document everything in OPD register for national health data",
]
tip_data = [[Paragraph(f"• {t}", S_CELL)] for t in tips]
tip_table = Table(tip_data, colWidths=[W])
tip_table.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [C_WHITE, C_LGRAY]),
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 0.3, C_TEAL),
]))
story.append(tip_table)
story += [SP(4)]
# ── Footer ───────────────────────────────────────────────────────────────────
story.append(Paragraph(
"Sources: Park's PSM · Katzung Pharmacology · National Malaria Programme · WHO ARI/Diarrhea Guidelines · WIFS/NDD National Programmes | For educational use — always verify with current guidelines",
S_FOOTER
))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print("PDF generated:", OUTPUT)