Skip to content

Instantly share code, notes, and snippets.

@josch
Forked from EnigmaCurry/latex.py
Created June 4, 2011 05:08

Revisions

  1. josch revised this gist Jul 11, 2011. 1 changed file with 8 additions and 7 deletions.
    15 changes: 8 additions & 7 deletions latex.py
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,10 @@
    import hashlib
    import blogofile_bf as bf

    html_escape_table = {"&": "&amp;",'"': "&quot;","'": "&apos;",">": "&gt;","<": "&lt;"}

    html_escape = lambda text: "".join(html_escape_table.get(c,c) for c in text)

    tex_template = r"""
    \documentclass[12pt]{article}
    \usepackage{ucs}
    @@ -27,10 +31,6 @@

    latex_block_re = re.compile(r"\s\$\$latex\s(.*?)\s\$", re.DOTALL)

    def render_tex_math_expr_to_png(math_block, png_location):
    """Wrap a mathematical TeX expression in $ symbols and render"""
    render_tex_to_png(math_block, png_location)

    def render_tex_to_png(latex_block, png_location):
    """Render a TeX formatted string to an image file
    @@ -100,13 +100,14 @@ def render_latex_blocks(src, cache_dir="_tmp", site_images_dir="images"):
    if(not os.path.isfile(png_cached)):
    bf.util.mkdir(cache_dir)
    bf.filter.logger.info("Rendering LaTeX: "+tex_expr)
    render_tex_math_expr_to_png(tex_expr,png_cached)
    render_tex_to_png(tex_expr,png_cached)
    #copy the rendered image to the site dir
    bf.util.mkdir(site_png_dir)
    shutil.copyfile(png_cached,site_png)
    #record the $$latex block and it's replacement <img> tag
    img_substitutions[m.group()] = "<img src=\"%s%s\">" % \
    (bf.config.site.url,bf.util.site_path_helper(site_images_dir,fn))
    img_substitutions[m.group()] = "<img alt=\"%s\" src=\"%s%s\">" % \
    (html_escape(tex_expr), bf.config.site.url,
    bf.util.site_path_helper(site_images_dir,fn))
    #Make the <img> tag replacements in a single pass
    p = re.compile('|'.join(map(re.escape, img_substitutions)))
    return p.sub(lambda x: img_substitutions[x.group(0)], src)
  2. josch revised this gist Jun 5, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions latex.py
    Original file line number Diff line number Diff line change
    @@ -105,8 +105,8 @@ def render_latex_blocks(src, cache_dir="_tmp", site_images_dir="images"):
    bf.util.mkdir(site_png_dir)
    shutil.copyfile(png_cached,site_png)
    #record the $$latex block and it's replacement <img> tag
    img_substitutions[m.group()] = "<img src=\"%s\">" % \
    (bf.util.site_path_helper(site_images_dir,fn))
    img_substitutions[m.group()] = "<img src=\"%s%s\">" % \
    (bf.config.site.url,bf.util.site_path_helper(site_images_dir,fn))
    #Make the <img> tag replacements in a single pass
    p = re.compile('|'.join(map(re.escape, img_substitutions)))
    return p.sub(lambda x: img_substitutions[x.group(0)], src)
  3. josch revised this gist Jun 4, 2011. 1 changed file with 24 additions and 17 deletions.
    41 changes: 24 additions & 17 deletions latex.py
    Original file line number Diff line number Diff line change
    @@ -13,26 +13,23 @@
    import blogofile_bf as bf

    tex_template = r"""
    \documentclass{article}
    \documentclass[12pt]{article}
    \usepackage{ucs}
    \usepackage[utf8x]{inputenc}
    \usepackage{amsmath}
    \usepackage{amsthm}
    \usepackage{amssymb}
    \usepackage{bm}
    \newcommand{\mx}[1]{\mathbf{\bm{#1}}}
    \newcommand{\vc}[1]{\mathbf{\bm{#1}}}
    \newcommand{\T}{\text{T}}
    \pagestyle{empty}
    \begin{document}
    %s
    \newpage
    $%s$
    \end{document}
    """

    latex_block_re = re.compile(r"\s\$\$latex\s(.*?)\s\$", re.DOTALL)

    def render_tex_math_expr_to_png(math_block, png_location):
    """Wrap a mathematical TeX expression in $ symbols and render"""
    render_tex_to_png("$%s$" % math_block, png_location)
    render_tex_to_png(math_block, png_location)

    def render_tex_to_png(latex_block, png_location):
    """Render a TeX formatted string to an image file
    @@ -56,15 +53,25 @@ def render_tex_to_png(latex_block, png_location):
    stdout=subprocess.PIPE)
    p.wait()
    #Generate the .ps
    p = subprocess.Popen(shlex.split('dvips source.dvi'),
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE)
    p.wait()
    #Generate the .png
    p = subprocess.Popen(shlex.split(
    'convert -density 120 -trim -transparent'
    ' "#FFFFFF" source.ps rendered.png'),stdout=subprocess.PIPE)
    p.wait()

    try:
    p = subprocess.Popen(shlex.split(
    'dvipng -bg Transparent -gamma 1.5 -D 120 -T tight'
    ' --strict source.dvi -o rendered.png'),
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE)
    p.wait()
    except:
    p = subprocess.Popen(shlex.split('dvips source.dvi'),
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE)
    p.wait()
    #Generate the .png
    p = subprocess.Popen(shlex.split(
    'convert -density 120 -trim -transparent'
    ' "#FFFFFF" source.ps rendered.png'),stdout=subprocess.PIPE)
    p.wait()

    #Copy the .png to the png_location
    os.chdir(previous_dir)
    shutil.copyfile(os.path.join(tmp_dir,"rendered.png"),png_location)
  4. @EnigmaCurry EnigmaCurry renamed this gist Apr 17, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. @EnigmaCurry EnigmaCurry renamed this gist Apr 17, 2011. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions blogofile_latex.py → blogofile_latex_filter.py
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    """
    Render TeX blocks to png
    This is a Blogofile filter. Place it in your _filters directory.
    """
    import tempfile
    import subprocess
  6. @EnigmaCurry EnigmaCurry renamed this gist Apr 17, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  7. @EnigmaCurry EnigmaCurry revised this gist Apr 17, 2011. 1 changed file with 21 additions and 0 deletions.
    21 changes: 21 additions & 0 deletions sample_post.markdown
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    ---
    categories: Category 1, Category 2
    date: 2009/07/24 16:20:00
    title: Sample LaTeX post
    filter: latex, markdown
    tags: test, blogofile, cool-stuff
    author: Ryan
    ---
    This is a sample post with TeX blocks.

    This is a TeX block:
    $$latex
    y = \int_0^\infty \gamma^2 \cos(x) dx $ this is after the block.
    This is an inline Tex block: $$latex \cos(x) $ and this is after.
    This is two seperate inline Tex blocks: $$latex \sin(x) $ and then $$latex \tan(x) $ and this is after.
    This is a mistyped TeX block because I didn't terminate it properly. $$latex \tan(x)$ and this text is rendered too because I didn't put a space before the dollar sign $
    This is a broken TeX block because I didn't put a space before it$$latex \tan(x) $
  8. @EnigmaCurry EnigmaCurry created this gist Apr 17, 2011.
    106 changes: 106 additions & 0 deletions blogofile_latex.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    """
    Render TeX blocks to png
    """
    import tempfile
    import subprocess
    import shutil
    import shlex
    import os
    import re
    import hashlib
    import blogofile_bf as bf

    tex_template = r"""
    \documentclass{article}
    \usepackage{amsmath}
    \usepackage{amsthm}
    \usepackage{amssymb}
    \usepackage{bm}
    \newcommand{\mx}[1]{\mathbf{\bm{#1}}}
    \newcommand{\vc}[1]{\mathbf{\bm{#1}}}
    \newcommand{\T}{\text{T}}
    \pagestyle{empty}
    \begin{document}
    %s
    \newpage
    \end{document}
    """

    latex_block_re = re.compile(r"\s\$\$latex\s(.*?)\s\$", re.DOTALL)

    def render_tex_math_expr_to_png(math_block, png_location):
    """Wrap a mathematical TeX expression in $ symbols and render"""
    render_tex_to_png("$%s$" % math_block, png_location)

    def render_tex_to_png(latex_block, png_location):
    """Render a TeX formatted string to an image file
    Depends on 'latex' and 'dvipng' binaries on the system path
    """

    #Create a temporary directory and go into it
    tmp_dir = tempfile.mkdtemp()
    previous_dir = os.getcwd()
    os.chdir(tmp_dir)

    tex_f = open(os.path.join(tmp_dir,"source.tex"),"w")
    tex_f.write((tex_template % latex_block))
    tex_f.close()

    try:
    #Generate the .dvi
    p = subprocess.Popen(shlex.split(
    'latex -interaction=nonstopmode source.tex'),
    stdout=subprocess.PIPE)
    p.wait()
    #Generate the .ps
    p = subprocess.Popen(shlex.split('dvips source.dvi'),
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE)
    p.wait()
    #Generate the .png
    p = subprocess.Popen(shlex.split(
    'convert -density 120 -trim -transparent'
    ' "#FFFFFF" source.ps rendered.png'),stdout=subprocess.PIPE)
    p.wait()
    #Copy the .png to the png_location
    os.chdir(previous_dir)
    shutil.copyfile(os.path.join(tmp_dir,"rendered.png"),png_location)
    finally:
    #Go back to the original directory and clean up the temp files
    os.chdir(previous_dir)
    shutil.rmtree(tmp_dir)

    def render_latex_blocks(src, cache_dir="_tmp", site_images_dir="images"):
    """Render a document with LaTeX blocks
    1) Extract all the $$latex blocks
    2) Render each TeX block to an image to the cache
    3) Copy the (pre)rendered image from the cache to the _site dir
    4) Replace the $$latex blocks with <img> tags
    """
    img_substitutions = {}
    for m in latex_block_re.finditer(src):
    tex_expr = m.groups()[0]
    fn = hashlib.md5(tex_expr).hexdigest()+".png"
    png_cached = os.path.join(cache_dir,fn)
    site_png_dir = bf.util.path_join("_site",bf.util.fs_site_path_helper(
    site_images_dir))
    site_png = bf.util.path_join(site_png_dir,fn)
    #only render the image if the image is not already cached
    if(not os.path.isfile(png_cached)):
    bf.util.mkdir(cache_dir)
    bf.filter.logger.info("Rendering LaTeX: "+tex_expr)
    render_tex_math_expr_to_png(tex_expr,png_cached)
    #copy the rendered image to the site dir
    bf.util.mkdir(site_png_dir)
    shutil.copyfile(png_cached,site_png)
    #record the $$latex block and it's replacement <img> tag
    img_substitutions[m.group()] = "<img src=\"%s\">" % \
    (bf.util.site_path_helper(site_images_dir,fn))
    #Make the <img> tag replacements in a single pass
    p = re.compile('|'.join(map(re.escape, img_substitutions)))
    return p.sub(lambda x: img_substitutions[x.group(0)], src)

    def run(src):
    return render_latex_blocks(src)