misc: autoconvert HEIC files (#88586)
gitea/wcs/pipeline/head This commit looks good Details

This commit is contained in:
Frédéric Péters 2024-03-24 22:44:28 +01:00
parent e0857ce653
commit 8fd3cdf6b1
3 changed files with 55 additions and 6 deletions

View File

@ -592,3 +592,23 @@ def test_file_download_url_on_wrong_field(pub):
resp = resp.form.submit('submit').follow() # -> submit
formdata = formdef.data_class().select()[0]
app.get(formdata.get_url() + 'files/1/', status=404)
def test_file_auto_convert_heic(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [fields.FileField(id='0', label='field label')]
formdef.store()
formdef.data_class().wipe()
with open(os.path.join(os.path.dirname(__file__), '..', 'image.heic'), 'rb') as fd:
upload = Upload('image.heic', fd.read(), 'image/heic')
resp = get_app(pub).get('/test/')
resp.forms[0]['f0$file'] = upload
resp = resp.forms[0].submit('submit') # -> validation
resp = resp.forms[0].submit('submit') # -> submit
resp = resp.follow()
assert resp.click('image.jpeg').follow().content_type == 'image/jpeg'
assert b'JFIF' in resp.click('image.jpeg').follow().body

BIN
tests/image.heic Normal file

Binary file not shown.

View File

@ -29,6 +29,7 @@ import mimetypes
import os
import random
import re
import subprocess
import sys
import tempfile
import time
@ -1047,12 +1048,6 @@ class FileWithPreviewWidget(CompositeWidget):
self.value.content_type = filetype
if self.max_file_size and hasattr(self.value, 'file_size'):
# validate file size
if self.value.file_size > self.max_file_size_bytes:
self.set_error(_('over file size limit (%s)') % self.max_file_size)
return
if self.file_type:
# validate file type
accepted_file_types = []
@ -1098,6 +1093,40 @@ class FileWithPreviewWidget(CompositeWidget):
) or filetype in blacklisted_file_types:
self.set_error(_('forbidden file type'))
if self.value.content_type in ('image/heic', 'image/heif') and not get_publisher().has_site_option(
'do-no-transform-heic-files'
):
# convert HEIC files to JPEG
try:
with open(self.value.fp.name, 'rb') as fd:
# libheic will automatically switch image orientation so we need to remove
# EXIF profile to avoid it being applied a second time.
# (graphicsmagick >= 1.3.41 have heif:ignore-transformations=false to avoid
# that).
rc = subprocess.run(
['gm', 'convert', '+profile', '"*"', 'HEIC:-', 'JPEG:-'],
input=fd.read(),
capture_output=True,
check=True,
)
from wcs.fields.file import FileField
self.value = FileField.convert_value_from_anything(
{
'content': rc.stdout,
'filename': os.path.splitext(self.value.base_filename)[0] + '.jpeg',
'content_type': 'image/jpeg',
}
)
except subprocess.CalledProcessError:
pass
if self.max_file_size and hasattr(self.value, 'file_size'):
# validate file size
if self.value.file_size > self.max_file_size_bytes:
self.set_error(_('over file size limit (%s)') % self.max_file_size)
return
class EmailWidget(StringWidget):
HTML_TYPE = 'email'