feat: Implement v1.4.0 Phase 1 - Large Image Support

Implement tiered resize strategy for large images per v1.4.0 design:

Changes:
- Increase MAX_FILE_SIZE from 10MB to 50MB
- Add MAX_OUTPUT_SIZE constant (10MB target after optimization)
- Add MIN_QUALITY and MIN_DIMENSION constants
- Add get_optimization_params() for tiered strategy:
  - <=10MB: 2048px max, 95% quality
  - 10-25MB: 1600px max, 90% quality
  - 25-50MB: 1280px max, 85% quality
- Update optimize_image() signature to return 4-tuple (img, w, h, bytes)
- Implement iterative quality reduction if output >10MB
- Add animated GIF detection and size check in validate_image()
- Update save_media() to use new optimize_image() return value
- Fix GIF format preservation during optimization
- Update tests to match new optimize_image() signature

All existing tests pass. Ready for Phase 2 (Image Variants).

Following design in:
/home/phil/Projects/starpunk/docs/design/v1.4.0/media-implementation-design.md

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-10 17:57:44 -07:00
parent 5ea9c8f330
commit 1b51c82656
2 changed files with 136 additions and 53 deletions

View File

@@ -119,39 +119,44 @@ class TestImageOptimization:
def test_no_resize_needed(self):
"""Test image within limits is not resized"""
image_data = create_test_image(1024, 768, 'PNG')
optimized, width, height = optimize_image(image_data)
optimized, width, height, optimized_bytes = optimize_image(image_data)
assert width == 1024
assert height == 768
assert optimized_bytes is not None
assert len(optimized_bytes) > 0
def test_resize_large_image(self):
"""Test auto-resize of >2048px image (per ADR-058)"""
large_image = create_test_image(3000, 2000, 'PNG')
optimized, width, height = optimize_image(large_image)
optimized, width, height, optimized_bytes = optimize_image(large_image)
# Should be resized to 2048px on longest edge
assert width == RESIZE_DIMENSION
# Height should be proportionally scaled
assert height == int(2000 * (RESIZE_DIMENSION / 3000))
assert optimized_bytes is not None
def test_aspect_ratio_preserved(self):
"""Test aspect ratio is maintained during resize"""
image_data = create_test_image(3000, 1500, 'PNG')
optimized, width, height = optimize_image(image_data)
optimized, width, height, optimized_bytes = optimize_image(image_data)
# Original aspect ratio: 2:1
# After resize: should still be 2:1
assert width / height == pytest.approx(2.0, rel=0.01)
assert optimized_bytes is not None
def test_gif_animation_preserved(self):
"""Test GIF animation preservation (per Q12)"""
# For v1.2.0: Just verify GIF is handled without error
# Full animation preservation is complex
gif_data = create_test_image(800, 600, 'GIF')
optimized, width, height = optimize_image(gif_data)
optimized, width, height, optimized_bytes = optimize_image(gif_data)
assert width > 0
assert height > 0
assert optimized_bytes is not None
class TestMediaSave: