Projet

Général

Profil

0001-misc-add-support-for-thumbnailing-PDF-files-26632.patch

Frédéric Péters, 22 septembre 2018 13:59

Télécharger (7,82 ko)

Voir les différences:

Subject: [PATCH] misc: add support for thumbnailing PDF files (#26632)

 debian/control         |  3 ++-
 wcs/fields.py          |  4 ++--
 wcs/forms/common.py    | 13 ++++++-------
 wcs/forms/root.py      |  6 +++---
 wcs/qommon/form.py     | 15 ++++++++++++---
 wcs/qommon/misc.py     | 29 ++++++++++++++++++++++++-----
 wcs/qommon/sessions.py |  8 ++++++++
 7 files changed, 57 insertions(+), 21 deletions(-)
debian/control
25 25
    python-qrcode,
26 26
    libjs-leaflet,
27 27
    python-magic,
28
    python-docutils
28
    python-docutils,
29
    graphicsmagick
29 30
Suggests: python-libxml2,
30 31
    python-lasso,
31 32
    python-psycopg2
wcs/fields.py
33 33
from qommon import _
34 34
from qommon import evalutils
35 35
from qommon.form import *
36
from qommon.misc import localstrftime, strftime, date_format, ellipsize
36
from qommon.misc import localstrftime, strftime, date_format, ellipsize, can_thumbnail
37 37
from qommon.template import Template, TemplateError
38 38
from qommon import get_cfg, get_logger
39 39

  
......
907 907
        t = TemplateIO(html=True)
908 908
        t += htmltext('<div class="file-field">')
909 909
        t += htmltext('<a download="%s" href="[download]?f=%s">') % (value.base_filename, self.id)
910
        if value.content_type and value.content_type.startswith('image/'):
910
        if can_thumbnail(value.content_type):
911 911
            t += htmltext('<img alt="" src="[download]?f=%s&thumbnail=1"/>') % self.id
912 912
        t += htmltext('<span>%s</span>') % value
913 913
        t += htmltext('</a></div>')
wcs/forms/common.py
81 81
                response.set_header(
82 82
                        'content-disposition', 'attachment; filename="%s"' % file.base_filename)
83 83

  
84
        fp = file.get_file_pointer()
85
        if self.thumbnails and file.content_type.startswith('image/'):
84
        if self.thumbnails and misc.can_thumbnail(file.content_type):
86 85
            try:
87
                thumbnail = misc.get_thumbnail(fp)
88
            except misc.ThumbnailError:
89
                pass
90
            else:
86
                thumbnail = misc.get_thumbnail(file.get_filename(),
87
                        content_type=file.content_type)
91 88
                response.set_content_type('image/png')
92 89
                return thumbnail
90
            except misc.ThumbnailError:
91
                pass
93 92

  
94
        return fp.read()
93
        return file.get_file_pointer().read()
95 94

  
96 95

  
97 96
class FilesDirectory(Directory):
wcs/forms/root.py
1114 1114
        if tempfile['charset']:
1115 1115
            response.set_charset(tempfile['charset'])
1116 1116

  
1117
        file_pointer = get_session().get_tempfile_content(t).get_file_pointer()
1118 1117
        if get_request().form.get('thumbnail') == '1':
1119 1118
            try:
1120
                thumbnail = misc.get_thumbnail(file_pointer)
1119
                thumbnail = misc.get_thumbnail(get_session().get_tempfile_path(t),
1120
                        content_type=tempfile['content_type'])
1121 1121
            except misc.ThumbnailError:
1122 1122
                pass
1123 1123
            else:
1124 1124
                response.set_content_type('image/png')
1125 1125
                return thumbnail
1126
        return file_pointer.read()
1126
        return get_session().get_tempfile_content(t).get_file_pointer().read()
1127 1127

  
1128 1128
    def validating(self, data):
1129 1129
        self.html_top(self.formdef.name)
wcs/qommon/form.py
71 71
from qommon import _, ngettext
72 72
import misc
73 73
from .humantime import humanduration2seconds, seconds2humanduration, timewords
74
from .misc import strftime, C_
74
from .misc import strftime, C_, HAS_GM
75 75
from publisher import get_cfg
76 76
from .template_utils import render_block_to_string
77 77

  
......
696 696
        if not temp:
697 697
            return False
698 698

  
699
        filetype = mimetypes.guess_type(temp.get('orig_filename', ''))
700
        if not (filetype and filetype[0] and filetype[0].startswith('image')):
699
        filetype = (mimetypes.guess_type(temp.get('orig_filename', '')) or [''])[0]
700
        if filetype == 'application/pdf':
701
            return HAS_GM
702

  
703
        if not filetype.startswith('image/'):
701 704
            return False
702 705

  
703 706
        if Image:
......
819 822
        # quack like UploadedFile
820 823
        return self.get_file_pointer()
821 824

  
825
    def get_filename(self):
826
        if not hasattr(self, 'qfilename'):
827
            raise AttributeError('filename')
828
        basedir = os.path.join(get_publisher().app_dir, 'uploads')
829
        return os.path.join(basedir, self.qfilename)
830

  
822 831
    def get_content(self):
823 832
        if hasattr(self, 'qfilename'):
824 833
            filename = os.path.join(get_publisher().app_dir, 'uploads', self.qfilename)
wcs/qommon/misc.py
51 51
from urllib2 import urlparse
52 52
from cStringIO import StringIO
53 53

  
54
try:
55
    subprocess.check_call(['which', 'gm'], stdout=open('/dev/null', 'w'))
56
    HAS_GM = True
57
except subprocess.CalledProcessError:
58
    HAS_GM = False
59

  
54 60

  
55 61
class ThumbnailError(Exception):
56 62
    pass
......
553 559
        digest.update(chunk)
554 560
    return digest.hexdigest()
555 561

  
556
def get_thumbnail(fp):
557
    if Image is None:
562

  
563
def can_thumbnail(content_type):
564
    if content_type == 'application/pdf' and not (HAS_GM and Image):
565
        return False
566
    if content_type and content_type.startswith('image/'):
567
        return bool(Image is not None)
568
    return False
569

  
570

  
571
def get_thumbnail(filepath, content_type=None):
572
    if not can_thumbnail(content_type or ''):
558 573
        raise ThumbnailError()
559 574

  
575
    if content_type == 'application/pdf':
576
        fp = StringIO(subprocess.check_output(
577
                ['gm', 'convert', '-geometry', '500x', filepath, 'png:-']))
578
    else:
579
        fp = open(filepath)
580

  
560 581
    try:
561 582
        image = Image.open(fp)
562 583
        image.thumbnail((500, 300))
563 584
        image_thumb_fp = StringIO()
564 585
        image.save(image_thumb_fp, "PNG")
565 586
    except IOError:
566
        # failed to create thumbnail; restore file pointer state and raise
567
        # exception.
568
        fp.seek(0)
587
        # failed to create thumbnail.
569 588
        raise ThumbnailError()
570 589
    return image_thumb_fp.getvalue()
571 590

  
wcs/qommon/sessions.py
303 303
            return None
304 304
        return misc.json_loads(open(filename).read())
305 305

  
306
    def get_tempfile_path(self, token):
307
        temp = self.get_tempfile(token)
308
        if not temp:
309
            return None
310
        dirname = os.path.join(get_publisher().app_dir, 'tempfiles')
311
        filename = os.path.join(dirname, temp['unsigned_token'])
312
        return filename
313

  
306 314
    def get_tempfile_content(self, token):
307 315
        temp = self.get_tempfile(token)
308 316
        if not temp:
309
-