Rendering window contents to image file


#1

Is there a way to render the contents of a window to an image file?

I've (accidently) created a really cool animation I would like to render out as seperate frames.

I could then put these together to create a movie file or import into some animation software. 

 

Thanks :)


#2

- Create an Image object to draw onto.
- Create a Graphics object; parameter is an Image object to "draw" onto. Use step 1's Image!
- Manage to get a pointer to the desired top-most level Component.
- Call Component::paint() with your Graphics object.
- Now, create an instance of desired ImageFileFormat subclass (PNGImageFormat, GIFImageFormat, JPEGImageFormat).

 

And now I leave the last bit up to you for at least some challenge; link a destination File, your Image object you've painted to and a call to your ImageFileFormat object's writeImageToStream() together.


#3

I am a big fan of "Time is Money" in the real world so I extracted this from my code. Why spend time figuring out how the hammer is made when you can start nailing right away. Hope this works

Image image( Image::ARGB, w, h, true, NativeImageType() );
Graphics g( image );

Component *pComponent = &yourComponent; //Address of your cocomponent
pComponent->paint( g );

//If ypou want a area of the component
image = image.getClippedImage( rect );

File file = fc.getResult().getFullPathName();
file = file.withFileExtension( ".png" ); //Or .gif, .jpg,...
FileOutputStream    stream( file );

if ( file.hasFileExtension( ".jpg" ) )
{
    JPEGImageFormat jPeg;
    jPeg.writeImageToStream( image, stream );
 }
 else if ( file.hasFileExtension( ".gif" ) )
 {
     GIFImageFormat gif;
     gif.writeImageToStream( image, stream );
 }
 else if ( file.hasFileExtension( ".png" ) )
 {
     PNGImageFormat png;
     png.writeImageToStream( image, stream );
 }

#4

Hmm. That's not a very good example for the OP to follow. It won't handle all image file extensions, check for failure in opening the stream, choose the correct image size, render any subcomponents, or choose between RGB/ARGB formats depending on whether the component is opaque.

What you want is something like this:

static bool writeComponentImageToFile (const File& file, Component& comp, Rectangle<int> subArea)
{
    if (ImageFileFormat* format = ImageFileFormat::findImageFormatForFileExtension (file))
    {
        FileOutputStream out (file);

        if (out.openedOk())
            return format->writeImageToStream (comp.createComponentSnapshot (subArea), out);
    }

    return false;
}

I've not tried compiling this, but you get the gist..


#5

Thanks guys much appreciated will have a play with this over next few days.


#6

Hi
I have almost the same issue here. I’m looking for a way to create a small thumbnail of the screen content of a window when it is not visible. The thumbnail should then be saved as small bmp files. Is that possible also? FYI I’m a newbie to JUCE :innocent:

-Cheers


#7

There are a lot of approaches in the thread, please let us know, which you tried and where you are stuck, otherwise we just repeat what is already said.

One thing I found to add, there is a helper method Component::createComponentSnapshot() which will create the Image for you. I don’t think it needs to be visible to do that, but you need to give it a size (call setSize() if it is a top level component or it may be set by it’s parent’s resized() method.

// ScopedPointer<Component> comp = new MyComponent();  // given component is a valid Component*
// comp->setSize (600, 400);                           // only needed if comp has no size set
File thumbFile = File::getSpecialLocation (File::userDesktopDirectory).getChildFile ("snapshot.png");
Image snapShot = comp->createComponentSnapshot (comp->getLocalBounds());
Image thumbnail = snapShot.rescaled (100, 100 * comp->getHeight() / copm->getWidth());

// copied from jules' posting above:
if (ImageFileFormat* format = ImageFileFormat::findImageFormatForFileExtension (thumbFile))
{
    FileOutputStream out (thumbFile);
    if (out.openedOk())
        format->writeImageToStream (thumbnail, thumbFile);
}

#8

Hi Daniel. Thanks a lot for your help!! -The code seems to work just fine :slight_smile: But I’m still struggling to make it work in the case when a window contains a VST GUI object of the type ‘AudioProcessorEditor’. When I do the same with such a window, the result is a well sized png file but its empty though. I’m just using the JUCE example ‘Audio Plugin Host’, and the idea was just to let the application create a set of small thumbs of all found VST instruments :slight_smile:
-Merry Christmas


#9

That’s a great idea, that would be very useful.

The problem with the vst-gui might be, that in this case it doesn’t use the JUCE graphics context to render, but I think it uses the window handle from the OS.
I had no time to dig into the hosting example, maybe somebody else can chime in, how this can be done…

Good luck!


#10

There’s a hidden JUCE function to create an Image from a native window handle. You’ll have to declare it like so in your own code:

namespace juce
{
    Image createSnapshotOfNativeWindow (void* nativeWindowHandle);
}

then call it with ComponentPeer::getNativeHandle()

Depending on the plugin format and window decorations you may have to remove trim these if required.


#11

Following on from my initial question, I’m currently trying to work out a neat way of rendering a component to an image at a specific size, without making an off-screen copy of it (it only seemed to render the background that way).
Basically I want to render an image of part of the screen at a consistent size, rather than its visible dimensions (which are dependant on the device screen size and orientation).


#12

Hi Dave, -your made my day :slight_smile: it works!! Thanks a 1000 times! Cheers.