2

I wrote a GUI-based Java program that takes 25 screenshots per second and saves them at a user-defined location.
It works pretty well except that it has two problems:

  • The mouse cursor is missing from the images and I know it will be because BufferedImages do not contain cursor information in them. They have to be added programatically.

  • The thread that takes screenshots is a daemon thread. So if I close the application, the thread is killed and the PNG image that was being written gets corrupted. I want to avoid that.

  • Here are the images of my application:
    The award-winning, intuitive GUI:
    enter image description here

    The high-definition images captured look like this:
    enter image description here
    As you can see from the image the cursor information is being displayed in the console using MouseInfo's static methods.


    Please let me know how to solve the above mentioned two problems.
    After solving the problem, the images now look like this:
    with cursor

    Dummy Derp
    • 237
    • 1
    • 3
    • 15

    1 Answers1

    2

    The mouse cursor is missing from the images and I know it will be because BufferedImages do not contain cursor information in them. They have to be added programatically.

    That is correct, you have to add the cursor afterwards. The reason for this is that a screenshot taken with the Robot class never contains the cursor. Not really because "the BufferedImage doesn't contain mouse info". A BufferedImage is a class that contains a raster of pixels.

    The thread that takes screenshots is a daemon thread. So if I close the application, the thread is killed and the PNG image that was being written gets corrupted. I want to avoid that.

    Simply, in the screenshot thread, use a flag that indicates wether it should continue or not. Keep taking screenshots as long as that boolean is set to true. Make sure to make it non-deamon. So, when you close the application, set the flag to false. Probably the most easy way to do this is to add a WindowListener:

    yourFrame.addWindowListener(new WindowAdapter()
    {
        public void windowClosed(WindowEvent e)
        {
            screenshotThread.stopTakingScreenshots(); // This methods set the flag
        }
    }
    

    Also notice that you are not taking the time it takes to make and save a screenshot in count. You use a fixed sleep of 40 milliseconds, but let's say that it takes 4 milliseconds to take and save the screenshot, then you should sleep for only 36 milliseconds. To time how long it takes to make the screenshot, use System.currentTimeMillis(); before and after your takeShot() method and make the difference.

    Martijn Courteaux
    • 67,591
    • 47
    • 198
    • 287
    • this can be done by implementing the `finalize()` method for the GUI window where I set the flag to false? and second, please tell me more about the first issue. – Dummy Derp Sep 11 '12 at 18:11
    • The application thread should wait for the screenshot thread to signal that it is finished. This would be in the application close method. – Gilbert Le Blanc Sep 11 '12 at 18:13
    • Reading up on destroy(), hang on! :) – Dummy Derp Sep 11 '12 at 18:14
    • 1
      `You use a fixed sleep of 40 milliseconds` Im so proud that my program takes such high-def images that you could read what was in the screenshot. :p Kidding! – Dummy Derp Sep 11 '12 at 18:20
    • Just to keep you updated, both the problems have been solved. – Dummy Derp Sep 12 '12 at 11:17
    • @DummyDerp: How did you add the cursor to the screenshots? Is is a pseudo cursor you drew (like a simple square or circle), or the real cursor image on that moment of recording? – Martijn Courteaux Sep 12 '12 at 11:36
    • The whole code is not needed. Just some simple references of the techniques you used. Yesterday, I googled a bit on how to do it. But I couldn't find out. – Martijn Courteaux Sep 12 '12 at 11:39
    • and another question: How do I lock the folder to which I am writing the images? – Dummy Derp Sep 12 '12 at 11:39
    • `Graphics2D g2D =(Graphics2D) img.getGraphics();` obtain Graphics2D and then draw the required image on the `BufferedImage` `g2D.drawImage(((ImageIcon)selectedCursor).getImage(),myCursorPoint.x,myCursorPoint.y,SCapGUI.this);` – Dummy Derp Sep 12 '12 at 11:40
    • 1
      Yes, that part is pretty obvious. But how to you get the current cursor image? – Martijn Courteaux Sep 12 '12 at 11:41
    • Oh, I see, you are not using the real cursor. Just a image of a default cursor. But when the cursor changes, because you are on a button, the recording will not show a hand, but the arrow. – Martijn Courteaux Sep 12 '12 at 11:56
    • That is correct. Sorry I deleted the posts so that I can post them back in a more organised manner. – Dummy Derp Sep 12 '12 at 11:57
    • 1. Create an `ImageIcon` object that stores the image of your cursor. 2. When editing the `BufferedImage` just call the `getImage()` method and it will return a `Image` object as required by the `draw()` method – Dummy Derp Sep 12 '12 at 11:59
    • @MartijnCourteaux How do I lock the folder to which I am writing the images? – Dummy Derp Sep 12 '12 at 12:00
    • I don't know. That depends on your OS for sure. Maybe this can help you: http://stackoverflow.com/questions/128038/how-can-i-lock-a-file-using-java-if-possible – Martijn Courteaux Sep 12 '12 at 12:05