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 GpuCache,
18 }
19
20 pub struct SaveSettings {
21 pub flip_vertical: bool,
22 pub try_crop: bool,
23 }
24
save<P: Clone + AsRef<Path>>( path: P, orig_pixels: Vec<u8>, size: DeviceIntSize, settings: SaveSettings )25 pub fn save<P: Clone + AsRef<Path>>(
26 path: P,
27 orig_pixels: Vec<u8>,
28 size: DeviceIntSize,
29 settings: SaveSettings
30 ) {
31 let mut width = size.width as u32;
32 let mut height = size.height as u32;
33 let mut buffer = image::RgbaImage::from_raw(
34 width,
35 height,
36 orig_pixels,
37 ).expect("bug: unable to construct image buffer");
38
39 if settings.flip_vertical {
40 // flip image vertically (texture is upside down)
41 buffer = image::imageops::flip_vertical(&buffer);
42 }
43
44 if settings.try_crop {
45 if let Ok(existing_image) = image::open(path.clone()) {
46 let old_dims = existing_image.dimensions();
47 println!("Crop from {:?} to {:?}", size, old_dims);
48 width = old_dims.0;
49 height = old_dims.1;
50 buffer = image::imageops::crop(
51 &mut buffer,
52 0,
53 0,
54 width,
55 height
56 ).to_image();
57 }
58 }
59
60 let encoder = PNGEncoder::new(File::create(path).unwrap());
61 encoder
62 .encode(&buffer, width, height, ColorType::Rgba8)
63 .expect("Unable to encode PNG!");
64 }
65
save_flipped<P: Clone + AsRef<Path>>( path: P, orig_pixels: Vec<u8>, size: DeviceIntSize, )66 pub fn save_flipped<P: Clone + AsRef<Path>>(
67 path: P,
68 orig_pixels: Vec<u8>,
69 size: DeviceIntSize,
70 ) {
71 save(path, orig_pixels, size, SaveSettings {
72 flip_vertical: true,
73 try_crop: true,
74 })
75 }
76
png( wrench: &mut Wrench, surface: ReadSurface, window: &mut WindowWrapper, mut reader: YamlFrameReader, rx: Receiver<NotifierEvent>, out_path: Option<PathBuf>, )77 pub fn png(
78 wrench: &mut Wrench,
79 surface: ReadSurface,
80 window: &mut WindowWrapper,
81 mut reader: YamlFrameReader,
82 rx: Receiver<NotifierEvent>,
83 out_path: Option<PathBuf>,
84 ) {
85 reader.do_frame(wrench);
86
87 // wait for the frame
88 rx.recv().unwrap();
89 wrench.render();
90
91 let (fb_size, data, settings) = match surface {
92 ReadSurface::Screen => {
93 let dim = window.get_inner_size();
94 let rect = FramebufferIntSize::new(dim.width, dim.height).into();
95 let data = wrench.renderer.read_pixels_rgba8(rect);
96 (dim, data, SaveSettings {
97 flip_vertical: true,
98 try_crop: true,
99 })
100 }
101 ReadSurface::GpuCache => {
102 let (size, data) = wrench.renderer
103 .read_gpu_cache();
104 (size, data, SaveSettings {
105 flip_vertical: false,
106 try_crop: false,
107 })
108 }
109 };
110
111 let out_path = out_path.unwrap_or_else(|| {
112 let mut path = reader.yaml_path().clone();
113 path.set_extension("png");
114 path
115 });
116
117 save(out_path, data, fb_size, settings);
118 }
119