JDK-8322845 : Smaller screen capture not equal to a subimage of a capture of the entire screen
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 11,17,21,22
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2023-12-29
  • Updated: 2024-01-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
ADDITIONAL SYSTEM INFORMATION :
Tested on several computers and operating systems

A DESCRIPTION OF THE PROBLEM :
I encountered some weird behavior while experimenting with `java.awt.Robot`. If I use it to take two screenshots, one of the entire screen and one of just a subsection of the screen, the subsection of the screen has different pixels than a subimage of the original screenshot with the same coordinates as the subsection screenshot. Here is my code:

```
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 javax.imageio.ImageIO;

public class ScreenCapTest {
    public static void main(String[] args) throws AWTException, IOException {
        // Construct Robot
        Robot r = new Robot();
        
        // Get dimensions of screen
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        
        // Take screenshot
        BufferedImage screen = r.createScreenCapture(new Rectangle(0,0, (int)screenSize.getWidth(), (int)screenSize.getHeight()));
        
        // Take screenshot of small section of screen
        int x = 5;
        int y = 5;
        int w = 50;
        int h = 50;
        BufferedImage subscreen = r.createScreenCapture(new Rectangle(x,y,w,h));
        
        // Create a subimage of the same section of the screen from the original screenshot
        BufferedImage subimageOfScreen = screen.getSubimage(x,y,w,h);
        
        // Are they equal?
        System.out.println(imgEqual(subimageOfScreen, subscreen));
        
        // Output images for comparison
        ImageIO.write(subimageOfScreen, "png", new File("subimage.png"));
        ImageIO.write(subscreen, "png", new File("subscreen.png"));
    }
    
    public static boolean imgEqual(BufferedImage image1, BufferedImage image2) {
        int width;
        int height;
        boolean imagesEqual = true;

        if( image1.getWidth()  == ( width  = image2.getWidth() ) && 
            image1.getHeight() == ( height = image2.getHeight() ) ){

            for(int x = 0;imagesEqual == true && x < width; x++){
                for(int y = 0;imagesEqual == true && y < height; y++){
                    if( image1.getRGB(x, y) != image2.getRGB(x, y) ){
                        imagesEqual = false;
                    }
                }
            }
        } else {
            imagesEqual = false;
        }
        return imagesEqual;
    }
}
```

Most of the time, it reports false, meaning that the subimage of a full screenshot from (5,5) to (55,55) is different from the screenshot of the screen from (5,5) to (55,55). Weirdly, for some values of x, y, w, and h, it prints true.

I can see that the saved images are slightly different, but I don't understand why this behavior exists. What's going on?

This question is currently being discussed on StackOverflow at https://stackoverflow.com/questions/77727691/java-awt-robot-why-doesnt-a-smaller-screen-capture-equal-a-subimage-of-a-captu

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the code in the description with a static window

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Console reads "true"
ACTUAL -
Console reads "false"

---------- BEGIN SOURCE ----------
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 javax.imageio.ImageIO;

public class ScreenCapTest {
    public static void main(String[] args) throws AWTException, IOException {
        // Construct Robot
        Robot r = new Robot();
        
        // Get dimensions of screen
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        
        // Take screenshot
        BufferedImage screen = r.createScreenCapture(new Rectangle(0,0, (int)screenSize.getWidth(), (int)screenSize.getHeight()));
        
        // Take screenshot of small section of screen
        int x = 5;
        int y = 5;
        int w = 50;
        int h = 50;
        BufferedImage subscreen = r.createScreenCapture(new Rectangle(x,y,w,h));
        
        // Create a subimage of the same section of the screen from the original screenshot
        BufferedImage subimageOfScreen = screen.getSubimage(x,y,w,h);
        
        // Are they equal?
        System.out.println(imgEqual(subimageOfScreen, subscreen));
        
        // Output images for comparison
        ImageIO.write(subimageOfScreen, "png", new File("subimage.png"));
        ImageIO.write(subscreen, "png", new File("subscreen.png"));
    }
    
    public static boolean imgEqual(BufferedImage image1, BufferedImage image2) {
        int width;
        int height;
        boolean imagesEqual = true;

        if( image1.getWidth()  == ( width  = image2.getWidth() ) && 
            image1.getHeight() == ( height = image2.getHeight() ) ){

            for(int x = 0;imagesEqual == true && x < width; x++){
                for(int y = 0;imagesEqual == true && y < height; y++){
                    if( image1.getRGB(x, y) != image2.getRGB(x, y) ){
                        imagesEqual = false;
                    }
                }
            }
        } else {
            imagesEqual = false;
        }
        return imagesEqual;
    }
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Easy to reproduce. Tested on Windows, with several releases of JDKs: The test program prints - true: When screen scale is 100% (8, 11, 17, 19, 21) - false: for other screen scales (11, 17, 19, 21) Seems hiDPi issue, with all JDK releases except 8
08-01-2024

Checked with attached test case, issue reproducible in JDK 11, 17, 21 and 22ea, Issue not reproducible in JDK8 Test Result ========= JDK 8 : true JDK 8u391: true JDK 11: false JDK 11.0.21: false JDK17: false JDK 21: false JDK22ea29:false
02-01-2024