Editorial Workflows

Markdown To PDF

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: Markdown to PDF by Mason Phillips @phillipsmn

Converts Markdown documents to PDF using Docverter and saves to Dropbox.

Based on W. Caleb McDaniel's' iMDtoPDF.py for Pythonista http://wcm1.web.rice.edu/pandoc-on-ios.html

Shared by: Mason Phillips

Comments: Comment Feed (RSS)

Michael — 28 Sep 2014
I have a question about using css in your workflow to format numbered paragraphs. I created the below doc in .md using Editorial, then converted to PDF using your workflow. I hope you can help:

1. Markdown automatically applies a hanging indent to numbered paragraphs. Xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx.

2. Subsequent numbered paragraphs are also automatically numbered and hanging indented. Xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx.

2.1. By hitting the return key 3 times after a numbered paragraph, I created this sub paragraph and cleared the numbering. Then I could create a series of numbered sub paragraphs by manually typing "2.1." "2.2." etc, which does not break the primary numbering. I realize these are not true "numbered sub paragraphs".

2.2. But when I convert the Editorial .md file to PDF through your workflow, these sub paragraphs are not hanging indented.

2.3. My question is, how can I create a hanging indent for these sub paragraphs, using the css in the workflow?

3. Paragraph three.

4. Paragraph four.

+ Add Comment

Workflow Preview
Get Current File Name ?
Include Folder
Include Extension
Set Variable ?
Variable Name
Request Text Input ?
Enter a filename
Initial Text
  • Single Line
  • Multiple Lines
Keyboard Options:
Set Variable ?
Variable Name
Run Python Script ?
Source Code
#coding: utf-8
# Markdown to PDF workflow
# by Mason Phillips

## This is a wrapper script for sending documents to Docverter
## for conversion from markdown to PDF using Pandoc. Typically
## Docverter calls are made with cURL; this script uses httplib.
## It is intended for use with Editorial on iOS, so output file
## is uploaded to Dropbox after document conversion.
## For more information, see: http://www.docverter.com/api.html
## Much of the concept and portions of code are from W. Caleb McDaniel's'
## iMDtoPDF.py for Pythonista http://wcm1.web.rice.edu/pandoc-on-ios.html

import httplib
import mimetypes
import re
import StringIO
import editor
import workflow
import os

## Helper functions for posting multipart/form-data request
## using standard libraries. Updated to reflect changes to
## httplib in Python 2.0.
## {{{ http://code.activestate.com/recipes/146306/ (r1)
def post_multipart(host, selector, fields, files):
    Post fields and files to an http host as multipart/form-data.
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return the server's response page.
    content_type, body = encode_multipart_formdata(fields, files)
    h = httplib.HTTPConnection(host)
    h.putrequest('POST', selector)
    h.putheader('content-type', content_type)
    h.putheader('content-length', str(len(body)))
    response = h.getresponse()
    output = response.read()
    return output
    # return h.file.read()
def encode_multipart_formdata(fields, files):
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
    L.append('--' + BOUNDARY + '--')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
## end of http://code.activestate.com/recipes/146306/ }}}
## Put editor contents in a file to send to Docverter.
text = editor.get_text()

#Check if the document starts with mmd metadata:
if re.match('^\\w+:', text):
	#Find the first empty line:
	empty_line_match = re.search('^\\s*$', text, re.MULTILINE)
	if empty_line_match:
		#Remove the metadata block from the text:
		input_text = text[empty_line_match.end(0):]
	input_text = text

f = open("docverterin.txt", "w").write(input_text.encode('utf-8'))

## Use CSS to style your output.
css = """
body{color:#222;font:normal normal 400 100%/1.5em georgia,serif;width:40em;margin:3em auto;}a:link{color:#36C;}a:visited{color:#248;}blockquote,ol,p,ul{display:block;margin:0 0 1.5em;}blockquote{border-left:solid .1em #E4E4E4;color:#515151;padding:0 1.5em 0 1.4em;}code{font:normal normal 87.5%/1.71428571em monospace,sans-serif;}img{display:block;margin:1.5em auto;}pre{display:block;font:normal normal 87.5%/1.71428571em monospace,sans-serif;margin:1.71428571em;}h1{font-size:225%;line-height:1.3334em;margin:0 0 .1666em;}h2{font-size:175%;line-height:1.28571429em;margin:0 0 .35714286em;}h3{font-size:137.5%;line-height:1.3636em;margin:0 0 .5em;}h4,h5,h6{font-size:112.5%;line-height:1.3334em;margin:0 0 .7778em;}ol,ul{list-style-position:outside;padding:0;}ol ol,ol ul,ul ol,ul ul{margin:0 0 .75em 2em;}table{border-collapse:collapse;width:100%;margin:1.5em 0;}td,th{border:solid .1em #000;font-family:sans-serif;font-size:87.5%;line-height:1.71428571em;text-align:center;}.footnote{font-size:.8em;vertical-align:super;}.footnotes ol{font-weight:700;}h1,h2,h3,h4,h5,h6,.footnotes ol li p{font-weight:400;}.proclaim{color: #335E0F;}.explain{color: #3A81AA;}.illustration{color:#E0A51B}@media only screen and (max-device-width: 480px) {body{width:90%;}}

# Use CSS3 Paged Media Module to number pages of PDF, set margins.
page_info = "@page {margin: 1in; @bottom-center{content: counter(page)}}"
c = open("docverter.css", "w").write(css + page_info)

## Set Docverter options and define fields using lists.
## Other options available at http://www.docverter.com/api.html#toc_2
fields = [("from", "markdown"), ("to", "pdf"), ("css", "docverter.css")]
files = [("input_files[]", "docverterin.txt", open("docverterin.txt", "r").read()), ("other_files[]", "docverter.css", open("docverter.css","r").read())]
## Post to Docverter using post_multipart()
output = post_multipart("c.docverter.com", "/convert", fields, files)
## Write output to a PDF file. 
outfile = workflow.get_variable('newTitle')+'.pdf'
buffer = StringIO.StringIO(output)
data = buffer.getvalue()
editor.set_file_contents(outfile, data, 'dropbox')

## Send the filename to the workflow.
Show HUD ?
HUD Text
Input has been stored in Dropbox.
  • 1 Second
  • 2 Seconds
  • 3 Seconds
  • "Success"
  • "Error"