1 /*
2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt;
27
28 import java.awt.event.InputEvent;
29 import java.awt.event.KeyEvent;
30 import java.awt.image.BufferedImage;
31 import java.awt.image.DataBufferInt;
32 import java.awt.image.DirectColorModel;
33 import java.awt.image.Raster;
34 import java.awt.image.WritableRaster;
35 import java.awt.peer.RobotPeer;
36
37 import sun.awt.AWTPermissions;
38 import sun.awt.ComponentFactory;
39 import sun.awt.SunToolkit;
40 import sun.awt.image.SunWritableRaster;
41
42 /**
43 * This class is used to generate native system input events
44 * for the purposes of test automation, self-running demos, and
45 * other applications where control of the mouse and keyboard
46 * is needed. The primary purpose of Robot is to facilitate
47 * automated testing of Java platform implementations.
48 * <p>
49 * Using the class to generate input events differs from posting
373 afterEvent();
374 }
375
376 private void checkKeycodeArgument(int keycode) {
377 // rather than build a big table or switch statement here, we'll
378 // just check that the key isn't VK_UNDEFINED and assume that the
379 // peer implementations will throw an exception for other bogus
380 // values e.g. -1, 999999
381 if (keycode == KeyEvent.VK_UNDEFINED) {
382 throw new IllegalArgumentException("Invalid key code");
383 }
384 }
385
386 /**
387 * Returns the color of a pixel at the given screen coordinates.
388 * @param x X position of pixel
389 * @param y Y position of pixel
390 * @return Color of the pixel
391 */
392 public synchronized Color getPixelColor(int x, int y) {
393 Color color = new Color(peer.getRGBPixel(x, y));
394 return color;
395 }
396
397 /**
398 * Creates an image containing pixels read from the screen. This image does
399 * not include the mouse cursor.
400 * @param screenRect Rect to capture in screen coordinates
401 * @return The captured image
402 * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero
403 * @throws SecurityException if {@code readDisplayPixels} permission is not granted
404 * @see SecurityManager#checkPermission
405 * @see AWTPermission
406 */
407 public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
408 checkScreenCaptureAllowed();
409
410 checkValidRect(screenRect);
411
412 BufferedImage image;
413 DataBufferInt buffer;
414 WritableRaster raster;
415
416 if (screenCapCM == null) {
417 /*
418 * Fix for 4285201
419 * Create a DirectColorModel equivalent to the default RGB ColorModel,
420 * except with no Alpha component.
421 */
422
423 screenCapCM = new DirectColorModel(24,
424 /* red mask */ 0x00FF0000,
425 /* green mask */ 0x0000FF00,
426 /* blue mask */ 0x000000FF);
427 }
428
429 // need to sync the toolkit prior to grabbing the pixels since in some
430 // cases rendering to the screen may be delayed
431 Toolkit.getDefaultToolkit().sync();
432
433 int pixels[];
434 int[] bandmasks = new int[3];
435
436 pixels = peer.getRGBPixels(screenRect);
437 buffer = new DataBufferInt(pixels, pixels.length);
438
439 bandmasks[0] = screenCapCM.getRedMask();
440 bandmasks[1] = screenCapCM.getGreenMask();
441 bandmasks[2] = screenCapCM.getBlueMask();
442
443 raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null);
444 SunWritableRaster.makeTrackable(buffer);
445
446 image = new BufferedImage(screenCapCM, raster, false, null);
447
448 return image;
449 }
450
451 private static void checkValidRect(Rectangle rect) {
452 if (rect.width <= 0 || rect.height <= 0) {
453 throw new IllegalArgumentException("Rectangle width and height must be > 0");
454 }
455 }
456
457 private static void checkScreenCaptureAllowed() {
458 SecurityManager security = System.getSecurityManager();
459 if (security != null) {
460 security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
461 }
462 }
463
464 /*
465 * Called after an event is generated
466 */
467 private void afterEvent() {
468 autoWaitForIdle();
|
1 /*
2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt;
27
28 import java.awt.event.InputEvent;
29 import java.awt.event.KeyEvent;
30 import java.awt.geom.AffineTransform;
31 import java.awt.image.BaseMultiResolutionImage;
32 import java.awt.image.MultiResolutionImage;
33 import java.awt.image.BufferedImage;
34 import java.awt.image.DataBufferInt;
35 import java.awt.image.DirectColorModel;
36 import java.awt.image.Raster;
37 import java.awt.image.WritableRaster;
38 import java.awt.peer.RobotPeer;
39
40 import sun.awt.AWTPermissions;
41 import sun.awt.ComponentFactory;
42 import sun.awt.SunToolkit;
43 import sun.awt.image.SunWritableRaster;
44
45 /**
46 * This class is used to generate native system input events
47 * for the purposes of test automation, self-running demos, and
48 * other applications where control of the mouse and keyboard
49 * is needed. The primary purpose of Robot is to facilitate
50 * automated testing of Java platform implementations.
51 * <p>
52 * Using the class to generate input events differs from posting
376 afterEvent();
377 }
378
379 private void checkKeycodeArgument(int keycode) {
380 // rather than build a big table or switch statement here, we'll
381 // just check that the key isn't VK_UNDEFINED and assume that the
382 // peer implementations will throw an exception for other bogus
383 // values e.g. -1, 999999
384 if (keycode == KeyEvent.VK_UNDEFINED) {
385 throw new IllegalArgumentException("Invalid key code");
386 }
387 }
388
389 /**
390 * Returns the color of a pixel at the given screen coordinates.
391 * @param x X position of pixel
392 * @param y Y position of pixel
393 * @return Color of the pixel
394 */
395 public synchronized Color getPixelColor(int x, int y) {
396 AffineTransform tx = GraphicsEnvironment.
397 getLocalGraphicsEnvironment().getDefaultScreenDevice().
398 getDefaultConfiguration().getDefaultTransform();
399 x = (int) (x * tx.getScaleX());
400 y = (int) (y * tx.getScaleY());
401 Color color = new Color(peer.getRGBPixel(x, y));
402 return color;
403 }
404
405 /**
406 * Creates an image containing pixels read from the screen. This image does
407 * not include the mouse cursor.
408 * @param screenRect Rect to capture in screen coordinates
409 * @return The captured image
410 * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero
411 * @throws SecurityException if {@code readDisplayPixels} permission is not granted
412 * @see SecurityManager#checkPermission
413 * @see AWTPermission
414 */
415 public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
416 return createCompatibleImage(screenRect, false)[0];
417 }
418
419 /**
420 * Creates an image containing pixels read from the screen.
421 * This image does not include the mouse cursor.
422 * This method can be used in case there is a scaling transform
423 * from user space to screen (device) space.
424 * Typically this means that the display is a high resolution screen,
425 * although strictly it means any case in which there is such a transform.
426 * Returns a {@link java.awt.image.MultiResolutionImage}.
427 * <p>
428 * For a non-scaled display, the {@code MultiResolutionImage}
429 * will have one image variant:
430 * <ul>
431 * <li> Base Image with user specified size.
432 * </ul>
433 * <p>
434 * For a high resolution display where there is a scaling transform,
435 * the {@code MultiResolutionImage} will have two image variants:
436 * <ul>
437 * <li> Base Image with user specified size. This is scaled from the screen.
438 * <li> Native device resolution image with device size pixels.
439 * </ul>
440 * <p>
441 * Example:
442 * <pre>
443 * Image nativeResImage;
444 * Image baseResImage;
445 * MultiResolutionImage mrImage = robot.createMultiResolutionScreenCapture(frame.getBounds());
446 * List<Image> resolutionVariants = mrImage.getResolutionVariants();
447 * if (resolutionVariants.size() > 1) {
448 * nativeResImage = resolutionVariants.get(1);
449 * } else {
450 * baseResImage = resolutionVariants.get(0);
451 * } </pre>
452 * @param screenRect Rect to capture in screen coordinates
453 * @return The captured image
454 * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero
455 * @throws SecurityException if {@code readDisplayPixels} permission is not granted
456 * @see SecurityManager#checkPermission
457 * @see AWTPermission
458 */
459 public synchronized MultiResolutionImage
460 createMultiResolutionScreenCapture(Rectangle screenRect) {
461
462 return new BaseMultiResolutionImage(
463 createCompatibleImage(screenRect, true));
464 }
465
466 private synchronized BufferedImage[]
467 createCompatibleImage(Rectangle screenRect, boolean isHiDPI) {
468
469 checkScreenCaptureAllowed();
470
471 checkValidRect(screenRect);
472
473 BufferedImage lowResolutionImage;
474 BufferedImage highResolutionImage;
475 DataBufferInt buffer;
476 WritableRaster raster;
477 BufferedImage[] imageArray;
478
479 if (screenCapCM == null) {
480 /*
481 * Fix for 4285201
482 * Create a DirectColorModel equivalent to the default RGB ColorModel,
483 * except with no Alpha component.
484 */
485
486 screenCapCM = new DirectColorModel(24,
487 /* red mask */ 0x00FF0000,
488 /* green mask */ 0x0000FF00,
489 /* blue mask */ 0x000000FF);
490 }
491
492 int[] bandmasks = new int[3];
493 bandmasks[0] = screenCapCM.getRedMask();
494 bandmasks[1] = screenCapCM.getGreenMask();
495 bandmasks[2] = screenCapCM.getBlueMask();
496
497 // need to sync the toolkit prior to grabbing the pixels since in some
498 // cases rendering to the screen may be delayed
499 Toolkit.getDefaultToolkit().sync();
500 AffineTransform tx = GraphicsEnvironment.
501 getLocalGraphicsEnvironment().getDefaultScreenDevice().
502 getDefaultConfiguration().getDefaultTransform();
503 double uiScaleX = tx.getScaleX();
504 double uiScaleY = tx.getScaleY();
505 int pixels[];
506
507 if (uiScaleX == 1 && uiScaleY == 1) {
508
509 pixels = peer.getRGBPixels(screenRect);
510 buffer = new DataBufferInt(pixels, pixels.length);
511
512 bandmasks[0] = screenCapCM.getRedMask();
513 bandmasks[1] = screenCapCM.getGreenMask();
514 bandmasks[2] = screenCapCM.getBlueMask();
515
516 raster = Raster.createPackedRaster(buffer, screenRect.width,
517 screenRect.height, screenRect.width, bandmasks, null);
518 SunWritableRaster.makeTrackable(buffer);
519
520 highResolutionImage = new BufferedImage(screenCapCM, raster,
521 false, null);
522 imageArray = new BufferedImage[1];
523 imageArray[0] = highResolutionImage;
524
525 } else {
526
527 int sX = (int) Math.floor(screenRect.x * uiScaleX);
528 int sY = (int) Math.floor(screenRect.y * uiScaleY);
529 int sWidth = (int) Math.ceil(screenRect.width * uiScaleX);
530 int sHeight = (int) Math.ceil(screenRect.height * uiScaleY);
531 int temppixels[];
532 Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight);
533 temppixels = peer.getRGBPixels(scaledRect);
534
535 // HighResolutionImage
536 pixels = temppixels;
537 buffer = new DataBufferInt(pixels, pixels.length);
538 raster = Raster.createPackedRaster(buffer, scaledRect.width,
539 scaledRect.height, scaledRect.width, bandmasks, null);
540 SunWritableRaster.makeTrackable(buffer);
541
542 highResolutionImage = new BufferedImage(screenCapCM, raster,
543 false, null);
544
545
546 // LowResolutionImage
547 lowResolutionImage = new BufferedImage(screenRect.width,
548 screenRect.height, highResolutionImage.getType());
549 Graphics2D g = lowResolutionImage.createGraphics();
550 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
551 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
552 g.setRenderingHint(RenderingHints.KEY_RENDERING,
553 RenderingHints.VALUE_RENDER_QUALITY);
554 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
555 RenderingHints.VALUE_ANTIALIAS_ON);
556 g.drawImage(highResolutionImage, 0, 0,
557 screenRect.width, screenRect.height,
558 0, 0, scaledRect.width, scaledRect.height, null);
559 g.dispose();
560
561 if(!isHiDPI) {
562 imageArray = new BufferedImage[1];
563 imageArray[0] = lowResolutionImage;
564 } else {
565 imageArray = new BufferedImage[2];
566 imageArray[0] = lowResolutionImage;
567 imageArray[1] = highResolutionImage;
568 }
569
570 }
571
572 return imageArray;
573 }
574
575 private static void checkValidRect(Rectangle rect) {
576 if (rect.width <= 0 || rect.height <= 0) {
577 throw new IllegalArgumentException("Rectangle width and height must be > 0");
578 }
579 }
580
581 private static void checkScreenCaptureAllowed() {
582 SecurityManager security = System.getSecurityManager();
583 if (security != null) {
584 security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
585 }
586 }
587
588 /*
589 * Called after an event is generated
590 */
591 private void afterEvent() {
592 autoWaitForIdle();
|