| """ |
| pdf.py β Zouq-ul-ilm | Professional Notes PDF Generator |
| Handles markdown headings (#, ##, ###) AND === TOPIC === dividers. |
| """ |
|
|
| from reportlab.lib.pagesizes import A4 |
| from reportlab.lib.styles import ParagraphStyle |
| from reportlab.lib.units import mm |
| from reportlab.lib import colors |
| from reportlab.lib.enums import TA_LEFT, TA_JUSTIFY |
| from reportlab.platypus import ( |
| BaseDocTemplate, Frame, PageTemplate, |
| Paragraph, Spacer, HRFlowable, |
| ListFlowable, ListItem, KeepTogether, PageBreak, |
| ) |
| from reportlab.platypus.flowables import Flowable |
| import re, io |
|
|
| |
| INK = colors.HexColor("#0F1117") |
| NAVY = colors.HexColor("#1B2A4A") |
| GOLD = colors.HexColor("#C8973F") |
| GOLD_LIGHT = colors.HexColor("#FBF3E4") |
| SLATE = colors.HexColor("#3D4A5C") |
| MUTED = colors.HexColor("#7B8499") |
| DIVIDER = colors.HexColor("#DDE1EA") |
| WHITE = colors.white |
|
|
| W_PAGE, H_PAGE = A4 |
| MARGIN_LR = 18*mm |
| MARGIN_TOP = 30*mm |
| MARGIN_BOT = 22*mm |
| TEXT_W = W_PAGE - 2*MARGIN_LR |
|
|
|
|
| |
| class TopicBanner(Flowable): |
| """Full-width dark banner for === TOPIC === headings.""" |
| BH = 15*mm |
|
|
| def __init__(self, title, width=TEXT_W): |
| super().__init__() |
| self.title = title |
| self.width = width |
| self.height = self.BH + 6*mm |
|
|
| def draw(self): |
| c = self.canv |
| c.saveState() |
| c.setFillColor(NAVY) |
| c.roundRect(0, 4*mm, self.width, self.BH, radius=5, fill=1, stroke=0) |
| c.setFillColor(GOLD) |
| c.roundRect(0, 4*mm, 4, self.BH, radius=2, fill=1, stroke=0) |
| c.setFillColor(WHITE) |
| c.setFont("Helvetica-Bold", 12.5) |
| c.drawString(9*mm, 4*mm + self.BH/2 - 4.5, self.title) |
| c.restoreState() |
|
|
|
|
| class SectionHeading(Flowable): |
| """Gold-accented card for ## H2 headings.""" |
| BH = 9*mm |
|
|
| def __init__(self, title, width=TEXT_W): |
| super().__init__() |
| self.title = title |
| self.width = width |
| self.height = self.BH + 5*mm |
|
|
| def draw(self): |
| c = self.canv |
| c.saveState() |
| c.setFillColor(GOLD_LIGHT) |
| c.setStrokeColor(GOLD) |
| c.setLineWidth(0.8) |
| c.roundRect(0, 3*mm, self.width, self.BH, radius=4, fill=1, stroke=1) |
| c.setFillColor(GOLD) |
| c.roundRect(0, 3*mm, 3.5, self.BH, radius=2, fill=1, stroke=0) |
| c.setFillColor(NAVY) |
| c.setFont("Helvetica-Bold", 11) |
| c.drawString(7*mm, 3*mm + self.BH/2 - 4, self.title) |
| c.restoreState() |
|
|
|
|
| |
| class ZouqDoc(BaseDocTemplate): |
| def __init__(self, target, doc_title="Notes", **kw): |
| self.doc_title = doc_title |
| super().__init__(target, **kw) |
| frame = Frame( |
| MARGIN_LR, MARGIN_BOT, TEXT_W, |
| H_PAGE - MARGIN_TOP - MARGIN_BOT, |
| leftPadding=0, rightPadding=0, |
| topPadding=0, bottomPadding=0, |
| ) |
| self.addPageTemplates([ |
| PageTemplate(id="main", frames=[frame], |
| onPage=self._decorate) |
| ]) |
|
|
| def _decorate(self, canvas, doc): |
| canvas.saveState() |
| W, H = A4 |
|
|
| |
| canvas.setFillColor(NAVY) |
| canvas.rect(0, H - MARGIN_TOP, W, MARGIN_TOP, fill=1, stroke=0) |
| canvas.setFillColor(GOLD) |
| canvas.rect(0, H - MARGIN_TOP, W, 2, fill=1, stroke=0) |
| canvas.setFillColor(WHITE) |
| canvas.setFont("Helvetica-Bold", 9.5) |
| canvas.drawString(MARGIN_LR, H - 16*mm, "Zouq-ul-ilm") |
| canvas.setFont("Helvetica", 8.5) |
| canvas.setFillColor(colors.HexColor("#A8B4C8")) |
| canvas.drawRightString(W - MARGIN_LR, H - 16*mm, self.doc_title[:65]) |
|
|
| |
| canvas.setFillColor(colors.HexColor("#F2F4F7")) |
| canvas.rect(0, 0, W, MARGIN_BOT - 4*mm, fill=1, stroke=0) |
| canvas.setFillColor(GOLD) |
| canvas.rect(0, MARGIN_BOT - 4*mm, W, 1.5, fill=1, stroke=0) |
| canvas.setFont("Helvetica", 7.5) |
| canvas.setFillColor(MUTED) |
| canvas.drawString(MARGIN_LR, 7*mm, |
| "Generated by Zouq-ul-ilm Β· AI-Powered Study Notes") |
| canvas.drawRightString(W - MARGIN_LR, 7*mm, f"Page {doc.page}") |
| canvas.restoreState() |
|
|
|
|
| |
| def _S(): |
| return { |
| "h1": ParagraphStyle("h1", |
| fontName="Helvetica-Bold", fontSize=19, leading=25, |
| textColor=NAVY, spaceBefore=4, spaceAfter=4), |
|
|
| "h3": ParagraphStyle("h3", |
| fontName="Helvetica-Bold", fontSize=11, leading=15, |
| textColor=SLATE, spaceBefore=7, spaceAfter=3), |
|
|
| "body": ParagraphStyle("body", |
| fontName="Helvetica", fontSize=10.5, leading=16.5, |
| textColor=SLATE, spaceAfter=5, alignment=TA_JUSTIFY), |
|
|
| "bullet": ParagraphStyle("bullet", |
| fontName="Helvetica", fontSize=10.5, leading=15.5, |
| textColor=SLATE, spaceBefore=1, spaceAfter=1), |
|
|
| "sub_bullet": ParagraphStyle("sub_bullet", |
| fontName="Helvetica", fontSize=9.8, leading=14, |
| textColor=MUTED, spaceBefore=1, spaceAfter=1), |
| } |
|
|
|
|
| |
| def _md(t): |
| t = t.replace("&", "&").replace("<", "<").replace(">", ">") |
| t = re.sub(r"\*\*(.+?)\*\*", r'<b>\1</b>', t) |
| t = re.sub(r"__(.+?)__", r'<b>\1</b>', t) |
| t = re.sub(r"\*(.+?)\*", r'<i>\1</i>', t) |
| t = re.sub(r"_(.+?)_", r'<i>\1</i>', t) |
| t = re.sub(r"~~(.+?)~~", |
| r'<font color="#9CA3AF"><strike>\1</strike></font>', t) |
| t = re.sub(r"`(.+?)`", |
| r'<font name="Courier" color="#B03030" backColor="#FEF2F2"> \1 </font>', |
| t) |
| return t |
|
|
|
|
| |
| H1_RE = re.compile(r'^#\s+(.+)') |
| H2_RE = re.compile(r'^##\s+(.+)') |
| H3_RE = re.compile(r'^###\s+(.+)') |
| BULLET_RE = re.compile(r'^\s*[-*β’]\s+(.+)') |
| SUB_RE = re.compile(r'^\s*\+\s+(.+)') |
| OL_RE = re.compile(r'^\s*\d+\.\s+(.+)') |
| TOPIC_RE = re.compile(r'^={3,}\s*(.+?)\s*={3,}$') |
| SEP_RE = re.compile(r'^[=\-]{3,}\s*$') |
|
|
|
|
| def _bullet_list(items, S, ordered=False): |
| li = [] |
| for text, is_sub in items: |
| style = S["sub_bullet"] if is_sub else S["bullet"] |
| li.append(ListItem( |
| Paragraph(_md(text), style), |
| bulletColor=MUTED if is_sub else GOLD, |
| leftIndent=28 if is_sub else 16, |
| bulletFontSize=9 if is_sub else 12, |
| )) |
| return ListFlowable(li, |
| bulletType="1" if ordered else "bullet", |
| bulletFontName="Helvetica-Bold", |
| bulletFontSize=10.5, |
| bulletColor=GOLD, |
| leftIndent=8, |
| spaceBefore=3, spaceAfter=6) |
|
|
|
|
| |
| def pdf1(text: str, output_path: str = None): |
| S = _S() |
|
|
| |
| m = re.search(r'^#\s+(.+)', text, re.M) or re.search(r'^={3,}\s*(.+?)\s*={3,}$', text, re.M) |
| doc_title = m.group(1).strip() if m else "Study Notes" |
|
|
| target = output_path or io.BytesIO() |
| doc = ZouqDoc(target, doc_title=doc_title, pagesize=A4, |
| topMargin=MARGIN_TOP, bottomMargin=MARGIN_BOT, |
| leftMargin=MARGIN_LR, rightMargin=MARGIN_LR) |
|
|
| story = [] |
| lines = text.split('\n') |
| i = 0 |
| topic_count = 0 |
|
|
| while i < len(lines): |
| line = lines[i].strip() |
|
|
| |
| if SEP_RE.match(line): |
| i += 1; continue |
|
|
| |
| if not line: |
| story.append(Spacer(1, 2.5*mm)) |
| i += 1; continue |
|
|
| |
| m = TOPIC_RE.match(line) |
| if m: |
| topic_count += 1 |
| if topic_count > 1: |
| story.append(PageBreak()) |
| story.append(Spacer(1, 2*mm)) |
| story.append(TopicBanner(m.group(1).strip().title())) |
| story.append(Spacer(1, 4*mm)) |
| i += 1; continue |
|
|
| |
| if H1_RE.match(line): |
| clean = re.sub(r'^#\s+', '', line) |
| story.append(Spacer(1, 3*mm)) |
| story.append(HRFlowable(width="100%", thickness=2, |
| color=GOLD, spaceAfter=2)) |
| story.append(Paragraph(_md(clean), S["h1"])) |
| story.append(HRFlowable(width="100%", thickness=0.4, |
| color=DIVIDER, spaceAfter=4)) |
| i += 1; continue |
|
|
| |
| if H2_RE.match(line): |
| clean = re.sub(r'^##\s+', '', line) |
| story.append(KeepTogether([ |
| Spacer(1, 4*mm), |
| SectionHeading(clean), |
| Spacer(1, 2.5*mm), |
| ])) |
| i += 1; continue |
|
|
| |
| if H3_RE.match(line): |
| clean = re.sub(r'^###\s+', '', line) |
| story.append(Spacer(1, 3*mm)) |
| story.append(Paragraph(_md(clean), S["h3"])) |
| story.append(HRFlowable(width="40%", thickness=1, |
| color=GOLD, spaceAfter=2)) |
| i += 1; continue |
|
|
| |
| if OL_RE.match(line): |
| items = [] |
| while i < len(lines): |
| m2 = OL_RE.match(lines[i].strip()) |
| if not m2: break |
| items.append((m2.group(1), False)) |
| i += 1 |
| story.append(_bullet_list(items, S, ordered=True)) |
| continue |
|
|
| |
| if BULLET_RE.match(line) or SUB_RE.match(line): |
| items = [] |
| while i < len(lines): |
| l2 = lines[i].strip() |
| mb = BULLET_RE.match(l2) |
| ms = SUB_RE.match(l2) |
| if mb: |
| items.append((mb.group(1), False)); i += 1 |
| elif ms: |
| items.append((ms.group(1), True)); i += 1 |
| else: |
| break |
| if items: |
| story.append(_bullet_list(items, S)) |
| continue |
|
|
| |
| story.append(Paragraph(_md(line), S["body"])) |
| i += 1 |
|
|
| doc.build(story) |
| if not output_path and isinstance(target, io.BytesIO): |
| return target.getvalue() |
|
|
|
|
| |
| if __name__ == "__main__": |
| sample = """ |
| === INFORMATION SECURITY FOUNDATIONS === |
| |
| Information Security Foundations |
| ===================================== |
| |
| Definition |
| Information security refers to the practice of protecting information from unauthorized access, use, disclosure, disruption, modification, or destruction. It involves a set of strategies, policies, and procedures to ensure the confidentiality, integrity, and availability of information. |
| |
| Key Concepts |
| * **Confidentiality:** Protecting information from unauthorized access or disclosure. |
| * **Integrity:** Ensuring that information is accurate, complete, and not modified without authorization. |
| * **Availability:** Ensuring that information is accessible and usable when needed. |
| * **Authentication:** Verifying the identity of users, systems, or entities. |
| * **Non-repudiation:** Ensuring that a sender of a message cannot deny having sent the message. |
| |
| Types/Categories of Information Security |
| * **Network Security:** Protecting networks from unauthorized access, use, or malicious activities. |
| + Firewalls and IDS |
| + VPN and encrypted tunnels |
| * **Application Security:** Protecting software applications from vulnerabilities. |
| * **Data Security:** Protecting data from unauthorized access, use, or disclosure. |
| * **Cloud Security:** Protecting cloud-based infrastructure, data, and applications from threats. |
| |
| Important Points |
| * **Risk Management:** Identifying, assessing, and mitigating risks to information security. |
| * **Threats:** Potential occurrences that could compromise security such as hacking or malware. |
| * **Vulnerabilities:** Weaknesses in systems that can be exploited by threats. |
| * **Incident Response:** Responding to and managing security incidents. |
| * **Compliance:** Adhering to laws like GDPR or HIPAA. |
| |
| Brief Summary |
| Information security foundations involve protecting information from unauthorized access. Key concepts include confidentiality, integrity, availability, authentication, and non-repudiation. By understanding these principles, individuals and organizations can establish a strong security foundation. |
| |
| === SYMMETRIC AND ASYMMETRIC CRYPTOGRAPHY === |
| |
| Introduction to Cryptography |
| |
| Cryptography is the practice of secure communication by transforming **plaintext** into unreadable **ciphertext** to protect it from unauthorized access. |
| |
| Key Concepts |
| * **Encryption:** The process of converting plaintext into ciphertext. |
| * **Decryption:** The process of converting ciphertext back into plaintext. |
| * **Key:** A secret code used for encryption and decryption. |
| |
| ## Symmetric Cryptography |
| |
| Definition: Symmetric cryptography uses the **same secret key** for both encryption and decryption. |
| |
| Types/Categories |
| * Block Ciphers: Divide data into fixed-length blocks (e.g., **AES**). |
| * Stream Ciphers: Encrypt data one bit or byte at a time (e.g., **RC4**). |
| |
| Important Points |
| * Advantages: |
| + Fast and efficient |
| + Easy to implement |
| + Low computational overhead |
| * Disadvantages: |
| + Key management is a major challenge |
| + Not suitable for large-scale networks |
| |
| ## Asymmetric Cryptography |
| |
| Definition: Asymmetric cryptography uses a **pair of keys**: a public key for encryption and a private key for decryption. |
| |
| Types/Categories |
| * **RSA** (Rivest-Shamir-Adleman): A widely used asymmetric encryption algorithm. |
| * **Elliptic Curve Cryptography (ECC):** Uses elliptic curves for stronger security with smaller keys. |
| |
| Brief Summary |
| Symmetric cryptography is fast and efficient but has key management challenges. Asymmetric cryptography provides secure key exchange and authentication but is computationally intensive. |
| """ |
| pdf1(sample, "/mnt/user-data/outputs/notes.pdf") |