Currently I am developing a project and it is a requirement that I screenshot the current active window on the screen (Assuming one monitor) and save it as an image.
I have worked at the following code which screenshots the entire screen:
int x = 0,y = 0;
Color suit = new Robot().getPixelColor(x, y);
Rectangle fs = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage rank = new Robot().createScreenCapture(fs);
ImageIO.write(rank, "bmp", new File("hi.bmp"));
and I am of the understanding that to get the size of the current active window one must use a method as such:
public static long getHWnd(Frame f) {
return f.getPeer() != null ? ((WComponentPeer) f.getPeer()).getHWnd() : 0;
}
however I am having trouble implementing this method into my code, and I have no previous experience working with frames or rectangles.
Could I be pointed in the right direction in terms of where to go next!
Thanks.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Out of the box, webdriver only takes a screenshot of the visible page area.
Following on from this post, I would like to ask how to take a full page screenshot in Selenium using Java, when the page length is greater than the viewport?
The posts describing how to do this are either unanswered (such as this one) or point towards the AShot library (such as this one) which provides the functionality, but it has some issues which means I do not want to use it. Specifically, when using a remote driver on e.g. Browserstack, it only renders the left-hand half of the screenshot. In addition it is no longer maintained by the original author and so it seems more appropriate to write a new function for what is essentially a fairly simple problem.
Prerequisite: access to an instance of WebDriver. Mine is instantiated with the class the code lives in.
The main function that coordinates the size of the screenshot and the scrolling down the page is as follows. Note that the image format is to make it compatible with pdiff :
public void takeFullScreenshot(String outputFile) throws IOException {
JavascriptExecutor js = ((JavascriptExecutor) webDriver);
// Scroll right to the top
js.executeScript("window.scrollTo(0,0)");
// Get the height of the screen
int windowHeight = ((Number) js.executeScript("return window.innerHeight")).intValue();
// Get the total height of the page
int pageHeight = ((Number) js.executeScript("return document.body.scrollHeight")).intValue();
// Calculate the number of full screen shots
double fullFraction = pageHeight / windowHeight;
int fullShots = (int) fullFraction; // this simply removes the decimals
// Initialise ouput image
int imageWidth = webDriver.manage().window().getSize().width;
BufferedImage fullScreenshot = new BufferedImage(imageWidth, pageHeight, BufferedImage.TYPE_4BYTE_ABGR);
// Get the graphics
Graphics2D fullGraphics = fullScreenshot.createGraphics();
// Calculate our scroll script
String script = "window.scrollBy(0," + String.valueOf(windowHeight) + ")";
// Loop - for the required number of full screenshots
for (int aShot = 0; aShot < fullShots; aShot ++) {
// Sort out the screenshot and paste it in the correct place
pasteScreenshot(fullGraphics, aShot * windowHeight);
// scroll
js.executeScript(script);
}
// Final phase - scroll to the bottom
js.executeScript(script); // we know this goes too far down, but should be OK.
// Take final screenshot and paste at the bottom
pasteScreenshot(fullGraphics, pageHeight - windowHeight);
// Save the whole thing to output file.
ImageIO.write(fullScreenshot, "PNG", new File(outputFile));
}
The little function that pastes the screenshot into the correct place in the output graphics is as follows:
private void pasteScreenshot (Graphics2D outputGraphics, int yCoordinate) throws IOException {
// Take screenshot and hold it as an image
File tmpFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
BufferedImage tmpImage = ImageIO.read(tmpFile);
// Draw it on the graphics of the final output image
outputGraphics.drawImage(tmpImage, null, 0, yCoordinate);
}
Hope this is useful.
i am writing a game using Libgdx and i need to detect when the user touches a sprite.
I tried to do so with this following code:
this code set the rect's position
for(int i = 0;i<circlesArray.length;i++)
{
rect[i] = new Rectangle(circles.getPosition(i).x,circles.getPosition(i).y,height/8,height/8);
}
and this code set the click as rectangle and checks if it overlaps the sprite
if(Gdx.input.isTouched())
{
click = new Rectangle(Gdx.input.getX(),Gdx.input.getY(),Gdx.input.getX(),Gdx.input.getY());
if(Intersector.overlaps(click,rect[1]));
{
System.out.println("clicked");
x[1] = 0;
}
}
From some reason that i cant understand the program detects a collision even when it is not happened, when i tap anywhere on the screen it says that i pressed the sprite.
What should i do to fix it?
This is your issue:
click = new Rectangle(Gdx.input.getX(), Gdx.input.getY(), Gdx.input.getX(), Gdx.input.getY());
Should be:
click = new Rectangle(Gdx.input.getX(), Gdx.input.getY(), 1, 1);
The last two parameters of a Rectangle are width and height. Here we give the rectangle a width and a height of 1 pixel but you can set it to whatever you like. You were setting those parameters as the inputs x and y which are different every time giving you varying results.
Edit:
To translate the input coordinates to your game world's coordinates based on the camera you have to do this:
Vector3 clickPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(clickPos);
click = new Rectangle(clickPos.x, clickPos.y, 1, 1);
When you use camera.unproject(Vector) it translates your inputs coordinates to work based off of where your camera is positioned in the game world. So now we're using a vector clickPos.
The reason we use a Vector3 is because this is what is required by the unproject function. We supply this vector with the inputs x and y but give it a 0 for the third parameter z since this is a 2d world.
I'm working on trying to make an image move in processing, but the image is leaving a trail. The important part which is tripping me up is that I cannot declare the background in draw(), because I have other functions which place images. Here is the relevant code:
void setup()
{
size(752,500);
background = loadImage("prairie.jpg");
background(background);
noStroke();
animal = loadImage("squirrel.png");
bird = loadImage("bird.gif");
rock = loadImage("rock.png");
cloud = loadImage("cloud.png");
jeep = loadImage("jeep.png");
flower = loadImage("flower.png");
}
float jeepX = 752;
float jeepY = 250;
float size = 100;
void draw()
{
image(jeep,150,350,125,125);
image(jeep,jeepX,jeepY,size,size);
jeepX--;
jeepY = jeepY + .25;
size += .25;
image(jeep,jeepX + 1,jeepY - .25, size -.25, size - .25, 0,0,0,0);
if(jeepY > height)
{
jeepX = 752;
jeepY = 250;
size = 100;
}
}
This is for lab and the TA didn't know how, and I didn't have a chance to ask the professor yet.
If no one knows the answer and/or it has something to do with other functions (which place images), i'll post the relevant code.
For moving objects not to leave a trail, you must first clear the frame before redrawing the picture.(don't forget to reset the background if you don't have one)
As it is, it draws one jeep, then another on top of it.
If you don't want the trail, you got clear the background. If not completely, at least part of it, or redraw every image not supposed to move every frame.
Like this:
Sample Code
PImage bg, still, moving;
void setup() {
while ( bg == null) {// got wait as size depends on this...
println("loading bg image...");
bg = loadImage("http://dc489.4shared.com/img/f9EaWk5w/s3/13757197c08/Black_Background_Metal_Hole_-_.jpg");
}
size(bg.width, bg.height);
still = loadImage("http://www.renderosity.com/mod/bcs/photos/Thumb85619.jpg");
moving = loadImage("https://cdn1.iconfinder.com/data/icons/humano2/128x128/apps/alienblaster.png");
}
void draw() {
background(bg);
image(still, 100, 100);
image(moving, 200, frameCount%height);
}
You need to redraw your background in the 'draw' method. To do this, simply add the following line of code to your 'draw' method:
background(red,green,blue);
You can use the Colour Selector in Processing (found under Tools) to find the correct rgb code for the colour you want.
The reason for this is that the draw method is run 60 times a second, whereas the 'setup' method is only run once when the program is executed. As such, when you move the image, if the background colour is not in the 'draw' method, then it will not be redrawn when the image is moved, thus leaving a trail.
Occasionally I have to display a popup or dialog relative to an existing component (prime example is a date input control with a calendar button beside it).
It worked beautifully for years, but always had the bug that the calendar could partially appear outside the screen (it was hardcoded to appear just to the right of the field). Just nobody ever noticed because there was never a date control at the far right in a window. Well that changed recently with the addition of a new window.
Well then, I thought, lets just fix a windows position (after I positioned it where it should be) to be completely on screen. I wrote a simple utility method to do just that:
public static void correctWindowLocationForScreen(Window window) {
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle screenRect = gc.getBounds();
Rectangle windowRect = window.getBounds();
Rectangle newRect = new Rectangle(windowRect);
if (windowRect.x + windowRect.width > screenRect.x + screenRect.width)
newRect.x = screenRect.x + screenRect.width - windowRect.width;
if (windowRect.y + windowRect.height > screenRect.y + screenRect.height)
newRect.y = screenRect.y + screenRect.height - windowRect.height;
if (windowRect.x < screenRect.x)
newRect.x = screenRect.x;
if (windowRect.y < screenRect.y)
newRect.y = screenRect.y;
if (!newRect.equals(windowRect))
window.setLocation(newRect.x, newRect.y);
}
Problem solved. Or not. I position my window using the on-screen coordinates from the triggering component (the button that makes the calendar appear):
JComponent invoker = ... // passed in from the date field (a JButton)
Window owner = SwingUtilities.getWindowAncestor(invoker);
JDialog dialog = new JDialog(owner);
dialog.setLocation(invoker.getLocationOnScreen());
correctWindowLocationForScreen(dialog);
Havoc breaks out if the "invoker" component is located in a window that spans two screens. Apparently "window.getGraphicsConfiguration()" returns whatever graphic configuration the windows top left corner happens to be in. Thats not necessarily the screen where the date component within the window is located.
So how can I position my dialog properly in this case?
One can iterate over all devices, and find the monitor where the point is in. Then keep to that Rectangle.
See GraphicsEnvironment.getScreenDevices.
This will not use the current Window, but you already found out that a window may be shown in several monitors.
Useful might be Component.getLocationOnScreen.
Ok, here is what I ended up with (a wall of code to handle the odd edge case).
correctWindowLocationForScreen() will reposition a window if it is not completely within the visible screen area (simplest case, its completely on one screen. Hard case, it spans multiple screens). If the window leaves the complete screen area by just one pixel, it is repositioned using the first screen rectangle found. If the window doesn't fit the screen, its positioned at the top left and extends over the screen to bottom right (its implied by the order in which positionInsideRectangle() checks/alters coordinates).
Its quite complicated considering the requirement is pretty simple.
/**
* Check that window is completely on screen, if not correct position.
* Will not ensure the window fits completely onto the screen.
*/
public static void correctWindowLocationForScreen(final Window window) {
correctComponentLocation(window, getScreenRectangles());
}
/**
* Set the component location so that it is completely inside the available
* regions (if possible).
* Although the method will make some effort to place the component
* nicely, it may end up partially outside the regions (either because it
* doesn't fit at all, or the regions are placed badly).
*/
public static void correctComponentLocation(final Component component, final Rectangle ... availableRegions) {
// check the simple cases (component completely inside one region, no regions available)
final Rectangle bounds = component.getBounds();
if (availableRegions == null || availableRegions.length <= 0)
return;
final List<Rectangle> intersecting = new ArrayList<>(3);
for (final Rectangle region : availableRegions) {
if (region.contains(bounds)) {
return;
} else if (region.intersects(bounds)) {
// partial overlap
intersecting.add(region);
}
}
switch (intersecting.size()) {
case 0:
// position component in the first available region
positionInsideRectangle(component, availableRegions[0]);
return;
case 1:
// position component in the only intersecting region
positionInsideRectangle(component, intersecting.get(0));
return;
default:
// uuuh oooh...
break;
}
// build area containing all detected intersections
// and check if the bounds fall completely into the intersection area
final Area area = new Area();
for (final Rectangle region : intersecting) {
final Rectangle2D r2d = new Rectangle2D.Double(region.x, region.y, region.width, region.height);
area.add(new Area(r2d));
}
final Rectangle2D boundsRect = new Rectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height);
if (area.contains(boundsRect))
return;
// bah, just place it in the first intersecting region...
positionInsideRectangle(component, intersecting.get(0));
}
/**
* Position component so that its completely inside the rectangle.
* If the component is larger than the rectangle, component will
* exceed to rectangle bounds to the right and bottom, e.g.
* the component is placed at the rectangles x respectively y.
*/
public static void positionInsideRectangle(final Component component, final Rectangle region) {
final Rectangle bounds = component.getBounds();
int x = bounds.x;
int y = bounds.y;
if (x + bounds.width > region.x + region.width)
x = region.x + region.width - bounds.width;
if (y + bounds.height > region.y + region.height)
y = region.y + region.height - bounds.height;
if (region.x < region.x)
x = region.x;
if (y < region.y)
y = region.y;
if (x != bounds.x || y != bounds.y)
component.setLocation(x, y);
}
/**
* Gets the available display space as an arrays of rectangles
* (there is one rectangle for each screen, if the environment is
* headless the resulting array will be empty).
*/
public static Rectangle[] getScreenRectangles() {
try {
Rectangle[] result;
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice[] devices = ge.getScreenDevices();
result = new Rectangle[devices.length];
for (int i=0; i<devices.length; ++i) {
final GraphicsDevice gd = devices[i];
result[i] = gd.getDefaultConfiguration().getBounds();
}
return result;
} catch (final Exception e) {
return new Rectangle[0];
}
}
I have 2 images as following:
I would like to combine them automatically, hopefully it can be done in Java
How to detect the pixel location and correct edges to combine both images, due to both images have overlapping and without knowing which is the correct edges to combine? Any algorithm can be provided?
ImageJ is a very good java image processing library. It may have plugins out there to do this already so perhaps worth a check.
I would start by trying to find a location in both images that is the same. Do a line profile across both images vertically and see if the pixel values and y values are the same. If the images are exactly the same in only one location then it should be easy. If there are multiple locations where the pixels are the same or the pixels in the y direction are never the same then I think your problem may not have a uniquie solution.
Here is some code to get you started
public class CombineImages implements PlugIn
{
#Override
public void run(String arg0) {
// TODO Auto-generated method stub
}
public ImagePlus combineImages(ImageProcessor ip1, ImageProcessor ip2){
//Get a line of Y pixel values for the first image for each x position and add them to a list
ArrayList<Roi> roiList1 = new ArrayList<Roi>();
for(int i=0; i<ip1.getWidth()-1; i++){
Roi roi = new Roi(i,i+1,1, ip1.getHeight());
roiList1.add(roi);
}
//Get a line of Y pixel values for the second image for each x position and add them to a list
ArrayList<Roi> roiList2 = new ArrayList<Roi>();
for(int i=0; i<ip2.getWidth()-1; i++){
Roi roi = new Roi(i,i+1,1, ip2.getHeight());
roiList2.add(roi);
}
//Check if these are the same and return the X values for both images that these correspond to
//You can then crop and combine the pixel values
return null;
}
}