use glium::{ backend::glutin::Display, glutin::{ self, dpi, event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, event_loop::ControlFlow, }, texture::{ClientFormat, RawImage2d}, BlitTarget, Rect, Surface, }; use std::{borrow::Cow, env, fs::File, io, path}; /// Load the image using `png` fn load_image(path: &path::PathBuf) -> io::Result> { use png::ColorType::*; let mut decoder = png::Decoder::new(File::open(path)?); decoder.set_transformations(png::Transformations::normalize_to_color8()); let mut reader = decoder.read_info()?; let mut img_data = vec![0; reader.output_buffer_size()]; let info = reader.next_frame(&mut img_data)?; let (data, format) = match info.color_type { Rgb => (img_data, ClientFormat::U8U8U8), Rgba => (img_data, ClientFormat::U8U8U8U8), Grayscale => ( { let mut vec = Vec::with_capacity(img_data.len() * 3); for g in img_data { vec.extend([g, g, g].iter().cloned()) } vec }, ClientFormat::U8U8U8, ), GrayscaleAlpha => ( { let mut vec = Vec::with_capacity(img_data.len() * 3); for ga in img_data.chunks(2) { let g = ga[0]; let a = ga[1]; vec.extend([g, g, g, a].iter().cloned()) } vec }, ClientFormat::U8U8U8U8, ), _ => unreachable!("uncovered color type"), }; Ok(RawImage2d { data: Cow::Owned(data), width: info.width, height: info.height, format: format, }) } fn main_loop(files: Vec) -> io::Result<()> { let mut files = files.into_iter(); let image = load_image(&files.next().unwrap())?; let event_loop = glutin::event_loop::EventLoop::new(); let window_builder = glutin::window::WindowBuilder::new().with_title("Show Example"); let context_builder = glutin::ContextBuilder::new().with_vsync(true); let display = glium::Display::new(window_builder, context_builder, &event_loop) .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; resize_window(&display, &image); let mut texture = glium::Texture2d::new(&display, image).unwrap(); draw(&display, &texture); event_loop.run(move |event, _, control_flow| match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => exit(control_flow), Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: code, .. }, .. }, .. } => match code { Some(VirtualKeyCode::Escape) => exit(control_flow), Some(VirtualKeyCode::Right) => match &files.next() { Some(path) => { match load_image(path) { Ok(image) => { resize_window(&display, &image); texture = glium::Texture2d::new(&display, image).unwrap(); draw(&display, &texture); } Err(err) => { println!("Error: {}", err); exit(control_flow); } }; } None => exit(control_flow), }, _ => {} }, Event::RedrawRequested(_) => draw(&display, &texture), _ => {} }); } fn draw(display: &glium::Display, texture: &glium::Texture2d) { let frame = display.draw(); fill_v_flipped( &texture.as_surface(), &frame, glium::uniforms::MagnifySamplerFilter::Linear, ); frame.finish().unwrap(); } fn exit(control_flow: &mut ControlFlow) { *control_flow = ControlFlow::Exit; } fn fill_v_flipped(src: &S1, target: &S2, filter: glium::uniforms::MagnifySamplerFilter) where S1: Surface, S2: Surface, { let src_dim = src.get_dimensions(); let src_rect = Rect { left: 0, bottom: 0, width: src_dim.0 as u32, height: src_dim.1 as u32, }; let target_dim = target.get_dimensions(); let target_rect = BlitTarget { left: 0, bottom: target_dim.1, width: target_dim.0 as i32, height: -(target_dim.1 as i32), }; src.blit_color(&src_rect, target, &target_rect, filter); } fn resize_window(display: &Display, image: &RawImage2d<'static, u8>) { let mut width = image.width; let mut height = image.height; if width < 50 && height < 50 { width *= 10; height *= 10; } else if width < 5 && height < 5 { width *= 10; height *= 10; } display .gl_window() .window() .set_inner_size(dpi::LogicalSize::new(f64::from(width), f64::from(height))); } fn main() { let args: Vec = env::args().collect(); if args.len() < 2 { println!("Usage: show files [...]"); } else { let mut files = vec![]; for file in args.iter().skip(1) { match if file.contains("*") { (|| -> io::Result<_> { for entry in glob::glob(&file) .map_err(|err| io::Error::new(io::ErrorKind::Other, err.msg))? { files.push( entry .map_err(|_| io::Error::new(io::ErrorKind::Other, "glob error"))?, ) } Ok(()) })() } else { files.push(path::PathBuf::from(file)); Ok(()) } { Ok(_) => (), Err(err) => { println!("{}: {}", file, err); break; } } } // "tests/pngsuite/pngsuite.png" match main_loop(files) { Ok(_) => (), Err(err) => println!("Error: {}", err), } } }