misc: add |convert_image_format filter tag (#86003)
gitea/wcs/pipeline/head This commit looks good
Details
gitea/wcs/pipeline/head This commit looks good
Details
This commit is contained in:
parent
16d1e680d0
commit
445dac2e9b
|
@ -43,7 +43,8 @@ Depends: graphviz,
|
|||
uwsgi-plugin-python3,
|
||||
${misc:Depends},
|
||||
${python3:Depends},
|
||||
Recommends: libreoffice-writer-nogui | libreoffice-writer,
|
||||
Recommends: graphicsmagick,
|
||||
libreoffice-writer-nogui | libreoffice-writer,
|
||||
poppler-utils,
|
||||
python3-docutils,
|
||||
python3-langdetect,
|
||||
|
|
|
@ -2,6 +2,8 @@ import datetime
|
|||
import html
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django.test import override_settings
|
||||
|
@ -1696,3 +1698,83 @@ def test_details_format(pub):
|
|||
pub.loggederror_class.wipe()
|
||||
assert tmpl.render(context) == 'String:\n foo'
|
||||
assert pub.loggederror_class.count() == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('image_format', ['jpeg', 'png', 'pdf'])
|
||||
def test_convert_image_format(pub, image_format):
|
||||
with pub.complex_data():
|
||||
img = Template('{{ url|qrcode|convert_image_format:"%s" }}' % image_format).render(
|
||||
{'url': 'http://example.com/', 'allow_complex': True}
|
||||
)
|
||||
assert pub.has_cached_complex_data(img)
|
||||
value = pub.get_cached_complex_data(img)
|
||||
assert value.orig_filename == 'qrcode.%s' % image_format
|
||||
assert value.content_type == {'jpeg': 'image/jpeg', 'png': 'image/png', 'pdf': 'application/pdf'}.get(
|
||||
image_format
|
||||
)
|
||||
with value.get_file_pointer() as fp:
|
||||
if image_format in ('jpeg', 'png'):
|
||||
img = PIL.Image.open(fp)
|
||||
assert img.format == image_format.upper()
|
||||
assert img.size == (330, 330)
|
||||
assert (
|
||||
zbar_decode_qrcode(img, symbols=[ZBarSymbol.QRCODE])[0].data.decode()
|
||||
== 'http://example.com/'
|
||||
)
|
||||
else:
|
||||
assert b'%PDF-' in fp.read()[:200]
|
||||
|
||||
|
||||
def test_convert_image_format_no_name(pub):
|
||||
with pub.complex_data():
|
||||
img = Template('{{ url|qrcode|rename_file:""|convert_image_format:"jpeg" }}').render(
|
||||
{'url': 'http://example.com/', 'allow_complex': True}
|
||||
)
|
||||
assert pub.has_cached_complex_data(img)
|
||||
value = pub.get_cached_complex_data(img)
|
||||
assert value.orig_filename == 'file.jpeg'
|
||||
|
||||
|
||||
def test_convert_image_format_errors(pub):
|
||||
pub.loggederror_class.wipe()
|
||||
with pub.complex_data():
|
||||
img = Template('{{ "xxx"|convert_image_format:"gif" }}').render({'allow_complex': True})
|
||||
assert pub.has_cached_complex_data(img)
|
||||
assert pub.get_cached_complex_data(img) is None
|
||||
assert pub.loggederror_class.count() == 1
|
||||
assert (
|
||||
pub.loggederror_class.select()[0].summary
|
||||
== '|convert_image_format: unknown format (must be one of jpeg, pdf, png)'
|
||||
)
|
||||
|
||||
pub.loggederror_class.wipe()
|
||||
with pub.complex_data():
|
||||
img = Template('{{ "xxx"|convert_image_format:"jpeg" }}').render({'allow_complex': True})
|
||||
assert pub.has_cached_complex_data(img)
|
||||
assert pub.get_cached_complex_data(img) is None
|
||||
assert pub.loggederror_class.count() == 1
|
||||
assert pub.loggederror_class.select()[0].summary == '|convert_image_format: missing input'
|
||||
|
||||
pub.loggederror_class.wipe()
|
||||
with mock.patch('subprocess.run', side_effect=FileNotFoundError()):
|
||||
with pub.complex_data():
|
||||
img = Template('{{ url|qrcode|convert_image_format:"jpeg" }}').render(
|
||||
{'url': 'http://example.com/', 'allow_complex': True}
|
||||
)
|
||||
assert pub.has_cached_complex_data(img)
|
||||
assert pub.get_cached_complex_data(img) is None
|
||||
assert pub.loggederror_class.count() == 1
|
||||
assert pub.loggederror_class.select()[0].summary == '|convert_image_format: not supported'
|
||||
|
||||
pub.loggederror_class.wipe()
|
||||
with mock.patch(
|
||||
'subprocess.run', side_effect=subprocess.CalledProcessError(returncode=-1, cmd='xx', stderr=b'xxx')
|
||||
):
|
||||
with pub.complex_data():
|
||||
img = Template('{{ url|qrcode|convert_image_format:"jpeg" }}').render(
|
||||
{'url': 'http://example.com/', 'allow_complex': True}
|
||||
)
|
||||
assert pub.has_cached_complex_data(img)
|
||||
assert pub.get_cached_complex_data(img) is None
|
||||
assert pub.loggederror_class.count() == 1
|
||||
assert pub.loggederror_class.select()[0].summary == '|convert_image_format: conversion error (xxx)'
|
||||
|
|
|
@ -24,6 +24,7 @@ import math
|
|||
import os
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
from decimal import Decimal
|
||||
from decimal import DivisionByZero as DecimalDivisionByZero
|
||||
|
@ -1086,6 +1087,58 @@ def rename_file(value, new_name):
|
|||
return file_object
|
||||
|
||||
|
||||
@register.filter
|
||||
def convert_image_format(value, new_format):
|
||||
from wcs.fields import FileField
|
||||
|
||||
formats = {
|
||||
'jpeg': 'image/jpeg',
|
||||
'pdf': 'application/pdf',
|
||||
'png': 'image/png',
|
||||
}
|
||||
if new_format not in formats:
|
||||
get_publisher().record_error(
|
||||
_('|convert_image_format: unknown format (must be one of %s)') % ', '.join(formats.keys())
|
||||
)
|
||||
return None
|
||||
|
||||
try:
|
||||
file_object = FileField.convert_value_from_anything(value)
|
||||
except ValueError:
|
||||
file_object = None
|
||||
if not file_object:
|
||||
get_publisher().record_error(_('|convert_image_format: missing input'))
|
||||
return None
|
||||
|
||||
if file_object.base_filename:
|
||||
current_name, current_format = os.path.splitext(file_object.base_filename)
|
||||
if current_format == f'.{new_format}':
|
||||
return file_object
|
||||
new_name = f'{current_name}.{new_format}'
|
||||
else:
|
||||
new_name = '%s.%s' % (_('file'), new_format)
|
||||
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
['gm', 'convert', '-', f'{new_format}:-'],
|
||||
input=file_object.get_content(),
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
get_publisher().record_error(_('|convert_image_format: not supported'))
|
||||
return None
|
||||
except subprocess.CalledProcessError as e:
|
||||
get_publisher().record_error(_('|convert_image_format: conversion error (%s)' % e.stderr.decode()))
|
||||
return None
|
||||
|
||||
new_file_object = FileField.convert_value_from_anything(
|
||||
{'content': proc.stdout, 'filename': new_name, 'content_type': formats[new_format]}
|
||||
)
|
||||
|
||||
return new_file_object
|
||||
|
||||
|
||||
@register.filter
|
||||
def first(value):
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue