add support for svg images in library 2

This commit is contained in:
Tobias Brunner 2025-07-08 15:24:56 +02:00
parent ff3a09d30c
commit a2489a7651
No known key found for this signature in database
3 changed files with 240 additions and 0 deletions

176
SVG_SUPPORT.md Normal file
View file

@ -0,0 +1,176 @@
# SVG Support in Image Library
## Overview
The Image Library now supports SVG (Scalable Vector Graphics) files alongside traditional raster image formats. This enhancement allows you to upload, manage, and display SVG images with the same ease as JPEG, PNG, and other image formats.
## Supported Formats
The Image Library now supports:
- **Raster Images**: JPEG, PNG, GIF, WebP, BMP, TIFF
- **Vector Images**: SVG
## Features
### 1. SVG File Validation
- SVG files are validated to ensure they contain valid XML structure
- File size limits apply (max 1MB by default)
- MIME type detection for proper handling
### 2. Automatic Dimension Detection
- SVG dimensions are extracted from `width` and `height` attributes
- Falls back to `viewBox` if width/height attributes are missing
- Provides sensible defaults (100x100) if dimensions cannot be determined
### 3. Proper Rendering
- **Template Tags**: SVG images use `<object>` tags for optimal rendering
- **Admin Interface**: SVG thumbnails display correctly in the admin
- **Form Widgets**: SVG previews work in form interfaces
### 4. Template Tag Support
The `image_library_img` template tag automatically handles SVG files:
```html
<!-- This will render an SVG using <object> tag or <img> tag for raster images -->
{% image_library_img "my-svg-logo" css_class="logo" %}
<!-- Output for SVG files -->
<object data="/media/image_library/my-svg-logo.svg" type="image/svg+xml" alt="My SVG Logo" class="logo">
<img src="/media/image_library/my-svg-logo.svg" alt="My SVG Logo" class="logo"/>
</object>
<!-- Output for raster images -->
<img src="/media/image_library/my-raster-image.jpg" alt="My Raster Image" class="logo"/>
```
## Usage
### 1. Uploading SVG Images
1. Go to the Django admin interface
2. Navigate to **Services > Image Library**
3. Click **Add Image**
4. Choose your SVG file in the image field
5. Fill in the required fields (name, alt text, etc.)
6. Save the image
### 2. Using SVG Images in Templates
```html
<!-- Load the template tag -->
{% load image_library %}
<!-- Use SVG images just like any other image -->
{% image_library_img "my-logo" css_class="img-fluid" %}
{% image_library_img "my-icon" css_class="icon" width="24" height="24" %}
<!-- Get SVG URL -->
{% image_library_url "my-logo" %}
```
### 3. Checking if an Image is SVG
In Python code:
```python
from hub.services.models.images import ImageLibrary
image = ImageLibrary.objects.get(slug="my-image")
if image.is_svg():
print("This is an SVG image")
print(f"MIME type: {image.get_mime_type()}")
```
## Migration
### Existing Images
All existing raster images continue to work without any changes. The migration is backward compatible.
### Updating Image Properties
If you want to update image properties for all existing images:
```bash
uv run --extra dev manage.py update_image_properties
```
## Benefits
1. **Scalability**: SVG images scale perfectly at any size
2. **Performance**: SVG files are typically smaller than high-resolution raster images
3. **Flexibility**: SVG images can be styled with CSS
4. **Accessibility**: SVG images provide better accessibility options
5. **Consistency**: All images are managed through the same unified interface
## Technical Details
### Model Changes
- Changed `ImageField` to `FileField` with custom validation
- Added `is_svg()` method to check if file is SVG
- Added `get_mime_type()` method to determine file type
- Enhanced `_update_image_properties()` to handle SVG dimensions
### Validation
- SVG files are validated as valid XML
- File size limits are enforced
- MIME type checking ensures only valid image/SVG files are accepted
### Rendering
- SVG files use `<object>` tags for optimal rendering
- Fallback `<img>` tags are provided for compatibility
- Admin interface properly displays SVG thumbnails
## File Size Considerations
SVG files are typically much smaller than equivalent raster images:
- **Simple logos**: 1-5KB
- **Complex illustrations**: 10-50KB
- **Very complex graphics**: 100KB+
This makes SVG files ideal for:
- Logos and brand assets
- Icons and symbols
- Simple illustrations
- Graphics that need to scale
## Browser Support
SVG support is excellent across all modern browsers:
- Chrome: Full support
- Firefox: Full support
- Safari: Full support
- Edge: Full support
- Internet Explorer 9+: Full support
## Best Practices
1. **Use SVG for**:
- Logos and brand assets
- Icons and symbols
- Simple illustrations
- Graphics that need to scale
2. **Use raster images for**:
- Photographs
- Complex graphics with many colors
- Images from external sources
3. **Optimize SVG files**:
- Remove unnecessary metadata
- Use simple shapes when possible
- Consider using SVG optimization tools
## Troubleshooting
### SVG Not Displaying
- Check that the SVG file is valid XML
- Ensure the file has proper width/height or viewBox attributes
- Verify the file size is under the limit (1MB)
### Wrong Dimensions
- SVG dimensions are extracted from width/height attributes or viewBox
- If dimensions appear wrong, check the SVG source
- Use the `update_image_properties` command to refresh dimensions
### Upload Errors
- Ensure the file is valid SVG format
- Check file size limits
- Verify the file contains valid XML structure

View file

@ -0,0 +1,40 @@
from django.core.management.base import BaseCommand
from hub.services.models.images import ImageLibrary
class Command(BaseCommand):
help = "Update image properties for existing images in the library"
def handle(self, *args, **options):
"""
Update image properties for all images in the library.
This is especially useful after adding SVG support.
"""
images = ImageLibrary.objects.all()
updated_count = 0
error_count = 0
self.stdout.write(f"Updating properties for {images.count()} images...")
for image in images:
try:
# Force update of image properties
image._update_image_properties()
updated_count += 1
# Show progress
if updated_count % 10 == 0:
self.stdout.write(f"Updated {updated_count} images...")
except Exception as e:
error_count += 1
self.stdout.write(
self.style.ERROR(f"Error updating {image.name}: {str(e)}")
)
self.stdout.write(
self.style.SUCCESS(
f"Successfully updated {updated_count} images. "
f"Errors: {error_count}"
)
)

View file

@ -0,0 +1,24 @@
# Generated by Django 5.2 on 2025-07-08 10:51
import hub.services.models.base
import hub.services.models.images
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("services", "0043_remove_article_image_remove_cloudprovider_logo_and_more"),
]
operations = [
migrations.AlterField(
model_name="imagelibrary",
name="image",
field=models.FileField(
help_text="Upload image file (max 1MB) - supports JPEG, PNG, GIF, WebP, BMP, TIFF, and SVG",
upload_to=hub.services.models.images.get_image_upload_path,
validators=[hub.services.models.base.validate_image_or_svg],
),
),
]