#!/usr/bin/env python3 """ Simple Markdown to PDF converter using markdown2 and reportlab """ import markdown2 from reportlab.lib.pagesizes import letter, A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import inch from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Table, TableStyle from reportlab.lib import colors from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY from html.parser import HTMLParser import re class MarkdownToPDFConverter: def __init__(self, input_file, output_file): self.input_file = input_file self.output_file = output_file self.doc = SimpleDocTemplate( output_file, pagesize=A4, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18 ) self.styles = getSampleStyleSheet() self._setup_styles() self.story = [] def _setup_styles(self): """Setup custom styles""" # Title style self.styles.add(ParagraphStyle( name='CustomTitle', parent=self.styles['Heading1'], fontSize=24, textColor=colors.HexColor('#2C3E50'), spaceAfter=30, alignment=TA_CENTER )) # Heading 2 self.styles.add(ParagraphStyle( name='CustomHeading2', parent=self.styles['Heading2'], fontSize=18, textColor=colors.HexColor('#2C3E50'), spaceAfter=12, spaceBefore=12 )) # Heading 3 self.styles.add(ParagraphStyle( name='CustomHeading3', parent=self.styles['Heading3'], fontSize=14, textColor=colors.HexColor('#27AE60'), spaceAfter=10, spaceBefore=10 )) # Code style self.styles.add(ParagraphStyle( name='Code', parent=self.styles['Normal'], fontSize=8, textColor=colors.black, backColor=colors.HexColor('#ECF0F1'), leftIndent=20, rightIndent=20 )) def convert(self): """Convert markdown file to PDF""" # Read markdown file with open(self.input_file, 'r', encoding='utf-8') as f: md_content = f.read() # Convert markdown to HTML html = markdown2.markdown(md_content, extras=['tables', 'fenced-code-blocks', 'header-ids']) # Parse HTML and convert to PDF elements self._parse_html_to_pdf(html) # Build PDF self.doc.build(self.story) def _parse_html_to_pdf(self, html): """Parse HTML and convert to PDF elements""" # Split by major sections lines = html.split('\n') for line in lines: line = line.strip() if not line: continue # Handle headings if line.startswith('', '', line) self.story.append(Paragraph(text, self.styles['CustomTitle'])) self.story.append(Spacer(1, 0.2*inch)) elif line.startswith('', '', line) self.story.append(Spacer(1, 0.2*inch)) self.story.append(Paragraph(text, self.styles['CustomHeading2'])) self.story.append(Spacer(1, 0.1*inch)) elif line.startswith('', '', line) self.story.append(Paragraph(text, self.styles['CustomHeading3'])) self.story.append(Spacer(1, 0.1*inch)) elif line.startswith('

'): text = re.sub(r'<.*?>', '', line) if text: self.story.append(Paragraph(text, self.styles['Normal'])) self.story.append(Spacer(1, 0.1*inch)) elif line.startswith('') or line.startswith('

'):
                text = re.sub(r'<.*?>', '', line)
                if text:
                    self.story.append(Paragraph(text, self.styles['Code']))
                    self.story.append(Spacer(1, 0.1*inch))

            elif line.startswith('
  • '): text = re.sub(r'<.*?>', '', line) if text: self.story.append(Paragraph(f"• {text}", self.styles['Normal'])) elif line.startswith('