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 Scaling | Physical | Logical | Scale Factor |
---|---|---|---|
100% | 1920ร1080 | 1920ร1080 | 1.0 |
125% | 1920ร1080 | 1536ร864 | 1.25 |
150% | 1920ร1080 | 1280ร720 | 1.5 |
175% | 1920ร1080 | 1097ร617 | 1.75 |
200% | 1920ร1080 | 960ร540 | 2.0 |
Solution: Brobot's Approachโ
Brobot provides automatic DPI detection and compensation through two key settings:
Default Configuration (Recommended)โ
# 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:
- Keeps DPI awareness enabled - Allows detection of Windows scaling
- Auto-detects scaling - Automatically calculates pattern resize factor
- 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:
- Captures at logical resolution (e.g., 1536ร864)
- Detects scaling factor (e.g., 1.25)
- Scales image to physical resolution (1920ร1080)
- 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:
- Robot provider with scaling compensation
- FFmpeg provider with true physical capture
- 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! โ