refactor try_decode_image

This commit is contained in:
Frederic Laing 2025-11-16 18:40:55 +01:00
parent 0353009321
commit 006b69d98b
No known key found for this signature in database
GPG key ID: C126157F0CDCD306

View file

@ -2979,56 +2979,76 @@ impl Tab {
} }
fn trigger_async_decode(&mut self) -> Vec<Command> { fn trigger_async_decode(&mut self) -> Vec<Command> {
let mut commands = Vec::new();
// Only trigger decode in gallery mode for the currently selected image // Only trigger decode in gallery mode for the currently selected image
if !self.gallery { if !self.gallery {
return commands; return Vec::new();
} }
if let Some(index) = self.select_focus { let Some(index) = self.select_focus else {
if let Some(items) = &self.items_opt { return Vec::new();
if let Some(item) = items.get(index) { };
if let Some(ItemThumbnail::Image(_, _, _full_handle_opt)) = &item.thumbnail_opt
let Some(items) = &self.items_opt else {
return Vec::new();
};
let Some(item) = items.get(index) else {
return Vec::new();
};
let Some(ItemThumbnail::Image(_, _, _)) = &item.thumbnail_opt else {
return Vec::new();
};
let Some(path) = item.path_opt() else {
return Vec::new();
};
// Clone path to avoid borrow checker issues
let path = path.to_path_buf();
// Clear any previous errors for this image
self.large_image_manager.clear_error(&path);
// Check if image is already decoded or currently decoding
if self.large_image_manager.get_decoded(&path).is_some()
|| self.large_image_manager.is_decoding(&path)
{ {
if let Some(path) = item.path_opt() { return Vec::new();
self.large_image_manager.clear_error(path);
// Only decode if not already decoded or decoding
if self.large_image_manager.get_decoded(path).is_none()
&& !self.large_image_manager.is_decoding(path)
{
if let Some((width, height)) = get_image_dimensions(path) {
let (has_memory, error_opt) =
check_memory_available(width, height);
if !has_memory {
// Insufficient memory --> try clearing cache
if !self.large_image_manager.cache_is_empty() {
log::info!(
"Insufficient memory, clearing {} cached images",
self.large_image_manager.cache_size()
);
self.large_image_manager.clear_cache();
// Check again after clearing cache
let (has_memory_after_clear, error_opt_after) =
check_memory_available(width, height);
if !has_memory_after_clear {
if let Some(error_msg) = error_opt_after {
self.large_image_manager
.store_error(path.clone(), error_msg);
log::warn!(
"Cannot load {}: insufficient memory even after cache clear",
path.display()
);
} }
return commands;
// Try to decode the image
self.try_decode_image(&path)
} }
log::info!(
"Memory available after cache clear, proceeding with decode" /// Attempt to decode a large image, handling memory constraints
fn try_decode_image(&mut self, path: &PathBuf) -> Vec<Command> {
let Some((width, height)) = get_image_dimensions(path) else {
self.large_image_manager.store_error(
path.clone(),
"Failed to read image dimensions".to_string(),
); );
} else { return Vec::new();
};
if !self.ensure_memory_available(path, width, height) {
return Vec::new();
}
// Mark image as decoding and create the decode task
self.large_image_manager.mark_decoding(path.clone());
vec![self.create_decode_command(path.clone())]
}
fn ensure_memory_available(&mut self, path: &PathBuf, width: u32, height: u32) -> bool {
let (has_memory, error_opt) = check_memory_available(width, height);
if has_memory {
return true;
}
// Try clearing cache
if self.large_image_manager.cache_is_empty() {
if let Some(error_msg) = error_opt { if let Some(error_msg) = error_opt {
self.large_image_manager self.large_image_manager
.store_error(path.clone(), error_msg); .store_error(path.clone(), error_msg);
@ -3037,43 +3057,44 @@ impl Tab {
path.display() path.display()
); );
} }
return commands; return false;
}
} }
self.large_image_manager.mark_decoding(path.clone()); log::info!(
"Insufficient memory, clearing {} cached images",
self.large_image_manager.cache_size()
);
self.large_image_manager.clear_cache();
let path_clone = path.clone(); let (has_memory_after_clear, error_opt_after) = check_memory_available(width, height);
commands.push(Command::Iced(
cosmic::iced::Task::perform( if has_memory_after_clear {
decode_large_image(path_clone), log::info!("Memory available after cache clear, proceeding with decode");
|result| { return true;
if let Some((path, width, height, pixels)) = result
{
Message::ImageDecoded(
path, width, height, pixels,
)
} else {
Message::AutoScroll(None)
} }
},
) if let Some(error_msg) = error_opt_after {
.into(), self.large_image_manager
)); .store_error(path.clone(), error_msg);
} else { log::warn!(
self.large_image_manager.store_error( "Cannot load {}: insufficient memory even after cache clear",
path.clone(), path.display()
"Failed to read image dimensions".to_string(),
); );
} }
} false
}
}
}
}
} }
commands fn create_decode_command(&self, path: PathBuf) -> Command {
Command::Iced(
cosmic::iced::Task::perform(decode_large_image(path), |result| {
result
.map(|(path, width, height, pixels)| {
Message::ImageDecoded(path, width, height, pixels)
})
.unwrap_or_else(|| Message::AutoScroll(None))
})
.into(),
)
} }
pub fn change_location(&mut self, location: &Location, history_i_opt: Option<usize>) { pub fn change_location(&mut self, location: &Location, history_i_opt: Option<usize>) {