png.rs (2967B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use crate::{WindowWrapper, NotifierEvent}; 6 use image::png::PNGEncoder; 7 use image::{self, ColorType, GenericImageView}; 8 use std::fs::File; 9 use std::path::{Path, PathBuf}; 10 use std::sync::mpsc::Receiver; 11 use webrender::api::units::*; 12 use crate::wrench::{Wrench, WrenchThing}; 13 use crate::yaml_frame_reader::YamlFrameReader; 14 15 pub enum ReadSurface { 16 Screen, 17 } 18 19 pub struct SaveSettings { 20 pub flip_vertical: bool, 21 pub try_crop: bool, 22 } 23 24 pub fn save<P: Clone + AsRef<Path>>( 25 path: P, 26 orig_pixels: Vec<u8>, 27 size: DeviceIntSize, 28 settings: SaveSettings 29 ) { 30 let mut width = size.width as u32; 31 let mut height = size.height as u32; 32 let mut buffer = image::RgbaImage::from_raw( 33 width, 34 height, 35 orig_pixels, 36 ).expect("bug: unable to construct image buffer"); 37 38 if settings.flip_vertical { 39 // flip image vertically (texture is upside down) 40 buffer = image::imageops::flip_vertical(&buffer); 41 } 42 43 if settings.try_crop { 44 if let Ok(existing_image) = image::open(path.clone()) { 45 let old_dims = existing_image.dimensions(); 46 println!("Crop from {:?} to {:?}", size, old_dims); 47 width = old_dims.0; 48 height = old_dims.1; 49 buffer = image::imageops::crop( 50 &mut buffer, 51 0, 52 0, 53 width, 54 height 55 ).to_image(); 56 } 57 } 58 59 let encoder = PNGEncoder::new(File::create(path).unwrap()); 60 encoder 61 .encode(&buffer, width, height, ColorType::Rgba8) 62 .expect("Unable to encode PNG!"); 63 } 64 65 pub fn save_flipped<P: Clone + AsRef<Path>>( 66 path: P, 67 orig_pixels: Vec<u8>, 68 size: DeviceIntSize, 69 ) { 70 save(path, orig_pixels, size, SaveSettings { 71 flip_vertical: true, 72 try_crop: true, 73 }) 74 } 75 76 pub fn png( 77 wrench: &mut Wrench, 78 surface: ReadSurface, 79 window: &mut WindowWrapper, 80 mut reader: YamlFrameReader, 81 rx: Receiver<NotifierEvent>, 82 out_path: Option<PathBuf>, 83 ) { 84 reader.do_frame(wrench); 85 86 // wait for the frame 87 rx.recv().unwrap(); 88 wrench.render(); 89 90 let (fb_size, data, settings) = match surface { 91 ReadSurface::Screen => { 92 let dim = window.get_inner_size(); 93 let rect = FramebufferIntSize::new(dim.width, dim.height).into(); 94 let data = wrench.renderer.read_pixels_rgba8(rect); 95 (dim, data, SaveSettings { 96 flip_vertical: true, 97 try_crop: true, 98 }) 99 } 100 }; 101 102 let out_path = out_path.unwrap_or_else(|| { 103 let mut path = reader.yaml_path().clone(); 104 path.set_extension("png"); 105 path 106 }); 107 108 save(out_path, data, fb_size, settings); 109 }