diff --git a/app/community/forms.py b/app/community/forms.py index 786b59fc..e537cef7 100644 --- a/app/community/forms.py +++ b/app/community/forms.py @@ -155,7 +155,7 @@ class CreateImageForm(CreatePostForm): def validate(self, extra_validators=None) -> bool: uploaded_file = request.files['image_file'] - if uploaded_file and uploaded_file.filename != '': + if uploaded_file and uploaded_file.filename != '' and not uploaded_file.filename.endswith('.svg'): Image.MAX_IMAGE_PIXELS = 89478485 # Do not allow fascist meme content try: diff --git a/app/community/routes.py b/app/community/routes.py index 06268465..9a6cfa87 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -679,13 +679,14 @@ def add_post(actor, type): Image.MAX_IMAGE_PIXELS = 89478485 # resize if necessary - img = Image.open(final_place) - if '.' + img.format.lower() in allowed_extensions: - img = ImageOps.exif_transpose(img) + if not final_place.endswith('.svg'): + img = Image.open(final_place) + if '.' + img.format.lower() in allowed_extensions: + img = ImageOps.exif_transpose(img) - # limit full sized version to 2000px - img.thumbnail((2000, 2000)) - img.save(final_place) + # limit full sized version to 2000px + img.thumbnail((2000, 2000)) + img.save(final_place) request_json['object']['attachment'] = [{'type': 'Image', 'url': f'https://{current_app.config["SERVER_NAME"]}/{final_place.replace("app/", "")}', 'name': form.image_alt_text.data}] diff --git a/app/community/util.py b/app/community/util.py index d241174b..236e6aeb 100644 --- a/app/community/util.py +++ b/app/community/util.py @@ -25,7 +25,7 @@ from sqlalchemy import func, desc, text import os -allowed_extensions = ['.gif', '.jpg', '.jpeg', '.png', '.webp', '.heic', '.mpo', '.avif'] +allowed_extensions = ['.gif', '.jpg', '.jpeg', '.png', '.webp', '.heic', '.mpo', '.avif', '.svg'] def search_for_community(address: str): @@ -649,30 +649,38 @@ def save_icon_file(icon_file, directory='communities') -> File: if file_ext.lower() == '.heic': register_heif_opener() + elif file_ext.lower() == '.avif': + import pillow_avif # resize if necessary - Image.MAX_IMAGE_PIXELS = 89478485 - img = Image.open(final_place) - if '.' + img.format.lower() in allowed_extensions: - img = ImageOps.exif_transpose(img) - img_width = img.width - img_height = img.height - if img.width > 250 or img.height > 250: - img.thumbnail((250, 250)) - img.save(final_place) + if file_ext.lower() in allowed_extensions: + if file_ext.lower() == '.svg': # svgs don't need to be resized + file = File(file_path=final_place, file_name=new_filename + file_ext, alt_text=f'{directory} icon', + thumbnail_path=final_place) + db.session.add(file) + return file + else: + Image.MAX_IMAGE_PIXELS = 89478485 + img = Image.open(final_place) + img = ImageOps.exif_transpose(img) img_width = img.width img_height = img.height - # save a second, smaller, version as a thumbnail - img.thumbnail((40, 40)) - img.save(final_place_thumbnail, format="WebP", quality=93) - thumbnail_width = img.width - thumbnail_height = img.height + if img.width > 250 or img.height > 250: + img.thumbnail((250, 250)) + img.save(final_place) + img_width = img.width + img_height = img.height + # save a second, smaller, version as a thumbnail + img.thumbnail((40, 40)) + img.save(final_place_thumbnail, format="WebP", quality=93) + thumbnail_width = img.width + thumbnail_height = img.height - file = File(file_path=final_place, file_name=new_filename + file_ext, alt_text=f'{directory} icon', - width=img_width, height=img_height, thumbnail_width=thumbnail_width, - thumbnail_height=thumbnail_height, thumbnail_path=final_place_thumbnail) - db.session.add(file) - return file + file = File(file_path=final_place, file_name=new_filename + file_ext, alt_text=f'{directory} icon', + width=img_width, height=img_height, thumbnail_width=thumbnail_width, + thumbnail_height=thumbnail_height, thumbnail_path=final_place_thumbnail) + db.session.add(file) + return file else: abort(400) @@ -695,6 +703,8 @@ def save_banner_file(banner_file, directory='communities') -> File: if file_ext.lower() == '.heic': register_heif_opener() + elif file_ext.lower() == '.avif': + import pillow_avif # resize if necessary Image.MAX_IMAGE_PIXELS = 89478485 diff --git a/app/static/styles.css b/app/static/styles.css index 060a97ee..80778e70 100644 --- a/app/static/styles.css +++ b/app/static/styles.css @@ -905,6 +905,7 @@ div.navbar { } .post_teaser_image_preview img { max-width: 100%; + min-width: 150px; margin-right: 4px; border-radius: 5px; height: auto; diff --git a/app/static/styles.scss b/app/static/styles.scss index 9b69b5ab..46349396 100644 --- a/app/static/styles.scss +++ b/app/static/styles.scss @@ -501,6 +501,7 @@ div.navbar { } img { max-width: 100%; + min-width: 150px; margin-right: 4px; border-radius: 5px; height: auto; diff --git a/app/templates/community/add_local.html b/app/templates/community/add_local.html index 99609b0c..c7ab04fb 100644 --- a/app/templates/community/add_local.html +++ b/app/templates/community/add_local.html @@ -22,9 +22,9 @@ {{ render_field(form.description) }} {{ render_field(form.icon_file) }} - Provide a square image that looks good when small. + {{ _('Provide a square image that looks good when small. SVG is allowed.') }} {{ render_field(form.banner_file) }} - Provide a wide image - letterbox orientation. + {{ _('Provide a wide image - letterbox orientation.') }} {{ render_field(form.rules) }} {{ render_field(form.nsfw) }} {{ render_field(form.local_only) }} diff --git a/app/utils.py b/app/utils.py index 5f84839b..fb5a6a70 100644 --- a/app/utils.py +++ b/app/utils.py @@ -187,7 +187,7 @@ def make_cache_key(sort=None, post_id=None, view_filter=None): def is_image_url(url): - common_image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.avif'] + common_image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.avif', '.svg+xml', '.svg+xml; charset=utf-8'] mime_type = mime_type_using_head(url) if mime_type: mime_type_parts = mime_type.split('/')