我正在尝试使用 Rust 中的 eframe/egui 实现我自己的图像查看器。 但是我似乎无法使用文件路径加载和显示图像。
我希望程序能够像这样工作:
选择目录
从目录中获取每个文件
显示最新图像
使用按钮单击/循环浏览图像
目前我被困在第3点XD
fn main() -> Result<(), eframe::Error>{
env_logger::init();
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
..Default::default()
};
eframe::run_native(
"Image Viewer",
options,
Box::new(
|cc| {
egui_extras::install_image_loaders(&cc.egui_ctx);
Box::<ImageViewer>::default()
}
)
)
}
#[derive(Default)]
struct ImageViewer {
directory_path: Option<String>,
images: Vec<String>,
has_images: bool,
current_image: i32
}
impl eframe::App for ImageViewer {
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.vertical_centered_justified(|ui| {
ui.horizontal_top(|ui| {
let path_label = ui.label("Path:");
let window_width = ui.available_width();
if let Some(directory_path) = &self.directory_path {
if ui.add_sized(
[window_width, 10.0],
egui::Button::new(directory_path)
)
.labelled_by(path_label.id)
.clicked() {
if let Some(path) = FileDialog::new().set_directory("/").pick_folder() {
self.directory_path = Some(path.display().to_string());
self.images = get_image_paths_from_directory(path);
self.has_images = self.images.len() > 0;
self.current_image = 0;
}
}
} else {
if ui.add_sized(
[window_width, 10.0],
egui::Button::new("No image directory selected")
)
.labelled_by(path_label.id)
.clicked() {
if let Some(path) = FileDialog::new().set_directory("/").pick_folder() {
self.directory_path = Some(path.display().to_string());
self.images = get_image_paths_from_directory(path);
self.has_images = self.images.len() > 0;
self.current_image = 0;
}
};
}
});
ui.vertical_centered_justified(|ui| {
if self.has_images {
// Load and display image
} else {
// Show placeholder
}
})
})
});
}
}
// Gets the file paths from a given PathBuf
fn get_image_paths_from_directory(path_buf: PathBuf) -> Vec<String> {
path_buf
.read_dir()
.unwrap()
.map(|entry| {
let entry = entry.unwrap();
let entry_path = entry.path();
let file_name = entry_path.as_os_str();
let file_name_as_str = file_name.to_str().unwrap();
let file_name_as_string = String::from(file_name_as_str);
file_name_as_string
})
.collect::<Vec<String>>()
}
我知道你可以实现这样的图像
ui.add(egui::Image::new(egui::include_image!(image_path)));
但是,您必须在运行程序之前声明 image_path,而且我似乎找不到在执行过程中更改路径的方法(或者如果可能的话)。另外,预先设置变量也无法达到选择目录和浏览其图像的目的。
我还尝试了一些将图像转换为字节并以这种方式加载它的方法,但没有取得积极的结果。
只需将 URI
file:///path/to/your/file.png
传递给您的 Image::new
调用,它需要任何实现 Into<ImageSource>
的内容,并且有一个 From<String> for ImageSource
的实现将 String
视为 URI:
let file_path = "/path/to/your/file.png";
let image = Image::new(format!("file://{file_path}"));
Ui::image
上的示例确实涵盖了这种情况,并且应该是更好的手册add(Image)
:
ui.image("file://assets/ferris.png");