diff options
author | Martin Vilcans <martin@librador.com> | 2014-10-09 14:27:40 +0200 |
---|---|---|
committer | Martin Vilcans <martin@librador.com> | 2014-10-09 14:27:40 +0200 |
commit | cc92ae9a34caa45b912a207ede59d55154a34bff (patch) | |
tree | fcbd1b72fe7d2555060c3654dd6a74363157e374 | |
parent | 8ee8e6158284e2c3f776c814c62fe17b4eebc969 (diff) | |
parent | cc53331eeed6aa5d68587e7dca430b65a7a9bf5c (diff) | |
download | screenplain-cc92ae9a34caa45b912a207ede59d55154a34bff.tar.gz |
Merge branch 'feature/pdf'
Closes #7
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rw-r--r-- | screenplain/export/pdf.py | 152 | ||||
-rw-r--r-- | screenplain/main.py | 5 | ||||
-rwxr-xr-x | setup.py | 3 |
5 files changed, 159 insertions, 4 deletions
diff --git a/.travis.yml b/.travis.yml index b4da1b0..b90b600 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: python python: - "2.7" - - "2.6" install: pip install -r requirements.txt script: bin/test diff --git a/requirements.txt b/requirements.txt index 3d09f64..321e747 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -#reportlab +reportlab unittest2 nose pep8 diff --git a/screenplain/export/pdf.py b/screenplain/export/pdf.py new file mode 100644 index 0000000..b5f0fb0 --- /dev/null +++ b/screenplain/export/pdf.py @@ -0,0 +1,152 @@ +# Copyright (c) 2014 Martin Vilcans +# Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license.php + +from reportlab.lib import pagesizes +from reportlab.platypus import ( + BaseDocTemplate, + Paragraph, + Frame, + PageTemplate, +) +from reportlab import platypus +from reportlab.lib.units import inch +from reportlab.lib.styles import ParagraphStyle +from reportlab.lib.enums import TA_CENTER + +from screenplain.types import ( + Action, Dialog, DualDialog, Transition, Slug +) +from screenplain import types + +lines_per_page = 55 +characters_per_line = 61 +frame_height = 12 * lines_per_page +frame_width = characters_per_line * 72 / 10.0 # Courier pitch is 10 chars/inch +page_width, page_height = pagesizes.letter +left_margin = 1.5 * inch +right_margin = page_width - left_margin - frame_width +top_margin = 1 * inch +bottom_margin = page_height - top_margin - frame_height + +character_width = 1.0 / 10 * inch + +default_style = ParagraphStyle( + 'default', + fontName='Courier', + fontSize=12, + leading=12, + spaceBefore=0, + spaceAfter=0, + leftIndent=0, + rightIndent=0, +) +character_style = ParagraphStyle( + 'character', default_style, + spaceBefore=12, + leftIndent=19 * character_width, + keepWithNext=1, +) +dialog_style = ParagraphStyle( + 'dialog', default_style, + leftIndent=9 * character_width, + rightIndent=frame_width - (45 * character_width), +) +parenthentical_style = ParagraphStyle( + 'parenthentical', default_style, + leftIndent=13 * character_width, + keepWithNext=1, +) +action_style = ParagraphStyle( + 'action', default_style, + spaceBefore=12, +) +centered_action_style = ParagraphStyle( + 'centered-action', action_style, + alignment=TA_CENTER, +) +slug_style = ParagraphStyle( + 'slug', default_style, + spaceBefore=12, + spaceAfter=12, + keepWithNext=1, +) +transition_style = ParagraphStyle( + 'transition', default_style, + spaceBefore=12, + spaceAfter=12, +) + + +class DocTemplate(BaseDocTemplate): + def __init__(self, *args, **kwargs): + frame = Frame( + left_margin, bottom_margin, frame_width, frame_height, + id='normal', + leftPadding=0, topPadding=0, rightPadding=0, bottomPadding=0 + ) + pageTemplates = [ + PageTemplate(id='standard', frames=[frame]) + ] + BaseDocTemplate.__init__( + self, pageTemplates=pageTemplates, *args, **kwargs + ) + + def handle_pageBegin(self): + self.canv.setFont('Courier', 12, leading=12) + page = self.page + 1 + if page >= 2: + self.canv.drawRightString( + left_margin + frame_width, + page_height - 42, + '%s.' % page + ) + self._handle_pageBegin() + + +def add_paragraph(story, para, style): + for line in para.lines: + story.append(Paragraph(line.to_html(), style)) + + +def add_dialog(story, dialog): + story.append(Paragraph(dialog.character.to_html(), character_style)) + for parenthetical, line in dialog.blocks: + if parenthetical: + story.append(Paragraph(line.to_html(), parenthentical_style)) + else: + story.append(Paragraph(line.to_html(), dialog_style)) + + +def add_dual_dialog(story, dual): + # TODO: format dual dialog + add_dialog(story, dual.left) + add_dialog(story, dual.right) + + +def to_pdf(screenplay, output_filename, template_constructor=DocTemplate): + doc = template_constructor( + output_filename, + pagesize=(page_width, page_height), + ) + story = [] + for para in screenplay: + if isinstance(para, Dialog): + add_dialog(story, para) + elif isinstance(para, DualDialog): + add_dual_dialog(story, para) + elif isinstance(para, Action): + add_paragraph( + story, para, + centered_action_style if para.centered else action_style + ) + elif isinstance(para, Slug): + add_paragraph(story, para, slug_style) + elif isinstance(para, Transition): + add_paragraph(story, para, transition_style) + elif isinstance(para, types.PageBreak): + story.append(platypus.PageBreak()) + else: + # Ignore unknown types + pass + doc.build(story) diff --git a/screenplain/main.py b/screenplain/main.py index 6def5af..ac308b5 100644 --- a/screenplain/main.py +++ b/screenplain/main.py @@ -4,7 +4,6 @@ # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license.php -import fileinput import sys import codecs from optparse import OptionParser @@ -12,7 +11,7 @@ from optparse import OptionParser from screenplain.parsers import fountain output_formats = ( - 'fdx', 'html' + 'fdx', 'html', 'pdf' ) usage = """Usage: %prog [options] [input-file [output-file]] @@ -62,6 +61,8 @@ def main(args): format = 'fdx' elif output_file.endswith('.html'): format = 'html' + elif output_file.endswith('.pdf'): + format = 'pdf' else: invalid_format( parser, @@ -9,6 +9,9 @@ setup( author='Martin Vilcans', author_email='screenplain@librador.com', url='http://www.screenplain.com/', + requires=[ + 'reportlab', + ], packages=[ 'screenplain', 'screenplain.export', |