Add endpoint for generating an image of a letter

The PDF preview is all good, but it’s hard, finickeity and feels dirty
to embed a PDF in a web page. It’s a more natural thing to embed an
image in a web page.

So this commit adds another endpoint to return an image of a letter
template. It generates this image from the PDF preview, so the stack
looks like:

1. `template.png` (generated in admin)
2. `template.pdf` (generated in admin)
3. HTML preview (generated by a `Renderer` in utils)
4. `Template` instance
5. serialised template from API
6. Template stored in database

The library used to convert the PDF to an image is Wand[1], which binds
to ImageMagick underneath. So in order to get this working locally on a
Mac you will probably need to do:
`brew install imagemagick ghostscript cairo pango`.

To get it working on Ubuntu/EC2 is an exercise left to the reader…

1. http://docs.wand-py.org/en/0.4.4/
This commit is contained in:
Chris Hill-Scott
2016-11-28 11:01:39 +00:00
parent d0f90eac7e
commit 43296469d6
6 changed files with 34 additions and 3 deletions

View File

@@ -25,7 +25,7 @@ Languages needed
- [Node](https://nodejs.org/) 5.0.0 or greater - [Node](https://nodejs.org/) 5.0.0 or greater
- [npm](https://www.npmjs.com/) 3.0.0 or greater - [npm](https://www.npmjs.com/) 3.0.0 or greater
```shell ```shell
brew install node brew install node imagemagick ghostscript cairo pango
``` ```
[NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing [NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing

View File

@@ -1,6 +1,7 @@
$outline-width: 5px; $outline-width: 5px;
.letter { .letter {
font-family: Helvetica, Arial, sans-serif; font-family: Helvetica, Arial, sans-serif;
box-shadow: box-shadow:
1px 1px 0 0 $panel-colour, 1px 1px 0 0 $panel-colour,
@@ -8,6 +9,16 @@ $outline-width: 5px;
-1px 1px 0 0 $panel-colour, -1px 1px 0 0 $panel-colour,
-2px 2px 0 0 rgba($panel-colour, 0.5); -2px 2px 0 0 rgba($panel-colour, 0.5);
outline: $outline-width solid rgba($text-colour, 0.1); outline: $outline-width solid rgba($text-colour, 0.1);
padding: 20px; padding: 0;
margin: $outline-width $outline-width $gutter; margin: $outline-width $outline-width $gutter;
a {
display: block;
}
img {
display: block;
max-width: 100%;
}
} }

View File

@@ -1,10 +1,12 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from io import BytesIO
from string import ascii_uppercase from string import ascii_uppercase
from flask import request, render_template, redirect, url_for, flash, abort from flask import request, render_template, redirect, url_for, flash, abort, send_file
from flask_login import login_required from flask_login import login_required
from flask_weasyprint import HTML, render_pdf from flask_weasyprint import HTML, render_pdf
from dateutil.parser import parse from dateutil.parser import parse
from wand.image import Image
from notifications_utils.template import Template from notifications_utils.template import Template
from notifications_utils.recipients import first_column_headings from notifications_utils.recipients import first_column_headings
@@ -64,6 +66,20 @@ def view_letter_template_as_pdf(service_id, template_id):
return render_pdf(HTML(string=template.rendered)) return render_pdf(HTML(string=template.rendered))
@main.route("/services/<service_id>/templates/<template_id>.png")
@login_required
@user_has_permissions('view_activity', admin_override=True)
def view_letter_template_as_image(service_id, template_id):
output = BytesIO()
with Image(
blob=view_letter_template_as_pdf(service_id, template_id).get_data()
) as image:
with image.convert('png') as converted:
converted.save(file=output)
output.seek(0)
return send_file(output, mimetype='image/png')
@main.route("/services/<service_id>/templates/<template_id>/version/<int:version>") @main.route("/services/<service_id>/templates/<template_id>/version/<int:version>")
@login_required @login_required
@user_has_permissions( @user_has_permissions(

View File

@@ -34,6 +34,8 @@ RUN \
zlib1g-dev \ zlib1g-dev \
libpango1.0-dev \ libpango1.0-dev \
libcairo2-dev \ libcairo2-dev \
libmagickwand-dev \
ghostscript \
&& echo "Install nodejs" \ && echo "Install nodejs" \
&& cd /tmp \ && cd /tmp \

View File

@@ -18,6 +18,7 @@ pyexcel-xls==0.1.0
pyexcel-xlsx==0.1.0 pyexcel-xlsx==0.1.0
pyexcel-ods3==0.1.1 pyexcel-ods3==0.1.1
pytz==2016.4 pytz==2016.4
wand==0.4.4
git+https://github.com/alphagov/notifications-python-client.git@3.0.1#egg=notifications-python-client==3.0.1 git+https://github.com/alphagov/notifications-python-client.git@3.0.1#egg=notifications-python-client==3.0.1

View File

@@ -44,6 +44,7 @@ def test_should_show_page_for_one_template(
'view, expected_content_type', 'view, expected_content_type',
[ [
('.view_letter_template_as_pdf', 'application/pdf'), ('.view_letter_template_as_pdf', 'application/pdf'),
('.view_letter_template_as_image', 'image/png'),
] ]
) )
@patch("app.main.views.templates.LetterPreview.__call__") @patch("app.main.views.templates.LetterPreview.__call__")