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! โœ