Powershell: Write-Host is very slow

Viewed 329

I have a Java application which has a functionality to take a screenshot. It does it by running Powershell script:

Add-Type -AssemblyName System.Windows.Forms,System.Drawing

$screens = [Windows.Forms.Screen]::AllScreens

$top    = ($screens.Bounds.Top    | Measure-Object -Minimum).Minimum
$left   = ($screens.Bounds.Left   | Measure-Object -Minimum).Minimum
$width  = ($screens.Bounds.Right  | Measure-Object -Maximum).Maximum
$height = ($screens.Bounds.Bottom | Measure-Object -Maximum).Maximum

$bounds   = [Drawing.Rectangle]::FromLTRB($left, $top, $width, $height)

$bmp      = New-Object System.Drawing.Bitmap ([int]$bounds.width), ([int]$bounds.height)

$graphics = [Drawing.Graphics]::FromImage($bmp)

$graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)

$memStream = New-Object System.IO.MemoryStream

$bmp.Save($memStream, [Drawing.Imaging.ImageFormat]::Jpeg)

Write-Host $memStream.ToArray()

$graphics.Dispose()
$bmp.Dispose()
$memStream.Dispose()

Java application listens to the output of it and does some operations on it. The problem is that sometimes Write-Host $memStream.ToArray() takes too much time(Sometimes in 2 minutes, sometimes 3 even 5). I'm not familiar with Powershell is there any analog of Write-Host which is faster? Or maybe I can take a screenshot using some other functionality faster? Thanks

1 Answers

You stated a solution using other functionality would be acceptable, so why not perform the screen capture directly with the Java application instead? Java is fully capable of this natively:

import java.awt.Robot;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.AWTException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

// Set up Robot and other vars
Robot robot = new Robot();
String imgFormat = "jpg";
BufferedImage screenBuffer;
Rectangle screenBounds;

// Enumerate all screens
GraphicsEnvironment graphEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] screens = graphEnv.getScreenDevices();

// Variables only used for generating filename
String fnameFormat = "%s-%s-screencap.%s";
String dtNowString = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
String filename = String.format(fnameFormat, dtNowString, "all", imgFormat);

Rectangle allScreenBounds = new Rectangle();
int num = 0;
for(GraphicsDevice screen : screens) {
  screenBounds = screen.getDefaultConfiguration().getBounds();
  allScreenBounds.x = Math.min(allScreenBounds.x, screenBounds.x);
  allScreenBounds.y = Math.min(allScreenBounds.y, screenBounds.y);

  // Make sure we only add extra pixels to the total width and height, subtracting overlapping dimensions
  // Does not take into account non-continuous display area, normally impossible on Windows
  allScreenBounds.width += Math.abs(allScreenBounds.width - (screenBounds.width + screenBounds.x));
  allScreenBounds.height += Math.abs(allScreenBounds.height - (screenBounds.height + screenBounds.y));

  System.out.println(String.format("Display %d: X=%d, Y=%d, Height=%d, Width=%d", num++, screenBounds.x, screenBounds.y, screenBounds.height, screenBounds.width));
}

System.out.println(String.format("Screen Area: X=%d, Y=%d, Height=%d, Width=%d", allScreenBounds.x, allScreenBounds.y, allScreenBounds.height, allScreenBounds.width));
screenBuffer = robot.createScreenCapture(allScreenBounds);

// Save the screencap to file
ImageIO.write(screenBuffer, imgFormat, new File(filename));

There is file-writing code there for testing but if this is performed by your application you can remove the filename variables, import javax.imageio.ImageIO, and the ImageIO.write call as you'll have the screenshot data in screenBuffer instead.

Related