Fix exception of Pillow for SVGs

Review Request #10851 — Created Jan. 24, 2020 and submitted — Latest diff uploaded

Information

Djblets
release-1.0.x
a93b0d8...

Reviewers

If someone uploads a SVG as file attachment
Review Boards tries to generate a thumbnail.

Pillow do not support SVGs and throws an exception.

https://github.com/python-pillow/Pillow/issues/3509

 - djblets.util.templatetags.djblets_images - Error thumbnailing image file uploaded/files/2020/01/24/d6a12e49-05b7-42d9-bd6c-50985fd98f8e__check.svg and saving as uploaded/files/2020/01/24/d6a12e49-05b7-42d9-bd6c-50985fd98f8e__check_600.svg: cannot identify image file <cStringIO.StringI object at 0x7ff6a9b57b58>
Traceback (most recent call last):
  File "/opt/reviewboard/dist/lib/python2.7/site-packages/djblets/util/templatetags/djblets_images.py", line 126, in thumbnail
    image = Image.open(data)
  File "/opt/reviewboard/dist/lib/python2.7/site-packages/PIL/Image.py", line 2705, in open
    % (filename if filename else fp))
IOError: cannot identify image file <cStringIO.StringI object at 0x7ff6a9b57b58>

As SVG do not need thumbnail because Browsers can
scale that without a problem we can provide
the original file here.

Added an SVG file and saw that the thumbnail exists
instead of an error 404.

Diff Revision 4 (Latest)

orig
1
2
3
4
djblets/util/templatetags/djblets_images.py
djblets/util/templatetags/djblets_images.py
Revision 53e954809457dd8acf459e59982c6297a2e6ca19 New Change
23 lines
24
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25

    
   
25

   
26
from __future__ import division, unicode_literals
26
from __future__ import division, unicode_literals
27

    
   
27

   
28
import logging
28
import logging

    
   
29
import os
29
import re
30
import re
30

    
   
31

   
31
from django import template
32
from django import template
32
from django.template import TemplateSyntaxError
33
from django.template import TemplateSyntaxError
33
from django.utils import six
34
from django.utils import six
34
from django.utils.html import format_html, format_html_join
35
from django.utils.html import format_html, format_html_join
35
from django.utils.six.moves import cStringIO as StringIO
36
from django.utils.six.moves import cStringIO as StringIO
36
from django.utils.translation import ugettext as _
37
from django.utils.translation import ugettext as _
37
from PIL import Image
38
from PIL import Image

    
   
39
from PIL.Image import registered_extensions
38

    
   
40

   
39
from djblets.util.decorators import blocktag
41
from djblets.util.decorators import blocktag
40

    
   
42

   
41

    
   
43

   
42
logger = logging.getLogger(__name__)
44
logger = logging.getLogger(__name__)
47 lines
def thumbnail(f, size='400x100'):
90
    This will create a thumbnail of the given ``file`` (a Django FileField or
92
    This will create a thumbnail of the given ``file`` (a Django FileField or
91
    ImageField) with the given size. Size can either be a string of WxH (in
93
    ImageField) with the given size. Size can either be a string of WxH (in
92
    pixels), or a 2-tuple. If the size is a tuple and the second part is None,
94
    pixels), or a 2-tuple. If the size is a tuple and the second part is None,
93
    it will be calculated to preserve the aspect ratio.
95
    it will be calculated to preserve the aspect ratio.
94

    
   
96

   

    
   
97
    If the image format is not registered in PIL the thumbnail is not generated

    
   
98
    and returned as-is.

    
   
99

   
95
    This will return the URL to the stored thumbnail.
100
    This will return the URL to the stored thumbnail.
96
    """
101
    """

    
   
102
    storage = f.storage

    
   
103
    ext = os.path.splitext(f.name)[1].lower()

    
   
104
    if ext not in registered_extensions():

    
   
105
        return storage.url(f.name)

    
   
106

   
97
    if isinstance(size, six.string_types):
107
    if isinstance(size, six.string_types):
98
        x, y = (int(x) for x in size.split('x'))
108
        x, y = (int(x) for x in size.split('x'))
99
        size_str = size
109
        size_str = size
100
    elif isinstance(size, tuple):
110
    elif isinstance(size, tuple):
101
        x, y = size
111
        x, y = size
11 lines
def thumbnail(f, size='400x100'):
113
        miniature = '%s_%s.%s' % (basename, size_str, format)
123
        miniature = '%s_%s.%s' % (basename, size_str, format)
114
    else:
124
    else:
115
        basename = filename
125
        basename = filename
116
        miniature = '%s_%s' % (basename, size_str)
126
        miniature = '%s_%s' % (basename, size_str)
117

    
   
127

   
118
    storage = f.storage

   
119

    
   

   
120
    if not storage.exists(miniature):
128
    if not storage.exists(miniature):
121
        try:
129
        try:
122
            f = storage.open(filename, 'rb')
130
            f = storage.open(filename, 'rb')
123
            data = StringIO(f.read())
131
            data = StringIO(f.read())
124
            f.close()
132
            f.close()
160 lines
Loading...