jolicode / jolicode/MediaBundle
EXIF orientation is never applied: portrait photos are rendered sideways
- Dominant language
- PHP
- Stars
- 118
- Forks
- 13
- Avg merge
- 22h 54m
- Merged PRs (30d)
- 3
Description
## Summary
Photos that carry an EXIF `Orientation` tag other than `1` (e.g. a portrait photo shot on a phone, stored as landscape pixels + a rotation flag) are never physically rotated anywhere in the pipeline. Every generated variation — and the raw "original" — ends up displayed sideways/squished wherever the consumer doesn't itself respect EXIF orientation (Imagick resizes, canvas-based previews such as Dropzone.js thumbnails, etc.).
## Where I looked
- `PreProcessor\ExifRemovalPreProcessor` only strips the `ifd1` group (embedded thumbnail metadata) via `exiftool -ifd1:all=`; it leaves the `Orientation` tag (in `ifd0`) intact.
- `Processor\Imagine::process()` calls `$this->imagine->load($binary->getContent())` and then runs the transformer chain (e.g. `Resize`), but never applies any rotation. `imagine/imagine`'s `Imagick` adapter does **not** auto-rotate on load either.
- `imagine/imagine` actually ships a filter for exactly this (`Imagine\Filter\Basic\Autorotate`, reading `ifd0.Orientation`), but nothing in `JoliMediaBundle` wires it in — there's no built-in pre-processor, processor step, or config option that calls it.
- Searching the bundle source for `orient`/`rotate` (case-insensitive) returns zero matches outside `Autorotate.php` in `imagine/imagine` itself.
Because the `Resize` transformer (`Transformer\Resize`) computes target dimensions from the *un-rotated* pixel dimensions, a portrait 3024×4032 source (stored as landscape 4032×3024 pixels + `Orientation: 6`) gets resized as if it were landscape, producing a visibly wrong/squished result in every variation — not just a rotation issue in consumers that ignore EXIF.
## Reproduction
1. Configure a library with the `imagine` processor (`driver: imagick`) and any `resize` variation.
2. Upload a JPEG shot in portrait orientation on a phone (has `Orientation: 6` or similar, landscape pixel dimensions).
3. Request any variation, or view the stored "original" directly.
4. The image (and any generated cache file) is sideways / has the wrong effective aspect ratio for the resize.
## Environment
- `jolicode/media-bundle` v0.9.1 (latest on Packagist as of this report)
- `processors.imagine.driver: imagick`
- ext-imagick 3.8.1 / ImageMagick 7.1.1
## Suggested fix
Rotate the pixel data once, before any transformer runs, and normalize the orientation flag so nothing double-rotates it later — e.g. a pre-processor for JPEG/TIFF (and HEIF, after `HeifPreProcessor` converts it) that calls `Imagick::autoOrientImage()` (or `autoOrient()` on older ext-imagick releases, the method was renamed) when `getImageOrientation()` isn't already `ORIENTATION_TOPLEFT`/`ORIENTATION_UNDEFINED`.
We worked around it locally with exactly that, registered ahead of `ExifRemovalPreProcessor` in `pre_processors`, and it resolves the issue. Happy to turn that into a PR against this repo if that's useful — let me know.
Contributor guide
Research direction
Start by reading Processor\Imagine::process(), Transformer\Resize, and PreProcessor\ExifRemovalPreProcessor, then trace the configured pre_processors ordering. Check the available Imagine Autorotate filter and the stated Imagick orientation behavior before deciding where the step belongs. Done means oriented pixels are normalized before resizing, the orientation flag cannot cause double rotation, and generated variations retain the correct aspect ratio.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100