Classify the FMT toxicology poisons from the K.S.N. Reddy book. According to their mechanism of action.
| Class | Primary Site/Mechanism | Key Examples |
|---|---|---|
| Corrosive | Local tissue destruction (protein denaturation) | H₂SO₄, NaOH, HNO₃, HgCl₂ |
| Irritant - Inorganic | GI mucosal inflammation; systemic organ toxicity | Arsenic, Mercury, Lead, Phosphorus |
| Irritant - Organic | Mucosal inflammation; cytotoxicity | Ricin, Abrus, Croton, Cantharides |
| Irritant - Mechanical | Physical abrasion of mucosa | Powdered glass, diamond dust |
| Neurotic - Cerebral | CNS depression/excitation | Opiates, Barbiturates, Datura, Alcohol |
| Neurotic - Spinal | Spinal cord excitation | Strychnine |
| Neurotic - Peripheral | NMJ blockade/nerve paralysis | Curare, Conium, Aconite |
| Cardiac | Myocardial/conducting system toxicity | Aconite, Digitalis, Oleander, Cyanide |
| Asphyxiant - Simple | O₂ displacement | CO₂, CH₄, N₂ |
| Asphyxiant - Chemical | HbO₂ block or cytochrome inhibition | CO, Cyanide, Nitrites, H₂S |
| Asphyxiant - Irritant gas | Pulmonary oedema → O₂ failure | Cl₂, NH₃, Phosgene, MIC |
Generate a quick reference PDF comparing signs/symptoms of each poison class
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "created"
mkdir -p /tmp/workspace/fmt-toxicology && echo "ready"
~/fmt-toxicology/generate_pdf.py
#!/usr/bin/env python3
"""
FMT Toxicology Quick Reference PDF
K.S.N. Reddy - Essentials of Forensic Medicine & Toxicology
Classification by Mechanism of Action: Signs & Symptoms
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
import os
OUTPUT = "/tmp/workspace/fmt-toxicology/FMT_Toxicology_Quick_Reference.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
C_DARK = colors.HexColor("#1a1a2e")
C_HEADER_BG = colors.HexColor("#16213e")
C_ACCENT1 = colors.HexColor("#0f3460") # Corrosive – deep navy
C_ACCENT2 = colors.HexColor("#533483") # Irritant – purple
C_ACCENT3 = colors.HexColor("#1a6b4a") # Neurotic – forest green
C_ACCENT4 = colors.HexColor("#9b1b1b") # Cardiac – deep red
C_ACCENT5 = colors.HexColor("#00639b") # Asphyxiant – steel blue
C_LIGHT1 = colors.HexColor("#dce9ff")
C_LIGHT2 = colors.HexColor("#ece5ff")
C_LIGHT3 = colors.HexColor("#d8f3e8")
C_LIGHT4 = colors.HexColor("#ffe0e0")
C_LIGHT5 = colors.HexColor("#d6f0ff")
C_ROW_ALT = colors.HexColor("#f5f5f5")
C_WHITE = colors.white
C_TEXT = colors.HexColor("#222222")
W, H = A4 # 595 x 842
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, **kwargs):
base = kwargs.pop("parent", "Normal")
s = ParagraphStyle(name, parent=styles[base], **kwargs)
return s
TITLE_ST = make_style("DocTitle", parent="Normal",
fontSize=22, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER,
spaceAfter=2, leading=26)
SUBTITLE_ST = make_style("DocSub", parent="Normal",
fontSize=11, fontName="Helvetica",
textColor=colors.HexColor("#b0c4de"), alignment=TA_CENTER,
spaceAfter=4, leading=14)
SECTION_ST = make_style("SecHead", parent="Normal",
fontSize=13, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_LEFT,
leftIndent=6, leading=16)
CELL_HEAD_ST = make_style("CellHead", parent="Normal",
fontSize=8, fontName="Helvetica-Bold",
textColor=C_WHITE, alignment=TA_CENTER, leading=10)
CELL_BODY_ST = make_style("CellBody", parent="Normal",
fontSize=7.5, fontName="Helvetica",
textColor=C_TEXT, alignment=TA_LEFT,
leftIndent=2, leading=9.5)
CELL_BODY_BOLD_ST = make_style("CellBodyB", parent="Normal",
fontSize=7.5, fontName="Helvetica-Bold",
textColor=C_TEXT, alignment=TA_LEFT,
leftIndent=2, leading=9.5)
FOOTNOTE_ST = make_style("Footnote", parent="Normal",
fontSize=7, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#555555"), alignment=TA_LEFT,
leading=9)
LEGEND_ST = make_style("Legend", parent="Normal",
fontSize=7.5, fontName="Helvetica",
textColor=C_TEXT, leading=10)
# ── Data ─────────────────────────────────────────────────────────────────────
poison_data = [
{
"class": "I. CORROSIVE POISONS",
"color": C_ACCENT1,
"light": C_LIGHT1,
"mechanism": "Denature proteins & destroy cell membranes on direct contact. Cause immediate local tissue necrosis (coagulation by acids / liquefaction by alkalis).",
"examples": "H₂SO₄ · HNO₃ · HCl · Carbolic acid · NaOH · KOH · NH₃ · ZnCl₂ · AgNO₃ · HgCl₂",
"local_signs": [
"Severe burning pain in mouth, throat, oesophagus, stomach",
"Whitish/brown/black staining of lips & oral mucosa",
"Acid – coagulative necrosis; tough leathery eschar",
"Alkali – liquefactive necrosis; soft, soapy, slippery",
"Oedema of glottis → stridor / asphyxia",
"Haematemesis; blood-stained vomit",
"Perforation of stomach / oesophagus (peritonitis)",
],
"systemic_signs": [
"Hypotensive shock (fluid loss, haemorrhage)",
"Acute renal failure",
"Laryngeal oedema → respiratory failure",
"Metabolic acidosis (mineral acids)",
"Hypocalcaemia (HF burns – fluoride chelates Ca²⁺)",
],
"pm_findings": [
"Charring/eschar of oral cavity & upper GI tract",
"Acid – stomach wall brownish-black, brittle",
"Alkali – stomach pale, softened, gelatinous",
"Peritonitis if perforation occurred",
],
},
{
"class": "II-A. IRRITANT POISONS – Inorganic (Metals & Non-metals)",
"color": C_ACCENT2,
"light": C_LIGHT2,
"mechanism": "Inflame GI mucosa; absorbed into circulation → organotropic toxicity (liver, kidneys, CNS, bone marrow). Heavy metals bind -SH groups of enzymes, inactivating cellular respiration.",
"examples": "Arsenic · Mercury · Lead · Copper sulphate · Antimony · Zinc phosphide · Phosphorus · Barium · Thallium · Iron",
"local_signs": [
"Burning/colicky abdominal pain",
"Profuse vomiting (may be rice-water in arsenic → mimics cholera)",
"Severe diarrhoea, bloody stools",
"Metallic taste in mouth",
"Salivation / garlic odour (arsenic, phosphorus)",
],
"systemic_signs": [
"Arsenic: Mees' lines (nails), peripheral neuritis, alopecia, 'raindrop' pigmentation",
"Mercury: Salivation, stomatitis, tremor ('hatter's shakes'), erethism",
"Lead: Wrist/foot drop, Burton's line (gums), basophilic stippling, anaemia",
"Copper SO₄: Blue-green vomit, haemolysis, jaundice",
"Phosphorus (yellow): Garlic breath, luminescent vomit, hepatotoxicity (fatty liver)",
"Thallium: Alopecia, peripheral neuritis, GI symptoms",
"Zinc phosphide/AlPO₄: Releases PH₃ gas → pulmonary oedema, cardiac toxicity",
],
"pm_findings": [
"Gastroenteritis; haemorrhagic mucosa",
"Liver: fatty change / necrosis (phosphorus, arsenic)",
"Kidney: proximal tubular necrosis (mercury, arsenic)",
"Mercury: diphtheritic colitis of ascending colon",
"Arsenic: subendocardial haemorrhages (L ventricle)",
],
},
{
"class": "II-B. IRRITANT POISONS – Organic (Vegetable & Animal)",
"color": colors.HexColor("#7b3fa0"),
"light": colors.HexColor("#f3e5ff"),
"mechanism": "Toxic proteins (lectins, alkaloids, resins) disrupt GI epithelium; some (ricin, abrin) inhibit protein synthesis at ribosomal level (N-glycosidase activity on 28S rRNA).",
"examples": "Ricin (Castor) · Abrin (Gunja) · Croton oil · Calotropis · Cantharides · Colocynth · Ergot · Capsicum · Argemone",
"local_signs": [
"Intense burning pain in throat & abdomen",
"Severe vomiting + watery/bloody diarrhoea",
"Salivation, lacrimation",
"Cantharides: blistering of lips/mouth, priapism",
"Ergot: constriction, tingling of extremities (St Anthony's fire)",
],
"systemic_signs": [
"Ricin/Abrin: multiorgan failure 2–5 days; hepatic & renal failure",
"Calotropis: cardiotoxic glycosides → arrhythmia",
"Cantharides: renal damage (haematuria, dysuria), priapism",
"Ergot: vasospasm → gangrene of extremities; uterotonic (abortion)",
"Argemone: epidemic dropsy – pitting oedema, glaucoma, cardiac failure",
],
"pm_findings": [
"Gastroenteritis with haemorrhage",
"Ricin: hepatic necrosis, splenic necrosis",
"Cantharides: renal tubular damage",
"Ergot: dry gangrene of digits/limbs",
],
},
{
"class": "II-C. IRRITANT POISONS – Mechanical",
"color": colors.HexColor("#8a5c00"),
"light": colors.HexColor("#fff4cc"),
"mechanism": "Physical abrasion and laceration of GI mucosa. No chemical toxicity; act by mechanical trauma → haemorrhage, perforation.",
"examples": "Powdered glass · Diamond dust · Hair (mixed in food) · Bamboo spiculae",
"local_signs": [
"Abdominal pain, bloody vomit",
"Haematemesis / melaena",
"Visible lacerations on GI mucosa",
"Peritonitis (if perforation)",
],
"systemic_signs": [
"Haemorrhagic shock (from GI bleeding)",
"Sepsis (secondary to perforation)",
],
"pm_findings": [
"Multiple mucosal lacerations / perforations",
"Foreign material visible in stomach contents",
"No specific toxic organ changes",
],
},
{
"class": "III-A. NEUROTIC – Cerebral (Narcotic / Somniferous)",
"color": C_ACCENT3,
"light": C_LIGHT3,
"mechanism": "Depress CNS via opioid-receptor agonism (opiates), GABA-A enhancement (barbiturates, BZDs), NMDA antagonism, or generalized membrane stabilisation. Reduce neuronal excitability.",
"examples": "Opium / Morphine / Heroin · Codeine · Barbiturates · Benzodiazepines · Chloral hydrate · Chloroform · Ether",
"local_signs": [
"Minimal local irritation",
"Bitter taste (opium)",
],
"systemic_signs": [
"Opiate triad: Pinpoint pupils (miosis) · Coma · Respiratory depression",
"Bradycardia, hypotension",
"Reduced respiratory rate → hypoxia → cyanosis",
"Barbiturates: hyporeflexia, bullous skin lesions ('barb burns')",
"Chloroform: cardiac sensitisation → VF; hepatotoxicity",
"Stages: Exhilaration → Hypnosis → Narcosis → Asphyxia → Death",
],
"pm_findings": [
"Pulmonary oedema (frothy fluid in airways)",
"Congested brain, cerebral oedema",
"Pinpoint pupils (opiates)",
"Liver necrosis (chloroform, barbiturates in chronic use)",
],
},
{
"class": "III-B. NEUROTIC – Cerebral (Deliriant / Exhilarant)",
"color": colors.HexColor("#2d7a2d"),
"light": colors.HexColor("#e6ffe6"),
"mechanism": "Anticholinergic blockade (atropine-like; Datura), cannabinoid receptor agonism (Cannabis), monoamine reuptake inhibition / release (Cocaine). Produce delirium and hallucinations.",
"examples": "Datura (Dhatura / Jimsonweed) · Cannabis (Ganja/Bhang) · Cocaine · Alcohol (early stages)",
"local_signs": [
"Datura: dry mouth, difficulty swallowing",
"Cannabis: injected conjunctivae",
"Cocaine: nasal septum ulceration (chronic snorting)",
],
"systemic_signs": [
"Datura: 'Blind as a bat, hot as a hare, red as a beet, dry as a bone, mad as a hatter' (anticholinergic toxidrome)",
" → Mydriasis, tachycardia, dry flushed skin, hyperthermia, urinary retention, delirium",
"Cannabis: euphoria, time distortion, hunger, tachycardia, paranoia",
"Cocaine: agitation, hypertension, tachycardia, hyperthermia, MI, stroke",
],
"pm_findings": [
"Datura: bladder distension; dry mucous membranes; dilated pupils",
"Cocaine: coronary vasospasm, cardiomegaly (chronic)",
],
},
{
"class": "III-C. NEUROTIC – Spinal Cord Poisons",
"color": colors.HexColor("#0d6b56"),
"light": colors.HexColor("#d5f5ee"),
"mechanism": "Strychnine blocks glycine receptors at Renshaw cells (inhibitory interneurons) in the anterior horn → disinhibition of motor neurons → generalised tetanic spasms.",
"examples": "Strychnine (Nux vomica) · Gelsemium · Brucine",
"local_signs": [
"Bitter taste",
"Slight difficulty swallowing",
],
"systemic_signs": [
"Extreme reflex hyperexcitability (any stimulus triggers convulsion)",
"Opisthotonus (board-like rigidity with spasm in extension)",
"Risus sardonicus (sardonic grin from facial spasm)",
"Violent tetanic convulsions (lucid intervals between spasms)",
"Consciousness retained during convulsions (unlike epilepsy)",
"Cyanosis, hypoxia → death from respiratory failure",
"Hyperthermia during spasms",
],
"pm_findings": [
"Cyanosis (asphyxia)",
"No specific pathological lesion",
"Opisthotonus may be retained at death",
"Congested viscera",
],
},
{
"class": "III-D. NEUROTIC – Peripheral Nerve Poisons",
"color": colors.HexColor("#155d4e"),
"light": colors.HexColor("#c8f0e5"),
"mechanism": "Block neuromuscular junction (curare – competitive nicotinic ACh-R antagonist) or keep voltage-gated Na⁺ channels persistently open (aconitine) causing depolarisation block and cardiac arrhythmia.",
"examples": "Conium maculatum (Hemlock / Coniine) · Curare · Aconite (Aconitine)",
"local_signs": [
"Aconite: immediate tingling/numbness of mouth & lips",
"Hemlock: slight local irritation",
],
"systemic_signs": [
"Aconite: paresthesia spreading downwards; bradycardia; hypotension; ventricular arrhythmias; 'ice-cold' sensation",
"Conium: ascending flaccid paralysis from legs upward; death from respiratory muscle paralysis; consciousness retained",
"Curare: flaccid paralysis (peripheral); no CNS effect; death from respiratory failure",
],
"pm_findings": [
"Asphyxia changes (cyanosis, congestion)",
"No specific organ lesion",
],
},
{
"class": "IV. CARDIAC POISONS",
"color": C_ACCENT4,
"light": C_LIGHT4,
"mechanism": "Cardiac glycosides inhibit Na⁺/K⁺-ATPase → ↑intracellular Na⁺ → ↑intracellular Ca²⁺ → enhanced contractility initially, then arrhythmia. Aconitine keeps Na⁺ channels open → ectopic pacemaker activity.",
"examples": "Aconite · Digitalis (Digoxin) · Oleander (Nerium) · Yellow Oleander (Thevetia) · Quinine · Veratrum · Nicotine (large dose)",
"local_signs": [
"Digitalis: nausea, vomiting (GI side effect)",
"Aconite: intense tingling & burning of mouth (distinctive)",
"Oleander: GI irritation",
],
"systemic_signs": [
"Bradycardia, heart block (AV block – digoxin)",
"Ventricular tachycardia / fibrillation (aconite, oleander)",
"Hypotension, shock",
"Digitalis toxicity: xanthopsia (yellow vision), ECG – 'reverse tick' ST depression",
"Aconite: severe hypotension, hypothermia, 'near-death' tingling sensation",
"Quinine: cinchonism (tinnitus, deafness, blurred vision), QT prolongation → TdP",
"Nicotine: initial HTN/tachycardia → bradycardia, hypotension, paralysis",
],
"pm_findings": [
"Cardiomegaly or normal heart",
"Coronary vessels may be normal",
"Pulmonary oedema (LHF)",
"Petechial haemorrhages in subepicardium",
],
},
{
"class": "V-A. ASPHYXIANT – Simple (O₂ Displacement)",
"color": C_ACCENT5,
"light": C_LIGHT5,
"mechanism": "Displace O₂ from ambient air without chemical reaction. Reduce pO₂ below 16% → cellular hypoxia. No direct tissue toxicity.",
"examples": "CO₂ (high conc.) · Methane · Nitrogen · Hydrogen · Helium · Argon",
"local_signs": [
"None significant locally",
],
"systemic_signs": [
"Headache, dizziness (early)",
"Tachycardia, rapid respirations",
"Confusion, disorientation",
"Cyanosis, loss of consciousness",
"Convulsions → death (O₂ < 6%)",
"CO₂ additionally: acidosis, Kussmaul breathing",
],
"pm_findings": [
"Cyanosis",
"Visceral congestion",
"Pulmonary oedema",
"No specific lesion",
],
},
{
"class": "V-B. ASPHYXIANT – Chemical (CO & MetHb-formers)",
"color": colors.HexColor("#0056b3"),
"light": colors.HexColor("#cce5ff"),
"mechanism": "CO binds Hb with 200-300× affinity of O₂ → carboxyhaemoglobin → impaired O₂ delivery. Nitrites/aniline/chlorates oxidise Fe²⁺ → Fe³⁺ → methaemoglobin → cannot carry O₂.",
"examples": "Carbon monoxide · Nitrites · Aniline · Dapsone · Chlorates · Nitrobenzene",
"local_signs": [
"CO: headache (often first complaint)",
"MetHb-formers: cyanosis without respiratory distress",
],
"systemic_signs": [
"CO: cherry-red skin & mucosae; headache; 'flu-like'; confusion; syncope; coma",
"CO: ECG changes; rhabdomyolysis; delayed neuropsychiatric syndrome",
"MetHb: chocolate-brown blood; cyanosis; SpO₂ falsely reads ~85%; dyspnoea",
"Both: tachycardia, hypotension, seizures, coma",
],
"pm_findings": [
"CO: cherry-pink hypostasis, blood, muscles, viscera",
"CO: congested brain, pulmonary oedema",
"MetHb: chocolate-brown blood (diagnostic)",
"MetHb: cyanosis despite pink tissues",
],
},
{
"class": "V-C. ASPHYXIANT – Histotoxic (Cyanide & H₂S)",
"color": colors.HexColor("#003d80"),
"light": colors.HexColor("#b8d4ff"),
"mechanism": "Cyanide inhibits cytochrome c oxidase (Complex IV of mitochondrial ETC) → cells cannot utilise O₂ → histotoxic anoxia (venous blood bright red due to unused O₂). H₂S similarly inhibits cytochrome oxidase.",
"examples": "HCN · KCN · NaCN · Hydrogen sulphide (H₂S) · Amygdalin (bitter almonds) · Cassava",
"local_signs": [
"Bitter almond odour (HCN) at scene / autopsy",
"H₂S: rotten eggs odour",
"Burning sensation in throat (rapid onset)",
],
"systemic_signs": [
"Extremely rapid onset (seconds to minutes)",
"Headache, dizziness → convulsions",
"Tachycardia → bradycardia",
"Cardiac arrest (histotoxic anoxia)",
"Skin may be pink (paradoxically well-oxygenated venous blood)",
"H₂S: 'knock-down' effect; pulmonary oedema; conjunctivitis ('gas eye')",
],
"pm_findings": [
"Bitter almond odour on opening body cavities (HCN)",
"Bright cherry-red hypostasis (venous blood oxygenated)",
"Bright red blood and viscera",
"Pulmonary oedema, cerebral oedema",
"No specific organ lesion (death from anoxia)",
],
},
{
"class": "V-D. ASPHYXIANT – Irritant Gases (Pulmonary Oedema)",
"color": colors.HexColor("#005580"),
"light": colors.HexColor("#c2e5f5"),
"mechanism": "React with respiratory tract mucosa → chemical burn → inflammatory mediators → pulmonary oedema and ARDS. Highly water-soluble gases (Cl₂, NH₃) damage upper airway; less soluble (phosgene, NO₂) reach alveoli → delayed oedema.",
"examples": "Chlorine · Ammonia · Phosgene (COCl₂) · MIC (Methyl isocyanate – Bhopal) · SO₂ · NO₂",
"local_signs": [
"Lacrimation, conjunctivitis",
"Rhinorrhoea, burning of nose & throat",
"Stridor (upper airway burn – Cl₂, NH₃)",
"Cough, haemoptysis",
],
"systemic_signs": [
"Bronchospasm, wheezing",
"Phosgene/MIC: delayed pulmonary oedema (4–24 h after exposure)",
"ARDS: tachypnoea, hypoxia, diffuse crackles",
"Reactive airways dysfunction syndrome (chronic)",
"MIC: also GI toxicity, hepatotoxicity, immunosuppression",
],
"pm_findings": [
"Florid pulmonary oedema",
"Haemorrhagic bronchopneumonia",
"Ulceration of respiratory tract mucosa",
"Chlorine: greenish tint to mucosa",
],
},
]
# ── Build flowables ───────────────────────────────────────────────────────────
def header_block(doc_w):
"""Dark header banner."""
data = [[Paragraph("FMT TOXICOLOGY – QUICK REFERENCE", TITLE_ST)]]
t = Table(data, colWidths=[doc_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_HEADER_BG),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def subheader_block(doc_w):
lines = [
"Signs & Symptoms by Mechanism of Action",
"Source: K.S.N. Reddy – Essentials of Forensic Medicine & Toxicology, 36th Ed. (2026)",
]
items = [Paragraph(l, SUBTITLE_ST) for l in lines]
data = [[item] for item in items]
t = Table(data, colWidths=[doc_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_HEADER_BG),
("TOPPADDING", (0,0), (-1,-1), 0),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def section_table(pdata, doc_w):
"""Build one poison class table."""
accent = pdata["color"]
light = pdata["light"]
col_w = [doc_w * f for f in [0.27, 0.30, 0.22, 0.21]]
def bullets(items, bold=False):
st = CELL_BODY_BOLD_ST if bold else CELL_BODY_ST
return "\n".join(f"• {i}" for i in items)
def p(txt, style=CELL_BODY_ST):
return Paragraph(txt, style)
header_row = [
Paragraph("MECHANISM OF ACTION", CELL_HEAD_ST),
Paragraph("SYSTEMIC SIGNS & SYMPTOMS", CELL_HEAD_ST),
Paragraph("LOCAL / GI SIGNS", CELL_HEAD_ST),
Paragraph("POST-MORTEM FINDINGS", CELL_HEAD_ST),
]
content_row = [
p(pdata["mechanism"]),
p(bullets(pdata["systemic_signs"])),
p(bullets(pdata["local_signs"])),
p(bullets(pdata["pm_findings"])),
]
examples_row = [
Paragraph("<b>Key Examples:</b>", CELL_BODY_BOLD_ST),
Paragraph(pdata["examples"], CELL_BODY_ST),
Paragraph("", CELL_BODY_ST),
Paragraph("", CELL_BODY_ST),
]
class_header = [[Paragraph(pdata["class"], SECTION_ST)]]
# Class banner
banner = Table(class_header, colWidths=[doc_w])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), accent),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
# Main data table
tdata = [header_row, content_row, examples_row]
tbl = Table(tdata, colWidths=col_w, repeatRows=1)
tbl.setStyle(TableStyle([
# Header
("BACKGROUND", (0,0), (-1,0), accent),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
# Content row
("BACKGROUND", (0,1), (-1,1), light),
("TOPPADDING", (0,1), (-1,1), 6),
("BOTTOMPADDING", (0,1), (-1,1), 6),
("LEFTPADDING", (0,1), (-1,1), 5),
("RIGHTPADDING", (0,1), (-1,1), 5),
("VALIGN", (0,1), (-1,1), "TOP"),
# Examples row
("BACKGROUND", (0,2), (-1,2), colors.HexColor("#f0f0f0")),
("SPAN", (1,2), (-1,2)),
("TOPPADDING", (0,2), (-1,2), 4),
("BOTTOMPADDING", (0,2), (-1,2), 4),
("LEFTPADDING", (0,2), (-1,2), 5),
# Borders
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("LINEBELOW", (0,0), (-1,0), 1.0, accent),
]))
return KeepTogether([banner, tbl])
def legend_table(doc_w):
items = [
("Cherry-pink hypostasis", "Carbon monoxide poisoning"),
("Chocolate-brown blood", "Methaemoglobinaemia"),
("Bright-red blood/viscera", "Cyanide (histotoxic anoxia)"),
("Garlic odour", "Arsenic / Phosphorus"),
("Bitter almond odour", "Cyanide (HCN)"),
("Rotten eggs odour", "Hydrogen sulphide (H₂S)"),
("Mees' lines (nails)", "Arsenic / Thallium"),
("Burton's blue gum line", "Chronic lead poisoning"),
("Opisthotonus", "Strychnine poisoning"),
("Pinpoint pupils (miosis)", "Opiates (morphine/heroin)"),
("Mydriasis", "Datura / Atropine / Cocaine"),
("Risus sardonicus", "Strychnine"),
]
col_w = [doc_w * 0.35, doc_w * 0.65]
header = [Paragraph("CLASSIC DIAGNOSTIC SIGN", CELL_HEAD_ST),
Paragraph("POISON", CELL_HEAD_ST)]
rows = [[Paragraph(s, CELL_BODY_BOLD_ST), Paragraph(p, CELL_BODY_ST)] for s, p in items]
data = [header] + rows
t = Table(data, colWidths=col_w)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [C_WHITE, C_ROW_ALT]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#bbbbbb")),
("TOPPADDING", (0,1), (-1,-1), 3),
("BOTTOMPADDING", (0,1), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
return t
def antidote_table(doc_w):
items = [
("Opiates", "Naloxone (0.4–2 mg IV)"),
("Organophosphates / Carbamates", "Atropine + Pralidoxime (2-PAM)"),
("Carbon monoxide", "100% O₂; Hyperbaric O₂"),
("Cyanide", "Amyl nitrite + Sodium nitrite + Sodium thiosulphate (or Hydroxocobalamin)"),
("Methaemoglobinaemia", "Methylene blue 1–2 mg/kg IV"),
("Digoxin / Cardiac glycosides", "Digoxin-specific Fab antibody fragments"),
("Iron", "Desferrioxamine (IV/IM)"),
("Lead", "EDTA; Dimercaprol (BAL); DMSA (succimer)"),
("Arsenic / Mercury / Gold", "Dimercaprol (BAL); DMSA; D-Penicillamine"),
("Paracetamol", "N-acetylcysteine (NAC)"),
("Warfarin / Anticoagulants", "Vitamin K; Fresh frozen plasma"),
("Acids / Alkalis (corrosives)", "NO emesis; dilution with water/milk; symptomatic"),
("Benzodiazepines", "Flumazenil"),
("Atropine / Anticholinergics", "Physostigmine"),
("Alcohol (methanol/ethylene glycol)", "Fomepizole; Ethanol; Haemodialysis"),
]
col_w = [doc_w * 0.42, doc_w * 0.58]
header = [Paragraph("POISON / CLASS", CELL_HEAD_ST),
Paragraph("ANTIDOTE / TREATMENT", CELL_HEAD_ST)]
rows = [[Paragraph(p, CELL_BODY_BOLD_ST), Paragraph(a, CELL_BODY_ST)] for p, a in items]
data = [header] + rows
t = Table(data, colWidths=col_w)
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_ACCENT4),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [C_WHITE, C_LIGHT4]),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#bbbbbb")),
("TOPPADDING", (0,1), (-1,-1), 3),
("BOTTOMPADDING", (0,1), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
return t
def make_section_header(title, color, doc_w):
data = [[Paragraph(title, SECTION_ST)]]
t = Table(data, colWidths=[doc_w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
# ── Page template (header / footer) ──────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
W_pt, H_pt = A4
# Footer
canvas.setFillColor(C_DARK)
canvas.rect(0, 0, W_pt, 22, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica", 7)
canvas.drawString(18, 7, "K.S.N. Reddy – Essentials of FMT, 36th Ed. (2026) | Quick Reference – For Educational Use Only")
canvas.drawRightString(W_pt - 18, 7, f"Page {doc.page}")
canvas.restoreState()
# ── Assemble document ─────────────────────────────────────────────────────────
def build_pdf():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=1.5*cm, bottomMargin=1.8*cm,
title="FMT Toxicology Quick Reference",
author="K.S.N. Reddy (36th Ed.)",
subject="Signs & Symptoms by Mechanism of Action",
)
dw = W - 3*cm # usable width
story = []
# ── Title banner
story.append(header_block(dw))
story.append(subheader_block(dw))
story.append(Spacer(1, 6))
# ── Poison class tables
for pdata in poison_data:
story.append(section_table(pdata, dw))
story.append(Spacer(1, 5))
# ── Page break before supplementary tables
story.append(PageBreak())
story.append(header_block(dw))
story.append(Spacer(1, 8))
# Legend
story.append(make_section_header("CLASSIC DIAGNOSTIC SIGNS AT A GLANCE", C_DARK, dw))
story.append(Spacer(1, 4))
story.append(legend_table(dw))
story.append(Spacer(1, 14))
# Antidotes
story.append(make_section_header("KEY ANTIDOTES & EMERGENCY MANAGEMENT", C_ACCENT4, dw))
story.append(Spacer(1, 4))
story.append(antidote_table(dw))
story.append(Spacer(1, 10))
# Footnote
story.append(HRFlowable(width=dw, thickness=0.5, color=colors.HexColor("#aaaaaa")))
story.append(Spacer(1, 4))
story.append(Paragraph(
"This document is compiled for medical education purposes. "
"Clinical management must follow current institutional protocols and specialist guidance. "
"Source: K.S.N. Reddy, The Essentials of Forensic Medicine and Toxicology, 36th Edition, 2026.",
FOOTNOTE_ST
))
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved: {OUTPUT}")
size_kb = os.path.getsize(OUTPUT) // 1024
print(f"File size: {size_kb} KB")
if __name__ == "__main__":
build_pdf()
cd /tmp/workspace/fmt-toxicology && python generate_pdf.py 2>&1
FMT Toxicology Quick Reference
PDF Document · PDF