Skip to content

Commit

Permalink
Use custom fonts in generated PDF reports
Browse files Browse the repository at this point in the history
  • Loading branch information
iamjazzar committed Jul 25, 2018
1 parent 6cd863e commit 7ea5cc6
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 5 deletions.
35 changes: 30 additions & 5 deletions eoc_journal/eoc_journal.py
Expand Up @@ -6,12 +6,13 @@
from io import BytesIO
import webob

from django.conf import settings

from lxml import html
from lxml.html.clean import clean_html

from reportlab.lib import pagesizes
from reportlab.lib.colors import Color
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer

from problem_builder.models import Answer
Expand All @@ -22,6 +23,7 @@
from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin

from .pdf_generator import get_style_sheet
from .api_client import ApiClient, calculate_engagement_score
from .course_blocks_api import CourseBlocksApiClient
from .utils import _, normalize_id
Expand Down Expand Up @@ -122,6 +124,14 @@ class EOCJournalXBlock(StudioEditableXBlockMixin, XBlock):
scope=Scope.content,
)

custom_font = String(
display_name=_("Default Font"),
help=_("A URL links to the custom font users are going to "
"generate PDFs in. (You can upload the font on Studio)"),
default=None,
scope=Scope.settings,
)

editable_fields = (
'display_name',
'key_takeaways_pdf',
Expand All @@ -131,6 +141,7 @@ class EOCJournalXBlock(StudioEditableXBlockMixin, XBlock):
'display_metrics_section',
'display_key_takeaways_section',
'display_answers',
'custom_font',
)

def student_view(self, context=None):
Expand Down Expand Up @@ -177,16 +188,18 @@ def serve_pdf(self, request, _suffix):
"""
Builds and serves a PDF document containing user's freeform answers.
"""
styles = getSampleStyleSheet()
font_url = self._add_url_scheme(self.custom_font)
styles = get_style_sheet(font_url=font_url)
pdf_buffer = BytesIO()
course_name = self._get_course_name()

title = _('{course_name} Report'.format(course_name=course_name))
display_name = self.display_name or course_name
report_header_name = self.display_name or course_name
title = _('{course_name} Report'.format(
course_name=course_name))

document = SimpleDocTemplate(pdf_buffer, pagesize=pagesizes.letter, title=title)
story = [
Paragraph(display_name, styles["Title"]),
Paragraph(report_header_name, styles["Title"]),
]

answer_sections = self.list_user_pb_answers_by_section()
Expand Down Expand Up @@ -448,3 +461,15 @@ def _expand_static_url(self, url):
except ImportError:
pass
return url

def _add_url_scheme(self, url):
"""
This is to add a protocol for the url
:param url:
:return:
"""
if url.startswith('http'):
return url

scheme = 'https' if settings.HTTPS == 'on' else 'http'
return '{}://{}'.format(scheme, url)
135 changes: 135 additions & 0 deletions eoc_journal/pdf_generator.py
@@ -0,0 +1,135 @@
"""
Utils around Reportlab customizations
"""

from reportlab.lib.enums import TA_CENTER
from reportlab.lib.fonts import tt2ps
from reportlab.lib.styles import (
getSampleStyleSheet,
StyleSheet1,
ParagraphStyle,
)

import reportlab
import reportlab.rl_config
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont


def get_style_sheet(font_url=None):
"""Returns a custom stylesheet object"""
if not font_url:
return getSampleStyleSheet()

stylesheet = StyleSheet1()

_baseFontName = 'custom'
_baseFontNameB = tt2ps(_baseFontName, 1, 0)
_baseFontNameI = tt2ps(_baseFontName, 0, 1)
_baseFontNameBI = tt2ps(_baseFontName, 1, 1)

font = TTFont(_baseFontName, font_url)
reportlab.rl_config.warnOnMissingFontGlyphs = 0
pdfmetrics.registerFont(font)

stylesheet.add(ParagraphStyle(name='Normal',
fontName=_baseFontName,
fontSize=10,
leading=12)
)

stylesheet.add(ParagraphStyle(name='BodyText',
parent=stylesheet['Normal'],
spaceBefore=6)
)
stylesheet.add(ParagraphStyle(name='Italic',
parent=stylesheet['BodyText'],
fontName=_baseFontNameI)
)

stylesheet.add(ParagraphStyle(name='Heading1',
parent=stylesheet['Normal'],
fontName=_baseFontNameB,
fontSize=18,
leading=22,
spaceAfter=6),
alias='h1')

stylesheet.add(ParagraphStyle(name='Title',
parent=stylesheet['Normal'],
fontName=_baseFontNameB,
fontSize=22,
leading=22,
alignment=TA_CENTER,
spaceAfter=6),
alias='title')

stylesheet.add(ParagraphStyle(name='Heading2',
parent=stylesheet['Normal'],
fontName=_baseFontNameB,
fontSize=14,
leading=18,
spaceBefore=12,
spaceAfter=6),
alias='h2')

stylesheet.add(ParagraphStyle(name='Heading3',
parent=stylesheet['Normal'],
fontName=_baseFontNameBI,
fontSize=12,
leading=14,
spaceBefore=12,
spaceAfter=6),
alias='h3')

stylesheet.add(ParagraphStyle(name='Heading4',
parent=stylesheet['Normal'],
fontName=_baseFontNameBI,
fontSize=10,
leading=12,
spaceBefore=10,
spaceAfter=4),
alias='h4')

stylesheet.add(ParagraphStyle(name='Heading5',
parent=stylesheet['Normal'],
fontName=_baseFontNameB,
fontSize=9,
leading=10.8,
spaceBefore=8,
spaceAfter=4),
alias='h5')

stylesheet.add(ParagraphStyle(name='Heading6',
parent=stylesheet['Normal'],
fontName=_baseFontNameB,
fontSize=7,
leading=8.4,
spaceBefore=6,
spaceAfter=2),
alias='h6')

stylesheet.add(ParagraphStyle(name='Bullet',
parent=stylesheet['Normal'],
firstLineIndent=0,
spaceBefore=3),
alias='bu')

stylesheet.add(ParagraphStyle(name='Definition',
parent=stylesheet['Normal'],
firstLineIndent=0,
leftIndent=36,
bulletIndent=0,
spaceBefore=6,
bulletFontName=_baseFontNameBI),
alias='df')

stylesheet.add(ParagraphStyle(name='Code',
parent=stylesheet['Normal'],
fontName='Courier',
fontSize=8,
leading=8.8,
firstLineIndent=0,
leftIndent=36))

return stylesheet

0 comments on commit 7ea5cc6

Please sign in to comment.