For multi-page renderings, the thumbnail was useless: it was the last page of the index. Instead, we create with ImageMagick a small thumbnail thats displays the cover page and overview page of the multi-page PDF. We take into account landscape/portrait renderings to combine those two images into a single thumbnail with a good ratio.
We directly use subprocess to run the ImageMagick commands, because the Python ImageMagick API is so poorly documented that after spending several hours trying to figure out which method to use, switching to subprocess with ImageMagick commands turned out to be a more reasonable solution. Signed-off-by: Thomas Petazzoni <[email protected]> --- INSTALL | 5 ++++- scripts/render.py | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/INSTALL b/INSTALL index b01a1ee..b1bafc9 100644 --- a/INSTALL +++ b/INSTALL @@ -23,10 +23,13 @@ MapOSMatic depends on : * JSON (any python-*json package should work). + * ImageMagick, for rendering the thumbnails of multi-page maps + On an debian/ubuntu installation, the following should be enough: sudo aptitude install python-django python-psycopg2 \ - python-feedparser python-imaging gettext + python-feedparser python-imaging gettext \ + imagemagick You will also most likely need a working PostGIS installation for the entire pipeline to run. See the INSTALL documentation of OcitySMap for diff --git a/scripts/render.py b/scripts/render.py index e3a78b5..4a975fc 100755 --- a/scripts/render.py +++ b/scripts/render.py @@ -28,6 +28,7 @@ import logging import os import sys import threading +import subprocess import ocitysmap2 import ocitysmap2.coords @@ -135,6 +136,38 @@ class JobRenderer(threading.Thread): ctypes.pythonapi.PyThreadState_SetAsyncExc(self.__get_my_tid(), 0) raise SystemError("PyThreadState_SetAsync failed") + def _gen_thumbnail(self, prefix, paper_width_mm, paper_height_mm): + l.info('Creating map thumbnail...') + if self.job.layout == "multi_page": + # Depending on whether we're rendering landscape or + # portrait, adapt how the tiling is done. + if paper_width_mm > paper_height_mm: + tile = "1x2" + else: + tile = "2x1" + + # With the 'montage' command from ImageMagick, create an + # image with the first two pages of the PDF (cover page + # and overview page). + montage_cmd = [ "montage", "-tile", tile, "%s.pdf[0]" % prefix, + "%s.pdf[2]" % prefix, "-geometry", "+10+10", + "-shadow", "%s%s" % (prefix, THUMBNAIL_SUFFIX) ] + ret = subprocess.call(montage_cmd) + if ret != 0: + return + + # And now scale it to the normal thumbnail size + mogrify_cmd = [ "mogrify", "-scale", "200x200", + "%s%s" % (prefix, THUMBNAIL_SUFFIX) ] + ret = subprocess.call(mogrify_cmd) + if ret != 0: + return + else: + if 'png' in RENDERING_RESULT_FORMATS: + img = Image.open(prefix + '.png') + img.thumbnail((200, 200), Image.ANTIALIAS) + img.save(prefix + THUMBNAIL_SUFFIX) + def run(self): """Renders the given job, encapsulating all processing errors and exceptions. @@ -188,11 +221,8 @@ class JobRenderer(threading.Thread): RENDERING_RESULT_FORMATS, prefix) # Create thumbnail - if 'png' in RENDERING_RESULT_FORMATS: - l.info('Creating map thumbnail...') - img = Image.open(prefix + '.png') - img.thumbnail((200, 200), Image.ANTIALIAS) - img.save(prefix + THUMBNAIL_SUFFIX) + self._gen_thumbnail(prefix, config.paper_width_mm, + config.paper_height_mm) self.result = RESULT_SUCCESS l.info("Finished rendering of job #%d." % self.job.id) -- 1.7.4.1
