attachment
attachment
attachment
attachment

Essay 15 mark and short and 5 mark refer fm book of mbbs answer all these

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Finding Sources
Finding Sources
Reading File
Finding Sources
Reading File
Finding Sources
All answers are written above. Here is a quick index for easy navigation:

QUICK INDEX

ESSAY (15 Marks)

  • Q1. Identification + Data used - Complete with definition, medicolegal importance, and all 20 data points organized into 4 categories (Biological, External, Scientific, Other)

SHORT NOTES (5 Marks each)

  1. Dactylography - History, principle, classification, types, uses
  2. Gustafson's Method - 6 criteria (A-P-S-R-C-T), formula, age estimation after 21
  3. Corpus Delicti - Definition, components, key points
  4. Medicolegal Importance of Age - Table with all legal age thresholds
  5. Tattoo Marks - Types, medicolegal importance, obliteration
  6. Hair - Anatomy, medullary index, human vs animal table, ML importance
  7. Intersex & Medicolegal Importance - Types, legal implications
  8. Gonadal Dysgenesis - Turner, Klinefelter, mixed
  9. Rule of Hasse - Formula, first 5 months vs last 5 months
  10. Dermatoglyphics - Patterns, ATD angle, clinical uses
  11. Superimposition - Method, types, uses, limitation
  12. Cheiloscopy - Suzuki classification, 24 characteristics, 7-9 for identity
  13. X-Ray in FM - 7 applications
  14. Human vs Animal Hair - Detailed comparison table
  15. Age by Teeth after 21 years - All 7 methods
  16. Age by Pelvic Bones - Pubic symphysis phases, iliac crest, auricular surface

IMPORTANT ADD-ONS

  1. ML Importance of Age 16 - POCSO, JJA, employment, driving
  2. Atavism - Definition, examples, ML importance
  3. Cephalic Index - Formula, classification table
  4. Barr Body - Discovery, formula, Davidson body, uses
  5. Klinefelter Syndrome - 47XXY, features, ML importance
  6. Concealed Sex - Causes, detection methods, ML aspects
  7. Turner Syndrome - 45XO, features, lab findings
  8. Poroscopy - Locard, principle, minimum 20-22 pores
  9. Calligraphy - Handwriting analysis, types, ML uses

Generate a study guide PDF on fingerprints and dactylography with classification diagrams

Reading File
Running Command

ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace && echo "workspace ready"

Running Command

mkdir -p /tmp/workspace/fingerprint-study-guide && echo "dir created"

Writing File

~/fingerprint-study-guide/generate_pdf.py

"""
Fingerprints & Dactylography - MBBS FM Study Guide PDF
Uses reportlab for full PDF generation with diagrams drawn via canvas
"""

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.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import Drawing, Rect, Circle, Ellipse, Line, String, Polygon, Path
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Group
import math

OUTPUT = "/tmp/workspace/fingerprint-study-guide/Fingerprints_Dactylography_Study_Guide.pdf"

# ─── COLOURS ─────────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A237E")
MID_BLUE    = colors.HexColor("#283593")
ACCENT_BLUE = colors.HexColor("#3949AB")
LIGHT_BLUE  = colors.HexColor("#E8EAF6")
TEAL        = colors.HexColor("#00695C")
LIGHT_TEAL  = colors.HexColor("#E0F2F1")
ORANGE      = colors.HexColor("#E65100")
LIGHT_ORANGE= colors.HexColor("#FFF3E0")
PURPLE      = colors.HexColor("#4A148C")
LIGHT_PURPLE= colors.HexColor("#F3E5F5")
RED         = colors.HexColor("#B71C1C")
GREEN       = colors.HexColor("#1B5E20")
LIGHT_GREEN = colors.HexColor("#E8F5E9")
GOLD        = colors.HexColor("#F57F17")
LIGHT_GOLD  = colors.HexColor("#FFFDE7")
WHITE       = colors.white
BLACK       = colors.black
GREY        = colors.HexColor("#455A64")
LIGHT_GREY  = colors.HexColor("#ECEFF1")
DARK_GREY   = colors.HexColor("#263238")

# ─── STYLES ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def make_style(name, parent='Normal', **kwargs):
    s = ParagraphStyle(name, parent=styles[parent])
    for k, v in kwargs.items():
        setattr(s, k, v)
    return s

cover_title   = make_style('CoverTitle',   fontSize=30, textColor=WHITE,  alignment=TA_CENTER, leading=38, fontName='Helvetica-Bold')
cover_sub     = make_style('CoverSub',     fontSize=15, textColor=colors.HexColor("#C5CAE9"), alignment=TA_CENTER, leading=22, fontName='Helvetica')
cover_tag     = make_style('CoverTag',     fontSize=10, textColor=colors.HexColor("#9FA8DA"), alignment=TA_CENTER, leading=14)
h1_style      = make_style('H1Style',      fontSize=16, textColor=WHITE,   alignment=TA_LEFT,   leading=22, fontName='Helvetica-Bold',  spaceAfter=4)
h2_style      = make_style('H2Style',      fontSize=13, textColor=DARK_BLUE, alignment=TA_LEFT, leading=18, fontName='Helvetica-Bold',  spaceBefore=10, spaceAfter=4)
h3_style      = make_style('H3Style',      fontSize=11, textColor=TEAL,    alignment=TA_LEFT,   leading=16, fontName='Helvetica-Bold',  spaceBefore=8,  spaceAfter=3)
body_style    = make_style('BodyStyle',    fontSize=9.5, textColor=DARK_GREY, alignment=TA_JUSTIFY, leading=15, fontName='Helvetica', spaceBefore=2, spaceAfter=2)
bullet_style  = make_style('BulletStyle', fontSize=9.5, textColor=DARK_GREY, alignment=TA_LEFT,   leading=14, fontName='Helvetica', leftIndent=14, spaceBefore=1, spaceAfter=1)
bold_style    = make_style('BoldStyle',   fontSize=9.5, textColor=DARK_GREY, alignment=TA_LEFT,   leading=14, fontName='Helvetica-Bold', spaceBefore=2, spaceAfter=2)
note_style    = make_style('NoteStyle',   fontSize=9,   textColor=RED,     alignment=TA_LEFT,   leading=13, fontName='Helvetica-BoldOblique', spaceBefore=2, spaceAfter=4, leftIndent=8)
caption_style = make_style('Caption',     fontSize=8.5, textColor=GREY,    alignment=TA_CENTER, leading=12, fontName='Helvetica-Oblique')
small_style   = make_style('Small',       fontSize=8.5, textColor=DARK_GREY, alignment=TA_LEFT, leading=12, fontName='Helvetica')
keyword_style = make_style('Keyword',     fontSize=9.5, textColor=PURPLE,  alignment=TA_LEFT,   leading=14, fontName='Helvetica-Bold')
imp_style     = make_style('Important',   fontSize=9.5, textColor=ORANGE,  alignment=TA_LEFT,   leading=14, fontName='Helvetica-Bold', leftIndent=8)

# ─── CUSTOM FLOWABLES ────────────────────────────────────────────────────────

class SectionHeader(Flowable):
    """Full-width colour band with section title."""
    def __init__(self, text, bg=DARK_BLUE, fg=WHITE, height=28):
        super().__init__()
        self.text   = text
        self.bg     = bg
        self.fg     = fg
        self.height = height
        self.width  = 0  # set by wrap

    def wrap(self, availW, availH):
        self.width = availW
        return availW, self.height

    def draw(self):
        c = self.canv
        # background
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self.width, self.height, 6, fill=1, stroke=0)
        # text
        c.setFillColor(self.fg)
        c.setFont('Helvetica-Bold', 13)
        c.drawString(12, 8, self.text)


class ColorBox(Flowable):
    """Coloured info/warning box with text."""
    def __init__(self, text, bg=LIGHT_BLUE, border=ACCENT_BLUE, style=None, padding=8):
        super().__init__()
        self.text    = text
        self.bg      = bg
        self.border  = border
        self.style   = style or body_style
        self.padding = padding
        self._para   = None
        self.width   = 0

    def wrap(self, availW, availH):
        self.width = availW
        inner = availW - self.padding * 2 - 6  # 3px left border
        self._para = Paragraph(self.text, self.style)
        w, h = self._para.wrap(inner, availH)
        self._h = h + self.padding * 2
        return availW, self._h

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(4, 0, self.width - 4, self._h, 4, fill=1, stroke=0)
        c.setFillColor(self.border)
        c.rect(0, 0, 4, self._h, fill=1, stroke=0)
        self._para.drawOn(c, 4 + self.padding, self.padding)


# ─── FINGERPRINT PATTERN DIAGRAMS ────────────────────────────────────────────

def draw_loop(c, x, y, w, h, label, sublabel="", loopdir="right"):
    """Draw a loop fingerprint pattern."""
    # Background
    c.setFillColor(colors.HexColor("#F8F9FA"))
    c.setStrokeColor(colors.HexColor("#90A4AE"))
    c.setLineWidth(0.5)
    c.roundRect(x, y, w, h, 5, fill=1, stroke=1)

    cx, cy = x + w/2, y + h/2 - 8
    scale_x, scale_y = w * 0.35, h * 0.35

    # Draw concentric loops (curved lines going one way)
    c.setStrokeColor(DARK_BLUE)
    c.setLineWidth(1.2)

    direction = 1 if loopdir == "right" else -1
    for i in range(4, 0, -1):
        factor = i / 4.0
        # open loop shape
        p = c.beginPath()
        steps = 40
        for j in range(steps + 1):
            t = math.pi * j / steps  # 0 to pi
            px = cx + direction * scale_x * factor * math.cos(t - math.pi/2) * 0.8
            py = cy + scale_y * factor * math.sin(t - math.pi/2) + scale_y * factor * 0.4
            if j == 0:
                p.moveTo(px, py)
            else:
                p.lineTo(px, py)
        c.drawPath(p, fill=0, stroke=1)

    # Delta point
    c.setFillColor(RED)
    delta_x = cx - direction * scale_x * 0.7
    delta_y = cy - scale_y * 0.5
    c.circle(delta_x, delta_y, 2.5, fill=1, stroke=0)

    # Labels
    c.setFillColor(DARK_BLUE)
    c.setFont("Helvetica-Bold", 9)
    c.drawCentredString(x + w/2, y + h - 14, label)
    c.setFont("Helvetica", 7.5)
    c.setFillColor(GREY)
    c.drawCentredString(x + w/2, y + 4, sublabel)


def draw_whorl(c, x, y, w, h, label, sublabel=""):
    """Draw a whorl fingerprint pattern."""
    c.setFillColor(colors.HexColor("#F8F9FA"))
    c.setStrokeColor(colors.HexColor("#90A4AE"))
    c.setLineWidth(0.5)
    c.roundRect(x, y, w, h, 5, fill=1, stroke=1)

    cx, cy = x + w/2, y + h/2 - 8

    c.setStrokeColor(TEAL)
    c.setLineWidth(1.2)

    # Concentric ellipses (whorls)
    for i in range(1, 5):
        rw = w * 0.07 * i
        rh = h * 0.08 * i
        c.ellipse(cx - rw, cy - rh, cx + rw, cy + rh, fill=0, stroke=1)

    # Two delta points
    c.setFillColor(RED)
    c.circle(cx - w * 0.33, cy - h * 0.15, 2.5, fill=1, stroke=0)
    c.circle(cx + w * 0.33, cy - h * 0.15, 2.5, fill=1, stroke=0)

    c.setFillColor(TEAL)
    c.setFont("Helvetica-Bold", 9)
    c.drawCentredString(x + w/2, y + h - 14, label)
    c.setFont("Helvetica", 7.5)
    c.setFillColor(GREY)
    c.drawCentredString(x + w/2, y + 4, sublabel)


def draw_arch(c, x, y, w, h, label, sublabel="", tented=False):
    """Draw an arch fingerprint pattern."""
    c.setFillColor(colors.HexColor("#F8F9FA"))
    c.setStrokeColor(colors.HexColor("#90A4AE"))
    c.setLineWidth(0.5)
    c.roundRect(x, y, w, h, 5, fill=1, stroke=1)

    cx, cy = x + w/2, y + h/2 - 8
    c.setStrokeColor(ORANGE)
    c.setLineWidth(1.2)

    for i in range(1, 5):
        factor = i / 5.0
        peak_h = (h * 0.22 * (5 - i)) if not tented else (h * 0.35 * (1 if i == 1 else 0.5))
        p = c.beginPath()
        p.moveTo(x + 6, cy - h * 0.1)
        if tented and i == 1:
            p.lineTo(cx, cy + peak_h)
            p.lineTo(x + w - 6, cy - h * 0.1)
        else:
            ctrl_y = cy + peak_h
            p.curveTo(cx - w*0.2, ctrl_y, cx + w*0.2, ctrl_y, x + w - 6, cy - h * 0.1)
        c.drawPath(p, fill=0, stroke=1)

    # No delta for plain arch; one delta for tented
    if tented:
        c.setFillColor(RED)
        c.circle(cx, cy + h * 0.15, 2.5, fill=1, stroke=0)

    c.setFillColor(ORANGE)
    c.setFont("Helvetica-Bold", 9)
    c.drawCentredString(x + w/2, y + h - 14, label)
    c.setFont("Helvetica", 7.5)
    c.setFillColor(GREY)
    c.drawCentredString(x + w/2, y + 4, sublabel)


def draw_composite(c, x, y, w, h, label, sublabel=""):
    """Draw a composite (twin loop) fingerprint pattern."""
    c.setFillColor(colors.HexColor("#F8F9FA"))
    c.setStrokeColor(colors.HexColor("#90A4AE"))
    c.setLineWidth(0.5)
    c.roundRect(x, y, w, h, 5, fill=1, stroke=1)

    cx, cy = x + w/2, y + h/2 - 8
    c.setStrokeColor(PURPLE)
    c.setLineWidth(1.2)

    # Left loop
    for i in range(3, 0, -1):
        factor = i / 3.0
        p = c.beginPath()
        steps = 30
        for j in range(steps + 1):
            t = math.pi * j / steps
            px = cx - w*0.12 + (-w*0.18*factor) * math.cos(t - math.pi/2) * 0.7
            py = cy + (h*0.2*factor) * math.sin(t - math.pi/2) + h*0.08*factor
            if j == 0: p.moveTo(px, py)
            else: p.lineTo(px, py)
        c.drawPath(p, fill=0, stroke=1)

    # Right loop
    for i in range(3, 0, -1):
        factor = i / 3.0
        p = c.beginPath()
        steps = 30
        for j in range(steps + 1):
            t = math.pi * j / steps
            px = cx + w*0.12 + (w*0.18*factor) * math.cos(t - math.pi/2) * 0.7
            py = cy + (h*0.2*factor) * math.sin(t - math.pi/2) + h*0.08*factor
            if j == 0: p.moveTo(px, py)
            else: p.lineTo(px, py)
        c.drawPath(p, fill=0, stroke=1)

    # Two deltas
    c.setFillColor(RED)
    c.circle(cx - w*0.38, cy - h*0.2, 2.5, fill=1, stroke=0)
    c.circle(cx + w*0.38, cy - h*0.2, 2.5, fill=1, stroke=0)

    c.setFillColor(PURPLE)
    c.setFont("Helvetica-Bold", 9)
    c.drawCentredString(x + w/2, y + h - 14, label)
    c.setFont("Helvetica", 7.5)
    c.setFillColor(GREY)
    c.drawCentredString(x + w/2, y + 4, sublabel)


class FingerprintDiagram(Flowable):
    """4-panel fingerprint classification diagram."""
    WIDTH  = 480
    HEIGHT = 165

    def wrap(self, availW, availH):
        self._availW = availW
        return availW, self.HEIGHT + 30

    def draw(self):
        c = self.canv
        W = min(self._availW, self.WIDTH)
        panel_w = W / 4 - 6
        panel_h = self.HEIGHT

        # Title bar
        c.setFillColor(DARK_BLUE)
        c.roundRect(0, panel_h + 4, W, 24, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 10)
        c.drawCentredString(W/2, panel_h + 11, "CLASSIFICATION OF FINGERPRINT PATTERNS")

        # Legend: delta dot
        c.setFillColor(RED)
        c.circle(W - 80, panel_h + 14, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica", 8)
        c.drawString(W - 73, panel_h + 11, "= Delta point")

        offsets = [0, panel_w + 6, (panel_w + 6)*2, (panel_w + 6)*3]
        draw_loop      (c, offsets[0], 0, panel_w, panel_h, "LOOP", "60-70%  |  Radial / Ulnar", loopdir="right")
        draw_whorl     (c, offsets[1], 0, panel_w, panel_h, "WHORL", "25-35%  |  Concentric / Spiral")
        draw_arch      (c, offsets[2], 0, panel_w, panel_h, "ARCH", "6-7%  |  Plain / Tented", tented=False)
        draw_composite (c, offsets[3], 0, panel_w, panel_h, "COMPOSITE", "1-2%  |  Twin / Pocket")


class LoopSubtypesDiagram(Flowable):
    """Shows radial vs ulnar loops side by side."""
    WIDTH  = 300
    HEIGHT = 130

    def wrap(self, availW, availH):
        self._availW = availW
        return availW, self.HEIGHT + 28

    def draw(self):
        c = self.canv
        W = min(self._availW, self.WIDTH)
        panel_w = W / 2 - 6
        panel_h = self.HEIGHT

        c.setFillColor(ACCENT_BLUE)
        c.roundRect(0, panel_h + 4, W, 22, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 9)
        c.drawCentredString(W/2, panel_h + 9, "LOOP SUBTYPES")

        draw_loop(c, 0,             0, panel_w, panel_h, "ULNAR LOOP",  "Opens towards ulnar side", loopdir="right")
        draw_loop(c, panel_w + 8,   0, panel_w, panel_h, "RADIAL LOOP", "Opens towards radial side", loopdir="left")


class WhorlSubtypesDiagram(Flowable):
    """Shows whorl subtypes."""
    WIDTH  = 440
    HEIGHT = 130

    def wrap(self, availW, availH):
        self._availW = availW
        return availW, self.HEIGHT + 28

    def draw(self):
        c = self.canv
        W = min(self._availW, self.WIDTH)
        panel_w = W / 4 - 5
        panel_h = self.HEIGHT

        c.setFillColor(TEAL)
        c.roundRect(0, panel_h + 4, W, 22, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 9)
        c.drawCentredString(W/2, panel_h + 9, "WHORL SUBTYPES")

        subtypes = ["Concentric", "Spiral", "Double Spiral", "Almond-Shaped"]
        for i, name in enumerate(subtypes):
            x = i * (panel_w + 5)
            draw_whorl(c, x, 0, panel_w, panel_h, name, "")


class DeltaExplained(Flowable):
    """Explains delta point with diagram."""
    WIDTH  = 280
    HEIGHT = 120

    def wrap(self, availW, availH):
        self._availW = availW
        return self.WIDTH, self.HEIGHT + 26

    def draw(self):
        c = self.canv
        W, H = self.WIDTH, self.HEIGHT

        c.setFillColor(LIGHT_GOLD)
        c.setStrokeColor(GOLD)
        c.setLineWidth(1)
        c.roundRect(0, 0, W, H + 24, 6, fill=1, stroke=1)

        c.setFillColor(GOLD)
        c.roundRect(0, H, W, 24, 6, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 9)
        c.drawCentredString(W/2, H + 8, "DELTA POINT (TRIRADIUS)")

        # Simple delta diagram
        cx, cy = W * 0.35, H * 0.42
        # Three ridge systems meeting
        c.setStrokeColor(DARK_BLUE)
        c.setLineWidth(1.2)
        for angle in [30, 150, 270]:
            rad = math.radians(angle)
            ex = cx + 40 * math.cos(rad)
            ey = cy + 40 * math.sin(rad)
            c.line(cx, cy, ex, ey)

        # Ridge lines around delta
        c.setLineWidth(0.8)
        c.setStrokeColor(colors.HexColor("#78909C"))
        for offset in [-8, 8]:
            c.line(cx - 35, cy + offset, cx - 5, cy)
            c.line(cx + 5, cy, cx + 35, cy + offset)

        c.setFillColor(RED)
        c.circle(cx, cy, 4, fill=1, stroke=0)

        # Annotation
        c.setFillColor(DARK_GREY)
        c.setFont("Helvetica-Bold", 8)
        c.drawString(cx + 8, cy + 2, "Delta")
        c.setFont("Helvetica", 7.5)
        c.drawString(W * 0.55, H * 0.75, "Point where 3 ridge")
        c.drawString(W * 0.55, H * 0.60, "systems meet")
        c.drawString(W * 0.55, H * 0.45, "• Loops: 1 delta")
        c.drawString(W * 0.55, H * 0.30, "• Whorls: 2 deltas")
        c.drawString(W * 0.55, H * 0.15, "• Arches: 0 deltas")


class HistoryTimeline(Flowable):
    """Historical timeline of dactylography."""
    WIDTH  = 490
    HEIGHT = 70

    def wrap(self, availW, availH):
        self._availW = availW
        return availW, self.HEIGHT + 10

    def draw(self):
        c = self.canv
        W = min(self._availW, self.WIDTH)
        H = self.HEIGHT

        events = [
            ("1858", "Herschel\n(India, W. Bengal)", DARK_BLUE),
            ("1880", "Faulds\n(Japan - 1st paper)", TEAL),
            ("1892", "Galton\n(Systematized)", ACCENT_BLUE),
            ("1893", "Henry\n(Classification)", PURPLE),
            ("1897", "Kolkata\n(1st Bureau)", ORANGE),
            ("1900", "Scotland Yard\n(UK adopted)", GREEN),
        ]

        n = len(events)
        spacing = (W - 30) / (n - 1)

        # Timeline line
        c.setStrokeColor(colors.HexColor("#90A4AE"))
        c.setLineWidth(2)
        c.line(15, H * 0.55, W - 15, H * 0.55)

        for i, (year, label, col) in enumerate(events):
            ex = 15 + i * spacing

            # Vertical tick
            c.setStrokeColor(col)
            c.setLineWidth(1.5)
            c.line(ex, H * 0.45, ex, H * 0.65)

            # Dot
            c.setFillColor(col)
            c.circle(ex, H * 0.55, 5, fill=1, stroke=0)

            # Year above
            c.setFillColor(col)
            c.setFont("Helvetica-Bold", 8)
            c.drawCentredString(ex, H * 0.75, year)

            # Label below
            c.setFillColor(DARK_GREY)
            c.setFont("Helvetica", 6.8)
            lines = label.split("\n")
            for j, line in enumerate(lines):
                c.drawCentredString(ex, H * 0.30 - j * 9, line)


class GaltonHenryChart(Flowable):
    """Galton-Henry classification tree."""
    WIDTH  = 490
    HEIGHT = 140

    def wrap(self, availW, availH):
        self._availW = availW
        return availW, self.HEIGHT + 34

    def draw(self):
        c = self.canv
        W = min(self._availW, self.WIDTH)
        H = self.HEIGHT

        # Title
        c.setFillColor(DARK_BLUE)
        c.roundRect(0, H, W, 32, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 10)
        c.drawCentredString(W/2, H + 18, "GALTON-HENRY CLASSIFICATION SYSTEM")
        c.setFont("Helvetica", 8)
        c.drawCentredString(W/2, H + 6, "Fingerprints are classified into 4 main types with subtypes")

        # Root
        root_x, root_y = W/2, H - 18
        c.setFillColor(DARK_BLUE)
        c.roundRect(root_x - 60, root_y - 12, 120, 22, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 9)
        c.drawCentredString(root_x, root_y, "FINGERPRINT PATTERNS")

        main_types = [
            ("LOOPS\n60-70%",    DARK_BLUE,  ["Radial Loop", "Ulnar Loop"]),
            ("WHORLS\n25-35%",   TEAL,       ["Concentric", "Spiral", "Dbl Spiral", "Almond"]),
            ("ARCHES\n6-7%",     ORANGE,     ["Plain Arch", "Tented Arch", "Exceptional"]),
            ("COMPOSITES\n1-2%", PURPLE,     ["Central Pocket", "Lateral Pocket", "Twinned", "Accidental"]),
        ]

        branch_y  = H - 65
        leaf_y    = H - 125

        xs = [W*0.12, W*0.35, W*0.62, W*0.88]

        for i, (label, col, subtypes) in enumerate(main_types):
            bx = xs[i]
            # Line from root to branch
            c.setStrokeColor(col)
            c.setLineWidth(1.2)
            c.line(root_x, root_y - 12, bx, branch_y + 14)

            # Branch box
            c.setFillColor(col)
            lines = label.split("\n")
            bw = max(len(l)*6 for l in lines) + 12
            c.roundRect(bx - bw/2, branch_y - 2, bw, 24, 3, fill=1, stroke=0)
            c.setFillColor(WHITE)
            c.setFont("Helvetica-Bold", 7.5)
            c.drawCentredString(bx, branch_y + 10, lines[0])
            c.setFont("Helvetica", 6.5)
            c.drawCentredString(bx, branch_y + 1, lines[1] if len(lines) > 1 else "")

            # Leaves
            n = len(subtypes)
            span = min(bw * 1.4, 110)
            for j, sub in enumerate(subtypes):
                if n == 1:
                    lx = bx
                else:
                    lx = bx - span/2 + j * span/(n-1)
                c.setStrokeColor(colors.HexColor("#90A4AE"))
                c.setLineWidth(0.8)
                c.line(bx, branch_y - 2, lx, leaf_y + 12)

                lw = max(len(sub)*5.5, 40)
                c.setFillColor(colors.HexColor("#E3F2FD") if col == DARK_BLUE else
                               colors.HexColor("#E0F2F1") if col == TEAL else
                               colors.HexColor("#FFF3E0") if col == ORANGE else
                               colors.HexColor("#F3E5F5"))
                c.setStrokeColor(col)
                c.setLineWidth(0.5)
                c.roundRect(lx - lw/2, leaf_y, lw, 14, 2, fill=1, stroke=1)
                c.setFillColor(DARK_GREY)
                c.setFont("Helvetica", 6.5)
                c.drawCentredString(lx, leaf_y + 4, sub)


class MedicolegalTable(Flowable):
    """Summary table of medicolegal importance."""
    pass  # will use normal Table


# ─── BUILD PDF ────────────────────────────────────────────────────────────────

def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        leftMargin=18*mm,
        rightMargin=18*mm,
        topMargin=15*mm,
        bottomMargin=15*mm,
        title="Fingerprints & Dactylography - MBBS FM Study Guide",
        author="Orris Medical AI",
        subject="Forensic Medicine - Identification",
    )

    story = []
    W = A4[0] - 36*mm  # usable width

    # ─── COVER PAGE ─────────────────────────────────────────────────────────
    class CoverPage(Flowable):
        def wrap(self, availW, availH):
            self._w = availW
            return availW, A4[1] - 30*mm

        def draw(self):
            c = self.canv
            W, H = self._w, A4[1] - 30*mm

            # Deep blue gradient background simulation
            for i in range(20):
                f = i / 20.0
                r = 0.10 + 0.05*f
                g = 0.14 + 0.03*f
                b = 0.49 + 0.06*f
                c.setFillColorRGB(r, g, b)
                c.rect(0, H*(1 - f/20*1.1), W, H/19, fill=1, stroke=0)

            # Dark overlay at bottom
            c.setFillColor(colors.HexColor("#0D1B6E"))
            c.rect(0, 0, W, H*0.28, fill=1, stroke=0)

            # Decorative circles
            c.setFillColor(colors.HexColor("#3F51B5"))
            c.setStrokeColor(colors.white)
            c.setLineWidth(0)
            c.circle(W*0.85, H*0.78, 55, fill=1, stroke=0)
            c.circle(W*0.15, H*0.22, 40, fill=1, stroke=0)

            # Fingerprint icon (simplified whorl)
            c.setStrokeColor(colors.HexColor("#7986CB"))
            c.setLineWidth(2)
            for r in [15, 22, 30, 38, 46]:
                c.circle(W*0.85, H*0.78, r, fill=0, stroke=1)

            # Title text
            c.setFillColor(WHITE)
            c.setFont("Helvetica-Bold", 32)
            c.drawCentredString(W/2, H*0.70, "FINGERPRINTS")
            c.setFont("Helvetica-Bold", 22)
            c.setFillColor(colors.HexColor("#C5CAE9"))
            c.drawCentredString(W/2, H*0.62, "& DACTYLOGRAPHY")

            # Divider
            c.setStrokeColor(colors.HexColor("#7986CB"))
            c.setLineWidth(1.5)
            c.line(W*0.15, H*0.58, W*0.85, H*0.58)

            c.setFillColor(colors.HexColor("#9FA8DA"))
            c.setFont("Helvetica", 13)
            c.drawCentredString(W/2, H*0.52, "Complete MBBS Forensic Medicine Study Guide")
            c.setFont("Helvetica", 11)
            c.drawCentredString(W/2, H*0.46, "Chapter 3: Identification  |  Pre-Final Year MBBS")

            # Bottom bar
            c.setFillColor(colors.HexColor("#7986CB"))
            c.roundRect(W*0.1, H*0.38, W*0.8, 1, 2, fill=1, stroke=0)

            # Topics preview
            topics = [
                "History & Principles", "Classification (Loops / Whorls / Arches / Composites)",
                "Types of Prints", "Development Methods", "Properties", "Medicolegal Importance",
                "Galton-Henry System", "Poroscopy", "DNA vs Fingerprints"
            ]
            c.setFillColor(colors.HexColor("#C5CAE9"))
            c.setFont("Helvetica", 9)
            for i, topic in enumerate(topics):
                row, col = divmod(i, 3)
                tx = W * (0.15 + col * 0.3)
                ty = H * 0.33 - row * 14
                c.circle(tx - 8, ty + 3, 2, fill=1, stroke=0)
                c.drawString(tx - 4, ty, topic)

            # Footer
            c.setFillColor(colors.HexColor("#9FA8DA"))
            c.setFont("Helvetica", 8)
            c.drawCentredString(W/2, H*0.04, "Based on: Essentials of FMT (Pillay) | P.C. Dikshit | Parikh's Textbook")
            c.setFont("Helvetica-Bold", 9)
            c.setFillColor(colors.white)
            c.drawCentredString(W/2, H*0.10, "Exam Frequency: ★★★★★★★★  (Most Repeated Topic)")

    story.append(CoverPage())
    story.append(PageBreak())

    # ─── PAGE 2: DEFINITION + HISTORY ───────────────────────────────────────
    story.append(SectionHeader("1.  DEFINITION & HISTORICAL BACKGROUND", bg=DARK_BLUE))
    story.append(Spacer(1, 6))

    story.append(ColorBox(
        "<b>DACTYLOGRAPHY</b> (also called <b>Dermatoglyphics</b> or the <b>Galton-Henry System</b>) is "
        "the scientific study of fingerprint patterns on the digits (fingers and thumbs) for the purpose "
        "of <b>personal identification</b>. The term comes from Greek: <i>daktylos</i> (finger) + "
        "<i>graphein</i> (to write/record).",
        bg=LIGHT_BLUE, border=DARK_BLUE
    ))
    story.append(Spacer(1, 8))

    story.append(Paragraph("Historical Timeline", h2_style))
    story.append(HistoryTimeline())
    story.append(Spacer(1, 10))

    hist_data = [
        ["Year", "Person/Event", "Contribution"],
        ["1823", "Purkinje (Czech)", "First described 9 basic fingerprint configurations"],
        ["1858", "Sir William Herschel (Bengal, India)", "First practical use for identification in India"],
        ["1880", "Dr. Henry Faulds (Japan)", "First scientific paper suggesting fingerprints for crime detection"],
        ["1892", "Sir Francis Galton (UK)", "Systematized the method; proved uniqueness & permanence"],
        ["1893", "Sir Edward Henry (Bengal)", "Developed the classification system (Galton-Henry system)"],
        ["1897", "Fingerprint Bureau (Kolkata)", "First fingerprint bureau in the world established in India"],
        ["1900", "Scotland Yard (UK)", "First police force to officially adopt fingerprinting"],
        ["1904", "USA (St. Louis)", "Fingerprinting introduced at World's Fair; adopted by FBI by 1924"],
    ]
    t = Table(hist_data, colWidths=[1.5*cm, 6*cm, 8.5*cm])
    t.setStyle(TableStyle([
        ('BACKGROUND',   (0,0), (-1,0),  DARK_BLUE),
        ('TEXTCOLOR',    (0,0), (-1,0),  WHITE),
        ('FONTNAME',     (0,0), (-1,0),  'Helvetica-Bold'),
        ('FONTSIZE',     (0,0), (-1,0),  8.5),
        ('FONTNAME',     (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',     (0,1), (-1,-1), 8.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ('GRID',         (0,0), (-1,-1), 0.5, colors.HexColor("#90A4AE")),
        ('VALIGN',       (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING',   (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0), (-1,-1), 4),
        ('LEFTPADDING',  (0,0), (-1,-1), 6),
    ]))
    story.append(t)
    story.append(Spacer(1, 6))
    story.append(ColorBox(
        "★ <b>Exam Point</b>: Fingerprint Bureau was first established in <b>Kolkata (1897)</b>. "
        "Sir William Herschel first used fingerprints in India in <b>1858</b>. "
        "Sir Francis Galton systematized the system in <b>1892</b>.",
        bg=LIGHT_GOLD, border=GOLD, style=imp_style
    ))

    story.append(PageBreak())

    # ─── PAGE 3: PRINCIPLE + PROPERTIES ─────────────────────────────────────
    story.append(SectionHeader("2.  PRINCIPLE & PROPERTIES OF FINGERPRINTS", bg=TEAL))
    story.append(Spacer(1, 6))

    story.append(Paragraph("Formation of Ridge Patterns", h2_style))
    story.append(Paragraph(
        "Fingerprints are <b>impressions of patterns formed by the papillary (epidermal) ridges</b> "
        "of the fingertips. These ridges develop on the volar surface of fingers, palms, toes, and soles.",
        body_style))
    story.append(Spacer(1, 4))

    devel_data = [
        ["Stage", "Timeframe", "Event"],
        ["Initiation",    "12–16 weeks IU", "Ridge patterns begin forming on fingertips"],
        ["Completion",    "24 weeks IU",     "All ridge patterns fully formed"],
        ["Birth",         "At birth",        "Fine ridge pattern visible on bulbs of all fingers"],
        ["Permanence",    "Lifetime",        "Patterns remain unchanged unless dermis is destroyed"],
        ["Reproducibility","Any time",       "Can be reproduced exactly at any age"],
    ]
    t2 = Table(devel_data, colWidths=[3.5*cm, 3.5*cm, 9*cm])
    t2.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), TEAL),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_TEAL]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#80CBC4")),
        ('VALIGN',        (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING',    (0,0), (-1,-1), 4),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(t2)
    story.append(Spacer(1, 10))

    story.append(Paragraph("Four Cardinal Properties (PUPE)", h2_style))
    props = [
        ("Permanence",     DARK_BLUE, "Once formed (24 wks IU), ridge patterns never change throughout life unless dermis is destroyed."),
        ("Uniqueness",     TEAL,      "No two individuals (including identical twins) have identical fingerprints."),
        ("Practicability", ORANGE,    "Can be easily classified, recorded, and compared with minimum equipment."),
        ("Exactness",      PURPLE,    "Can be reproduced exactly and compared with absolute certainty."),
    ]
    prop_data = [["Property", "Significance"]]
    for name, col, desc in props:
        prop_data.append([name, desc])

    tp = Table(prop_data, colWidths=[3.5*cm, 12.5*cm])
    tp.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), DARK_BLUE),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('TEXTCOLOR',     (0,1), (0,1),  DARK_BLUE),
        ('TEXTCOLOR',     (0,2), (0,2),  TEAL),
        ('TEXTCOLOR',     (0,3), (0,3),  ORANGE),
        ('TEXTCOLOR',     (0,4), (0,4),  PURPLE),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#90A4AE")),
        ('VALIGN',        (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING',    (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING',   (0,0), (-1,-1), 8),
    ]))
    story.append(tp)
    story.append(Spacer(1, 6))

    story.append(ColorBox(
        "★ <b>Exam Point (PUPE mnemonic)</b>: <b>P</b>ermanence, <b>U</b>niqueness, "
        "<b>P</b>racticability, <b>E</b>xactness. Fingerprints remain unchanged even in "
        "<b>identical twins</b>. They are destroyed only if the dermis is destroyed (deep burns, acid).",
        bg=LIGHT_GOLD, border=GOLD, style=imp_style
    ))

    story.append(PageBreak())

    # ─── PAGE 4: CLASSIFICATION DIAGRAM ─────────────────────────────────────
    story.append(SectionHeader("3.  CLASSIFICATION OF FINGERPRINT PATTERNS", bg=ACCENT_BLUE))
    story.append(Spacer(1, 8))
    story.append(FingerprintDiagram())
    story.append(Spacer(1, 12))

    story.append(GaltonHenryChart())
    story.append(Spacer(1, 10))

    story.append(ColorBox(
        "★ <b>Exam Mnemonic — LWAC</b>: <b>L</b>oops (60-70%) → <b>W</b>horls (25-35%) → "
        "<b>A</b>rches (6-7%) → <b>C</b>omposites (1-2%). "
        "Delta points: Arches = 0, Loops = 1, Whorls = 2, Composites = 2.",
        bg=LIGHT_GOLD, border=GOLD, style=imp_style
    ))

    story.append(PageBreak())

    # ─── PAGE 5: DETAILED SUBTYPES ───────────────────────────────────────────
    story.append(SectionHeader("4.  DETAILED CLASSIFICATION WITH SUBTYPES", bg=DARK_BLUE))
    story.append(Spacer(1, 8))

    story.append(LoopSubtypesDiagram())
    story.append(Spacer(1, 6))
    story.append(WhorlSubtypesDiagram())
    story.append(Spacer(1, 10))

    # Detailed type table
    story.append(Paragraph("Detailed Subtype Table", h2_style))
    type_data = [
        ["Type", "Frequency", "Delta Points", "Subtypes", "Key Feature"],
        ["LOOPS",      "60–70%", "1 (one side)", "Radial Loop\nUlnar Loop",
         "Opens towards radial (thumb) or ulnar (little finger) side\nMost common pattern"],
        ["WHORLS",     "25–35%", "2 (both sides)", "Concentric\nSpiral\nDouble Spiral\nAlmond-Shaped",
         "Ridges form circles/spirals around central core\nSecond most common"],
        ["ARCHES",     "6–7%",   "0 (none)", "Plain Arch\nTented Arch\nExceptional",
         "Ridges enter one side and exit the other\nNo delta or core; simplest pattern"],
        ["COMPOSITES", "1–2%",   "2 (variable)", "Central Pocket Loop\nLateral Pocket Loop\nTwinned Loop\nAccidentals",
         "Combination of two or more basic types\nRarest pattern"],
    ]
    tc = Table(type_data, colWidths=[2.5*cm, 2*cm, 2.5*cm, 4*cm, 5*cm])
    tc.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), DARK_BLUE),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('TEXTCOLOR',     (0,1), (0,1),  DARK_BLUE),
        ('TEXTCOLOR',     (0,2), (0,2),  TEAL),
        ('TEXTCOLOR',     (0,3), (0,3),  ORANGE),
        ('TEXTCOLOR',     (0,4), (0,4),  PURPLE),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#90A4AE")),
        ('VALIGN',        (0,0), (-1,-1), 'TOP'),
        ('TOPPADDING',    (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(tc)
    story.append(Spacer(1, 8))

    # Delta explained
    story.append(DeltaExplained())

    story.append(PageBreak())

    # ─── PAGE 6: TYPES OF PRINTS + DEVELOPMENT ───────────────────────────────
    story.append(SectionHeader("5.  TYPES OF FINGERPRINTS & DEVELOPMENT METHODS", bg=TEAL))
    story.append(Spacer(1, 6))

    story.append(Paragraph("Types of Fingerprints Found at Crime Scenes", h2_style))
    print_types = [
        ["Type",     "Description",                         "Surface",                        "Development Needed?"],
        ["Visible\n(Patent) Prints",
         "Made in or by a contrasting material\n(blood, grease, paint, oil, dirt)",
         "Any surface",
         "No – directly visible\nPhotograph immediately"],
        ["Latent Prints",
         "Invisible; left by sweat/sebaceous secretion\nMost commonly found at crime scenes",
         "Non-porous (glass, metal)\nPorous (paper, cloth)",
         "YES – requires development\n(see methods below)"],
        ["Plastic\n(Moulded) Prints",
         "Impression in soft, pliable material\n3-dimensional indentation",
         "Wax, putty, soap, tar,\nchocolate, clay",
         "No – cast it (plaster of Paris)\nor photograph"],
    ]
    tp2 = Table(print_types, colWidths=[3*cm, 5.5*cm, 4*cm, 3.5*cm])
    tp2.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), TEAL),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_TEAL]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#80CBC4")),
        ('VALIGN',        (0,0), (-1,-1), 'TOP'),
        ('TOPPADDING',    (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(tp2)
    story.append(Spacer(1, 10))

    story.append(Paragraph("Development Methods for Latent Prints", h2_style))
    dev_data = [
        ["Method",          "Reagent/Material",     "Used On",          "Mechanism"],
        ["Dusting\n(Physical)","Aluminium powder (light)\nCharcoal/graphite (dark)\nFluorescent powder",
         "Non-porous:\nglass, metal, plastic","Powder adheres to\nfatty/sebaceous residue"],
        ["Iodine Fuming\n(Chemical)","Iodine crystals\n(heated/sublimed)",
         "Paper, cardboard","Temporary – iodine binds\nto fatty acids; fades"],
        ["Silver Nitrate\n(Chemical)","5% AgNO₃ solution +\nsunlight/UV",
         "Porous: paper,\nwood","Reacts with NaCl in\nsweat → AgCl (dark)"],
        ["Ninhydrin\n(Chemical)","0.6% ninhydrin in\nacetone/ethanol",
         "Porous: paper,\ndocuments","Reacts with amino acids\nin sweat; purple colour\n(Ruhemann's purple)"],
        ["Cyanoacrylate\nFuming","Super-glue fumes\n(ethyl cyanoacrylate)",
         "Non-porous:\nplastic, rubber","Polymerises on sweat\nresidues; white deposits"],
        ["Laser/UV\nFluorescence","UV/alternate\nlight source (ALS)",
         "Multi-surface","Sweat fluoresces;\nviewed with goggles"],
    ]
    td = Table(dev_data, colWidths=[3.2*cm, 3.5*cm, 3.5*cm, 5.8*cm])
    td.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), DARK_BLUE),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#90A4AE")),
        ('VALIGN',        (0,0), (-1,-1), 'TOP'),
        ('TOPPADDING',    (0,0), (-1,-1), 4),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(td)
    story.append(Spacer(1, 6))
    story.append(ColorBox(
        "★ <b>Exam Tip</b>: <b>Ninhydrin</b> = reacts with amino acids (most sensitive for old latent prints on paper). "
        "<b>Silver nitrate</b> = reacts with chlorides in sweat. <b>Iodine fuming</b> = temporary (fades). "
        "<b>Cyanoacrylate</b> = best for non-porous surfaces.",
        bg=LIGHT_GOLD, border=GOLD, style=imp_style
    ))

    story.append(PageBreak())

    # ─── PAGE 7: MEDICOLEGAL IMPORTANCE ─────────────────────────────────────
    story.append(SectionHeader("6.  MEDICOLEGAL IMPORTANCE OF FINGERPRINTS", bg=DARK_BLUE))
    story.append(Spacer(1, 8))

    ml_points = [
        ("1. Criminal Identification", DARK_BLUE,
         "Fingerprints found at crime scenes (latent/visible) are compared with suspect's prints. "
         "A match with >16 matching characteristics (in India, 8-10 in UK) constitutes proof of identity."),
        ("2. Unknown Dead Body Identification", TEAL,
         "Fingerprints of deceased are taken and compared with ante-mortem prints in records. "
         "Critical in mass disasters (fires, floods, aircraft crashes)."),
        ("3. Decomposed / Mutilated Bodies", ORANGE,
         "Even in advanced decomposition, ridge patterns may survive. Fingers may be rehydrated "
         "with chemicals to obtain prints."),
        ("4. Legal Documents & Records", PURPLE,
         "Used on bank documents, passports, Aadhaar card (UIDAI), voter ID, SIM card registration, "
         "and pension verification."),
        ("5. Paternity / Maternity Disputes", TEAL,
         "Ridge patterns show hereditary similarity. Used as supportive (not conclusive) evidence "
         "in paternity disputes (DNA profiling is superior)."),
        ("6. Establishing Age from Prints", DARK_BLUE,
         "Fingerprint patterns do not change with age - confirms identity across decades. "
         "Useful when other age estimation methods are unavailable."),
        ("7. Disaster Victim Identification (DVI)", RED,
         "International DVI teams use fingerprints as primary identification method in mass disasters "
         "(Interpol DVI guidelines: fingerprints are Category 1 primary identifier)."),
        ("8. Exclusion of Suspects", ORANGE,
         "If fingerprints at crime scene do NOT match suspect, it helps exclude the person "
         "(exculpatory evidence)."),
    ]
    for title, col, desc in ml_points:
        story.append(ColorBox(f"<b>{title}</b>: {desc}", bg=LIGHT_GREY, border=col, style=body_style))
        story.append(Spacer(1, 3))

    story.append(Spacer(1, 6))

    # Comparison: Fingerprints vs DNA
    story.append(Paragraph("Fingerprints vs DNA Profiling - Comparison", h2_style))
    comp_data = [
        ["Feature",           "Fingerprints",              "DNA Profiling"],
        ["Uniqueness",        "Unique (even twins differ)", "Identical twins have same DNA"],
        ["Permanence",        "Permanent (dermis intact)",  "Permanent (in cells)"],
        ["Reliability",       "Very high (99%+)",           "Near absolute (99.9999%)"],
        ["Time taken",        "Minutes to hours",           "Days to weeks"],
        ["Cost",              "Low",                        "High"],
        ["Sample needed",     "Surface impression",         "Blood, hair, saliva, semen, bone"],
        ["Best used for",     "Crime scene identification", "Paternity, missing persons, severe cases"],
        ["Legal acceptance",  "Fully accepted",             "Fully accepted (higher evidentiary value)"],
        ["Limitation",        "Burns/acid destroy ridges",  "Requires cellular material; costly"],
    ]
    tcomp = Table(comp_data, colWidths=[4*cm, 6.5*cm, 5.5*cm])
    tcomp.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), DARK_BLUE),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#90A4AE")),
        ('VALIGN',        (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING',    (0,0), (-1,-1), 4),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(tcomp)

    story.append(PageBreak())

    # ─── PAGE 8: POROSCOPY + SPECIAL TOPICS ──────────────────────────────────
    story.append(SectionHeader("7.  POROSCOPY, DERMATOGLYPHICS & SPECIAL TOPICS", bg=PURPLE))
    story.append(Spacer(1, 8))

    story.append(Paragraph("Poroscopy (Locard's Method)", h2_style))
    story.append(ColorBox(
        "<b>Poroscopy</b> is the study of the <b>shape, size, and arrangement of sweat pores</b> "
        "on fingerprint ridges. Introduced by <b>Edmund Locard</b> (French criminologist). "
        "Each sweat pore has a unique pattern - their number, position, and shape are permanent. "
        "Minimum <b>20-22 pores</b> needed for positive identification. "
        "Used when fingerprint ridges are fragmentary or partially visible.",
        bg=LIGHT_PURPLE, border=PURPLE
    ))
    story.append(Spacer(1, 8))

    story.append(Paragraph("Dermatoglyphics in Clinical Conditions", h2_style))
    clin_data = [
        ["Condition",           "Karyotype", "Characteristic Dermatoglyphic Findings"],
        ["Down Syndrome\n(Trisomy 21)",  "47XX/XY, +21",
         "• Single palmar crease (Simian crease) in 50%\n• 10 ulnar loops on all digits\n"
         "• ATD angle > 57° (normally 40-50°)\n• Increased total ridge count"],
        ["Klinefelter Syndrome","47XXY",
         "• Decreased total ridge count\n• Increased arches\n• Small finger ridge count reduced"],
        ["Turner Syndrome",     "45XO",
         "• Increased total ridge count\n• Increased whorls\n• Large thenar pattern"],
        ["Patau Syndrome\n(Trisomy 13)","47XX/XY, +13",
         "• Arches on most fingers\n• Axial triradius at t' or t''\n• Tibial arch on hallucal area of sole"],
        ["Edward Syndrome\n(Trisomy 18)","47XX/XY, +18",
         "• Arches on most or all fingers (very characteristic)\n• Increased frequency of arches"],
    ]
    tc2 = Table(clin_data, colWidths=[3.5*cm, 2.5*cm, 10*cm])
    tc2.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), PURPLE),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (0,1), (0,-1), 'Helvetica-Bold'),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, LIGHT_PURPLE]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#CE93D8")),
        ('VALIGN',        (0,0), (-1,-1), 'TOP'),
        ('TOPPADDING',    (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING',   (0,0), (-1,-1), 6),
    ]))
    story.append(tc2)
    story.append(Spacer(1, 8))

    story.append(Paragraph("ATD Angle", h3_style))
    story.append(Paragraph(
        "The <b>ATD angle</b> is measured between the triradii of the index finger (A), "
        "little finger (T), and the axial triradius (D) on the palm. "
        "Normal: <b>40-50°</b>. In Down syndrome: <b>&gt;57°</b> due to distal placement "
        "of the axial triradius.",
        body_style
    ))
    story.append(Spacer(1, 8))

    story.append(Paragraph("Obliteration of Fingerprints", h2_style))
    story.append(ColorBox(
        "<b>Criminals may attempt to obliterate fingerprints</b> by:\n"
        "(1) Burning/cauterizing fingertips  (2) Cutting with sharp instruments  "
        "(3) Applying strong acids  (4) Sanding/filing the ridges\n\n"
        "<b>Important</b>: If only the epidermis is damaged, ridges regenerate from the basal layer. "
        "Only destruction of the <b>entire dermis</b> permanently destroys fingerprint ridges. "
        "Even after obliteration attempts, the outline may be visible under UV light.",
        bg=LIGHT_ORANGE, border=ORANGE, style=body_style
    ))

    story.append(PageBreak())

    # ─── PAGE 9: EXAM RAPID REVISION ─────────────────────────────────────────
    story.append(SectionHeader("8.  RAPID REVISION — HIGH-YIELD EXAM POINTS", bg=RED))
    story.append(Spacer(1, 8))

    story.append(Paragraph("One-Liners for MCQ / Short Answer", h2_style))
    oneliners = [
        ("First use of fingerprints in India", "Sir William Herschel, 1858, West Bengal"),
        ("Systematized fingerprint system", "Sir Francis Galton, 1892"),
        ("First Fingerprint Bureau in world", "Kolkata, India, 1897"),
        ("Classification system named after", "Galton-Henry System"),
        ("Frequency of loops", "60-70% (most common)"),
        ("Frequency of whorls", "25-35%"),
        ("Frequency of arches", "6-7%"),
        ("Frequency of composites", "1-2% (rarest)"),
        ("Delta points: Arches", "0 (no delta)"),
        ("Delta points: Loops", "1 delta"),
        ("Delta points: Whorls", "2 deltas"),
        ("Fingerprint ridge formation starts", "12-16 weeks intrauterine life"),
        ("Fingerprint formation completed", "24 weeks intrauterine life"),
        ("Study of sweat pores", "Poroscopy (Locard)"),
        ("Study of ridge patterns", "Dermatoglyphics"),
        ("Single palmar crease in", "Down syndrome (Simian crease)"),
        ("ATD angle in Down syndrome", "> 57° (normal 40-50°)"),
        ("Increased whorls + high ridge count in", "Turner syndrome (45XO)"),
        ("Decreased ridge count in", "Klinefelter syndrome (47XXY)"),
        ("Most reliable identification method", "DNA profiling (99.9999%)"),
        ("Min characteristics to match (India)", "16 (UK: 8-10)"),
        ("Ninhydrin reacts with", "Amino acids in sweat (paper prints)"),
        ("Silver nitrate reacts with", "Chlorides (NaCl) in sweat"),
        ("Iodine fuming result", "Temporary (fades on exposure)"),
        ("Best method for non-porous surfaces", "Cyanoacrylate fuming (superglue)"),
        ("Interpol DVI - fingerprints category", "Category 1 (Primary identifier)"),
        ("Minimum pores for poroscopy ID", "20-22 pores"),
    ]
    ol_data = [["Question / Key Point", "Answer"]] + oneliners
    tol = Table(ol_data, colWidths=[9*cm, 7*cm])
    tol.setStyle(TableStyle([
        ('BACKGROUND',    (0,0), (-1,0), RED),
        ('TEXTCOLOR',     (0,0), (-1,0), WHITE),
        ('FONTNAME',      (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',      (0,0), (-1,0), 8.5),
        ('FONTNAME',      (0,1), (-1,-1),'Helvetica'),
        ('FONTSIZE',      (0,1), (-1,-1), 8.5),
        ('FONTNAME',      (1,1), (1,-1), 'Helvetica-Bold'),
        ('TEXTCOLOR',     (1,1), (1,-1), DARK_BLUE),
        ('ROWBACKGROUNDS',(0,1), (-1,-1), [WHITE, colors.HexColor("#FFEBEE")]),
        ('GRID',          (0,0), (-1,-1), 0.5, colors.HexColor("#EF9A9A")),
        ('VALIGN',        (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING',    (0,0), (-1,-1), 4),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING',   (0,0), (-1,-1), 8),
    ]))
    story.append(tol)
    story.append(Spacer(1, 8))

    story.append(ColorBox(
        "<b>MNEMONIC SUMMARY</b>\n\n"
        "• Pattern frequency: <b>LWAC</b> — Loops (60-70%), Whorls (25-35%), Arches (6-7%), Composites (1-2%)\n"
        "• Properties: <b>PUPE</b> — Permanence, Uniqueness, Practicability, Exactness\n"
        "• Deltas: 0 (Arch) → 1 (Loop) → 2 (Whorl/Composite)\n"
        "• Development methods: <b>DISC-N</b> — Dusting, Iodine, Silver nitrate, Cyanoacrylate, Ninhydrin\n"
        "• Dermatoglyphics in syndromes: Down=Simian crease+ulnar loops, Turner=whorls, Klinefelter=arches",
        bg=LIGHT_GREEN, border=GREEN, style=bold_style
    ))

    story.append(Spacer(1, 8))
    story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#90A4AE")))
    story.append(Spacer(1, 4))
    story.append(Paragraph(
        "<i>Sources: The Essentials of Forensic Medicine & Toxicology 36th Ed. (Pillay) | "
        "P.C. Dikshit Textbook of Forensic Medicine & Toxicology | "
        "Parikh's Textbook of Medical Jurisprudence, Forensic Medicine & Toxicology</i>",
        caption_style
    ))

    # Build
    doc.build(story)
    print(f"PDF generated: {OUTPUT}")

if __name__ == "__main__":
    build_pdf()
Running Command

cd /tmp/workspace/fingerprint-study-guide && python generate_pdf.py 2>&1

Editing File

~/fingerprint-study-guide/generate_pdf.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/fingerprint-study-guide/generate_pdf.py'
Running Command

cd /tmp/workspace/fingerprint-study-guide && python generate_pdf.py 2>&1

Running Command

ls -lh /tmp/workspace/fingerprint-study-guide/

Your study guide PDF is ready! Here's your download link:

Fingerprints Dactylography Study Guide

PDF Document · PDF


What's inside the PDF (9 pages, A4):

Page 1 - Cover Page

  • Full-colour dark blue cover with fingerprint whorl icon, topic list, and exam frequency rating

Page 2 - Definition & Historical Background

  • Timeline diagram (1858 Herschel → 1892 Galton → 1897 Kolkata Bureau → 1900 Scotland Yard)
  • Detailed history table with all key dates and contributors

Page 3 - Principle & Properties

  • Formation timeline (12 wks → 16 wks → 24 wks IU)
  • The 4 Cardinal Properties: PUPE mnemonic (Permanence, Uniqueness, Practicability, Exactness)

Page 4 - Classification Diagram

  • 4-panel visual diagram showing Loop, Whorl, Arch, Composite patterns with delta points marked
  • Galton-Henry classification tree with all subtypes branching out

Page 5 - Detailed Subtypes

  • Loop subtypes diagram (Radial vs Ulnar)
  • Whorl subtypes diagram (all 4)
  • Delta point explanation diagram

Page 6 - Types of Prints & Development Methods

  • Visible, Latent, and Plastic prints comparison table
  • Development methods table (Dusting, Iodine, Silver Nitrate, Ninhydrin, Cyanoacrylate, UV)

Page 7 - Medicolegal Importance

  • 8 medicolegal uses in colour-coded boxes
  • Fingerprints vs DNA Profiling comparison table

Page 8 - Poroscopy & Dermatoglyphics

  • Poroscopy (Locard) explained
  • Clinical dermatoglyphics table: Down, Klinefelter, Turner, Patau, Edwards syndromes
  • Obliteration of fingerprints

Page 9 - Rapid Revision

  • 27 one-liner MCQ points table
  • All mnemonics box (LWAC, PUPE, DISC-N)
This is a shared conversation. Sign in to Orris to start your own chat.