1


I am facing a problem taking screenshots from Java on Linux with transparent windows.
The problem is that the screenshot taken with Robot deals with transparent windows as if they were opaque.
It is very similar to the problem stated at: Taking a screenshot in Java on Linux?

I wonder if there is any satisfactory solution to avoid this problem.

This is the code I use to take the screenshots:

protected BufferedImage getScreenShot()
{
    BufferedImage screenShotImage = null;

    try
    {
        screenShotImage = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
    }
    catch( Exception ex )
    {
        ex.printStackTrace();
    }

    return( screenShotImage );
}

The code to get the screenshot is the following (at the derived JFrame class):

public void M_repaint( )
{
    long timeStamp = System.currentTimeMillis();
    if( ( timeStamp - _lastScreenShotTimeStamp ) > 4000 )
    {
        updateAlpha( 0.0f );

        SwingUtilities.invokeLater( new Runnable(){
            @Override
            public void run()
            {
                BufferedImage image = getScreenShot();
                try
                {
                    ImageIO.write(image, "png", new File( "robotScreenshotBefore.png"));
                }
                catch( Exception ex )
                {
                    ex.printStackTrace();
                }

                try
                {
                    String[] cmd = { "./lens.screenshot.sh" };
                    Process script_exec = Runtime.getRuntime().exec(cmd);
                    script_exec.waitFor();
                }
                catch( Exception ex )
                {
                    ex.printStackTrace();
                }

                image = getScreenShot();
                try
                {
                    ImageIO.write(image, "png", new File( "robotScreenshotAfter.png"));
                }
                catch( Exception ex )
                {
                    ex.printStackTrace();
                }
                _lensJPanel.setScreenShotImage( image );
                updateAlpha( 1.0f );
            }
        });

        _lastScreenShotTimeStamp = timeStamp;
    }

    repaint();
}

The script ./lens.screenshot.sh has the following contents:

#/bin/bash
rm gnome-screenshot.png
gnome-screenshot --file="gnome-screenshot.png"

The application is a magnifying lens.
The way the application works is that every time the window (the lens) changes its position on the screen, the function M_repaint( ) is called.
Inside that function there is a kind of timer, that makes that when 4 seconds have elapsed from last screenshot, a new screenshot is taken in case the window appearence has changed

Previously to take the screenshot, the JFrame in made invisible, so that it does not appear inside the screenshot itself.
But once the window has been painted on the screen, it appears in the screenshot even if it had been made invisible previously.
I attach one of the sets of screenshots taken from the application with the previus code ( robotScreenshotBefore.png, gnome-screenshot.png and robotScreenshotAfter.png)

  • 1
    Could you please post a picture of the default screenshot and the one you got with the `Robot` class? – BackSlash Sep 18 '18 at 08:39

2 Answers2

0

I have updated the information on the question, and I will also attach the screenshots taken from a Linux machine

As we can see the first screenshot (the one that happens in a normal execution), shows the window just made transparent.
The following two screenshots show the window correctly made invisible (the first of them is taken directly from Linux and the last one, is taken with Robot, after having invoked the gnome screenshot tool)

The problem is that the application cannot wait for so much time before taking the screenshot, as this waiting time is showed as an anoying flicker.

robotScreenshotBefore.png
robotScreenshotBefore.png

gnome-screenshot.png
gnome-screenshot.png

robotScreenshotAfter.png
robotScreenshotAfter.png

0

Finally the solution found was to wait for some milliseconds for the transparency to take effect before taking the screenshot, in case the OS was not Windows.

So, the final function used to paint is the following:

public void M_repaint( )
{
    long timeStamp = System.currentTimeMillis();
    if( ( timeStamp - _lastScreenShotTimeStamp ) > 4000 )
    {
        updateAlpha( 0.0f );

        SwingUtilities.invokeLater( new Runnable(){
            @Override
            public void run()
            {
                if( !OSValidator.isWindows() )
                {
                    try
                    {
                        Thread.sleep( 26 );     // if mac or linux (and may be others), give enough time for transparency to take effect.
                    }
                    catch( Exception ex )
                    {
                        ex.printStackTrace();
                    }
                }

                BufferedImage image = getScreenShot();

                _lensJPanel.setScreenShotImage( image );
                updateAlpha( 1.0f );
            }
        });

        _lastScreenShotTimeStamp = timeStamp;
    }

    repaint();
}