summaryrefslogtreecommitdiffstats
path: root/third_party/rust/png/examples
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/png/examples')
-rw-r--r--third_party/rust/png/examples/pngcheck.rs360
-rw-r--r--third_party/rust/png/examples/show.rs199
2 files changed, 559 insertions, 0 deletions
diff --git a/third_party/rust/png/examples/pngcheck.rs b/third_party/rust/png/examples/pngcheck.rs
new file mode 100644
index 0000000000..6cd0b5b7e2
--- /dev/null
+++ b/third_party/rust/png/examples/pngcheck.rs
@@ -0,0 +1,360 @@
+#![allow(non_upper_case_globals)]
+
+extern crate getopts;
+extern crate glob;
+extern crate png;
+
+use std::io;
+use std::io::prelude::*;
+use std::path::Path;
+use std::fs::File;
+use std::env;
+
+use getopts::{Matches, Options, ParsingStyle};
+use term::{color, Attr};
+
+fn parse_args() -> Matches {
+ let args: Vec<String> = env::args().collect();
+ let mut opts = Options::new();
+ opts.optflag("c", "", "colorize output (for ANSI terminals)")
+ .optflag("q", "", "test quietly (output only errors)")
+ //.optflag("t", "", "print contents of tEXt chunks (can be used with -q)");
+ .optflag("v", "", "test verbosely (print most chunk data)")
+ .parsing_style(ParsingStyle::StopAtFirstFree);
+ if args.len() > 1 {
+ match opts.parse(&args[1..]) {
+ Ok(matches) => return matches,
+ Err(err) => println!("{}", err)
+ }
+ }
+ println!("{}", opts.usage(&format!("Usage: pngcheck [-cpt] [file ...]")));
+ std::process::exit(0);
+}
+
+#[derive(Clone, Copy)]
+struct Config {
+ quiet: bool,
+ verbose: bool,
+ color: bool
+}
+
+fn display_interlaced(i: bool) -> &'static str {
+ if i {
+ "interlaced"
+ } else {
+ "non-interlaced"
+ }
+}
+
+fn display_image_type(bits: u8, color: png::ColorType) -> String {
+ use png::ColorType::*;
+ format!(
+ "{}-bit {}",
+ bits,
+ match color {
+ Grayscale => "grayscale",
+ RGB => "RGB",
+ Indexed => "palette",
+ GrayscaleAlpha => "grayscale+alpha",
+ RGBA => "RGB+alpha"
+ }
+ )
+}
+// channels after expansion of tRNS
+fn final_channels(c: png::ColorType, trns: bool) -> u8 {
+ use png::ColorType::*;
+ match c {
+ Grayscale => 1 + if trns { 1 } else { 0 },
+ RGB => 3,
+ Indexed => 3 + if trns { 1 } else { 0 },
+ GrayscaleAlpha => 2,
+ RGBA => 4
+ }
+}
+fn check_image<P: AsRef<Path>>(c: Config, fname: P) -> io::Result<()> {
+ // TODO improve performance by resusing allocations from decoder
+ use png::Decoded::*;
+ let mut t = term::stdout().ok_or(io::Error::new(
+ io::ErrorKind::Other,
+ "could not open terminal"
+ ))?;
+ let mut data = vec![0; 10*1024];
+ let data_p = data.as_mut_ptr();
+ let mut reader = io::BufReader::new(File::open(&fname)?);
+ let fname = fname.as_ref().to_string_lossy();
+ let n = reader.read(&mut data)?;
+ let mut buf = &data[..n];
+ let mut pos = 0;
+ let mut decoder = png::StreamingDecoder::new();
+ // Image data
+ let mut width = 0;
+ let mut height = 0;
+ let mut color = png::ColorType::Grayscale;
+ let mut bits = 0;
+ let mut trns = false;
+ let mut interlaced = false;
+ let mut compressed_size = 0;
+ let mut n_chunks = 0;
+ let mut have_idat = false;
+ macro_rules! c_ratio(
+ // TODO add palette entries to compressed_size
+ () => ({
+ compressed_size as f32/(
+ height as u64 *
+ (width as u64 * final_channels(color, trns) as u64 * bits as u64 + 7)>>3
+ ) as f32
+ });
+ );
+ let display_error = |err| -> Result<_, io::Error> {
+ let mut t = term::stdout().ok_or(io::Error::new(
+ io::ErrorKind::Other,
+ "could not open terminal"
+ ))?;
+ if c.verbose {
+ if c.color {
+ print!(": ");
+ t.fg(color::RED)?;
+ writeln!(t, "{}", err)?;
+ t.attr(Attr::Bold)?;
+ write!(t, "ERRORS DETECTED")?;
+ t.reset()?;
+ } else {
+ println!(": {}", err);
+ print!("ERRORS DETECTED")
+ }
+ println!(" in {}", fname);
+ } else {
+ if !c.quiet { if c.color {
+ t.fg(color::RED)?;
+ t.attr(Attr::Bold)?;
+ write!(t, "ERROR")?;
+ t.reset()?;
+ write!(t, ": ")?;
+ t.fg(color::YELLOW)?;
+ writeln!(t, "{}", fname)?;
+ t.reset()?;
+ } else {
+ println!("ERROR: {}", fname)
+ }}
+ print!("{}: ", fname);
+ if c.color {
+ t.fg(color::RED)?;
+ writeln!(t, "{}", err)?;
+ t.reset()?;
+ } else {
+ println!("{}", err);
+ }
+
+ }
+ Ok(())
+ };
+
+ if c.verbose {
+ print!("File: ");
+ if c.color {
+ t.attr(Attr::Bold)?;
+ write!(t, "{}", fname)?;
+ t.reset()?;
+ } else {
+ print!("{}", fname);
+ }
+ print!(" ({}) bytes", data.len())
+
+ }
+ loop {
+ if buf.len() == 0 {
+ // circumvent borrow checker
+ assert!(!data.is_empty());
+ let n = reader.read(unsafe {
+ ::std::slice::from_raw_parts_mut(data_p, data.len())
+ })?;
+
+ // EOF
+ if n == 0 {
+ println!("ERROR: premature end of file {}", fname);
+ break;
+ }
+ buf = &data[..n];
+ }
+ match decoder.update(buf, &mut Vec::new()) {
+ Ok((_, ImageEnd)) => {
+ if !have_idat {
+ display_error(png::DecodingError::Format("IDAT chunk missing".into()))?;
+ break;
+ }
+ if !c.verbose && !c.quiet {
+ if c.color {
+ t.fg(color::GREEN)?;
+ t.attr(Attr::Bold)?;
+ write!(t, "OK")?;
+ t.reset()?;
+ write!(t, ": ")?;
+ t.fg(color::YELLOW)?;
+ write!(t, "{}", fname)?;
+ t.reset()?;
+ } else {
+ print!("OK: {}", fname)
+ }
+ println!(
+ " ({}x{}, {}{}, {}, {:.1}%)",
+ width,
+ height,
+ display_image_type(bits, color),
+ (if trns { "+trns" } else { "" }),
+ display_interlaced(interlaced),
+ 100.0*(1.0-c_ratio!())
+ )
+ } else if !c.quiet {
+ println!("");
+ if c.color {
+ t.fg(color::GREEN)?;
+ t.attr(Attr::Bold)?;
+ write!(t, "No errors detected ")?;
+ t.reset()?;
+ } else {
+ print!("No errors detected ");
+ }
+ println!(
+ "in {} ({} chunks, {:.1}% compression)",
+ fname,
+ n_chunks,
+ 100.0*(1.0-c_ratio!())
+ )
+ }
+ break
+ },
+ Ok((n, res)) => {
+ buf = &buf[n..];
+ pos += n;
+ match res {
+ Header(w, h, b, c, i) => {
+ width = w;
+ height = h;
+ bits = b as u8;
+ color = c;
+ interlaced = i;
+ }
+ ChunkBegin(len, type_str) => {
+ use png::chunk;
+ n_chunks += 1;
+ if c.verbose {
+ let chunk = String::from_utf8_lossy(&type_str);
+ println!("");
+ print!(" chunk ");
+ if c.color {
+ t.fg(color::YELLOW)?;
+ write!(t, "{}", chunk)?;
+ t.reset()?;
+ } else {
+ print!("{}", chunk)
+ }
+ print!(
+ " at offset {:#07x}, length {}",
+ pos - 4, // substract chunk name length
+ len
+ )
+ }
+ match type_str {
+ chunk::IDAT => {
+ have_idat = true;
+ compressed_size += len
+ },
+ chunk::tRNS => {
+ trns = true;
+ },
+ _ => ()
+ }
+ }
+ ImageData => {
+ //println!("got {} bytes of image data", data.len())
+ }
+ ChunkComplete(_, type_str) if c.verbose => {
+ use png::chunk::*;
+ match type_str {
+ IHDR => {
+ println!("");
+ print!(
+ " {} x {} image, {}{}, {}",
+ width,
+ height,
+ display_image_type(bits, color),
+ (if trns { "+trns" } else { "" }),
+ display_interlaced(interlaced),
+ );
+ }
+ _ => ()
+ }
+ }
+ AnimationControl(actl) => {
+ println!("");
+ print!(
+ " {} frames, {} plays",
+ actl.num_frames,
+ actl.num_plays,
+ );
+ }
+ FrameControl(fctl) => {
+ println!("");
+ println!(
+ " sequence #{}, {} x {} pixels @ ({}, {})",
+ fctl.sequence_number,
+ fctl.width,
+ fctl.height,
+ fctl.x_offset,
+ fctl.y_offset,
+ /*fctl.delay_num,
+ fctl.delay_den,
+ fctl.dispose_op,
+ fctl.blend_op,*/
+ );
+ print!(
+ " {}/{} s delay, dispose: {}, blend: {}",
+ fctl.delay_num,
+ if fctl.delay_den == 0 { 100 } else {fctl.delay_den},
+ fctl.dispose_op,
+ fctl.blend_op,
+ );
+ }
+ _ => ()
+ }
+ //println!("{} {:?}", n, res)
+ },
+ Err(err) => {
+ let _ = display_error(err);
+ break
+ }
+ }
+ }
+ Ok(())
+}
+
+fn main() {
+ let m = parse_args();
+
+ let config = Config {
+ quiet: m.opt_present("q"),
+ verbose: m.opt_present("v"),
+ color: m.opt_present("c")
+ };
+
+ for file in m.free {
+ let result = if file.contains("*") {
+ glob::glob(&file).map_err(|err| {
+ io::Error::new(io::ErrorKind::Other, err)
+ }).and_then(|mut glob| glob.try_for_each(|entry| {
+ entry.map_err(|err| {
+ io::Error::new(io::ErrorKind::Other, err)
+ }).and_then(|file| {
+ check_image(config, file)
+ })
+ }))
+ } else {
+ check_image(config, &file)
+ };
+
+ result.unwrap_or_else(|err| {
+ println!("{}: {}", file, err);
+ std::process::exit(1)
+ });
+ }
+}
diff --git a/third_party/rust/png/examples/show.rs b/third_party/rust/png/examples/show.rs
new file mode 100644
index 0000000000..9185b8f77e
--- /dev/null
+++ b/third_party/rust/png/examples/show.rs
@@ -0,0 +1,199 @@
+extern crate glium;
+extern crate glob;
+extern crate png;
+
+use std::env;
+use std::io;
+use std::fs::File;
+use std::borrow::Cow;
+use std::path;
+use std::error::Error;
+
+use glium::{Surface, Rect, BlitTarget};
+use glium::texture::{RawImage2d, ClientFormat};
+use glium::glutin::{self, Event, VirtualKeyCode, dpi};
+use glium::backend::glutin::Display;
+
+/// Load the image using `png`
+fn load_image(path: &path::PathBuf) -> io::Result<RawImage2d<'static, u8>> {
+ use png::ColorType::*;
+ let decoder = png::Decoder::new(File::open(path)?);
+ let (info, mut reader) = decoder.read_info()?;
+ let mut img_data = vec![0; info.buffer_size()];
+ 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<path::PathBuf>) -> io::Result<()> {
+ use glium::glutin::{KeyboardInput, WindowEvent};
+
+ let mut files = files.iter();
+ let image = load_image(files.next().unwrap())?;
+
+ let mut events_loop = glutin::EventsLoop::new();
+ let window = glutin::WindowBuilder::new();
+ let context = glutin::ContextBuilder::new()
+ .with_vsync(true);
+
+ let display = Display::new(window, context, &events_loop)
+ .map_err(|err| io::Error::new(
+ io::ErrorKind::Other,
+ err.description()
+ ))?;
+ // building the display, ie. the main object
+ resize_window(&display, &image);
+ let mut opengl_texture = glium::Texture2d::new(&display, image).unwrap();
+
+ let mut stop = false;
+ let mut res = Ok(());
+ 'main: loop {
+ let frame = display.draw();
+ fill_v_flipped(&opengl_texture.as_surface(), &frame, glium::uniforms::MagnifySamplerFilter::Linear);
+ frame.finish().unwrap();
+
+ // polling and handling the events received by the window
+ events_loop.poll_events(|event| {
+ if stop {return;}
+ match event {
+ Event::WindowEvent {event: WindowEvent::CloseRequested, ..} => {
+ stop = true;
+ return;
+ }
+ Event::WindowEvent {
+ event: WindowEvent::KeyboardInput {
+ input: KeyboardInput {
+ state: glutin::ElementState::Pressed,
+ virtual_keycode: code,
+ ..
+ },
+ ..
+ },
+ ..
+ } => match code {
+ Some(VirtualKeyCode::Escape) => {
+ stop = true;
+ return;
+ }
+ Some(VirtualKeyCode::Right) => {
+ match files.next() {
+ Some(path) => {
+ let image = match load_image(path) {
+ Ok(image) => image,
+ Err(err) => {
+ stop = true;
+ res = Err(err);
+ return;
+ }
+ };
+ resize_window(&display, &image);
+ opengl_texture = glium::Texture2d::new(&display, image).unwrap();
+ },
+ None => {
+ stop = true;
+ return;
+ }
+ }
+ },
+ _ => ()
+ },
+ _ => ()
+ }
+ });
+
+ if stop {break 'main;}
+ }
+ res
+}
+
+fn fill_v_flipped<S1, S2>(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<String> = 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)
+ }
+ }
+}