Gingivitis and periodontal disease
"periodontal disease"[MeSH Terms] AND "gingivitis"[MeSH Terms]
| Feature | Gingivitis | Periodontitis |
|---|---|---|
| Location | Marginal gingiva only | Deep tissues + bone |
| Bone resorption | Absent | Present |
| Pocket depth | Normal sulcus | Deepened periodontal pocket |
| Reversibility | Reversible | Not reversible |
| Pain | Usually none | Usually none (until abscess) |
| Onset | 2 weeks without brushing | Progresses from gingivitis |




| Category | Features |
|---|---|
| Linear gingival erythema | Distinct linear erythema; does not respond to conventional therapy; closely associated with oral candidiasis |
| Necrotizing periodontal disease | Ulceration of interdental papilla + bleeding + pain; may invade alveolar bone (necrotizing ulcerative periodontitis) |
| Enhanced chronic periodontitis | Worsening of pre-existing disease |
| Stage | Treatment |
|---|---|
| Gingivitis | Plaque removal, improved oral hygiene - fully reversible |
| Chronic periodontitis | Professional scaling/root planing, periodontal surgery; disease can be arrested but bone loss is permanent |
| ANUG | Chlorhexidine 0.12% rinses BID + professional debridement/scaling; metronidazole for immunocompromised or systemic signs |
| Periodontal abscess | Drainage ± antibiotics; NSAIDs for pain |
| HIV-related | Povidone-iodine/chlorhexidine rinses + antifungals + scaling |
Provide me Well formed PDF
mkdir -p /home/daytona/workspace/periodontal-pdf && ls /home/daytona/workspace/
~/periodontal-pdf/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 mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, ListFlowable, ListItem, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Image as RLImage
import urllib.request
import os
import io
# ── Download images ─────────────────────────────────────────────────────────
IMG_DIR = "/home/daytona/workspace/periodontal-pdf/imgs"
os.makedirs(IMG_DIR, exist_ok=True)
image_urls = {
"chronic_perio.png": "https://cdn.orris.care/cdss_images/33356f5f496fb283cc24558359756a3b881076f3538147250b5e8f6bcc49d971.png",
"normal_gingiva.png": "https://cdn.orris.care/cdss_images/2e0ecc7ac02e9f8b4258175ade4bf4bdede06a0097b16e2ac4914a6abb11abd6.png",
"advanced_perio.png": "https://cdn.orris.care/cdss_images/6476ed713e2de55cb2834230b1e1c2383ebd66d0a2c4f89105cb99c4b80d9286.png",
"anug.png": "https://cdn.orris.care/cdss_images/e4049e57bdbde5c93587687f30fad16d0b5fee605d7cb4671f8a7adc7532bb5e.png",
}
for fname, url in image_urls.items():
dest = os.path.join(IMG_DIR, fname)
if not os.path.exists(dest):
try:
urllib.request.urlretrieve(url, dest)
print(f" Downloaded {fname}")
except Exception as e:
print(f" WARN: could not download {fname}: {e}")
# ── Colour palette ───────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1A3557")
TEAL = colors.HexColor("#0D7377")
LIGHT_BG = colors.HexColor("#EAF4F4")
ACCENT = colors.HexColor("#F0A500")
WHITE = colors.white
LIGHT_GREY= colors.HexColor("#F5F7FA")
MID_GREY = colors.HexColor("#B0BAC9")
DARK_GREY = colors.HexColor("#444444")
# ── Styles ───────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def make_style(name, parent="Normal", **kwargs):
return ParagraphStyle(name, parent=base[parent], **kwargs)
sTitle = make_style("sTitle", "Title",
fontSize=26, textColor=WHITE, alignment=TA_CENTER,
spaceAfter=4, leading=32)
sSubT = make_style("sSubT", "Normal",
fontSize=13, textColor=colors.HexColor("#CCE8EA"),
alignment=TA_CENTER, spaceAfter=2)
sH1 = make_style("sH1", "Heading1",
fontSize=14, textColor=WHITE,
spaceAfter=4, spaceBefore=14, leading=18)
sH2 = make_style("sH2", "Heading2",
fontSize=11, textColor=NAVY,
spaceAfter=3, spaceBefore=10, leading=14)
sBody = make_style("sBody", "Normal",
fontSize=9.5, textColor=DARK_GREY, leading=14,
spaceAfter=5, alignment=TA_JUSTIFY)
sBullet = make_style("sBullet", "Normal",
fontSize=9.5, textColor=DARK_GREY, leading=14,
leftIndent=12, spaceAfter=2)
sCaption = make_style("sCaption", "Normal",
fontSize=8, textColor=colors.HexColor("#666666"),
alignment=TA_CENTER, spaceAfter=6, leading=11)
sFooter = make_style("sFooter", "Normal",
fontSize=7.5, textColor=MID_GREY, alignment=TA_CENTER)
sBox = make_style("sBox", "Normal",
fontSize=9.5, textColor=NAVY, leading=14,
leftIndent=8, rightIndent=8, spaceAfter=3)
sTH = make_style("sTH", "Normal",
fontSize=9, textColor=WHITE,
alignment=TA_CENTER, leading=12, fontName="Helvetica-Bold")
sTD = make_style("sTD", "Normal",
fontSize=8.5, textColor=DARK_GREY,
alignment=TA_CENTER, leading=12)
# ── Page template with header/footer ────────────────────────────────────────
PAGE_W, PAGE_H = A4
MARGIN = 2.2 * cm
def on_page(canvas, doc):
canvas.saveState()
# Header bar
canvas.setFillColor(NAVY)
canvas.rect(0, PAGE_H - 1.1*cm, PAGE_W, 1.1*cm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawString(MARGIN, PAGE_H - 0.72*cm, "Gingivitis & Periodontal Disease")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(PAGE_W - MARGIN, PAGE_H - 0.72*cm,
"Medical Reference | Orris")
# Footer
canvas.setFillColor(NAVY)
canvas.rect(0, 0, PAGE_W, 0.9*cm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica", 7.5)
canvas.drawCentredString(PAGE_W/2, 0.32*cm,
f"Page {doc.page} • Sources: Sherris & Ryan's Medical Microbiology | "
"Tintinalli's Emergency Medicine | Scott-Brown's Otorhinolaryngology | "
"Cummings Otolaryngology")
canvas.restoreState()
def on_first_page(canvas, doc):
canvas.saveState()
# Hero gradient strip
canvas.setFillColor(NAVY)
canvas.rect(0, PAGE_H - 6.5*cm, PAGE_W, 6.5*cm, fill=1, stroke=0)
canvas.setFillColor(TEAL)
canvas.rect(0, PAGE_H - 6.5*cm, PAGE_W, 0.4*cm, fill=1, stroke=0)
# Footer
canvas.setFillColor(NAVY)
canvas.rect(0, 0, PAGE_W, 0.9*cm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica", 7.5)
canvas.drawCentredString(PAGE_W/2, 0.32*cm,
"Sources: Sherris & Ryan's Medical Microbiology | Tintinalli's Emergency Medicine | "
"Scott-Brown's Otorhinolaryngology | Cummings Otolaryngology")
canvas.restoreState()
# ── Helper builders ──────────────────────────────────────────────────────────
def section_header(text):
"""Coloured section header band."""
data = [[Paragraph(text, sH1)]]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
return t
def info_box(paragraphs):
"""Light-blue callout box."""
data = [[p] for p in paragraphs]
t = Table(data, colWidths=[PAGE_W - 2*MARGIN - 1.6*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), LIGHT_BG),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("LINEAFTER", (0,0), (0,-1), 4, TEAL),
]))
return t
def two_col_images(path1, cap1, path2, cap2, w=7.2*cm):
img_cells = []
for path, cap in [(path1,cap1),(path2,cap2)]:
cell = []
if path and os.path.exists(path):
cell.append(RLImage(path, width=w, height=5*cm))
cell.append(Paragraph(cap, sCaption))
img_cells.append(cell)
t = Table([img_cells], colWidths=[(PAGE_W-2*MARGIN)/2]*2)
t.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 4),
]))
return t
def single_image(path, cap, w=10*cm, h=6*cm):
cells = []
if path and os.path.exists(path):
cells.append(RLImage(path, width=w, height=h))
cells.append(Paragraph(cap, sCaption))
t = Table([[c] for c in cells], colWidths=[PAGE_W-2*MARGIN])
t.setStyle(TableStyle([
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
]))
return t
def make_table(headers, rows, col_widths=None):
if col_widths is None:
n = len(headers)
col_widths = [(PAGE_W - 2*MARGIN) / n] * n
th_row = [Paragraph(h, sTH) for h in headers]
td_rows = [[Paragraph(str(c), sTD) for c in row] for row in rows]
data = [th_row] + td_rows
t = Table(data, colWidths=col_widths, repeatRows=1)
style = [
("BACKGROUND", (0,0), (-1,0), NAVY),
("BACKGROUND", (0,1), (-1,-1), LIGHT_GREY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LIGHT_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
t.setStyle(TableStyle(style))
return t
# ── Build story ──────────────────────────────────────────────────────────────
story = []
# ─── COVER (first page content) ─────────────────────────────────────────────
story.append(Spacer(1, 5.2*cm)) # space below hero bar
story.append(Paragraph("Gingivitis & Periodontal Disease", sTitle))
story.append(Paragraph("A Comprehensive Medical Reference", sSubT))
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph(
"Sources: Sherris & Ryan's Medical Microbiology · Tintinalli's Emergency Medicine · "
"Scott-Brown's Otorhinolaryngology · Cummings Otolaryngology · Junqueira's Basic Histology",
sSubT))
story.append(Spacer(1, 1*cm))
story.append(HRFlowable(width="100%", thickness=1, color=TEAL, spaceAfter=12))
# Quick overview box
story.append(info_box([
Paragraph("<b>Overview</b>", sBox),
Paragraph(
"Periodontal disease is a continuum that begins with <b>gingivitis</b> — reversible "
"inflammation of the marginal gingiva — and may progress to <b>chronic periodontitis</b>, "
"with irreversible destruction of the periodontal ligament, alveolar bone, and ultimately "
"tooth loss. Both conditions are driven by polymicrobial anaerobic plaque bacteria, modified "
"by host immune response, genetics, and systemic factors.",
sBox),
]))
story.append(Spacer(1, 0.6*cm))
# Chronic periodontitis hero image
p = os.path.join(IMG_DIR, "chronic_perio.png")
story.append(single_image(p,
"Figure 1. Chronic periodontitis — inflamed, swollen gingiva with heavy plaque accumulation "
"and calculus deposits. (Scott-Brown's Otorhinolaryngology)",
w=12*cm, h=7*cm))
story.append(PageBreak())
# ─── SECTION 1: Anatomy ──────────────────────────────────────────────────────
story.append(section_header("1. Normal Anatomy of the Periodontium"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"The <b>periodontium</b> (attachment apparatus) anchors each tooth to the alveolar bone and "
"maintains the integrity of the dentoalveolar unit. It comprises two functional components:",
sBody))
story.append(make_table(
["Component", "Structures Included", "Primary Function"],
[
["Gingival component", "Junctional epithelium, gingival tissue, gingival fibres", "Seals the gingival sulcus; barrier against plaque"],
["Periodontal component", "Periodontal ligament, alveolar bone, cementum", "Mechanical support and tooth anchoring"],
],
col_widths=[4.5*cm, 8*cm, 5.5*cm]
))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"The <b>free gingiva</b> forms a 2–3 mm gingival sulcus in the healthy state. The "
"<b>attached gingiva</b> adheres firmly to underlying alveolar bone. Disease states weaken and "
"destroy the attachment apparatus, resulting in tooth mobility and eventual tooth loss.",
sBody))
# ─── SECTION 2: Disease spectrum ────────────────────────────────────────────
story.append(Spacer(1, 0.3*cm))
story.append(section_header("2. Disease Spectrum — Gingivitis vs. Periodontitis"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Plaque-induced periodontal disease encompasses two related entities. <b>Gingivitis</b> is "
"considered a precursor lesion; <b>chronic periodontitis</b> represents irreversible progression "
"once alveolar bone resorption begins. — <i>Sherris & Ryan's Medical Microbiology</i>",
sBody))
story.append(make_table(
["Feature", "Gingivitis", "Chronic Periodontitis"],
[
["Tissue involved", "Marginal gingiva only", "Deep tissues + alveolar bone"],
["Bone resorption", "Absent", "Present"],
["Pocket depth", "Normal sulcus (2–3 mm)", "Deepened periodontal pocket (>3 mm)"],
["Reversibility", "✓ Fully reversible", "✗ Bone loss is permanent"],
["Pain", "Usually absent", "Usually absent (unless abscess)"],
["Onset from plaque", "Within 2 weeks", "Months to years"],
["Treatment goal", "Plaque removal → full resolution","Arrest progression; surgery if needed"],
],
col_widths=[4.5*cm, 7.5*cm, 6*cm]
))
# ─── SECTION 3: Gingivitis ───────────────────────────────────────────────────
story.append(Spacer(1, 0.3*cm))
story.append(section_header("3. Gingivitis"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Gingivitis is <b>inflammation confined to the marginal gingiva with no bone loss</b>. It "
"develops within <b>2 weeks</b> in subjects who fail effective tooth cleansing.",
sBody))
story.append(Paragraph("<b>3.1 Histopathology</b>", sH2))
story.append(info_box([
Paragraph(
"Marked inflammatory infiltrate of <b>PMNs, lymphocytes, and plasma cells</b> in the "
"connective tissue adjacent to the epithelium lining the gingival crevice. "
"<b>Collagen loss</b> from inflamed connective tissue. No direct bacterial tissue invasion "
"in early stages. — <i>Sherris & Ryan's Medical Microbiology</i>",
sBox),
]))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("<b>3.2 Causes of Gingival Bleeding</b>", sH2))
story.append(make_table(
["Local Causes", "Systemic Causes"],
[
["Chronic gingivitis", "Pregnancy (hormonal exacerbation)"],
["Chronic periodontitis", "Leukaemia"],
["Acute necrotizing gingivitis","HIV infection"],
["Angioma / telangiectasia", "Clotting defects / anticoagulants"],
["", "Scurvy (Vitamin C deficiency)"],
],
col_widths=[9*cm, 9*cm]
))
# ─── SECTION 4: Chronic Periodontitis ───────────────────────────────────────
story.append(PageBreak())
story.append(section_header("4. Chronic Periodontitis"))
story.append(Spacer(1, 0.3*cm))
# Normal vs diseased image comparison
p_norm = os.path.join(IMG_DIR, "normal_gingiva.png")
p_adv = os.path.join(IMG_DIR, "advanced_perio.png")
story.append(two_col_images(
p_norm, "Figure 2A. Normal gingiva — healthy pink, firm tissue with intact interdental papillae.",
p_adv, "Figure 2B. Advanced periodontal disease — severely inflamed, bleeding gingiva with marked recession and bone loss."
))
story.append(Paragraph(
"<i>Figures 2A–B: Sherris & Ryan's Medical Microbiology</i>", sCaption))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Chronic periodontitis is <b>responsible for most tooth loss in people over 35–40 years</b>. "
"It progresses as a series of acute episodes separated by quiescent periods. Once alveolar "
"bone is resorbed, the condition is termed periodontitis — the bone loss does not regenerate "
"even if further inflammation is arrested. — <i>Sherris & Ryan's Medical Microbiology</i>",
sBody))
story.append(Paragraph("<b>4.1 Pathogenesis</b>", sH2))
story.append(Paragraph("As plaque-induced gingivitis progresses:", sBody))
for step in [
"Apical migration of the gingival attachment down the tooth root surface",
"Loss of connective tissue attachment (collagen destruction)",
"Alveolar bone resorption → gingival sulcus deepens into a periodontal pocket",
"If a pocket neck becomes constricted, an acute periodontal abscess may form",
"Unchecked progression → tooth loosening → eventual tooth exfoliation",
]:
story.append(Paragraph(f"• {step}", sBullet))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("<b>4.2 Causative Organisms (Polymicrobial Anaerobic)</b>", sH2))
story.append(Paragraph(
"All forms of periodontitis are polymicrobial infections involving predominantly "
"<b>Gram-negative anaerobic bacteria</b> of the subgingival plaque. "
"— <i>Sherris & Ryan's Medical Microbiology</i>",
sBody))
story.append(make_table(
["Organism", "Gram Stain", "Significance"],
[
["Porphyromonas gingivalis", "Gram −ve anaerobe", "Primary pathogen; drives progression"],
["Aggregatibacter (Actinobacillus) actinomycetemcomitans", "Gram −ve capnophile", "Produces leukotoxin; key in aggressive/juvenile periodontitis"],
["Treponema denticola", "Spirochaete", "Synergises with P. gingivalis"],
["Prevotella intermedia", "Gram −ve anaerobe", "Found in high numbers in necrotizing disease"],
["Fusobacterium spp.", "Gram −ve anaerobe", "Bridge organism in plaque biofilm"],
],
col_widths=[6*cm, 4*cm, 8*cm]
))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>4.3 Aggressive Periodontitis</b>", sH2))
story.append(make_table(
["Type", "Age Group", "Key Organism", "Feature"],
[
["Localized aggressive periodontitis", "Adolescents", "A. actinomycetemcomitans", "Leukotoxin production; rapid bone loss"],
["Generalized aggressive periodontitis", "Young adults", "Mixed anaerobes", "Widespread rapid attachment loss"],
],
col_widths=[5*cm, 3.5*cm, 5.5*cm, 4*cm]
))
story.append(Paragraph("<b>4.4 Clinical Assessment</b>", sH2))
for pt in [
"<b>Periodontal probing:</b> Probe placed in gingival sulcus; pocket depth >3 mm indicates attachment loss",
"<b>Bleeding on probing:</b> Reflects active gingival inflammation",
"<b>Radiography:</b> Demonstrates alveolar bone loss (horizontal or vertical patterns)",
"<b>Tooth mobility:</b> Late sign indicating severe bone and ligament destruction",
]:
story.append(Paragraph(f"• {pt}", sBullet))
# ─── SECTION 5: ANUG ────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("5. Acute Necrotizing Ulcerative Gingivitis (ANUG)"))
story.append(Spacer(1, 0.3*cm))
p_anug = os.path.join(IMG_DIR, "anug.png")
story.append(single_image(p_anug,
"Figure 3. Acute Necrotizing Ulcerative Gingivitis (ANUG) — severely inflamed, "
"bleeding gingiva with tissue necrosis and punched-out interdental papillae. "
"(Tintinalli's Emergency Medicine)",
w=11*cm, h=6.5*cm))
story.append(Paragraph(
"Also called <b>Vincent's disease</b> or <b>trench mouth</b>. ANUG is a "
"<b>distinctly different disease</b> from gingivitis–chronic periodontitis. It is an "
"acute, painful, aggressively destructive infection. — <i>Tintinalli's Emergency Medicine</i>",
sBody))
story.append(Paragraph("<b>5.1 Diagnostic Triad</b>", sH2))
story.append(info_box([
Paragraph("1. <b>Pain</b> (unlike chronic periodontitis)", sBox),
Paragraph('2. Ulcerated / "punched-out" <b>interdental papillae</b>', sBox),
Paragraph("3. <b>Gingival bleeding</b>", sBox),
]))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("<b>5.2 Secondary Signs</b>", sH2))
for s in ["Fetid breath (halitosis)", "Pseudomembrane formation",
"Foul metallic taste", "Tooth mobility",
"Lymphadenopathy", "Fever and malaise"]:
story.append(Paragraph(f"• {s}", sBullet))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>5.3 Spectrum of Disease</b>", sH2))
story.append(make_table(
["Stage", "Description"],
[
["ANUG (localized)", "Destruction limited to soft gingival tissue; painful ulceration of interdental papillae"],
["Necrotizing ulcerative periodontitis", "Extension to alveolar bone and periodontal ligament"],
["Noma (cancrum oris)", "Fatal necrosis spreading to cheeks, lips, and underlying facial bones"],
],
col_widths=[5.5*cm, 12.5*cm]
))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>5.4 Causative Organisms (Fusospirochetal)</b>", sH2))
story.append(Paragraph(
"<i>Treponema</i> spp., <i>Fusobacterium</i>, <i>Selenomonas</i>, <i>Prevotella intermedia</i>. "
"These organisms actually <b>invade</b> tissue, unlike organisms in chronic periodontitis. "
"Spirochetes are demonstrable in tissue on morphologic studies. "
"— <i>Sherris & Ryan's Medical Microbiology</i>",
sBody))
story.append(Paragraph("<b>5.5 Predisposing Factors</b>", sH2))
story.append(make_table(
["Factor", "Relevance"],
[
["HIV infection (CD4 <200 cells/µL)", "Most important; ANUG should prompt HIV testing if status unknown"],
["Previous ANUG episode", "Strongest independent risk factor for recurrence"],
["Poor oral hygiene", "Allows anaerobic plaque accumulation"],
["Emotional stress", "Impairs immune function"],
["Malnutrition / poor diet", "Reduces mucosal integrity"],
["Tobacco and alcohol use", "Impair mucosal defences"],
["Young age (early 20s)", "Peak demographic"],
["Recent illness / immunosuppression","General immune compromise"],
],
col_widths=[6.5*cm, 11.5*cm]
))
# ─── SECTION 6: Abscesses ───────────────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("6. Gingival and Periodontal Abscesses"))
story.append(Spacer(1, 0.3*cm))
story.append(make_table(
["Type", "Origin", "Features", "Treatment"],
[
["Gingival abscess", "Foreign body entrapment (popcorn kernel, bristle, food)",
"Acutely painful; enlarges over 24–48 h; purulent exudate expressible",
"Remove foreign body; irrigate with normal saline; home irrigation"],
["Periodontal abscess", "Plaque/debris entrapped in periodontal pocket",
"Severe pain; small or large depending on pocket size",
"Small: saline rinses + antibiotics. Large: I&D. Chlorhexidine 0.12% BID. NSAIDs for analgesia."],
],
col_widths=[3.5*cm, 4.5*cm, 5*cm, 5*cm]
))
# ─── SECTION 7: HIV-Related ─────────────────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(section_header("7. HIV-Related Periodontal Disease"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"HIV-associated periodontal disease is classified into three categories. With HAART, "
"prevalence has dropped from <10% to as low as <1%. CD4 counts below "
"<b>200 cells/µL</b> greatly increase the risk of necrotizing disease. "
"— <i>Cummings Otolaryngology Head and Neck Surgery</i>",
sBody))
story.append(make_table(
["Category", "Clinical Features", "Key Association"],
[
["Linear gingival erythema",
"Distinct linear erythema along gingival margin; does not respond to conventional therapy",
"Closely associated with oral candidiasis (OC)"],
["Necrotizing periodontal disease (NUP)",
"Ulceration of interdental papilla + bleeding + pain; may invade alveolar bone",
"Strongly associated with OC; may extend to noma"],
["Enhanced chronic periodontitis",
"Accelerated progression of pre-existing periodontal disease",
"CD4 depletion reduces host defence"],
],
col_widths=[4.5*cm, 7.5*cm, 6*cm]
))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph("<b>Treatment of HIV-Related Disease:</b>", sH2))
for pt in [
"Dental plaque removal + oral rinses with 10% povidone-iodine + 0.1–0.2% chlorhexidine gluconate",
"Topical or systemic antifungal treatment (candidiasis is closely associated)",
"Debridement of necrotic tissue; scaling",
"If no response: parenteral clindamycin or metronidazole",
]:
story.append(Paragraph(f"• {pt}", sBullet))
# ─── SECTION 8: Systemic Associations ───────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(section_header("8. Systemic Associations"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Significant research links periodontal disease with systemic conditions. "
"The relationship is often <b>bidirectional</b>. "
"— <i>Scott-Brown's Otorhinolaryngology Head & Neck Surgery</i>",
sBody))
story.append(make_table(
["Systemic Condition", "Relationship to Periodontal Disease"],
[
["Diabetes mellitus", "Hyperglycaemia impairs host defences; periodontitis worsens glycaemic control (bidirectional)"],
["Atherosclerotic vascular disease", "Shared inflammatory mechanisms; bacteraemia from oral flora implicated"],
["Pregnancy", "Hormonal changes exacerbate gingivitis; associated with preterm birth risk"],
["HIV/AIDS", "Immunosuppression accelerates all forms; ANUG is an AIDS-defining illness in context"],
["Leukaemia", "Gingival infiltration and haematologic bleeding cause gingival enlargement and bleeding"],
],
col_widths=[5.5*cm, 12.5*cm]
))
# ─── SECTION 9: Treatment Summary ───────────────────────────────────────────
story.append(PageBreak())
story.append(section_header("9. Treatment Summary"))
story.append(Spacer(1, 0.3*cm))
story.append(make_table(
["Condition", "First-Line Treatment", "Adjuncts / Notes"],
[
["Gingivitis",
"Improved oral hygiene; professional plaque removal",
"Fully reversible. Chlorhexidine rinses may supplement."],
["Chronic Periodontitis",
"Scaling and root planing (SRP); oral hygiene instruction",
"Bone loss is permanent; goal is to arrest progression. Periodontal surgery if SRP insufficient."],
["Aggressive Periodontitis",
"SRP + systemic antibiotics (amoxicillin + metronidazole)",
"Referral to periodontist essential; more rapid progression"],
["ANUG",
"Chlorhexidine 0.12% rinses BID + professional debridement",
"Metronidazole for immunocompromised or systemic signs. Address predisposing factors."],
["Periodontal Abscess",
"I&D for large abscesses; saline rinses + antibiotics for small",
"NSAIDs preferred over narcotics for analgesia"],
["HIV-Related Periodontal Disease",
"Povidone-iodine/chlorhexidine rinses + debridement",
"Add antifungals; clindamycin/metronidazole if refractory; ensure HAART optimisation"],
["Peri-Implantitis",
"Remove plaque/debris around implant; irrigate with normal saline or 0.12% chlorhexidine",
"Refer to dentist; treat similarly to periodontal abscess"],
],
col_widths=[4*cm, 7*cm, 7*cm]
))
story.append(Spacer(1, 0.3*cm))
story.append(info_box([
Paragraph(
"<b>Referral Note:</b> All patients with periodontal disease require dentist referral for "
"definitive treatment — extensive dental cleaning, oral hygiene instruction, and in some "
"cases, periodontal surgery. Treatment is primarily directed at removing plaque and its "
"by-products. — <i>Tintinalli's Emergency Medicine</i>",
sBox),
]))
# ─── SECTION 10: Key Points ─────────────────────────────────────────────────
story.append(Spacer(1, 0.4*cm))
story.append(section_header("10. High-Yield Key Points"))
story.append(Spacer(1, 0.3*cm))
key_points = [
"Gingivitis develops within <b>2 weeks</b> of inadequate oral hygiene; it is <b>fully reversible</b>.",
"Periodontitis = gingivitis + <b>alveolar bone loss</b>; bone does NOT regenerate once lost.",
"Main organisms: <i>P. gingivalis</i>, <i>T. denticola</i>, <i>A. actinomycetemcomitans</i> (leukotoxin in aggressive disease).",
"ANUG is <b>painful</b> (unlike chronic periodontitis) with punched-out interdental papillae.",
"ANUG in a patient of unknown HIV status → prompt HIV serologic testing.",
"HIV-related periodontal disease: linear gingival erythema, necrotizing ulcerative periodontitis, enhanced chronic periodontitis.",
"Periodontal disease has bidirectional relationships with <b>diabetes</b> and <b>cardiovascular disease</b>.",
"Bleeding on probing = active gingival inflammation; pocket depth >3 mm = attachment loss.",
"Periodontal abscess treatment: NSAIDs preferred over narcotics for analgesia.",
"With HAART, prevalence of HIV-related periodontal disease dropped from <10% to <1%.",
]
for i, kp in enumerate(key_points, 1):
story.append(Paragraph(f"<b>{i}.</b> {kp}", sBullet))
story.append(Spacer(1, 1*cm))
story.append(HRFlowable(width="100%", thickness=0.5, color=MID_GREY, spaceAfter=6))
story.append(Paragraph(
"References: Sherris & Ryan's Medical Microbiology (8th ed.) · Tintinalli's Emergency "
"Medicine (pp. 1621–1625) · Scott-Brown's Otorhinolaryngology Head & Neck Surgery · "
"Cummings Otolaryngology Head and Neck Surgery · Junqueira's Basic Histology (17th ed.)",
sFooter))
# ─── Build PDF ───────────────────────────────────────────────────────────────
OUT = "/home/daytona/workspace/periodontal-pdf/Gingivitis_Periodontal_Disease.pdf"
doc = SimpleDocTemplate(
OUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=MARGIN + 0.8*cm, # leave room for header
bottomMargin=MARGIN + 0.3*cm,
title="Gingivitis & Periodontal Disease",
author="Orris Medical Reference",
subject="Dental/Oral Medicine",
)
doc.build(story,
onFirstPage=on_first_page,
onLaterPages=on_page)
print(f"PDF saved to: {OUT}")
cd /home/daytona/workspace/periodontal-pdf && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/periodontal-pdf/Gingivitis_Periodontal_Disease.pd…
Gingivitis Periodontal Disease
PDF Document · PDF
Instruments use in dental posting
instruments used in dental posting oral surgery basic set
Generate a comprehensive PDF guide on dental instruments