/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.ui.test.util; import com.google.dart.tools.ui.Activator; import java.awt.AWTException; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.imageio.ImageIO; /** * Dumps a <em>png</em> of the current screen in the standard "captures" output directory (as * defined by {@link ScreenCapture#getOutputLocation()}). * <p> * Since taking screen shots consumes considerable resources, heap limits may be exceeded during a * capture. To address this, {@link OutOfMemoryError}s are caught and the capture retried after a * short interval ( {@link ScreenCapture#CAPTURE_RETRY_INTERVAL}). The number of retries is bounded * by {@link ScreenCapture#MAX_CAPTURE_RETRIES}. */ public class ScreenCapture { public static final long CAPTURE_RETRY_INTERVAL = TimeUnit.SECONDS.toMillis(3); public static final int MAX_CAPTURE_RETRIES = 5; public static final String OUTPUT_DIR = "captures"; private static final String BASE_IMAGE_NAME = "screenshot"; private static final String IMAGE_EXT = "png"; private static final String PATH_DELIM = System.getProperty("file.separator"); // Keep a static Robot around to do the screencapture private static Robot robot; // Increment counter for unique screenshot file names on a per run basis private static int counter = 0; static { try { robot = new Robot(); } catch (AWTException e) { Activator.logError(e); } } private static BufferedImage captureScreen() { Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screenSize = toolkit.getScreenSize(); Rectangle screenRect = new Rectangle(screenSize); for (int i = 0; i < MAX_CAPTURE_RETRIES; ++i) { try { return robot.createScreenCapture(screenRect); } catch (OutOfMemoryError e) { Activator.logError("OutOfMemoryError caught in screen capture (attempt [" + i + "])"); try { Thread.sleep(CAPTURE_RETRY_INTERVAL); } catch (InterruptedException ie) { //Just continue } } } Activator.logError("Screen Capture failed"); return null; } private static File createScreenCaptureFile(BufferedImage image, String name) { File file; try { ensureOutputDirExists(); file = writeFile(image, name); } catch (IOException e) { Activator.logError(e); return null; } return file; } private static void ensureOutputDirExists() { File dir = new File(OUTPUT_DIR); if (!dir.exists()) { dir.mkdir(); } } private static String getOutputLocation() { return OUTPUT_DIR + PATH_DELIM; } private static File writeFile(BufferedImage image, String name) throws IOException { String path = getOutputLocation() + name + "_" + BASE_IMAGE_NAME + "_" + counter++ + "." + IMAGE_EXT; File file = new File(path); ImageIO.write(image, IMAGE_EXT, file); return file; } /** * Save the screen pixels as a PNG image file in the {@value #OUTPUT_DIR} directory. Existing * screen capture files will be overwritten. The name parameter will be used as a prefix for the * name of the produced image. * * @return the file into which the image was stored, or <code>null</code> if the image could not * be stored. */ public File createScreenCapture(String name) { BufferedImage image = captureScreen(); if (image == null) { return null; } return createScreenCaptureFile(image, name); } }