File size: 3,114 Bytes
2720487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from playwright.sync_api import sync_playwright
from PIL import Image
import io


def latex_to_pil(latex_code, target_width, target_height, fontsize=18):
    html_template = """
    <!DOCTYPE html>
    <html>
    <head>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.0/dist/katex.min.css">
        <script src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.js"></script>
        <style>
            body {
                margin: 0;
                padding: 0;
                display: flex;
            }
            #content {
                font-size: {fontsize}px;
            }
        </style>
    </head>
    <body>
        <div id="content">{content}</div>
        <script>
            function renderMath() {
                let content = document.getElementById('content');
                let html = content.innerHTML;

                // Replace display equations
                html = html.replace(/\\$\\$(.*?)\\$\\$/gs, (match, equation) => {
                    let span = document.createElement('span');
                    katex.render(equation, span, { displayMode: true, throwOnError: false, errorColor: '#000' });
                    return span.outerHTML;
                });

                // Replace inline equations
                html = html.replace(/\\$(.*?)\\$/g, (match, equation) => {
                    if(match.startsWith('\\\\$')) return match; // Ignore escaped dollars
                    let span = document.createElement('span');
                    katex.render(equation, span, { displayMode: false, throwOnError: false, errorColor: '#000' });
                    return span.outerHTML;
                });

                content.innerHTML = html;
            }

            renderMath();
        </script>
    </body>
    </html>
    """

    formatted_latex = latex_code.replace('\n', '\\n').replace('"', '\\"')
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.set_viewport_size({'width': target_width, 'height': target_height})

        while fontsize <= 30:
            html_content = html_template.replace("{content}", formatted_latex).replace("{fontsize}", str(fontsize))
            page.set_content(html_content)

            dimensions = page.evaluate("""() => {
                const render = document.getElementById('content');
                return {
                    width: render.offsetWidth,
                    height: render.offsetHeight
                };
            }""")

            if dimensions['width'] >= target_width or dimensions['height'] >= target_height:
                fontsize -= 1
                break
            else:
                fontsize += 1

        html_content = html_template.replace("{content}", formatted_latex).replace("{fontsize}", str(fontsize))
        page.set_content(html_content)

        screenshot_bytes = page.screenshot()
        browser.close()

        image_stream = io.BytesIO(screenshot_bytes)
        pil_image = Image.open(image_stream)
        pil_image.load()
        return pil_image