Skip to content

Instantly share code, notes, and snippets.

@EnigmaCurry
Created April 17, 2011 15:23

Revisions

  1. EnigmaCurry renamed this gist Apr 17, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. 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
  3. EnigmaCurry renamed this gist Apr 17, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. 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) $
  5. 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)