Skip to content

Commit 6a8d981

Browse files
authored
Feat: add heif upload support (*.heic, e.g., for iOS devices) (#1375)
* Add heif support through pillow-heif * fix isort * Mark no cover * Pin Pillow to <10 for tests
1 parent 46e7e28 commit 6a8d981

File tree

8 files changed

+48
-5
lines changed

8 files changed

+48
-5
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ CHANGELOG
1010
* Add an edit button to the file widget which opens edit file pop-up
1111
* Refactored directory list view for significant performance increases
1212
* Remove thumbnail generation from the directory list view request response cycle
13+
* Support for upload of webp images
14+
* Optional support for upload of heif images
1315
* Add Django 4.2 support
1416
* Add thumbnail view for faster visual management of image libraries
1517
* Fix File.objects.only() query required for deleting user who own files.

docs/installation.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ The easiest way to get ``django-filer`` is simply install it with `pip`_::
1010

1111
$ pip install django-filer
1212

13+
Optional heic support
14+
---------------------
15+
16+
Currently, django-filer supports upload of heif images (``*.heic``, such as
17+
retrieved from iOS devices by airdrop) using an optional dependency::
18+
19+
$ pip install django-filer\[heif\]
20+
1321

1422
Dependencies
1523
------------
@@ -31,6 +39,11 @@ check `Pillow doc`_.
3139
* for `Django`_ >=3.0 use `django-polymorphic`_ >=2.1
3240
* for `Django`_ >=3.1 use `django-polymorphic`_ >=3.0
3341

42+
If heif support is chosen, django-filer also installs
43+
44+
* pillow-heif
45+
46+
3447
Configuration
3548
-------------
3649

filer/apps.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ class FilerConfig(AppConfig):
88
name = 'filer'
99
verbose_name = _("Filer")
1010

11-
def ready(self):
11+
def register_optional_heif_supprt(self):
12+
try: # pragma: no cover
13+
from pillow_heif import register_heif_opener
14+
15+
from .settings import IMAGE_EXTENSIONS, IMAGE_MIME_TYPES
16+
17+
register_heif_opener()
18+
IMAGE_EXTENSIONS += [".heic", ".heics", ".heif", ".heifs", ".hif"]
19+
IMAGE_MIME_TYPES.append("heic")
20+
except (ModuleNotFoundError, ImportError):
21+
# No heif support installed
22+
pass
23+
24+
def resolve_validators(self):
1225
"""Resolve dotted path file validators"""
1326

1427
import importlib
@@ -37,3 +50,7 @@ def ready(self):
3750
except (ImportError, ModuleNotFoundError, AttributeError):
3851
raise ImproperlyConfigured(f"""filer: could not import validator "{item}".""")
3952
self.FILE_VALIDATORS[mime_type] = functions
53+
54+
def ready(self):
55+
self.resolve_validators()
56+
self.register_optional_heif_supprt()

filer/management/commands/import_files.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ def import_file(self, file_obj, folder):
2525
"""
2626
Create a File or an Image into the given folder
2727
"""
28+
from ...settings import IMAGE_EXTENSIONS
2829
try:
2930
iext = os.path.splitext(file_obj.name)[1].lower()
3031
except: # noqa
3132
iext = ''
32-
if iext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']:
33+
if iext in IMAGE_EXTENSIONS:
3334
obj, created = Image.objects.get_or_create(
3435
original_filename=file_obj.name,
3536
file=file_obj,

filer/models/abstract.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ class Meta:
8383
@classmethod
8484
def matches_file_type(cls, iname, ifile, mime_type):
8585
# source: https://www.freeformatter.com/mime-types-list.html
86-
image_subtypes = ['gif', 'jpeg', 'png', 'x-png', 'svg+xml', 'webp']
86+
from ..settings import IMAGE_MIME_TYPES
8787
maintype, subtype = mime_type.split('/')
88-
return maintype == 'image' and subtype in image_subtypes
88+
return maintype == 'image' and subtype in IMAGE_MIME_TYPES
8989

9090
def file_data_changed(self, post_init=False):
9191
attrs_updated = super().file_data_changed(post_init=post_init)

filer/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ def update_server_settings(settings, defaults, s, t):
281281
}
282282

283283
DEFERRED_THUMBNAIL_SIZES = (40, 80, 160)
284+
IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
285+
IMAGE_MIME_TYPES = ['gif', 'jpeg', 'png', 'x-png', 'svg+xml', 'webp']
284286

285287
FILE_VALIDATORS = {
286288
"text/html": ["filer.validation.deny_html"],

setup.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
]
1212

1313

14+
EXTRA_REQUIREMENTS = {
15+
"heif": [
16+
"pillow-heif",
17+
],
18+
}
19+
20+
1421
CLASSIFIERS = [
1522
'Development Status :: 5 - Production/Stable',
1623
'Environment :: Web Environment',
@@ -61,6 +68,7 @@
6168
include_package_data=True,
6269
zip_safe=False,
6370
install_requires=REQUIREMENTS,
71+
extras_require=EXTRA_REQUIREMENTS,
6472
python_requires='>=3.8',
6573
classifiers=CLASSIFIERS,
6674
test_suite='tests.settings.run',

tests/requirements/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# requirements from setup.py
2-
Pillow
2+
Pillow<10 # Remove pinning for 3.0.0 release
33

44
# other requirements
55
coverage

0 commit comments

Comments
 (0)