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
374 afterEvent();
375 }
376
377 private void checkKeycodeArgument(int keycode) {
378 // rather than build a big table or switch statement here, we'll
379 // just check that the key isn't VK_UNDEFINED and assume that the
380 // peer implementations will throw an exception for other bogus
381 // values e.g. -1, 999999
382 if (keycode == KeyEvent.VK_UNDEFINED) {
383 throw new IllegalArgumentException("Invalid key code");
384 }
385 }
386
387 /**
388 * Returns the color of a pixel at the given screen coordinates.
389 * @param x X position of pixel
390 * @param y Y position of pixel
391 * @return Color of the pixel
392 */
393 public synchronized Color getPixelColor(int x, int y) {
394 Color color = new Color(peer.getRGBPixel(x, y));
395 return color;
396 }
397
398 /**
399 * Creates an image containing pixels read from the screen. This image does
400 * not include the mouse cursor.
401 * @param screenRect Rect to capture in screen coordinates
402 * @return The captured image
403 * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero
404 * @throws SecurityException if {@code readDisplayPixels} permission is not granted
405 * @see SecurityManager#checkPermission
406 * @see AWTPermission
407 */
408 public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
409 checkScreenCaptureAllowed();
410
411 checkValidRect(screenRect);
412
413 BufferedImage image;
414 DataBufferInt buffer;
415 WritableRaster raster;
416
417 if (screenCapCM == null) {
418 /*
419 * Fix for 4285201
420 * Create a DirectColorModel equivalent to the default RGB ColorModel,
421 * except with no Alpha component.
422 */
423
424 screenCapCM = new DirectColorModel(24,
425 /* red mask */ 0x00FF0000,
426 /* green mask */ 0x0000FF00,
427 /* blue mask */ 0x000000FF);
428 }
429
430 // need to sync the toolkit prior to grabbing the pixels since in some
431 // cases rendering to the screen may be delayed
432 Toolkit.getDefaultToolkit().sync();
433
434 int pixels[];
435 int[] bandmasks = new int[3];
436
437 pixels = peer.getRGBPixels(screenRect);
438 buffer = new DataBufferInt(pixels, pixels.length);
439
440 bandmasks[0] = screenCapCM.getRedMask();
441 bandmasks[1] = screenCapCM.getGreenMask();
442 bandmasks[2] = screenCapCM.getBlueMask();
443
444 raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null);
445 SunWritableRaster.makeTrackable(buffer);
446
447 image = new BufferedImage(screenCapCM, raster, false, null);
448
449 return image;
450 }
451
452 private static void checkValidRect(Rectangle rect) {
453 if (rect.width <= 0 || rect.height <= 0) {
454 throw new IllegalArgumentException("Rectangle width and height must be > 0");
455 }
456 }
457
458 private static void checkScreenCaptureAllowed() {
459 SecurityManager security = System.getSecurityManager();
460 if (security != null) {
461 security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
462 }
463 }
464
465 /*
466 * Called after an event is generated
467 */
468 private void afterEvent() {
469 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
377 afterEvent();
378 }
379
380 private void checkKeycodeArgument(int keycode) {
381 // rather than build a big table or switch statement here, we'll
382 // just check that the key isn't VK_UNDEFINED and assume that the
383 // peer implementations will throw an exception for other bogus
384 // values e.g. -1, 999999
385 if (keycode == KeyEvent.VK_UNDEFINED) {
386 throw new IllegalArgumentException("Invalid key code");
387 }
388 }
389
390 /**
391 * Returns the color of a pixel at the given screen coordinates.
392 * @param x X position of pixel
393 * @param y Y position of pixel
394 * @return Color of the pixel
395 */
396 public synchronized Color getPixelColor(int x, int y) {
397 AffineTransform tx = GraphicsEnvironment.
398 getLocalGraphicsEnvironment().getDefaultScreenDevice().
399 getDefaultConfiguration().getDefaultTransform();
400 x = (int) (x * tx.getScaleX());
401 y = (int) (y * tx.getScaleY());
402 Color color = new Color(peer.getRGBPixel(x, y));
403 return color;
404 }
405
406 /**
407 * Creates an image containing pixels read from the screen. This image does
408 * not include the mouse cursor.
409 * @param screenRect Rect to capture in screen coordinates
410 * @return The captured image
411 * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero
412 * @throws SecurityException if {@code readDisplayPixels} permission is not granted
413 * @see SecurityManager#checkPermission
414 * @see AWTPermission
415 */
416 public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
417 return createCompatibleImage(screenRect, false)[0];
418 }
419
420 /**
421 * Creates an image containing pixels read from the screen.
422 * This image does not include the mouse cursor.
423 * This method can be used in case there is a scaling transform
424 * from user space to screen (device) space.
425 * Typically this means that the display is a high resolution screen,
426 * although strictly it means any case in which there is such a transform.
427 * Returns a {@link java.awt.image.MultiResolutionImage}.
428 * <p>
429 * For a non-scaled display, the {@code MultiResolutionImage}
430 * will have one image variant:
431 * <ul>
432 * <li> Base Image with user specified size.
433 * </ul>
434 * <p>
435 * For a high resolution display where there is a scaling transform,
436 * the {@code MultiResolutionImage} will have two image variants:
437 * <ul>
438 * <li> Base Image with user specified size. This is scaled from the screen.
439 * <li> Native device resolution image with device size pixels.
440 * </ul>
441 * <p>
442 * Example:
443 * <pre>
444 * Image nativeResImage;
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 * nativeResImage = 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 * @since 9
460 */
461 public synchronized MultiResolutionImage
462 createMultiResolutionScreenCapture(Rectangle screenRect) {
463
464 return new BaseMultiResolutionImage(
465 createCompatibleImage(screenRect, true));
466 }
467
468 private synchronized BufferedImage[]
469 createCompatibleImage(Rectangle screenRect, boolean isHiDPI) {
470
471 checkScreenCaptureAllowed();
472
473 checkValidRect(screenRect);
474
475 BufferedImage lowResolutionImage;
476 BufferedImage highResolutionImage;
477 DataBufferInt buffer;
478 WritableRaster raster;
479 BufferedImage[] imageArray;
480
481 if (screenCapCM == null) {
482 /*
483 * Fix for 4285201
484 * Create a DirectColorModel equivalent to the default RGB ColorModel,
485 * except with no Alpha component.
486 */
487
488 screenCapCM = new DirectColorModel(24,
489 /* red mask */ 0x00FF0000,
490 /* green mask */ 0x0000FF00,
491 /* blue mask */ 0x000000FF);
492 }
493
494 int[] bandmasks = new int[3];
495 bandmasks[0] = screenCapCM.getRedMask();
496 bandmasks[1] = screenCapCM.getGreenMask();
497 bandmasks[2] = screenCapCM.getBlueMask();
498
499 // need to sync the toolkit prior to grabbing the pixels since in some
500 // cases rendering to the screen may be delayed
501 Toolkit.getDefaultToolkit().sync();
502 AffineTransform tx = GraphicsEnvironment.
503 getLocalGraphicsEnvironment().getDefaultScreenDevice().
504 getDefaultConfiguration().getDefaultTransform();
505 double uiScaleX = tx.getScaleX();
506 double uiScaleY = tx.getScaleY();
507 int pixels[];
508
509 if (uiScaleX == 1 && uiScaleY == 1) {
510
511 pixels = peer.getRGBPixels(screenRect);
512 buffer = new DataBufferInt(pixels, pixels.length);
513
514 bandmasks[0] = screenCapCM.getRedMask();
515 bandmasks[1] = screenCapCM.getGreenMask();
516 bandmasks[2] = screenCapCM.getBlueMask();
517
518 raster = Raster.createPackedRaster(buffer, screenRect.width,
519 screenRect.height, screenRect.width, bandmasks, null);
520 SunWritableRaster.makeTrackable(buffer);
521
522 highResolutionImage = new BufferedImage(screenCapCM, raster,
523 false, null);
524 imageArray = new BufferedImage[1];
525 imageArray[0] = highResolutionImage;
526
527 } else {
528
529 int sX = (int) Math.floor(screenRect.x * uiScaleX);
530 int sY = (int) Math.floor(screenRect.y * uiScaleY);
531 int sWidth = (int) Math.ceil(screenRect.width * uiScaleX);
532 int sHeight = (int) Math.ceil(screenRect.height * uiScaleY);
533 int temppixels[];
534 Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight);
535 temppixels = peer.getRGBPixels(scaledRect);
536
537 // HighResolutionImage
538 pixels = temppixels;
539 buffer = new DataBufferInt(pixels, pixels.length);
540 raster = Raster.createPackedRaster(buffer, scaledRect.width,
541 scaledRect.height, scaledRect.width, bandmasks, null);
542 SunWritableRaster.makeTrackable(buffer);
543
544 highResolutionImage = new BufferedImage(screenCapCM, raster,
545 false, null);
546
547
548 // LowResolutionImage
549 lowResolutionImage = new BufferedImage(screenRect.width,
550 screenRect.height, highResolutionImage.getType());
551 Graphics2D g = lowResolutionImage.createGraphics();
552 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
553 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
554 g.setRenderingHint(RenderingHints.KEY_RENDERING,
555 RenderingHints.VALUE_RENDER_QUALITY);
556 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
557 RenderingHints.VALUE_ANTIALIAS_ON);
558 g.drawImage(highResolutionImage, 0, 0,
559 screenRect.width, screenRect.height,
560 0, 0, scaledRect.width, scaledRect.height, null);
561 g.dispose();
562
563 if(!isHiDPI) {
564 imageArray = new BufferedImage[1];
565 imageArray[0] = lowResolutionImage;
566 } else {
567 imageArray = new BufferedImage[2];
568 imageArray[0] = lowResolutionImage;
569 imageArray[1] = highResolutionImage;
570 }
571
572 }
573
574 return imageArray;
575 }
576
577 private static void checkValidRect(Rectangle rect) {
578 if (rect.width <= 0 || rect.height <= 0) {
579 throw new IllegalArgumentException("Rectangle width and height must be > 0");
580 }
581 }
582
583 private static void checkScreenCaptureAllowed() {
584 SecurityManager security = System.getSecurityManager();
585 if (security != null) {
586 security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
587 }
588 }
589
590 /*
591 * Called after an event is generated
592 */
593 private void afterEvent() {
594 autoWaitForIdle();
|