Monday, February 21, 2011

Java multi-monitor screenshots

Random snippets I might want again one day ;)

Create a "C:\\CanDelete" directory before running any of this, or change the path building.

Take a screenshot of each monitor individually:
package com.blogspot.whileonefork.screencapture;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;


public class EachMonitor {
 public static void main(String[] argv) throws Exception {
  //Take a screenshot of every monitor
  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsDevice[] screens = ge.getScreenDevices();
  
  for (GraphicsDevice screen : screens) {
   Robot robotForScreen = new Robot(screen);
   Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
   
   //The screen bounds have an annoying tendency to have an offset x/y; we want (0,0) => (width, height)
   screenBounds.x = 0;
   screenBounds.y = 0;
   BufferedImage screenShot = robotForScreen.createScreenCapture(screenBounds);
   String ext = "jpg";
   String outputFile = "C:\\CanDelete\\screenshot_" 
    + screen.getIDstring().replaceAll("[^A-Za-z0-9]", "_")
    + "."
    + ext;   
   ImageIO.write(screenShot, ext, new File(outputFile));
   System.out.println("Saved " + outputFile 
    + " of " + screen.getIDstring() 
    + " xy=(" + screenBounds.x + "," + screenBounds.y + ")"
    + " bounds=("+ screenBounds.width + "," + screenBounds.height + ")");
  }
 }
}


Take a single big screenshot of all monitors:

package com.blogspot.whileonefork.screencapture;

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class AllMonitors {
 public static void main(String[] argv) throws Exception {      
  /**
   * Take one big screenshot of the entire UI. 
   * On my Windows box monitors seem to act like they are side by side on X, extending on Y.
   * Seems, at least on windows, to ignore any offset config setup in display properties.
   */
  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsDevice[] screens = ge.getScreenDevices();
  
  Rectangle allScreenBounds = new Rectangle();
  for (GraphicsDevice screen : screens) {
   Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
   
   allScreenBounds.width += screenBounds.width;
   allScreenBounds.height = Math.max(allScreenBounds.height, screenBounds.height);      
  }
  
  Robot robot = new Robot();
  BufferedImage screenShot = robot.createScreenCapture(allScreenBounds);
  
  String ext = "jpg";
  String outputFile = "C:\\CanDelete\\AllMonitors" 
   + "."
   + ext;   
  ImageIO.write(screenShot, ext, new File(outputFile));
  System.out.println("Saved " + outputFile 
   + " of all monitors " 
   + " xy=(" + allScreenBounds.x + "," + allScreenBounds.y + ")"
   + " bounds=("+ allScreenBounds.width + "," + allScreenBounds.height + ")");  
 } 
}


All this has been tested exactly once on a Windows box with two monitors of substantially different size; ymmv :)

8 comments:

Dustin Gamester said...

This seems to give errors when the first monitor is lower than the following monitors. If anyone else runs into this problem a corrected version can be found below. Also note that this version does not save a file, and instead returns a buffered image.


package book;

import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AllMonitors {

public BufferedImage getScreenshot() {

//get handle to graphics environment
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] screens = ge.getScreenDevices();

//if screens are detected proceed
if (screens.length > 0) {

try {
//get the first screen
GraphicsDevice a = screens[0];

//get the monitor resolution
Toolkit t = Toolkit.getDefaultToolkit();
Rectangle allScreenBounds = new Rectangle(t.getScreenSize());

//offset screen capture (in cases where first monitor is not the
//highest this will come into effect)
allScreenBounds.y = -1 * screens[0].getDefaultConfiguration().getBounds().y;

//take screenshot
Robot robot = new Robot();
BufferedImage screenShot = robot.createScreenCapture(allScreenBounds);

return screenShot;
} catch (AWTException ex) {
Logger.getLogger(AllMonitors.class.getName()).log(Level.SEVERE, null, ex);
}
}

//if no screens detected return null
return null;
}
}

Sorin Portase said...

The code to compute the virtual screen bounds can be found in the jdk's javadoc (http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/GraphicsConfiguration.html):

Rectangle virtualBounds = new Rectangle();
GraphicsEnvironment ge = GraphicsEnvironment.
getLocalGraphicsEnvironment();
GraphicsDevice[] gs =
ge.getScreenDevices();
for (int j = 0; j < gs.length; j++) {
GraphicsDevice gd = gs[j];
GraphicsConfiguration[] gc =
gd.getConfigurations();
for (int i=0; i < gc.length; i++) {
virtualBounds =
virtualBounds.union(gc[i].getBounds());
}
}

Scott Schafer said...

Thanks for this post, but especially +1000 to Dustin. If I had hair, I would have pulled it all out over this bug. Your comment saved me a lot of aggravation.

joe pelletier said...

add this to the end of the for loop and it will work with as many monitors as you have ::: allScreenBounds.x=Math.min(allScreenBounds.x, screenBounds.x);
allScreenBounds.y=Math.min(allScreenBounds.y, screenBounds.y);

joe pelletier said...

add this to the end of the for loop and it will work with as many monitors as you have ::: allScreenBounds.x=Math.min(allScreenBounds.x, screenBounds.x);
allScreenBounds.y=Math.min(allScreenBounds.y, screenBounds.y);

for IT the said...

I have read your blog its very attractive and impressive. I like it your blog.

Java Training in Chennai Core Java Training in Chennai Core Java Training in Chennai

Java Online Training Java Online Training Core Java 8 Training in Chennai Core java 8 online training JavaEE Training in Chennai Java EE Training in Chennai

Naviya Nair said...

I have read your blog its very attractive and impressive. I like it your blog.

Java Online Training Java EE Online Training Java EE Online Training Java 8 online training Core Java 8 online training

Java Online Training from India Java Online Training from India Core Java Training Online Core Java Training Online Java Training InstitutesJava Training Institutes

Asim Shaikh said...

Thanks for sharing the info, keep up the good work going.... I really enjoyed exploring your site. good resource...best modem router combo

Post a Comment