1

I want to take the screenshot of a java native application ( any framework AWT, Swing, JavaFx ) without bringing it to the foreground. Are there any framework-specific methods available for this?

I have tried using Robot class to get the screenshot

private static void capture(int x, int y , int width , int height, String setName) {
    Robot robot = new Robot();
    Rectangle area = new Rectangle(x, y, width, height);
    BufferedImage image = robot.createScreenCapture(area);
    ImageIO.write(image, "png", new File(System.getProperty("user.dir") + "\\images\\" + setName +".png"));
}

Now robot class with just take the area coordinates and capture the image, whether the target application is on the top or not, to get the application on the top I am using JNA to bring it to focus

private static void bringToFocus() {
    for (DesktopWindow desktopWindow : WindowUtils.getAllWindows(true)) {
        if (desktopWindow.getTitle().contains("notepad")) {
            HWND hwnd = User32.INSTANCE.FindWindow(null, desktopWindow.getTitle());
            User32.INSTANCE.SetForegroundWindow(hwnd);
            break;
        }
    }
}

But this is an example where we need to capture only one application, if we need to capture 10 applications screenshots we need to one by one bring them to the front and capture and bring next.

Is there any framework specific method availabe which can take the application screenshot without bringing it to the front.

Jonas
  • 121,568
  • 97
  • 310
  • 388
ameer zeya
  • 23
  • 4
  • 1
    Related [How to take snapshot of selected area of screen in javafx?](https://stackoverflow.com/questions/41287372/how-to-take-snapshot-of-selected-area-of-screen-in-javafx) – jewelsea Jan 23 '23 at 06:31
  • 1
    Remember, if you're trying to get the system to take the snapshot, then application will need to be in the foreground, as it's capturing what's been rendered onto the screen itself. You "could" move them to an off screen position first and try snapshotting them from there, but, unless you're running within the same JVM as the applications, you really don't have many options – MadProgrammer Jan 23 '23 at 09:02
  • 1
    One option for Java Swing is to modify the application itself to take its own snapshots at various checkpoints by using the `JPanel` `print` method. – Gilbert Le Blanc Jan 23 '23 at 13:13
  • @MadProgrammer I can use agentmain to inject in the running JVM, do we have a solution in that scenario ? – ameer zeya Jan 23 '23 at 17:14
  • @ameerzeya You would then need to know which UI framework is in use - which might take more work and could have an adverse effect on the running system - I'm just saying – MadProgrammer Jan 23 '23 at 20:36

1 Answers1

0

If your screen shot only needs to be of the Java GUI, you can paint to a BufferedImage

public static Image screenShot(Component c) {
  BufferedImage im = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
  Graphics g = im.getGraphics();
  c.paint(g); // Paint is the proper entry point to painting a (J)Component, rather than paintComponent
  g.dispose(); // You should dispose of your graphics object after you've finished
  return im;
}

If your requirement is to paint the Java GUI component along with the rest of the screen, but like your java (J)Frame is in front, you can do that by painting the screen using the robot first, then doing what I've posted above, but with the BufferedImage (which has already been drawn on) being passed in as a parameter rather than being created in the method.

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • `printAll` not `paint` - `paint` could easily run you into a `NullPointerException` – MadProgrammer Jan 23 '23 at 20:36
  • @MadProgrammer re: "run you into an NPE" - I didn't know that. Can you explain how this could occur and how printAll would fix this problem? – ControlAltDel Jan 23 '23 at 20:44
  • from (bad) memory, it has to do with the double buffering and the native peer. It's possible that the app is detected from the native peer on some systems when it's present on the screen (ie hidden) to save resources (or something like that), where as `paintAll` does to use double buffering our relies on the native peer. It'a also possible for `paint` not to paint ALL the component (or child components), possibly due to optimisation, `printAll` is generally a safer bet when you want to do these kind of things – MadProgrammer Jan 23 '23 at 20:46
  • @MadProgrammer Hi again. I respectfully disagree. `print` and `printAll` are API for printing to paper, and using this for a screenshot could get you in trouble if the user has a `Component` that overrides print (say, to not draw the background). Re: Double buffering: `paint` is just a method, and calling it doesn't affect double buffering. Lastly, as far as paint/paintAll or printAll, line 270 in (https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/print/StandardPrint.java) for years ago is how I was painting to a BufferedImage. Anyhoo, I'll leave it to OP to figure out what's right. – ControlAltDel Jan 24 '23 at 15:02
  • No issue mate - but I use `printAll` ALL the time to take screen shots because I hit a NPE when using `paint`. *"get you in trouble if the user has a Component that overrides print"* - So, this is maybe not the right place to do those things - but that's a discussion for another day – MadProgrammer Jan 24 '23 at 20:45
  • Taking a few moments to look into the code, print will call paint - but it modifies the workflow through a `IS_PRINTING` which skips over delegating the actual paint workflow to the `RepaintManager` and about there my mind imploded :P - but deals a lot with the low level aspects of painting (including double buffering and I think `VolatileImage` for hardware acceleration) – MadProgrammer Jan 24 '23 at 20:55
  • In case you still want to keep using the `paint` workflow - might I suggest `paintAll` instead – MadProgrammer Jan 24 '23 at 20:57
  • @MadProgrammer Yes you can suggest paintAll over paint; I don't remember why I made the decision to call paint over paintAll. Also, looking around a little bit, I found this from a long time ago: https://stackoverflow.com/questions/18527102/does-jframe-paintall-work-in-linux so at least you can say your advice is consistent! – ControlAltDel Jan 24 '23 at 21:33
  • Working across a number of different platforms, you tend to run into some "interesting" things – MadProgrammer Jan 24 '23 at 22:03