From 31f7c4ba141126f37af7181a5e2589be708aaf4c Mon Sep 17 00:00:00 2001 From: Jack Moffitt Date: Tue, 16 Jul 2013 09:54:16 -0600 Subject: [PATCH] Write out PNG file after compositing based on `-o` option. --- src/components/main/compositing/mod.rs | 45 ++++++++++++++++++++++---- src/components/main/servo.rc | 1 + src/support/opengles/rust-opengles | 2 +- src/support/png/rust-png | 2 +- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index d277c2f551e..fa9799210b5 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -24,6 +24,8 @@ use std::comm; use std::comm::{Chan, SharedChan, Port}; use std::num::Orderable; use std::task; +use std::uint; +use std::vec; use extra::uv_global_loop; use extra::timer; use geom::matrix::identity; @@ -35,6 +37,8 @@ use layers::layers::{ImageData, WithDataFn}; use layers::layers::{TextureLayerKind, TextureLayer, TextureManager}; use layers::rendergl; use layers::scene::Scene; +use opengles::gl2; +use png; use servo_util::{time, url}; use servo_util::time::profile; use servo_util::time::ProfilerChan; @@ -464,6 +468,8 @@ impl CompositorTask { }; let profiler_chan = self.profiler_chan.clone(); + let write_png = self.opts.output_file.is_some(); + let exit = self.opts.exit_after_load; let composite = || { do profile(time::CompositingCategory, profiler_chan.clone()) { debug!("compositor: compositing"); @@ -474,7 +480,40 @@ impl CompositorTask { rendergl::render_scene(context, scene); } + // Render to PNG. We must read from the back buffer (ie, before + // window.present()) as OpenGL ES 2 does not have glReadBuffer(). + if write_png { + let (width, height) = (window_size.width as uint, window_size.height as uint); + let path = Path(*self.opts.output_file.get_ref()); + let mut pixels = gl2::read_pixels(0, 0, + width as gl2::GLsizei, + height as gl2::GLsizei, + gl2::RGB, gl2::UNSIGNED_BYTE); + // flip image vertically (texture is upside down) + let orig_pixels = pixels.clone(); + let stride = width * 3; + for uint::range(0, height) |y| { + let dst_start = y * stride; + let src_start = (height - y - 1) * stride; + vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride), + orig_pixels.slice(src_start, src_start + stride), + stride); + } + let img = png::Image { + width: width as u32, + height: height as u32, + color_type: png::RGB8, + pixels: pixels, + }; + let res = png::store_png(&img, &path); + assert!(res.is_ok()); + + *done = true; + } + window.present(); + + if exit { *done = true; } }; // When the user scrolls, move the layer around. @@ -548,12 +587,6 @@ impl CompositorTask { *recomposite = true; } - if self.opts.exit_after_load { - do window.set_finished_callback || { - *done = true; - } - } - // Enter the main event loop. while !*done { // Check for new messages coming from the rendering task. diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index a009790daad..1f660764c93 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -21,6 +21,7 @@ extern mod js; extern mod layers; extern mod newcss (name = "css"); extern mod opengles; +extern mod png; extern mod script; extern mod servo_net (name = "net"); extern mod servo_msg (name = "msg"); diff --git a/src/support/opengles/rust-opengles b/src/support/opengles/rust-opengles index 17bd4bbc049..b5cb5593f49 160000 --- a/src/support/opengles/rust-opengles +++ b/src/support/opengles/rust-opengles @@ -1 +1 @@ -Subproject commit 17bd4bbc04942e7de9eae76c0f8a76dfcb3dc9fc +Subproject commit b5cb5593f4938a578eebda56c905bbaff33efe66 diff --git a/src/support/png/rust-png b/src/support/png/rust-png index e2b6deb09da..8cf4744b6c1 160000 --- a/src/support/png/rust-png +++ b/src/support/png/rust-png @@ -1 +1 @@ -Subproject commit e2b6deb09da651aa188f154394d63f45188de653 +Subproject commit 8cf4744b6c17a1df5f4f056313d32fb6e5af959e