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 :)

7 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

Post a Comment