Editorial Workflows

PDF (LaTeX)

public workflow

Install Workflow...

This workflow contains at least one Python script. Only use it if you trust the person who shared this with you, and if you know exactly what it does.

I understand, install the workflow!

This is a workflow for Editorial, a Markdown and plain text editor for iOS. To download it, you need to view this page on a device that has the app installed.

Description: The best way I've found to convert Markdown to PDF. This converts the Markdown file being edited to LaTeX and puts it on the clipboard. Then switch to the iOS app Texpad, paste the LaTeX into an empty .tex file and tap typeset to convert to PDF.

The workflow supports basic Markdown syntax except links, plus you can write LaTeX commands in the Markdown to do tables, equations and anything else. You have precise control over page design. The PDFs look great, because LaTeX knows about all the bits (letters, words ... pages) and optimises spacings. It all happens on the iPad, including images.

Shared by: Peter Hopcroft (peterh)

Comments: Comment Feed (RSS)

Jeremy Kidwell — 14 Oct 2014
I installed this workflow and gave it a spin, particularly since I like the idea of typesetting MD-->LaTeX-->PDF. There's only one limitation that I can see, and this is that there are a few features I'm using from MMD, i.e. footnotes in particular (https://github.com/fletcher/MultiMarkdown/wiki/MultiMarkdown-Syntax-Guide#footnotes) and the script simply doesn't parse them. Peter, do you have an alternative arrangement for formatting footnotes in your workflow, or do they simply not come up in the kind of writing you're doing? Thanks for sharing the workflow - it would be great to enhance with some MMD features if you have any ideas in this direction, happy to help.
anonymous — 16 Jan 2015
Texpad natively supports markdown formatting on an equal footing with Latex anyway, so you don't gain much by using editorial here.

+ Add Comment

Workflow Preview
Using this workflow ?
Source Code
#coding: utf-8
"""
PDF (LaTeX) - Peter Hopcroft, February 2014

The best way I've found to convert Markdown to PDF. This converts the Markdown file being edited to LaTeX and puts it on the clipboard. Then switch to the iOS app Texpad, paste the LaTeX into an empty .tex file and tap typeset to convert to PDF.

The workflow supports basic Markdown syntax except links, plus you can write LaTeX commands in the Markdown to do tables, equations and anything else. You have precise control over page design. The PDFs look great, because LaTeX knows about all the bits (letters, words ... pages) and optimises spacings. It all happens on the iPad, including images.

You'll need:
    http://tobi.oetiker.ch/lshort/lshort.pdf
    http://ctan.unsw.edu.au/macros/latex/contrib/memoir/memman.pdf
    grit

	
MEMOIR: The LaTeX uses the Memoir class.

LaTeX COMMANDS IN MARKDOWN: The workflow converts Markdown to html, then to LaTeX. To write LaTeX commands in Markdown requires \ { and } characters, and you are supposed to backslash escape them in Markdown. But Python Markdown does not seem to need this. The workflow loads the Tabulary package for writing tables.

CONVERSION:
from		to
#				title: same as ##, but no number
##			numbered chapter heading: starts on new page unless at start of text
###			section heading
####		subsection heading
#####		runin heading
######	same as #####
---			\pfbreak
code span elements: | is the end delimiter for now
code block elements: \end{verbatim} is the end delimiter

ENCODING: The workflow encodes the LaTeX as utf-8 to send to Texpad. But you can only use the less-than-256 characters listed in LaTeX's T1 encoding, see:
    http://www.tex.ac.uk/tex-archive/macros/latex/doc/encguide.pdf
For a character outside this, Texpad gives an 'package inputenc error'.

PICTURES: Before you run the workflow, import your picture files into Texpad (use +). They are imported as .png, about three times the size of .jpg. The workflow turns a Markdown image element into an equivalent LaTeX graphic element. My extensions:
- LaTeX requires a width. You can write a width in the alt text; if you don't the default is \textwidth.
- If you write a caption in the title text, the workflow puts the picture in a figure (floating) envoronment, with the caption under the picture.

For example:
	
![](picture.png) -> \includegraphics[width=\textwidth]{picture.png}

![100mm](picture.png) -> \includegraphics[width=100mm]{picture.png}

![100mm](picture.png 'Caption text here') ->
	
\begin{figure}[!hbtp]
\includegraphics[width=100mm]{picture.png}	
\par{}Caption text here
\end{figure}

The .png in the image file name is optional. Texpad has a bug, and sometimes says it can't find the image file when it is there. Try again.

LIGATURES: Texpad's local typesetter has a bug with some fonts (with utopia): Some ligatures are typeset wrong, eg 'ff' appears as 'f '. To avoid this, the E dictionary in the python script can put a zero-width space between faulty ligature character pairs; see the example for 'ff'. If you find more faulty pairs, add them to the E dictionary.

BEWARE:
- Don't use \ or & in regular text, because LaTeX assumes they are parts of commands.
- Some LaTeX commands conflict with Markdown and won't work. Eg LaTeX speech marks are ` ... ' and `` ... '', but you can't use them because Markdown uses ` to mark span code.
- I haven't tested all the valid combinations of Markdown syntax. Some will probably fail or look bad. For example, you can't nest block quotes.
- The faulty ligature pairs have the zero-width space inserted throughout the Markdown, including picture file names (rename if necessary) and LaTeX commands (I don't know if any are affected).

AND: I gleaned LaTeX from tex.stackoverflow. LaTeX can be sweatier than latex. The workflow has the sin of nonzero parskip nonzero and zero parindent. Texpad has a lot of rough edges.

"""
Convert markdown to LaTeX for Texpad ?
Source Code
#coding: utf-8

# PDF (LaTeX) - Peter Hopcroft, February 2014

import clipboard
import console
import editor
import markdown
import re
import os
import workflow

# constants -------------------------------------

# start of a LaTeX document, defines the page design- \\ is an escaped \
LSTART = """
\\documentclass[a4paper,12pt,openany,oneside]{memoir} 

\\usepackage[T1]{fontenc}
\\usepackage[utf8]{inputenc}
\\usepackage{utopia}
%\\usepackage{palatino}	% this works
%\\raggedright
\\usepackage{graphicx}
\\usepackage{enumitem}
\\usepackage{tabulary}

%\\usepackage{microtype} % does not help with ligature bug
%\\DisableLigatures[f]{encoding=T1, family=*}

% my global lengths
\\newlength{\\myparskip}
\\setlength{\\myparskip}{1.0ex plus 0.2ex minus 0.2ex}
\\newlength{\\myindent}
\\setlength{\\myindent}{3ex}
\\newlength{\\myskipbig}		% for headings
\\setlength{\\myskipbig}{5ex plus 1.0ex minus 1.0ex}
\\newlength{\\myskipsmall}		% for headings
\\setlength{\\myskipsmall}{1.5ex plus 0.3ex minus 0.3ex}

% page layout
\\pagestyle{plain}
\\setlrmarginsandblock{35mm}{35mm}{*}
\\setulmarginsandblock{25mm}{25mm}{*}
\\setlength{\\footskip}{8mm}
\\checkandfixthelayout

% paragraphs
\\setlength{\\parindent}{0pt}
\\abnormalparskip{\\myparskip}

% the headings
\\setsecnumdepth{chapter} % number chapters but not lesser headings

% h1 - same as chapter heading but no number
\\newcommand{\\mytitle}[1]%
    {{\\newpage\\vspace*{-1.2\\topskip}%
     \\Large\\mdseries\\raggedright{#1}%
     \\vspace{\\myskipbig}}} % is a group

% h2 - chapter heading
\\chapterstyle{section}
\\renewcommand*{\\chapterheadstart}{\\vspace*{-1.4\\topskip}} % space before
\\renewcommand*{\\chapnumfont}{\\Large\\mdseries\\raggedright}
\\renewcommand*{\\afterchapternum}{\\hspace{1.0ex}} % space after number
\\renewcommand*{\\chaptitlefont}{\\Large\\mdseries\\raggedright}
\\setlength{\\afterchapskip}{\\myskipbig} % space after

% h3 - section heading
\\setbeforesecskip{-\\myskipbig} % - for no hdr indent
\\setsecheadstyle{\\large\\mdseries\\raggedright}
\\setaftersecskip{\\myskipsmall}

% h4 - subsection heading
\\setbeforesubsecskip{-\\myskipbig} % - for no hdr indent
\\setsubsecheadstyle{\\itshape\\raggedright}
\\setaftersubsecskip{\\myskipsmall}

% h5 & h6 subsubsection heading - runin
\\setbeforesubsubsecskip{-\\myskipbig} % - for no hdr indent
\\setsubsubsecheadstyle{\\itshape\\raggedright}
\\setaftersubsubsecskip{-1.4ex} % for runin heading
    
% lists, using enumitem
\\newenvironment{myul}%   % unordered list
    {\\begin{itemize} [topsep=0pt, partopsep=0pt, itemsep=0pt, %
     parsep=\\parskip, leftmargin=\\myindent, labelindent=1.0pt, %
     labelsep=*, label={\\rule[0.2ex]{0.7ex}{0.7ex}}]}%
    {\\end{itemize} \\vspace{0ex} }

\\newenvironment{myol}%   % ordered list
    {\\begin{enumerate} [topsep=0pt, partopsep=0pt, itemsep=0pt, %
     parsep=\\parskip, leftmargin=\\myindent, labelindent=0.5pt, %
     labelsep=*, label=\\arabic*]}%
    {\\end{enumerate} \\vspace{0ex} }

% miscellaneous
\\newenvironment{myblockquote}%
    {\\leftskip=\\myindent}%
    {}

% verbatim: zero the space above and below trivlists, for verbatim
% caution: affects all trivlist environments (eg centering) beneficially
\\zerotrivseps					
\\verbatimindent=0ex		% for memoir verbatim
\\newenvironment{myverbatim}%
    {\\verbatim\\leftskip=\\myindent}%
    {\\endverbatim}

\\pfbreakskip=\\myskipbig	% hr -> \pfbreak; set the gap
%\\newcommand{\\myhr}%    old hr
%    {{\\centering\\rule[0.4ex]{10ex}{0.3pt}\\par}} % inner set {} is group

\\begin{document}
"""

# end of a LaTeX document
LEND = """
\\end{document}
"""

# dictionaries -------------------------------------

# html -> latex equivalents - \\ is an escaped \
D = {'<p>':'\n',
     '</p>': '', 
     '<h1>':'\n\\mytitle{',
     '</h1>':'}',
     '<h2>':'\n\\chapter{',
     '</h2>':'}',
     '<h3>':'\n\\section{',
     '</h3>':'}',
     '<h4>':'\n\\subsection{',
     '</h4>':'}',
     '<h5>':'\n\\subsubsection{',
     '</h5>':'}',
     '<h6>':'\n\\subsubsection{',
     '</h6>':'}',
     '<blockquote>':'\n\\begin{myblockquote}',
     '</blockquote>':'\n\\end{myblockquote}',
     '<ul>':'\n\\begin{myul}',
     '</ul>':'\\end{myul}',
     '<ol>':'\n\\begin{myol}',
     '</ol>': '\\end{myol}',
     '<li>':'\\item ',
     '</li>':'',
     '<pre><code>':'\n\\begin{myverbatim}',
     '</code></pre>':'\\end{myverbatim}',
     '<hr />':'\n\\pfbreak',
     '<em>':'\\emph{',
     '</em>':'}',
     '<strong>':'\\textbf{',
     '</strong>':'}',
     '<code>':'\\verb|',
     '</code>':'|',
     }

# html entities -> LaTeX characters or commands
# texpad has a bug with local typesetting: some ligatures, eg 'ff', 
# can typeset wrongly as 'f '; the lines below with \kern insert a 
# zero-size gap between two characters so they typeset properly
E = {'&amp;':'&',
     '&lt;':'<',
     'ff':'f\kern0pt{}f'
     }    

# functions -------------------------------------

# convert one html img element into a latex img element
def latex_img (html_img):
    # extract img file name
    mo = re.search('src="(.*?)"', html_img) # src="anychars"
    if (not mo) or (mo.group(1) == ''):
        f = 'No image file name found' # default
    else:
        f = mo.group(1)

    # extract img width
    mo = re.search('alt="(.*?)"', html_img) # alt="anychars"
    if (not mo) or (mo.group(1) == ''):
        w = '\\textwidth' # default
    else:
        w = mo.group(1)
        
    li = '\\includegraphics[width=' + w + ']{' + f + '}'
    
    # extract title
    mo = re.search('title="(.*?)"', html_img)	# get title="anychars"
    if (mo) and (mo.group(1) != ''):					# put in float
        li = '\n\\begin{figure}[!hbtp]\n' + li + '\n\\par{}' + mo.group(1) + '\n\\end{figure}\n'
    return li

# convert all html img elements to latex img elements
def do_imgs (txt): 
    new_txt = ''
    els = txt.split('<img')  # find img elements, start with <img
    for el in els:
        if '/>' in el:
            i_r = el.split('/>', 1)	# split into img element and the rest
            new_txt += latex_img(i_r[0]) + i_r[1]
        else:
            new_txt += el # no img element
    return new_txt
    
# main -------------------------------------
        
console.clear()
txt = editor.get_text()

if '\\' in txt:
    console.alert('Warning:\nThe markdown text\nhas the character:\n\\',
                  'These can only be in LaTeX commands, not in ordinary text',
                  'Continue')
if '&' in txt:
    console.alert('Warning:\nThe markdown text\nhas the character:\n&',
                  'These can only be in LaTeX lists, not in ordinary text',
                  'Continue')
                  
txt = markdown.markdown (txt)			# convert to html, no extensions
for k, v in D.iteritems():				# convert most html to LaTeX
    txt = txt.replace(k, v)
txt = do_imgs(txt)								# convert html imgs to latex imgs

if '<a' in txt and '</a>' in txt:	# check for unsupported html
    console.alert('Warning:\nThere is a markdown link',
                  'This workflow does not suport links in LaTeX', 
                  'Continue')
elif '<' in txt or '>' in txt:
   console.alert('Warning:\nThe LaTeX file has < or > brackets',
                 "This could be HTML that hasn't been converted to laTeX",
                 'Continue')

for k, v in E.iteritems():				# convert minor things to LaTeX
    txt = txt.replace(k, v)

txt = LSTART + txt + LEND					# add preamble and postamble
clipboard.set(txt.encode('utf_8', 'replace'))
console.alert('The LaTeX is on the clipboard', 'Switch to Texpad, paste into an empty .tex file, tap typeset, then tap the eye button to see the PDF', 'OK')

# -------------------------------------