- Add pillow-heif dependency for iPhone photo support - Auto-convert HEIC to JPEG (browsers can't display HEIC) - Graceful error if pillow-heif not installed - Handles RGBA/P mode conversion to RGB 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
171 lines
6.8 KiB
Markdown
171 lines
6.8 KiB
Markdown
# v1.4.2 Implementation Report - HEIC Image Support
|
|
|
|
**Date**: 2025-12-16
|
|
**Developer**: Claude (Fullstack Developer Agent)
|
|
**Status**: Completed
|
|
**Design Document**: `/home/phil/Projects/starpunk/docs/design/v1.4.2/heic-support-design.md`
|
|
|
|
## Summary
|
|
|
|
Successfully implemented HEIC/HEIF image format support for iPhone photo uploads. HEIC images are automatically detected and converted to JPEG format (browsers cannot display HEIC natively). Implementation includes graceful error handling when pillow-heif library is not installed.
|
|
|
|
## Implementation Details
|
|
|
|
### Files Modified
|
|
|
|
1. **`requirements.txt`**
|
|
- Added `pillow-heif==0.18.*` dependency
|
|
- Updated `Pillow` from `10.0.*` to `10.1.*` (required by pillow-heif)
|
|
|
|
2. **`starpunk/media.py`**
|
|
- Added conditional import for `pillow_heif` with `HEIC_SUPPORTED` flag
|
|
- Modified `validate_image()` function:
|
|
- Updated return type from `Tuple[str, int, int]` to `Tuple[bytes, str, int, int]`
|
|
- Added HEIC detection after image verification
|
|
- Implemented HEIC to JPEG conversion at quality 95
|
|
- Handles RGBA/P mode conversion to RGB (JPEG doesn't support alpha)
|
|
- Re-opens converted image for further processing
|
|
- Updated `save_media()` call site to unpack 4-tuple instead of 3-tuple
|
|
|
|
3. **`starpunk/__init__.py`**
|
|
- Updated `__version__` from `"1.4.1"` to `"1.4.2"`
|
|
- Updated `__version_info__` from `(1, 4, 1)` to `(1, 4, 2)`
|
|
|
|
4. **`tests/test_media_upload.py`**
|
|
- Added `HEIC_SUPPORTED` import
|
|
- Created `create_test_heic()` helper function
|
|
- Updated existing validation tests to handle new 4-tuple return signature
|
|
- Added new `TestHEICSupport` class with 5 test cases:
|
|
- `test_heic_detection_and_conversion` - Verifies HEIC to JPEG conversion
|
|
- `test_heic_with_rgba_mode` - Tests alpha channel handling
|
|
- `test_heic_dimensions_preserved` - Verifies dimensions unchanged
|
|
- `test_heic_error_without_library` - Tests graceful degradation
|
|
- `test_heic_full_upload_flow` - End-to-end upload test
|
|
|
|
5. **`CHANGELOG.md`**
|
|
- Added v1.4.2 release entry with:
|
|
- Feature additions (HEIC support, automatic conversion, error handling)
|
|
- Dependency updates (pillow-heif, Pillow version bump)
|
|
|
|
## Technical Decisions
|
|
|
|
### D1: Conversion Quality Setting
|
|
- **Decision**: Use `quality=95` for HEIC to JPEG conversion
|
|
- **Rationale**: Preserves maximum detail from original; subsequent `optimize_image()` call will further compress if needed per size-aware strategy
|
|
|
|
### D2: Return Signature Change
|
|
- **Decision**: Change `validate_image()` from 3-tuple to 4-tuple return
|
|
- **Rationale**: Cleanest way to return converted bytes without adding new parameters or breaking encapsulation
|
|
- **Impact**: Updated all call sites (only `save_media()` affected)
|
|
|
|
### D3: Pillow Version Bump
|
|
- **Challenge**: `pillow-heif==0.18.0` requires `Pillow>=10.1.0`
|
|
- **Decision**: Bump Pillow from `10.0.*` to `10.1.*`
|
|
- **Risk Assessment**: Minor version bump unlikely to introduce breaking changes
|
|
- **Mitigation**: Ran full test suite - all 879 tests pass
|
|
|
|
## Test Results
|
|
|
|
All tests pass:
|
|
```
|
|
tests/test_media_upload.py - 33/33 PASSED
|
|
- 7 validation tests (updated for new signature)
|
|
- 5 HEIC-specific tests (new)
|
|
- 4 optimization tests
|
|
- 3 save tests
|
|
- 4 attachment tests
|
|
- 2 deletion tests
|
|
- 3 security tests
|
|
- 5 logging tests
|
|
```
|
|
|
|
Media-related tests across all suites: 51/51 PASSED
|
|
|
|
## Code Changes Summary
|
|
|
|
### Key Changes in `validate_image()`
|
|
|
|
**Before** (v1.4.1):
|
|
```python
|
|
def validate_image(file_data: bytes, filename: str) -> Tuple[str, int, int]:
|
|
# ... validation logic ...
|
|
return mime_type, width, height
|
|
```
|
|
|
|
**After** (v1.4.2):
|
|
```python
|
|
def validate_image(file_data: bytes, filename: str) -> Tuple[bytes, str, int, int]:
|
|
# ... validation logic ...
|
|
|
|
# HEIC/HEIF conversion (v1.4.2)
|
|
if img.format in ('HEIF', 'HEIC'):
|
|
if not HEIC_SUPPORTED:
|
|
raise ValueError("HEIC/HEIF images require pillow-heif library...")
|
|
# Convert to JPEG
|
|
output = io.BytesIO()
|
|
if img.mode in ('RGBA', 'P'):
|
|
img = img.convert('RGB')
|
|
img.save(output, format='JPEG', quality=95)
|
|
output.seek(0)
|
|
file_data = output.getvalue()
|
|
img = Image.open(io.BytesIO(file_data))
|
|
|
|
return file_data, mime_type, width, height
|
|
```
|
|
|
|
## Deployment Notes
|
|
|
|
1. **Dependency Installation**: Run `uv pip install -r requirements.txt` to install pillow-heif
|
|
2. **Backward Compatibility**: Fully backward compatible - existing uploads unaffected
|
|
3. **Database**: No schema changes required
|
|
4. **Configuration**: No config changes required
|
|
5. **Graceful Degradation**: If pillow-heif not installed, HEIC uploads fail with helpful error message
|
|
|
|
## Performance Considerations
|
|
|
|
- **Conversion Overhead**: HEIC to JPEG conversion adds ~100-300ms per image
|
|
- **Memory Usage**: Conversion happens in-memory (BytesIO) - no temp files
|
|
- **Subsequent Optimization**: Converted JPEG flows through existing optimization pipeline
|
|
- **File Size**: HEIC typically converts to larger JPEG initially, then optimization reduces to target
|
|
|
|
## Edge Cases Handled
|
|
|
|
1. **HEIC with alpha channel** - Converted to RGB (JPEG doesn't support alpha)
|
|
2. **HEIC in P mode** - Converted to RGB for JPEG compatibility
|
|
3. **Missing library** - Graceful error with actionable message
|
|
4. **Already JPEG misnamed as HEIC** - Pillow format detection handles correctly
|
|
5. **Large HEIC files** - Flow through existing 50MB limit and size-aware optimization
|
|
|
|
## Security Considerations
|
|
|
|
- **Pillow vulnerability surface**: Increased slightly by adding pillow-heif
|
|
- **Mitigation**: Using pinned versions (`0.18.*`), regular updates needed
|
|
- **Input validation**: HEIC files still go through Pillow's `verify()` check
|
|
- **Conversion safety**: JPEG conversion happens in controlled environment
|
|
|
|
## Follow-up Items
|
|
|
|
None required for this release. Future considerations:
|
|
|
|
1. Monitor pillow-heif for security updates
|
|
2. Consider WebP as conversion target (better compression, modern browser support)
|
|
3. Track conversion time metrics if performance becomes concern
|
|
|
|
## Developer Notes
|
|
|
|
Implementation closely followed the design document at `docs/design/v1.4.2/heic-support-design.md`. All checklist items completed:
|
|
|
|
- [x] Add `pillow-heif==0.18.*` to requirements.txt
|
|
- [x] Add HEIC import and registration to media.py
|
|
- [x] Modify `validate_image()` return type to include bytes
|
|
- [x] Add HEIC detection and conversion logic to `validate_image()`
|
|
- [x] Update `save_media()` to handle new return value
|
|
- [x] Update `__version__` to "1.4.2"
|
|
- [x] Add HEIC test cases
|
|
- [x] Update CHANGELOG.md
|
|
- [x] Run full test suite
|
|
|
|
## Conclusion
|
|
|
|
v1.4.2 successfully implements HEIC image support with minimal code changes (41 lines added/modified in media.py). Implementation is clean, well-tested, and maintains backward compatibility. iPhone users can now upload photos directly without manual conversion.
|