Skip to content

Commit 76e89e6

Browse files
LeandroPG19claude
andauthored
feat: apply EXIF orientation when decoding a wallpaper (pop-os#142)
Cameras store portrait photos with the pixels laid out landscape and record the rotation in the Exif metadata. `ImageReader::decode` ignores it, so those wallpapers are drawn rotated. It is also why such a photo looks right in an image viewer but rotated in the wallpaper and in the cosmic-settings preview. Decode through `into_decoder` instead, so the orientation reported by the decoder can be applied to the decoded image. Unlike `decode`, `into_decoder` does not check the allocation limit against the size of the decoded image, so that check is kept explicitly. Signed-off-by: Leandro Pérez G. <leandropatodo@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ed65f7d commit 76e89e6

1 file changed

Lines changed: 29 additions & 17 deletions

File tree

src/wallpaper.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use crate::{CosmicBg, CosmicBgLayer};
44

55
use std::collections::VecDeque;
66
use std::fs;
7+
use std::io::BufReader;
78
use std::path::PathBuf;
89
use std::time::{Duration, Instant};
910

1011
use cosmic_bg_config::state::State;
1112
use cosmic_bg_config::{Color, Entry, SamplingMethod, ScalingMode, Source};
1213
use cosmic_config::CosmicConfigEntry;
13-
use image::{DynamicImage, ImageReader, Limits};
14+
use image::{DynamicImage, ImageDecoder, ImageReader, ImageResult, Limits};
1415
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
1516
use rand::rng;
1617
use rand::seq::SliceRandom;
@@ -126,23 +127,17 @@ impl Wallpaper {
126127
.ok()
127128
.and_then(|f| f.with_guessed_format().ok())
128129
{
129-
Some(mut f) => {
130-
let mut limits = Limits::default();
131-
limits.max_alloc = Some(1024 * 1024 * 1024);
132-
f.limits(limits);
133-
134-
match f.decode() {
135-
Ok(img) => Some(img),
136-
Err(why) => {
137-
tracing::warn!(
138-
?why,
139-
"Failed to decode image: {}",
140-
path.display()
141-
);
142-
continue;
143-
}
130+
Some(f) => match decode(f) {
131+
Ok(img) => Some(img),
132+
Err(why) => {
133+
tracing::warn!(
134+
?why,
135+
"Failed to decode image: {}",
136+
path.display()
137+
);
138+
continue;
144139
}
145-
}
140+
},
146141
None => continue,
147142
};
148143
}
@@ -371,6 +366,23 @@ impl Wallpaper {
371366
}
372367
}
373368

369+
fn decode(mut reader: ImageReader<BufReader<fs::File>>) -> ImageResult<DynamicImage> {
370+
let mut limits = Limits::default();
371+
limits.max_alloc = Some(1024 * 1024 * 1024);
372+
reader.limits(limits.clone());
373+
374+
let mut decoder = reader.into_decoder()?;
375+
let orientation = decoder.orientation()?;
376+
377+
limits.reserve(decoder.total_bytes())?;
378+
decoder.set_limits(limits)?;
379+
380+
let mut image = DynamicImage::from_decoder(decoder)?;
381+
image.apply_orientation(orientation);
382+
383+
Ok(image)
384+
}
385+
374386
fn current_image(output: &str) -> Option<Source> {
375387
let state = State::state().ok()?;
376388
let mut wallpapers = State::get_entry(&state)

0 commit comments

Comments
 (0)