#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)))
h.endheaders()
h.send(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)
L.append('')
L.append(value)
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('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
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):]
else:
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.
workflow.set_output(outfile)
There are no comments yet.
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.