1 extern crate glium;
2 extern crate glob;
3 extern crate png;
4
5 use std::borrow::Cow;
6 use std::env;
7 use std::error::Error;
8 use std::fs::File;
9 use std::io;
10 use std::path;
11
12 use glium::backend::glutin::Display;
13 use glium::glutin::{self, dpi, Event, VirtualKeyCode};
14 use glium::texture::{ClientFormat, RawImage2d};
15 use glium::{BlitTarget, Rect, Surface};
16
17 /// Load the image using `png`
load_image(path: &path::PathBuf) -> io::Result<RawImage2d<'static, u8>>18 fn load_image(path: &path::PathBuf) -> io::Result<RawImage2d<'static, u8>> {
19 use png::ColorType::*;
20 let decoder = png::Decoder::new(File::open(path)?);
21 let (info, mut reader) = decoder.read_info()?;
22 let mut img_data = vec![0; info.buffer_size()];
23 reader.next_frame(&mut img_data)?;
24
25 let (data, format) = match info.color_type {
26 RGB => (img_data, ClientFormat::U8U8U8),
27 RGBA => (img_data, ClientFormat::U8U8U8U8),
28 Grayscale => (
29 {
30 let mut vec = Vec::with_capacity(img_data.len() * 3);
31 for g in img_data {
32 vec.extend([g, g, g].iter().cloned())
33 }
34 vec
35 },
36 ClientFormat::U8U8U8,
37 ),
38 GrayscaleAlpha => (
39 {
40 let mut vec = Vec::with_capacity(img_data.len() * 3);
41 for ga in img_data.chunks(2) {
42 let g = ga[0];
43 let a = ga[1];
44 vec.extend([g, g, g, a].iter().cloned())
45 }
46 vec
47 },
48 ClientFormat::U8U8U8U8,
49 ),
50 _ => unreachable!("uncovered color type"),
51 };
52
53 Ok(RawImage2d {
54 data: Cow::Owned(data),
55 width: info.width,
56 height: info.height,
57 format: format,
58 })
59 }
60
main_loop(files: Vec<path::PathBuf>) -> io::Result<()>61 fn main_loop(files: Vec<path::PathBuf>) -> io::Result<()> {
62 use glium::glutin::{KeyboardInput, WindowEvent};
63
64 let mut files = files.iter();
65 let image = load_image(files.next().unwrap())?;
66
67 let mut events_loop = glutin::EventsLoop::new();
68 let window = glutin::WindowBuilder::new();
69 let context = glutin::ContextBuilder::new().with_vsync(true);
70
71 let display = Display::new(window, context, &events_loop)
72 .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
73 // building the display, ie. the main object
74 resize_window(&display, &image);
75 let mut opengl_texture = glium::Texture2d::new(&display, image).unwrap();
76
77 let mut stop = false;
78 let mut res = Ok(());
79 'main: loop {
80 let frame = display.draw();
81 fill_v_flipped(
82 &opengl_texture.as_surface(),
83 &frame,
84 glium::uniforms::MagnifySamplerFilter::Linear,
85 );
86 frame.finish().unwrap();
87
88 // polling and handling the events received by the window
89 events_loop.poll_events(|event| {
90 if stop {
91 return;
92 }
93 match event {
94 Event::WindowEvent {
95 event: WindowEvent::CloseRequested,
96 ..
97 } => {
98 stop = true;
99 return;
100 }
101 Event::WindowEvent {
102 event:
103 WindowEvent::KeyboardInput {
104 input:
105 KeyboardInput {
106 state: glutin::ElementState::Pressed,
107 virtual_keycode: code,
108 ..
109 },
110 ..
111 },
112 ..
113 } => match code {
114 Some(VirtualKeyCode::Escape) => {
115 stop = true;
116 return;
117 }
118 Some(VirtualKeyCode::Right) => match files.next() {
119 Some(path) => {
120 let image = match load_image(path) {
121 Ok(image) => image,
122 Err(err) => {
123 stop = true;
124 res = Err(err);
125 return;
126 }
127 };
128 resize_window(&display, &image);
129 opengl_texture = glium::Texture2d::new(&display, image).unwrap();
130 }
131 None => {
132 stop = true;
133 return;
134 }
135 },
136 _ => (),
137 },
138 _ => (),
139 }
140 });
141
142 if stop {
143 break 'main;
144 }
145 }
146 res
147 }
148
fill_v_flipped<S1, S2>(src: &S1, target: &S2, filter: glium::uniforms::MagnifySamplerFilter) where S1: Surface, S2: Surface,149 fn fill_v_flipped<S1, S2>(src: &S1, target: &S2, filter: glium::uniforms::MagnifySamplerFilter)
150 where
151 S1: Surface,
152 S2: Surface,
153 {
154 let src_dim = src.get_dimensions();
155 let src_rect = Rect {
156 left: 0,
157 bottom: 0,
158 width: src_dim.0 as u32,
159 height: src_dim.1 as u32,
160 };
161 let target_dim = target.get_dimensions();
162 let target_rect = BlitTarget {
163 left: 0,
164 bottom: target_dim.1,
165 width: target_dim.0 as i32,
166 height: -(target_dim.1 as i32),
167 };
168 src.blit_color(&src_rect, target, &target_rect, filter);
169 }
170
resize_window(display: &Display, image: &RawImage2d<'static, u8>)171 fn resize_window(display: &Display, image: &RawImage2d<'static, u8>) {
172 let mut width = image.width;
173 let mut height = image.height;
174 if width < 50 && height < 50 {
175 width *= 10;
176 height *= 10;
177 } else if width < 5 && height < 5 {
178 width *= 10;
179 height *= 10;
180 }
181 display
182 .gl_window()
183 .window()
184 .set_inner_size(dpi::LogicalSize::new(f64::from(width), f64::from(height)));
185 }
186
main()187 fn main() {
188 let args: Vec<String> = env::args().collect();
189 if args.len() < 2 {
190 println!("Usage: show files [...]");
191 } else {
192 let mut files = vec![];
193 for file in args.iter().skip(1) {
194 match if file.contains("*") {
195 (|| -> io::Result<_> {
196 for entry in glob::glob(&file)
197 .map_err(|err| io::Error::new(io::ErrorKind::Other, err.msg))?
198 {
199 files.push(
200 entry
201 .map_err(|_| io::Error::new(io::ErrorKind::Other, "glob error"))?,
202 )
203 }
204 Ok(())
205 })()
206 } else {
207 files.push(path::PathBuf::from(file));
208 Ok(())
209 } {
210 Ok(_) => (),
211 Err(err) => {
212 println!("{}: {}", file, err);
213 break;
214 }
215 }
216 }
217 // "tests/pngsuite/pngsuite.png"
218 match main_loop(files) {
219 Ok(_) => (),
220 Err(err) => println!("Error: {}", err),
221 }
222 }
223 }
224