Nannou: Add saveFrame method

Created on 2 Aug 2018  路  6Comments  路  Source: nannou-org/nannou

Hello there,
I've been looking into switching to nannou for my daily generative animations (insta), but my usual workflow is to generate frames of the animation to encode later with ffmpeg. (I'm currently using a custom wrapper in Scala around the Processing libraries.)

I'm a complete beginner in Rust so of course in nannou as well, but I could not find any reference to a similar function. I guess I could directly read the pixels from the gl context but that sounds a bit scary now, and against the idea of having a beginner friendly environment.

Would it be possible to have this feature in the framework? Or any other way to export the rendered output to share online?

I'll be more than willing to contribute back once I get used to rust, but this is a key issue for me to switch to nannou at the moment.

Most helpful comment

@jli I think this should be solved by Window::capture_frame and TextureCapturer now - check out the draw_capture.rs and draw_capture_hi_res.rs examples for their respective examples. Let me know your thoughts!

All 6 comments

Hey @MacTuitui, really nice animations!

I think the method you're looking for is Window::read_front_buffer. You can get access to the window via app.window(window_id) or app.main_window() might be easier if you just have a single window. You might need to use it in combination with the image crate. Glium (the OpenGL library we're using at the moment) has a nice example of this here.

I like your idea of adding a save_frame method - it would be nice to have a simpler method that simplifies this! We should also add an example for this, as I'm sure there are more people who would find this useful!

Out of curiosity, what format do you encode your animations to?

Thanks! I think I can manage to figure out the details with this info.

I'll try to do the switch as soon as I get comfortable with rust and eventually I'll submit a PR with a save_frame method inspired by what Processing has, with automatic numbering / string formatting etc... Feel free to close this issue until then.

As for the encoding format, I usually encode to h.264/mp4 with pixel format yuv420 (as no online platform that I now of supports true colors) for instagram and when I think that the compression settings used by twitter will kill everything (and for what I do, I sometimes end up with very heavy videos - 80M for 10 seconds is not rare), I try to make a GIF... then it's a challenge to stay within the 15M limit of twitter!

Small update to tell you where I'm at with this issue.

I'm currently using the following code to automate the saving process.

if app.elapsed_frames() > START_FRAME {
  let image:  nannou::glium::texture::RawImage2d<u8> = app.main_window().read_front_buffer();
  let image = nannou::image::ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
  let image = nannou::image::DynamicImage::ImageRgba8(image).flipv();
  image.save(format!("frame-{:04}.png", app.elapsed_frames()-START_FRAME)).unwrap();
}
if app.elapsed_frames() > LENGTH_FRAMES-START_FRAME {
  exit(0)
}

Where START_FRAME and LENGTH_FRAMES are global constants to decide when to start and when to stop the sketch.

And it's... super slow. The first thing to note is that this will give you images twice the size of the sketch, and since I did not find a way to save as tiff in the image crate, I don't know if that's the conversion to png or getting the data in the right format that is slow. I know you are working on getting support for (complex) framebuffers, maybe there might be something to do to make this faster.

(In processing I was able to get the image data then spawn a new thread to save the data to disk, getting no huge overhead on the main thread by using all possible threads, usually not used in a sketch.)

see also 319

afaict, I think we're still missing a built-in saveFrame method, so could we reopen this?

I saw @MacTuitui had this screenshot example: https://github.com/MacTuitui/nannou-screenshot-example (apparently based on work by @freesig ).

I think it'd be nice if something like this was built in, wdyt?

@jli I think this should be solved by Window::capture_frame and TextureCapturer now - check out the draw_capture.rs and draw_capture_hi_res.rs examples for their respective examples. Let me know your thoughts!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tpltnt picture tpltnt  路  4Comments

dimitre picture dimitre  路  3Comments

mkesper picture mkesper  路  4Comments

mitchmindtree picture mitchmindtree  路  4Comments

jtnimoy picture jtnimoy  路  3Comments