天天看點

Java Robot 擷取高分辨率桌面截圖

通過 Robot.createScreenCapture 方法擷取螢幕截圖(無滑鼠)時,發現2160x1440的螢幕,隻能生成分辨率為 1440 x 960 的圖檔。系統是 windows11,縮放為 150%,生成的 1440 x 960 分辨率為 2160/1.5 x 1440/1.5 的值;如果 WIDTH 和 HEIGHT 填寫1440 x 960,生成的截圖是正常的,知識分辨率小一點,如果填寫 2160x1440 ,則生成的截圖裡,桌面的截圖在最終生成的整個圖像的左上角,其餘部分全部為黑色。

BufferedImage screenCapture = robot.createScreenCapture(new Rectangle(0, 0, WIDTH, HEIGHT)); // 截屏      

通過分析 Robot.createScreenCapture 方法發現,其确實适配了縮放的情況,也生成了縮放前後的兩個尺寸的圖像,但是卻傳回了低分辨率的那一個。

private synchronized BufferedImage[]
            createCompatibleImage(Rectangle screenRect, boolean isHiDPI) {

        checkScreenCaptureAllowed();

        checkValidRect(screenRect);

        BufferedImage lowResolutionImage;
        BufferedImage highResolutionImage;
        DataBufferInt buffer;
        WritableRaster raster;
        BufferedImage[] imageArray;

        if (screenCapCM == null) {
            /*
             * Fix for 4285201
             * Create a DirectColorModel equivalent to the default RGB ColorModel,
             * except with no Alpha component.
             */

            screenCapCM = new DirectColorModel(24,
                    /* red mask */ 0x00FF0000,
                    /* green mask */ 0x0000FF00,
                    /* blue mask */ 0x000000FF);
        }

        int[] bandmasks = new int[3];
        bandmasks[0] = screenCapCM.getRedMask();
        bandmasks[1] = screenCapCM.getGreenMask();
        bandmasks[2] = screenCapCM.getBlueMask();

        // need to sync the toolkit prior to grabbing the pixels since in some
        // cases rendering to the screen may be delayed
        Toolkit.getDefaultToolkit().sync();

        GraphicsConfiguration gc = GraphicsEnvironment
                .getLocalGraphicsEnvironment()
                .getDefaultScreenDevice().
                getDefaultConfiguration();
        gc = SunGraphicsEnvironment.getGraphicsConfigurationAtPoint(
                gc, screenRect.getCenterX(), screenRect.getCenterY());

        AffineTransform tx = gc.getDefaultTransform();
        double uiScaleX = tx.getScaleX();
        double uiScaleY = tx.getScaleY();
        int[] pixels;

        if (uiScaleX == 1 && uiScaleY == 1) {

            pixels = peer.getRGBPixels(screenRect);
            buffer = new DataBufferInt(pixels, pixels.length);

            bandmasks[0] = screenCapCM.getRedMask();
            bandmasks[1] = screenCapCM.getGreenMask();
            bandmasks[2] = screenCapCM.getBlueMask();

            raster = Raster.createPackedRaster(buffer, screenRect.width,
                    screenRect.height, screenRect.width, bandmasks, null);
            SunWritableRaster.makeTrackable(buffer);

            highResolutionImage = new BufferedImage(screenCapCM, raster,
                    false, null);
            imageArray = new BufferedImage[1];
            imageArray[0] = highResolutionImage;

        } else {
            Rectangle scaledRect;
            if (peer.useAbsoluteCoordinates()) {
                scaledRect = toDeviceSpaceAbs(gc, screenRect.x,
                        screenRect.y, screenRect.width, screenRect.height);
            } else {
                scaledRect = toDeviceSpace(gc, screenRect.x,
                        screenRect.y, screenRect.width, screenRect.height);
            }
            // HighResolutionImage
            pixels = peer.getRGBPixels(scaledRect);
            buffer = new DataBufferInt(pixels, pixels.length);
            raster = Raster.createPackedRaster(buffer, scaledRect.width,
                    scaledRect.height, scaledRect.width, bandmasks, null);
            SunWritableRaster.makeTrackable(buffer);

            highResolutionImage = new BufferedImage(screenCapCM, raster,
                    false, null);


            // LowResolutionImage
            lowResolutionImage = new BufferedImage(screenRect.width,
                    screenRect.height, highResolutionImage.getType());
            Graphics2D g = lowResolutionImage.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.setRenderingHint(RenderingHints.KEY_RENDERING,
                    RenderingHints.VALUE_RENDER_QUALITY);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g.drawImage(highResolutionImage, 0, 0,
                    screenRect.width, screenRect.height,
                    0, 0, scaledRect.width, scaledRect.height, null);
            g.dispose();

            if(!isHiDPI) {
                imageArray = new BufferedImage[1];
                imageArray[0] = lowResolutionImage;//重點看這裡
            } else {
                imageArray = new BufferedImage[2];
                imageArray[0] = lowResolutionImage;//重點看這裡
                imageArray[1] = highResolutionImage;//重點看這裡
            }

        }

        return imageArray;
    }      

imageArray[0] 是低分辨率的那個圖像。

public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
        return createCompatibleImage(screenRect, false)[0];
    }      
public static BufferedImage getHighResolutionImage() throws AWTException {
        Robot robot = getRobot();
        MultiResolutionImage multiResolutionImage = robot.createMultiResolutionScreenCapture(new Rectangle(0, 0, WIDTH, HEIGHT));
        Image image = multiResolutionImage.getResolutionVariant(SCALE_WIDTH, SCALE_HEIGHT);
        BufferedImage screenCapture = (BufferedImage) image;
        return screenCapture;
    }