Skip to main content
Version: Latest

DPI Scaling and Resolution Guide

The Problem

Java 21 introduced DPI awareness, which causes screen captures to return logical resolution instead of physical resolution when Windows display scaling is enabled.

Example

  • Physical Monitor: 1920×1080 pixels
  • Windows Scaling: 125%
  • Java 21 Captures: 1536×864 pixels (logical resolution)
  • Pattern Images: 1920×1080 pixels (physical resolution)
  • Result: Pattern matching fails! ❌

Understanding Resolution Types

Physical Resolution

The actual number of pixels on your monitor.

  • Example: 1920×1080, 2560×1440, 3840×2160
  • What pattern images are usually created at
  • What Java 8 captures

Logical Resolution

The scaled resolution that applications see.

  • Formula: Physical Resolution ÷ Scaling Factor
  • Example: 1920×1080 ÷ 1.25 = 1536×864
  • What Java 21+ captures by default

Common Scaling Scenarios

Windows ScalingPhysicalLogicalScale Factor
100%1920×10801920×10801.0
125%1920×10801536×8641.25
150%1920×10801280×7201.5
175%1920×10801097×6171.75
200%1920×1080960×5402.0

Solution: Brobot's Approach

Brobot provides automatic DPI detection and compensation through two key settings:

# Enable DPI awareness for auto-detection to work
brobot.dpi.disable=false

# Enable automatic DPI detection and pattern scaling
brobot.dpi.resize-factor=auto

# Use SikuliX as the capture provider
brobot.capture.provider=SIKULIX

This configuration:

  1. Keeps DPI awareness enabled - Allows detection of Windows scaling
  2. Auto-detects scaling - Automatically calculates pattern resize factor
  3. Adjusts patterns - Scales patterns to match logical resolution

How It Works

When DPI awareness is enabled (brobot.dpi.disable=false):

  • Java captures at logical resolution (e.g., 1536×864 with 125% scaling)
  • Auto-detector detects the scaling (e.g., 125% = 1.25x)
  • Patterns are automatically resized (scaled by 0.8x to match)
  • Pattern matching works correctly! ✅

Brobot provides multiple solutions to handle DPI scaling:

1. Robot Provider with Scaling (Default)

The Robot provider automatically detects DPI scaling and compensates by scaling captured images to physical resolution.

# Automatically scales to physical resolution
brobot.capture.provider=ROBOT
brobot.capture.robot.scale-to-physical=true
brobot.capture.robot.expected-physical-width=1920
brobot.capture.robot.expected-physical-height=1080

How it works:

  1. Captures at logical resolution (e.g., 1536×864)
  2. Detects scaling factor (e.g., 1.25)
  3. Scales image to physical resolution (1920×1080)
  4. Pattern matching works! ✅

2. FFmpeg Provider (JavaCV)

FFmpeg captures at true physical resolution without any scaling needed.

# True physical resolution capture
brobot.capture.provider=FFMPEG

Advantages:

  • No scaling artifacts
  • Always physical resolution
  • Uses bundled JavaCV (no external installation)

3. Disable DPI Awareness (JVM Flag)

You can disable Java's DPI awareness entirely:

java -Dsun.java2d.dpiaware=false -jar myapp.jar

Note: This must be set as a JVM argument, not in code.

Configuration by Use Case

High-DPI Windows Laptop

# Robot with automatic scaling
brobot.capture.provider=ROBOT
brobot.capture.robot.scale-to-physical=true
brobot.capture.robot.expected-physical-width=1920
brobot.capture.robot.expected-physical-height=1080

4K Monitor with Scaling

# Adjust expected resolution
brobot.capture.provider=ROBOT
brobot.capture.robot.scale-to-physical=true
brobot.capture.robot.expected-physical-width=3840
brobot.capture.robot.expected-physical-height=2160

Multi-Monitor Setup

# FFmpeg handles multi-monitor well
brobot.capture.provider=FFMPEG

CI/CD Environment

# Auto-detect and adapt
brobot.capture.provider=AUTO
brobot.capture.prefer-physical=true

Detecting Your Setup

Check Current Resolution

@Autowired
private CaptureConfiguration config;

// Print detailed configuration
config.printConfigurationReport();

Manual Detection

// Get screen dimensions
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
System.out.println("Logical: " + screenSize.width + "×" + screenSize.height);

// Check for scaling
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();

double scale = gc.getDefaultTransform().getScaleX();
System.out.println("Scale Factor: " + scale);

// Calculate physical resolution
int physicalWidth = (int)(screenSize.width * scale);
int physicalHeight = (int)(screenSize.height * scale);
System.out.println("Physical: " + physicalWidth + "×" + physicalHeight);

Troubleshooting

Symptom: Pattern matching fails

Diagnosis:

BufferedImage capture = captureService.captureScreen();
System.out.println("Captured: " + capture.getWidth() + "×" + capture.getHeight());
// If this shows 1536×864 instead of 1920×1080, you have scaling issues

Solution:

brobot.capture.robot.scale-to-physical=true

Symptom: Captures are blurry after scaling

Solution: Use FFmpeg for true physical capture:

brobot.capture.provider=FFMPEG

Symptom: Wrong expected resolution

Solution: Update to match your monitor:

brobot.capture.robot.expected-physical-width=2560
brobot.capture.robot.expected-physical-height=1440

Best Practices

1. Always Test Your Resolution

@PostConstruct
public void verifyResolution() {
BufferedImage test = captureService.captureScreen();
System.out.println("Capture resolution: " +
test.getWidth() + "×" + test.getHeight());

if (test.getWidth() != 1920) {
System.out.println("Warning: Not capturing at expected resolution!");
}
}

2. Create Patterns at Consistent Resolution

  • Always create pattern images at physical resolution
  • Or always create them at logical resolution
  • Be consistent across your pattern library

3. Document Your Setup

# This application expects patterns at 1920×1080 physical resolution
# Ensure capture is configured to match:
brobot.capture.provider=ROBOT
brobot.capture.robot.scale-to-physical=true
brobot.capture.robot.expected-physical-width=1920

4. Handle Multiple Resolutions

// Detect and adapt to different resolutions
int screenWidth = captureService.captureScreen().getWidth();

if (screenWidth == 1920) {
// Full HD setup
} else if (screenWidth == 2560) {
// 2K setup
} else if (screenWidth == 3840) {
// 4K setup
}

Platform-Specific Notes

Windows

  • Most likely to have DPI scaling enabled
  • Check: Settings → Display → Scale and layout
  • Common scales: 125%, 150%, 175%

macOS

  • Retina displays use 2× scaling
  • JavaCV FFmpeg handles this well
  • Consider using FFmpeg provider

Linux

  • Less common to have scaling issues
  • Check with: xrandr --current
  • Robot provider usually sufficient

Summary

The Problem: Java 21 captures at logical resolution with DPI scaling

The Solution: Brobot automatically handles it via:

  1. Robot provider with scaling compensation
  2. FFmpeg provider with true physical capture
  3. Configurable resolution expectations

Quick Fix:

# Just add this to application.properties:
brobot.capture.provider=ROBOT
brobot.capture.robot.scale-to-physical=true

Your pattern matching will work correctly regardless of DPI scaling! ✅