Analysis
| Grade | Features |
|---|---|
| 0 | Normal |
| I | Doubtful JSN; possible osteophytes |
| II | Definite osteophytes; possible JSN |
| III | Moderate multiple osteophytes; definite JSN; some sclerosis |
| IV | Large osteophytes; marked JSN; severe sclerosis; possible bone deformity |

Disclaimer: This is an educational radiographic analysis. Clinical correlation with the patient's age, symptoms, functional status, and examination findings is essential for management decisions. Final interpretation must be by a qualified radiologist or treating physician.
Telugu
| గ్రేడ్ | వివరణ |
|---|---|
| 0 | సాధారణం |
| I | అనుమానాస్పద మార్పులు |
| II | స్పష్టమైన ఎముక ముళ్ళు; కొంత జాయింట్ స్పేస్ తగ్గుదల |
| III | మధ్యస్థ నుండి తీవ్రమైన మార్పులు |
| IV | పెద్ద ఎముక ముళ్ళు; తీవ్రమైన జాయింట్ స్పేస్ తగ్గుదల; తీవ్రమైన స్క్లెరోసిస్ |
⚕️ గమనిక: ఇది విద్యాపరమైన విశ్లేషణ మాత్రమే. చికిత్స నిర్ణయాలు తీసుకోవడానికి అర్హత కలిగిన వైద్యుడిని సంప్రదించండి.
Analysis
| వివరణ | విలువ |
|---|---|
| వైపు | Left Knee (ఎడమ మోకాలి) - "L" గుర్తు కనిపిస్తోంది |
| వయసు | 63 సంవత్సరాలు |
| ఆసుపత్రి | A1 Amar Orthopedic Hospital, Auto Nagar, Guntur |
| వ్యూలు | Left Knee LAT (లేటరల్) + Left/Right Knee AP |
| గ్రేడ్ | వివరణ | ఈ రోగి |
|---|---|---|
| 0 | సాధారణం | - |
| I | అనుమానాస్పద | - |
| II | స్పష్టమైన ఎముక ముళ్ళు | - |
| III | మధ్యస్థ JSN + స్క్లెరోసిస్ | - |
| IV | తీవ్రమైన JSN + పెద్ద ఎముక ముళ్ళు + ఎముక వైకల్యం | ✅ |
⚕️ గమనిక: ఈ 63 సంవత్సరాల రోగికి మందులతో ఉపశమనం కలగకపోతే, Total Knee Replacement Surgery అత్యంత మంచి ఎంపిక. అర్హత కలిగిన ఆర్తోపెడిక్ సర్జన్ని సంప్రదించండి.
Create a patient education PDF about knee osteoarthritis and TKR surgery options
mkdir -p /tmp/workspace/knee-oa-pdf && ls /tmp/workspace/knee-oa-pdf/
pip show reportlab 2>/dev/null | head -3; python3 -c "from reportlab.pdfgen import canvas; print('reportlab OK')"
python3 -c " import subprocess result = subprocess.run(['fc-list', ':lang=te'], capture_output=True, text=True) print(result.stdout[:2000] if result.stdout else 'No Telugu fonts found') "
# Download a Telugu-supporting font (Noto Sans Telugu) cd /tmp/workspace/knee-oa-pdf wget -q "https://github.com/google/fonts/raw/main/ofl/notosanstelugu/NotoSansTelugu%5Bwdth%2Cwght%5D.ttf" -O NotoSansTelugu.ttf 2>&1 | head -5 ls -lh NotoSansTelugu.ttf 2>/dev/null || echo "Download failed"
cd /tmp/workspace/knee-oa-pdf curl -L "https://github.com/google/fonts/raw/main/ofl/notosanstelugu/NotoSansTelugu%5Bwdth%2Cwght%5D.ttf" -o NotoSansTelugu.ttf --silent ls -lh NotoSansTelugu.ttf 2>/dev/null && echo "OK" || echo "Failed"
~/knee-oa-pdf/build_pdf.py
"""
Patient Education PDF: Knee Osteoarthritis & TKR Surgery
Bilingual: English + Telugu
Uses reportlab with Noto Sans Telugu for Telugu rendering
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
import os
FONT_PATH = "/tmp/workspace/knee-oa-pdf/NotoSansTelugu.ttf"
OUTPUT = "/tmp/workspace/knee-oa-pdf/Knee_OA_Patient_Education.pdf"
# Register Telugu font
pdfmetrics.registerFont(TTFont("Telugu", FONT_PATH))
pdfmetrics.registerFont(TTFont("TeluguBold", FONT_PATH)) # variable font; bold weight embedded
# ── Colour palette ──────────────────────────────────────────────────────────
BLUE_DARK = colors.HexColor("#1a3a5c")
BLUE_MID = colors.HexColor("#2c6fad")
BLUE_LIGHT = colors.HexColor("#ddeeff")
ORANGE = colors.HexColor("#e07b1a")
GREEN = colors.HexColor("#2e7d32")
RED = colors.HexColor("#c62828")
GREY_LIGHT = colors.HexColor("#f5f5f5")
GREY_MED = colors.HexColor("#dddddd")
WHITE = colors.white
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
COVER_TITLE = S("CoverTitle",
fontName="Helvetica-Bold", fontSize=26, textColor=WHITE,
alignment=TA_CENTER, spaceAfter=6, leading=32)
COVER_SUB = S("CoverSub",
fontName="Helvetica", fontSize=14, textColor=BLUE_LIGHT,
alignment=TA_CENTER, spaceAfter=4)
COVER_TEL = S("CoverTel",
fontName="Telugu", fontSize=16, textColor=BLUE_LIGHT,
alignment=TA_CENTER, spaceAfter=4)
SECTION_HEAD = S("SectionHead",
fontName="Helvetica-Bold", fontSize=14, textColor=WHITE,
backColor=BLUE_MID, borderPad=6, alignment=TA_LEFT,
spaceAfter=8, spaceBefore=14, leading=20,
leftIndent=-10, rightIndent=-10)
SUBSECTION_HEAD = S("SubHead",
fontName="Helvetica-Bold", fontSize=11, textColor=BLUE_DARK,
spaceAfter=4, spaceBefore=8)
BODY_EN = S("BodyEN",
fontName="Helvetica", fontSize=10, textColor=colors.black,
spaceAfter=4, leading=15, alignment=TA_JUSTIFY)
BODY_TEL = S("BodyTel",
fontName="Telugu", fontSize=11, textColor=colors.HexColor("#1a1a1a"),
spaceAfter=6, leading=17, alignment=TA_JUSTIFY)
BULLET_EN = S("BulletEN",
fontName="Helvetica", fontSize=10, textColor=colors.black,
leftIndent=14, spaceAfter=3, leading=14,
bulletIndent=4)
BULLET_TEL = S("BulletTel",
fontName="Telugu", fontSize=10.5, textColor=colors.HexColor("#1a1a1a"),
leftIndent=14, spaceAfter=3, leading=15,
bulletIndent=4)
LABEL_EN = S("LabelEN",
fontName="Helvetica-Bold", fontSize=10, textColor=BLUE_DARK,
spaceAfter=2)
CAPTION = S("Caption",
fontName="Helvetica-Oblique", fontSize=8.5, textColor=colors.grey,
alignment=TA_CENTER, spaceAfter=4)
FOOTER = S("Footer",
fontName="Helvetica", fontSize=8, textColor=colors.grey,
alignment=TA_CENTER)
WARNING = S("Warning",
fontName="Helvetica-Bold", fontSize=9, textColor=RED,
alignment=TA_CENTER, spaceAfter=4)
# ── Helper builders ──────────────────────────────────────────────────────────
def hr(color=BLUE_MID, thickness=1):
return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=6, spaceBefore=2)
def section_banner(text_en, text_tel):
"""Blue banner with English title + Telugu subtitle."""
data = [[
Paragraph(f"<b>{text_en}</b>", S("SH2",
fontName="Helvetica-Bold", fontSize=13, textColor=WHITE, leading=18)),
Paragraph(text_tel, S("SH2T",
fontName="Telugu", fontSize=13, textColor=BLUE_LIGHT, leading=18, alignment=TA_LEFT))
]]
t = Table(data, colWidths=["55%", "45%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), BLUE_DARK),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
def two_col(left_paras, right_paras, left_w="50%", right_w="50%"):
"""Two column layout."""
left = [p for p in left_paras]
right = [p for p in right_paras]
from reportlab.platypus import FrameBreak
data = [[left, right]]
t = Table(data, colWidths=[left_w, right_w])
t.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (0,-1), 0),
("RIGHTPADDING", (0,0), (0,-1), 8),
("LEFTPADDING", (1,0), (1,-1), 8),
("RIGHTPADDING", (1,0), (1,-1), 0),
]))
return t
def info_box(rows, title_en="", title_tel="", bg=BLUE_LIGHT, title_bg=BLUE_MID):
"""Coloured info box with optional title."""
table_data = []
if title_en:
table_data.append([
Paragraph(f"<b>{title_en}</b>", S("IBTitle",
fontName="Helvetica-Bold", fontSize=10.5, textColor=WHITE, leading=14)),
Paragraph(title_tel, S("IBTitleT",
fontName="Telugu", fontSize=11, textColor=BLUE_LIGHT, leading=15))
])
for en, tel in rows:
table_data.append([
Paragraph(en, S("IBRowE", fontName="Helvetica", fontSize=9.5, leading=13, textColor=colors.black)),
Paragraph(tel, S("IBRowT", fontName="Telugu", fontSize=10, leading=14, textColor=colors.black))
])
style = [
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ROWBACKGROUNDS",(0,0), (-1,-1), [bg, colors.HexColor("#eaf3fb")]),
("GRID", (0,0), (-1,-1), 0.3, GREY_MED),
]
if title_en:
style += [
("BACKGROUND", (0,0), (-1,0), title_bg),
("TOPPADDING", (0,0), (-1,0), 7),
("BOTTOMPADDING", (0,0), (-1,0), 7),
]
t = Table(table_data, colWidths=["50%", "50%"])
t.setStyle(TableStyle(style))
return t
def grade_table():
headers = [
Paragraph("<b>Grade</b>", S("TH", fontName="Helvetica-Bold", fontSize=10, textColor=WHITE)),
Paragraph("<b>English Description</b>", S("TH2", fontName="Helvetica-Bold", fontSize=10, textColor=WHITE)),
Paragraph("<b>Telugu వివరణ</b>", S("TH3", fontName="Telugu", fontSize=10, textColor=WHITE)),
Paragraph("<b>X-Ray Findings</b>", S("TH4", fontName="Helvetica-Bold", fontSize=10, textColor=WHITE)),
]
rows = [
["0", "Normal", "సాధారణం", "No changes"],
["I", "Doubtful", "అనుమానాస్పద", "Possible osteophyte"],
["II", "Mild", "తేలికపాటి", "Definite osteophytes; possible JSN"],
["III", "Moderate", "మధ్యస్థం", "Multiple osteophytes; definite JSN; some sclerosis"],
["IV (Severe)", "Severe", "తీవ్రమైన", "Large osteophytes; marked JSN; severe sclerosis"],
]
row_colors = [BLUE_LIGHT, WHITE, BLUE_LIGHT, WHITE, colors.HexColor("#ffe0e0")]
data = [headers]
for r in rows:
data.append([
Paragraph(f"<b>{r[0]}</b>", S("GR", fontName="Helvetica-Bold", fontSize=10, textColor=BLUE_DARK)),
Paragraph(r[1], S("GE", fontName="Helvetica", fontSize=10)),
Paragraph(r[2], S("GT", fontName="Telugu", fontSize=10.5)),
Paragraph(r[3], S("GX", fontName="Helvetica", fontSize=9.5, textColor=colors.dimgrey)),
])
t = Table(data, colWidths=["15%", "18%", "22%", "45%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS", (0,1), (-1,-1), row_colors),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, GREY_MED),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("ROWBACKGROUNDS",(0,-1),(-1,-1), [colors.HexColor("#ffe0e0")]),
]))
return t
# ── Cover page content ───────────────────────────────────────────────────────
def cover_page():
elems = []
# Header banner
banner_data = [[
Paragraph("PATIENT EDUCATION GUIDE", S("PT1",
fontName="Helvetica-Bold", fontSize=22, textColor=WHITE,
alignment=TA_CENTER, leading=28)),
]]
banner = Table(banner_data, colWidths=["100%"])
banner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), BLUE_DARK),
("TOPPADDING", (0,0), (-1,-1), 18),
("BOTTOMPADDING", (0,0), (-1,-1), 18),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
]))
elems.append(banner)
elems.append(Spacer(1, 12))
# Title box
title_data = [[
Paragraph(
"<b>Knee Osteoarthritis &<br/>Total Knee Replacement (TKR)</b>",
S("MainTitle", fontName="Helvetica-Bold", fontSize=20, textColor=BLUE_DARK,
alignment=TA_CENTER, leading=28)),
]]
title_box = Table(title_data, colWidths=["100%"])
title_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), BLUE_LIGHT),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 14),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
("BOX", (0,0), (-1,-1), 1, BLUE_MID),
]))
elems.append(title_box)
elems.append(Spacer(1, 4))
tel_title_data = [[
Paragraph(
"మోకాలి ఆస్టియోఆర్థ్రైటిస్ మరియు టోటల్ నీ రిప్లేస్మెంట్ (TKR) — రోగి విద్యా మార్గదర్శిక",
S("TelTitle", fontName="Telugu", fontSize=13, textColor=BLUE_DARK,
alignment=TA_CENTER, leading=20)),
]]
tel_title_box = Table(tel_title_data, colWidths=["100%"])
tel_title_box.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#eef6ff")),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 14),
("RIGHTPADDING", (0,0), (-1,-1), 14),
("BOX", (0,0), (-1,-1), 0.5, BLUE_MID),
]))
elems.append(tel_title_box)
elems.append(Spacer(1, 16))
# Quick info strip
qinfo = [
[
Paragraph("<b>Hospital</b><br/>A1 Amar Orthopedic Hospital\nAuto Nagar, Guntur",
S("QI", fontName="Helvetica", fontSize=9.5, alignment=TA_CENTER, leading=14)),
Paragraph("<b>Prepared for</b><br/>Patients with Knee Pain &\nOsteoarthritis",
S("QI2", fontName="Helvetica", fontSize=9.5, alignment=TA_CENTER, leading=14)),
Paragraph("<b>Language</b><br/>English / Telugu\n(ఇంగ్లీష్ / తెలుగు)",
S("QI3", fontName="Helvetica", fontSize=9.5, alignment=TA_CENTER, leading=14)),
Paragraph("<b>Date</b><br/>July 2026",
S("QI4", fontName="Helvetica", fontSize=9.5, alignment=TA_CENTER, leading=14)),
]
]
qt = Table(qinfo, colWidths=["25%","25%","25%","25%"])
qt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), GREY_LIGHT),
("GRID", (0,0), (-1,-1), 0.5, GREY_MED),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,0), (-1,-1), 10),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
elems.append(qt)
elems.append(Spacer(1, 18))
# Contents
toc = [
["1", "What is Knee Osteoarthritis?", "మోకాలి ఆస్టియోఆర్థ్రైటిస్ అంటే ఏమిటి?"],
["2", "Causes & Risk Factors", "కారణాలు మరియు ప్రమాద కారకాలు"],
["3", "Symptoms", "లక్షణాలు"],
["4", "X-Ray Grading (K-L Scale)", "X-Ray గ్రేడింగ్"],
["5", "Non-Surgical Treatment", "శస్త్రచికిత్స లేని చికిత్స"],
["6", "When is Surgery Needed?", "శస్త్రచికిత్స ఎప్పుడు అవసరం?"],
["7", "Total Knee Replacement (TKR)", "టోటల్ నీ రిప్లేస్మెంట్"],
["8", "Before & After Surgery", "శస్త్రచికిత్సకు ముందు మరియు తర్వాత"],
["9", "Recovery & Rehabilitation", "కోలుకోవడం మరియు పునఃస్థాపన"],
["10","FAQ", "తరచుగా అడిగే ప్రశ్నలు"],
]
toc_data = [[
Paragraph("<b>#</b>", S("TC0", fontName="Helvetica-Bold", fontSize=9.5, textColor=WHITE)),
Paragraph("<b>English</b>", S("TC1", fontName="Helvetica-Bold", fontSize=9.5, textColor=WHITE)),
Paragraph("<b>Telugu</b>", S("TC2", fontName="Telugu", fontSize=9.5, textColor=WHITE)),
]]
for row in toc:
toc_data.append([
Paragraph(f"<b>{row[0]}</b>", S("TN", fontName="Helvetica-Bold", fontSize=9.5, textColor=BLUE_DARK)),
Paragraph(row[1], S("TE", fontName="Helvetica", fontSize=9.5)),
Paragraph(row[2], S("TT", fontName="Telugu", fontSize=10)),
])
toc_table = Table(toc_data, colWidths=["8%", "46%", "46%"])
toc_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, GREY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.3, GREY_MED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
elems.append(Paragraph("<b>Table of Contents — విషయ సూచిక</b>",
S("TOCHead", fontName="Helvetica-Bold", fontSize=12, textColor=BLUE_DARK, spaceAfter=6)))
elems.append(toc_table)
return elems
# ── Section 1: What is Knee OA ───────────────────────────────────────────────
def section1():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("1. What is Knee Osteoarthritis?",
"1. మోకాలి ఆస్టియోఆర్థ్రైటిస్ అంటే ఏమిటి?"))
el.append(Spacer(1, 6))
el.append(Paragraph(
"Knee osteoarthritis (OA) is a degenerative joint disease in which the cartilage — the "
"smooth cushioning layer covering the ends of bones — gradually wears away. As the cartilage "
"thins and disappears, bones start to rub against each other, causing pain, stiffness, and "
"reduced mobility. It is the most common form of arthritis worldwide.",
BODY_EN))
el.append(Paragraph(
"మోకాలి ఆస్టియోఆర్థ్రైటిస్ అంటే కీళ్ల రోగం. మోకాలిలో ఎముకల చివరల్లో ఉండే మెత్తని పదార్థం "
"(కార్టిలేజ్) నెమ్మదిగా అరిగిపోతుంది. దీని వల్ల ఎముకలు ఒకదానితో ఒకటి రాపాడి నొప్పి, "
"కఠినత్వం, నడవడంలో ఇబ్బంది కలుగుతాయి. ప్రపంచంలో అత్యంత సాధారణమైన కీళ్ల రోగం ఇదే.",
BODY_TEL))
el.append(Spacer(1, 6))
# Normal vs OA comparison
compare = [
[
Paragraph("<b>Normal Knee</b>\nసాధారణ మోకాలి",
S("NC", fontName="Helvetica-Bold", fontSize=10, alignment=TA_CENTER, leading=15)),
Paragraph("<b>Osteoarthritic Knee</b>\nఆస్టియోఆర్థ్రైటిస్ మోకాలి",
S("OC", fontName="Helvetica-Bold", fontSize=10, alignment=TA_CENTER, leading=15,
textColor=RED)),
],
[
Paragraph(
"• Thick, smooth cartilage\n• Normal joint space\n• No osteophytes\n• Painless movement\n\n"
"• మందమైన, మృదువైన కార్టిలేజ్\n• సాధారణ కీళ్ల స్థలం\n• ఎముక ముళ్ళు లేవు\n• నొప్పిలేని కదలిక",
S("NL", fontName="Telugu", fontSize=10, leading=15, textColor=GREEN)),
Paragraph(
"• Thin or absent cartilage\n• Narrowed joint space\n• Bone spurs (osteophytes)\n"
"• Pain, stiffness, swelling\n\n"
"• సన్నగా అయిన కార్టిలేజ్\n• తగ్గిన కీళ్ల స్థలం\n• ఎముక ముళ్ళు\n• నొప్పి, కఠినత్వం, వాపు",
S("OL", fontName="Telugu", fontSize=10, leading=15, textColor=RED)),
]
]
ct = Table(compare, colWidths=["50%","50%"])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), colors.HexColor("#e8f5e9")),
("BACKGROUND", (1,0), (1,-1), colors.HexColor("#ffebee")),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING",(0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (0,-1), 1, GREEN),
("BOX", (1,0), (1,-1), 1, RED),
("LINEAFTER", (0,0), (0,-1), 1, GREY_MED),
("ALIGN", (0,0), (-1,0), "CENTER"),
]))
el.append(ct)
return el
# ── Section 2: Causes & Risk Factors ────────────────────────────────────────
def section2():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("2. Causes & Risk Factors", "2. కారణాలు మరియు ప్రమాద కారకాలు"))
el.append(Spacer(1, 6))
risks = [
("Age (60+ years)", "వయసు (60+ సంవత్సరాలు)"),
("Obesity / Overweight", "అధిక బరువు / స్థూలకాయం"),
("Female gender (post-menopause)", "మహిళలు (రుతువిరామం తర్వాత)"),
("Previous knee injury", "గతంలో మోకాలికి గాయం"),
("Repetitive heavy work / squatting", "మోకాలుపై నిరంతర ఒత్తిడి / కూర్చోవడం"),
("Family history of OA", "కుటుంబంలో ఆస్టియోఆర్థ్రైటిస్ చరిత్ర"),
("Weak quadriceps muscles", "తొడ కండరాల బలహీనత"),
("Varus/Valgus knee deformity", "కాళ్ళు వంగిన లేదా లోపలికి వంగిన స్థితి"),
]
el.append(info_box(risks, "Risk Factors", "ప్రమాద కారకాలు",
bg=colors.HexColor("#fff8e1"), title_bg=ORANGE))
return el
# ── Section 3: Symptoms ──────────────────────────────────────────────────────
def section3():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("3. Symptoms", "3. లక్షణాలు"))
el.append(Spacer(1, 6))
symptoms = [
("Pain during or after walking / climbing stairs",
"నడవడం / మెట్లు ఎక్కడం సమయంలో లేదా తర్వాత నొప్పి"),
("Morning stiffness lasting < 30 minutes",
"ఉదయం నిద్రలేచినప్పుడు కఠినత్వం (30 నిమిషాల కంటే తక్కువ)"),
("Swelling around the knee joint",
"మోకాలి చుట్టూ వాపు"),
("Creaking / grinding sound (crepitus) in the knee",
"మోకాలిలో నలుగు శబ్దం (క్రెపిటస్)"),
("Difficulty fully straightening or bending the knee",
"మోకాలిని పూర్తిగా వంచడం లేదా నిటారుగా చేయడంలో ఇబ్బంది"),
("Bony enlargement around the knee",
"మోకాలి చుట్టూ ఎముక పెద్దదవడం"),
("Knee gives way / feeling of instability",
"మోకాలి అకస్మాత్తుగా వంగడం / అస్థిరత అనుభవించడం"),
]
el.append(info_box(symptoms, "Common Symptoms", "సాధారణ లక్షణాలు",
bg=colors.HexColor("#fce4ec"), title_bg=RED))
return el
# ── Section 4: Grading ───────────────────────────────────────────────────────
def section4():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("4. X-Ray Grading (Kellgren-Lawrence Scale)",
"4. X-Ray గ్రేడింగ్ (కెల్గ్రెన్-లారెన్స్ స్కేల్)"))
el.append(Spacer(1, 6))
el.append(Paragraph(
"Doctors use the Kellgren-Lawrence (K-L) scale to grade OA severity based on X-ray findings. "
"Grade IV is the most severe, often requiring surgery.",
BODY_EN))
el.append(Paragraph(
"X-Ray పరీక్ష ఆధారంగా కెల్గ్రెన్-లారెన్స్ స్కేల్ ద్వారా వ్యాధి తీవ్రతను "
"వైద్యులు అంచనా వేస్తారు. గ్రేడ్ IV అత్యంత తీవ్రమైనది — సాధారణంగా శస్త్రచికిత్స అవసరమవుతుంది.",
BODY_TEL))
el.append(Spacer(1, 4))
el.append(grade_table())
return el
# ── Section 5: Non-Surgical Treatment ───────────────────────────────────────
def section5():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("5. Non-Surgical Treatment", "5. శస్త్రచికిత్స లేని చికిత్స"))
el.append(Spacer(1, 6))
el.append(Paragraph(
"Most patients with mild-to-moderate OA (Grade I-III) are managed without surgery first. "
"These treatments reduce pain and improve function:",
BODY_EN))
el.append(Paragraph(
"తేలికపాటి నుండి మధ్యస్థ OA (గ్రేడ్ I-III) రోగులకు మొదట శస్త్రచికిత్స లేకుండా "
"చికిత్స చేస్తారు. ఈ చికిత్సలు నొప్పిని తగ్గించి పనితీరును మెరుగుపరుస్తాయి:",
BODY_TEL))
el.append(Spacer(1, 6))
treatments = [
("LIFESTYLE", "జీవనశైలి మార్పులు",
"• Weight loss (reduces load on knee by 3-4x per kg lost)\n"
"• Low-impact exercise: walking, swimming, cycling\n"
"• Avoid squatting, cross-legged sitting, stairs when painful\n"
"• Use walking stick on the opposite hand",
"• బరువు తగ్గించుకోవడం (ప్రతి కిలో తగ్గితే మోకాలిపై 3-4 రెట్లు ఒత్తిడి తగ్గుతుంది)\n"
"• తక్కువ ప్రయాసతో కూడిన వ్యాయామం: నడక, ఈత, సైక్లింగ్\n"
"• నొప్పిగా ఉన్నప్పుడు కూర్చోవడం, మెట్లు ఎక్కడం మానుకోండి\n"
"• వ్యతిరేక చేతిలో నడకకర్ర వాడండి"),
("MEDICATIONS", "మందులు",
"• Paracetamol (first-line pain relief)\n"
"• NSAIDs: Diclofenac, Ibuprofen (with food)\n"
"• Topical gels: Diclofenac gel on knee\n"
"• Glucosamine / Chondroitin supplements",
"• పారాసెటమాల్ (మొదటి నొప్పి నివారిణి)\n"
"• NSAIDs: డైక్లోఫెనాక్, ఐబుప్రోఫెన్ (భోజనంతో తినండి)\n"
"• టాపికల్ జెల్: మోకాలిపై డైక్లోఫెనాక్ జెల్ రాయండి\n"
"• గ్లూకోసమైన్ / కాండ్రోయిటిన్ సప్లిమెంట్స్"),
("INJECTIONS", "ఇంజెక్షన్లు",
"• Corticosteroid injection: Reduces inflammation; lasts weeks\n"
"• Hyaluronic acid injection: Lubricates joint; lasts months\n"
"• PRP (Platelet-Rich Plasma): Regenerative; newer option",
"• కార్టికోస్టెరాయిడ్ ఇంజెక్షన్: వాపు తగ్గించుతుంది; కొన్ని వారాలు పని చేస్తుంది\n"
"• హైలురోనిక్ యాసిడ్ ఇంజెక్షన్: కీళ్లను మెరుగుపరుస్తుంది; నెలల పాటు పని చేస్తుంది\n"
"• PRP (ప్లేట్లెట్-రిచ్ ప్లాస్మా): పునరుత్పత్తి చికిత్స"),
("PHYSIOTHERAPY", "ఫిజియోతెరపీ",
"• Quadriceps strengthening exercises\n"
"• Hot/cold packs, TENS therapy\n"
"• Knee bracing / unloader brace\n"
"• Orthotic insoles for alignment correction",
"• తొడ కండరాలు బలపర్చే వ్యాయామాలు\n"
"• వేడి/చల్లని కాంప్రెస్, TENS థెరపీ\n"
"• నీ బ్రేస్ / అన్లోడర్ బ్రేస్\n"
"• అలైన్మెంట్ సరిచేయడానికి ఆర్తోటిక్ ఇన్సోల్స్"),
]
for code, tel_head, en_body, tel_body in treatments:
row_data = [[
Paragraph(f"<b>{code}</b>", S("TRH",
fontName="Helvetica-Bold", fontSize=10.5, textColor=BLUE_DARK, leading=16)),
Paragraph(tel_head, S("TRHT",
fontName="Telugu", fontSize=11, textColor=BLUE_DARK, leading=16)),
]]
body_row = [[
Paragraph(en_body, S("TRB",
fontName="Helvetica", fontSize=9.5, leading=15, textColor=colors.black)),
Paragraph(tel_body, S("TRBT",
fontName="Telugu", fontSize=10, leading=15, textColor=colors.black)),
]]
t = Table(row_data + body_row, colWidths=["50%","50%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_LIGHT),
("BACKGROUND", (0,1), (-1,1), WHITE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 0.5, BLUE_MID),
("LINEAFTER", (0,0), (0,-1), 0.5, GREY_MED),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
el.append(t)
el.append(Spacer(1, 5))
return el
# ── Section 6: When is Surgery Needed ───────────────────────────────────────
def section6():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("6. When is Surgery Needed?",
"6. శస్త్రచికిత్స ఎప్పుడు అవసరం?"))
el.append(Spacer(1, 6))
indications = [
("Kellgren-Lawrence Grade III-IV OA on X-ray",
"X-Ray లో కెల్గ్రెన్-లారెన్స్ గ్రేడ్ III-IV OA"),
("Persistent pain despite 3-6 months of conservative treatment",
"3-6 నెలల పాటు మందులు వాడినా నొప్పి తగ్గకపోవడం"),
("Severely limited daily activities (walking, climbing stairs)",
"రోజువారీ కార్యకలాపాలు (నడవడం, మెట్లు ఎక్కడం) తీవ్రంగా దెబ్బతినడం"),
("Bone-on-bone contact (near-complete cartilage loss)",
"ఎముక-ఎముక సంపర్కం (కార్టిలేజ్ దాదాపు పూర్తిగా అరిగిపోవడం)"),
("Significant varus/valgus deformity",
"తీవ్రమైన కాళ్ళు వంగిన/లోపలికి వంగిన స్థితి"),
("Failed injections and physiotherapy",
"ఇంజెక్షన్లు మరియు ఫిజియోతెరపీ పని చేయకపోవడం"),
("Poor quality of life due to knee pain",
"మోకాలి నొప్పి వల్ల జీవన నాణ్యత క్షీణించడం"),
]
el.append(info_box(indications,
"Indications for Surgery",
"శస్త్రచికిత్స సూచనలు",
bg=colors.HexColor("#fff3e0"), title_bg=ORANGE))
return el
# ── Section 7: TKR Surgery ───────────────────────────────────────────────────
def section7():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("7. Total Knee Replacement (TKR) Surgery",
"7. టోటల్ నీ రిప్లేస్మెంట్ (TKR) శస్త్రచికిత్స"))
el.append(Spacer(1, 6))
el.append(Paragraph(
"Total Knee Replacement (TKR), also called Total Knee Arthroplasty (TKA), is a surgical "
"procedure in which the damaged knee joint surfaces are removed and replaced with artificial "
"implants (prosthesis) made of metal and plastic. It is one of the most successful "
"surgeries in orthopaedics with >95% patient satisfaction at 10 years.",
BODY_EN))
el.append(Paragraph(
"టోటల్ నీ రిప్లేస్మెంట్ (TKR) శస్త్రచికిత్సలో దెబ్బతిన్న మోకాలి ఉపరితలాలను తొలగించి "
"మెటల్ మరియు ప్లాస్టిక్తో తయారైన కృత్రిమ ఉపకరణాలు (ప్రొస్థెసిస్) అమర్చుతారు. "
"ఆర్తోపెడిక్ శస్త్రచికిత్సలలో ఇది అత్యంత విజయవంతమైనది — 10 సంవత్సరాలలో >95% రోగి సంతృప్తి.",
BODY_TEL))
el.append(Spacer(1, 8))
# Procedure steps
steps = [
("Step 1 — Anaesthesia\nదశ 1 — అనస్థీషియా",
"Spinal or general anaesthesia given.\n"
"వెన్నెముక లేదా సాధారణ అనస్థీషియా ఇవ్వబడుతుంది."),
("Step 2 — Incision\nదశ 2 — కోత",
"8-12 cm incision made over the front of the knee.\n"
"మోకాలి ముందు భాగంలో 8-12 సె.మీ. కోత పెడతారు."),
("Step 3 — Bone resurfacing\nదశ 3 — ఎముక తొలగింపు",
"Damaged cartilage and minimal bone removed from femur, tibia and patella.\n"
"ఫెమర్, టిబియా మరియు పటెల్లా నుండి దెబ్బతిన్న కార్టిలేజ్ మరియు కొద్దిపాటి ఎముక తొలగిస్తారు."),
("Step 4 — Implant placement\nదశ 4 — ఇంప్లాంట్ అమర్చడం",
"Metal components fixed to bone ends; polyethylene spacer inserted between them.\n"
"మెటల్ భాగాలు ఎముక చివర్లకు అమర్చబడతాయి; మధ్యలో పాలిఇథిలీన్ స్పేసర్ ఉంచబడుతుంది."),
("Step 5 — Closure\nదశ 5 — మూయడం",
"Wound closed with sutures/staples; drain placed if needed. Duration: ~1.5-2 hours.\n"
"గాయం కుట్లు/స్టేపుల్స్తో మూయబడుతుంది. వ్యవధి: సుమారు 1.5-2 గంటలు."),
]
step_data = []
for step_head, step_body in steps:
step_data.append([
Paragraph(f"<b>{step_head}</b>",
S("SH", fontName="Telugu", fontSize=10, textColor=WHITE, leading=16)),
Paragraph(step_body,
S("SB", fontName="Telugu", fontSize=10, leading=16, textColor=colors.black)),
])
st = Table(step_data, colWidths=["35%","65%"])
st.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1),
[BLUE_DARK, BLUE_MID, BLUE_DARK, BLUE_MID, BLUE_DARK]),
("BACKGROUND", (1,0), (1,-1), WHITE),
("ROWBACKGROUNDS", (1,0), (1,-1),
[WHITE, GREY_LIGHT, WHITE, GREY_LIGHT, WHITE]),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 0.5, BLUE_MID),
]))
# Fix text color for odd rows
for i in range(0, 5, 2):
st.setStyle(TableStyle([("TEXTCOLOR", (0,i), (0,i), WHITE)]))
for i in range(1, 5, 2):
st.setStyle(TableStyle([("TEXTCOLOR", (0,i), (0,i), WHITE)]))
el.append(st)
el.append(Spacer(1, 8))
# Types of TKR
el.append(Paragraph("<b>Types of Knee Replacement — నీ రిప్లేస్మెంట్ రకాలు</b>",
S("TH", fontName="Helvetica-Bold", fontSize=11, textColor=BLUE_DARK, spaceAfter=5)))
types = [
("Total Knee Replacement (TKR)\nటోటల్ నీ రిప్లేస్మెంట్",
"All 3 compartments replaced. Best for severe multi-compartment OA (Grade IV).\n"
"3 కంపార్ట్మెంట్లు అన్నీ మార్చబడతాయి. తీవ్రమైన OA (గ్రేడ్ IV) కి అత్యుత్తమం.",
BLUE_LIGHT),
("Unicompartmental Knee Replacement (UKR)\nఒక కంపార్ట్మెంట్ రిప్లేస్మెంట్",
"Only 1 damaged compartment replaced. Suitable for isolated medial/lateral OA in younger patients.\n"
"ఒక కంపార్ట్మెంట్ మాత్రమే మార్చబడుతుంది. యువ రోగులలో ఒకే కంపార్ట్మెంట్ OA కి అనువైనది.",
colors.HexColor("#e8f5e9")),
("High Tibial Osteotomy (HTO)\nహై టిబియల్ ఆస్టియోటమీ",
"Bone cut and realigned to shift load away from damaged compartment. For younger, active patients.\n"
"ఎముకను కత్తిరించి దిశ మార్చడం ద్వారా ఒత్తిడి తగ్గిస్తారు. యువ, చురుకైన రోగులకు అనువైనది.",
colors.HexColor("#fff8e1")),
]
for name, desc, bg in types:
t = Table([[
Paragraph(f"<b>{name}</b>",
S("TN2", fontName="Telugu", fontSize=10, textColor=BLUE_DARK, leading=16)),
Paragraph(desc,
S("TD2", fontName="Telugu", fontSize=10, leading=15, textColor=colors.black)),
]], colWidths=["35%","65%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg),
("BACKGROUND", (1,0), (1,0), WHITE),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("VALIGN", (0,0), (-1,-1), "TOP"),
("BOX", (0,0), (-1,-1), 0.5, GREY_MED),
]))
el.append(t)
el.append(Spacer(1, 4))
return el
# ── Section 8: Before & After Surgery ───────────────────────────────────────
def section8():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("8. Before & After Surgery",
"8. శస్త్రచికిత్సకు ముందు మరియు తర్వాత"))
el.append(Spacer(1, 6))
before = [
("Blood tests, ECG, chest X-ray required",
"రక్త పరీక్షలు, ECG, ఛాతీ X-Ray అవసరం"),
("Stop blood thinners (aspirin) 5-7 days before",
"శస్త్రచికిత్సకు 5-7 రోజుల ముందు రక్తం పలచన మందులు ఆపండి"),
("Fasting from midnight before surgery",
"శస్త్రచికిత్సకు ముందు రాత్రి నుండి ఉపవాసం"),
("Arrange for someone to care post-surgery",
"శస్త్రచికిత్స తర్వాత సంరక్షణ కోసం ఏర్పాట్లు చేయండి"),
("Pre-operative physiotherapy strengthens muscles",
"శస్త్రచికిత్సకు ముందు ఫిజియోతెరపీ కండరాలు బలపరుస్తుంది"),
]
after = [
("Blood clot prevention: stockings + walking",
"రక్తం గడ్డకట్టడం నివారణ: స్టాకింగ్స్ + నడక"),
("Pain managed with medicines + ice packs",
"మందులు + మంచు కాంప్రెస్తో నొప్పి నిర్వహణ"),
("Physiotherapy starts Day 1 after surgery",
"శస్త్రచికిత్స తర్వాత 1వ రోజు నుండి ఫిజియోతెరపీ ప్రారంభం"),
("Hospital stay: 3-5 days typically",
"ఆసుపత్రిలో ఉండే వ్యవధి: సాధారణంగా 3-5 రోజులు"),
("Staples/stitches removed at 10-14 days",
"10-14 రోజులలో కుట్లు తీయబడతాయి"),
]
el.append(two_col(
[Paragraph("<b>Before Surgery — శస్త్రచికిత్సకు ముందు</b>",
S("BSH", fontName="Helvetica-Bold", fontSize=10.5, textColor=BLUE_DARK, spaceAfter=5))]
+ [info_box(before, bg=colors.HexColor("#e3f2fd"), title_bg=BLUE_MID)],
[Paragraph("<b>After Surgery — శస్త్రచికిత్స తర్వాత</b>",
S("ASH", fontName="Helvetica-Bold", fontSize=10.5, textColor=BLUE_DARK, spaceAfter=5))]
+ [info_box(after, bg=colors.HexColor("#e8f5e9"), title_bg=GREEN)],
))
return el
# ── Section 9: Recovery ──────────────────────────────────────────────────────
def section9():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("9. Recovery & Rehabilitation",
"9. కోలుకోవడం మరియు పునఃస్థాపన"))
el.append(Spacer(1, 6))
timeline = [
("Week 1-2\nవారం 1-2",
"Walk with walker/crutches. Perform ankle pumps, quad sets.\n"
"వాకర్/కర్రలతో నడవడం. చీలమండ వ్యాయామాలు, తొడ వ్యాయామాలు."),
("Week 3-6\nవారం 3-6",
"Walk without support indoors. Bend knee >90°. Climb stairs with support.\n"
"ఇంట్లో సహాయం లేకుండా నడవడం. మోకాలిని >90° వంచడం. సహాయంతో మెట్లు ఎక్కడం."),
("Week 6-12\nవారం 6-12",
"Most daily activities resumed. Drive (left knee: 4-6 wks; right knee: 6-8 wks).\n"
"రోజువారీ కార్యకలాపాలు పునఃప్రారంభం. వాహనం నడపడం (ఎడమ మోకాలి: 4-6 వారాలు; కుడి: 6-8 వారాలు)."),
("3-6 Months\n3-6 నెలలు",
"Near-full function. Swimming, cycling allowed. Avoid impact sports.\n"
"దాదాపు పూర్తి పనితీరు. ఈత, సైక్లింగ్ అనుమతి. అధిక ప్రభావ క్రీడలు నివారించండి."),
("1 Year+\n1 సంవత్సరం+",
"Full recovery. Implant lifespan: 15-25 years with proper care.\n"
"పూర్తి కోలుకోవడం. ఇంప్లాంట్ జీవితకాలం: సరైన సంరక్షణతో 15-25 సంవత్సరాలు."),
]
tl_data = [[
Paragraph("<b>Timeline</b>", S("TLH", fontName="Helvetica-Bold", fontSize=10, textColor=WHITE)),
Paragraph("<b>Activity / కార్యకలాపం</b>",
S("TLTH", fontName="Telugu", fontSize=10, textColor=WHITE)),
]]
for time, act in timeline:
tl_data.append([
Paragraph(f"<b>{time}</b>",
S("TLT", fontName="Telugu", fontSize=10, textColor=BLUE_DARK, leading=15)),
Paragraph(act,
S("TLA", fontName="Telugu", fontSize=10, leading=15, textColor=colors.black)),
])
tl_table = Table(tl_data, colWidths=["22%","78%"])
tl_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), BLUE_DARK),
("ROWBACKGROUNDS",(0,1), (-1,-1), [BLUE_LIGHT, WHITE, BLUE_LIGHT, WHITE, BLUE_LIGHT]),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("GRID", (0,0), (-1,-1), 0.3, GREY_MED),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
el.append(tl_table)
el.append(Spacer(1, 8))
# Do/Don't table
do_dont = [
[
Paragraph("<b>DO - చేయవలసినవి</b>",
S("DD1", fontName="Telugu", fontSize=11, textColor=GREEN, alignment=TA_CENTER)),
Paragraph("<b>DON'T - చేయకూడనివి</b>",
S("DD2", fontName="Telugu", fontSize=11, textColor=RED, alignment=TA_CENTER)),
],
[
Paragraph(
"• Use walker / stick as advised\n• Do daily physiotherapy exercises\n"
"• Keep wound clean and dry\n• Elevate leg to reduce swelling\n"
"• Sleep with pillow under knee initially\n• Report fever, redness, discharge\n\n"
"• సూచించిన వాకర్/కర్ర వాడండి\n• రోజూ ఫిజియోతెరపీ వ్యాయామాలు చేయండి\n"
"• గాయాన్ని శుభ్రంగా, పొడిగా ఉంచండి\n• వాపు తగ్గించడానికి కాలు పైకి ఉంచండి\n"
"• మొదట మోకాలి కింద దిండు పెట్టి పడుకోండి\n• జ్వరం, ఎర్రదనం, స్రావం నివేదించండి",
S("DO", fontName="Telugu", fontSize=10, leading=15, textColor=GREEN)),
Paragraph(
"• Don't kneel or squat\n• Don't sit cross-legged\n"
"• Don't climb stairs unnecessarily early\n• Don't ignore pain / swelling\n"
"• Don't miss follow-up appointments\n• Don't stop physiotherapy early\n\n"
"• మోకాళ్ళపై నిలబడకండి లేదా కూర్చోకండి\n• కాళ్ళు మడిచి కూర్చోకండి\n"
"• అనవసరంగా మెట్లు ఎక్కకండి\n• నొప్పి/వాపును పట్టించుకోకుండా వదలకండి\n"
"• ఫాలో-అప్ అపాయింట్మెంట్లు మిస్ చేయకండి\n• ఫిజియోతెరపీ త్వరగా ఆపకండి",
S("DONT", fontName="Telugu", fontSize=10, leading=15, textColor=RED)),
]
]
dd_table = Table(do_dont, colWidths=["50%","50%"])
dd_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#e8f5e9")),
("BACKGROUND", (1,0), (1,0), colors.HexColor("#ffebee")),
("BACKGROUND", (0,1), (0,1), colors.HexColor("#f1f8f1")),
("BACKGROUND", (1,1), (1,1), colors.HexColor("#fff5f5")),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 12),
("RIGHTPADDING", (0,0), (-1,-1), 12),
("BOX", (0,0), (0,-1), 1, GREEN),
("BOX", (1,0), (1,-1), 1, RED),
("LINEAFTER", (0,0), (0,-1), 0.5, GREY_MED),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
el.append(dd_table)
return el
# ── Section 10: FAQ ──────────────────────────────────────────────────────────
def section10():
el = []
el.append(Spacer(1, 8))
el.append(section_banner("10. Frequently Asked Questions (FAQ)",
"10. తరచుగా అడిగే ప్రశ్నలు"))
el.append(Spacer(1, 6))
faqs = [
("Is TKR surgery safe at age 60+?",
"60+ వయసులో TKR శస్త్రచికిత్స సురక్షితమా?",
"Yes. TKR has excellent outcomes in patients aged 60-80. Proper pre-operative "
"evaluation minimizes risks. Over 95% of patients report significant pain relief.",
"అవును. 60-80 సంవత్సరాల రోగులలో TKR అద్భుతమైన ఫలితాలు ఇస్తుంది. "
"శస్త్రచికిత్సకు ముందు సరైన మూల్యాంకనం ప్రమాదాలను తగ్గిస్తుంది. "
"95% కంటే ఎక్కువ రోగులు నొప్పిలో గణనీయమైన ఉపశమనం నివేదిస్తారు."),
("How long does a knee implant last?",
"నీ ఇంప్లాంట్ ఎంత కాలం ఉంటుంది?",
"Modern implants last 15-25 years in most patients. Avoiding high-impact activities "
"and maintaining healthy weight prolongs implant life.",
"ఆధునిక ఇంప్లాంట్లు చాలా రోగులలో 15-25 సంవత్సరాలు ఉంటాయి. "
"అధిక ప్రభావ కార్యకలాపాలు నివారించడం మరియు ఆరోగ్యకరమైన బరువు నిర్వహించడం "
"ఇంప్లాంట్ జీవితాన్ని పొడిగిస్తుంది."),
("Will I be able to walk normally after TKR?",
"TKR తర్వాత నేను సాధారణంగా నడవగలనా?",
"Yes — most patients walk without support within 4-6 weeks and return to full daily "
"activities within 3 months. Stairs, driving and light activities are gradually resumed.",
"అవును — చాలా మంది రోగులు 4-6 వారాలలో సహాయం లేకుండా నడుస్తారు మరియు "
"3 నెలలలో పూర్తి రోజువారీ కార్యకలాపాలు పునఃప్రారంభిస్తారు."),
("Is there pain after TKR surgery?",
"TKR శస్త్రచికిత్స తర్వాత నొప్పి ఉంటుందా?",
"Some pain and swelling for the first few weeks is normal. Pain is well-controlled with "
"medicines. By 3 months most patients are significantly more comfortable than before surgery.",
"మొదటి కొన్ని వారాలు కొంత నొప్పి మరియు వాపు సాధారణం. "
"మందులతో నొప్పి బాగా నియంత్రించబడుతుంది. "
"3 నెలలలో చాలా మంది రోగులు శస్త్రచికిత్సకు ముందు కంటే చాలా సౌకర్యంగా ఉంటారు."),
("Can both knees be replaced at the same time?",
"రెండు మోకాళ్ళను ఒకేసారి మార్చవచ్చా?",
"Bilateral simultaneous TKR is possible but carries higher risk. Most surgeons prefer "
"staged replacement (6 weeks to 3 months apart) especially in patients over 70.",
"ద్వైపాక్షిక ఒకేసారి TKR సాధ్యమే కానీ ఎక్కువ ప్రమాదం ఉంది. "
"చాలా మంది సర్జన్లు వ్యవధి ఉంచిన రిప్లేస్మెంట్ (6 వారాలు నుండి 3 నెలల తేడాతో) "
"ముఖ్యంగా 70 సంవత్సరాలు దాటిన రోగులలో ఇష్టపడతారు."),
]
for i, (q_en, q_tel, a_en, a_tel) in enumerate(faqs):
bg = BLUE_LIGHT if i % 2 == 0 else colors.HexColor("#f0f7ff")
faq_data = [
[
Paragraph(f"<b>Q: {q_en}</b>",
S("QE", fontName="Helvetica-Bold", fontSize=10, textColor=BLUE_DARK, leading=15)),
Paragraph(f"<b>ప్ర: {q_tel}</b>",
S("QT", fontName="Telugu", fontSize=10.5, textColor=BLUE_DARK, leading=16)),
],
[
Paragraph(f"A: {a_en}",
S("AE", fontName="Helvetica", fontSize=9.5, leading=14, textColor=colors.black)),
Paragraph(f"జ: {a_tel}",
S("AT", fontName="Telugu", fontSize=10, leading=15, textColor=colors.black)),
]
]
ft = Table(faq_data, colWidths=["50%","50%"])
ft.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), bg),
("BACKGROUND", (0,1), (-1,1), WHITE),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("BOX", (0,0), (-1,-1), 0.5, BLUE_MID),
("LINEAFTER", (0,0), (0,-1), 0.3, GREY_MED),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LINEBELOW", (0,0), (-1,0), 0.3, BLUE_MID),
]))
el.append(ft)
el.append(Spacer(1, 5))
return el
# ── Disclaimer footer ────────────────────────────────────────────────────────
def disclaimer():
el = []
el.append(Spacer(1, 10))
el.append(hr(RED, 1))
d_data = [[
Paragraph(
"<b>IMPORTANT NOTICE / ముఖ్యమైన నోటీస్:</b> This document is for patient education "
"only and does not constitute medical advice. Treatment decisions must be made by a "
"qualified orthopaedic surgeon after clinical examination. / "
"ఈ పత్రం రోగి విద్యా ప్రయోజనాల కోసం మాత్రమే, ఇది వైద్య సలహా కాదు. "
"చికిత్స నిర్ణయాలు క్లినికల్ పరీక్ష తర్వాత అర్హత కలిగిన ఆర్తోపెడిక్ సర్జన్ తీసుకుంటారు.",
S("DISC", fontName="Telugu", fontSize=9, textColor=RED, leading=14, alignment=TA_CENTER))
]]
dt = Table(d_data, colWidths=["100%"])
dt.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#fff3f3")),
("BOX", (0,0), (-1,-1), 0.8, RED),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
el.append(dt)
el.append(Spacer(1, 6))
el.append(Paragraph(
"A1 Amar Orthopedic Hospital, Auto Nagar, Guntur | Patient Education Series | July 2026",
S("FT", fontName="Helvetica", fontSize=8, textColor=colors.grey, alignment=TA_CENTER)))
return el
# ── Page number canvas callback ──────────────────────────────────────────────
def add_page_number(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 8)
canvas.setFillColor(colors.grey)
canvas.drawCentredString(A4[0]/2, 18*mm,
f"Page {doc.page} | Knee OA & TKR Patient Guide | A1 Amar Orthopedic Hospital")
canvas.restoreState()
# ── Build document ───────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=18*mm, leftMargin=18*mm,
topMargin=14*mm, bottomMargin=22*mm,
title="Knee OA & TKR Patient Education Guide",
author="A1 Amar Orthopedic Hospital",
subject="Patient Education - Knee Osteoarthritis & Total Knee Replacement"
)
story = []
story += cover_page()
story += section1()
story += section2()
story += section3()
story += section4()
story += section5()
story += section6()
story += section7()
story += section8()
story += section9()
story += section10()
story += disclaimer()
doc.build(story, onFirstPage=add_page_number, onLaterPages=add_page_number)
print(f"PDF created: {OUTPUT}")
if __name__ == "__main__":
build()
cd /tmp/workspace/knee-oa-pdf && python3 build_pdf.py 2>&1
ls -lh /tmp/workspace/knee-oa-pdf/Knee_OA_Patient_Education.pdf && python3 -c " from pypdf import PdfReader r = PdfReader('/tmp/workspace/knee-oa-pdf/Knee_OA_Patient_Education.pdf') print(f'Pages: {len(r.pages)}') print(f'Title: {r.metadata.title}') "
Knee OA Patient Education
PDF Document · PDF
| Section | English | Telugu |
|---|---|---|
| Cover | Table of contents, hospital branding | విషయ సూచిక |
| 1 | What is Knee OA? (Normal vs OA comparison table) | మోకాలి ఆస్టియోఆర్థ్రైటిస్ అంటే ఏమిటి? |
| 2 | Causes & Risk Factors | కారణాలు మరియు ప్రమాద కారకాలు |
| 3 | Symptoms | లక్షణాలు |
| 4 | X-Ray Grading (Kellgren-Lawrence Scale I-IV) | X-Ray గ్రేడింగ్ |
| 5 | Non-Surgical Treatment (Lifestyle, Meds, Injections, PT) | శస్త్రచికిత్స లేని చికిత్స |
| 6 | When is Surgery Needed? | శస్త్రచికిత్స సూచనలు |
| 7 | TKR Surgery - Step by Step + Types (TKR/UKR/HTO) | TKR శస్త్రచికిత్స వివరాలు |
| 8 | Before & After Surgery | శస్త్రచికిత్సకు ముందు మరియు తర్వాత |
| 9 | Recovery Timeline + Do's & Don'ts | కోలుకోవడం + చేయవలసినవి/చేయకూడనివి |
| 10 | FAQ (5 common questions) | తరచుగా అడిగే ప్రశ్నలు |
Make a pre-operative checklist PDF for patients scheduling surgery
ls /tmp/workspace/knee-oa-pdf/ && python3 -c "from reportlab.pdfgen import canvas; print('OK')"
~/knee-oa-pdf/build_checklist.py
"""
Pre-Operative Checklist PDF for TKR Surgery Patients
Bilingual: English + Telugu
A1 Amar Orthopedic Hospital, Auto Nagar, Guntur
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
FONT_PATH = "/tmp/workspace/knee-oa-pdf/NotoSansTelugu.ttf"
OUTPUT = "/tmp/workspace/knee-oa-pdf/PreOp_Checklist_TKR.pdf"
pdfmetrics.registerFont(TTFont("Tel", FONT_PATH))
# ── Colours ──────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#0d2b4e")
BLUE = colors.HexColor("#1565c0")
BLUE_LIGHT = colors.HexColor("#ddeeff")
BLUE_PALE = colors.HexColor("#f0f7ff")
TEAL = colors.HexColor("#00695c")
TEAL_LIGHT = colors.HexColor("#e0f2f1")
ORANGE = colors.HexColor("#e65100")
ORANGE_LIGHT= colors.HexColor("#fff3e0")
RED = colors.HexColor("#b71c1c")
RED_LIGHT = colors.HexColor("#ffebee")
GREEN = colors.HexColor("#2e7d32")
GREEN_LIGHT= colors.HexColor("#e8f5e9")
GREY = colors.HexColor("#757575")
GREY_LIGHT = colors.HexColor("#f5f5f5")
GREY_MED = colors.HexColor("#e0e0e0")
WHITE = colors.white
AMBER = colors.HexColor("#ff6f00")
AMBER_LIGHT= colors.HexColor("#fffde7")
W = A4[0] - 36*mm # usable width
# ── Style helpers ─────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
def hr(c=BLUE, t=0.8):
return HRFlowable(width="100%", thickness=t, color=c, spaceAfter=4, spaceBefore=2)
# ── Checkbox cell (drawn as a Unicode square) ─────────────────────────────────
BOX = "☐" # ☐ unchecked box
CHK = "☑" # ☑ (for legend)
def cb():
"""Returns a paragraph with a printable checkbox."""
return Paragraph(BOX, S("CB",
fontName="Helvetica", fontSize=14, textColor=GREY,
alignment=TA_CENTER, leading=16))
# ── Section banner ────────────────────────────────────────────────────────────
def banner(icon, en, tel, bg=NAVY):
data = [[
Paragraph(f"<b>{icon} {en}</b>", S("BN",
fontName="Helvetica-Bold", fontSize=12, textColor=WHITE, leading=17)),
Paragraph(tel, S("BNT",
fontName="Tel", fontSize=12, textColor=colors.HexColor("#bbdefb"), leading=17)),
]]
t = Table(data, colWidths=["55%","45%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
return t
# ── Single checklist row ──────────────────────────────────────────────────────
def row(en, tel, note_en="", note_tel="", odd=True, urgent=False):
bg = RED_LIGHT if urgent else (GREY_LIGHT if odd else WHITE)
en_text = f"<b>{en}</b>" if urgent else en
tel_text = f"<b>{tel}</b>" if urgent else tel
note_style_e = S("NE", fontName="Helvetica-Oblique", fontSize=8,
textColor=ORANGE if urgent else GREY, leading=11)
note_style_t = S("NT", fontName="Tel", fontSize=8.5,
textColor=ORANGE if urgent else GREY, leading=12)
col_en = [Paragraph(en_text, S("RE", fontName="Helvetica", fontSize=9.5,
textColor=RED if urgent else colors.black, leading=14))]
if note_en:
col_en.append(Paragraph(note_en, note_style_e))
col_tel = [Paragraph(tel_text, S("RT", fontName="Tel", fontSize=10,
textColor=RED if urgent else colors.black, leading=15))]
if note_tel:
col_tel.append(Paragraph(note_tel, note_style_t))
data = [[cb(), col_en, col_tel]]
t = Table(data, colWidths=["6%", "47%", "47%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(0,0), 4),
("LEFTPADDING", (1,0),(1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "TOP"),
("LINEBELOW", (0,0),(-1,-1), 0.3, GREY_MED),
("BOX", (0,0),(0,-1), 0.3, GREY_MED),
]))
if urgent:
t.setStyle(TableStyle([("BOX",(0,0),(-1,-1),1,RED)]))
return t
def sub_header(en, tel, bg=BLUE_LIGHT, tc=BLUE):
data = [[
Paragraph(f"<b>{en}</b>", S("SH",
fontName="Helvetica-Bold", fontSize=9.5, textColor=tc, leading=13)),
Paragraph(tel, S("SHT",
fontName="Tel", fontSize=10, textColor=tc, leading=14)),
]]
t = Table(data, colWidths=["50%","50%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
return t
# ── PAGE HEADER ───────────────────────────────────────────────────────────────
def page_header():
el = []
# Top hospital strip
h_data = [[
Paragraph("<b>A1 AMAR ORTHOPEDIC HOSPITAL</b>",
S("H1", fontName="Helvetica-Bold", fontSize=14, textColor=WHITE, leading=18)),
Paragraph("Auto Nagar, Guntur | Orthopaedics & Joint Replacement",
S("H2", fontName="Helvetica", fontSize=9, textColor=colors.HexColor("#bbdefb"),
alignment=TA_RIGHT, leading=13)),
]]
ht = Table(h_data, colWidths=["60%","40%"])
ht.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 12),
("BOTTOMPADDING", (0,0),(-1,-1), 12),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
el.append(ht)
el.append(Spacer(1, 6))
# Title row
title_data = [[
Paragraph(
"<b>PRE-OPERATIVE CHECKLIST</b><br/>Total Knee Replacement (TKR) Surgery",
S("PT", fontName="Helvetica-Bold", fontSize=16, textColor=NAVY,
alignment=TA_CENTER, leading=22)),
],[
Paragraph(
"శస్త్రచికిత్సకు ముందు తనిఖీ జాబితా — టోటల్ నీ రిప్లేస్మెంట్ (TKR) శస్త్రచికిత్స",
S("PT2", fontName="Tel", fontSize=13, textColor=BLUE,
alignment=TA_CENTER, leading=18)),
]]
tt = Table(title_data, colWidths=["100%"])
tt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), BLUE_PALE),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1, BLUE),
]))
el.append(tt)
el.append(Spacer(1, 6))
# Patient info strip
info_data = [[
Paragraph("<b>Patient Name / రోగి పేరు:</b> _______________________________",
S("PI1", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("<b>Age / వయసు:</b> _______ <b>Sex / లింగం:</b> _______",
S("PI2", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("<b>Surgery Date / శస్త్రచికిత్స తేదీ:</b> _______________",
S("PI3", fontName="Helvetica", fontSize=9.5, leading=14)),
],[
Paragraph("<b>IP Number / IP నంబర్:</b> _______________________________",
S("PI4", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("<b>Surgeon / సర్జన్:</b> _______________________________",
S("PI5", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("<b>Side / వైపు:</b> ☐ Right / కుడి ☐ Left / ఎడమ ☐ Both / రెండూ",
S("PI6", fontName="Helvetica", fontSize=9.5, leading=14)),
]]
it = Table(info_data, colWidths=["34%","33%","33%"])
it.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), GREY_LIGHT),
("GRID", (0,0),(-1,-1), 0.4, GREY_MED),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 8),
("RIGHTPADDING", (0,0),(-1,-1), 8),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
el.append(it)
el.append(Spacer(1, 4))
# Legend
legend = Table([[
Paragraph(f"{BOX} = Tick when done / చేసినప్పుడు గుర్తు పెట్టండి",
S("LG", fontName="Helvetica", fontSize=8.5, textColor=GREY)),
Paragraph("<font color='#b71c1c'><b>Red rows = CRITICAL items / ఎర్రటి వరుసలు = అత్యంత ముఖ్యమైనవి</b></font>",
S("LG2", fontName="Helvetica", fontSize=8.5, textColor=RED)),
Paragraph("Tick ALL boxes before coming to hospital / ఆసుపత్రికి వచ్చే ముందు అన్ని పెట్టెలు గుర్తు పెట్టండి",
S("LG3", fontName="Helvetica", fontSize=8.5, textColor=GREY, alignment=TA_RIGHT)),
]], colWidths=["40%","35%","25%"])
legend.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 0),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
el.append(legend)
el.append(hr(NAVY, 1.5))
return el
# ── SECTION A: Tests & Investigations (2 weeks before) ───────────────────────
def section_a():
el = []
el.append(banner("🔬", "A. Tests & Investigations (2 Weeks Before Surgery)",
"A. పరీక్షలు మరియు నిర్ధారణలు (శస్త్రచికిత్సకు 2 వారాల ముందు)", NAVY))
el.append(sub_header("Blood Tests — రక్త పరీక్షలు", "Collect reports & bring on admission day",
BLUE_LIGHT, BLUE))
items_a1 = [
("Complete Blood Count (CBC / Haemogram)",
"పూర్తి రక్త పరిశోధన (CBC)"),
("Blood Group & Cross-matching",
"రక్త గ్రూప్ మరియు క్రాస్-మ్యాచింగ్"),
("Blood Glucose Fasting & Post-Prandial",
"ఉపవాస రక్తంలో చక్కెర పరీక్ష"),
("HbA1c (if diabetic / షుగర్ రోగులకు)",
"HbA1c"),
("Serum Creatinine & Electrolytes (Na, K)",
"సీరమ్ క్రియాటినిన్ మరియు ఎలెక్ట్రోలైట్స్"),
("Liver Function Tests (LFT)",
"కాలేయ పనితీరు పరీక్షలు (LFT)"),
("Coagulation profile: PT, aPTT, INR",
"రక్తం గడ్డకట్టే పరీక్షలు: PT, aPTT, INR"),
("HIV, HBsAg, HCV screening",
"HIV, హెపటైటిస్ B & C పరీక్షలు"),
]
for i, (e, t) in enumerate(items_a1):
el.append(row(e, t, odd=(i%2==0)))
el.append(Spacer(1,3))
el.append(sub_header("Cardiac Tests — గుండె పరీక్షలు", "", TEAL_LIGHT, TEAL))
items_a2 = [
("12-Lead ECG (Electrocardiogram)",
"ECG (గుండె లయ పరీక్ష)",
"Mandatory for all patients >40 years",
"40 సంవత్సరాలు పైన అందరికీ తప్పనిసరి"),
("Echocardiogram (2D Echo)",
"2D ఎకో (గుండె అల్ట్రాసౌండ్)",
"If ECG abnormal or history of heart disease",
"ECG అసాధారణంగా ఉంటే లేదా గుండె చరిత్ర ఉంటే"),
("Cardiologist fitness certificate",
"కార్డియాలజిస్ట్ ఫిట్నెస్ సర్టిఫికెట్",
"Required if hypertension / heart disease",
"రక్తపోటు / గుండె సమస్య ఉంటే తప్పనిసరి"),
]
for i, item in enumerate(items_a2):
el.append(row(item[0], item[1],
note_en=item[2] if len(item)>2 else "",
note_tel=item[3] if len(item)>3 else "",
odd=(i%2==0)))
el.append(Spacer(1,3))
el.append(sub_header("Imaging — చిత్రణ పరీక్షలు", "", ORANGE_LIGHT, ORANGE))
items_a3 = [
("Weight-bearing X-Ray both knees AP & Lateral",
"రెండు మోకాళ్ళ నిలబడే X-Ray (AP మరియు Lateral)",
"Full-leg standing X-ray if deformity present",
"వైకల్యం ఉంటే పూర్తి కాలు X-Ray"),
("Chest X-Ray (PA view)",
"ఛాతీ X-Ray",
"For anaesthesia clearance",
"అనస్థీషియా అనుమతి కోసం"),
("MRI Knee (if requested by surgeon)",
"మోకాలి MRI (సర్జన్ అభ్యర్థించినప్పుడు)",
"Usually not mandatory for standard TKR",
"సాధారణ TKR కి సాధారణంగా తప్పనిసరి కాదు"),
]
for i, item in enumerate(items_a3):
el.append(row(item[0], item[1],
note_en=item[2] if len(item)>2 else "",
note_tel=item[3] if len(item)>3 else "",
odd=(i%2==0)))
return el
# ── SECTION B: Medications (1 week before) ───────────────────────────────────
def section_b():
el = []
el.append(Spacer(1,6))
el.append(banner("💊", "B. Medications to STOP Before Surgery",
"B. శస్త్రచికిత్సకు ముందు ఆపవలసిన మందులు", RED))
el.append(Spacer(1,2))
meds_stop = [
("Aspirin / Ecosprin",
"ఆస్పిరిన్ / ఎకోస్ప్రిన్",
"STOP 7 days before surgery — risk of bleeding",
"శస్త్రచికిత్సకు 7 రోజుల ముందు ఆపండి — రక్తస్రావం ప్రమాదం",
True),
("Clopidogrel (Plavix) / Ticagrelor",
"క్లోపిడోగ్రెల్ / టికాగ్రెలర్",
"STOP 7 days before — consult cardiologist first",
"7 రోజుల ముందు ఆపండి — ముందు కార్డియాలజిస్ట్ సంప్రదించండి",
True),
("Warfarin / Rivaroxaban / Apixaban",
"వార్ఫారిన్ / రివారోగ్జాబన్",
"STOP 5 days before — surgeon's specific instructions",
"5 రోజుల ముందు ఆపండి — సర్జన్ సూచనలు అనుసరించండి",
True),
("NSAIDs: Diclofenac, Ibuprofen, Naproxen",
"NSAIDs: డైక్లోఫెనాక్, ఐబుప్రోఫెన్",
"STOP 5 days before surgery",
"శస్త్రచికిత్సకు 5 రోజుల ముందు ఆపండి",
True),
("Metformin (Diabetes medication)",
"మెట్ఫార్మిన్ (డయాబెటిస్ మందు)",
"Stop 48 hours before surgery; resume after",
"శస్త్రచికిత్సకు 48 గంటల ముందు ఆపండి",
False),
("Herbal supplements / Vitamins E, Fish oil",
"మూలికా మందులు / విటమిన్ E, చేప నూనె",
"Stop 2 weeks before — risk of bleeding",
"2 వారాల ముందు ఆపండి — రక్తస్రావం ప్రమాదం",
False),
]
for i, item in enumerate(meds_stop):
el.append(row(item[0], item[1],
note_en=item[2], note_tel=item[3],
odd=(i%2==0), urgent=item[4]))
el.append(Spacer(1,4))
# Continue meds box
cont_data = [[
Paragraph("<b>CONTINUE these medications (unless told otherwise):</b>",
S("CM1", fontName="Helvetica-Bold", fontSize=9.5, textColor=GREEN, leading=13)),
Paragraph("<b>ఈ మందులు కొనసాగించండి (సర్జన్ ఆపమనే వరకు):</b>",
S("CM2", fontName="Tel", fontSize=10, textColor=GREEN, leading=14)),
],[
Paragraph(
"• Antihypertensives (BP tablets) — take on morning of surgery with a sip of water\n"
"• Thyroid medications (Thyroxine)\n"
"• Inhalers for asthma\n"
"• Anti-epileptic drugs",
S("CM3", fontName="Helvetica", fontSize=9.5, leading=14, textColor=colors.black)),
Paragraph(
"• రక్తపోటు మందులు — శస్త్రచికిత్స రోజు ఉదయం కొద్దిగా నీళ్ళతో తీసుకోండి\n"
"• థైరాయిడ్ మందులు (థైరాక్సిన్)\n"
"• ఆస్తమా ఇన్హేలర్లు\n"
"• ఎపిలెప్సీ మందులు",
S("CM4", fontName="Tel", fontSize=10, leading=15, textColor=colors.black)),
]]
cmt = Table(cont_data, colWidths=["50%","50%"])
cmt.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), GREEN_LIGHT),
("BACKGROUND", (0,1),(-1,1), colors.HexColor("#f1f8f1")),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 1, GREEN),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
el.append(cmt)
return el
# ── SECTION C: Pre-admission preparations ────────────────────────────────────
def section_c():
el = []
el.append(Spacer(1,6))
el.append(banner("🏥", "C. Pre-Admission Preparations (1 Week Before)",
"C. ముందస్తు సన్నాహాలు (1 వారం ముందు)", BLUE))
items_c = [
("Donate / arrange 2 units of blood (same group)",
"రక్తదానం / 2 యూనిట్ల రక్తం అదే గ్రూప్లో ఏర్పాటు చేయండి",
"Autologous or family donor preferred",
"స్వయం లేదా కుటుంబ దాత ఇష్టం",
True),
("Get Anaesthesia Pre-assessment (OPD)",
"అనస్థీషియా ముందస్తు మూల్యాంకనం (OPD) పూర్తి చేయండి",
"Anaesthetist will review fitness for surgery",
"అనస్థీషియా డాక్టర్ శస్త్రచికిత్సకు అనువైనదో పరీక్షిస్తారు",
True),
("Sign Informed Consent form",
"అవగాహన సమ్మతి ఫారం సంతకం చేయండి",
"Surgeon will explain risks and benefits",
"సర్జన్ ప్రమాదాలు మరియు ప్రయోజనాలు వివరిస్తారు",
True),
("Dental check-up (if dental infection suspected)",
"దంత పరీక్ష (దంత సంక్రమణ అనుమానం ఉంటే)",
"Active dental infections must be treated before implant surgery",
"ఇంప్లాంట్ శస్త్రచికిత్సకు ముందు దంత సంక్రమణలు చికిత్స చేయాలి",
False),
("Physiotherapy session: learn post-op exercises",
"ఫిజియోతెరపీ సెషన్: శస్త్రచికిత్స తర్వాత వ్యాయామాలు నేర్చుకోండి",
"Practice quadriceps sets, ankle pumps, deep breathing",
"తొడ వ్యాయామాలు, చీలమండ వ్యాయామాలు, శ్వాసవ్యాయామాలు నేర్చుకోండి",
False),
("Arrange home care / caregiver post-discharge",
"ఇంట్లో సంరక్షణ / సంరక్షకుడి ఏర్పాటు చేయండి",
"You will need help for 4-6 weeks after surgery",
"శస్త్రచికిత్స తర్వాత 4-6 వారాలు సహాయం అవసరం",
False),
("Prepare home: remove trip hazards, install grab bars",
"ఇంట్లో తయారీ: పడిపోయే ప్రమాదాలు తొలగించండి, గ్రాబ్ బార్లు అమర్చండి",
"Bathroom rails, raised toilet seat, non-slip mats recommended",
"బాత్రూమ్ రైల్స్, ఎత్తైన టాయిలెట్ సీట్, జారకుండా చాపలు సిఫారసు",
False),
("Purchase walker / crutches in advance",
"ముందస్తుగా వాకర్ / కర్రలు కొనండి",
"Confirm type with physiotherapist",
"ఫిజియోతెరపిస్ట్తో రకం నిర్ధారించుకోండి",
False),
("Prepare loose, comfortable clothing for hospital",
"ఆసుపత్రి కోసం వదులైన, సౌకర్యమైన దుస్తులు తయారు చేయండి",
"Shorts / pyjamas — knee must be easily accessible",
"నిక్కర్లు / పైజమాలు — మోకాలి తేలికగా చేరుకోగలగాలి",
False),
]
for i, item in enumerate(items_c):
el.append(row(item[0], item[1],
note_en=item[2] if len(item)>2 else "",
note_tel=item[3] if len(item)>3 else "",
odd=(i%2==0), urgent=item[4]))
return el
# ── SECTION D: Night before surgery ──────────────────────────────────────────
def section_d():
el = []
el.append(Spacer(1,6))
el.append(banner("🌙", "D. Night Before Surgery (Evening / 8 PM onwards)",
"D. శస్త్రచికిత్సకు ముందు రాత్రి (సాయంత్రం / రాత్రి 8 గంటల నుండి)", NAVY))
items_d = [
("Last solid meal by 10 PM the night before",
"మధ్యరాత్రి 10 గంటలలోపు చివరి ఘన ఆహారం తినండి",
"No food after midnight — strict fasting required",
"మధ్యరాత్రి తర్వాత ఆహారం తినవద్దు — కఠినమైన ఉపవాసం అవసరం",
True),
("Clear fluids (water, clear juice) until 2 hours before surgery",
"శస్త్రచికిత్సకు 2 గంటల ముందు వరకు నీళ్ళు/మీగడ లేని జ్యూస్ తాగవచ్చు",
"NO milk, tea with milk, solid food after midnight",
"మధ్యరాత్రి తర్వాత పాలు, చాయ్, ఘన ఆహారం తీసుకోవద్దు",
True),
("Shower / bathe with antiseptic soap (Betadine / Hibiscrub)",
"యాంటీసెప్టిక్ సబ్బుతో స్నానం (బెటడైన్ / హిబిస్క్రబ్)",
"Especially scrub the knee area thoroughly",
"ముఖ్యంగా మోకాలి ప్రాంతాన్ని బాగా శుభ్రం చేయండి",
False),
("Remove nail polish from toenails / fingernails",
"కాలి / వేలి గోర్ల మీద నెయిల్ పాలిష్ తొలగించండి",
"Nail colour interferes with pulse oximeter monitoring",
"నెయిల్ పాలిష్ pulse oximeter పనిచేయకుండా చేస్తుంది",
False),
("Remove jewellery, piercings, contact lenses",
"నగలు, పియర్సింగ్లు, కాంటాక్ట్ లెన్సులు తొలగించండి",
"Store valuables safely at home",
"విలువైన వస్తువులు ఇంట్లో భద్రంగా ఉంచండి",
False),
("Take prescribed BP / heart medication with a small sip of water",
"రక్తపోటు / గుండె మందులు కొద్దిగా నీళ్ళతో తీసుకోండి",
"Only medicines specifically approved by anaesthetist",
"అనస్థీషియా డాక్టర్ అనుమతించిన మందులు మాత్రమే",
False),
("Ensure good night's sleep; no alcohol",
"మంచి నిద్ర పొందండి; మద్యం తాగవద్దు",
"Alcohol within 24 hours increases complication risk",
"24 గంటలలో మద్యం సమస్యల ప్రమాదం పెంచుతుంది",
False),
]
for i, item in enumerate(items_d):
el.append(row(item[0], item[1],
note_en=item[2] if len(item)>2 else "",
note_tel=item[3] if len(item)>3 else "",
odd=(i%2==0), urgent=item[4]))
return el
# ── SECTION E: Morning of surgery ────────────────────────────────────────────
def section_e():
el = []
el.append(Spacer(1,6))
el.append(banner("☀️", "E. Morning of Surgery (Admission Day)",
"E. శస్త్రచికిత్స రోజు ఉదయం (అడ్మిషన్ రోజు)", TEAL))
items_e = [
("STRICTLY NO FOOD from midnight onwards",
"మధ్యరాత్రి నుండి ఆహారం తీసుకోవద్దు — అత్యంత ముఖ్యం",
"Surgery will be CANCELLED if fasting is not followed",
"ఉపవాసం పాటించకపోతే శస్త్రచికిత్స రద్దు చేయబడుతుంది",
True),
("Arrive at hospital 2 hours before scheduled time",
"నిర్ణీత సమయానికి 2 గంటల ముందు ఆసుపత్రికి చేరుకోండి",
"Admission, paperwork, IV line placement takes time",
"అడ్మిషన్, కాగితపని, IV లైన్ వేయడానికి సమయం పడుతుంది",
True),
("Take approved morning medications with small sip of water",
"అనుమతించిన ఉదయం మందులు కొద్దిగా నీళ్ళతో తీసుకోండి",
"Only BP / heart / thyroid tablets if cleared by anaesthetist",
"అనస్థీషియా అనుమతించిన మందులు మాత్రమే",
False),
("Wear clean, loose-fitting clothes",
"శుభ్రమైన, వదులైన దుస్తులు వేసుకోండి",
"Avoid tight clothes, belts, compression stockings from home",
"ఇంటి నుండి గట్టి దుస్తులు, బెల్ట్లు ధరించవద్దు",
False),
("Do NOT apply creams, lotions or deodorant on the knee",
"మోకాలిపై క్రీమ్లు, లోషన్లు లేదా డియోడరెంట్ వేయవద్దు",
"Skin must be clean and dry for surgery prep",
"శస్త్రచికిత్స సన్నాహానికి చర్మం శుభ్రంగా, పొడిగా ఉండాలి",
False),
("Bring ALL X-Rays, scan reports, blood reports",
"అన్ని X-Rays, స్కాన్ రిపోర్ట్లు, రక్త రిపోర్ట్లు తీసుకొచ్చండి",
"Originals + photocopies of all investigation reports",
"అన్ని పరీక్ష రిపోర్ట్ల ఒరిజినల్స్ + ఫోటోకాపీలు",
False),
("Bring a responsible adult companion (>18 years)",
"బాధ్యతగల పెద్ద వ్యక్తి (>18 సంవత్సరాలు) వెంట తీసుకొచ్చండి",
"They must stay for at least 24 hours post-surgery",
"వారు శస్త్రచికిత్స తర్వాత కనీసం 24 గంటలు ఉండాలి",
True),
]
for i, item in enumerate(items_e):
el.append(row(item[0], item[1],
note_en=item[2] if len(item)>2 else "",
note_tel=item[3] if len(item)>3 else "",
odd=(i%2==0), urgent=item[4]))
return el
# ── SECTION F: Documents to bring ────────────────────────────────────────────
def section_f():
el = []
el.append(Spacer(1,6))
el.append(banner("📄", "F. Documents to Bring on Admission Day",
"F. అడ్మిషన్ రోజు తీసుకొచ్చే పత్రాలు", ORANGE))
docs = [
("Government ID proof (Aadhaar / Voter ID / Passport)",
"ప్రభుత్వ గుర్తింపు పత్రం (ఆధార్ / ఓటర్ ID / పాస్పోర్ట్)"),
("All previous X-rays, MRI, CT scan reports",
"అన్ని పాత X-Rays, MRI, CT స్కాన్ రిపోర్ట్లు"),
("All blood test reports (less than 2 weeks old)",
"అన్ని రక్త పరీక్ష రిపోర్ట్లు (2 వారాల కంటే తాజావి)"),
("Cardiologist / specialist fitness certificate",
"కార్డియాలజిస్ట్ / స్పెషలిస్ట్ ఫిట్నెస్ సర్టిఫికెట్"),
("Complete list of current medications",
"ప్రస్తుత మందుల పూర్తి జాబితా"),
("Health insurance card / TPA letter (if applicable)",
"హెల్త్ ఇన్సూరెన్స్ కార్డ్ / TPA లెటర్ (వర్తించే వారికి)"),
("Ayushman Bharat / CGHS / ESI card (if applicable)",
"ఆయుష్మాన్ భారత్ / CGHS / ESI కార్డ్ (వర్తించే వారికి)"),
("Hospital admission fee / advance deposit",
"ఆసుపత్రి అడ్వాన్స్ డిపాజిట్"),
("Emergency contact numbers (2 family members)",
"అత్యవసర సంప్రదింపు నంబర్లు (2 కుటుంబ సభ్యులు)"),
]
for i, (e, t) in enumerate(docs):
el.append(row(e, t, odd=(i%2==0)))
return el
# ── SECTION G: What NOT to bring ─────────────────────────────────────────────
def section_g():
el = []
el.append(Spacer(1,6))
el.append(banner("🚫", "G. Do NOT Bring to Hospital",
"G. ఆసుపత్రికి తీసుకురావద్దు", RED))
donts = [
("Jewellery, gold, valuables (leave at home)",
"నగలు, బంగారం, విలువైన వస్తువులు (ఇంట్లో వదలండి)"),
("Large amounts of cash",
"పెద్ద మొత్తంలో నగదు"),
("Dentures (unless necessary — inform anaesthetist)",
"దంతాల సెట్ (అనవసరమైతే — అనస్థీషియా డాక్టర్కు తెలియజేయండి)"),
("Hearing aids (inform anaesthetist if you use one)",
"వినికిడి సహాయం (మీరు వాడుతుంటే అనస్థీషియా డాక్టర్కు చెప్పండి)"),
("Contact lenses (wear glasses instead)",
"కాంటాక్ट్ లెన్సులు (అద్దాలు ధరించండి)"),
("Strong perfumes / body sprays / nail polish",
"బలమైన పరిమళ ద్రవ్యాలు / నెయిల్ పాలిష్"),
("Excess luggage (minimal personal items only)",
"అతిగా సామాను (కనీస వ్యక్తిగత వస్తువులు మాత్రమే)"),
]
for i, (e, t) in enumerate(donts):
el.append(row(e, t, odd=(i%2==0), urgent=False))
return el
# ── SECTION H: Pre-existing conditions ───────────────────────────────────────
def section_h():
el = []
el.append(Spacer(1,6))
el.append(banner("⚕️", "H. Special Instructions for Pre-existing Conditions",
"H. ముందే ఉన్న వ్యాధులకు ప్రత్యేక సూచనలు", NAVY))
conditions = [
("DIABETES / డయాబెటిస్",
"• Stop Metformin 48 hrs before\n• Check blood sugar morning of surgery\n"
"• Target sugar: 140-180 mg/dL before surgery\n• Inform if on Insulin",
"• మెట్ఫార్మిన్ 48 గంటల ముందు ఆపండి\n• శస్త్రచికిత్స ఉదయం చక్కెర పరీక్షించండి\n"
"• లక్ష్యం: 140-180 mg/dL\n• ఇన్సులిన్ వాడుతుంటే తెలియజేయండి",
AMBER_LIGHT, AMBER),
("HYPERTENSION / రక్తపోటు",
"• Continue BP tablets on surgery morning with sip of water\n"
"• Target BP: <150/90 before surgery\n• Bring latest BP readings",
"• BP మందులు శస్త్రచికిత్స ఉదయం కొద్దిగా నీళ్ళతో తీసుకోండి\n"
"• లక్ష్యం: <150/90\n• తాజా BP రీడింగ్లు తీసుకొచ్చండి",
BLUE_LIGHT, BLUE),
("HEART DISEASE / గుండె వ్యాధి",
"• Mandatory cardiologist clearance letter\n• Do NOT stop heart medications\n"
"• Bring pacemaker card if applicable\n• ECG & Echo required",
"• తప్పనిసరిగా కార్డియాలజిస్ట్ అనుమతి లెటర్ తీసుకొచ్చండి\n"
"• గుండె మందులు ఆపవద్దు\n• పేస్మేకర్ కార్డ్ (వర్తించే వారికి)\n• ECG & Echo అవసరం",
RED_LIGHT, RED),
("ASTHMA / COPD / ఆస్తమా",
"• Bring inhalers to hospital\n• Inform anaesthetist about frequency of attacks\n"
"• Respiratory physiotherapy pre-operatively advisable",
"• ఇన్హేలర్లు ఆసుపత్రికి తీసుకొచ్చండి\n• దాడుల పౌనఃపున్యం అనస్థీషియా డాక్టర్కు చెప్పండి\n"
"• శ్వాస వ్యాయామాలు ముందే చేయడం మంచిది",
TEAL_LIGHT, TEAL),
("KIDNEY DISEASE / మూత్రపిండాల వ్యాధి",
"• Serum creatinine must be within acceptable range\n"
"• Nephrology clearance if creatinine >1.5 mg/dL\n• Avoid NSAIDs",
"• సీరమ్ క్రియాటినిన్ అనుమతించిన పరిధిలో ఉండాలి\n"
"• క్రియాటినిన్ >1.5 mg/dL అయితే నెఫ్రాలజిస్ట్ అనుమతి\n• NSAIDs వద్దు",
ORANGE_LIGHT, ORANGE),
]
for cond, en_body, tel_body, bg, tc in conditions:
cond_data = [[
Paragraph(f"<b>{cond}</b>",
S("CH", fontName="Helvetica-Bold", fontSize=10, textColor=tc, leading=14)),
Paragraph("", S("empty", fontName="Helvetica", fontSize=1)),
],[
Paragraph(en_body,
S("CB2", fontName="Helvetica", fontSize=9.5, leading=15, textColor=colors.black)),
Paragraph(tel_body,
S("CB3", fontName="Tel", fontSize=10, leading=15, textColor=colors.black)),
]]
ct = Table(cond_data, colWidths=["50%","50%"])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), bg),
("BACKGROUND", (0,1),(-1,1), WHITE),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, tc),
("SPAN", (0,0),(1,0)),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
el.append(ct)
el.append(Spacer(1,4))
return el
# ── SECTION I: Contact & Final Reminder ──────────────────────────────────────
def section_i():
el = []
el.append(Spacer(1,6))
reminder_data = [[
Paragraph("<b>EMERGENCY CONTACT / అత్యవసర సంప్రదింపు</b>",
S("EC1", fontName="Tel", fontSize=11, textColor=WHITE,
alignment=TA_CENTER, leading=16)),
],[
Paragraph(
"A1 Amar Orthopedic Hospital, Auto Nagar, Guntur\n"
"If you have ANY questions about your preparation, call us BEFORE the surgery day.",
S("EC2", fontName="Helvetica", fontSize=10, alignment=TA_CENTER, leading=15,
textColor=colors.HexColor("#bbdefb"))),
],[
Paragraph(
"ఏదైనా సందేహం ఉంటే శస్త్రచికిత్స రోజు కంటే ముందే ఆసుపత్రిని సంప్రదించండి.\n"
"Phone: _______________________ Whatsapp: _______________________",
S("EC3", fontName="Tel", fontSize=10.5, alignment=TA_CENTER, leading=16,
textColor=WHITE)),
]]
et = Table(reminder_data, colWidths=["100%"])
et.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 14),
("BOX", (0,0),(-1,-1), 1.5, BLUE),
]))
el.append(et)
el.append(Spacer(1,6))
# Signature strip
sig_data = [[
Paragraph("Patient Signature / రోగి సంతకం: _____________________",
S("SIG1", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("Caregiver Signature / సంరక్షకుడి సంతకం: _____________________",
S("SIG2", fontName="Helvetica", fontSize=9.5, leading=14)),
Paragraph("Staff Verified By / సిబ్బంది ధృవీకరణ: _____________________ Date: ___________",
S("SIG3", fontName="Helvetica", fontSize=9.5, leading=14)),
]]
st = Table(sig_data, colWidths=["33%","34%","33%"])
st.setStyle(TableStyle([
("GRID", (0,0),(-1,-1), 0.5, GREY_MED),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 8),
("BACKGROUND", (0,0),(-1,-1), GREY_LIGHT),
("VALIGN", (0,0),(-1,-1), "BOTTOM"),
]))
el.append(st)
el.append(Spacer(1,6))
# Disclaimer
disc = Table([[
Paragraph(
"<b>DISCLAIMER / నోటీస్:</b> This checklist is a guide only. "
"Follow your surgeon's and anaesthetist's specific individual instructions above all else. "
"Surgery may be postponed if any critical preparation is incomplete. / "
"ఈ చెక్లిస్ట్ మార్గదర్శకం మాత్రమే. మీ సర్జన్ మరియు అనస్థీషియా డాక్టర్ "
"నిర్దిష్ట సూచనలు అన్నింటికంటే ముఖ్యం. ముఖ్యమైన సన్నాహాలు అసంపూర్ణంగా ఉంటే "
"శస్త్రచికిత్స వాయిదా వేయబడవచ్చు.",
S("DISC", fontName="Tel", fontSize=8.5, textColor=RED,
alignment=TA_CENTER, leading=14))
]], colWidths=["100%"])
disc.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#fff3f3")),
("BOX", (0,0),(-1,-1), 0.8, RED),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("RIGHTPADDING", (0,0),(-1,-1), 10),
]))
el.append(disc)
el.append(Spacer(1,4))
el.append(Paragraph(
"A1 Amar Orthopedic Hospital | Pre-Operative Checklist — TKR | July 2026 | Page {page}",
S("FT", fontName="Helvetica", fontSize=8, textColor=GREY, alignment=TA_CENTER)))
return el
# ── Page number callback ──────────────────────────────────────────────────────
def add_page_num(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 7.5)
canvas.setFillColor(GREY)
canvas.drawCentredString(
A4[0]/2, 14*mm,
f"A1 Amar Orthopedic Hospital | Pre-Op Checklist (TKR) | Page {doc.page}")
canvas.restoreState()
# ── BUILD ─────────────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=16*mm, leftMargin=16*mm,
topMargin=12*mm, bottomMargin=20*mm,
title="Pre-Operative Checklist — Total Knee Replacement (TKR)",
author="A1 Amar Orthopedic Hospital",
subject="Pre-Op Patient Checklist — TKR Surgery"
)
story = []
story += page_header()
story += section_a()
story += section_b()
story += section_c()
story += section_d()
story += section_e()
story += section_f()
story += section_g()
story += section_h()
story += section_i()
doc.build(story, onFirstPage=add_page_num, onLaterPages=add_page_num)
print(f"Done: {OUTPUT}")
if __name__ == "__main__":
build()
cd /tmp/workspace/knee-oa-pdf && python3 build_checklist.py 2>&1
python3 -c " from pypdf import PdfReader r = PdfReader('/tmp/workspace/knee-oa-pdf/PreOp_Checklist_TKR.pdf') print(f'Pages: {len(r.pages)}') print(f'Size: $(ls -lh /tmp/workspace/knee-oa-pdf/PreOp_Checklist_TKR.pdf | awk \"{print \$5}\")') " ls -lh /tmp/workspace/knee-oa-pdf/PreOp_Checklist_TKR.pdf
PreOp Checklist TKR
PDF Document · PDF
| Section | Contents |
|---|---|
| Header | Patient name, IP no., age, sex, surgeon, surgery date, knee side - all fillable |
| A - Tests & Investigations | Blood tests (CBC, coags, glucose, LFTs, HIV/HBsAg), cardiac (ECG, Echo, cardiologist certificate), imaging (X-ray, Chest X-ray, MRI) |
| B - Medications to STOP | Aspirin, clopidogrel, warfarin, NSAIDs, Metformin, herbal supplements - with exact stop dates. Green box for medications to continue |
| C - Pre-Admission Preparations | Blood donation, anaesthesia assessment, consent, dental check, physio, home prep, walker purchase |
| D - Night Before Surgery | Fasting rules, antiseptic shower, nail polish removal, jewellery, last approved medications |
| E - Morning of Surgery | Strict fasting reminder, arrival timing, what to wear, NO creams on knee, reports to carry, companion requirement |
| F - Documents to Bring | ID proof, reports, insurance/Ayushman cards, advance deposit, emergency contacts |
| G - Do NOT Bring | Jewellery, cash, dentures, contact lenses, perfumes |
| H - Special Conditions | Colour-coded boxes for Diabetes, Hypertension, Heart Disease, Asthma/COPD, Kidney Disease |
| Footer | Signature strip (patient + caregiver + staff), hospital contact, disclaimer |