produire des vignettes pour les fichiers SVG (#75505) #176

Merged
fpeters merged 2 commits from wip/75505-La-production-de-vignettes-pour into main 2023-03-31 10:34:41 +02:00
4 changed files with 55 additions and 7 deletions

View File

@ -1,5 +1,6 @@
import os
import re
import urllib.parse
import pytest
import responses
@ -413,3 +414,37 @@ def test_form_file_field_prefill(pub):
formdata = formdef.data_class().select()[0]
assert formdata.data['0'].base_filename == 'qrcode.png'
assert formdata.data['0'].get_content().startswith(b'\x89PNG')
SVG_CONTENT = b'''<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 63.72 64.25" style="enable-background:new 0 0 63.72 64.25;" xml:space="preserve"> <g> </g> </svg>'''
def test_form_file_svg_thumbnail(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [fields.FileField(id='0', label='file')]
formdef.store()
formdef.data_class().wipe()
upload = Upload('test.svg', SVG_CONTENT, 'image/svg+xml')
app = get_app(pub)
resp = app.get('/test/')
resp.forms[0]['f0$file'] = upload
resp = resp.forms[0].submit('submit')
thumbnail_url = resp.pyquery('.fileinfo.thumbnail img')[0].attrib['src']
svg_resp = app.get(urllib.parse.urljoin(resp.request.url, thumbnail_url))
assert svg_resp.body == SVG_CONTENT
assert svg_resp.headers['Content-Type'] == 'image/svg+xml'
resp = resp.forms[0].submit('submit')
assert resp.status_int == 302
resp = resp.follow()
assert 'The form has been recorded' in resp.text
thumbnail_url = resp.pyquery('.file-field img').attr('src')
svg_resp = app.get(urllib.parse.urljoin(resp.request.url, thumbnail_url))
svg_resp = svg_resp.follow()
assert svg_resp.body == SVG_CONTENT
assert svg_resp.headers['Content-Type'] == 'image/svg+xml'

View File

@ -90,14 +90,18 @@ class FileDirectory(Directory):
def serve_file(cls, file, thumbnail=False):
response = get_response()
if misc.is_svg_filetype(file.content_type) and thumbnail:
thumbnail = False
if thumbnail:
if file.can_thumbnail():
try:
content = misc.get_thumbnail(file.get_fs_filename(), content_type=file.content_type)
response.set_content_type('image/png')
return content
except misc.ThumbnailError:
raise errors.TraversalError()
if file.content_type:
try:
content = misc.get_thumbnail(file.get_fs_filename(), content_type=file.content_type)
response.set_content_type('image/png')
return content
except misc.ThumbnailError:
raise errors.TraversalError()
else:
raise errors.TraversalError()
@ -1045,7 +1049,7 @@ class FormdefDirectoryBase(Directory):
if tempfile['charset']:
response.set_charset(tempfile['charset'])
if get_request().form.get('thumbnail') == '1':
if get_request().form.get('thumbnail') == '1' and not misc.is_svg_filetype(tempfile['content_type']):
try:
thumbnail = misc.get_thumbnail(
get_session().get_tempfile_path(t), content_type=tempfile['content_type']

View File

@ -846,6 +846,9 @@ class FileWithPreviewWidget(CompositeWidget):
if not filetype:
return False
if misc.is_svg_filetype(filetype):
return True
if filetype == 'application/pdf':
return HAS_PDFTOPPM

View File

@ -686,6 +686,10 @@ def file_digest(content, chunk_size=100000):
return digest.hexdigest()
def is_svg_filetype(filetype):
return filetype and filetype.split('+')[0] == 'image/svg'
def can_thumbnail(content_type):
if content_type == 'application/pdf':
return bool(HAS_PDFTOPPM and Image)
@ -767,6 +771,8 @@ def get_thumbnail(filepath, content_type=None):
except OSError:
# failed to create thumbnail.
raise ThumbnailError()
finally:
fp.close()
# store thumbnail
with open(thumb_filepath, 'wb') as f: