Posture essay notes for exercise therapy bpt
posture plumb line lateral view standing alignment

This clinical photograph comparison displays a lateral view of a human subject's standing posture analyzed using a digital posture evaluation system. Image (a) depicts 'natural standing posture,' characterized by an observable forward head position and anterior pelvic tilt relative to the vertical plumb line (red). Image (b) shows the 'posture after postural cueing' (specifically head inclination and chin tuck instructions). Visible changes include an improved cervical anterior angle (CAA), with the head and tragus of the ear aligning more posteriorly toward the vertical reference line. The shoulders appear less rounded, and there is a noticeable reduction in lumbar lordosis and anterior pelvic inclination. Digital markers (yellow dots) and red geometric lines indicate the measurement points for the cervical anterior angle and pelvic forward inclination angle (PFIA). This comparison illustrates the immediate musculoskeletal effects of verbal postural interventions on spinal alignment and pelvic tilt, relevant to physical therapy and ergonomic assessments.

This clinical photograph illustrates a posturology study assessing static postural alignment in a male subject. The image is a lateral (sagittal) view of the patient standing on a specialized platform equipped with bilateral handrails, likely a baropodometry or stabilometry system. The patient’s posture is analyzed relative to a superimposed vertical reference line (plumb line). Key anatomical markers are visible at the level of the acromioclavicular joint, the greater trochanter of the femur, and the lateral malleolus of the ankle to evaluate sagittal balance. Notable findings include a mild forward head posture and anterior translation of the center of mass, evidenced by the abdominal protrusion and the relationship of the hip and shoulder markers to the vertical axis. A measurement scale is visible on the background wall, used for quantifying postural deviations. This type of imaging is clinically relevant in physical therapy, orthopedics, and rehabilitation for evaluating the efficacy of plantar orthoses on body mechanics and spinal alignment.

This diagnostic image consists of side-by-side whole-body biplanar radiographs (Anteroposterior and Lateral) of a 15-year-old patient, acquired using the EOS system for sagittal balance and posture analysis. The AP view on the left demonstrates coronal alignment, showing a Cobb angle of 9° (T7-L2) and a lateral pelvic tilt of 7 mm. The lateral view on the right illustrates sagittal spinal and pelvic parameters, featuring measurements for Spino-Sacral Angle (125°), T1 Tilt (9°), Thoracic Kyphosis T1/T12 (51°), T9 Tilt (17°), and Lumbar Lordosis L1/L5 (35°). Pelvic morphology is characterized by Sacral Slope (SS: 28°), Pelvic Incidence (PI: 39°), and Pelvic Tilt (PT: 12°). Global balance is indicated by the Sagittal Vertical Axis (SVA: -31 mm) and the Cranial Alignment Measurement (CAM) plumb line (-38 mm). The image serves as an educational example of how low-dose biplanar radiography allows for comprehensive standing posture assessment and 3D reconstruction of the musculoskeletal system.
"posture"[MeSH Terms] AND "exercise therapy"[MeSH Terms]
| Type | Meaning | Example |
|---|---|---|
| Static posture | Body at rest, with no movement | Standing, sitting, lying |
| Dynamic posture | Body moving, with posture maintained during movement | Walking, running, lifting |
| Good (ideal) posture | Minimal stress and strain, maximum efficiency | Plumb line alignment |
| Poor (faulty) posture | Segments malaligned, with increased stress on structures | Forward head, round shoulders |

| Region | Deviation | Typical muscle changes |
|---|---|---|
| Head and neck | Forward head posture | Tight suboccipitals, SCM and upper trapezius. Weak deep neck flexors. |
| Shoulders | Round shoulders (protracted scapulae) | Tight pectorals. Weak rhomboids, middle and lower trapezius. |
| Upper back | Kyphosis (flat or round back) | Tight anterior chest wall. Weak thoracic extensors. |
| Lower back | Lordosis (hollow back) | Tight hip flexors and lumbar extensors. Weak abdominals and gluteals. |
| Lower back | Flat back | Tight hamstrings. Weak hip flexors. |
| Pelvis | Anterior pelvic tilt | As in lordosis. |
| Spine | Scoliosis (lateral curvature with rotation) | Asymmetry. Concave side tight, convex side stretched and weak. |
| Knees | Genu valgum, genu varum, genu recurvatum | Ligamentous and muscle imbalance. |
| Feet | Flat foot (pes planus), pes cavus | Weak intrinsic muscles and tibialis posterior. |
Make a revision PPT on posture for exam prep
Which topic should the revision PPT cover in detail first?
| Type | Meaning | Example |
|---|---|---|
| Static posture | Body at rest, with no movement | Standing, sitting, lying |
| Dynamic posture | Body moving, with posture maintained during movement | Walking, running, lifting |
| Good (ideal) posture | Minimal stress and strain, maximum efficiency | Plumb line alignment |
| Poor (faulty) posture | Segments malaligned, with increased stress on structures | Forward head, round shoulders |

| Region | Deviation | Typical muscle changes |
|---|---|---|
| Head and neck | Forward head posture | Tight suboccipitals, SCM and upper trapezius. Weak deep neck flexors. |
| Shoulders | Round shoulders (protracted scapulae) | Tight pectorals. Weak rhomboids, middle and lower trapezius. |
| Upper back | Kyphosis (flat or round back) | Tight anterior chest wall. Weak thoracic extensors. |
| Lower back | Lordosis (hollow back) | Tight hip flexors and lumbar extensors. Weak abdominals and gluteals. |
| Lower back | Flat back | Tight hamstrings. Weak hip flexors. |
| Pelvis | Anterior pelvic tilt | As in lordosis. |
| Spine | Scoliosis (lateral curvature with rotation) | Asymmetry. Concave side tight, convex side stretched and weak. |
| Knees | Genu valgum, genu varum, genu recurvatum | Ligamentous and muscle imbalance. |
| Feet | Flat foot (pes planus), pes cavus | Weak intrinsic muscles and tibialis posterior. |
ls -la /tmp/workspace/ 2>/dev/null; python -c "import pptx; print(pptx.__version__)"
mkdir -p /tmp/workspace/posture-ppt/assets /tmp/workspace/posture-ppt/output && cd /tmp/workspace/posture-ppt && python /tmp/skills/shared/scripts/fetch_images.py "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_432280f40d6a2e7218c0fed76e287118c26ee04169c612b3c4babdf1589e3e26.jpg" "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_5e0330c727122db87354d3cb13278faa3823a70544f5d215948fb8424cae225c.jpg" > assets/imgs.json; python - <<'E' import json,base64 from PIL import Image r=json.load(open('/tmp/workspace/posture-ppt/assets/imgs.json')) for i,x in enumerate(r): print(x['error']) if x['base64']: b=x['base64'].split(',',1)[1] p=f'/tmp/workspace/posture-ppt/assets/img{i}.jpg' open(p,'wb').write(base64.b64decode(b)) print(p, Image.open(p).size) E
~/posture-ppt/build.py
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.oxml.ns import qn
from PIL import Image
import copy
from lxml import etree
NAVY = RGBColor(0x0B, 0x3C, 0x49)
TEAL = RGBColor(0x1F, 0x7A, 0x8C)
CORAL = RGBColor(0xE0, 0x7A, 0x5F)
SAND = RGBColor(0xF6, 0xF2, 0xEA)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK = RGBColor(0x22, 0x2B, 0x31)
GREY = RGBColor(0x5B, 0x67, 0x70)
LTEAL = RGBColor(0xDD, 0xEE, 0xF1)
FONT = "Calibri"
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
BLANK = prs.slide_layouts[6]
page = [0]
def bg(slide, color):
f = slide.background.fill
f.solid()
f.fore_color.rgb = color
def rect(slide, x, y, w, h, fill, shape=MSO_SHAPE.RECTANGLE, line=None):
s = slide.shapes.add_shape(shape, Inches(x), Inches(y), Inches(w), Inches(h))
s.fill.solid()
s.fill.fore_color.rgb = fill
if line is None:
s.line.fill.background()
else:
s.line.color.rgb = line
s.line.width = Pt(1)
s.shadow.inherit = False
return s
def text(slide, x, y, w, h, s, size=18, bold=False, color=DARK, align=PP_ALIGN.LEFT,
anchor=MSO_ANCHOR.TOP, italic=False):
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.vertical_anchor = anchor
tf.margin_left = tf.margin_right = Inches(0.05)
tf.margin_top = tf.margin_bottom = Inches(0.03)
p = tf.paragraphs[0]
p.alignment = align
r = p.add_run()
r.text = s
r.font.name = FONT
r.font.size = Pt(size)
r.font.bold = bold
r.font.italic = italic
r.font.color.rgb = color
return tb
def bullets(slide, x, y, w, h, items, size=18, color=DARK, space=6, bullet_color=CORAL):
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = tf.margin_right = Inches(0.05)
first = True
for it in items:
p = tf.paragraphs[0] if first else tf.add_paragraph()
first = False
level = 0
if isinstance(it, dict):
level = it.get("level", 0)
head, tail = it.get("head"), it.get("tail", "")
elif isinstance(it, tuple):
head, tail = it
else:
head, tail = None, it
pPr = p._p.get_or_add_pPr()
marL = 0.28 + 0.3 * level
pPr.set("marL", str(int(Inches(marL))))
pPr.set("indent", str(int(-Inches(0.24))))
buClr = etree.SubElement(pPr, qn("a:buClr"))
c = etree.SubElement(buClr, qn("a:srgbClr"))
c.set("val", "%02X%02X%02X" % (bullet_color[0], bullet_color[1], bullet_color[2]))
bu = etree.SubElement(pPr, qn("a:buChar"))
bu.set("char", "•" if level == 0 else "-")
p.space_after = Pt(space)
if head:
r = p.add_run()
r.text = head
r.font.bold = True
r.font.name = FONT
r.font.size = Pt(size - level * 2)
r.font.color.rgb = NAVY
if tail:
r = p.add_run()
r.text = tail
r.font.name = FONT
r.font.size = Pt(size - level * 2)
r.font.color.rgb = color
return tb
def header(slide, title, sub=None):
bg(slide, SAND)
rect(slide, 0, 0, 13.333, 1.1, NAVY)
rect(slide, 0, 1.1, 13.333, 0.06, CORAL)
text(slide, 0.6, 0.12, 12, 0.7, title, size=32, bold=True, color=WHITE, anchor=MSO_ANCHOR.MIDDLE)
if sub:
text(slide, 0.6, 0.68, 12, 0.35, sub, size=14, color=RGBColor(0xBF, 0xDD, 0xE3), italic=True)
page[0] += 1
text(slide, 12.2, 7.05, 0.9, 0.3, str(page[0]), size=11, color=GREY, align=PP_ALIGN.RIGHT)
text(slide, 0.6, 7.05, 8, 0.3, "Posture | Exercise Therapy | BPT revision", size=11, color=GREY)
def card(slide, x, y, w, h, title, items, size=16, head_fill=TEAL, body_fill=WHITE):
rect(slide, x, y, w, h, body_fill, line=RGBColor(0xD8, 0xD2, 0xC4))
rect(slide, x, y, w, 0.5, head_fill)
text(slide, x + 0.1, y, w - 0.2, 0.5, title, size=17, bold=True, color=WHITE, anchor=MSO_ANCHOR.MIDDLE)
bullets(slide, x + 0.1, y + 0.6, w - 0.2, h - 0.65, items, size=size, space=4)
def table(slide, x, y, w, colw, rows, size=13, row_h=0.5, head_fill=NAVY):
nrows, ncols = len(rows), len(rows[0])
gs = slide.shapes.add_table(nrows, ncols, Inches(x), Inches(y), Inches(w), Inches(row_h * nrows))
t = gs.table
tblPr = t._tbl.tblPr
# remove style banding to control fill ourselves
tblPr.set("bandRow", "0")
tblPr.set("firstRow", "0")
tot = sum(colw)
for i, cw in enumerate(colw):
t.columns[i].width = Inches(w * cw / tot)
for r in range(nrows):
t.rows[r].height = Inches(row_h)
for c in range(ncols):
cell = t.cell(r, c)
cell.margin_left = cell.margin_right = Inches(0.08)
cell.margin_top = cell.margin_bottom = Inches(0.04)
cell.vertical_anchor = MSO_ANCHOR.MIDDLE
cell.fill.solid()
if r == 0:
cell.fill.fore_color.rgb = head_fill
else:
cell.fill.fore_color.rgb = WHITE if r % 2 else LTEAL
tf = cell.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
run = p.add_run()
run.text = rows[r][c]
run.font.name = FONT
run.font.size = Pt(size)
run.font.bold = (r == 0) or (c == 0)
run.font.color.rgb = WHITE if r == 0 else (NAVY if c == 0 else DARK)
return t
def picture(slide, path, x, y, maxw, maxh):
im = Image.open(path)
ar = im.width / im.height
w, h = maxw, maxw / ar
if h > maxh:
h, w = maxh, maxh * ar
px = x + (maxw - w) / 2
py = y + (maxh - h) / 2
slide.shapes.add_picture(path, Inches(px), Inches(py), Inches(w), Inches(h))
return px, py, w, h
def notes(slide, s):
slide.notes_slide.notes_text_frame.text = s
# ---------- 1 Title ----------
s = prs.slides.add_slide(BLANK)
bg(s, NAVY)
rect(s, 0, 5.2, 13.333, 0.08, CORAL)
text(s, 0.9, 1.7, 11.5, 1.3, "POSTURE", size=72, bold=True, color=WHITE)
text(s, 0.9, 3.0, 11.5, 0.8, "Exercise Therapy revision deck for BPT exams", size=28, color=RGBColor(0xBF, 0xDD, 0xE3))
text(s, 0.9, 3.9, 11.5, 0.8,
"Definition | Control | Plumb line | Deviations | Assessment | Management | Exam tips",
size=18, color=CORAL, bold=True)
text(s, 0.9, 5.5, 11.5, 0.5, "Sources: Bailey and Love 28th ed, Kandel Principles of Neural Science 6th ed, Rheumatology 2022, Campbell's Operative Orthopaedics 15th ed, standard physiotherapy teaching",
size=13, color=RGBColor(0xBF, 0xDD, 0xE3))
# ---------- 2 Definition ----------
s = prs.slides.add_slide(BLANK)
header(s, "Definition and Importance", "Start every essay answer with a clear definition")
card(s, 0.6, 1.5, 6.0, 2.6, "Definitions", [
("Posture: ", "the relative arrangement of body parts, or the attitude the body assumes, to balance stability with minimal energy cost"),
("Postural orientation: ", "how body parts are aligned with each other and with the environment"),
("Good posture: ", "muscle and skeletal balance that protects supporting structures from injury or progressive deformity"),
], size=15)
card(s, 6.8, 1.5, 5.9, 2.6, "Why it matters", [
"Upright trunk lowers the energy needed to hold the centre of mass over the base of support",
"Protects ligaments, discs and joints from strain",
"Affects breathing, balance, performance and pain",
], size=15, head_fill=CORAL)
card(s, 0.6, 4.3, 6.0, 2.6, "Good posture does", [
"Reduce muscle and ligament strain",
"Reduce fatigue and energy expenditure",
"Prevent deformity and early degeneration",
"Improve breathing, balance, function",
], size=15)
card(s, 6.8, 4.3, 5.9, 2.6, "Poor posture causes", [
"Neck and back pain, headache, TMJ strain",
"Muscle imbalance and joint wear",
"Reduced lung capacity",
"Higher injury and fall risk",
], size=15, head_fill=CORAL)
notes(s, "Kandel 6th ed: postural orientation and balance control interact but can act independently.")
# ---------- 3 Classification ----------
s = prs.slides.add_slide(BLANK)
header(s, "Classification of Posture", "Know the table and the postural vs structural difference")
table(s, 0.6, 1.5, 12.1, [2, 4, 3.5], [
["Type", "Meaning", "Example"],
["Static posture", "Body at rest, no movement", "Standing, sitting, lying"],
["Dynamic posture", "Body moving, posture maintained during movement", "Walking, running, lifting"],
["Good posture", "Minimal stress, maximum efficiency, plumb line alignment", "Standard standing"],
["Faulty posture", "Segments malaligned, increased stress on tissues", "Forward head, round shoulders"],
], size=15, row_h=0.62)
card(s, 0.6, 4.8, 5.9, 2.1, "Postural (functional) deformity", [
"Flexible, correctable actively or passively",
"Cause: habit, muscle imbalance, fatigue",
"Corrects on forward bend",
], size=15)
card(s, 6.8, 4.8, 5.9, 2.1, "Structural deformity", [
"Fixed, bony or soft tissue change",
"Does not correct voluntarily or passively",
"Rib hump persists on Adam's test",
], size=15, head_fill=CORAL)
# ---------- 4 Control ----------
s = prs.slides.add_slide(BLANK)
header(s, "Control of Posture", "Postural tone + sensory input + central integration + reflexes")
card(s, 0.6, 1.5, 4.0, 2.7, "Sensory inputs", [
"Visual",
"Vestibular",
"Somatosensory: muscle spindles, joint receptors, plantar surface",
], size=15)
card(s, 4.7, 1.5, 4.0, 2.7, "Central integration", [
"Brainstem: vestibular nuclei, reticular formation",
"Cerebellum",
"Basal ganglia and cortex",
], size=15)
card(s, 8.8, 1.5, 3.9, 2.7, "Effectors and reflexes", [
"Antigravity (tonic) extensors",
"Stretch, righting, tonic neck and labyrinthine reflexes",
], size=15, head_fill=CORAL)
rect(s, 0.6, 4.45, 12.1, 2.45, WHITE, line=RGBColor(0xD8, 0xD2, 0xC4))
text(s, 0.75, 4.5, 11.8, 0.45, "Postural tone (Kandel, 6th ed)", size=18, bold=True, color=NAVY)
bullets(s, 0.75, 4.95, 11.8, 1.9, [
"Antigravity support from tonic trunk, neck and ankle extensors, plus passive bone-on-bone forces (knees locked) and stretched ligaments (front of hip)",
"Postural tone is not static: it changes constantly with alignment, voluntary movement and task",
"Tone alone cannot maintain balance. Even breathing causes sway that is actively countered",
], size=15, space=4)
# ---------- 5 Plumb line ----------
s = prs.slides.add_slide(BLANK)
header(s, "Standard Posture: Lateral Plumb Line", "Kendall alignment, top to bottom: EST-HKA")
picture(s, "/tmp/workspace/posture-ppt/assets/img0.jpg", 0.6, 1.4, 4.6, 5.0)
text(s, 0.6, 6.45, 4.6, 0.5, "Lateral view with plumb line at acromion, greater trochanter, lateral malleolus (study image)",
size=11, italic=True, color=GREY)
card(s, 5.5, 1.5, 7.2, 5.4, "Line of gravity passes through", [
("Ear: ", "lobe of the ear (mastoid process)"),
("Shoulder: ", "middle of the shoulder joint (acromion)"),
("Trunk: ", "middle of the trunk"),
("Hip: ", "greater trochanter, slightly behind hip joint axis"),
("Knee: ", "slightly in front of the knee axis"),
("Ankle: ", "slightly in front of the lateral malleolus"),
("Spine (SVA): ", "odontoid, C7/T1 disc, T12/L1 disc, posterosuperior S1"),
], size=17)
# ---------- 6 Curves + AP view ----------
s = prs.slides.add_slide(BLANK)
header(s, "Normal Spinal Curves and Other Views", "Numbers are favourite viva and short note questions")
table(s, 0.6, 1.5, 6.3, [2.6, 2, 2.6], [
["Curve", "Normal range", "With age"],
["Cervical lordosis", "35 to 45 degrees", "-"],
["Thoracic kyphosis", "20 to 50 (mean 35)", "Increases"],
["Lumbar lordosis", "40 to 80 (mean 60)", "Decreases"],
], size=15, row_h=0.65)
bullets(s, 0.6, 4.3, 6.3, 2.6, [
"Most lumbar lordosis lies between L4 and S1",
"In efficient posture, cervical and lumbar lordosis balance thoracic kyphosis",
"Primary curves (kyphotic): thoracic, sacral. Secondary (lordotic): cervical, lumbar, from sitting and standing",
], size=15)
card(s, 7.2, 1.5, 5.5, 2.5, "Posterior view", [
"Head midline, spinous processes in a straight line",
"Level: shoulder tips, scapulae, iliac crests, PSIS",
"Gluteal folds level, feet symmetrical",
], size=15)
card(s, 7.2, 4.2, 5.5, 2.7, "Anterior view", [
"Head straight, shoulders and clavicles level",
"Equal chest and waist contours",
"Patellae face forward, knees and ankles equidistant from the line",
"Weight evenly distributed on both feet",
], size=15, head_fill=CORAL)
# ---------- 7 Factors ----------
s = prs.slides.add_slide(BLANK)
header(s, "Factors Affecting Posture")
card(s, 0.6, 1.5, 3.9, 5.4, "Constitutional", [
"Heredity and body build",
"Age: kyphosis rises, lordosis falls",
"Congenital deformity",
"Obesity, pregnancy (centre of gravity shifts forward)",
], size=16)
card(s, 4.7, 1.5, 3.9, 5.4, "Functional", [
"Muscle weakness, tightness, imbalance",
"Pain and fatigue",
"Poor habits, occupation, prolonged sitting",
"Ill-fitting furniture, footwear, foot deformity",
], size=16, head_fill=CORAL)
card(s, 8.8, 1.5, 3.9, 5.4, "Systemic", [
"Psychological state (depression gives slumped posture)",
"Visual or hearing defects (head tilt)",
"Neurological disease (Parkinson disease gives flexed posture)",
"Arthritis and spinal disease",
], size=16)
# ---------- 8 Deviations table ----------
s = prs.slides.add_slide(BLANK)
header(s, "Common Postural Deviations", "Learn: region, deviation, tight muscles, weak muscles")
table(s, 0.5, 1.4, 12.3, [1.5, 2.4, 4.2, 4.2], [
["Region", "Deviation", "Tight / shortened", "Weak / lengthened"],
["Head, neck", "Forward head", "Suboccipitals, SCM, upper trapezius", "Deep neck flexors"],
["Shoulder", "Round shoulders", "Pectorals", "Rhomboids, middle and lower trapezius"],
["Upper back", "Kyphosis", "Anterior chest wall", "Thoracic extensors"],
["Lower back", "Lordosis", "Hip flexors, lumbar extensors", "Abdominals, gluteals"],
["Lower back", "Flat back", "Hamstrings", "Hip flexors"],
["Spine", "Scoliosis", "Concave side", "Convex side (stretched)"],
["Knee", "Genu valgum, varum, recurvatum", "Ligament and muscle imbalance", "Variable"],
["Foot", "Pes planus, pes cavus", "Variable", "Intrinsics, tibialis posterior"],
], size=13, row_h=0.6)
# ---------- 9 Crossed syndromes ----------
s = prs.slides.add_slide(BLANK)
header(s, "Muscle Imbalance: Crossed Syndromes (Janda)", "Draw the cross in the exam to score marks")
card(s, 0.6, 1.5, 6.0, 4.0, "Upper crossed syndrome", [
("Tight: ", "pectorals, upper trapezius, levator scapulae, suboccipitals"),
("Weak: ", "deep neck flexors, middle and lower trapezius, rhomboids"),
("Picture: ", "forward head, round shoulders, increased cervical lordosis and thoracic kyphosis, winged scapulae"),
], size=16)
card(s, 6.8, 1.5, 5.9, 4.0, "Lower crossed syndrome", [
("Tight: ", "hip flexors, lumbar extensors"),
("Weak: ", "abdominals, gluteus maximus and medius"),
("Picture: ", "anterior pelvic tilt, increased lumbar lordosis, protruding abdomen"),
], size=16, head_fill=CORAL)
rect(s, 0.6, 5.7, 12.1, 1.2, LTEAL)
text(s, 0.8, 5.75, 11.7, 1.1,
"Sway back: pelvis shifts forward, thoracic spine flexed, long kyphosis. Treat by lengthening the tight muscles and strengthening the weak ones, never the reverse.",
size=16, color=NAVY, bold=True, anchor=MSO_ANCHOR.MIDDLE)
# ---------- 10 Assessment ----------
s = prs.slides.add_slide(BLANK)
header(s, "Postural Assessment", "History, observation, tests, measurement")
picture(s, "/tmp/workspace/posture-ppt/assets/img1.jpg", 0.6, 1.4, 5.6, 4.6)
text(s, 0.6, 6.05, 5.6, 0.8,
"Lateral, posterior and anterior views with plumb lines: forward head, kyphosis, lordosis, knee posture, scoliosis, rearfoot, genu valgum or varum (study image)",
size=11, italic=True, color=GREY)
bullets(s, 6.5, 1.5, 6.3, 5.4, [
("History: ", "occupation, pain, habits, onset, family history, aggravating and relieving positions"),
("Observation: ", "patient in underwear; anterior, posterior, lateral views against plumb line or posture grid; compare levels of shoulders, scapulae, pelvis, gluteal creases"),
("Postural vs structural: ", "ask for active or passive correction; Adam's forward bend test for rib hump"),
("Measurement: ", "plumb line, posture grid, flexible ruler, scoliometer, inclinometer, photographs, radiograph (Cobb angle)"),
("Muscle tests: ", "length (Thomas test, hamstrings, pectorals) and strength (MMT)"),
("Also: ", "leg length, wall-occiput distance, balance and gait"),
], size=16, space=7)
# ---------- 11 Management principles ----------
s = prs.slides.add_slide(BLANK)
header(s, "Exercise Therapy Management", "Find the cause, stretch tight, strengthen weak, re-educate, educate")
card(s, 0.6, 1.5, 3.9, 5.4, "1. Mobilise and stretch", [
"Relaxation and warm-up",
"Mobilise stiff segments (thoracic extension)",
"Stretch pectorals, upper trapezius, levator scapulae, suboccipitals",
"Stretch hip flexors, lumbar extensors, hamstrings, TFL",
"Static, PNF hold-relax, self-stretch",
], size=15)
card(s, 4.7, 1.5, 3.9, 5.4, "2. Strengthen", [
"Deep neck flexors: chin tuck, craniocervical flexion",
"Scapular retractors and depressors: rows, prone Y/T/W, wall angels",
"Thoracic extensors",
"Abdominals: pelvic tilt, curl-up, plank, TrA drawing in",
"Gluteus maximus: bridging, clamshell",
], size=15, head_fill=CORAL)
card(s, 8.8, 1.5, 3.9, 5.4, "3. Re-educate", [
"Pelvic tilt: crook lying, then sitting, standing, activity",
"Mirror training, verbal, tactile and visual cues",
"Wall standing: heels, buttocks, shoulders, head touch wall",
"Balance and proprioception (wobble board, single leg stance)",
"Core stability and Pilates-type work",
], size=15)
# ---------- 12 Specific conditions ----------
s = prs.slides.add_slide(BLANK)
header(s, "Management of Specific Deviations")
table(s, 0.5, 1.4, 12.3, [1.7, 5.4, 5.2], [
["Condition", "Exercise programme", "Notes"],
["Forward head, round shoulders", "Chin tuck, deep neck flexor training, scapular retraction, pectoral stretch", "Ergonomic correction of workstation"],
["Kyphosis", "Thoracic extension, chest stretch, back extensors, scapular retraction", "Postural kyphosis under 50 degrees: exercise improves posture but evidence for changing the curve is limited. Follow with lateral X-ray every 6 to 12 months"],
["Lordosis", "Pelvic tilt, abdominal strengthening, hip flexor and lumbar stretch, gluteal work", "Check footwear and obesity"],
["Scoliosis (functional)", "Correct cause, stretch concave side, strengthen convex side, Schroth-type exercise", "Structural curves may need bracing and referral"],
["Flat foot", "Short foot exercise, heel raises, toe curls", "Arch supports and proper footwear"],
], size=13, row_h=0.8)
# ---------- 13 Ergonomics ----------
s = prs.slides.add_slide(BLANK)
header(s, "Ergonomics, Prevention and Patient Education")
card(s, 0.6, 1.5, 6.0, 5.4, "Workstation and daily habits", [
"Screen at eye level, head over shoulders",
"Lumbar curve supported, hips and knees about 90 degrees, feet flat",
"Elbows at 90 degrees, forearms supported",
"Change position every 30 to 45 minutes",
"Bag on both shoulders, light loads",
], size=16)
card(s, 6.8, 1.5, 5.9, 5.4, "Prevention and advice", [
"Lift with bent knees, load close, no twisting",
"Firm mattress, low pillow",
"Proper footwear",
"Regular exercise and daily posture check",
"School screening and early correction in children",
"Home exercise programme with follow-up",
], size=16, head_fill=CORAL)
# ---------- 14 Evidence ----------
s = prs.slides.add_slide(BLANK)
header(s, "Recent Evidence (PubMed)", "Supports exercise for postural problems")
bullets(s, 0.7, 1.6, 11.9, 3.6, [
("Systematic review 2024: ", "effect of exercise on postural alignment (J Bodyw Mov Ther, PMID 39593708)"),
("Systematic review and meta-analysis 2024: ", "Pilates for postural misalignment (Musculoskelet Care, PMID 39562728)"),
("Postural cueing: ", "chin tuck and head inclination instructions can produce immediate improvement in forward head and pelvic tilt in photographic studies"),
], size=19, space=12)
rect(s, 0.7, 5.0, 11.9, 1.6, LTEAL)
text(s, 0.9, 5.05, 11.5, 1.5,
"Caution: effect sizes were not checked from full texts. Use these as supporting references, and follow your syllabus text (Kisner and Colby, Kendall) for exam wording.",
size=16, color=NAVY, anchor=MSO_ANCHOR.MIDDLE)
# ---------- 15 Exam revision ----------
s = prs.slides.add_slide(BLANK)
header(s, "Exam Revision: Mnemonics and Likely Questions")
card(s, 0.6, 1.5, 5.9, 2.4, "Mnemonics", [
("EST-HKA: ", "Ear, Shoulder, Trunk, Hip, Knee, Ankle (plumb line)"),
("Curves: ", "35 to 45 (C), 20 to 50 (T), 40 to 80 (L)"),
("Rule: ", "stretch tight, strengthen weak"),
], size=15)
card(s, 6.8, 1.5, 5.9, 2.4, "Answer skeleton (essay)", [
"Definition, types",
"Control, plumb line, curves",
"Deviations, causes, assessment",
"Exercise management, prevention",
], size=15, head_fill=CORAL)
card(s, 0.6, 4.1, 12.1, 2.8, "Likely questions", [
"Define posture. Describe standard posture with plumb line landmarks (long essay)",
"Classify faulty postures. Discuss causes and assessment (long essay)",
"Management of kyphosis, lordosis, scoliosis by exercise (long or short essay)",
"Short notes: postural tone, crossed syndromes, pelvic tilt exercise, Adam's test, ergonomics",
], size=15)
prs.save("/tmp/workspace/posture-ppt/output/Posture_Revision_Exercise_Therapy.pptx")
print("saved", len(prs.slides))
cd /tmp/workspace/posture-ppt && python build.py && python - <<'E' from pptx import Presentation from pptx.util import Emu p=Presentation('output/Posture_Revision_Exercise_Therapy.pptx') for i,s in enumerate(p.slides,1): for sh in s.shapes: if sh.left+sh.width>p.slide_width+10 or sh.top+sh.height>p.slide_height+10: print('overflow',i,sh.shape_type,sh.name) if sh.has_table if hasattr(sh,'has_table') else False: print('table slide',i,'height in',round(sh.height/914400,2),'top',round(sh.top/914400,2)) E
cd /tmp/workspace/posture-ppt && python - <<'E' s=open('build.py').read() s=s.replace('''], size=15) card(s, 6.8, 1.5, 5.9, 2.6, "Why it matters"''','''], size=14) card(s, 6.8, 1.5, 5.9, 2.6, "Why it matters"''') open('build.py','w').write(s) E python build.py && ls -la output
Posture Revision Exercise Therapy
Presentation · PPTX
Pblumb lime
plumb line posture anterior posterior lateral view landmarks

This clinical photograph demonstrates a lateral photographic technique used for the objective measurement of forward head posture (FHP) and forward shoulder angle in a human subject. The image features a lateral view of the upper torso, neck, and head with specific anatomical landmarks identified by black surface markers. Key markers are placed at the external auditory meatus (ear) and the acromion process of the shoulder. A vertical reference line (plumb line) is superimposed over the subject, originating from a fixed posterior point. To quantify postural deviations, angled lines connect the ear and shoulder markers to the vertical axis. The visual illustrates a significant anterior displacement of the head relative to the shoulder girdle and vertical plumb line, a common musculoskeletal finding in postural assessments. This educational material is relevant for physiotherapy, orthopedics, and kinesiology, specifically for teaching diagnostic measurements of craniovertebral angles and rounding of the shoulders associated with postural syndromes.

This clinical photograph demonstrates a sagittal plane posture assessment of a pediatric subject using a standardized photogrammetric method proposed by Pausić et al. (2010). The image features a side-profile view with a vertical reference line representing the ideal gravitational plumb line. Digital overlays include white dots at specific anatomical landmarks: the external auditory meatus, acromion, greater trochanter, lateral knee center, and external malleolus. White lines connect these points to visualize the alignment of the head, trunk, pelvis, and lower extremities. A horizontal double-headed arrow with '+' and '-' symbols is positioned at the shoulder level to indicate anterior or posterior trunk deviation relative to the vertical plumb line. This visual tool is used in physical therapy and orthopedics to quantitatively assess postural parameters such as head protraction, thoracic kyphosis, lumbar lordosis, and pelvic tilt, facilitating the identification of spinal misalignments or habitual postural adaptations.

| Finding | Interpretation |
|---|---|
| Ear in front of the line | Forward head posture |
| Acromion in front of the line | Round shoulders |
| Increased thoracic curve behind the line | Kyphosis |
| Trochanter and pelvis in front, with increased lumbar curve | Lordosis, anterior pelvic tilt |
| Knee behind the line | Genu recurvatum |
| Knee in front of the line | Flexed knee |
| C7 line falls to one side of the gluteal crease | Lateral spinal tilt, scoliosis |
| Unequal landmark heights | Shoulder, pelvic or leg length asymmetry |
Create a one-page posture cheat sheet PDF
~/posture-ppt/cheatsheet.py
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor, white
from reportlab.platypus import Paragraph, Table, TableStyle
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.utils import ImageReader
NAVY = HexColor("#0B3C49"); TEAL = HexColor("#1F7A8C"); CORAL = HexColor("#E07A5F")
SAND = HexColor("#F6F2EA"); LT = HexColor("#DDEEF1"); DARK = HexColor("#222B31"); GREY = HexColor("#5B6770")
W, H = A4
M = 22
GAP = 10
CW = (W - 2 * M - GAP) / 2
out = "/tmp/workspace/posture-ppt/output/Posture_Cheat_Sheet.pdf"
c = canvas.Canvas(out, pagesize=A4)
c.setTitle("Posture Cheat Sheet - Exercise Therapy BPT")
body = ParagraphStyle("b", fontName="Helvetica", fontSize=7.6, leading=9.2, textColor=DARK)
bul = ParagraphStyle("bul", parent=body, leftIndent=8, bulletIndent=0, spaceAfter=1.2)
cell = ParagraphStyle("cell", parent=body, fontSize=7, leading=8.2)
cellh = ParagraphStyle("cellh", parent=cell, fontName="Helvetica-Bold", textColor=white)
cellb = ParagraphStyle("cellb", parent=cell, fontName="Helvetica-Bold", textColor=NAVY)
# background
c.setFillColor(SAND); c.rect(0, 0, W, H, fill=1, stroke=0)
c.setFillColor(NAVY); c.rect(0, H - 52, W, 52, fill=1, stroke=0)
c.setFillColor(CORAL); c.rect(0, H - 55, W, 3, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 22); c.drawString(M, H - 34, "POSTURE CHEAT SHEET")
c.setFont("Helvetica", 9); c.setFillColor(HexColor("#BFDDE3"))
c.drawRightString(W - M, H - 30, "Exercise Therapy | BPT exam revision")
c.drawRightString(W - M, H - 42, "Sources: Bailey & Love 28e, Kandel 6e, Thieme Atlas, standard PT texts")
TOP = H - 64
BOT = 30
def box(x, y, w, title, items, color=TEAL, paras=False):
"""items: list of strings (bullets) -> returns new y"""
ps = [Paragraph(t, bul) for t in items]
inner = w - 12
hts = []
for p in ps:
_, h = p.wrap(inner - 8, 1000)
hts.append(h + 1.2)
total = 13 + sum(hts) + 5
c.setFillColor(white); c.setStrokeColor(HexColor("#D8D2C4")); c.setLineWidth(0.6)
c.roundRect(x, y - total, w, total, 3, fill=1, stroke=1)
c.setFillColor(color); c.roundRect(x, y - 13, w, 13, 3, fill=1, stroke=0)
c.rect(x, y - 13, w, 6, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 8.6); c.drawString(x + 6, y - 9.5, title)
cy = y - 13 - 3
for p, h in zip(ps, hts):
p.wrap(inner - 8, 1000)
p.drawOn(c, x + 6 + 0, cy - (h - 1.2))
c.setFillColor(CORAL); c.circle(x + 8, cy - 4.5, 1.1, fill=1, stroke=0)
cy -= h
return y - total - 6
def tbl(x, y, w, rows, colw, color=NAVY):
data = []
for r, row in enumerate(rows):
data.append([Paragraph(t, cellh if r == 0 else (cellb if i == 0 else cell)) for i, t in enumerate(row)])
tot = sum(colw)
t = Table(data, colWidths=[w * cw / tot for cw in colw])
st = [("BACKGROUND", (0, 0), (-1, 0), color),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.4, HexColor("#D8D2C4")),
("TOPPADDING", (0, 0), (-1, -1), 2), ("BOTTOMPADDING", (0, 0), (-1, -1), 2),
("LEFTPADDING", (0, 0), (-1, -1), 3), ("RIGHTPADDING", (0, 0), (-1, -1), 3)]
for r in range(1, len(rows)):
st.append(("BACKGROUND", (0, r), (-1, r), white if r % 2 else LT))
t.setStyle(TableStyle(st))
_, h = t.wrap(w, 1000)
t.drawOn(c, x, y - h)
return y - h - 6
LX = M
RX = M + CW + GAP
# ---------------- LEFT COLUMN ----------------
y = TOP
y = box(LX, y, CW, "1. DEFINITION", [
"<b>Posture</b>: relative arrangement of body parts; position that balances stability with minimal energy cost.",
"<b>Good posture</b>: muscle and skeletal balance that protects structures from injury or progressive deformity.",
"<b>Postural orientation</b>: alignment of body parts with each other and the environment.",
])
y = box(LX, y, CW, "2. TYPES", [
"<b>Static</b> (standing, sitting, lying) vs <b>dynamic</b> (walking, lifting).",
"<b>Postural (functional)</b> deformity: flexible, corrects actively or passively, due to habit or imbalance.",
"<b>Structural</b> deformity: fixed, bony or soft tissue change; rib hump persists on Adam's test.",
], color=CORAL)
y = box(LX, y, CW, "3. CONTROL OF POSTURE", [
"<b>Inputs</b>: visual, vestibular, somatosensory (spindles, joint, plantar).",
"<b>Centres</b>: brainstem (vestibular nuclei, reticular formation), cerebellum, basal ganglia, cortex.",
"<b>Reflexes</b>: stretch, righting, tonic neck, labyrinthine. <b>Effectors</b>: antigravity extensors.",
"Postural tone is not static; it changes with alignment and task. Tone alone cannot keep balance.",
])
# plumb line box with image
hdr_y = y
img = ImageReader("/tmp/workspace/posture-ppt/assets/img0.jpg")
iw, ih = img.getSize()
imgw = 72; imgh = imgw * ih / iw
items = [
"<b>Lateral line passes (EST-HKA)</b>:",
"<b>E</b>ar lobe (mastoid)",
"<b>S</b>houlder (acromion)",
"<b>T</b>runk midline",
"<b>H</b>ip: greater trochanter (slightly behind axis)",
"<b>K</b>nee: slightly in front of axis",
"<b>A</b>nkle: slightly in front of lateral malleolus",
]
ps = [Paragraph(t, bul) for t in items]
tw = CW - 12 - imgw - 6
hts = [p.wrap(tw - 8, 1000)[1] + 1.2 for p in ps]
total = 13 + max(sum(hts), imgh) + 20
c.setFillColor(white); c.setStrokeColor(HexColor("#D8D2C4")); c.roundRect(LX, y - total, CW, total, 3, fill=1, stroke=1)
c.setFillColor(TEAL); c.roundRect(LX, y - 13, CW, 13, 3, fill=1, stroke=0); c.rect(LX, y - 13, CW, 6, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 8.6); c.drawString(LX + 6, y - 9.5, "4. PLUMB LINE (LINE OF GRAVITY)")
c.drawImage(img, LX + 6, y - 13 - 3 - imgh, imgw, imgh, mask=None)
cy = y - 16
for p, h in zip(ps, hts):
p.wrap(tw - 8, 1000)
p.drawOn(c, LX + 6 + imgw + 6, cy - (h - 1.2))
if p is not ps[0]:
c.setFillColor(CORAL); c.circle(LX + 6 + imgw + 8, cy - 4.5, 1.1, fill=1, stroke=0)
cy -= h
fp = Paragraph("<b>Posterior</b>: plumb line from C7 spinous process falls through the gluteal crease; if not, lateral spinal tilt. "
"<b>Anterior</b>: midline of head, sternum, umbilicus, between feet.", body)
_, fh = fp.wrap(CW - 12, 100)
fp.drawOn(c, LX + 6, y - total + 3)
y = y - total - 6
y = box(LX, y, CW, "5. NORMAL SPINAL CURVES", [
"<b>Cervical lordosis</b> 35 to 45 deg.",
"<b>Thoracic kyphosis</b> 20 to 50 deg (mean 35); increases with age.",
"<b>Lumbar lordosis</b> 40 to 80 deg (mean 60); decreases with age; most between L4 and S1.",
"Sagittal axis: odontoid, C7/T1, T12/L1, posterosuperior S1.",
])
y = box(LX, y, CW, "6. FACTORS AFFECTING POSTURE", [
"Heredity, age, body build, obesity, pregnancy.",
"Muscle weakness or tightness, pain, fatigue, habits, occupation.",
"Footwear, foot deformity, furniture, vision or hearing defects.",
"Depression, neurological disease (Parkinson flexed posture).",
], color=CORAL)
left_end = y
# ---------------- RIGHT COLUMN ----------------
y = TOP
c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 8.6)
y = tbl(RX, y, CW, [
["Region", "Deviation", "Tight", "Weak"],
["Head, neck", "Forward head", "Suboccipitals, SCM, upper trap", "Deep neck flexors"],
["Shoulder", "Round shoulders", "Pectorals", "Rhomboids, mid and lower trap"],
["Upper back", "Kyphosis", "Anterior chest", "Thoracic extensors"],
["Low back", "Lordosis", "Hip flexors, lumbar extensors", "Abdominals, glutes"],
["Low back", "Flat back", "Hamstrings", "Hip flexors"],
["Spine", "Scoliosis", "Concave side", "Convex side"],
["Foot", "Pes planus", "Variable", "Intrinsics, tib. posterior"],
], [1.1, 1.3, 2.0, 2.0], color=CORAL)
# label above table
# (table has no title, so put the heading as first row replacement)
y = box(RX, y, CW, "7. CROSSED SYNDROMES (JANDA)", [
"<b>Upper</b>: tight pectorals, upper trap, levator scapulae, suboccipitals; weak deep neck flexors, lower and mid trap, rhomboids. Gives forward head, round shoulders, kyphosis.",
"<b>Lower</b>: tight hip flexors, lumbar extensors; weak abdominals, gluteals. Gives anterior pelvic tilt, lordosis.",
"<b>Sway back</b>: pelvis forward, thoracic spine flexed, long kyphosis.",
])
y = box(RX, y, CW, "8. ASSESSMENT", [
"<b>History</b>: occupation, pain, habits, onset, family history.",
"<b>Observation</b>: plumb line or posture grid, 3 views; compare shoulders, scapulae, pelvis, gluteal creases.",
"<b>Postural vs structural</b>: correct the deformity; Adam's forward bend test.",
"<b>Measures</b>: scoliometer, inclinometer, flexible ruler, photographs, X-ray (Cobb angle).",
"<b>Muscle tests</b>: length (Thomas, hamstrings, pectorals) and MMT.",
], color=TEAL)
y = box(RX, y, CW, "9. EXERCISE MANAGEMENT: STRETCH, STRENGTHEN, RE-EDUCATE", [
"<b>Stretch</b>: pectorals, upper trap, levator, suboccipitals, hip flexors, lumbar extensors, hamstrings (static, PNF hold-relax).",
"<b>Strengthen</b>: chin tuck and deep neck flexors; rows, prone Y/T/W, wall angels; thoracic extensors; pelvic tilt, curl-up, plank; bridging, clamshell; short foot.",
"<b>Re-educate</b>: pelvic tilt (crook lying, sitting, standing), mirror and cues, wall standing, balance and proprioception, core stability.",
"<b>Mobilise</b> stiff segments first (thoracic extension).",
], color=CORAL)
y = box(RX, y, CW, "10. SPECIFIC CONDITIONS", [
"<b>Kyphosis</b>: extension and chest stretch; postural kyphosis under 50 deg, exercise helps posture but evidence for changing the curve is limited; X-ray every 6 to 12 months.",
"<b>Lordosis</b>: pelvic tilt, abdominals, stretch hip flexors and lumbar extensors.",
"<b>Scoliosis (functional)</b>: correct cause, stretch concave, strengthen convex, Schroth-type; structural may need brace and referral.",
"<b>Flat foot</b>: short foot, heel raises, arch support.",
], color=TEAL)
y = box(RX, y, CW, "11. ERGONOMICS AND ADVICE", [
"Screen at eye level; lumbar support; hips and knees about 90 deg; feet flat.",
"Change position every 30 to 45 min; bag on both shoulders.",
"Lift with bent knees, load close; firm mattress; proper footwear.",
], color=CORAL)
right_end = y
# bottom exam strip
sy = min(left_end, right_end) - 2
sp = Paragraph("<b>EXAM TIPS:</b> Rule = stretch the tight, strengthen the weak. Essay order: definition, types, control, plumb line, curves, deviations, causes, assessment, exercise management, prevention. "
"Likely: plumb line landmarks, crossed syndromes, pelvic tilt exercise, Adam's test, management of kyphosis, lordosis and scoliosis.",
ParagraphStyle("t", parent=body, textColor=white, fontSize=7.6, leading=9.2))
_, th = sp.wrap(W - 2 * M - 12, 100)
bh = th + 8
by = BOT - 4
c.setFillColor(NAVY); c.roundRect(M, by, W - 2 * M, bh, 3, fill=1, stroke=0)
sp.drawOn(c, M + 6, by + 4)
print("left_end", round(left_end, 1), "right_end", round(right_end, 1), "strip top", round(by + bh, 1))
c.showPage(); c.save()
cd /tmp/workspace/posture-ppt && python cheatsheet.py; python -c "import fitz" 2>&1 | head -1; python -c "import pypdfium2" 2>&1 | head -1
cd /tmp/workspace/posture-ppt && ls && python cheatsheet.py; python -c "import fitz; print('fitz ok')" 2>&1 | tail -1; python -c "import pypdfium2; print('pdfium ok')" 2>&1 | tail -1
cd /tmp/workspace/posture-ppt && python - <<'E' import pypdfium2 as p d=p.PdfDocument('output/Posture_Cheat_Sheet.pdf') print(len(d)) d[0].render(scale=1.6).to_pil().save('assets/preview.png') E
cd /tmp/workspace/posture-ppt && python - <<'E' s=open('cheatsheet.py').read() s=s.replace('fontSize=7.6, leading=9.2, textColor=DARK)','fontSize=8.5, leading=10.3, textColor=DARK)') s=s.replace('cell = ParagraphStyle("cell", parent=body, fontSize=7, leading=8.2)','cell = ParagraphStyle("cell", parent=body, fontSize=7.8, leading=9.2)') s=s.replace('fontSize=7.6, leading=9.2))\n_, th','fontSize=8.5, leading=10.3))\n_, th') # plumb box total s=s.replace('total = 13 + max(sum(hts), imgh) + 20','''fp = Paragraph("<b>Posterior</b>: plumb line from C7 spinous process falls through the gluteal crease; if not, lateral spinal tilt. " "<b>Anterior</b>: midline of head, sternum, umbilicus, between feet.", body) _, fh = fp.wrap(CW - 12, 100) total = 13 + 3 + max(sum(hts), imgh) + 4 + fh + 4''') s=s.replace('''fp = Paragraph("<b>Posterior</b>: plumb line from C7 spinous process falls through the gluteal crease; if not, lateral spinal tilt. " "<b>Anterior</b>: midline of head, sternum, umbilicus, between feet.", body) _, fh = fp.wrap(CW - 12, 100) fp.drawOn(c, LX + 6, y - total + 3)''','fp.drawOn(c, LX + 6, y - total + 4)') s=s.replace('imgw = 72','imgw = 70') s=s.replace('"9. EXERCISE MANAGEMENT: STRETCH, STRENGTHEN, RE-EDUCATE"','"9. EXERCISE MANAGEMENT"') # table title s=s.replace('''c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 8.6) y = tbl(''','''c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 9) c.drawString(RX, y - 9, "COMMON DEVIATIONS: TIGHT vs WEAK"); y -= 14 y = tbl(''') open('cheatsheet.py','w').write(s) E python cheatsheet.py && python - <<'E' import pypdfium2 as p d=p.PdfDocument('/tmp/workspace/posture-ppt/output/Posture_Cheat_Sheet.pdf') print(len(d)) d[0].render(scale=1.6).to_pil().save('/tmp/workspace/posture-ppt/assets/preview.png') E
Posture Cheat Sheet
PDF Document · PDF
Exercises for scoliosis
"scoliosis"[MeSH Terms] AND "exercise therapy"[MeSH Terms]
PMID: 38726971
PMID: 41175413

| Use exercise | Limits |
|---|---|
| Mild to moderate AIS (about 10 to 25 degrees) | Not a substitute for bracing in progressing curves (about 25 to 40 degrees in a growing child) |
| Alongside bracing | Not for curves needing surgery (generally over 45 to 50 degrees) |
| Adult scoliosis with pain | Needs referral for neurological signs |
| Post-operative rehabilitation | Exercise must stay within surgeon precautions |
| Functional (postural) scoliosis | Structural curves will not fully correct |
| Aim | Exercise | How |
|---|---|---|
| Mobilise and stretch concave side | Side-lying over a roll or pillow (concavity up) | Roll under the apex of the concavity, arm overhead on the concave side; hold 20 to 30 s. |
| Concave-side lateral stretch | Standing or sitting; arm overhead, side-bend away from the concavity; avoid pushing into the convexity. | |
| Cat-camel (quadruped) | Gentle spinal mobility, with a pelvic tilt. | |
| Hip flexor, hamstring and pectoral stretch | Reduce tightness that tilts the pelvis or rounds the shoulders. | |
| Strengthen convex side and trunk | Side-lying lateral trunk lift | Convex side up (weak side): lift trunk or legs against gravity. |
| Side plank (modified) | Hold with correction; add time on the weaker side. | |
| Prone back extension | Strengthen erector spinae and thoracic extensors. | |
| Bird-dog | Trunk stability while correcting. | |
| Bridging, clamshell | Glutes and pelvic stability. | |
| Abdominal curl-up, pelvic tilt, TrA drawing in | Core control. | |
| Scapular and shoulder girdle | Rows, prone Y/T/W, wall angels | Level and stabilise the shoulders. |
| Posture and balance | Mirror training, wall standing, single-leg stance | Re-educate self-correction and proprioception. |
| Breathing | Deep (diaphragmatic) breathing | Expand the concave chest wall. |
Lumbosacral angle Forward lean posture Scoliosis Kyphosis Flat back from carolin kishner
| Change | Effect |
|---|---|
| Increased angle (sacrum more horizontal, anterior pelvic tilt) | Increased lumbar lordosis. More shear at L5/S1 and more load on facet joints. Linked to low back pain and spondylolisthesis. |
| Decreased angle (sacrum more vertical, posterior pelvic tilt) | Flat back. Reduced lordosis and more load on the discs. |
| Tight, strong or in sustained contraction | Weak or elongated |
|---|---|
| Plantar flexors (gastrocnemius, soleus) are often tight and work to stop the body falling forward | Tibialis anterior and other ankle dorsiflexors are often weak |
| Back extensors, hip extensors and neck extensors work continuously | Abdominals and hip flexors are often weak |
| Type | Features |
|---|---|
| Nonstructural (functional/postural) | Flexible. Cause is outside the spine: leg length difference, pain/spasm, habit. Corrects on forward bend and when the cause is removed. |
| Structural | Fixed, with vertebral rotation and a rib hump on forward bend. Causes: idiopathic (about 80%), congenital, neuromuscular, others. |
| Curve | Approach |
|---|---|
| Under about 20 to 25 degrees | Observation, with exercise and education |
| About 25 to 40 degrees in a growing child | Bracing, plus exercise |
| Above about 40 to 50 degrees | Surgical referral |
| Type | Features |
|---|---|
| Postural kyphosis (round back) | Flexible. No vertebral change and no sharp angulation. Corrects with backward bending and prone hyperextension (Miller's Review of Orthopaedics, 9th ed). |
| Scheuermann disease | Structural adolescent kyphosis, with wedging of more than 5 degrees at three adjacent vertebrae and end-plate changes (Bailey and Love's). It is rigid. |
| Other structural | Congenital, post-traumatic, osteoporotic compression fractures, ankylosing spondylitis, metabolic bone disease. |
| Tight or strong | Weak or lengthened |
|---|---|
| Hamstrings and hip extensors | Hip flexors (iliopsoas) |
| Rectus abdominis and obliques (often short) | Lumbar extensors and, often, the upper back extensors |
| Posture | Pelvis / lumbosacral angle | Spine | Tight | Weak |
|---|---|---|---|---|
| Forward lean | Neutral | Straight, body inclined at the ankles | Plantar flexors, back extensors | Tibialis anterior, abdominals, hip flexors |
| Scoliosis | Often pelvic obliquity | Lateral curve with rotation | Concave side | Convex side |
| Kyphosis | Variable | Increased thoracic curve | Pectorals, hip flexors, hamstrings | Thoracic extensors, scapular retractors |
| Flat back | Posterior tilt, reduced angle | Reduced lumbar lordosis | Hamstrings, abdominals | Hip flexors, lumbar extensors |
| Lordosis (for contrast) | Anterior tilt, increased angle | Increased lumbar curve | Hip flexors, lumbar extensors | Abdominals, glutes |
Exercise for Scoliosis
| Step | Exercise | Dose (typical, not fixed) |
|---|---|---|
| 1. Warm-up and mobility | Cat-camel, pelvic tilt in crook lying | 10 reps |
| 2. Stretch concave side | Side-lying over a roll at the concavity, arm overhead on the concave side | Hold 20 to 30 s, 3 to 5 times |
| Standing or sitting side-bend away from the concavity | Hold 15 to 20 s, 3 times | |
| Hip flexor, hamstring, pectoral stretches | Hold 30 s, 2 to 3 times | |
| 3. Strengthen convex side and trunk | Side-lying trunk lift, convex side up | 8 to 12 reps, 2 to 3 sets |
| Modified side plank on the convex side | Hold 10 to 30 s | |
| Prone back extension, bird-dog | 8 to 12 reps | |
| Curl-up, transversus abdominis drawing in | 10 reps, 2 sets | |
| Bridging, clamshell | 10 to 15 reps | |
| 4. Scapular and shoulder girdle | Rows, prone Y/T/W, wall angels | 10 reps, 2 sets |
| 5. Scoliosis-specific (Schroth) | Elongation, derotation, rotational breathing into the concave side, then hold | 5 to 10 breaths per position |
| 6. Posture and balance | Mirror self-correction, wall standing, single-leg stance | Daily, during activities |
Make a one-page scoliosis exercise PDF
~/posture-ppt/scoliosis_sheet.py
import json, subprocess, base64, io
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor, white
from reportlab.platypus import Paragraph, Table, TableStyle
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.utils import ImageReader
URL = "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_451a1ba79f1a73251ab88e6aa387aa52f46b49f944c6d3deb0d667701aeda723.jpg"
res = json.loads(subprocess.check_output(["python", "/tmp/skills/shared/scripts/fetch_images.py", URL]))
img = None
if res and res[0]["base64"]:
img = ImageReader(io.BytesIO(base64.b64decode(res[0]["base64"].split(",", 1)[1])))
NAVY = HexColor("#0B3C49"); TEAL = HexColor("#1F7A8C"); CORAL = HexColor("#E07A5F")
SAND = HexColor("#F6F2EA"); LT = HexColor("#DDEEF1"); DARK = HexColor("#222B31")
W, H = A4
M = 22; GAP = 10
CW = (W - 2 * M - GAP) / 2
out = "/tmp/workspace/posture-ppt/output/Scoliosis_Exercise_Sheet.pdf"
c = canvas.Canvas(out, pagesize=A4)
c.setTitle("Scoliosis Exercise Sheet - Exercise Therapy BPT")
body = ParagraphStyle("b", fontName="Helvetica", fontSize=8.2, leading=10, textColor=DARK)
bul = ParagraphStyle("bul", parent=body, spaceAfter=1.2)
cell = ParagraphStyle("cell", parent=body, fontSize=7.5, leading=8.9)
cellh = ParagraphStyle("cellh", parent=cell, fontName="Helvetica-Bold", textColor=white)
cellb = ParagraphStyle("cellb", parent=cell, fontName="Helvetica-Bold", textColor=NAVY)
c.setFillColor(SAND); c.rect(0, 0, W, H, fill=1, stroke=0)
c.setFillColor(NAVY); c.rect(0, H - 52, W, 52, fill=1, stroke=0)
c.setFillColor(CORAL); c.rect(0, H - 55, W, 3, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 21); c.drawString(M, H - 34, "SCOLIOSIS EXERCISE SHEET")
c.setFont("Helvetica", 9); c.setFillColor(HexColor("#BFDDE3"))
c.drawRightString(W - M, H - 30, "Exercise Therapy | BPT exam revision")
c.drawRightString(W - M, H - 42, "Sources: Campbell's 15e, PubMed meta-analyses, standard PT teaching")
TOP = H - 64
BOT = 30
def box(x, y, w, title, items, color=TEAL):
ps = [Paragraph(t, bul) for t in items]
inner = w - 12
hts = [p.wrap(inner - 8, 1000)[1] + 1.2 for p in ps]
total = 13 + 3 + sum(hts) + 4
c.setFillColor(white); c.setStrokeColor(HexColor("#D8D2C4")); c.setLineWidth(0.6)
c.roundRect(x, y - total, w, total, 3, fill=1, stroke=1)
c.setFillColor(color); c.roundRect(x, y - 13, w, 13, 3, fill=1, stroke=0)
c.rect(x, y - 13, w, 6, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 8.8); c.drawString(x + 6, y - 9.5, title)
cy = y - 16
for p, h in zip(ps, hts):
p.wrap(inner - 8, 1000)
p.drawOn(c, x + 14, cy - (h - 1.2))
c.setFillColor(CORAL); c.circle(x + 8, cy - 4.5, 1.1, fill=1, stroke=0)
cy -= h
return y - total - 6
def tbl(x, y, w, rows, colw, color=NAVY):
data = [[Paragraph(t, cellh if r == 0 else (cellb if i == 0 else cell)) for i, t in enumerate(row)] for r, row in enumerate(rows)]
tot = sum(colw)
t = Table(data, colWidths=[w * cw / tot for cw in colw])
st = [("BACKGROUND", (0, 0), (-1, 0), color), ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.4, HexColor("#D8D2C4")),
("TOPPADDING", (0, 0), (-1, -1), 2), ("BOTTOMPADDING", (0, 0), (-1, -1), 2),
("LEFTPADDING", (0, 0), (-1, -1), 3), ("RIGHTPADDING", (0, 0), (-1, -1), 3)]
for r in range(1, len(rows)):
st.append(("BACKGROUND", (0, r), (-1, r), white if r % 2 else LT))
t.setStyle(TableStyle(st))
_, h = t.wrap(w, 1000)
t.drawOn(c, x, y - h)
return y - h - 6
def heading(x, y, s):
c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 9); c.drawString(x, y - 9, s)
return y - 14
LX = M; RX = M + CW + GAP
# ---------- LEFT ----------
y = TOP
y = box(LX, y, CW, "1. DEFINITION AND TYPES", [
"<b>Scoliosis</b>: lateral spinal curve with vertebral rotation; 3D deformity; Cobb angle 10 degrees or more.",
"<b>Nonstructural (postural)</b>: flexible, corrects on forward bend or when the cause is removed (leg length difference, spasm, habit).",
"<b>Structural</b>: fixed, rib hump on Adam's test. Idiopathic (most), congenital, neuromuscular.",
"<b>Adolescent idiopathic (AIS)</b>: 10 years to skeletal maturity; commonest type.",
])
y = box(LX, y, CW, "2. AIMS OF EXERCISE", [
"Slow or stop progression, especially in growth.",
"Improve symmetry, trunk rotation (ATR) and posture.",
"Strengthen trunk; improve chest expansion and breathing.",
"Improve pain, function and self-image; support brace wear and post-op recovery.",
], color=CORAL)
y = heading(LX, y, "CURVE SIZE PATHWAY (usual teaching)")
y = tbl(LX, y, CW, [
["Cobb angle", "Approach"],
["Under about 20 to 25 deg", "Observation + exercise + education"],
["About 25 to 40 deg, growing", "Brace + exercise"],
["Above about 40 to 50 deg", "Surgical referral"],
], [1.3, 2.2])
y = box(LX, y, CW, "3. ASSESS FIRST", [
"<b>Adam's forward bend test</b>: rib hump = structural.",
"<b>Scoliometer</b> (angle of trunk rotation), plumb line from C7 to gluteal crease.",
"Shoulder, scapular, pelvic levels; leg length; neurological screen.",
"<b>X-ray</b>: Cobb angle, Risser sign (maturity). Muscle length and strength, vital capacity, SRS-22.",
])
# image + rule box
imgw = 92
if img:
iw, ih = img.getSize(); imgh = imgw * ih / iw
else:
imgh = 0
items = [
"<b>STRETCH the concave side</b>",
"<b>STRENGTHEN the convex side</b>",
"<b>CORRECT in 3D</b>: elongate, derotate, stabilise",
"<b>CARRY OVER</b> to daily activity",
]
ps = [Paragraph(t, bul) for t in items]
tw = CW - 12 - imgw - 6
hts = [p.wrap(tw - 8, 1000)[1] + 1.2 for p in ps]
cap = Paragraph("<i>Schroth correction, historical photo: active self-correction straightens the midline.</i>",
ParagraphStyle("cap", parent=body, fontSize=7, leading=8.4))
_, caph = cap.wrap(CW - 12, 100)
total = 13 + 3 + max(sum(hts), imgh) + 3 + caph + 4
c.setFillColor(white); c.setStrokeColor(HexColor("#D8D2C4")); c.roundRect(LX, y - total, CW, total, 3, fill=1, stroke=1)
c.setFillColor(TEAL); c.roundRect(LX, y - 13, CW, 13, 3, fill=1, stroke=0); c.rect(LX, y - 13, CW, 6, fill=1, stroke=0)
c.setFillColor(white); c.setFont("Helvetica-Bold", 8.8); c.drawString(LX + 6, y - 9.5, "4. THE CORE RULE")
if img:
c.drawImage(img, LX + 6, y - 16 - imgh, imgw, imgh)
cy = y - 20
for p, h in zip(ps, hts):
p.wrap(tw - 8, 1000)
p.drawOn(c, LX + 6 + imgw + 14, cy - (h - 1.2))
c.setFillColor(CORAL); c.circle(LX + 6 + imgw + 8, cy - 4.5, 1.1, fill=1, stroke=0)
cy -= h + 4
cap.drawOn(c, LX + 6, y - total + 4)
y = y - total - 6
left_end = y
# ---------- RIGHT ----------
y = TOP
y = heading(RX, y, "EXERCISE PROGRAMME (typical dose, not fixed)")
y = tbl(RX, y, CW, [
["Step", "Exercise", "Dose"],
["Warm-up", "Cat-camel, pelvic tilt in crook lying", "10 reps"],
["Stretch concave", "Side-lying over roll at concavity, arm overhead", "Hold 20 to 30 s x 3 to 5"],
["", "Side-bend away from concavity (stand or sit)", "Hold 15 to 20 s x 3"],
["", "Hip flexor, hamstring, pectoral stretches", "Hold 30 s x 2 to 3"],
["Strengthen convex + trunk", "Side-lying trunk lift (convex up)", "8 to 12 x 2 to 3 sets"],
["", "Modified side plank (convex side)", "Hold 10 to 30 s"],
["", "Prone back extension, bird-dog", "8 to 12 reps"],
["", "Curl-up, TrA drawing in; bridging, clamshell", "10 to 15 reps"],
["Scapular", "Rows, prone Y/T/W, wall angels", "10 reps x 2"],
["Posture, balance", "Mirror self-correction, wall standing, single-leg stance", "Daily"],
], [1.35, 3.0, 1.55], color=CORAL)
y = box(RX, y, CW, "5. SCHROTH SEQUENCE (SCOLIOSIS-SPECIFIC)", [
"<b>1.</b> Find neutral and identify your curve pattern (3 or 4 curve types).",
"<b>2.</b> <b>Pelvic correction</b>: shift pelvis to level the lumbar spine.",
"<b>3.</b> <b>Elongation</b>: grow tall through the spine.",
"<b>4.</b> <b>Derotation + shoulder/thoracic shift</b> toward the concavity.",
"<b>5.</b> <b>Rotational breathing</b>: breathe into the collapsed concave chest wall; use mirror and props.",
"<b>6.</b> <b>Stabilise</b> the corrected shape to the end of the breath; repeat in standing, sitting, side-lying; then use in daily life.",
"<b>Other methods</b>: SEAS (self-correction + stabilisation), Lyon, Side-Shift, BSPTS.",
], color=TEAL)
y = box(RX, y, CW, "6. EXAMPLE: RIGHT THORACIC CURVE", [
"Convex right, concave left.",
"Stretch the left trunk and chest wall; breathe into the left posterior ribs.",
"Strengthen the right side, thoracic and lumbar extensors.",
"Check and treat any compensatory lumbar curve by the same rule.",
], color=CORAL)
y = box(RX, y, CW, "7. PROGRESSION AND REVIEW", [
"Add hold time, then reps, then resistance, then functional tasks.",
"Supervised sessions several times a week at first; then daily home programme of about 20 to 45 min.",
"Re-check scoliometer every 3 to 6 months; X-ray as advised. Wear brace as prescribed; exercise is in addition.",
])
y = box(RX, y, CW, "8. PRECAUTIONS AND REFERRAL", [
"Avoid forced stretch or manipulation of rigid curves.",
"Refer: rapid progression, neurological signs, severe pain, atypical features (left thoracic curve, early onset).",
"Post-op: follow the surgeon's limits.",
], color=CORAL)
y = box(RX, y, CW, "9. EVIDENCE", [
"2024 network meta-analysis, 17 RCTs (PMID 38726971): scoliosis-specific exercise improved Cobb angle, ATR and quality of life; Schroth + SEAS best for Cobb and ATR.",
"2025 meta-analysis, 9 RCTs (PMID 41175413): benefit for Cobb, ATR, pain, function and self-image.",
"Campbell's 15e: observation and bracing, often with Schroth-based PT, are the main nonoperative methods; older reports found no scientific support for PT alone. Trials are small and vary in quality.",
])
right_end = y
sp = Paragraph("<b>EXAM TIPS:</b> Define, classify, assess (Adam's, scoliometer, Cobb), aims, then <b>stretch concave, strengthen convex</b>, "
"Schroth (elongation, derotation, rotational breathing), bracing and surgery thresholds, precautions, review. "
"Quote both views on evidence: textbooks cautious, recent meta-analyses supportive.",
ParagraphStyle("t", parent=body, textColor=white))
_, th = sp.wrap(W - 2 * M - 12, 100)
bh = th + 8; by = BOT - 4
c.setFillColor(NAVY); c.roundRect(M, by, W - 2 * M, bh, 3, fill=1, stroke=0)
sp.drawOn(c, M + 6, by + 4)
print("left_end", round(left_end, 1), "right_end", round(right_end, 1), "strip top", round(by + bh, 1), "img", bool(img))
c.showPage(); c.save()
cd /tmp/workspace/posture-ppt && python scoliosis_sheet.py && python - <<'E' import pypdfium2 as p d=p.PdfDocument('output/Scoliosis_Exercise_Sheet.pdf') print(len(d)) d[0].render(scale=1.6).to_pil().save('assets/preview2.png') E
ls /tmp/skills/ /tmp/skills/shared 2>&1 | head; ls -la /tmp/workspace/posture-ppt /tmp/workspace/posture-ppt/output 2>&1 | head -20; cd /tmp/workspace/posture-ppt && curl -sL -m 60 -o assets/schroth.jpg "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_451a1ba79f1a73251ab88e6aa387aa52f46b49f944c6d3deb0d667701aeda723.jpg"; python -c "from PIL import Image; im=Image.open('assets/schroth.jpg'); print(im.size)"
cd /tmp/workspace/posture-ppt && python - <<'E' s=open('scoliosis_sheet.py').read() start=s.index('URL = ') end=s.index('NAVY = ') s=s[:start]+'img = ImageReader("/tmp/workspace/posture-ppt/assets/schroth.jpg")\n\n'+s[end:] s=s.replace('import json, subprocess, base64, io\n','') open('scoliosis_sheet.py','w').write(s) E python scoliosis_sheet.py && python - <<'E' import pypdfium2 as p d=p.PdfDocument('/tmp/workspace/posture-ppt/output/Scoliosis_Exercise_Sheet.pdf') print(len(d)) d[0].render(scale=1.6).to_pil().save('/tmp/workspace/posture-ppt/assets/preview2.png') E
cd /tmp/workspace/posture-ppt && python - <<'E' s=open('scoliosis_sheet.py').read() a=s.index('# image + rule box') b=s.index('left_end = y') new='''y = box(LX, y, CW, "4. THE CORE RULE", [ "<b>STRETCH</b> the concave side (shortened, tight).", "<b>STRENGTHEN</b> the convex side (stretched, weak).", "<b>CORRECT in 3D</b>: elongate, derotate, stabilise.", "<b>CARRY OVER</b> the corrected posture into daily activity.", "Exercise supports, and does not replace, bracing or surgery when those are indicated.", ]) y = box(LX, y, CW, "5. BREATHING AND CHEST WALL", [ "Concave side ribs are crowded and the chest wall is restricted; the convex side is prominent (rib hump).", "Use <b>rotational breathing</b>: direct the breath into the collapsed concave side while holding the correction.", "Add deep diaphragmatic breathing and chest expansion work to maintain vital capacity, especially in large thoracic curves.", ], color=CORAL) ''' s=s[:a]+new+s[b:] s=s.replace('"5. SCHROTH SEQUENCE','"6. SCHROTH SEQUENCE').replace('"6. EXAMPLE','"7. EXAMPLE').replace('"7. PROGRESSION','"8. PROGRESSION').replace('"8. PRECAUTIONS','"9. PRECAUTIONS').replace('"9. EVIDENCE','"10. EVIDENCE') open('scoliosis_sheet.py','w').write(s) E python scoliosis_sheet.py && python - <<'E' import pypdfium2 as p d=p.PdfDocument('/tmp/workspace/posture-ppt/output/Scoliosis_Exercise_Sheet.pdf') print(len(d)) d[0].render(scale=1.6).to_pil().save('/tmp/workspace/posture-ppt/assets/preview2.png') E
Scoliosis Exercise Sheet
PDF Document · PDF
Make a one-page scoliosis exercise PDF
ls -la /tmp/workspace/posture-ppt/output/ && python -c " from pypdf import PdfReader r=PdfReader('/tmp/workspace/posture-ppt/output/Scoliosis_Exercise_Sheet.pdf'); print(len(r.pages))"
Scoliosis Exercise Sheet
PDF Document · PDF