diff --git a/filer/management/commands/filer_check.py b/filer/management/commands/filer_check.py
index 3a2de61b3..3eb77d12b 100644
--- a/filer/management/commands/filer_check.py
+++ b/filer/management/commands/filer_check.py
@@ -4,6 +4,8 @@
from django.core.management.base import BaseCommand
from django.utils.module_loading import import_string
+from PIL import UnidentifiedImageError
+
from filer import settings as filer_settings
@@ -41,6 +43,13 @@ def add_arguments(self, parser):
default=False,
help="Delete references in database if files are missing in media folder.",
)
+ parser.add_argument(
+ '--image-dimensions',
+ action='store_true',
+ dest='image_dimensions',
+ default=False,
+ help="Look for images without dimensions set, set them accordingly.",
+ )
parser.add_argument(
'--noinput',
'--no-input',
@@ -72,6 +81,8 @@ def handle(self, *args, **options):
self.stdout.write("Aborted: Delete orphaned files from storage.")
return
self.verify_storages(options)
+ if options['image_dimensions']:
+ self.image_dimensions(options)
def verify_references(self, options):
from filer.models.filemodels import File
@@ -112,3 +123,41 @@ def walk(prefix):
filer_public = filer_settings.FILER_STORAGES['public']['main']
storage = import_string(filer_public['ENGINE'])()
walk(filer_public['UPLOAD_TO_PREFIX'])
+
+ def image_dimensions(self, options):
+ from django.db.models import Q
+
+ import easy_thumbnails
+ from easy_thumbnails.VIL import Image as VILImage
+
+ from filer.models.imagemodels import Image
+ from filer.utils.compatibility import PILImage
+
+ no_dimensions = Image.objects.filter(
+ Q(_width=0) | Q(_width__isnull=True)
+ )
+ self.stdout.write(f"trying to set dimensions on {no_dimensions.count()} files")
+ for image in no_dimensions:
+ if image.file_ptr:
+ file_holder = image.file_ptr
+ else:
+ file_holder = image
+ try:
+ imgfile = file_holder.file
+ imgfile.seek(0)
+ except (FileNotFoundError):
+ pass
+ else:
+ if image.file.name.lower().endswith('.svg'):
+ with VILImage.load(imgfile) as vil_image:
+ # invalid svg doesnt throw errors
+ image._width, image._height = vil_image.size
+ else:
+ try:
+ with PILImage.open(imgfile) as pil_image:
+ image._width, image._height = pil_image.size
+ image._transparent = easy_thumbnails.utils.is_transparent(pil_image)
+ except UnidentifiedImageError:
+ continue
+ image.save()
+ return
diff --git a/tests/test_filer_check.py b/tests/test_filer_check.py
index 01b951ca0..f18bd389c 100644
--- a/tests/test_filer_check.py
+++ b/tests/test_filer_check.py
@@ -1,6 +1,6 @@
import os
import shutil
-from io import StringIO
+from io import BytesIO, StringIO
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
@@ -9,10 +9,21 @@
from filer import settings as filer_settings
from filer.models.filemodels import File
+from filer.models.imagemodels import Image
from tests.helpers import create_image
class FilerCheckTestCase(TestCase):
+
+ svg_file_string = """
+
+ """
+
def setUp(self):
# ensure that filer_public directory is empty from previous tests
storage = import_string(filer_settings.FILER_STORAGES['public']['main']['ENGINE'])()
@@ -67,3 +78,81 @@ def test_delete_orphans(self):
call_command('filer_check', delete_orphans=True, interactive=False, verbosity=0)
self.assertFalse(os.path.exists(orphan_file))
+
+ def test_image_dimensions_corrupted_file(self):
+ original_filename = 'testimage.jpg'
+ file_obj = SimpleUploadedFile(
+ name=original_filename,
+ # corrupted!
+ content=create_image().tobytes(),
+ content_type='image/jpeg')
+ self.filer_image = Image.objects.create(
+ file=file_obj,
+ original_filename=original_filename)
+
+ self.filer_image._width = 0
+ self.filer_image.save()
+ call_command('filer_check', image_dimensions=True)
+
+ def test_image_dimensions_file_not_found(self):
+ self.filer_image = Image.objects.create(
+ file="123.jpg",
+ original_filename="123.jpg")
+ call_command('filer_check', image_dimensions=True)
+ self.filer_image.refresh_from_db()
+
+ def test_image_dimensions(self):
+
+ original_filename = 'testimage.jpg'
+ with BytesIO() as jpg:
+ create_image().save(jpg, format='JPEG')
+ jpg.seek(0)
+ file_obj = SimpleUploadedFile(
+ name=original_filename,
+ content=jpg.read(),
+ content_type='image/jpeg')
+ self.filer_image = Image.objects.create(
+ file=file_obj,
+ original_filename=original_filename)
+
+ self.filer_image._width = 0
+ self.filer_image.save()
+
+ call_command('filer_check', image_dimensions=True)
+ self.filer_image.refresh_from_db()
+ self.assertGreater(self.filer_image._width, 0)
+
+ def test_image_dimensions_invalid_svg(self):
+
+ original_filename = 'test.svg'
+ svg_file = bytes("" + self.svg_file_string, "utf-8")
+ file_obj = SimpleUploadedFile(
+ name=original_filename,
+ content=svg_file,
+ content_type='image/svg+xml')
+ self.filer_image = Image.objects.create(
+ file=file_obj,
+ original_filename=original_filename)
+
+ self.filer_image._width = 0
+ self.filer_image.save()
+ call_command('filer_check', image_dimensions=True)
+
+ def test_image_dimensions_svg(self):
+
+ original_filename = 'test.svg'
+ svg_file = bytes(self.svg_file_string, "utf-8")
+ file_obj = SimpleUploadedFile(
+ name=original_filename,
+ content=svg_file,
+ content_type='image/svg+xml')
+ self.filer_image = Image.objects.create(
+ file=file_obj,
+ original_filename=original_filename)
+
+ self.filer_image._width = 0
+ self.filer_image.save()
+
+ call_command('filer_check', image_dimensions=True)
+ self.filer_image.refresh_from_db()
+ self.assertGreater(self.filer_image._width, 0)