import os import markdown from xhtml2pdf import pisa from datetime import datetime import io # iT Guys Identity Colors CSS_STYLES = """ @page { size: A4; margin: 20mm; margin-bottom: 25mm; /* Space for footer */ background-color: #ffffff; @frame footer_frame { -pdf-frame-content: footer_content; bottom: 10mm; margin-left: 20mm; margin-right: 20mm; height: 10mm; } } body { font-family: Helvetica, Arial, sans-serif; color: #333; line-height: 1.5; font-size: 11pt; } /* Headers */ h1 { color: #1478cf; /* Primary Blue */ border-left: 5px solid #2ecc71; /* Green Accent */ padding-left: 15px; background-color: #f0f8ff; /* Light Blue BG */ padding-top: 10px; padding-bottom: 10px; margin-top: 20px; font-size: 24pt; } h2 { color: #14508c; /* Darker Blue */ border-bottom: 2px solid #00f7ff; /* Cyan Accent */ padding-bottom: 5px; margin-top: 30px; font-size: 16pt; } h3 { color: #444; font-size: 13pt; margin-top: 20px; } /* Tables */ table { width: 100%; border: 1px solid #ddd; margin: 20px 0; font-size: 10pt; } th { background-color: #1478cf; color: white; padding: 8px; font-weight: bold; } td { border: 1px solid #ddd; padding: 8px; } /* Callouts / Admonitions (Python-Markdown Extension) */ .admonition { margin: 20px 0; padding: 0; border: 1px solid #ddd; border-radius: 4px; background-color: #ffffff; page-break-inside: avoid; } .admonition-title { font-weight: bold; padding: 8px 12px; background-color: #f0f0f0; border-bottom: 1px solid #ddd; font-size: 10pt; text-transform: uppercase; } /* Specific Types */ .admonition.note, .admonition.info { border-color: #bce8f1; } .admonition.note .admonition-title, .admonition.info .admonition-title { background-color: #d9edf7; color: #31708f; } .admonition.warning, .admonition.important, .admonition.attention { border-color: #faebcc; } .admonition.warning .admonition-title, .admonition.important .admonition-title { background-color: #fcf8e3; color: #8a6d3b; } .admonition.tip, .admonition.hint, .admonition.success { border-color: #d6e9c6; } .admonition.tip .admonition-title, .admonition.hint .admonition-title { background-color: #dff0d8; color: #3c763d; } .admonition p { padding: 10px 12px; margin: 0; } /* Legacy Blockquote fallback */ blockquote { background-color: #f9f9f9; border-left: 5px solid #ccc; margin: 10px 0; padding: 10px; color: #666; } /* Code Blocks */ pre { background-color: #2b2b2b; color: #f8f8f2; padding: 10px; border: 1px solid #444; font-family: monospace; font-size: 9pt; white-space: pre-wrap; /* Wrap long lines */ } /* Images */ img { zoom: 60%; /* xhtml2pdf sometimes renders images very large */ margin: 20px auto; } """ def convert_markdown_to_pdf(input_path, output_path): # Read Markdown with open(input_path, 'r', encoding='utf-8') as f: md_text = f.read() # Process Variables now = datetime.now() replacements = { '{{DATA_ATUAL}}': now.strftime("%d/%m/%Y"), '{{ANO}}': str(now.year) } for k, v in replacements.items(): if k in md_text: md_text = md_text.replace(k, v) # Determine Base Directory for assets base_dir = os.path.dirname(os.path.abspath(input_path)).replace("\\", "/") # Pre-process image paths to be absolute for xhtml2pdf import re def replace_img(match): alt = match.group(1) src = match.group(2) if not os.path.isabs(src) and not src.startswith("http"): src = os.path.join(base_dir, src).replace("\\", "/") return f'' md_text = re.sub(r'!\[(.*?)\]\((.*?)\)', replace_img, md_text) # Convert Markdown to HTML html_content = markdown.markdown( md_text, extensions=['tables', 'fenced_code', 'toc', 'sane_lists', 'admonition'] ) # Footer content footer = """
""" final_html = f""" {footer}